|
|
@@ -0,0 +1,305 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Module\Mex\Logic;
|
|
|
+
|
|
|
+use App\Module\Mex\Models\MexAdminOperation;
|
|
|
+use App\Module\Mex\Models\MexWarehouse;
|
|
|
+use App\Module\Mex\Models\MexTransaction;
|
|
|
+use App\Module\Mex\Enums\AdminOperationType;
|
|
|
+use App\Module\Mex\Enums\TransactionType;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 农贸市场管理员操作逻辑
|
|
|
+ *
|
|
|
+ * 处理管理员操作相关的核心业务逻辑
|
|
|
+ */
|
|
|
+class MexAdminLogic
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 仓库账户ID
|
|
|
+ */
|
|
|
+ private const WAREHOUSE_USER_ID = 15;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 调控账户ID
|
|
|
+ */
|
|
|
+ private const CONTROL_USER_ID = 16;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 物品注入(增加市场供应)
|
|
|
+ *
|
|
|
+ * @param int $adminUserId 管理员用户ID
|
|
|
+ * @param int $itemId 商品ID
|
|
|
+ * @param int $quantity 数量
|
|
|
+ * @param string $price 价格
|
|
|
+ * @param string|null $remark 备注
|
|
|
+ * @return array 操作结果
|
|
|
+ */
|
|
|
+ public static function injectItem(int $adminUserId, int $itemId, int $quantity, string $price, ?string $remark = null): array
|
|
|
+ {
|
|
|
+ if ($quantity <= 0) {
|
|
|
+ return ['success' => false, 'message' => '注入数量必须大于0'];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bccomp($price, '0', 5) <= 0) {
|
|
|
+ return ['success' => false, 'message' => '注入价格必须大于0'];
|
|
|
+ }
|
|
|
+
|
|
|
+ $totalAmount = bcmul($price, $quantity, 5);
|
|
|
+
|
|
|
+ try {
|
|
|
+ return DB::transaction(function () use ($adminUserId, $itemId, $quantity, $price, $totalAmount, $remark) {
|
|
|
+ // 获取操作前的仓库数量
|
|
|
+ $warehouse = MexWarehouse::firstOrCreate(
|
|
|
+ ['item_id' => $itemId],
|
|
|
+ [
|
|
|
+ 'quantity' => 0,
|
|
|
+ 'total_buy_amount' => '0.00000',
|
|
|
+ 'total_sell_amount' => '0.00000',
|
|
|
+ 'total_buy_quantity' => 0,
|
|
|
+ 'total_sell_quantity' => 0,
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ $beforeQuantity = $warehouse->quantity;
|
|
|
+
|
|
|
+ // 更新仓库库存(注入操作相当于系统买入)
|
|
|
+ $warehouse->quantity += $quantity;
|
|
|
+ $warehouse->total_buy_quantity += $quantity;
|
|
|
+ $warehouse->total_buy_amount = bcadd($warehouse->total_buy_amount, $totalAmount, 5);
|
|
|
+ $warehouse->last_transaction_at = now();
|
|
|
+ $warehouse->save();
|
|
|
+
|
|
|
+ $afterQuantity = $warehouse->quantity;
|
|
|
+
|
|
|
+ // 创建成交记录
|
|
|
+ $transaction = MexTransaction::create([
|
|
|
+ 'buy_order_id' => null,
|
|
|
+ 'sell_order_id' => null,
|
|
|
+ 'buyer_id' => self::WAREHOUSE_USER_ID, // 仓库账户作为买方
|
|
|
+ 'seller_id' => self::CONTROL_USER_ID, // 调控账户作为卖方
|
|
|
+ 'item_id' => $itemId,
|
|
|
+ 'quantity' => $quantity,
|
|
|
+ 'price' => $price,
|
|
|
+ 'total_amount' => $totalAmount,
|
|
|
+ 'transaction_type' => TransactionType::ADMIN_INJECT,
|
|
|
+ 'is_admin_operation' => true,
|
|
|
+ 'admin_user_id' => $adminUserId,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 创建管理员操作记录
|
|
|
+ $operation = MexAdminOperation::create([
|
|
|
+ 'admin_user_id' => $adminUserId,
|
|
|
+ 'operation_type' => AdminOperationType::INJECT,
|
|
|
+ 'item_id' => $itemId,
|
|
|
+ 'quantity' => $quantity,
|
|
|
+ 'price' => $price,
|
|
|
+ 'total_amount' => $totalAmount,
|
|
|
+ 'before_warehouse_quantity' => $beforeQuantity,
|
|
|
+ 'after_warehouse_quantity' => $afterQuantity,
|
|
|
+ 'transaction_id' => $transaction->id,
|
|
|
+ 'remark' => $remark,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => '物品注入成功',
|
|
|
+ 'operation_id' => $operation->id,
|
|
|
+ 'transaction_id' => $transaction->id,
|
|
|
+ 'before_quantity' => $beforeQuantity,
|
|
|
+ 'after_quantity' => $afterQuantity,
|
|
|
+ 'injected_quantity' => $quantity,
|
|
|
+ ];
|
|
|
+ });
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ return ['success' => false, 'message' => '物品注入失败:' . $e->getMessage()];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 物品回收(减少市场库存)
|
|
|
+ *
|
|
|
+ * @param int $adminUserId 管理员用户ID
|
|
|
+ * @param int $itemId 商品ID
|
|
|
+ * @param int $quantity 数量
|
|
|
+ * @param string $price 价格
|
|
|
+ * @param string|null $remark 备注
|
|
|
+ * @return array 操作结果
|
|
|
+ */
|
|
|
+ public static function recycleItem(int $adminUserId, int $itemId, int $quantity, string $price, ?string $remark = null): array
|
|
|
+ {
|
|
|
+ if ($quantity <= 0) {
|
|
|
+ return ['success' => false, 'message' => '回收数量必须大于0'];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bccomp($price, '0', 5) <= 0) {
|
|
|
+ return ['success' => false, 'message' => '回收价格必须大于0'];
|
|
|
+ }
|
|
|
+
|
|
|
+ $totalAmount = bcmul($price, $quantity, 5);
|
|
|
+
|
|
|
+ try {
|
|
|
+ return DB::transaction(function () use ($adminUserId, $itemId, $quantity, $price, $totalAmount, $remark) {
|
|
|
+ // 检查仓库库存
|
|
|
+ $warehouse = MexWarehouse::where('item_id', $itemId)->first();
|
|
|
+
|
|
|
+ if (!$warehouse || $warehouse->quantity < $quantity) {
|
|
|
+ throw new \Exception('仓库库存不足,无法回收');
|
|
|
+ }
|
|
|
+
|
|
|
+ $beforeQuantity = $warehouse->quantity;
|
|
|
+
|
|
|
+ // 更新仓库库存(回收操作相当于系统卖出)
|
|
|
+ $warehouse->quantity -= $quantity;
|
|
|
+ $warehouse->total_sell_quantity += $quantity;
|
|
|
+ $warehouse->total_sell_amount = bcadd($warehouse->total_sell_amount, $totalAmount, 5);
|
|
|
+ $warehouse->last_transaction_at = now();
|
|
|
+ $warehouse->save();
|
|
|
+
|
|
|
+ $afterQuantity = $warehouse->quantity;
|
|
|
+
|
|
|
+ // 创建成交记录
|
|
|
+ $transaction = MexTransaction::create([
|
|
|
+ 'buy_order_id' => null,
|
|
|
+ 'sell_order_id' => null,
|
|
|
+ 'buyer_id' => self::CONTROL_USER_ID, // 调控账户作为买方
|
|
|
+ 'seller_id' => self::WAREHOUSE_USER_ID, // 仓库账户作为卖方
|
|
|
+ 'item_id' => $itemId,
|
|
|
+ 'quantity' => $quantity,
|
|
|
+ 'price' => $price,
|
|
|
+ 'total_amount' => $totalAmount,
|
|
|
+ 'transaction_type' => TransactionType::ADMIN_RECYCLE,
|
|
|
+ 'is_admin_operation' => true,
|
|
|
+ 'admin_user_id' => $adminUserId,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 创建管理员操作记录
|
|
|
+ $operation = MexAdminOperation::create([
|
|
|
+ 'admin_user_id' => $adminUserId,
|
|
|
+ 'operation_type' => AdminOperationType::RECYCLE,
|
|
|
+ 'item_id' => $itemId,
|
|
|
+ 'quantity' => $quantity,
|
|
|
+ 'price' => $price,
|
|
|
+ 'total_amount' => $totalAmount,
|
|
|
+ 'before_warehouse_quantity' => $beforeQuantity,
|
|
|
+ 'after_warehouse_quantity' => $afterQuantity,
|
|
|
+ 'transaction_id' => $transaction->id,
|
|
|
+ 'remark' => $remark,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => '物品回收成功',
|
|
|
+ 'operation_id' => $operation->id,
|
|
|
+ 'transaction_id' => $transaction->id,
|
|
|
+ 'before_quantity' => $beforeQuantity,
|
|
|
+ 'after_quantity' => $afterQuantity,
|
|
|
+ 'recycled_quantity' => $quantity,
|
|
|
+ ];
|
|
|
+ });
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ return ['success' => false, 'message' => '物品回收失败:' . $e->getMessage()];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取管理员操作记录
|
|
|
+ *
|
|
|
+ * @param int $page 页码
|
|
|
+ * @param int $pageSize 每页数量
|
|
|
+ * @param int|null $adminUserId 管理员用户ID筛选
|
|
|
+ * @param AdminOperationType|null $operationType 操作类型筛选
|
|
|
+ * @return array 操作记录列表
|
|
|
+ */
|
|
|
+ public static function getAdminOperations(int $page = 1, int $pageSize = 20, ?int $adminUserId = null, ?AdminOperationType $operationType = null): array
|
|
|
+ {
|
|
|
+ $query = MexAdminOperation::query()->orderBy('created_at', 'desc');
|
|
|
+
|
|
|
+ if ($adminUserId) {
|
|
|
+ $query->where('admin_user_id', $adminUserId);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($operationType) {
|
|
|
+ $query->where('operation_type', $operationType);
|
|
|
+ }
|
|
|
+
|
|
|
+ $operations = $query->paginate($pageSize, ['*'], 'page', $page);
|
|
|
+
|
|
|
+ $result = [];
|
|
|
+ foreach ($operations->items() as $operation) {
|
|
|
+ $result[] = [
|
|
|
+ 'id' => $operation->id,
|
|
|
+ 'admin_user_id' => $operation->admin_user_id,
|
|
|
+ 'operation_type' => $operation->operation_type->value,
|
|
|
+ 'operation_type_desc' => $operation->operation_type->getDescription(),
|
|
|
+ 'item_id' => $operation->item_id,
|
|
|
+ 'quantity' => $operation->quantity,
|
|
|
+ 'price' => $operation->price,
|
|
|
+ 'total_amount' => $operation->total_amount,
|
|
|
+ 'before_warehouse_quantity' => $operation->before_warehouse_quantity,
|
|
|
+ 'after_warehouse_quantity' => $operation->after_warehouse_quantity,
|
|
|
+ 'quantity_change' => $operation->after_warehouse_quantity - $operation->before_warehouse_quantity,
|
|
|
+ 'transaction_id' => $operation->transaction_id,
|
|
|
+ 'remark' => $operation->remark,
|
|
|
+ 'created_at' => $operation->created_at,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'operations' => $result,
|
|
|
+ 'total' => $operations->total(),
|
|
|
+ 'page' => $page,
|
|
|
+ 'page_size' => $pageSize,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取管理员操作统计
|
|
|
+ *
|
|
|
+ * @param int $days 统计天数
|
|
|
+ * @return array 统计信息
|
|
|
+ */
|
|
|
+ public static function getAdminOperationStats(int $days = 7): array
|
|
|
+ {
|
|
|
+ $startDate = now()->subDays($days)->startOfDay();
|
|
|
+
|
|
|
+ $stats = MexAdminOperation::where('created_at', '>=', $startDate)
|
|
|
+ ->selectRaw('
|
|
|
+ COUNT(*) as total_operations,
|
|
|
+ COUNT(CASE WHEN operation_type = ? THEN 1 END) as inject_count,
|
|
|
+ COUNT(CASE WHEN operation_type = ? THEN 1 END) as recycle_count,
|
|
|
+ SUM(CASE WHEN operation_type = ? THEN quantity ELSE 0 END) as inject_quantity,
|
|
|
+ SUM(CASE WHEN operation_type = ? THEN quantity ELSE 0 END) as recycle_quantity,
|
|
|
+ SUM(CASE WHEN operation_type = ? THEN total_amount ELSE 0 END) as inject_amount,
|
|
|
+ SUM(CASE WHEN operation_type = ? THEN total_amount ELSE 0 END) as recycle_amount,
|
|
|
+ COUNT(DISTINCT admin_user_id) as active_admins,
|
|
|
+ COUNT(DISTINCT item_id) as affected_items
|
|
|
+ ', [
|
|
|
+ AdminOperationType::INJECT->value,
|
|
|
+ AdminOperationType::RECYCLE->value,
|
|
|
+ AdminOperationType::INJECT->value,
|
|
|
+ AdminOperationType::RECYCLE->value,
|
|
|
+ AdminOperationType::INJECT->value,
|
|
|
+ AdminOperationType::RECYCLE->value,
|
|
|
+ ])
|
|
|
+ ->first();
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'days' => $days,
|
|
|
+ 'total_operations' => $stats->total_operations ?? 0,
|
|
|
+ 'inject_count' => $stats->inject_count ?? 0,
|
|
|
+ 'recycle_count' => $stats->recycle_count ?? 0,
|
|
|
+ 'inject_quantity' => $stats->inject_quantity ?? 0,
|
|
|
+ 'recycle_quantity' => $stats->recycle_quantity ?? 0,
|
|
|
+ 'inject_amount' => $stats->inject_amount ?? '0.00000',
|
|
|
+ 'recycle_amount' => $stats->recycle_amount ?? '0.00000',
|
|
|
+ 'net_quantity' => ($stats->inject_quantity ?? 0) - ($stats->recycle_quantity ?? 0),
|
|
|
+ 'net_amount' => bcsub($stats->inject_amount ?? '0', $stats->recycle_amount ?? '0', 5),
|
|
|
+ 'active_admins' => $stats->active_admins ?? 0,
|
|
|
+ 'affected_items' => $stats->affected_items ?? 0,
|
|
|
+ 'start_date' => $startDate,
|
|
|
+ 'end_date' => now(),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+}
|