diff --git a/app/Http/Controllers/Single/SingleOrderController.php b/app/Http/Controllers/Single/SingleOrderController.php index 9ec2bea..905b861 100644 --- a/app/Http/Controllers/Single/SingleOrderController.php +++ b/app/Http/Controllers/Single/SingleOrderController.php @@ -357,52 +357,50 @@ class SingleOrderController extends Controller throw new UnprocessableEntityHttpException('موجودی شما کمتر از میزان سفارش است'); } - $this->assertProviderOrderAccepted($data); - - $this->syncOrderProfitFields($data); - $data['order'] = $order = Order::create($data); + $order = $this->openOrderThenCoverWithProvider($data); $abshode = $this->resolveAbshodeProductContext($data); $productId = (int) ($data['product_id'] ?? $abshode['id'] ?? 0); $usesProductWallet = $productId > 0 && !$config->isMainWalletProduct($productId); - if ($usesProductWallet) { - new TransactionInterface($wallet_interface, [ - "cash" => $data['payment_amount'], - "product_id" => $productId, - 'expire_at' => now(), - 'active' => true, - 'order_id' => $order->id, - 'start_at' => now(), - 'title' => 'برداشت وجه نقد', - ], 12, false, false); - $wallet_interface_product = $this->productWalletInterface($productId); - $this->normalizeProductWalletGold($wallet_interface_product); - new TransactionInterface($wallet_interface_product, [ - "gold" => $data['amount'], - "product_id" => $productId, - 'expire_at' => now(), - 'active' => true, - 'order_id' => $order->id, - 'start_at' => now(), - 'title' => $this->meltedOrProductBuyTitle($data), - ], 1, true, false); - } else { - $buyTransaction = [ - "cash" => $data['payment_amount'], - "gold" => $data['amount'], - 'expire_at' => now(), - 'active' => true, - 'order_id' => $order->id, - 'start_at' => now(), - 'title' => $this->meltedOrProductBuyTitle($data), - ]; - if ($productId > 0) { - $buyTransaction['product_id'] = $productId; - $buyTransaction['note'] = 'product_id:' . $productId; + $this->runAfterProviderCover($order, $data, function () use (&$data, $wallet_interface, $productId, $usesProductWallet, $order) { + if ($usesProductWallet) { + new TransactionInterface($wallet_interface, [ + "cash" => $data['payment_amount'], + "product_id" => $productId, + 'expire_at' => now(), + 'active' => true, + 'order_id' => $order->id, + 'start_at' => now(), + 'title' => 'برداشت وجه نقد', + ], 12, false, false); + $wallet_interface_product = $this->productWalletInterface($productId); + $this->normalizeProductWalletGold($wallet_interface_product); + new TransactionInterface($wallet_interface_product, [ + "gold" => $data['amount'], + "product_id" => $productId, + 'expire_at' => now(), + 'active' => true, + 'order_id' => $order->id, + 'start_at' => now(), + 'title' => $this->meltedOrProductBuyTitle($data), + ], 1, true, false); + } else { + $buyTransaction = [ + "cash" => $data['payment_amount'], + "gold" => $data['amount'], + 'expire_at' => now(), + 'active' => true, + 'order_id' => $order->id, + 'start_at' => now(), + 'title' => $this->meltedOrProductBuyTitle($data), + ]; + if ($productId > 0) { + $buyTransaction['product_id'] = $productId; + $buyTransaction['note'] = 'product_id:' . $productId; + } + new TransactionInterface($wallet_interface, $buyTransaction, 1, true, false); } - new TransactionInterface($wallet_interface, $buyTransaction, 1, true, false); - } - $this->finalizeProviderOrder($data); + }); $response['1'] = 2; return $response; @@ -642,47 +640,45 @@ class SingleOrderController extends Controller throw new UnprocessableEntityHttpException($this->insufficientGoldBalanceMessage($data)); } - $this->assertProviderOrderAccepted($data); + $order = $this->openOrderThenCoverWithProvider($data); - $this->syncOrderProfitFields($data); - $data['order'] = $order = Order::create($data); - - if ($usesProductWallet) { - $this->normalizeProductWalletGold($wallet_interface_product); - new TransactionInterface($wallet_interface_product, [ - "gold" => $goldDebit, - "product_id" => $productId, - 'expire_at' => now(), - 'active' => true, - 'order_id' => $order->id, - 'start_at' => now(), - 'title' => $this->meltedOrProductSellTitle($data), - ], 1, false, false); - new TransactionInterface($wallet_interface, [ - "cash" => $data['total_price'], - "product_id" => $productId, - 'expire_at' => now(), - 'active' => true, - 'order_id' => $order->id, - 'start_at' => now(), - 'title' => 'واریز وجه نقد', - ], 12, false, true); - } else { - $sellTransaction = [ - "gold" => $goldDebit, - "cash" => $data['total_price'], - 'expire_at' => now(), - 'active' => true, - 'order_id' => $order->id, - 'title' => $this->meltedOrProductSellTitle($data), - ]; - if ($productId > 0) { - $sellTransaction['product_id'] = $productId; - $sellTransaction['note'] = 'product_id:' . $productId; + $this->runAfterProviderCover($order, $data, function () use (&$data, $wallet_interface, $wallet_interface_product, $productId, $usesProductWallet, $goldDebit, $order) { + if ($usesProductWallet) { + $this->normalizeProductWalletGold($wallet_interface_product); + new TransactionInterface($wallet_interface_product, [ + "gold" => $goldDebit, + "product_id" => $productId, + 'expire_at' => now(), + 'active' => true, + 'order_id' => $order->id, + 'start_at' => now(), + 'title' => $this->meltedOrProductSellTitle($data), + ], 1, false, false); + new TransactionInterface($wallet_interface, [ + "cash" => $data['total_price'], + "product_id" => $productId, + 'expire_at' => now(), + 'active' => true, + 'order_id' => $order->id, + 'start_at' => now(), + 'title' => 'واریز وجه نقد', + ], 12, false, true); + } else { + $sellTransaction = [ + "gold" => $goldDebit, + "cash" => $data['total_price'], + 'expire_at' => now(), + 'active' => true, + 'order_id' => $order->id, + 'title' => $this->meltedOrProductSellTitle($data), + ]; + if ($productId > 0) { + $sellTransaction['product_id'] = $productId; + $sellTransaction['note'] = 'product_id:' . $productId; + } + new TransactionInterface($wallet_interface, $sellTransaction, 2, false, true); } - new TransactionInterface($wallet_interface, $sellTransaction, 2, false, true); - } - $this->finalizeProviderOrder($data); + }); } private function processSellTransactionProduct(&$data, $wallet, $wallet_interface) @@ -1034,11 +1030,92 @@ class SingleOrderController extends Controller return; } - $this->assertNoRecentDuplicateLocalOrder($data); + if (!isset($data['order'])) { + $this->assertNoRecentDuplicateLocalOrder($data); + } $data['_montzar_parsed'] = app(MontzarService::class)->submitOrder($data); } + /** + * اول رکورد محلی (در انتظار همکار)، بعد ارسال به لیمان، بعد کیف. + * اگر همکار رد کند یا کیف بترکد، همان رکورد با وضعیت ناموفق و شرح خطا می‌ماند. + */ + private function openOrderThenCoverWithProvider(array &$data): Order + { + $this->syncOrderProfitFields($data); + $montzar = app(ConfigService::class)->usesMontzarPricing(); + if ($montzar) { + $this->assertNoRecentDuplicateLocalOrder($data); + $data['sts'] = 4; + $data['payment_sts'] = 1; + $this->stampColleagueQuoteOnOrderData($data); + } + + $order = Order::create($data); + $data['order'] = $order; + + if ($montzar) { + try { + $this->assertProviderOrderAccepted($data); + $this->finalizeProviderOrder($data); + $order->refresh(); + } catch (\Throwable $e) { + $this->markOrderFailed($order, $e->getMessage()); + throw $e instanceof UnprocessableEntityHttpException + ? $e + : new UnprocessableEntityHttpException( + $e->getMessage() !== '' ? $e->getMessage() : 'ارسال سفارش به همکار ناموفق بود' + ); + } + } + + return $order; + } + + private function runAfterProviderCover(Order $order, array &$data, callable $walletFn): void + { + try { + $walletFn(); + $this->markOrderSucceeded($order); + } catch (\Throwable $e) { + $this->markOrderFailed($order, $e->getMessage()); + throw $e instanceof UnprocessableEntityHttpException + ? $e + : new UnprocessableEntityHttpException( + $e->getMessage() !== '' ? $e->getMessage() : 'ثبت کیف پس از ارسال به همکار ناموفق بود' + ); + } + } + + private function stampColleagueQuoteOnOrderData(array &$data): void + { + $config = app(ConfigService::class); + $live = (float) $config->get('montzar_live_price', 0); + $diff = (float) $config->get('montzar_diff', 0); + $unit = ((int) ($data['direction'] ?? 0) === 1) + ? ($live + $diff) + : ($live - $diff); + $data['total_price_montzar'] = $unit > 0 ? $unit : 0; + } + + private function markOrderSucceeded(Order $order): void + { + $order->sts = 2; + $order->payment_sts = 4; + $order->description = null; + $order->save(); + } + + private function markOrderFailed(Order $order, string $message): void + { + $order->sts = 3; + $order->payment_sts = 7; + $trimmed = trim($message); + $order->description = $trimmed !== '' ? mb_substr($trimmed, 0, 1000) : 'ناموفق'; + $order->save(); + } + private function finalizeProviderOrder(array &$data): void { if (!app(ConfigService::class)->usesMontzarPricing()) { @@ -1067,6 +1144,7 @@ class SingleOrderController extends Controller $duplicate = Order::where('customer_id', $customerId) ->where('direction', $direction) + ->whereIn('sts', [2, 4]) ->where('created_at', '>=', now()->subSeconds($windowSeconds)) ->whereRaw('ROUND(amount, 6) = ?', [$amount]) ->exists(); diff --git a/app/Models/Order.php b/app/Models/Order.php index 4c019e8..5a39676 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -37,6 +37,9 @@ class Order extends Model 'type',//نوع مشتری 'pay_at',//تاریخ انجام معامله در پنل ادمین 'price_id',// + 'provider_id', + 'total_price_montzar', + 'description', ]; protected $casts = [ @@ -46,7 +49,8 @@ class Order extends Model static $STS = [ 1 => 'باز', 2 => 'موفق', - 3 => 'ناموفق' + 3 => 'ناموفق', + 4 => 'در انتظار همکار', ]; static $DIRECTION = [ 1 => 'خرید',