diff --git a/app/Http/Controllers/Single/SingleOrderController.php b/app/Http/Controllers/Single/SingleOrderController.php index 8c325f6..33ce376 100644 --- a/app/Http/Controllers/Single/SingleOrderController.php +++ b/app/Http/Controllers/Single/SingleOrderController.php @@ -32,6 +32,10 @@ class SingleOrderController extends Controller public function store(Request $request) { $data = $request->all(); + $data['payment_product_id'] = $this->resolveGoldPaymentProductId($data); + if (preg_match('/^gold:\d+$/', (string) ($data['method'] ?? ''))) { + $data['method'] = 'gold'; + } $data['is_katod'] = ($data['method'] ?? null) === 'katod'; if ($data['is_katod']) { $data['method'] = 'gold'; @@ -332,22 +336,69 @@ class SingleOrderController extends Controller $data['total_fee'] = 0; $data['service_charge_price'] = $data['service_charge'] * $data['price_original']; $data['wallet'] = $wallet; - if ($wallet->gold < $data['total_amount']) { + + $paymentProductId = (int) ($data['payment_product_id'] ?? 0); + $paymentWalletInterface = $wallet_interface; + $paymentProduct = null; + $paymentWallet = $wallet; + + if ($paymentProductId > 0) { + $paymentProduct = Product::find($paymentProductId); + if ( + !$paymentProduct + || (int) ($paymentProduct->metal_id ?? 0) !== (int) ($data['product']['metal_id'] ?? 0) + ) { + throw new UnprocessableEntityHttpException('روش پرداخت نامعتبر است.'); + } + + $paymentWalletInterface = $this->productWalletInterface($paymentProductId); + $paymentWallet = $paymentWalletInterface->wallet; + if (!$paymentWallet) { + throw new UnprocessableEntityHttpException('کیف پول یافت نشد.'); + } + } + + if ((float) $paymentWallet->gold < $data['total_amount']) { throw new UnprocessableEntityHttpException($this->insufficientGoldBalanceMessage($data)); } if (!$data['product']['open_buy']) { throw new UnprocessableEntityHttpException('خرید این محصول در این لحظه مقدور نمیباشد'); } $data['order'] = $order = Order::create($data); - $data['transaction'][] = new TransactionInterface($wallet_interface, $_inp = [ + + $paymentSellTitle = $paymentProduct + ? self::productSellTitle($paymentProduct->title ?? '') + : self::mainMetalSellTitle(); + + $paymentTransaction = [ "number" => $data['number'], "gold" => $data['total_amount'], - "product_id" => $data["product_id"], 'expire_at' => now(), 'active' => true, 'order_id' => $order->id, - 'title' => self::mainMetalSellTitle(), - ], 12, false, true); + 'title' => $paymentSellTitle, + ]; + + if ($paymentProductId > 0) { + $paymentTransaction['product_id'] = $paymentProductId; + $this->normalizeProductWalletGold($paymentWalletInterface); + $data['transaction'][] = new TransactionInterface( + $paymentWalletInterface, + $paymentTransaction, + 1, + false, + false + ); + } else { + $data['transaction'][] = new TransactionInterface( + $paymentWalletInterface, + $paymentTransaction, + 12, + false, + true + ); + } + $wallet_interface_product = $this->productWalletInterface((int) $data["product_id"]); $this->normalizeProductWalletGold($wallet_interface_product); new TransactionInterface($wallet_interface_product, [ @@ -794,6 +845,20 @@ class SingleOrderController extends Controller return null; } + private function resolveGoldPaymentProductId(array $data): ?int + { + if (!empty($data['payment_product_id'])) { + return (int) $data['payment_product_id']; + } + + $method = (string) ($data['method'] ?? ''); + if (preg_match('/^gold:(\d+)$/', $method, $matches)) { + return (int) $matches[1]; + } + + return null; + } + private function resolveAbshodeProductContext(array $data): array { $productId = (int) ($data['product_id'] ?? $data['abshode_id'] ?? 0); diff --git a/app/Services/ProductDisplayPriceService.php b/app/Services/ProductDisplayPriceService.php index e8060ec..c15fb14 100644 --- a/app/Services/ProductDisplayPriceService.php +++ b/app/Services/ProductDisplayPriceService.php @@ -100,7 +100,7 @@ class ProductDisplayPriceService ? $this->resolveLiveBuyPriceWithFallback() : $this->resolveStrictLiveBuyPrice(); - if ($unitBuy <= 0 && app(ConfigService::class)->getBool('show_last_price', false)) { + if ($unitBuy <= 0 && $useLast) { $unitBuy = $this->resolveHistoricalBasePrice(); } @@ -262,25 +262,11 @@ class ProductDisplayPriceService /** @param array> $feed */ private function applyReferenceFeedPrice(Product $product, array $feed, ZaarboxPriceService $zaarbox): void { - if (Product::hasStoredPriceColumns()) { - $stored = (int) ($product->price ?? 0) + (int) ($product->price_profit ?? 0); - if ($stored > 0) { - $product->setAttribute('price', (int) ($product->price ?? 0)); - if (Schema::hasColumn($product->getTable(), 'price_profit')) { - $product->setAttribute('price_profit', (int) ($product->price_profit ?? 0)); - } - - return; - } - } - + $useLast = $this->productUsesLastPriceIfZero($product); $row = $zaarbox->findFeedRow($feed, (string) $product->reading_method); if ($row === null) { - $useLast = $this->productUsesLastPriceIfZero($product); $offset = ProductPriceService::offsetPercent($product); - $historical = app(ConfigService::class)->getBool('show_last_price', false) - ? $this->resolveHistoricalBasePrice() - : 0; + $historical = $useLast ? $this->resolveHistoricalBasePrice() : 0; $computed = $historical > 0 ? ProductPriceService::adjustedTotal($historical, 0, $offset) : 0; @@ -291,7 +277,7 @@ class ProductDisplayPriceService $computed = $zaarbox->computeAdjustedProductPrice($product, $row); if ($computed <= 0) { - if ($this->productUsesLastPriceIfZero($product)) { + if ($useLast) { $fallback = $this->resolveLastPriceFallback($product); if ($fallback > 0) { $product->setAttribute('price', $fallback); @@ -455,10 +441,11 @@ class ProductDisplayPriceService /** * نمایش در اپ کاربر: - * • خاموش (show=false در DB) → false + * • خاموش (active=false در DB) → false + * • خارج از ساعات معامله → false * • قیمت نمایشی بعد از enrich → true - * • قیمت صفر و show_last_price خاموش → false - * • قیمت صفر و show_last_price روشن و fallback موجود → true + * • قیمت صفر و use_last_price_if_zero خاموش → false + * • قیمت صفر و use_last_price_if_zero روشن و fallback موجود → true */ public function resolveCustomerShow(Product $product): bool { @@ -474,11 +461,10 @@ class ProductDisplayPriceService return true; } - if (! app(ConfigService::class)->getBool('show_last_price', false)) { + if (! $this->productUsesLastPriceIfZero($product)) { return false; } - return $this->resolveLastPriceFallback($product) > 0 - || $this->resolveHistoricalBasePrice() > 0; + return $this->resolveLastPriceFallback($product) > 0; } } diff --git a/app/Services/ProductPriceService.php b/app/Services/ProductPriceService.php index ea536d1..1b5b849 100644 --- a/app/Services/ProductPriceService.php +++ b/app/Services/ProductPriceService.php @@ -51,6 +51,10 @@ class ProductPriceService $data['price_profit'] = 0; } + if (\Illuminate\Support\Facades\Schema::hasColumn($product->getTable(), 'show')) { + $data['show'] = self::resolveShowAfterPriceSync($product, $adjustedPrice); + } + Product::where('id', $product->id)->update($data); return [ @@ -67,6 +71,19 @@ class ProductPriceService ]; } + private static function resolveShowAfterPriceSync(Product $product, int $adjustedPrice): bool + { + if (! ($product->active ?? true)) { + return false; + } + + if (! app(ConfigService::class)->isProductWithinTradingHours($product)) { + return false; + } + + return $adjustedPrice > 0; + } + /** وقتی فقط درصد در ادمین عوض می‌شود (بدون sync جدید) */ public static function reapplyOffsetPercent(Product $product, float $newOffsetPercent, ?float $oldOffsetPercent = null): void { diff --git a/database/sql/deploy_settings_const.sql b/database/sql/deploy_settings_const.sql index f6f3bba..617811f 100644 --- a/database/sql/deploy_settings_const.sql +++ b/database/sql/deploy_settings_const.sql @@ -425,19 +425,19 @@ SELECT 'referral_id', 'required', 'کد معرف اجباری', 1, 1, 'روشن WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'referral_id' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'fee_single', '500000', 'اختلاف پایه نمایش', 1, 1, NULL, 'number' +SELECT 'fee_single', '500000', 'اختلاف پایه نمایش', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'fee_single' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'buy_fee', '', 'سود خرید نمایش', 1, 1, NULL, 'number' +SELECT 'buy_fee', '', 'سود خرید نمایش', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'buy_fee' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'sell_fee', '', 'سود فروش نمایش', 1, 1, NULL, 'number' +SELECT 'sell_fee', '', 'سود فروش نمایش', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'sell_fee' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'fee_cash', '500000', 'کارمزد ریالی سفارش (legacy)', 0, 1, NULL, 'number' +SELECT 'fee_cash', '500000', 'کارمزد ریالی سفارش (legacy)', 0, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'fee_cash' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) @@ -445,15 +445,15 @@ SELECT 'fee_service_charge_percentage', '0.005', 'درصد کارمزد سفار WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'fee_service_charge_percentage' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'min_withdraw', '', 'حداقل برداشت (ریال)', 1, 1, NULL, 'number' +SELECT 'min_withdraw', '', 'حداقل برداشت (ریال)', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'min_withdraw' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'min_first_buy', '', 'حداقل اولین خرید (ریال)', 1, 1, NULL, 'number' +SELECT 'min_first_buy', '', 'حداقل اولین خرید (ریال)', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'min_first_buy' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'minimum_sell', '', 'حداقل فروش', 1, 1, NULL, 'number' +SELECT 'minimum_sell', '', 'حداقل فروش', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'minimum_sell' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) @@ -639,12 +639,18 @@ UPDATE `settings` SET `type` = 'switch' WHERE `key` IN ( 'banner_enabled' ); --- number -UPDATE `settings` SET `type` = 'number' WHERE `key` IN ( - 'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', 'fee_service_charge_percentage', 'fee_free', +-- price (مبالغ ریالی) +UPDATE `settings` SET `type` = 'price' WHERE `key` IN ( + 'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', 'min_withdraw', 'min_first_buy', 'minimum_sell', - 'montzar_product_id', 'gift_for_referrer', - 'gift_for_referral', 'up_price', 'down_price', 'payping_fin_customer_id', 'tahesab_port', + 'up_price', 'down_price' +); + +-- number (شماره، شناسه، درصد، تعداد — بدون جداکننده هزارگان) +UPDATE `settings` SET `type` = 'number' WHERE `key` IN ( + 'fee_service_charge_percentage', 'fee_free', 'service_charge_percentage', + 'montzar_product_id', 'gift_for_referrer', 'gift_for_referral', + 'payping_fin_customer_id', 'tahesab_port', 'referral_limit', 'deposit_sms_support_number' ); @@ -659,7 +665,7 @@ UPDATE `settings` SET `type` = 'text' WHERE `key` IN ( 'payping_fin_token', 'payping_gateway_item', 'tahesab_host', 'tahesab_token', 'tahesab_db', 'node_client_id', 'node_shared_secret', 'sse_path', - 'tahesab_bank_account', 'telegram_bot_token', 'bale_bot_token', 'support_messenger_id', 'referral_limit', + 'tahesab_bank_account', 'telegram_bot_token', 'bale_bot_token', 'support_messenger_id', 'referral_bonus_amount', 'balance_report_exclude_customer_id', 'metal_type', 'montify_name', 'price_extreme_date', 'default_vc_number', 'liman_token' ); @@ -1104,6 +1110,19 @@ UPDATE `settings` SET `can_edit` = 1 WHERE `key` IN ( 'text_about', 'text_rule' ); +-- تفکیک نهایی type (بعد از همه batchها — override روی دیتابیس موجود) +UPDATE `settings` SET `type` = 'price' WHERE `key` IN ( + 'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', + 'min_withdraw', 'min_first_buy', 'minimum_sell', + 'up_price', 'down_price' +); +UPDATE `settings` SET `type` = 'number' WHERE `key` IN ( + 'fee_service_charge_percentage', 'fee_free', 'service_charge_percentage', + 'montzar_product_id', 'gift_for_referrer', 'gift_for_referral', + 'payping_fin_customer_id', 'tahesab_port', 'referral_limit', + 'deposit_sms_support_number' +); + COMMIT; SELECT 'deploy_settings_const.sql finished' AS status; diff --git a/database/sql/deploy_settings_const_preserve_value_sync_can_edit.sql b/database/sql/deploy_settings_const_preserve_value_sync_can_edit.sql index b83f50f..040e834 100644 --- a/database/sql/deploy_settings_const_preserve_value_sync_can_edit.sql +++ b/database/sql/deploy_settings_const_preserve_value_sync_can_edit.sql @@ -405,19 +405,19 @@ SELECT 'referral_id', 'required', 'کد معرف اجباری', 1, 1, 'روشن WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'referral_id' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'fee_single', '500000', 'اختلاف پایه نمایش', 1, 1, NULL, 'number' +SELECT 'fee_single', '500000', 'اختلاف پایه نمایش', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'fee_single' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'buy_fee', '', 'سود خرید نمایش', 1, 1, NULL, 'number' +SELECT 'buy_fee', '', 'سود خرید نمایش', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'buy_fee' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'sell_fee', '', 'سود فروش نمایش', 1, 1, NULL, 'number' +SELECT 'sell_fee', '', 'سود فروش نمایش', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'sell_fee' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'fee_cash', '500000', 'کارمزد ریالی سفارش (legacy)', 0, 1, NULL, 'number' +SELECT 'fee_cash', '500000', 'کارمزد ریالی سفارش (legacy)', 0, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'fee_cash' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) @@ -425,15 +425,15 @@ SELECT 'fee_service_charge_percentage', '0.005', 'درصد کارمزد سفار WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'fee_service_charge_percentage' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'min_withdraw', '', 'حداقل برداشت (ریال)', 1, 1, NULL, 'number' +SELECT 'min_withdraw', '', 'حداقل برداشت (ریال)', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'min_withdraw' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'min_first_buy', '', 'حداقل اولین خرید (ریال)', 1, 1, NULL, 'number' +SELECT 'min_first_buy', '', 'حداقل اولین خرید (ریال)', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'min_first_buy' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) -SELECT 'minimum_sell', '', 'حداقل فروش', 1, 1, NULL, 'number' +SELECT 'minimum_sell', '', 'حداقل فروش', 1, 1, NULL, 'price' WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'minimum_sell' LIMIT 1); INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`) @@ -615,12 +615,18 @@ UPDATE `settings` SET `type` = 'switch' WHERE `key` IN ( 'register_referral_sms_to_referrer', 'register_referral_bonus_message', 'price_from_nasiryan' ); --- number -UPDATE `settings` SET `type` = 'number' WHERE `key` IN ( - 'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', 'fee_service_charge_percentage', 'fee_free', +-- price (مبالغ ریالی) +UPDATE `settings` SET `type` = 'price' WHERE `key` IN ( + 'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', 'min_withdraw', 'min_first_buy', 'minimum_sell', - 'montzar_product_id', 'gift_for_referrer', - 'gift_for_referral', 'up_price', 'down_price', 'payping_fin_customer_id', 'tahesab_port', + 'up_price', 'down_price' +); + +-- number (شماره، شناسه، درصد، تعداد — بدون جداکننده هزارگان) +UPDATE `settings` SET `type` = 'number' WHERE `key` IN ( + 'fee_service_charge_percentage', 'fee_free', 'service_charge_percentage', + 'montzar_product_id', 'gift_for_referrer', 'gift_for_referral', + 'payping_fin_customer_id', 'tahesab_port', 'referral_limit', 'deposit_sms_support_number' ); @@ -635,7 +641,7 @@ UPDATE `settings` SET `type` = 'text' WHERE `key` IN ( 'payping_fin_token', 'payping_gateway_item', 'tahesab_host', 'tahesab_token', 'tahesab_db', 'node_client_id', 'node_shared_secret', 'sse_path', - 'tahesab_bank_account', 'telegram_bot_token', 'bale_bot_token', 'support_messenger_id', 'referral_limit', + 'tahesab_bank_account', 'telegram_bot_token', 'bale_bot_token', 'support_messenger_id', 'referral_bonus_amount', 'balance_report_exclude_customer_id', 'metal_type', 'montify_name', 'price_extreme_date', 'default_vc_number', 'liman_token' ); @@ -1158,6 +1164,19 @@ JOIN ( ) d ON d.`key` = s.`key` SET s.`can_edit` = d.`can_edit`; +-- تفکیک نهایی type (بعد از همه batchها — override روی دیتابیس موجود) +UPDATE `settings` SET `type` = 'price' WHERE `key` IN ( + 'fee_single', 'buy_fee', 'sell_fee', 'fee_cash', + 'min_withdraw', 'min_first_buy', 'minimum_sell', + 'up_price', 'down_price' +); +UPDATE `settings` SET `type` = 'number' WHERE `key` IN ( + 'fee_service_charge_percentage', 'fee_free', 'service_charge_percentage', + 'montzar_product_id', 'gift_for_referrer', 'gift_for_referral', + 'payping_fin_customer_id', 'tahesab_port', 'referral_limit', + 'deposit_sms_support_number' +); + COMMIT; SELECT 'deploy_settings_const.sql finished' AS status;