MexAccountLogic.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <?php
  2. namespace App\Module\Mex\Logic;
  3. use App\Module\Fund\Services\FundService;
  4. use App\Module\Fund\Enums\FUND_TYPE;
  5. use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
  6. use App\Module\Game\Enums\REWARD_SOURCE_TYPE;
  7. use App\Module\GameItems\Services\ItemService;
  8. use App\Module\Mex\Logic\MexTransactionLogic;
  9. use App\Module\Mex\Logic\MexWarehouseLogic;
  10. use App\Module\Mex\Logic\FundLogic;
  11. use App\Module\Mex\Enums\TransactionType;
  12. use Illuminate\Support\Facades\DB;
  13. use Illuminate\Support\Facades\Log;
  14. /**
  15. * 农贸市场账户流转逻辑
  16. *
  17. * 处理用户与仓库账户之间的资金和物品流转
  18. * 仓库账户USER_ID为15,调控账户USER_ID为16
  19. * 支持多币种交易,默认使用钻石币种
  20. */
  21. class MexAccountLogic
  22. {
  23. // 仓库账户ID
  24. const WAREHOUSE_USER_ID = 15;
  25. // 调控账户ID
  26. const REGULATION_USER_ID = 16;
  27. /**
  28. * 处理用户卖出订单的账户流转
  29. * 用户卖出:资金从仓库转出到用户、物品从用户转入仓库
  30. *
  31. * @param int $userId 用户ID
  32. * @param int $itemId 商品ID
  33. * @param int $quantity 数量
  34. * @param string $price 单价
  35. * @param string $totalAmount 总金额
  36. * @param int $orderId 订单ID
  37. * @param FUND_CURRENCY_TYPE|null $currencyType 币种类型,默认使用钻石
  38. * @return array 操作结果
  39. */
  40. public static function processSellOrder(int $userId, int $itemId, int $quantity, string $price, string $totalAmount, int $orderId, ?FUND_CURRENCY_TYPE $currencyType = null): array
  41. {
  42. try {
  43. DB::beginTransaction();
  44. // 获取币种类型,默认使用钻石
  45. $currencyType = $currencyType ?? FundLogic::getDefaultCurrency();
  46. // 获取对应的账户类型
  47. $availableAccountType = FundLogic::getAvailableAccountType($currencyType);
  48. if (!$availableAccountType) {
  49. DB::rollBack();
  50. return ['success' => false, 'message' => '不支持的币种类型'];
  51. }
  52. // 1. 验证用户是否有足够的物品
  53. $checkResult = ItemService::checkItemQuantity($userId, $itemId, $quantity);
  54. if (!$checkResult->success) {
  55. DB::rollBack();
  56. return ['success' => false, 'message' => $checkResult->message];
  57. }
  58. // 2. 从用户扣除物品
  59. $consumeResult = ItemService::consumeItem($userId, $itemId, null, $quantity, [
  60. 'reason' => 'mex_sell',
  61. 'order_id' => $orderId,
  62. 'remark' => "农贸市场卖出物品,订单ID:{$orderId}"
  63. ]);
  64. if (!$consumeResult['success']) {
  65. DB::rollBack();
  66. return ['success' => false, 'message' => '扣除用户物品失败:' . ($consumeResult['message'] ?? '未知错误')];
  67. }
  68. // 3. 给仓库账户添加物品
  69. $addResult = ItemService::addItem(self::WAREHOUSE_USER_ID, $itemId, $quantity, [
  70. 'reason' => 'mex_warehouse_buy',
  71. 'source_type' => REWARD_SOURCE_TYPE::MEX_BUY,
  72. 'source_id' => $orderId,
  73. 'order_id' => $orderId,
  74. 'remark' => "农贸市场仓库收购物品,订单ID:{$orderId}"
  75. ]);
  76. if (!$addResult['success']) {
  77. DB::rollBack();
  78. return ['success' => false, 'message' => '仓库添加物品失败:' . ($addResult['message'] ?? '未知错误')];
  79. }
  80. // 4. 从仓库账户转出资金给用户
  81. $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, $availableAccountType->value);
  82. $precision = $currencyType->getPrecision();
  83. $fundAmount = (int)bcmul($totalAmount, bcpow('10', $precision), 0); // 根据币种精度转换
  84. $transferResult = $warehouseFundService->trade(
  85. $userId,
  86. $fundAmount,
  87. 'mex_sell',
  88. $orderId,
  89. "农贸市场卖出收款,订单ID:{$orderId}"
  90. );
  91. if (is_string($transferResult)) {
  92. DB::rollBack();
  93. return ['success' => false, 'message' => '资金转移失败:' . $transferResult];
  94. }
  95. // 5. 更新仓库统计
  96. $warehouseResult = MexWarehouseLogic::addStock($itemId, $quantity, $totalAmount);
  97. if (!$warehouseResult) {
  98. DB::rollBack();
  99. return ['success' => false, 'message' => '更新仓库统计失败'];
  100. }
  101. // 6. 创建成交记录
  102. $transactionResult = MexTransactionLogic::createTransaction([
  103. 'sell_order_id' => $orderId,
  104. 'buyer_id' => self::WAREHOUSE_USER_ID,
  105. 'seller_id' => $userId,
  106. 'item_id' => $itemId,
  107. 'currency_type' => $currencyType->value,
  108. 'quantity' => $quantity,
  109. 'price' => $price,
  110. 'total_amount' => $totalAmount,
  111. 'transaction_type' => TransactionType::USER_SELL,
  112. 'is_admin_operation' => false,
  113. ]);
  114. if (!$transactionResult) {
  115. DB::rollBack();
  116. return ['success' => false, 'message' => '创建成交记录失败'];
  117. }
  118. DB::commit();
  119. return [
  120. 'success' => true,
  121. 'message' => '卖出订单处理成功',
  122. 'transaction_id' => $transactionResult->id,
  123. 'fund_transfer' => $transferResult,
  124. 'item_consume' => $consumeResult,
  125. 'warehouse_add' => $addResult
  126. ];
  127. } catch (\Exception $e) {
  128. DB::rollBack();
  129. Log::error('Mex卖出订单处理失败', [
  130. 'user_id' => $userId,
  131. 'item_id' => $itemId,
  132. 'quantity' => $quantity,
  133. 'order_id' => $orderId,
  134. 'error' => $e->getMessage(),
  135. 'trace' => $e->getTraceAsString()
  136. ]);
  137. return ['success' => false, 'message' => '系统错误:' . $e->getMessage()];
  138. }
  139. }
  140. /**
  141. * 处理用户买入订单的账户流转
  142. * 用户买入:资金从用户转入仓库、物品从仓库转出到用户
  143. *
  144. * @param int $userId 用户ID
  145. * @param int $itemId 商品ID
  146. * @param int $quantity 数量
  147. * @param string $price 单价
  148. * @param string $totalAmount 总金额
  149. * @param int $orderId 订单ID
  150. * @param FUND_CURRENCY_TYPE|null $currencyType 币种类型,默认使用钻石
  151. * @return array 操作结果
  152. */
  153. public static function processBuyOrder(int $userId, int $itemId, int $quantity, string $price, string $totalAmount, int $orderId, ?FUND_CURRENCY_TYPE $currencyType = null): array
  154. {
  155. try {
  156. DB::beginTransaction();
  157. // 获取币种类型,默认使用钻石
  158. $currencyType = $currencyType ?? FundLogic::getDefaultCurrency();
  159. // 获取对应的账户类型
  160. $availableAccountType = FundLogic::getAvailableAccountType($currencyType);
  161. if (!$availableAccountType) {
  162. DB::rollBack();
  163. return ['success' => false, 'message' => '不支持的币种类型'];
  164. }
  165. // 1. 验证仓库是否有足够的物品
  166. if (!MexWarehouseLogic::checkStockSufficient($itemId, $quantity)) {
  167. DB::rollBack();
  168. return ['success' => false, 'message' => '仓库库存不足'];
  169. }
  170. // 2. 验证用户是否有足够的资金
  171. $userFundService = new FundService($userId, $availableAccountType->value);
  172. $precision = $currencyType->getPrecision();
  173. $fundAmount = (int)bcmul($totalAmount, bcpow('10', $precision), 0); // 根据币种精度转换
  174. if ($userFundService->balance() < $fundAmount) {
  175. DB::rollBack();
  176. return ['success' => false, 'message' => '用户资金不足'];
  177. }
  178. // 3. 从用户转出资金到仓库
  179. $transferResult = $userFundService->trade(
  180. self::WAREHOUSE_USER_ID,
  181. $fundAmount,
  182. 'mex_buy',
  183. $orderId,
  184. "农贸市场买入付款,订单ID:{$orderId}"
  185. );
  186. if (is_string($transferResult)) {
  187. DB::rollBack();
  188. return ['success' => false, 'message' => '资金转移失败:' . $transferResult];
  189. }
  190. // 4. 从仓库扣除物品
  191. $consumeResult = ItemService::consumeItem(self::WAREHOUSE_USER_ID, $itemId, null, $quantity, [
  192. 'reason' => 'mex_warehouse_sell',
  193. 'order_id' => $orderId,
  194. 'remark' => "农贸市场仓库出售物品,订单ID:{$orderId}"
  195. ]);
  196. if (!$consumeResult['success']) {
  197. DB::rollBack();
  198. return ['success' => false, 'message' => '仓库扣除物品失败:' . ($consumeResult['message'] ?? '未知错误')];
  199. }
  200. // 5. 给用户添加物品
  201. $addResult = ItemService::addItem($userId, $itemId, $quantity, [
  202. 'reason' => 'mex_buy',
  203. 'source_type' => REWARD_SOURCE_TYPE::MEX_BUY,
  204. 'source_id' => $orderId,
  205. 'order_id' => $orderId,
  206. 'remark' => "农贸市场买入物品,订单ID:{$orderId}"
  207. ]);
  208. if (!$addResult['success']) {
  209. DB::rollBack();
  210. return ['success' => false, 'message' => '用户添加物品失败:' . ($addResult['message'] ?? '未知错误')];
  211. }
  212. // 6. 更新仓库统计
  213. $warehouseResult = MexWarehouseLogic::reduceStock($itemId, $quantity, $totalAmount);
  214. if (!$warehouseResult) {
  215. DB::rollBack();
  216. return ['success' => false, 'message' => '更新仓库统计失败'];
  217. }
  218. // 7. 创建成交记录
  219. $transactionResult = MexTransactionLogic::createTransaction([
  220. 'buy_order_id' => $orderId,
  221. 'buyer_id' => $userId,
  222. 'seller_id' => self::WAREHOUSE_USER_ID,
  223. 'item_id' => $itemId,
  224. 'currency_type' => $currencyType->value,
  225. 'quantity' => $quantity,
  226. 'price' => $price,
  227. 'total_amount' => $totalAmount,
  228. 'transaction_type' => TransactionType::USER_BUY,
  229. 'is_admin_operation' => false,
  230. ]);
  231. if (!$transactionResult) {
  232. DB::rollBack();
  233. return ['success' => false, 'message' => '创建成交记录失败'];
  234. }
  235. DB::commit();
  236. return [
  237. 'success' => true,
  238. 'message' => '买入订单处理成功',
  239. 'transaction_id' => $transactionResult->id,
  240. 'fund_transfer' => $transferResult,
  241. 'item_consume' => $consumeResult,
  242. 'user_add' => $addResult
  243. ];
  244. } catch (\Exception $e) {
  245. DB::rollBack();
  246. Log::error('Mex买入订单处理失败', [
  247. 'user_id' => $userId,
  248. 'item_id' => $itemId,
  249. 'quantity' => $quantity,
  250. 'order_id' => $orderId,
  251. 'error' => $e->getMessage(),
  252. 'trace' => $e->getTraceAsString()
  253. ]);
  254. return ['success' => false, 'message' => '系统错误:' . $e->getMessage()];
  255. }
  256. }
  257. /**
  258. * 检查仓库账户资金余额
  259. *
  260. * @param FUND_CURRENCY_TYPE|null $currencyType 币种类型,默认使用钻石
  261. * @return int 余额(按币种精度存储的整数)
  262. */
  263. public static function getWarehouseFundBalance(?FUND_CURRENCY_TYPE $currencyType = null): int
  264. {
  265. $currencyType = $currencyType ?? FundLogic::getDefaultCurrency();
  266. $availableAccountType = FundLogic::getAvailableAccountType($currencyType);
  267. if (!$availableAccountType) {
  268. return 0;
  269. }
  270. $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, $availableAccountType->value);
  271. return $warehouseFundService->balance();
  272. }
  273. /**
  274. * 检查调控账户资金余额
  275. *
  276. * @param FUND_CURRENCY_TYPE|null $currencyType 币种类型,默认使用钻石
  277. * @return int 余额(按币种精度存储的整数)
  278. */
  279. public static function getRegulationFundBalance(?FUND_CURRENCY_TYPE $currencyType = null): int
  280. {
  281. $currencyType = $currencyType ?? FundLogic::getDefaultCurrency();
  282. $availableAccountType = FundLogic::getAvailableAccountType($currencyType);
  283. if (!$availableAccountType) {
  284. return 0;
  285. }
  286. $regulationFundService = new FundService(self::REGULATION_USER_ID, $availableAccountType->value);
  287. return $regulationFundService->balance();
  288. }
  289. }