option('customer'); $productId = (int) $this->option('product'); $execute = (bool) $this->option('execute'); if ($customerId <= 0 || $productId <= 0) { $this->error('پارامترهای --customer و --product الزامی هستند.'); return self::FAILURE; } $customer = Customer::find($customerId); if (!$customer) { $this->error("مشتری {$customerId} یافت نشد."); return self::FAILURE; } $product = Product::find($productId); if (!$product) { $this->error("محصول {$productId} یافت نشد."); return self::FAILURE; } if ($configService->isMainWalletProduct($productId)) { $this->error("محصول {$productId} به کیف اصلی متصل است؛ نیازی به انتقال نیست."); return self::FAILURE; } $goldAmount = $this->resolveGoldAmount($customerId, $productId); if ($goldAmount === null || $goldAmount <= 0) { $this->error('مقدار طلا مشخص نشد. از --gold یا --order یا --transaction استفاده کنید.'); return self::FAILURE; } $ownerType = (int) $customer->type; $mainWallet = Wallet::query() ->where('owner', $customerId) ->where('owner_type', $ownerType) ->whereNull('fund_id') ->whereNull('product_id') ->first(); if (!$mainWallet) { $this->error('کیف اصلی مشتری یافت نشد.'); return self::FAILURE; } $effectiveProductId = Controller::effectiveProductWalletId($productId); $productWallet = Wallet::query() ->where('owner', $customerId) ->where('owner_type', $ownerType) ->whereNull('fund_id') ->where('product_id', $effectiveProductId) ->first(); $productWalletGold = (float) ($productWallet?->gold ?? 0); $mainWalletGold = (float) $mainWallet->gold; $this->info('--- پیش‌نمایش اصلاح موجودی ---'); $this->line("مشتری: {$customerId} ({$customer->name})"); $this->line("محصول: {$productId} ({$product->title})"); $this->line('مقدار انتقال: ' . round($goldAmount, 5) . ' گرم'); $this->line('کیف اصلی قبل: ' . round($mainWalletGold, 5) . ' گرم'); $this->line('کیف محصول قبل: ' . round($productWalletGold, 5) . ' گرم'); $this->line('کیف اصلی بعد: ' . round($mainWalletGold - $goldAmount, 5) . ' گرم'); $this->line('کیف محصول بعد: ' . round($productWalletGold + $goldAmount, 5) . ' گرم'); if ($mainWalletGold < $goldAmount) { $this->error('موجودی کیف اصلی کافی نیست.'); return self::FAILURE; } if ($this->alreadyCorrected($customerId, $productId, $goldAmount)) { $this->warn('به نظر می‌رسد این اصلاح قبلاً انجام شده است. برای اطمینان دوباره اجرا نمی‌شود.'); return self::SUCCESS; } if (!$execute) { $this->newLine(); $this->warn('حالت پیش‌نمایش — برای اجرا فلگ --execute را اضافه کنید.'); return self::SUCCESS; } DB::transaction(function () use ($customer, $customerId, $ownerType, $productId, $product, $goldAmount, $effectiveProductId) { $note = 'اصلاح موجودی — انتقال ' . round($goldAmount, 5) . ' گرم از کیف اصلی به کیف «' . $product->title . '"'; $orderId = (int) ($this->option('order') ?? 0); if ($orderId > 0) { $note .= " (سفارش {$orderId})"; } $withdraw = Withdraw::create([ 'user_id' => 0, 'customer_id' => $customerId, 'gold' => 0, 'note' => $note, 'sts' => 4, ]); $mainWalletInterface = new WalletInterface($customerId, $ownerType); new TransactionInterface($mainWalletInterface, [ 'cash' => 0, 'gold' => $goldAmount, 'product_id' => $productId, 'expire_at' => now(), 'note' => $note, 'withdraw_id' => $withdraw->id, 'order_id' => $orderId > 0 ? $orderId : null, 'active' => true, 'title' => 'اصلاح موجودی — کسر از کیف اصلی', ], 7, false, false); $productWalletInterface = new WalletInterface($customerId, $ownerType, null, $effectiveProductId); new TransactionInterface($productWalletInterface, [ 'cash' => 0, 'gold' => $goldAmount, 'product_id' => $productId, 'expire_at' => now(), 'note' => $note, 'withdraw_id' => $withdraw->id, 'order_id' => $orderId > 0 ? $orderId : null, 'active' => true, 'title' => 'اصلاح موجودی — واریز به کیف محصول', ], 7, true, false); app(WalletBroadcastService::class)->broadcastForCustomer($customerId, $ownerType); }); $this->newLine(); $this->info('اصلاح با موفقیت انجام شد.'); return self::SUCCESS; } private function resolveGoldAmount(int $customerId, int $productId): ?float { $explicitGold = $this->option('gold'); if ($explicitGold !== null && $explicitGold !== '') { return round((float) $explicitGold, 5); } $transactionId = (int) ($this->option('transaction') ?? 0); if ($transactionId > 0) { $transaction = Transaction::query() ->where('id', $transactionId) ->where('customer_id', $customerId) ->first(); if ($transaction && (float) $transaction->gold > 0) { return round(abs((float) $transaction->gold), 5); } $this->warn("تراکنش {$transactionId} یافت نشد یا مقدار طلا ندارد."); } $orderId = (int) ($this->option('order') ?? 0); if ($orderId > 0) { $order = Order::query() ->where('id', $orderId) ->where('customer_id', $customerId) ->first(); if ($order) { $orderProductId = (int) ($order->product_id ?? $order->abshode_id ?? 0); if ($orderProductId === $productId && (float) $order->amount > 0) { return round((float) $order->amount, 5); } $this->warn("سفارش {$orderId} به محصول {$productId} مرتبط نیست یا amount ندارد."); } else { $this->warn("سفارش {$orderId} یافت نشد."); } } return $this->detectFromMainWalletTransactions($customerId, $productId); } private function detectFromMainWalletTransactions(int $customerId, int $productId): ?float { $ownerType = (int) (Customer::find($customerId)?->type ?? 2); $mainWalletId = Wallet::query() ->where('owner', $customerId) ->where('owner_type', $ownerType) ->whereNull('fund_id') ->whereNull('product_id') ->value('id'); if (!$mainWalletId) { return null; } $total = Transaction::query() ->where('wallet', $mainWalletId) ->where('customer_id', $customerId) ->where('product_id', $productId) ->where('type', 1) ->where('gold', '>', 0) ->sum('gold'); if ($total > 0) { $this->line('مقدار از تراکنش‌های خرید روی کیف اصلی تشخیص داده شد: ' . round((float) $total, 5) . ' گرم'); return round((float) $total, 5); } return null; } private function alreadyCorrected(int $customerId, int $productId, float $goldAmount): bool { $orderId = (int) ($this->option('order') ?? 0); $needle = $orderId > 0 ? "سفارش {$orderId}" : 'اصلاح موجودی'; $exists = Transaction::query() ->where('customer_id', $customerId) ->where('product_id', $productId) ->where('gold', '>=', $goldAmount - 0.00001) ->where('note', 'like', '%' . $needle . '%') ->where('title', 'like', '%واریز به کیف محصول%') ->exists(); return $exists; } }