From 37a54e07647a0757e566d8ad81406175422c065e Mon Sep 17 00:00:00 2001 From: adonis Date: Sat, 27 Jun 2026 11:29:09 +0330 Subject: [PATCH] fixed provider price 2 --- .../Site/PriceStreamController.php | 2 +- app/Services/PriceBroadcastService.php | 1 + app/Services/ProductDisplayPriceService.php | 12 +- tests/Unit/ProductDisplayPriceServiceTest.php | 158 ++++++++++++++++++ 4 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/ProductDisplayPriceServiceTest.php diff --git a/app/Http/Controllers/Site/PriceStreamController.php b/app/Http/Controllers/Site/PriceStreamController.php index f1a6912..c4afcd6 100644 --- a/app/Http/Controllers/Site/PriceStreamController.php +++ b/app/Http/Controllers/Site/PriceStreamController.php @@ -45,7 +45,7 @@ class PriceStreamController extends Controller $send('last', $last); } - $list = app(PriceBroadcastService::class)->buildListPayload(true); + $list = app(PriceBroadcastService::class)->buildListPayload(false); if (is_array($list) && $list !== []) { $send('list', $list); } diff --git a/app/Services/PriceBroadcastService.php b/app/Services/PriceBroadcastService.php index 9c5de66..7687363 100644 --- a/app/Services/PriceBroadcastService.php +++ b/app/Services/PriceBroadcastService.php @@ -169,6 +169,7 @@ class PriceBroadcastService 'price_profit' => (int) ($product['price_profit'] ?? 0), 'show' => (bool) ($product['show'] ?? true), 'active' => (bool) ($product['active'] ?? true), + 'reference_provider_active' => (bool) ($product['reference_provider_active'] ?? false), ]; } diff --git a/app/Services/ProductDisplayPriceService.php b/app/Services/ProductDisplayPriceService.php index b1952fa..e5155f5 100644 --- a/app/Services/ProductDisplayPriceService.php +++ b/app/Services/ProductDisplayPriceService.php @@ -9,10 +9,10 @@ use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Schema; /** - * قیمت نمایشی محصولات برای API — فقط از کش/تنظیمات (بدون HTTP روی list). + * قیمت نمایشی محصولات برای API. * * • آبشده با «قیمت اپ» → montzar_live_price / کش /api/price/last - * • محصول با reading_method → ردیف فید zaarbox از کش کران (۳۰ث) + * • محصول با reading_method → فید zaarbox (کش ۱۵ث + fetch روی cache miss) */ class ProductDisplayPriceService { @@ -51,12 +51,16 @@ class ProductDisplayPriceService /** * پر کردن price روی مدل‌ها برای پاسخ JSON — بدون UPDATE دیتابیس */ - /** پر کردن کش مظنه اگر خالی باشد (قبل از enrich لیست مشتری) */ + /** پر کردن کش مظنه و فید zaarbox اگر خالی باشند (قبل از enrich لیست مشتری) */ public function warmLivePriceCache(): void { if (! is_array(Cache::get(self::LIVE_PRICE_CACHE_KEY))) { $this->resolveFallbackPayload(); } + + if (! app(ConfigService::class)->isStore()) { + app(ZaarboxPriceService::class)->cachedPriceList(false); + } } public function enrichForApi(Collection|iterable $products): void @@ -438,7 +442,7 @@ class ProductDisplayPriceService return 0; } - $feed = app(ZaarboxPriceService::class)->getCachedPriceListOnly(); + $feed = app(ZaarboxPriceService::class)->cachedPriceList(false); if (!is_array($feed)) { return 0; } diff --git a/tests/Unit/ProductDisplayPriceServiceTest.php b/tests/Unit/ProductDisplayPriceServiceTest.php new file mode 100644 index 0000000..6669ec2 --- /dev/null +++ b/tests/Unit/ProductDisplayPriceServiceTest.php @@ -0,0 +1,158 @@ +mock(ConfigService::class, function ($mock) { + $mock->shouldReceive('isStore')->andReturn(false); + }); + + $row = [ + 'key' => 'tala18', + 'name' => 'گرم ۱۸ tala.ir', + 'price' => 165_000_000, + 'profit' => 58_400, + ]; + $feed = [$row]; + + $this->mock(ZaarboxPriceService::class, function ($mock) use ($feed, $row) { + $mock->shouldReceive('cachedPriceList')->with(false)->once()->andReturn($feed); + $mock->shouldReceive('findFeedRow')->with($feed, 'tala18')->andReturn($row); + $mock->shouldReceive('resolveReferenceProviderTotal')->with($row)->andReturn(165_058_400); + $mock->shouldReceive('computeAdjustedProductPrice')->andReturn(165_058_400); + }); + + $product = new Product([ + 'id' => 13, + 'reading_method' => 'tala18', + 'use_last_price_if_zero' => false, + 'price' => 0, + 'active' => true, + ]); + + app(ProductDisplayPriceService::class)->enrichForApi(collect([$product])); + + $this->assertSame(165_058_400, (int) $product->price); + $this->assertTrue($product->getAttribute('reference_provider_active')); + } + + public function test_reference_product_with_zero_provider_and_toggle_off_stays_unpriced(): void + { + $this->mock(ConfigService::class, function ($mock) { + $mock->shouldReceive('isStore')->andReturn(false); + }); + + $row = [ + 'key' => 'tala18', + 'name' => 'گرم ۱۸ tala.ir', + 'price' => 0, + 'profit' => 58_400, + ]; + $feed = [$row]; + + $this->mock(ZaarboxPriceService::class, function ($mock) use ($feed, $row) { + $mock->shouldReceive('cachedPriceList')->with(false)->once()->andReturn($feed); + $mock->shouldReceive('findFeedRow')->with($feed, 'tala18')->andReturn($row); + $mock->shouldReceive('resolveReferenceProviderTotal')->with($row)->andReturn(0); + }); + + $product = new Product([ + 'id' => 13, + 'reading_method' => 'tala18', + 'use_last_price_if_zero' => false, + 'price' => 99_000_000, + 'active' => true, + ]); + + $service = app(ProductDisplayPriceService::class); + $service->enrichForApi(collect([$product])); + + $this->assertSame(0, (int) $product->price); + $this->assertFalse($product->getAttribute('reference_provider_active')); + $this->assertFalse($service->resolveCustomerShow($product)); + } + + public function test_reference_product_with_zero_provider_and_toggle_on_uses_stored_fallback(): void + { + if (! Product::hasUseLastPriceIfZeroColumn()) { + $this->markTestSkipped('use_last_price_if_zero column not present'); + } + + $this->mock(ConfigService::class, function ($mock) { + $mock->shouldReceive('isStore')->andReturn(false); + $mock->shouldReceive('isProductWithinTradingHours')->andReturn(true); + $mock->shouldReceive('getBool')->with('show_last_price', false)->andReturn(false); + }); + + $row = [ + 'key' => 'tala18', + 'name' => 'گرم ۱۸ tala.ir', + 'price' => 0, + 'profit' => 0, + ]; + $feed = [$row]; + + $this->mock(ZaarboxPriceService::class, function ($mock) use ($feed, $row) { + $mock->shouldReceive('cachedPriceList')->with(false)->once()->andReturn($feed); + $mock->shouldReceive('findFeedRow')->with($feed, 'tala18')->andReturn($row); + $mock->shouldReceive('resolveReferenceProviderTotal')->with($row)->andReturn(0); + $mock->shouldReceive('computeAdjustedProductPrice')->andReturn(0); + }); + + $product = new Product([ + 'id' => 13, + 'reading_method' => 'tala18', + 'use_last_price_if_zero' => true, + 'price' => 150_000_000, + 'active' => true, + ]); + + $service = app(ProductDisplayPriceService::class); + $service->enrichForApi(collect([$product])); + + $this->assertSame(150_000_000, (int) $product->price); + $this->assertTrue($product->getAttribute('reference_provider_active')); + $this->assertTrue($service->resolveCustomerShow($product)); + } + + public function test_missing_feed_with_toggle_off_zeros_reference_product(): void + { + $this->mock(ConfigService::class, function ($mock) { + $mock->shouldReceive('isStore')->andReturn(false); + }); + + $this->mock(ZaarboxPriceService::class, function ($mock) { + $mock->shouldReceive('cachedPriceList')->with(false)->once()->andReturn(null); + }); + + $product = new Product([ + 'id' => 13, + 'reading_method' => 'tala18', + 'use_last_price_if_zero' => false, + 'price' => 120_000_000, + 'active' => true, + ]); + + app(ProductDisplayPriceService::class)->enrichForApi(collect([$product])); + + $this->assertSame(0, (int) $product->price); + $this->assertFalse($product->getAttribute('reference_provider_active')); + } +}