From dec13e85379c2df78075030ac28ed5c7ea5b2f6d Mon Sep 17 00:00:00 2001 From: adonis Date: Sun, 28 Jun 2026 10:46:09 +0330 Subject: [PATCH] fixed price --- .../Single/SingleOrderController.php | 29 +++++------ .../Controllers/Site/ReportController.php | 7 ++- app/Services/ConfigService.php | 44 +++++++++++++++-- app/Services/ProductDisplayPriceService.php | 48 +++++++++++++++++++ 4 files changed, 106 insertions(+), 22 deletions(-) diff --git a/app/Http/Controllers/Single/SingleOrderController.php b/app/Http/Controllers/Single/SingleOrderController.php index d4a36f0..bc9a91e 100644 --- a/app/Http/Controllers/Single/SingleOrderController.php +++ b/app/Http/Controllers/Single/SingleOrderController.php @@ -25,6 +25,7 @@ use App\Models\Setting; use App\Models\Cnt; use App\Services\MontzarService; use App\Services\ConfigService; +use App\Services\ProductDisplayPriceService; use App\Services\WalletBroadcastService; @@ -43,21 +44,9 @@ class SingleOrderController extends Controller } $config = app(ConfigService::class); - $toBool = function ($value) { - return filter_var($value, FILTER_VALIDATE_BOOLEAN); - }; - $config->assertTradingOpen(); - if ($config->usesMontzarPricing()) { - $montzar_closed = $toBool($config->Config('montzar_closed')); - $montzar_buy = !$toBool($config->Config('montzar_open_buy')) && (int) $data['direction'] === 1; - $montzar_sell = !$toBool($config->Config('montzar_open_sell')) && (int) $data['direction'] === 2; - - if ($montzar_closed || $montzar_buy || $montzar_sell) { - throw new UnprocessableEntityHttpException('عدم ارائه سرویس.'); - } - } + $config->assertMontzarOrderAllowed((int) ($data['direction'] ?? 0)); // throw new UnprocessableEntityHttpException('به دلیل نوسانات سفارشات بسته میباشد.'); $transactionType = $data['direction'] == 1 ? "خرید" : "فروش"; @@ -76,17 +65,23 @@ class SingleOrderController extends Controller if (auth('customer')->id()) { $data['customer_id'] = auth('customer')->id(); - $latestPrice = Price::latest()->first(); - if (!$latestPrice || $latestPrice->price == 0) { + $orderProductId = (int) ($data['abshode_id'] ?? $data['product_id'] ?? $config->mainProductId() ?? 0); + $orderProduct = $orderProductId > 0 ? Product::find($orderProductId) : null; + + $basePrice = app(ProductDisplayPriceService::class)->resolveOrderBasePrice($orderProduct); + + if ($basePrice <= 0) { if ($config->isOutsideTradingHours()) { throw new UnprocessableEntityHttpException($config->tradingClosedMessage()); } throw new UnprocessableEntityHttpException('عدم ارائه سرویس.'); } + + $latestPrice = Price::latest()->first(); $data['all_price'] = $latestPrice; - $data['price'] = $latestPrice->price; - $data['price_id'] = $latestPrice->id; + $data['price'] = $basePrice; + $data['price_id'] = $latestPrice?->id; $feeCash = Setting::where('key', 'fee_cash')->first(); $feeServiceCharge = Setting::where('key', 'fee_service_charge_percentage')->first(); if (!$feeCash || !$feeServiceCharge) { diff --git a/app/Http/Controllers/Site/ReportController.php b/app/Http/Controllers/Site/ReportController.php index 3122144..7163722 100644 --- a/app/Http/Controllers/Site/ReportController.php +++ b/app/Http/Controllers/Site/ReportController.php @@ -318,7 +318,10 @@ class ReportController extends Controller 'montzar_response' => $montzar ?? null, ]); - $config->UpdateConfig('montzar_closed', 'true'); + $config->applyMontzarSyncFailure(); + if (!$config->getBool('montzar_closed', true)) { + $montzar_price = $config->getInt('montzar_live_price', 0); + } } } @@ -542,7 +545,7 @@ class ReportController extends Controller $config->UpdateConfig('montzar_closed', $montzar === 0 ? 'true' : 'false'); } catch (\Throwable $e) { $montzar = 0; - $config->UpdateConfig('montzar_closed', 'true'); + $config->applyMontzarSyncFailure(); \Log::error('STORE MONZAR PRICE ERROR', ['message' => $e->getMessage()]); } } diff --git a/app/Services/ConfigService.php b/app/Services/ConfigService.php index c060f63..ac7f16c 100644 --- a/app/Services/ConfigService.php +++ b/app/Services/ConfigService.php @@ -487,11 +487,49 @@ class ConfigService $closed = $this->isOutsideTradingHours($now); Cnt::where('key', 'app_closed')->update(['value' => $closed ? 'true' : 'false']); - if ($closed) { - $this->UpdateConfig('montzar_closed', 'true'); + return $closed; + } + + /** + * montzar_closed فقط وضعیت sync زنده است — نباید به‌تنهایی سفارش را ببندد. + * اگر sync خطا داد ولی montzar_live_price و open_buy/sell معتبرند، معامله باز بماند. + */ + public function applyMontzarSyncFailure(): void + { + $staleLive = $this->getInt('montzar_live_price', 0); + $stillOpen = $this->getBool('montzar_open_buy', false) + || $this->getBool('montzar_open_sell', false); + + $this->UpdateConfig( + 'montzar_closed', + ($staleLive > 0 && $stillOpen) ? 'false' : 'true' + ); + } + + public function assertMontzarOrderAllowed(int $direction): void + { + if (!$this->usesMontzarPricing()) { + return; } - return $closed; + $direction = (int) $direction; + $openBuy = $this->getBool('montzar_open_buy', true); + $openSell = $this->getBool('montzar_open_sell', true); + + if ($direction === 1 && !$openBuy) { + throw new UnprocessableEntityHttpException('عدم ارائه سرویس.'); + } + + if ($direction === 2 && !$openSell) { + throw new UnprocessableEntityHttpException('عدم ارائه سرویس.'); + } + + if ($this->getBool('montzar_closed', false)) { + $basePrice = app(ProductDisplayPriceService::class)->resolveOrderBasePrice(); + if ($basePrice <= 0) { + throw new UnprocessableEntityHttpException('عدم ارائه سرویس.'); + } + } } public function formatTradingTimeForDisplay(string $time): string diff --git a/app/Services/ProductDisplayPriceService.php b/app/Services/ProductDisplayPriceService.php index e5155f5..7bbae05 100644 --- a/app/Services/ProductDisplayPriceService.php +++ b/app/Services/ProductDisplayPriceService.php @@ -360,6 +360,54 @@ class ProductDisplayPriceService return $this->extractBaseFromPayload($this->livePricePayload()); } + /** قیمت پایه سفارش — همان منبع نمایش اپ (کش / montzar_live_price / prices) */ + public function resolveOrderBasePrice(?Product $product = null): int + { + $this->warmLivePriceCache(); + + if ($product instanceof Product) { + if ($this->usesAppPrice($product)) { + $useLast = $this->productUsesLastPriceIfZero($product); + $base = $useLast + ? $this->resolveAppBasePrice() + : $this->resolveStrictLiveAppBasePrice(); + + if ($base <= 0 && $useLast) { + return $this->resolveLastPriceFallback($product); + } + + if ($base <= 0) { + return 0; + } + + $offset = Product::hasPriceOffsetColumn() + ? (float) ($product->price_offset_percent ?? 0) + : 0.0; + + return ProductPriceService::adjustedTotal($base, 0, $offset); + } + + if ($product->reading_method) { + $this->enrichForApi(collect([$product])); + $unit = (int) (($product->price ?? 0) + ($product->price_profit ?? 0)); + if ($unit > 0) { + return $unit; + } + } + + if ((int) ($product->direct_price ?? 0) === 1) { + return (int) (($product->price ?? 0) + ($product->price_profit ?? 0)); + } + } + + $base = $this->resolveAppBasePrice(); + if ($base > 0) { + return $base; + } + + return $this->resolveHistoricalBasePrice(); + } + /** @param array $payload */ private function extractBaseFromPayload(array $payload): int {