82 lines
2.5 KiB
PHP
82 lines
2.5 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace app\common\service;
|
||
|
||
use support\think\Db;
|
||
|
||
/**
|
||
* 充值待支付订单超时处理:
|
||
* - 同用户最多允许 3 笔待支付订单
|
||
* - 待支付订单创建后 60 秒未支付,自动标记为失败并写失败原因
|
||
*/
|
||
final class DepositOrderExpireService
|
||
{
|
||
public const MAX_PENDING_DEPOSIT = 3;
|
||
public const EXPIRE_SECONDS = 60;
|
||
|
||
/**
|
||
* 超时失效处理。
|
||
*
|
||
* @param int|null $userId 仅处理某用户;null 表示不过滤用户
|
||
* @param string|null $orderNo 仅处理某订单;null 表示不过滤订单
|
||
*
|
||
* @return int 本次转失败的订单数
|
||
*/
|
||
public static function expirePendingOrders(?int $userId = null, ?string $orderNo = null): int
|
||
{
|
||
$expireBefore = time() - self::EXPIRE_SECONDS;
|
||
$query = Db::name('deposit_order')
|
||
->where('status', 0)
|
||
->where('create_time', '<=', $expireBefore);
|
||
if ($userId !== null && $userId > 0) {
|
||
$query->where('user_id', $userId);
|
||
}
|
||
if ($orderNo !== null && $orderNo !== '') {
|
||
$query->where('order_no', $orderNo);
|
||
}
|
||
$rows = $query->field(['id', 'remark'])->select()->toArray();
|
||
if ($rows === []) {
|
||
return 0;
|
||
}
|
||
$now = time();
|
||
$affectedCount = 0;
|
||
foreach ($rows as $row) {
|
||
$id = isset($row['id']) && is_numeric($row['id']) ? intval($row['id']) : 0;
|
||
if ($id <= 0) {
|
||
continue;
|
||
}
|
||
$oldRemark = isset($row['remark']) && is_string($row['remark']) ? trim($row['remark']) : '';
|
||
$reason = '[timeout] unpaid over ' . self::EXPIRE_SECONDS . 's';
|
||
$remark = $oldRemark === '' ? $reason : mb_substr($oldRemark . ' | ' . $reason, 0, 255);
|
||
$affected = Db::name('deposit_order')
|
||
->where('id', $id)
|
||
->where('status', 0)
|
||
->update([
|
||
'status' => 2,
|
||
'remark' => $remark,
|
||
'update_time' => $now,
|
||
]);
|
||
if (is_numeric($affected) && intval($affected) > 0) {
|
||
$affectedCount++;
|
||
}
|
||
}
|
||
|
||
return $affectedCount;
|
||
}
|
||
|
||
public static function pendingCountByUserId(int $userId): int
|
||
{
|
||
if ($userId <= 0) {
|
||
return 0;
|
||
}
|
||
|
||
return Db::name('deposit_order')
|
||
->where('user_id', $userId)
|
||
->where('status', 0)
|
||
->count();
|
||
}
|
||
}
|
||
|