diff --git a/app/Http/Controllers/Single/SingleOrderController.php b/app/Http/Controllers/Single/SingleOrderController.php index 2e8418d..32b5cbb 100644 --- a/app/Http/Controllers/Single/SingleOrderController.php +++ b/app/Http/Controllers/Single/SingleOrderController.php @@ -66,7 +66,11 @@ class SingleOrderController extends Controller $orderProductId = (int) ($data['abshode_id'] ?? $data['product_id'] ?? $config->mainProductId() ?? 0); $orderProduct = $orderProductId > 0 ? Product::find($orderProductId) : null; - $basePrice = app(ProductDisplayPriceService::class)->resolveOrderBasePrice($orderProduct); + $orderDirection = isset($data['direction']) ? (int) $data['direction'] : null; + + // پایه وسطِ نرخ خرید/فروش همکار است — سفارش با همان سمتی حساب شود که با همکار معامله می‌کنیم + $basePrice = app(ProductDisplayPriceService::class) + ->resolveOrderTradePrice($orderProduct, $orderDirection); if ($basePrice <= 0) { if ($config->isOutsideTradingHours()) { @@ -79,7 +83,7 @@ class SingleOrderController extends Controller $data['all_price'] = $latestPrice; $data['price'] = $basePrice; $data['price_id'] = $latestPrice?->id; - $data['difference'] = $config->orderPriceDiffRial(isset($data['direction']) ? (int) $data['direction'] : null); + $data['difference'] = $config->orderPriceDiffRial($orderDirection); $data['service_charge_percentage'] = $config->orderServiceChargePercentage(); $fee_free = Setting::where('key', 'fee_free')->where('is_active', true)->value('value'); @@ -125,7 +129,7 @@ class SingleOrderController extends Controller if (!empty($data['fee_free'])) { $data['service_charge_percentage'] = 0; } - $data['price_original'] = $this->resolveProductUnitBasePrice($data['product']); + $data['price_original'] = $this->resolveProductUnitBasePrice($data['product'], 1); $this->applyCashPriceDiff($config, $data['product'], 1, $data, (float) $data['price_original']); $data['total_fee'] = $data['number'] * $data['fee']; $data['total_price_original'] = $this->resolveProductOrderPricingAmount($data['product'], 1.0) @@ -146,7 +150,7 @@ class SingleOrderController extends Controller if (!empty($data['fee_free'])) { $data['service_charge_percentage'] = 0; } - $data['price_original'] = $this->resolveProductUnitBasePrice($data['product']); + $data['price_original'] = $this->resolveProductUnitBasePrice($data['product'], 2); $this->applyCashPriceDiff($config, $data['product'], 2, $data, (float) $data['price_original']); $data['total_fee'] = $data['number'] * $data['fee']; $data['total_price_original'] = $this->resolveProductOrderPricingAmount($data['product'], 1.0) @@ -1382,7 +1386,7 @@ class SingleOrderController extends Controller $base = (float) ($basePriceRial ?? 0); if ($base <= 0) { - $base = (float) $this->resolveProductUnitBasePrice($product); + $base = (float) $this->resolveProductUnitBasePrice($product, $direction); } if ($base <= 0) { $base = ProductPriceService::productBasePriceRial($product); @@ -1510,13 +1514,13 @@ class SingleOrderController extends Controller * - reading_method (مثل شمش zaarbox) → همان قیمت enrichشدهٔ لیست/UI، نه ستون کهنه/صفر DB * - بقیه → قیمت ذخیره‌شدهٔ محصول */ - private function resolveProductUnitBasePrice(Product $product): int + private function resolveProductUnitBasePrice(Product $product, ?int $direction = null): int { $display = app(ProductDisplayPriceService::class); // قیمت اپ یا فید مرجع — همان منبع نمایش؛ DB خام برای reading_method اغلب ۰/کهنه است if ($display->usesAppPrice($product) || $product->reading_method) { - return (int) round($display->resolveOrderBasePrice($product)); + return (int) round($display->resolveOrderTradePrice($product, $direction)); } return (int) (($product->price ?? 0) + ($product->price_profit ?? 0)); diff --git a/app/Services/ConditionalOrderService.php b/app/Services/ConditionalOrderService.php index a445f6d..543f69c 100644 --- a/app/Services/ConditionalOrderService.php +++ b/app/Services/ConditionalOrderService.php @@ -74,7 +74,7 @@ class ConditionalOrderService } $display = app(ProductDisplayPriceService::class); - $currentPrice = $this->resolveComparePrice($product, $liquidPrice, $display); + $currentPrice = $this->resolveComparePrice($product, $liquidPrice, $display, $config, (int) $order->direction); if ($currentPrice <= 0 || ! $order->conditionMet($currentPrice)) { return; } @@ -89,12 +89,20 @@ class ConditionalOrderService $this->executeOrder($order, $product, $currentPrice); } - private function resolveComparePrice(Product $product, int $liquidPrice, ProductDisplayPriceService $display): int - { + private function resolveComparePrice( + Product $product, + int $liquidPrice, + ProductDisplayPriceService $display, + ConfigService $config, + int $direction + ): int { if ($display->usesAppPrice($product)) { $base = $liquidPrice > 0 ? $liquidPrice : $display->resolveOrderBasePrice($product); - return max(0, (int) $base); + // مقایسه با همان قیمتی که مشتری در اپ می‌بیند و سفارش با آن ثبت می‌شود، نه پایهٔ وسط + $trade = $config->buildTradeDisplayPrices((float) $base, $config->priceProvider()); + + return max(0, (int) ($direction === 2 ? $trade['sell'] : $trade['buy'])); } $price = (int) ($product->price ?? 0); diff --git a/app/Services/ConfigService.php b/app/Services/ConfigService.php index 3329cdd..8c92b71 100644 --- a/app/Services/ConfigService.php +++ b/app/Services/ConfigService.php @@ -132,6 +132,22 @@ class ConfigService return $this->displayBuyPriceDiffRial(); } + /** + * اختلاف دوطرفهٔ نرخ همکار (نصف فاصلهٔ نرخ خرید و فروش همکار). + * + * پایهٔ ذخیره‌شده (montzar_live_price) وسط این دو نرخ است، پس نرخ واقعی معاملهٔ ما با همکار + * «پایه + این مقدار» برای خرید و «پایه − این مقدار» برای فروش است. + * فقط برای provider همکار معنا دارد؛ بقیه نرخ دوطرفه نمی‌دهند. + */ + public function providerTradeSpreadRial(): float + { + if ($this->priceProvider() !== 'montzar') { + return 0.0; + } + + return max(0.0, (float) $this->get('montzar_diff', 0)); + } + /** درصد کارمزد سفارش — fee_service_charge_percentage، service_charge_percentage، config/fee.php */ public function orderServiceChargePercentage(): float { diff --git a/app/Services/ProductDisplayPriceService.php b/app/Services/ProductDisplayPriceService.php index 54b5469..589f327 100644 --- a/app/Services/ProductDisplayPriceService.php +++ b/app/Services/ProductDisplayPriceService.php @@ -471,6 +471,45 @@ class ProductDisplayPriceService return $this->resolveHistoricalBasePrice(); } + /** + * قیمت پایهٔ سفارش برای یک جهت — با اختلاف واقعی نرخ همکار. + * پایه وسطِ نرخ خرید/فروش همکار است؛ سفارش باید با همان سمتی حساب شود که ما با همکار معامله می‌کنیم. + */ + public function resolveOrderTradePrice(?Product $product = null, ?int $direction = null): int + { + $base = (float) $this->resolveOrderBasePrice($product); + + return (int) $this->applyProviderTradeSpread($base, $product, $direction); + } + + /** + * خرید → پایه + اختلاف نرخ همکار، فروش → پایه − اختلاف. + * فقط روی قیمتی که از مظنهٔ اپ آمده؛ محصول با قیمت دستی/فید/فرمول دست نمی‌خورد. + * ceil مثل buildTradeDisplayPrices تا قیمت سفارش با قیمت نمایشی اپ یکی بماند. + */ + public function applyProviderTradeSpread( + float $basePrice, + ?Product $product = null, + ?int $direction = null + ): float { + if ($basePrice <= 0 || $direction === null) { + return $basePrice; + } + + if ($product instanceof Product && ! $this->usesAppPrice($product)) { + return $basePrice; + } + + $spread = app(ConfigService::class)->providerTradeSpreadRial(); + if ($spread <= 0) { + return $basePrice; + } + + return $direction === 2 + ? max(0.0, ceil($basePrice - $spread)) + : ceil($basePrice + $spread); + } + /** @param array $payload */ private function extractBaseFromPayload(array $payload): int {