|
|
@@ -158,12 +158,12 @@ class ConsumeService
|
|
|
case CONSUME_TYPE::ITEM->value:
|
|
|
return self::checkItemConsume($userId, $consumeItem);
|
|
|
|
|
|
+ case CONSUME_TYPE::FUND_CONFIG->value:
|
|
|
+ return self::checkFundConfigConsume($userId, $consumeItem);
|
|
|
+
|
|
|
case CONSUME_TYPE::CURRENCY->value:
|
|
|
return self::checkCurrencyConsume($userId, $consumeItem);
|
|
|
|
|
|
- case CONSUME_TYPE::FUND->value:
|
|
|
- return self::checkFundConsume($userId, $consumeItem);
|
|
|
-
|
|
|
default:
|
|
|
return [
|
|
|
'success' => false,
|
|
|
@@ -187,12 +187,12 @@ class ConsumeService
|
|
|
case CONSUME_TYPE::ITEM->value:
|
|
|
return self::executeItemConsume($userId, $consumeItem, $source, $sourceId);
|
|
|
|
|
|
+ case CONSUME_TYPE::FUND_CONFIG->value:
|
|
|
+ return self::executeFundConfigConsume($userId, $consumeItem, $source, $sourceId);
|
|
|
+
|
|
|
case CONSUME_TYPE::CURRENCY->value:
|
|
|
return self::executeCurrencyConsume($userId, $consumeItem, $source, $sourceId);
|
|
|
|
|
|
- case CONSUME_TYPE::FUND->value:
|
|
|
- return self::executeFundConsume($userId, $consumeItem, $source, $sourceId);
|
|
|
-
|
|
|
default:
|
|
|
return [
|
|
|
'success' => false,
|
|
|
@@ -240,26 +240,28 @@ class ConsumeService
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 检查货币消耗
|
|
|
+ * 检查账户种类消耗
|
|
|
+ *
|
|
|
+ * 注意:这里的target_id指向fund_config表的id(账户种类ID)
|
|
|
*
|
|
|
* @param int $userId 用户ID
|
|
|
* @param GameConsumeItem $consumeItem 消耗项
|
|
|
* @return array 检查结果
|
|
|
*/
|
|
|
- protected static function checkCurrencyConsume(int $userId, GameConsumeItem $consumeItem): array
|
|
|
+ protected static function checkFundConfigConsume(int $userId, GameConsumeItem $consumeItem): array
|
|
|
{
|
|
|
- $currencyId = $consumeItem->target_id;
|
|
|
+ $fundConfigId = $consumeItem->target_id;
|
|
|
$amount = $consumeItem->quantity;
|
|
|
|
|
|
- // 获取用户货币账户
|
|
|
- $account = FundLogic::get_account($userId, $currencyId);
|
|
|
+ // 获取用户账户
|
|
|
+ $account = FundLogic::get_account($userId, $fundConfigId);
|
|
|
|
|
|
// 检查账户是否存在
|
|
|
if ($account === false) {
|
|
|
return [
|
|
|
'success' => false,
|
|
|
- 'message' => "用户没有该货币账户",
|
|
|
- 'currency_id' => $currencyId
|
|
|
+ 'message' => "用户没有该账户种类",
|
|
|
+ 'fund_config_id' => $fundConfigId
|
|
|
];
|
|
|
}
|
|
|
|
|
|
@@ -267,8 +269,8 @@ class ConsumeService
|
|
|
if ($account->balance < $amount) {
|
|
|
return [
|
|
|
'success' => false,
|
|
|
- 'message' => "货币余额不足,需要 {$amount},实际 {$account->balance}",
|
|
|
- 'currency_id' => $currencyId,
|
|
|
+ 'message' => "账户余额不足,需要 {$amount},实际 {$account->balance}",
|
|
|
+ 'fund_config_id' => $fundConfigId,
|
|
|
'required' => $amount,
|
|
|
'actual' => $account->balance
|
|
|
];
|
|
|
@@ -276,7 +278,7 @@ class ConsumeService
|
|
|
|
|
|
return [
|
|
|
'success' => true,
|
|
|
- 'message' => '货币余额足够'
|
|
|
+ 'message' => '账户余额足够'
|
|
|
];
|
|
|
}
|
|
|
|
|
|
@@ -373,7 +375,9 @@ class ConsumeService
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 执行货币消耗
|
|
|
+ * 执行账户种类消耗
|
|
|
+ *
|
|
|
+ * 注意:这里的target_id指向fund_config表的id(账户种类ID)
|
|
|
*
|
|
|
* @param int $userId 用户ID
|
|
|
* @param GameConsumeItem $consumeItem 消耗项
|
|
|
@@ -381,9 +385,9 @@ class ConsumeService
|
|
|
* @param int $sourceId 消耗来源ID
|
|
|
* @return array 执行结果
|
|
|
*/
|
|
|
- protected static function executeCurrencyConsume(int $userId, GameConsumeItem $consumeItem, string $source, int $sourceId): array
|
|
|
+ protected static function executeFundConfigConsume(int $userId, GameConsumeItem $consumeItem, string $source, int $sourceId): array
|
|
|
{
|
|
|
- $currencyId = $consumeItem->target_id;
|
|
|
+ $fundConfigId = $consumeItem->target_id;
|
|
|
$amount = -$consumeItem->quantity; // 负数表示消耗
|
|
|
|
|
|
// 构建备注
|
|
|
@@ -392,10 +396,10 @@ class ConsumeService
|
|
|
$remark .= ",ID:{$sourceId}";
|
|
|
}
|
|
|
|
|
|
- // 消耗货币
|
|
|
+ // 消耗账户资金
|
|
|
$result = FundLogic::handle(
|
|
|
$userId,
|
|
|
- $currencyId,
|
|
|
+ $fundConfigId,
|
|
|
$amount,
|
|
|
FUND_LOG_TYPE::TRADE, // 使用TRADE类型,因为CONSUME可能不存在
|
|
|
$sourceId,
|
|
|
@@ -405,72 +409,196 @@ class ConsumeService
|
|
|
if ($result !== true) {
|
|
|
return [
|
|
|
'success' => false,
|
|
|
- 'message' => is_string($result) ? $result : '货币消耗失败',
|
|
|
- 'currency_id' => $currencyId,
|
|
|
+ 'message' => is_string($result) ? $result : '账户资金消耗失败',
|
|
|
+ 'fund_config_id' => $fundConfigId,
|
|
|
'amount' => abs($amount)
|
|
|
];
|
|
|
}
|
|
|
|
|
|
return [
|
|
|
'success' => true,
|
|
|
- 'message' => '货币消耗成功',
|
|
|
- 'currency_id' => $currencyId,
|
|
|
+ 'message' => '账户资金消耗成功',
|
|
|
+ 'fund_config_id' => $fundConfigId,
|
|
|
'amount' => abs($amount)
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 执行代币账户消耗
|
|
|
+ * 检查币种消耗
|
|
|
+ *
|
|
|
+ * 注意:这里的target_id指向fund_currency表的id(币种ID)
|
|
|
+ * 这个方法会检查用户所有与该币种相关的账户,并计算总余额
|
|
|
*
|
|
|
* @param int $userId 用户ID
|
|
|
* @param GameConsumeItem $consumeItem 消耗项
|
|
|
- * @param string $source 消耗来源
|
|
|
- * @param int $sourceId 消耗来源ID
|
|
|
- * @return array 执行结果
|
|
|
+ * @return array 检查结果
|
|
|
*/
|
|
|
- protected static function executeFundConsume(int $userId, GameConsumeItem $consumeItem, string $source, int $sourceId): array
|
|
|
+ protected static function checkCurrencyConsume(int $userId, GameConsumeItem $consumeItem): array
|
|
|
{
|
|
|
- $fundId = $consumeItem->target_id;
|
|
|
- $amount = -$consumeItem->quantity; // 负数表示消耗
|
|
|
-
|
|
|
- // 构建备注
|
|
|
- $remark = "消耗组:{$consumeItem->group_id},来源:{$source}";
|
|
|
- if ($sourceId > 0) {
|
|
|
- $remark .= ",ID:{$sourceId}";
|
|
|
- }
|
|
|
+ $currencyId = $consumeItem->target_id;
|
|
|
+ $amount = $consumeItem->quantity;
|
|
|
|
|
|
try {
|
|
|
- // 消耗代币账户
|
|
|
- $fundService = new \App\Module\Fund\Services\FundService($userId, $fundId);
|
|
|
- $result = $fundService->trade(
|
|
|
- 0, // 系统账户
|
|
|
- abs($amount), // 正数金额
|
|
|
- $source,
|
|
|
- $sourceId,
|
|
|
- $remark
|
|
|
- );
|
|
|
-
|
|
|
- if (is_string($result)) {
|
|
|
+ // 获取该币种的所有账户种类
|
|
|
+ $fundConfigs = \App\Module\Fund\Models\FundConfigModel::where('currency_id', $currencyId)->get();
|
|
|
+
|
|
|
+ if ($fundConfigs->isEmpty()) {
|
|
|
return [
|
|
|
'success' => false,
|
|
|
- 'message' => $result,
|
|
|
- 'fund_id' => $fundId,
|
|
|
- 'amount' => abs($amount)
|
|
|
+ 'message' => "币种不存在或没有关联的账户种类",
|
|
|
+ 'currency_id' => $currencyId
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取用户所有与该币种相关的账户
|
|
|
+ $fundConfigIds = $fundConfigs->pluck('id')->toArray();
|
|
|
+ $accounts = \App\Module\Fund\Models\FundModel::where('user_id', $userId)
|
|
|
+ ->whereIn('fund_id', $fundConfigIds)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ if ($accounts->isEmpty()) {
|
|
|
+ return [
|
|
|
+ 'success' => false,
|
|
|
+ 'message' => "用户没有该币种的账户",
|
|
|
+ 'currency_id' => $currencyId
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算总余额
|
|
|
+ $totalBalance = $accounts->sum('balance');
|
|
|
+
|
|
|
+ // 检查余额是否足够
|
|
|
+ if ($totalBalance < $amount) {
|
|
|
+ return [
|
|
|
+ 'success' => false,
|
|
|
+ 'message' => "币种总余额不足,需要 {$amount},实际 {$totalBalance}",
|
|
|
+ 'currency_id' => $currencyId,
|
|
|
+ 'required' => $amount,
|
|
|
+ 'actual' => $totalBalance
|
|
|
];
|
|
|
}
|
|
|
|
|
|
return [
|
|
|
'success' => true,
|
|
|
- 'message' => '代币账户消耗成功',
|
|
|
- 'fund_id' => $fundId,
|
|
|
- 'amount' => abs($amount)
|
|
|
+ 'message' => '币种总余额足够',
|
|
|
+ 'accounts' => $accounts->toArray()
|
|
|
];
|
|
|
} catch (\Exception $e) {
|
|
|
return [
|
|
|
'success' => false,
|
|
|
- 'message' => '代币账户消耗异常: ' . $e->getMessage(),
|
|
|
- 'fund_id' => $fundId,
|
|
|
- 'amount' => abs($amount)
|
|
|
+ 'message' => '检查币种消耗异常: ' . $e->getMessage(),
|
|
|
+ 'currency_id' => $currencyId
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行币种消耗
|
|
|
+ *
|
|
|
+ * 注意:这里的target_id指向fund_currency表的id(币种ID)
|
|
|
+ * 这个方法会优先从用户的可用账户中扣除,如果不足则依次从其他账户扣除
|
|
|
+ *
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @param GameConsumeItem $consumeItem 消耗项
|
|
|
+ * @param string $source 消耗来源
|
|
|
+ * @param int $sourceId 消耗来源ID
|
|
|
+ * @return array 执行结果
|
|
|
+ */
|
|
|
+ protected static function executeCurrencyConsume(int $userId, GameConsumeItem $consumeItem, string $source, int $sourceId): array
|
|
|
+ {
|
|
|
+ $currencyId = $consumeItem->target_id;
|
|
|
+ $amountToConsume = $consumeItem->quantity;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 先检查是否有足够的余额
|
|
|
+ $checkResult = self::checkCurrencyConsume($userId, $consumeItem);
|
|
|
+ if (!$checkResult['success']) {
|
|
|
+ return $checkResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取该币种的所有账户种类
|
|
|
+ $fundConfigs = \App\Module\Fund\Models\FundConfigModel::where('currency_id', $currencyId)->get();
|
|
|
+ $fundConfigIds = $fundConfigs->pluck('id')->toArray();
|
|
|
+
|
|
|
+ // 获取用户所有与该币种相关的账户
|
|
|
+ $accounts = \App\Module\Fund\Models\FundModel::where('user_id', $userId)
|
|
|
+ ->whereIn('fund_id', $fundConfigIds)
|
|
|
+ ->orderBy('fund_id') // 按账户种类ID排序,通常可用账户ID较小
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ // 开始事务
|
|
|
+ \Illuminate\Support\Facades\DB::beginTransaction();
|
|
|
+
|
|
|
+ $remainingAmount = $amountToConsume;
|
|
|
+ $consumedAccounts = [];
|
|
|
+
|
|
|
+ // 依次从各个账户中扣除
|
|
|
+ foreach ($accounts as $account) {
|
|
|
+ if ($remainingAmount <= 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ $accountBalance = $account->balance;
|
|
|
+ $amountToDeduct = min($accountBalance, $remainingAmount);
|
|
|
+
|
|
|
+ if ($amountToDeduct > 0) {
|
|
|
+ // 构建备注
|
|
|
+ $remark = "币种消耗:{$currencyId},消耗组:{$consumeItem->group_id},来源:{$source}";
|
|
|
+ if ($sourceId > 0) {
|
|
|
+ $remark .= ",ID:{$sourceId}";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 从当前账户扣除
|
|
|
+ $result = FundLogic::handle(
|
|
|
+ $userId,
|
|
|
+ $account->fund_id,
|
|
|
+ -$amountToDeduct, // 负数表示消耗
|
|
|
+ FUND_LOG_TYPE::TRADE,
|
|
|
+ $sourceId,
|
|
|
+ $remark
|
|
|
+ );
|
|
|
+
|
|
|
+ if ($result !== true) {
|
|
|
+ \Illuminate\Support\Facades\DB::rollBack();
|
|
|
+ return [
|
|
|
+ 'success' => false,
|
|
|
+ 'message' => is_string($result) ? $result : "从账户 {$account->fund_id} 扣除失败",
|
|
|
+ 'currency_id' => $currencyId,
|
|
|
+ 'fund_config_id' => $account->fund_id,
|
|
|
+ 'amount' => $amountToDeduct
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ $consumedAccounts[] = [
|
|
|
+ 'fund_config_id' => $account->fund_id,
|
|
|
+ 'amount' => $amountToDeduct
|
|
|
+ ];
|
|
|
+
|
|
|
+ $remainingAmount -= $amountToDeduct;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提交事务
|
|
|
+ \Illuminate\Support\Facades\DB::commit();
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => '币种消耗成功',
|
|
|
+ 'currency_id' => $currencyId,
|
|
|
+ 'amount' => $amountToConsume,
|
|
|
+ 'consumed_accounts' => $consumedAccounts
|
|
|
+ ];
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 回滚事务
|
|
|
+ if (\Illuminate\Support\Facades\DB::transactionLevel() > 0) {
|
|
|
+ \Illuminate\Support\Facades\DB::rollBack();
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => false,
|
|
|
+ 'message' => '币种消耗异常: ' . $e->getMessage(),
|
|
|
+ 'currency_id' => $currencyId,
|
|
|
+ 'amount' => $amountToConsume
|
|
|
];
|
|
|
}
|
|
|
}
|