222 lines
8.2 KiB
PHP
222 lines
8.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\common\service;
|
|
|
|
use support\think\Db;
|
|
|
|
class AdminWalletService
|
|
{
|
|
public static function ensureWallet(int $adminId): array
|
|
{
|
|
$wallet = Db::name('admin_wallet')->where('admin_id', $adminId)->find();
|
|
if (is_array($wallet)) {
|
|
return $wallet;
|
|
}
|
|
$now = time();
|
|
Db::name('admin_wallet')->insert([
|
|
'admin_id' => $adminId,
|
|
'balance' => '0.00',
|
|
'frozen_balance' => '0.00',
|
|
'total_income' => '0.00',
|
|
'total_withdraw' => '0.00',
|
|
'create_time' => $now,
|
|
'update_time' => $now,
|
|
]);
|
|
return Db::name('admin_wallet')->where('admin_id', $adminId)->find() ?: [];
|
|
}
|
|
|
|
public static function creditCommission(
|
|
int $adminId,
|
|
?int $channelId,
|
|
string $amount,
|
|
string $refType,
|
|
int $refId,
|
|
string $remark,
|
|
?int $operatorAdminId = null
|
|
): void
|
|
{
|
|
$wallet = self::ensureWallet($adminId);
|
|
$before = strval($wallet['balance'] ?? '0.00');
|
|
$after = bcadd($before, $amount, 2);
|
|
$now = time();
|
|
Db::name('admin_wallet')->where('admin_id', $adminId)->update([
|
|
'balance' => $after,
|
|
'total_income' => Db::raw('total_income + ' . $amount),
|
|
'update_time' => $now,
|
|
]);
|
|
Db::name('admin_wallet_record')->insert([
|
|
'admin_id' => $adminId,
|
|
'channel_id' => $channelId,
|
|
'biz_type' => 'commission_income',
|
|
'direction' => 1,
|
|
'amount' => $amount,
|
|
'balance_before' => $before,
|
|
'balance_after' => $after,
|
|
'ref_type' => $refType,
|
|
'ref_id' => $refId,
|
|
'idempotency_key' => 'commission_income_' . $adminId . '_' . $refId,
|
|
'operator_admin_id' => $operatorAdminId,
|
|
'remark' => $remark,
|
|
'create_time' => $now,
|
|
]);
|
|
}
|
|
|
|
public static function applyWithdraw(
|
|
int $adminId,
|
|
int $channelId,
|
|
string $withdrawCoin,
|
|
string $receiveType,
|
|
string $receiveAccount,
|
|
string $idempotencyKey,
|
|
string $remark
|
|
): array
|
|
{
|
|
$existing = Db::name('admin_withdraw_order')->where('idempotency_key', $idempotencyKey)->find();
|
|
if (is_array($existing)) {
|
|
$existAdminId = intval($existing['admin_id'] ?? 0);
|
|
if ($existAdminId !== $adminId) {
|
|
return ['ok' => false, 'msg' => __('Idempotency key conflict')];
|
|
}
|
|
return [
|
|
'ok' => true,
|
|
'order_id' => intval($existing['id'] ?? 0),
|
|
'order_no' => strval($existing['order_no'] ?? ''),
|
|
'idempotent_hit' => true,
|
|
];
|
|
}
|
|
|
|
$wallet = self::ensureWallet($adminId);
|
|
$before = strval($wallet['balance'] ?? '0.00');
|
|
if (bccomp($before, $withdrawCoin, 2) < 0) {
|
|
return ['ok' => false, 'msg' => __('Insufficient wallet balance')];
|
|
}
|
|
$after = bcsub($before, $withdrawCoin, 2);
|
|
$beforeFrozen = strval($wallet['frozen_balance'] ?? '0.00');
|
|
$afterFrozen = bcadd($beforeFrozen, $withdrawCoin, 2);
|
|
$now = time();
|
|
$orderNo = 'AWD' . date('YmdHis') . str_pad(strval($adminId), 6, '0', STR_PAD_LEFT) . strval(random_int(1000, 9999));
|
|
|
|
Db::name('admin_wallet')->where('admin_id', $adminId)->update([
|
|
'balance' => $after,
|
|
'frozen_balance' => $afterFrozen,
|
|
'update_time' => $now,
|
|
]);
|
|
$orderId = Db::name('admin_withdraw_order')->insertGetId([
|
|
'order_no' => $orderNo,
|
|
'admin_id' => $adminId,
|
|
'channel_id' => $channelId > 0 ? $channelId : null,
|
|
'amount' => $withdrawCoin,
|
|
'actual_amount' => $withdrawCoin,
|
|
'status' => 0,
|
|
'receive_type' => $receiveType,
|
|
'receive_account' => $receiveAccount,
|
|
'idempotency_key' => $idempotencyKey,
|
|
'review_admin_id' => null,
|
|
'review_time' => null,
|
|
'remark' => $remark,
|
|
'create_time' => $now,
|
|
'update_time' => $now,
|
|
]);
|
|
Db::name('admin_wallet_record')->insert([
|
|
'admin_id' => $adminId,
|
|
'channel_id' => $channelId > 0 ? $channelId : null,
|
|
'biz_type' => 'withdraw_freeze',
|
|
'direction' => 2,
|
|
'amount' => $withdrawCoin,
|
|
'balance_before' => $before,
|
|
'balance_after' => $after,
|
|
'ref_type' => 'admin_withdraw_order',
|
|
'ref_id' => $orderId,
|
|
'idempotency_key' => 'admin_withdraw_freeze_' . $orderId,
|
|
'operator_admin_id' => $adminId,
|
|
'remark' => $remark !== '' ? $remark : '管理员提现申请冻结',
|
|
'create_time' => $now,
|
|
]);
|
|
|
|
return ['ok' => true, 'order_id' => $orderId, 'order_no' => $orderNo];
|
|
}
|
|
|
|
public static function approveWithdraw(array $order, int $reviewAdminId, string $remark): void
|
|
{
|
|
$orderId = intval($order['id'] ?? 0);
|
|
$adminId = intval($order['admin_id'] ?? 0);
|
|
$amount = strval($order['amount'] ?? '0.00');
|
|
$wallet = self::ensureWallet($adminId);
|
|
$frozen = strval($wallet['frozen_balance'] ?? '0.00');
|
|
$afterFrozen = bcsub($frozen, $amount, 2);
|
|
$now = time();
|
|
|
|
Db::name('admin_wallet')->where('admin_id', $adminId)->update([
|
|
'frozen_balance' => $afterFrozen,
|
|
'total_withdraw' => Db::raw('total_withdraw + ' . $amount),
|
|
'update_time' => $now,
|
|
]);
|
|
Db::name('admin_withdraw_order')->where('id', $orderId)->update([
|
|
'status' => 1,
|
|
'review_admin_id' => $reviewAdminId,
|
|
'review_time' => $now,
|
|
'remark' => $remark,
|
|
'update_time' => $now,
|
|
]);
|
|
Db::name('admin_wallet_record')->insert([
|
|
'admin_id' => $adminId,
|
|
'channel_id' => $order['channel_id'] ?? null,
|
|
'biz_type' => 'withdraw_success',
|
|
'direction' => 2,
|
|
'amount' => $amount,
|
|
'balance_before' => strval($wallet['balance'] ?? '0.00'),
|
|
'balance_after' => strval($wallet['balance'] ?? '0.00'),
|
|
'ref_type' => 'admin_withdraw_order',
|
|
'ref_id' => $orderId,
|
|
'idempotency_key' => 'admin_withdraw_success_' . $orderId,
|
|
'operator_admin_id' => $reviewAdminId,
|
|
'remark' => $remark !== '' ? $remark : '管理员提现审核通过',
|
|
'create_time' => $now,
|
|
]);
|
|
}
|
|
|
|
public static function rejectWithdraw(array $order, int $reviewAdminId, string $remark): void
|
|
{
|
|
$orderId = intval($order['id'] ?? 0);
|
|
$adminId = intval($order['admin_id'] ?? 0);
|
|
$amount = strval($order['amount'] ?? '0.00');
|
|
$wallet = self::ensureWallet($adminId);
|
|
$before = strval($wallet['balance'] ?? '0.00');
|
|
$after = bcadd($before, $amount, 2);
|
|
$frozen = strval($wallet['frozen_balance'] ?? '0.00');
|
|
$afterFrozen = bcsub($frozen, $amount, 2);
|
|
$now = time();
|
|
|
|
Db::name('admin_wallet')->where('admin_id', $adminId)->update([
|
|
'balance' => $after,
|
|
'frozen_balance' => $afterFrozen,
|
|
'update_time' => $now,
|
|
]);
|
|
Db::name('admin_withdraw_order')->where('id', $orderId)->update([
|
|
'status' => 2,
|
|
'review_admin_id' => $reviewAdminId,
|
|
'review_time' => $now,
|
|
'remark' => $remark,
|
|
'update_time' => $now,
|
|
]);
|
|
Db::name('admin_wallet_record')->insert([
|
|
'admin_id' => $adminId,
|
|
'channel_id' => $order['channel_id'] ?? null,
|
|
'biz_type' => 'withdraw_refund',
|
|
'direction' => 1,
|
|
'amount' => $amount,
|
|
'balance_before' => $before,
|
|
'balance_after' => $after,
|
|
'ref_type' => 'admin_withdraw_order',
|
|
'ref_id' => $orderId,
|
|
'idempotency_key' => 'admin_withdraw_refund_' . $orderId,
|
|
'operator_admin_id' => $reviewAdminId,
|
|
'remark' => $remark !== '' ? $remark : '管理员提现审核拒绝退回',
|
|
'create_time' => $now,
|
|
]);
|
|
}
|
|
}
|
|
|