montzar added

This commit is contained in:
2026-05-25 12:47:04 +03:30
parent 7f0f91701e
commit b84ea8aabe
5 changed files with 232 additions and 428 deletions
@@ -23,7 +23,8 @@ use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use App\Models\Setting; use App\Models\Setting;
use App\Models\Cnt; use App\Models\Cnt;
use App\Services\LimanService; use App\Services\MontzarService;
use App\Services\ConfigService;
class SingleOrderController extends Controller class SingleOrderController extends Controller
@@ -31,27 +32,24 @@ class SingleOrderController extends Controller
public function store(Request $request) public function store(Request $request)
{ {
$data = $request->all(); $data = $request->all();
$config = app(ConfigService::class);
$toBool = function ($value) {
return filter_var($value, FILTER_VALIDATE_BOOLEAN);
};
if ($this->Config('liman_price') == 'true') { if ($toBool($config->Config('montzar_price'))) {
$liman_closed = Cnt::where('key', 'liman_closed')->value('value') == "true"; $montzar_closed = $toBool($config->Config('montzar_closed'));
$liman_buy = Cnt::where('key', 'liman_open_buy')->value('value') == "false" && $data['direction'] == 1; $montzar_buy = !$toBool($config->Config('montzar_open_buy')) && (int) $data['direction'] === 1;
$liman_sell = Cnt::where('key', 'liman_open_sell')->value('value') == "false" && $data['direction'] == 2; $montzar_sell = !$toBool($config->Config('montzar_open_sell')) && (int) $data['direction'] === 2;
if ($liman_closed || $liman_buy || $liman_sell) { if ($montzar_closed || $montzar_buy || $montzar_sell) {
throw new UnprocessableEntityHttpException('عدم ارائه سرویس.');
}
} elseif ($this->Config('goldir_price') == 'true') {
$goldir_closed = Cnt::where('key', 'goldir_closed')->first()['value'] == "true";
$goldir_buy = Cnt::where('key', 'goldir_open_buy')->first()['value'] == "false" && $data['direction'] == 1;
$goldir_sell = Cnt::where('key', 'goldir_open_sell')->first()['value'] == "false" && $data['direction'] == 2;
if ($goldir_closed || $goldir_buy || $goldir_sell) {
throw new UnprocessableEntityHttpException('عدم ارائه سرویس.'); throw new UnprocessableEntityHttpException('عدم ارائه سرویس.');
} }
} }
if($this->Config('close_price') == 'true'){
if(Cnt::where('key', 'app_closed')->first()['value'] == "true"){ if ($toBool($config->Config('close_price'))) {
if (Cnt::where('key', 'app_closed')->value('value') == "true") {
throw new UnprocessableEntityHttpException('عدم ارائه سرویس.'); throw new UnprocessableEntityHttpException('عدم ارائه سرویس.');
} }
} }
@@ -190,7 +188,7 @@ class SingleOrderController extends Controller
'start_at' => now(), 'start_at' => now(),
], 1, true, false); ], 1, true, false);
$response['1'] = 2; $response['1'] = 2;
//send to Goldir //send to provider
$this->sendProviderOrder($data, $wallet_interface, (int) $data['direction']); $this->sendProviderOrder($data, $wallet_interface, (int) $data['direction']);
return $response; return $response;
} }
@@ -472,9 +470,9 @@ class SingleOrderController extends Controller
private function sendProviderOrder(array &$data, $wallet_interface, int $direction) private function sendProviderOrder(array &$data, $wallet_interface, int $direction)
{ {
if ($this->Config('liman_price') == "true") { if ($this->Config('montzar_price') == "true") {
try { try {
return app(LimanService::class)->sendOrder($data); return app(MontzarService::class)->sendOrder($data);
} catch (UnprocessableEntityHttpException $e) { } catch (UnprocessableEntityHttpException $e) {
$this->rollbackProviderFailedOrder($data, $wallet_interface, $direction); $this->rollbackProviderFailedOrder($data, $wallet_interface, $direction);
throw $e; throw $e;
@@ -482,12 +480,12 @@ class SingleOrderController extends Controller
$this->rollbackProviderFailedOrder($data, $wallet_interface, $direction); $this->rollbackProviderFailedOrder($data, $wallet_interface, $direction);
throw new UnprocessableEntityHttpException( throw new UnprocessableEntityHttpException(
'خطا در ثبت سفارش نزد لیمان: ' . $e->getMessage() 'خطا در ثبت سفارش ارائه دهنده: ' . $e->getMessage()
); );
} }
} }
return $this->sendGoldir($data); return null;
} }
private function rollbackProviderFailedOrder(array $data, $wallet_interface, int $direction): void private function rollbackProviderFailedOrder(array $data, $wallet_interface, int $direction): void
@@ -520,56 +518,6 @@ class SingleOrderController extends Controller
$order->delete(); $order->delete();
} }
private function sendGoldir($data)
{
if ($this->Config('send_to_goldir') == "true") {
$goldir_base_url=$this->Config('goldir_base_url')??'https://gold.ir';
// $liman_diff = Cnt::where('key', 'goldir_diff')->value('value');
// $liman_price = Cnt::where('key', 'goldir_price')->value('value');
$mazaneh = ($data['direction'] == 1) ? Cnt::where('key', 'goldir_truly_buy_mazaneh')->value('value') : Cnt::where('key', 'goldir_truly_sell_mazaneh')->value('value');
$cash = Cnt::where('key', 'goldir_price')->value('value') * $data['amount'];
$response = Http::withToken(Cnt::where('key', 'goldir')->first()['value'])->post($goldir_base_url."/server/customer/order", [
"mazaneh" => ((int)$mazaneh),
'amount' => $data['amount'],
'description' => $this->Config('name_fa') . " - " . auth('customer')->user()->name,
'direction' => $data['direction'],
'product_id' => $this->Config('hamkar_product_id'),
'cash' => $cash,
'input_mode'=> 'gold'
])/*->json()*/
;
if (isset($response['message']) && $response['message'] == 'no authorised') {
$cnt = new Cnt();
$response = Http::withToken($cnt->goldir_login())//$this->ConfigService('liman_token'))
->post($goldir_base_url."/server/customer/order", [
"mazaneh" => ((int)$mazaneh),
'amount' => $data['amount'],
'description' => $this->Config('name_fa') . " - " . auth('customer')->user()->name,
'direction' => $data['direction'],
'product_id' => $this->Config('hamkar_product_id'),
'cash' => $cash,
'input_mode'=> 'gold'
])/*->json()*/
;
}
Cnt::where('key', 'goldir_order_response')->update(['value' => $response /*json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)*/]);
Cnt::where('key', 'last_order_log')->update(['value' => $response]);
if (!isset($response[1]) && !isset($response[1]['id'])) {
throw new UnprocessableEntityHttpException('سفارشات توسط ارائه دهنده بسته شده است.');
}
$data['provider_id'] = $response[1]['id'];
return $response;
}
// $data['total_price_goldir'] = ($data['direction'] == 1) ? ($liman_price+$liman_diff) : ($liman_price-$liman_diff) ;
}
public function storeBackUp(Request $request) public function storeBackUp(Request $request)
{ {
$data = $request->all(); $data = $request->all();
+133 -275
View File
@@ -9,18 +9,17 @@ use App\Models\Cnt;
use App\Models\Setting; use App\Models\Setting;
use App\Models\ConfigStatic; use App\Models\ConfigStatic;
use App\Models\Customer; use App\Models\Customer;
use App\Services\LimanService; use App\Services\MontzarService;
use App\Models\Price; use App\Models\Price;
use App\Models\PriceCandle; use App\Models\PriceCandle;
use App\Models\PriceTrigger; use App\Models\PriceTrigger;
use App\Models\Product; use App\Models\Product;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use Morilog\Jalali\Jalalian; use Morilog\Jalali\Jalalian;
use App\Http\Controllers\Admin\ProductController; use App\Services\ConfigService;
class ReportController extends Controller class ReportController extends Controller
@@ -112,18 +111,19 @@ class ReportController extends Controller
public function lastPrice() public function lastPrice()
{ {
$config = app(ConfigService::class);
$closed = false; $closed = false;
$goldir_price = 0; $montzar_price = 0;
$liman_price = 0;
$tgn = 0; $tgn = 0;
$pr_price = 0; $pr_price = 0;
$open_buy = true; $open_buy = true;
$open_sell = true; $open_sell = true;
$liman_open_buy = false; $montzar_open_buy = false;
$liman_open_sell = false; $montzar_open_sell = false;
$priceSource = null; $priceSource = null;
$priceValue = 0; $priceValue = 0;
@@ -132,16 +132,30 @@ class ReportController extends Controller
return filter_var($value, FILTER_VALIDATE_BOOLEAN); return filter_var($value, FILTER_VALIDATE_BOOLEAN);
}; };
$zeroResponse = function () {
return [
'sell' => 0,
'buy' => 0,
'price_last' => 0,
'price' => 0,
'main_product' => 0,
'taban_gohar' => 0,
'montzar' => 0,
'closed' => true,
'time' => now(),
];
};
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| بستن قیمت طبق منطق قبلی | بستن قیمت طبق منطق قبلی
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
if ($this->Config('close_price') == 'true') { if ($toBool($config->Config('close_price'))) {
$startDay = $this->Config('startDay'); $startDay = $config->Config('startDay') ?: '00:00';
[$startHour, $startMinute] = explode(':', $startDay); [$startHour, $startMinute] = explode(':', $startDay);
$endDay = $this->Config('endDay'); $endDay = $config->Config('endDay') ?: '23:59';
[$endHour, $endMinute] = explode(':', $endDay); [$endHour, $endMinute] = explode(':', $endDay);
$current = Carbon::now(); $current = Carbon::now();
@@ -149,27 +163,16 @@ class ReportController extends Controller
$end = Carbon::today()->setTime((int) $endHour, (int) $endMinute); $end = Carbon::today()->setTime((int) $endHour, (int) $endMinute);
if (!$current->between($start, $end)) { if (!$current->between($start, $end)) {
Cnt::where('key', 'app_closed')->update(['value' => "true"]); // عمومی: در Cnt بماند
Cnt::where('key', 'goldir_closed')->update(['value' => "true"]); Cnt::where('key', 'app_closed')->update(['value' => 'true']);
Cnt::where('key', 'liman_closed')->update(['value' => "true"]);
return [ // مربوط به منتزر: settings
'sell' => 0, $config->UpdateConfig('montzar_closed', 'true');
'buy' => 0,
'price_last' => 0, return $zeroResponse();
'price' => 0,
'main_product' => 0,
'taban_gohar' => 0,
'goldir' => 0,
'liman' => 0,
'closed' => true,
'time' => now()->format('H:i:s'),
];
} }
Cnt::where('key', 'app_closed')->update(['value' => "false"]); Cnt::where('key', 'app_closed')->update(['value' => 'false']);
Cnt::where('key', 'goldir_closed')->update(['value' => "false"]);
Cnt::where('key', 'liman_closed')->update(['value' => "false"]);
} }
/* /*
@@ -179,83 +182,53 @@ class ReportController extends Controller
*/ */
$settings = Setting::whereIn('key', [ $settings = Setting::whereIn('key', [
'fee_single', 'fee_single',
'goldir_price',
'tabanGohar_price', 'tabanGohar_price',
'main_product_price', 'main_product_price',
'buy_fee', 'buy_fee',
'sell_fee', 'sell_fee',
'show_last_price',
])->get(); ])->get();
$settingsMap = $settings->pluck('value', 'key'); $settingsMap = $settings->pluck('value', 'key');
$show_last_price = $toBool($settingsMap->get('show_last_price', false));
$taban_gohar_price = $settingsMap->get('tabanGohar_price'); $taban_gohar_price = $settingsMap->get('tabanGohar_price');
$difference = (float) $settingsMap->get('fee_single', 0);
$gold_ir_price = $settingsMap->get('goldir_price');
$main_product_price = $settingsMap->get('main_product_price'); $main_product_price = $settingsMap->get('main_product_price');
$difference = (float) $settingsMap->get('fee_single', 0);
$diff_buy = (float) $settingsMap->get('buy_fee', $difference); $diff_buy = (float) $settingsMap->get('buy_fee', $difference);
$diff_sell = (float) $settingsMap->get('sell_fee', $difference); $diff_sell = (float) $settingsMap->get('sell_fee', $difference);
$liman_price_enabled = $toBool($this->Config('liman_price')); $montzar_price_enabled = $toBool($config->Config('montzar_price'));
\Log::info('LAST_PRICE DEBUG START', [
'file' => __FILE__,
'close_price' => $this->Config('close_price'),
'liman_price_raw' => $this->Config('liman_price'),
'liman_price_enabled' => $liman_price_enabled,
'liman_product_id' => $this->Config('liman_product_id'),
'liman_base_url' => $this->Config('liman_base_url'),
'liman_token_exists' => (bool) Setting::where('key', 'liman_token')->value('value'),
]);
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Montpar / Liman - اولویت اول | Montzar - اولویت اول
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
if ($liman_price_enabled && !$closed) { if ($montzar_price_enabled && !$closed) {
try { try {
$limanBaseUrl = rtrim($this->Config('liman_base_url') ?: 'https://montpar.ir', '/'); $montzarBaseUrl = rtrim($config->Config('montzar_base_url') ?: 'https://montpar.ir', '/');
$limanProductId = (int) ($this->Config('liman_product_id') ?: 25); $montzarProductId = (int) ($config->Config('montzar_product_id') ?: 25);
$liman = app(LimanService::class)->productList(); $montzar = app(MontzarService::class)->productList();
\Log::info('PROVIDER FIRST RESPONSE', [ if (isset($montzar['message'])) {
'base_url' => $limanBaseUrl, throw new \Exception('Provider message: ' . $montzar['message']);
'product_id' => $limanProductId,
'type' => gettype($liman),
'message' => is_array($liman) ? ($liman['message'] ?? null) : null,
'available_ids' => is_array($liman) ? collect($liman)->pluck('id')->values()->all() : null,
]);
if (isset($liman['message'])) {
throw new \Exception('Provider message: ' . $liman['message']);
} }
$collection = collect($liman); $collection = collect($montzar);
$lpLiman = $collection->firstWhere('id', $limanProductId); $montzarProduct = $collection->firstWhere('id', $montzarProductId);
\Log::info('PROVIDER PRODUCT PICKED', [ if (!$montzarProduct) {
'base_url' => $limanBaseUrl, throw new \Exception("Provider product not found. product_id={$montzarProductId}");
'liman_product_id' => $limanProductId,
'found' => (bool) $lpLiman,
'has_sub_agent' => $lpLiman && isset($lpLiman['sub_agent']),
'open_buy' => $lpLiman['open_buy'] ?? null,
'open_sell' => $lpLiman['open_sell'] ?? null,
'buy_gram' => $lpLiman['sub_agent']['rate_buy_gram_price'] ?? null,
'sell_gram' => $lpLiman['sub_agent']['rate_sell_gram_price'] ?? null,
]);
if (!$lpLiman) {
throw new \Exception("Provider product not found. product_id={$limanProductId}");
} }
if (!isset($lpLiman['sub_agent'])) { if (!isset($montzarProduct['sub_agent'])) {
throw new \Exception("Provider product has no sub_agent. product_id={$limanProductId}"); throw new \Exception("Provider product has no sub_agent. product_id={$montzarProductId}");
} }
$buy = (float) ($lpLiman['sub_agent']['rate_buy_gram_price'] ?? 0); $buy = (float) ($montzarProduct['sub_agent']['rate_buy_gram_price'] ?? 0);
$sell = (float) ($lpLiman['sub_agent']['rate_sell_gram_price'] ?? 0); $sell = (float) ($montzarProduct['sub_agent']['rate_sell_gram_price'] ?? 0);
if ($buy <= 0 || $sell <= 0) { if ($buy <= 0 || $sell <= 0) {
throw new \Exception("Provider invalid gram price. buy={$buy}, sell={$sell}"); throw new \Exception("Provider invalid gram price. buy={$buy}, sell={$sell}");
@@ -265,160 +238,46 @@ class ReportController extends Controller
$customPrice['price'] = ($buy + $sell) / 2; $customPrice['price'] = ($buy + $sell) / 2;
$customPrice['diff'] = ($buy - $sell) / 2; $customPrice['diff'] = ($buy - $sell) / 2;
Cnt::where('key', 'liman_price')->update([ $config->UpdateConfig('montzar_price', (float) $customPrice['price']);
'value' => (float) $customPrice['price'] $config->UpdateConfig('montzar_diff', (float) $customPrice['diff']);
]); $config->UpdateConfig('montzar_mazaneh', ((float) $customPrice['price'] * 4.331802));
Cnt::where('key', 'liman_diff')->update([ $config->UpdateConfig(
'value' => (float) $customPrice['diff'] 'montzar_truly_buy_mazaneh',
]); $montzarProduct['sub_agent']['rate_buy_price'] ?? 0
);
Cnt::where('key', 'liman_mazaneh')->update([ $config->UpdateConfig(
'value' => ((float) $customPrice['price'] * 4.331802) 'montzar_truly_sell_mazaneh',
]); $montzarProduct['sub_agent']['rate_sell_price'] ?? 0
);
Cnt::where('key', 'liman_truly_buy_mazaneh')->update([ $config->UpdateConfig(
'value' => $lpLiman['sub_agent']['rate_buy_price'] ?? 0 'montzar_last_product_log',
]); json_encode($montzarProduct, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
);
Cnt::where('key', 'liman_truly_sell_mazaneh')->update([ $montzar_open_sell = $toBool($montzarProduct['open_sell'] ?? false);
'value' => $lpLiman['sub_agent']['rate_sell_price'] ?? 0 $montzar_open_buy = $toBool($montzarProduct['open_buy'] ?? false);
]);
Cnt::where('key', 'log')->update([ $config->UpdateConfig('montzar_open_sell', $montzar_open_sell ? 'true' : 'false');
'value' => json_encode($lpLiman, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) $config->UpdateConfig('montzar_open_buy', $montzar_open_buy ? 'true' : 'false');
]);
$liman_open_sell = $toBool($lpLiman['open_sell'] ?? false); if ($montzar_open_sell || $montzar_open_buy) {
$liman_open_buy = $toBool($lpLiman['open_buy'] ?? false); $montzar_price = (int) $customPrice['price'];
Cnt::where('key', 'liman_open_sell')->update([
'value' => $liman_open_sell ? "true" : "false"
]);
Cnt::where('key', 'liman_open_buy')->update([
'value' => $liman_open_buy ? "true" : "false"
]);
if ($liman_open_sell || $liman_open_buy) {
$liman_price = (int) $customPrice['price'];
} }
Cnt::where('key', 'liman_closed')->update([ $config->UpdateConfig('montzar_closed', $montzar_price == 0 ? 'true' : 'false');
'value' => $liman_price == 0 ? "true" : "false"
]);
\Log::info('PROVIDER PRICE SUCCESS', [
'base_url' => $limanBaseUrl,
'liman_product_id' => $limanProductId,
'liman_price' => $liman_price,
'liman_diff' => $customPrice['diff'],
'open_buy' => $liman_open_buy,
'open_sell' => $liman_open_sell,
]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
$liman_price = 0; $montzar_price = 0;
\Log::error('PROVIDER PRICE ERROR', [ \Log::error('MONZAR PRICE ERROR', [
'base_url' => $limanBaseUrl ?? null,
'message' => $e->getMessage(), 'message' => $e->getMessage(),
'liman_product_id' => $limanProductId ?? null, 'montzar_product_id' => $montzarProductId ?? null,
'liman_response' => $liman ?? null, 'montzar_response' => $montzar ?? null,
]); ]);
Cnt::where('key', 'liman_closed')->update([ $config->UpdateConfig('montzar_closed', 'true');
'value' => "true"
]);
}
}
/*
|--------------------------------------------------------------------------
| Goldir
|--------------------------------------------------------------------------
*/
if ($gold_ir_price == 'true' && !$closed) {
try {
$goldir = Http::timeout(7)
->withOptions([
'curl' => [
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
CURLOPT_TCP_FASTOPEN => 1,
]
])
->withoutVerifying()
->withToken(Cnt::where('key', 'goldir')->value('value'))
->get('https://gold.ir/server/customer/product/list')
->json();
if ((isset($goldir['message']) && $goldir['message'] == 'no authorised') || $goldir == null) {
$cnt = new Cnt();
$goldir = Http::timeout(2)
->withToken($cnt->goldir_login())
->get('https://gold.ir/server/customer/product/list')
->json();
}
$collection = collect($goldir);
$lpGoldir = $collection->firstWhere('id', 40);
if ($lpGoldir && isset($lpGoldir['sub_agent'])) {
$buy = (float) $lpGoldir['sub_agent']['rate_buy_gram_price'];
$sell = (float) $lpGoldir['sub_agent']['rate_sell_gram_price'];
$customPrice = [];
$customPrice['price'] = (ceil($buy) + ceil($sell)) / 2;
$customPrice['diff'] = (ceil($buy) - ceil($sell)) / 2;
Cnt::where('key', 'goldir_price')->update([
'value' => (float) $customPrice['price']
]);
Cnt::where('key', 'goldir_diff')->update([
'value' => (float) $customPrice['diff']
]);
Cnt::where('key', 'goldir_mazaneh')->update([
'value' => ((float) $customPrice['price'] * 4.331802)
]);
Cnt::where('key', 'goldir_truly_buy_mazaneh')->update([
'value' => $lpGoldir['sub_agent']['rate_buy_price']
]);
Cnt::where('key', 'goldir_truly_sell_mazaneh')->update([
'value' => $lpGoldir['sub_agent']['rate_sell_price']
]);
Cnt::where('key', 'log')->update([
'value' => json_encode($goldir, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
]);
$open_sell = $toBool($lpGoldir['open_sell'] ?? false);
$open_buy = $toBool($lpGoldir['open_buy'] ?? false);
Cnt::where('key', 'goldir_open_sell')->update([
'value' => $open_sell ? "true" : "false"
]);
Cnt::where('key', 'goldir_open_buy')->update([
'value' => $open_buy ? "true" : "false"
]);
if ($open_sell || $open_buy) {
$goldir_price = (int) $customPrice['price'];
}
}
Cnt::where('key', 'goldir_closed')->update([
'value' => $goldir_price == 0 ? "true" : "false"
]);
} catch (\Throwable $e) {
$goldir_price = 0;
Cnt::where('key', 'goldir_closed')->update([
'value' => "true"
]);
} }
} }
@@ -426,10 +285,12 @@ class ReportController extends Controller
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Main Product | Main Product
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| عمومی است، پس از Cnt خوانده می‌شود.
|--------------------------------------------------------------------------
*/ */
if ($main_product_price == 'true' && !$closed) { if ($toBool($main_product_price) && !$closed) {
$main_product_id = Cnt::where('key', 'main_product')->value('value'); $main_product_id = Cnt::where('key', 'main_product')->value('value');
$pr_product = Product::find($main_product_id); $pr_product = $main_product_id ? Product::find($main_product_id) : null;
if ($pr_product) { if ($pr_product) {
$pr_price = (float) $pr_product['price'] + (float) $pr_product['price_profit']; $pr_price = (float) $pr_product['price'] + (float) $pr_product['price_profit'];
@@ -441,13 +302,13 @@ class ReportController extends Controller
| Taban Gohar | Taban Gohar
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
if ($taban_gohar_price == 'true' && !$closed) { if ($toBool($taban_gohar_price) && !$closed) {
try { try {
$taban_gohar = Http::withOptions([ $taban_gohar = Http::withOptions([
'curl' => [ 'curl' => [
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4, CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
CURLOPT_TCP_FASTOPEN => 1, CURLOPT_TCP_FASTOPEN => 1,
] ],
]) ])
->withoutVerifying() ->withoutVerifying()
->timeout(2) ->timeout(2)
@@ -464,19 +325,16 @@ class ReportController extends Controller
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| انتخاب قیمت اصلی | انتخاب قیمت اصلی
| اولویت: | اولویت:
| Liman/Montpar -> Goldir -> Taban Gohar -> Main Product | Montzar -> Taban Gohar -> Main Product
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
if ($liman_price_enabled && ($liman_price ?? 0) !== 0 && !$closed) { if ($montzar_price_enabled && ($montzar_price ?? 0) !== 0 && !$closed) {
$priceValue = (int) $liman_price; $priceValue = (int) $montzar_price;
$priceSource = 'liman'; $priceSource = 'montzar';
} elseif ($gold_ir_price == 'true' && ($goldir_price ?? 0) !== 0 && !$closed) { } elseif ($toBool($taban_gohar_price) && ($tgn ?? 0) !== 0 && !$closed) {
$priceValue = (int) $goldir_price;
$priceSource = 'goldir';
} elseif ($taban_gohar_price == 'true' && ($tgn ?? 0) !== 0 && !$closed) {
$priceValue = $tgn; $priceValue = $tgn;
$priceSource = 'taban_gohar'; $priceSource = 'taban_gohar';
} elseif ($main_product_price == 'true' && ($pr_price ?? 0) !== 0 && !$closed) { } elseif ($toBool($main_product_price) && ($pr_price ?? 0) !== 0 && !$closed) {
$priceValue = $pr_price; $priceValue = $pr_price;
$priceSource = 'main_product'; $priceSource = 'main_product';
} else { } else {
@@ -484,32 +342,39 @@ class ReportController extends Controller
$priceSource = null; $priceSource = null;
} }
/*
|--------------------------------------------------------------------------
| اگر هیچ منبعی قیمت نداد، قیمت قبلی دیتابیس را برنگردان
|--------------------------------------------------------------------------
*/
if ($priceValue <= 0) { if ($priceValue <= 0) {
\Log::warning('LAST_PRICE NO SOURCE PRICE', [ if (!$show_last_price) {
'liman_price' => $liman_price, return [
'goldir_price' => $goldir_price, 'sell' => 0,
'taban_gohar' => $tgn, 'buy' => 0,
'main_product' => $pr_price, 'price_last' => 0,
'price_source' => $priceSource, 'price' => 0,
]); 'main_product' => $pr_price ?? 0,
'taban_gohar' => $tgn ?? 0,
'montzar' => $montzar_price ?? 0,
'closed' => true,
'time' => now(),
];
}
return [ $lastPrice = Price::latest()->first();
'sell' => 0,
'buy' => 0, if (!$lastPrice || (float) $lastPrice->price <= 0) {
'price_last' => 0, return [
'price' => 0, 'sell' => 0,
'main_product' => $pr_price ?? 0, 'buy' => 0,
'taban_gohar' => $tgn ?? 0, 'price_last' => 0,
'goldir' => $goldir_price ?? 0, 'price' => 0,
'liman' => $liman_price ?? 0, 'main_product' => $pr_price ?? 0,
'closed' => true, 'taban_gohar' => $tgn ?? 0,
'time' => now(), 'montzar' => $montzar_price ?? 0,
]; 'closed' => true,
'time' => now(),
];
}
$priceValue = (float) $lastPrice->price;
$priceSource = 'database_last';
} }
/* /*
@@ -546,41 +411,36 @@ class ReportController extends Controller
$candle->save(); $candle->save();
} else { } else {
PriceCandle::create([ PriceCandle::create([
"start" => $priceValue, 'start' => $priceValue,
"end" => $priceValue, 'end' => $priceValue,
"high" => $priceValue, 'high' => $priceValue,
"low" => $priceValue, 'low' => $priceValue,
"date_at" => date("Y-m-d") 'date_at' => date('Y-m-d'),
]); ]);
} }
} }
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| محاسبه sell / buy با همان priceValue همین اجرای فعلی | محاسبه sell / buy
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
if ($priceSource === 'liman') { if ($priceSource === 'montzar') {
$liman_profit = (float) Cnt::where('key', 'liman_diff')->value('value'); $montzar_profit = (float) $config->Config('montzar_diff');
$final_buy_diff = $diff_buy + $liman_profit; $final_buy_diff = $diff_buy + $montzar_profit;
$final_sell_diff = $diff_sell + $liman_profit; $final_sell_diff = $diff_sell + $montzar_profit;
$sell = $liman_open_sell $sell = $montzar_open_sell
? ceil($priceValue - $final_sell_diff) ? ceil($priceValue - $final_sell_diff)
: 0; : 0;
$buy = $liman_open_buy $buy = $montzar_open_buy
? ceil($priceValue + $final_buy_diff) ? ceil($priceValue + $final_buy_diff)
: 0; : 0;
$priceLast = ceil($priceValue + $final_buy_diff); $priceLast = ceil($priceValue + $final_buy_diff);
} else { } else {
if ($priceSource === 'goldir' && $goldir_price !== 0) {
$goldir_profit = (float) Cnt::where('key', 'goldir_diff')->value('value');
$difference = $goldir_profit;
}
$sell = $open_sell $sell = $open_sell
? ceil($priceValue - $difference) ? ceil($priceValue - $difference)
: 0; : 0;
@@ -599,14 +459,12 @@ class ReportController extends Controller
'price' => $priceValue, 'price' => $priceValue,
'main_product' => $pr_price ?? 0, 'main_product' => $pr_price ?? 0,
'taban_gohar' => $tgn ?? 0, 'taban_gohar' => $tgn ?? 0,
'goldir' => $goldir_price ?? 0, 'montzar' => $montzar_price ?? 0,
'liman' => $liman_price ?? 0,
'closed' => false, 'closed' => false,
'time' => now(), 'time' => now(),
]; ];
} }
public function check() public function check()
{ {
$service = Http:: $service = Http::
+2 -2
View File
@@ -20,7 +20,7 @@ class Cnt extends Model
protected $casts = [ protected $casts = [
'value_json'=>'array' 'value_json'=>'array'
]; ];
public function goldir_login(){ /* public function goldir_login(){
$mobile = self::where('key', 'goldir_mobile')->value('value'); $mobile = self::where('key', 'goldir_mobile')->value('value');
$password = self::where('key', 'goldir_password')->value('value'); $password = self::where('key', 'goldir_password')->value('value');
$goldir_base_url=Controller::Config('goldir_base_url')??'https://gold.ir'; $goldir_base_url=Controller::Config('goldir_base_url')??'https://gold.ir';
@@ -44,6 +44,6 @@ class Cnt extends Model
'updated_at' => now() 'updated_at' => now()
]); ]);
return $goldir['access_token']; return $goldir['access_token'];
} }*/
} }
+1 -1
View File
@@ -13,7 +13,7 @@ class ConfigService
public function UpdateConfig($name, $value) public function UpdateConfig($name, $value)
{ {
return Setting::updateOrCreate( return \App\Models\Setting::updateOrCreate(
['key' => $name], ['key' => $name],
['value' => $value] ['value' => $value]
); );
@@ -6,15 +6,20 @@ use App\Models\Cnt;
use App\Models\Order; use App\Models\Order;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
class LimanService class MontzarService
{ {
private function config(): ConfigService
{
return app(ConfigService::class);
}
private function baseUrl(): string private function baseUrl(): string
{ {
return rtrim( return rtrim(
app(ConfigService::class)->Config('liman_base_url') ?: 'https://montpar.ir', $this->config()->Config('montzar_base_url') ?: 'https://montpar.ir',
'/' '/'
); );
} }
@@ -23,37 +28,36 @@ class LimanService
{ {
return $this->baseUrl() . '/' . ltrim($path, '/'); return $this->baseUrl() . '/' . ltrim($path, '/');
} }
public function liman_login()
public function montzarLogin(): string
{ {
$config = app(ConfigService::class); $response = Http::timeout(10)
->acceptJson()
->post($this->endpoint('/server/auth/login'), [
'mobile' => $this->config()->Config('montzar_mobile'),
'password' => $this->config()->Config('montzar_password'),
'provider' => 'customer',
'type_app' => 'client',
])
->json();
$mobile = $config->Config('liman_mobile'); $token = $response['access_token'] ?? $response['token'] ?? null;
$password = $config->Config('liman_password');
$liman = Http::timeout(10)->post($this->endpoint('/server/auth/login'), [
'mobile' => $mobile,
'password' => $password,
'provider' => 'customer',
'type_app' => 'client',
])->json();
$token = $liman['access_token'] ?? $liman['token'] ?? null;
if (!$token) { if (!$token) {
throw new \Exception('Liman login failed: ' . json_encode($liman, JSON_UNESCAPED_UNICODE)); throw new \Exception('Montzar login failed: ' . json_encode($response, JSON_UNESCAPED_UNICODE));
} }
$config->UpdateConfig('liman_token', $token); $this->config()->UpdateConfig('montzar_token', $token);
return $token; return $token;
} }
public function getToken(): string public function getToken(): string
{ {
$token = trim((string) app(ConfigService::class)->Config('liman_token')); $token = trim((string) $this->config()->Config('montzar_token'));
if (!$token) { if (!$token) {
$token = $this->liman_login(); $token = $this->montzarLogin();
} }
return $token; return $token;
@@ -64,27 +68,29 @@ class LimanService
$token = $this->getToken(); $token = $this->getToken();
$response = Http::timeout(7) $response = Http::timeout(7)
->acceptJson()
->withOptions([ ->withOptions([
'curl' => [ 'curl' => [
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4, CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
CURLOPT_TCP_FASTOPEN => 1, CURLOPT_TCP_FASTOPEN => 1,
] ],
]) ])
->withToken($token) ->withToken($token)
->get($this->endpoint('/server/customer/product/list')) ->get($this->endpoint('/server/customer/product/list'))
->json(); ->json();
if ((isset($response['message']) && $response['message'] === 'no authorised') || $response === null) { if ((isset($response['message']) && $response['message'] === 'no authorised') || $response === null) {
$token = $this->liman_login(); $token = $this->montzarLogin();
$response = Http::timeout(7) $response = Http::timeout(7)
->acceptJson()
->withToken($token) ->withToken($token)
->get($this->endpoint('/server/customer/product/list')) ->get($this->endpoint('/server/customer/product/list'))
->json(); ->json();
} }
if (!is_array($response)) { if (!is_array($response)) {
throw new \Exception('Provider product list response is not array'); throw new \Exception('Montzar product list response is not array');
} }
return $response; return $response;
@@ -93,35 +99,34 @@ class LimanService
public function sendOrder(array &$data) public function sendOrder(array &$data)
{ {
$payload = $this->makeOrderPayload($data); $payload = $this->makeOrderPayload($data);
$token = $this->getToken(); $token = $this->getToken();
$httpResponse = $this->postToLiman( $httpResponse = $this->postToMontzar(
$this->endpoint('/server/customer/order'), $this->endpoint('/server/customer/order'),
$token, $token,
$payload $payload
); );
$body = $this->decodeLimanHttpBody($httpResponse); $body = $this->decodeMontzarHttpBody($httpResponse);
if (is_array($body) && ($body['message'] ?? null) === 'no authorised') { if (is_array($body) && ($body['message'] ?? null) === 'no authorised') {
$token = $this->liman_login(); $token = $this->montzarLogin();
$httpResponse = $this->postToLiman( $httpResponse = $this->postToMontzar(
$this->endpoint('/server/customer/order'), $this->endpoint('/server/customer/order'),
$token, $token,
$payload $payload
); );
$body = $this->decodeLimanHttpBody($httpResponse); $body = $this->decodeMontzarHttpBody($httpResponse);
} }
$this->logLimanOrderResponse($httpResponse, $body); $this->logMontzarOrderResponse($httpResponse, $body);
$parsed = $this->parseLimanOrderResponse($body, (int) $data['direction']); $parsed = $this->parseMontzarOrderResponse($body, (int) $data['direction']);
if (!$parsed['ok']) { if (!$parsed['ok']) {
Log::warning('Liman order rejected', [ Log::warning('Montzar order rejected', [
'base_url' => $this->baseUrl(), 'base_url' => $this->baseUrl(),
'status' => $httpResponse->status(), 'status' => $httpResponse->status(),
'body' => $body, 'body' => $body,
@@ -131,11 +136,11 @@ class LimanService
]); ]);
throw new UnprocessableEntityHttpException( throw new UnprocessableEntityHttpException(
$this->formatLimanErrorMessage($parsed['error'], $httpResponse) $this->formatMontzarErrorMessage($parsed['error'], $httpResponse)
); );
} }
$this->syncOrderWithLimanResponse($data, $parsed); $this->syncOrderWithMontzarResponse($data, $parsed);
return $body; return $body;
} }
@@ -143,13 +148,13 @@ class LimanService
private function makeOrderPayload(array $data): array private function makeOrderPayload(array $data): array
{ {
$mazaneh = ((int) $data['direction'] === 1) $mazaneh = ((int) $data['direction'] === 1)
? Cnt::where('key', 'liman_truly_buy_mazaneh')->value('value') ? $this->config()->Config('montzar_truly_buy_mazaneh')
: Cnt::where('key', 'liman_truly_sell_mazaneh')->value('value'); : $this->config()->Config('montzar_truly_sell_mazaneh');
$limanPrice = (float) Cnt::where('key', 'liman_price')->value('value'); $montzarPrice = (float) $this->config()->Config('montzar_price');
$cash = (int) round( $cash = (int) round(
$data['total_price'] ?? ($limanPrice * (float) $data['amount']) $data['total_price'] ?? ($montzarPrice * (float) $data['amount'])
); );
$customerName = auth('customer')->check() $customerName = auth('customer')->check()
@@ -159,15 +164,15 @@ class LimanService
return [ return [
'mazaneh' => (int) $mazaneh, 'mazaneh' => (int) $mazaneh,
'amount' => (float) $data['amount'], 'amount' => (float) $data['amount'],
'description' => app(ConfigService::class)->Config('name_fa') . ' - ' . $customerName, 'description' => $this->config()->Config('name_fa') . ' - ' . $customerName,
'direction' => (int) $data['direction'], 'direction' => (int) $data['direction'],
'product_id' => (int) (app(ConfigService::class)->Config('liman_product_id') ?: 25), 'product_id' => (int) ($this->config()->Config('montzar_product_id') ?: 25),
'cash' => $cash, 'cash' => $cash,
'input_mode' => 'gold', 'input_mode' => 'gold',
]; ];
} }
private function postToLiman(string $url, string $token, array $payload) private function postToMontzar(string $url, string $token, array $payload)
{ {
return Http::timeout(15) return Http::timeout(15)
->acceptJson() ->acceptJson()
@@ -175,7 +180,7 @@ class LimanService
->post($url, $payload); ->post($url, $payload);
} }
private function decodeLimanHttpBody($httpResponse): ?array private function decodeMontzarHttpBody($httpResponse): ?array
{ {
$body = $httpResponse->json(); $body = $httpResponse->json();
@@ -198,25 +203,28 @@ class LimanService
return null; return null;
} }
private function logLimanOrderResponse($httpResponse, $body): void private function logMontzarOrderResponse($httpResponse, $body): void
{ {
try { try {
$value = $body === null $value = $body === null
? $httpResponse->body() ? $httpResponse->body()
: json_encode($body, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); : json_encode($body, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
Cnt::where('key', 'liman_order_response')->update(['value' => $value]); // مربوط به منتزر: settings
$this->config()->UpdateConfig('montzar_order_response', $value);
// عمومی: اگر در const/Cnt داری همان‌جا بماند
Cnt::where('key', 'last_order_log')->update(['value' => $value]); Cnt::where('key', 'last_order_log')->update(['value' => $value]);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::warning('Could not persist liman order response', [ Log::warning('Could not persist montzar order response', [
'error' => $e->getMessage(), 'error' => $e->getMessage(),
]); ]);
} }
} }
private function formatLimanErrorMessage(?string $error, $httpResponse): string private function formatMontzarErrorMessage(?string $error, $httpResponse): string
{ {
if ($error && $error !== 'پاسخ نامعتبر از سرور لیمان (اتصال یا فرمت JSON)') { if ($error && $error !== 'پاسخ نامعتبر از سرور منتظر (اتصال یا فرمت JSON)') {
return $error; return $error;
} }
@@ -224,38 +232,27 @@ class LimanService
$raw = trim((string) $httpResponse->body()); $raw = trim((string) $httpResponse->body());
if ($raw === '') { if ($raw === '') {
return "خطا در ارتباط با لیمان (HTTP {$status})"; return "خطا در ارتباط با منتظر (HTTP {$status})";
} }
if (stripos($raw, '<!DOCTYPE') !== false || stripos($raw, '<html') !== false) { if (stripos($raw, '<!DOCTYPE') !== false || stripos($raw, '<html') !== false) {
return "خطا از سرویس لیمان (HTTP {$status}). پاسخ JSON دریافت نشد."; return "خطا از سرویس منتظر (HTTP {$status}). پاسخ JSON دریافت نشد.";
} }
return mb_substr($raw, 0, 300); return mb_substr($raw, 0, 300);
} }
/** private function parseMontzarOrderResponse($body, int $direction): array
* @return array{ok: bool, provider_id: ?int, error: ?string}
*/
private function parseLimanOrderResponse($body, int $direction): array
{ {
if (!is_array($body)) { if (!is_array($body)) {
return [ return [
'ok' => false, 'ok' => false,
'provider_id' => null, 'provider_id' => null,
'error' => 'پاسخ نامعتبر از سرور لیمان (اتصال یا فرمت JSON)', 'error' => 'پاسخ نامعتبر از سرور منتظر (اتصال یا فرمت JSON)',
]; ];
} }
if (!empty($body['message']) && is_string($body['message'])) { if (!empty($body['message']) && is_string($body['message'])) {
if ($body['message'] === 'no authorised') {
return [
'ok' => false,
'provider_id' => null,
'error' => 'no authorised',
];
}
return [ return [
'ok' => false, 'ok' => false,
'provider_id' => null, 'provider_id' => null,
@@ -330,20 +327,18 @@ class LimanService
return (int) $body['order']['id']; return (int) $body['order']['id'];
} }
if (isset($body[1]) && is_array($body[1])) { foreach ([1, 2] as $index) {
if (!empty($body[1]['id'])) { if (isset($body[$index]) && is_array($body[$index])) {
return (int) $body[1]['id']; if (!empty($body[$index]['id'])) {
} return (int) $body[$index]['id'];
}
if (!empty($body[1]['order']['id'])) { if (!empty($body[$index]['order']['id'])) {
return (int) $body[1]['order']['id']; return (int) $body[$index]['order']['id'];
}
} }
} }
if (isset($body[2]) && is_array($body[2]) && !empty($body[2]['id'])) {
return (int) $body[2]['id'];
}
foreach (['buy', 'sell'] as $sideKey) { foreach (['buy', 'sell'] as $sideKey) {
if (!isset($body[$sideKey]) || !is_array($body[$sideKey])) { if (!isset($body[$sideKey]) || !is_array($body[$sideKey])) {
continue; continue;
@@ -361,14 +356,14 @@ class LimanService
return null; return null;
} }
private function syncOrderWithLimanResponse(array &$data, array $parsed): void private function syncOrderWithMontzarResponse(array &$data, array $parsed): void
{ {
$limanDiff = (float) Cnt::where('key', 'liman_diff')->value('value'); $montzarDiff = (float) $this->config()->Config('montzar_diff');
$limanPrice = (float) Cnt::where('key', 'liman_price')->value('value'); $montzarPrice = (float) $this->config()->Config('montzar_price');
$totalPriceLiman = ((int) $data['direction'] === 1) $totalPriceMontzar = ((int) $data['direction'] === 1)
? ($limanPrice + $limanDiff) ? ($montzarPrice + $montzarDiff)
: ($limanPrice - $limanDiff); : ($montzarPrice - $montzarDiff);
$providerOrderId = $parsed['provider_id'] ?? null; $providerOrderId = $parsed['provider_id'] ?? null;
@@ -377,11 +372,14 @@ class LimanService
$data['order']->provider_id = $providerOrderId; $data['order']->provider_id = $providerOrderId;
} }
$data['order']->total_price_liman = $totalPriceLiman; if (Schema::hasColumn('orders', 'total_price_montzar')) {
$data['order']->total_price_montzar = $totalPriceMontzar;
}
$data['order']->save(); $data['order']->save();
} }
$data['total_price_liman'] = $totalPriceLiman; $data['total_price_montzar'] = $totalPriceMontzar;
if ($providerOrderId !== null) { if ($providerOrderId !== null) {
$data['provider_id'] = $providerOrderId; $data['provider_id'] = $providerOrderId;