Files
boursecu_server/app/Console/Commands/FixMisplacedProductGoldCommand.php
T

263 lines
10 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\Order;
use App\Models\Product;
use App\Models\Withdraw;
use App\Services\ConfigService;
use App\Services\WalletBroadcastService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Rooyesh\Wallet\interfaces\TransactionInterface;
use Rooyesh\Wallet\interfaces\WalletInterface;
use Rooyesh\Wallet\models\Transaction;
use Rooyesh\Wallet\models\Wallet;
class FixMisplacedProductGoldCommand extends Command
{
protected $signature = 'wallet:fix-misplaced-product-gold
{--customer= : شناسه مشتری}
{--product= : شناسه محصول (مثلاً 40 برای آبشده سرمایه‌گذاری)}
{--gold= : مقدار طلا به گرم (اختیاری)}
{--order= : شناسه سفارش برای تشخیص خودکار مقدار}
{--transaction= : شناسه تراکنش برای تشخیص خودکار مقدار}
{--execute : اجرای واقعی (بدون این فلگ فقط پیش‌نمایش است)}';
protected $description = 'انتقال طلای اشتباهی‌نشسته در کیف اصلی به کیف محصول (باگ abshode_id بدون product_id)';
public function handle(ConfigService $configService): int
{
$customerId = (int) $this->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;
}
}