0.使用模拟数据进行充值和提现

1.优化提现接口/api/finance/withdrawCreate
2.优化充值接口/api/finance/depositCreate
This commit is contained in:
2026-05-20 15:57:19 +08:00
parent b9e4d806f7
commit 1b8d947f97
25 changed files with 2022 additions and 179 deletions

View File

@@ -3,18 +3,19 @@
namespace app\admin\controller\order;
use app\common\controller\Backend;
use app\common\library\finance\DepositSettlement;
use app\common\library\finance\MockPay;
use RuntimeException;
use support\think\Db;
use support\Response;
use Throwable;
use Webman\Http\Request as WebmanRequest;
/**
* 充值订单
*
* 订单的"由 0 转 1成功入账"统一走 app\common\library\finance\DepositSettlement。
* 当前充值接口为 mock 支付网关,点击即成功;后台不再保留人工审核按钮,
* 如需人工补单,请通过后续专门的"补单/冲正"工具完成,而不是在这个 CRUD 里直接改 status。
*
* 编辑入口现在只用于"查看详情"GET 返回订单 + 关联的 user/channel 信息,
* 阻止 POST 任何改字段的动作(保证金额、状态只能由结算服务变更)。
* 模拟支付流程:用户确认支付后 status=3待审核管理员 approve 后由 DepositSettlement 入账
* 编辑入口用于查看详情;审核通过/驳回走 approve/reject。
*/
class DepositOrder extends Backend
{
@@ -30,7 +31,7 @@ class DepositOrder extends Backend
protected string|array $orderGuarantee = ['id' => 'desc'];
protected array $withJoinTable = ['user', 'channel'];
protected array $withJoinTable = ['user', 'channel', 'reviewAdmin'];
protected function initController(WebmanRequest $request): ?Response
{
@@ -58,6 +59,7 @@ class DepositOrder extends Backend
->visible([
'user' => ['username', 'phone'],
'channel' => ['name'],
'reviewAdmin' => ['username'],
])
->alias($alias)
->where($where)
@@ -93,7 +95,7 @@ class DepositOrder extends Backend
}
if ($this->request && $this->request->method() === 'POST') {
return $this->error(__('Deposit orders are auto-settled; direct modification is not allowed. Use the dedicated tool for manual adjustment.'));
return $this->error(__('Please use approve/reject buttons to complete the review'));
}
$row = $this->loadWithRelations(intval(strval($id)));
@@ -113,8 +115,9 @@ class DepositOrder extends Backend
->withJoin($this->withJoinTable, $this->withJoinType)
->with($this->withJoinTable)
->visible([
'user' => ['username', 'phone', 'admin_id'],
'channel' => ['name'],
'user' => ['username', 'phone', 'admin_id'],
'channel' => ['name'],
'reviewAdmin' => ['username'],
])
->where($this->model->getTable() . '.id', $id)
->find();
@@ -164,4 +167,190 @@ class DepositOrder extends Backend
return $adminIds === [] ? [0] : $adminIds;
}
/**
* 审核通过将待审核订单结算入账status 3 -> 1
*/
public function approve(WebmanRequest $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if ($request->method() !== 'POST') {
return $this->error(__('Parameter error'));
}
$id = $this->intParam($request->post('id'));
if ($id <= 0) {
return $this->error(__('Parameter error'));
}
$scoped = $this->loadWithRelations($id);
if (!$scoped) {
return $this->error(__('Record not found'));
}
if (!$this->checkChannelScoped($scoped)) {
return $this->error(__('You have no permission'));
}
$order = Db::name('deposit_order')->where('id', $id)->find();
if (!$order) {
return $this->error(__('Record not found'));
}
$currentStatus = $this->intParam($order['status'] ?? 0);
if ($currentStatus !== MockPay::DEPOSIT_STATUS_PENDING_REVIEW) {
return $this->error(__('This order has already been reviewed'));
}
$now = time();
$adminId = $this->intParam($this->auth->id ?? 0);
$adminName = $this->adminDisplayName();
$extraRemark = '管理员(' . $adminName . ')审核通过并入账';
try {
DepositSettlement::settle(
$id,
DepositSettlement::SOURCE_ADMIN_APPROVE,
'admin approve mock deposit',
$adminId > 0 ? $adminId : null,
$extraRemark
);
} catch (RuntimeException $e) {
return $this->error($e->getMessage());
} catch (Throwable $e) {
return $this->error($e->getMessage());
}
$patch = [
'update_time' => $now,
];
if ($this->depositOrderHasColumn('review_admin_id')) {
$patch['review_admin_id'] = $adminId > 0 ? $adminId : null;
}
if ($this->depositOrderHasColumn('review_time')) {
$patch['review_time'] = $now;
}
Db::name('deposit_order')->where('id', $id)->where('status', 1)->update($patch);
return $this->success(__('Approved'));
}
/**
* 审核驳回必须填写备注reject_reason
*/
public function reject(WebmanRequest $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if ($request->method() !== 'POST') {
return $this->error(__('Parameter error'));
}
$id = $this->intParam($request->post('id'));
if ($id <= 0) {
return $this->error(__('Parameter error'));
}
$remarkRaw = $request->post('remark');
$remark = is_string($remarkRaw) ? trim($remarkRaw) : '';
if ($remark === '') {
return $this->error(__('Please provide reject reason'));
}
$scoped = $this->loadWithRelations($id);
if (!$scoped) {
return $this->error(__('Record not found'));
}
if (!$this->checkChannelScoped($scoped)) {
return $this->error(__('You have no permission'));
}
$order = Db::name('deposit_order')->where('id', $id)->find();
if (!$order) {
return $this->error(__('Record not found'));
}
$currentStatus = $this->intParam($order['status'] ?? 0);
if ($currentStatus !== MockPay::DEPOSIT_STATUS_PENDING_REVIEW) {
return $this->error(__('This order has already been reviewed'));
}
$now = time();
$adminId = $this->intParam($this->auth->id ?? 0);
$adminName = $this->adminDisplayName();
$rejectReason = mb_substr($remark, 0, 255);
$baseRemark = is_string($order['remark'] ?? null) ? trim($order['remark']) : '';
$note = '管理员(' . $adminName . ')驳回:' . $rejectReason;
$combined = $baseRemark === '' ? $note : mb_substr($baseRemark . ' | ' . $note, 0, 255);
$update = [
'status' => 2,
'remark' => $combined,
'update_time' => $now,
];
if ($this->depositOrderHasColumn('reject_reason')) {
$update['reject_reason'] = $rejectReason;
}
if ($this->depositOrderHasColumn('review_admin_id')) {
$update['review_admin_id'] = $adminId > 0 ? $adminId : null;
}
if ($this->depositOrderHasColumn('review_time')) {
$update['review_time'] = $now;
}
$affected = Db::name('deposit_order')
->where('id', $id)
->where('status', MockPay::DEPOSIT_STATUS_PENDING_REVIEW)
->update($update);
if (!is_numeric($affected) || intval($affected) <= 0) {
return $this->error(__('This order has already been reviewed'));
}
return $this->success(__('Rejected'));
}
private function depositOrderHasColumn(string $column): bool
{
static $cache = [];
if (array_key_exists($column, $cache)) {
return $cache[$column];
}
try {
$rows = Db::query('SHOW COLUMNS FROM `deposit_order` LIKE ?', [$column]);
$cache[$column] = is_array($rows) && $rows !== [];
} catch (Throwable $e) {
$cache[$column] = false;
}
return $cache[$column];
}
private function intParam($raw): int
{
if ($raw === null || $raw === '') {
return 0;
}
if (is_numeric(strval($raw))) {
return intval(strval($raw));
}
return 0;
}
private function adminDisplayName(): string
{
if (!$this->auth) {
return 'admin';
}
$username = $this->auth->username ?? '';
if (is_string($username) && trim($username) !== '') {
return trim($username);
}
return 'admin#' . strval($this->auth->id ?? 0);
}
}