From b021acde56d7601fcc1349a0df35580fd2c1f457 Mon Sep 17 00:00:00 2001 From: adonis Date: Sun, 14 Jun 2026 22:00:21 +0330 Subject: [PATCH] fix bug --- .../Controllers/Admin/ProductController.php | 15 +-- .../Controllers/Customer/CartController.php | 2 + .../Single/SingleOrderController.php | 12 ++- app/Services/ConfigService.php | 95 ++++++++++++++++++- app/Services/ProductDisplayPriceService.php | 6 +- app/Services/ProductPriceSyncService.php | 2 +- app/Services/ZaarboxPriceService.php | 2 +- 7 files changed, 119 insertions(+), 15 deletions(-) diff --git a/app/Http/Controllers/Admin/ProductController.php b/app/Http/Controllers/Admin/ProductController.php index dfda3c9..2e855a8 100644 --- a/app/Http/Controllers/Admin/ProductController.php +++ b/app/Http/Controllers/Admin/ProductController.php @@ -207,9 +207,7 @@ class ProductController extends SuperController $displayPriceService->warmLivePriceCache(); $displayPriceService->enrichForApi($products); $products->each(function (Product $product) use ($displayPriceService) { - if (! $displayPriceService->hasCustomerDisplayPrice($product)) { - $product->setAttribute('show', false); - } + $product->setAttribute('show', $displayPriceService->resolveCustomerShow($product)); }); } @@ -257,12 +255,11 @@ class ProductController extends SuperController public function auto_close_open() { + $config = app(ConfigService::class); $products = Product::with([])->get(); - $current_time = now()->format('H:i:s'); foreach ($products as $product) { - $show = ($current_time >= $product->auto_open_at && $current_time <= $product->auto_close_at); Product::where('id', $product->id)->update([ - 'show' => $show, + 'show' => $config->isProductWithinTradingHours($product), ]); } @@ -358,13 +355,17 @@ class ProductController extends SuperController } - /** فروشگاه — نمایش در اپ کاربر: فعال + قیمت ذخیره‌شده یا محصول وزنی */ + /** فروشگاه — نمایش در اپ کاربر: فعال + ساعات + قیمت ذخیره‌شده یا محصول وزنی */ private function storeProductShowForCustomer(Product $product): bool { if (! $product->active) { return false; } + if (! app(ConfigService::class)->isProductWithinTradingHours($product)) { + return false; + } + $storedPrice = (int) ($product->price ?? 0) + (int) ($product->price_profit ?? 0); if ($storedPrice > 0) { return true; diff --git a/app/Http/Controllers/Customer/CartController.php b/app/Http/Controllers/Customer/CartController.php index 10fbc69..104090b 100644 --- a/app/Http/Controllers/Customer/CartController.php +++ b/app/Http/Controllers/Customer/CartController.php @@ -364,6 +364,8 @@ class CartController extends Controller throw new UnprocessableEntityHttpException("خرید {$product->title} در این لحظه مقدور نیست."); } + app(ConfigService::class)->assertProductTradingOpen($product); + $line = $requestLines->get($item->product_id); $qty = (int) $item->quantity; diff --git a/app/Http/Controllers/Single/SingleOrderController.php b/app/Http/Controllers/Single/SingleOrderController.php index 00b3a68..58a87ba 100644 --- a/app/Http/Controllers/Single/SingleOrderController.php +++ b/app/Http/Controllers/Single/SingleOrderController.php @@ -42,6 +42,8 @@ class SingleOrderController extends Controller 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; @@ -52,10 +54,6 @@ class SingleOrderController extends Controller } } - if ($toBool($config->Config('close_price'))) { - $config->assertTradingOpen(); - } - // throw new UnprocessableEntityHttpException('به دلیل نوسانات سفارشات بسته میباشد.'); $transactionType = $data['direction'] == 1 ? "خرید" : "فروش"; $customer = Customer::find(auth('customer')->id() ?? ($data['customer_id'] ?? null)); @@ -76,6 +74,9 @@ class SingleOrderController extends Controller $latestPrice = Price::latest()->first(); if (!$latestPrice || $latestPrice->price == 0) { + if ($config->isOutsideTradingHours()) { + throw new UnprocessableEntityHttpException($config->tradingClosedMessage()); + } throw new UnprocessableEntityHttpException('عدم ارائه سرویس.'); } $data['all_price'] = $latestPrice; @@ -120,6 +121,8 @@ class SingleOrderController extends Controller // Check if the user wants to transact with a product or non-product (gold) if (isset($data['product_id']) and $data['product'] = Product::find($data['product_id'])) { + $config->assertProductTradingOpen($data['product']); + // Check if the user wants to buy if ($data['direction'] == 1) { @@ -166,6 +169,7 @@ class SingleOrderController extends Controller if (!$data['product']) { throw new UnprocessableEntityHttpException('محصول آبشده یافت نشد.'); } + $config->assertProductTradingOpen($data['product']); if ($data['direction'] == 1) { $data['difference'] = $this->resolveCashSpread($config, $data['product'], 1); $data['service_charge_percentage'] = $data['product']['percent_fee_buy']; diff --git a/app/Services/ConfigService.php b/app/Services/ConfigService.php index 534dd95..ef81150 100644 --- a/app/Services/ConfigService.php +++ b/app/Services/ConfigService.php @@ -457,10 +457,103 @@ class ConfigService return $closed; } + public function formatTradingTimeForDisplay(string $time): string + { + $normalized = $this->normalizeTradingTime($time, '00:00'); + + return $normalized . ':00'; + } + + public function tradingClosedMessage(?Carbon $now = null): string + { + $bounds = $this->tradingHourBounds(); + $start = $this->formatTradingTimeForDisplay($bounds['start']); + $end = $this->formatTradingTimeForDisplay($bounds['end']); + + return "فروشگاه در حال حاضر بسته است. ساعت کاری از {$start} تا {$end} می‌باشد."; + } + public function assertTradingOpen(?Carbon $now = null): void { if ($this->isOutsideTradingHours($now)) { - throw new UnprocessableEntityHttpException('فروشگاه در حال حاضر بسته است.'); + throw new UnprocessableEntityHttpException($this->tradingClosedMessage($now)); + } + } + + public function hasProductTradingWindow(?string $open, ?string $close): bool + { + if ($open === null || $close === null || trim($open) === '' || trim($close) === '') { + return false; + } + + return $this->formatProductTime($open) !== $this->formatProductTime($close); + } + + public function formatProductTime(?string $time): string + { + if ($time === null || trim($time) === '') { + return '00:00:00'; + } + + $time = trim($time); + if (preg_match('/(\d{1,2}:\d{2}(?::\d{2})?)/', $time, $matches)) { + $parts = explode(':', $matches[1]); + + return sprintf( + '%02d:%02d:%02d', + (int) ($parts[0] ?? 0), + (int) ($parts[1] ?? 0), + (int) ($parts[2] ?? 0) + ); + } + + return '00:00:00'; + } + + public function isWithinTimeWindow(?string $open, ?string $close, ?Carbon $now = null): bool + { + if (!$this->hasProductTradingWindow($open, $close)) { + return true; + } + + $now = $now ?? Carbon::now(); + $current = $now->format('H:i:s'); + $openStr = $this->formatProductTime($open); + $closeStr = $this->formatProductTime($close); + + return $current >= $openStr && $current <= $closeStr; + } + + /** ساعت کاری سراسری (close_price) + بازه auto_open_at/auto_close_at هر محصول */ + public function isProductWithinTradingHours(Product $product, ?Carbon $now = null): bool + { + if ($this->isClosePriceEnabled() && $this->isOutsideTradingHours($now)) { + return false; + } + + return $this->isWithinTimeWindow($product->auto_open_at, $product->auto_close_at, $now); + } + + public function productTradingClosedMessage(Product $product): string + { + $title = trim((string) ($product->title ?? 'محصول')); + + if ($this->hasProductTradingWindow($product->auto_open_at, $product->auto_close_at)) { + $open = $this->formatProductTime($product->auto_open_at); + $close = $this->formatProductTime($product->auto_close_at); + + return "محصول «{$title}» در حال حاضر بسته است. ساعت فعال‌سازی از {$open} تا {$close} می‌باشد."; + } + + return $this->tradingClosedMessage(); + } + + public function assertProductTradingOpen(Product $product, ?Carbon $now = null): void + { + $this->assertTradingOpen($now); + + if (!$this->isProductWithinTradingHours($product, $now)) { + throw new UnprocessableEntityHttpException($this->productTradingClosedMessage($product)); } } } diff --git a/app/Services/ProductDisplayPriceService.php b/app/Services/ProductDisplayPriceService.php index a1ad5d5..e8060ec 100644 --- a/app/Services/ProductDisplayPriceService.php +++ b/app/Services/ProductDisplayPriceService.php @@ -462,7 +462,11 @@ class ProductDisplayPriceService */ public function resolveCustomerShow(Product $product): bool { - if (! (bool) ($product->show ?? true)) { + if (! (bool) ($product->active ?? true)) { + return false; + } + + if (! app(ConfigService::class)->isProductWithinTradingHours($product)) { return false; } diff --git a/app/Services/ProductPriceSyncService.php b/app/Services/ProductPriceSyncService.php index 6e7a603..e750b93 100644 --- a/app/Services/ProductPriceSyncService.php +++ b/app/Services/ProductPriceSyncService.php @@ -178,7 +178,7 @@ class ProductPriceSyncService $synced = false; foreach ($products as $product) { - $show = ($currentTime >= $product->auto_open_at && $currentTime <= $product->auto_close_at); + $show = app(ConfigService::class)->isProductWithinTradingHours($product); foreach ($RPrices as $RPrice) { if ($product->reading_method == ($RPrice['name'] ?? null)) { diff --git a/app/Services/ZaarboxPriceService.php b/app/Services/ZaarboxPriceService.php index 21d6032..d264c14 100644 --- a/app/Services/ZaarboxPriceService.php +++ b/app/Services/ZaarboxPriceService.php @@ -349,7 +349,7 @@ class ZaarboxPriceService $liquidGoldPrice = app(ProductDisplayPriceService::class)->resolveAppBasePrice(); $p = Product::find($product->id); if ($p && $liquidGoldPrice > 0) { - $show = ($currentTime >= $product->auto_open_at && $currentTime <= $product->auto_close_at); + $show = app(ConfigService::class)->isProductWithinTradingHours($product); $p->amount = $row['price'] / $liquidGoldPrice; $p->show = $show; $p->save();