0.使用模拟数据进行充值和提现
1.优化提现接口/api/finance/withdrawCreate 2.优化充值接口/api/finance/depositCreate
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace app\admin\controller\order;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
use app\common\library\finance\DDPayGateway;
|
||||
use app\common\library\finance\MockPay;
|
||||
use support\think\Db;
|
||||
use support\Response;
|
||||
use Throwable;
|
||||
@@ -265,12 +266,21 @@ class WithdrawOrder extends Backend
|
||||
$orderNo = is_string($fresh['order_no'] ?? null) ? trim($fresh['order_no'] ?? '') : strval($fresh['order_no'] ?? '');
|
||||
$receiveType = is_string($fresh['receive_type'] ?? null) ? strtolower(trim($fresh['receive_type'] ?? '')) : '';
|
||||
$payChannel = is_string($fresh['pay_channel'] ?? null) ? strtolower(trim($fresh['pay_channel'] ?? '')) : '';
|
||||
if ($payChannel === '') {
|
||||
$payChannel = 'ddpay';
|
||||
}
|
||||
|
||||
// 当前仅 ddpay + bank 类型自动出金(与移动端 withdrawCreate 校验一致)
|
||||
if ($orderNo !== '' && $receiveType === 'bank' && $payChannel === 'ddpay') {
|
||||
// 模拟出金:审核通过即标记已打款,不回冲、不调用 DDPay
|
||||
if ($orderNo !== '' && MockPay::shouldSimulateWithdrawPayout($payChannel)) {
|
||||
$prevRemark = is_string($fresh['remark'] ?? null) ? trim($fresh['remark']) : '';
|
||||
$mockNote = '[mock] 管理员(' . $adminName . ')审核通过,模拟打款成功';
|
||||
$finalRemark = $prevRemark === '' ? $mockNote : mb_substr($prevRemark . ' | ' . $mockNote, 0, 255);
|
||||
Db::name('withdraw_order')
|
||||
->where('id', $id)
|
||||
->where('status', 1)
|
||||
->update([
|
||||
'status' => 3,
|
||||
'remark' => $finalRemark,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
} elseif ($orderNo !== '' && $receiveType === 'bank' && $payChannel === 'ddpay') {
|
||||
$base = \app\common\library\finance\DDPayGateway::publicBaseUrlForCallbacks($request);
|
||||
if ($base === '') {
|
||||
$base = 'https://' . strval($request->host());
|
||||
@@ -514,12 +524,15 @@ class WithdrawOrder extends Backend
|
||||
]);
|
||||
}
|
||||
|
||||
$finalStatus = Db::name('withdraw_order')->where('id', $id)->value('status');
|
||||
$finalStatusInt = is_numeric($finalStatus) ? intval($finalStatus) : 1;
|
||||
|
||||
return $this->success(__('Approved'), [
|
||||
'id' => $id,
|
||||
'amount' => $newAmount,
|
||||
'fee' => $newFee,
|
||||
'actual_amount' => $newActual,
|
||||
'status' => 1,
|
||||
'status' => $finalStatusInt,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user