added some feature for accounting and price
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Order;
|
||||
use App\Models\TransactionsAdmin;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* دفترکل حسابداری داخلی (transactions_admins).
|
||||
*
|
||||
* اصل: گزارشات باید همیشه کامل باشد — مستقل از اینکه اپ به حسابداری بیرونی (تهحساب و …) وصل است یا نه.
|
||||
* این سرویس تنها نقطهٔ متمرکز ثبت سند دفترکل برای معامله/کیفپول/پاداش است و idempotent عمل میکند.
|
||||
*/
|
||||
class AccountingLedgerService
|
||||
{
|
||||
/**
|
||||
* ثبت سند دفترکل برای معاملهٔ خرید/فروش مشتری.
|
||||
* idempotent بر اساس order_id — اگر قبلاً ثبت شده باشد همان را برمیگرداند.
|
||||
*/
|
||||
public function recordTrade(?Order $order): ?TransactionsAdmin
|
||||
{
|
||||
if (! $order || ! $order->id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$existing = TransactionsAdmin::where('order_id', $order->id)->first();
|
||||
if ($existing) {
|
||||
return $existing;
|
||||
}
|
||||
|
||||
try {
|
||||
return TransactionsAdmin::create([
|
||||
'customer_id' => $order->customer_id,
|
||||
'customer_to_id' => $order->customer_id,
|
||||
'order_id' => $order->id,
|
||||
'user_id' => $order->customer_id,
|
||||
'wallet' => null,
|
||||
'transaction_id' => null,
|
||||
'cash' => (int) round((float) ($order->total_price ?? 0)),
|
||||
'note' => $this->tradeNote((int) ($order->direction ?? 0)),
|
||||
'type' => 1,
|
||||
'gold' => (float) ($order->amount ?? 0),
|
||||
'balance_cash' => 0,
|
||||
'balance_gold' => 0,
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
report($e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** توضیح سند معامله — همسان با desc تهحساب تا گزارشات و حسابداری یکی دیده شوند. */
|
||||
public function tradeNote(int $direction): string
|
||||
{
|
||||
return $direction === 1 ? 'خرید آبشده' : ($direction === 2 ? 'فروش آبشده' : 'معامله');
|
||||
}
|
||||
}
|
||||
@@ -580,21 +580,46 @@ class ConfigService
|
||||
return $current >= $openStr && $current <= $closeStr;
|
||||
}
|
||||
|
||||
/** ساعت کاری سراسری (close_price) + بازه auto_open_at/auto_close_at هر محصول */
|
||||
/**
|
||||
* آیا محصول بازه زمانی اختصاصی خودش را override کرده؟
|
||||
* فقط وقتی سوییچ override_trading_hours روشن باشد و بازه معتبری (شروع != پایان) داشته باشد.
|
||||
*/
|
||||
public function productOverridesTradingHours(Product $product): bool
|
||||
{
|
||||
if (!Product::hasOverrideTradingHoursColumn()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!($product->override_trading_hours ?? false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->hasProductTradingWindow($product->auto_open_at, $product->auto_close_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* ساعت معامله یک محصول:
|
||||
* - اگر سوییچ override محصول روشن باشد → فقط بازه خود محصول حاکم است (سراسری نادیده گرفته میشود).
|
||||
* - در غیر این صورت → فیلتر سراسری close_price + startDay/endDay اعمال میشود.
|
||||
*/
|
||||
public function isProductWithinTradingHours(Product $product, ?Carbon $now = null): bool
|
||||
{
|
||||
if ($this->productOverridesTradingHours($product)) {
|
||||
return $this->isWithinTimeWindow($product->auto_open_at, $product->auto_close_at, $now);
|
||||
}
|
||||
|
||||
if ($this->isClosePriceEnabled() && $this->isOutsideTradingHours($now)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isWithinTimeWindow($product->auto_open_at, $product->auto_close_at, $now);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function productTradingClosedMessage(Product $product): string
|
||||
{
|
||||
$title = trim((string) ($product->title ?? 'محصول'));
|
||||
|
||||
if ($this->hasProductTradingWindow($product->auto_open_at, $product->auto_close_at)) {
|
||||
if ($this->productOverridesTradingHours($product)) {
|
||||
$open = $this->formatProductTime($product->auto_open_at);
|
||||
$close = $this->formatProductTime($product->auto_close_at);
|
||||
|
||||
@@ -606,8 +631,6 @@ class ConfigService
|
||||
|
||||
public function assertProductTradingOpen(Product $product, ?Carbon $now = null): void
|
||||
{
|
||||
$this->assertTradingOpen($now);
|
||||
|
||||
if (!$this->isProductWithinTradingHours($product, $now)) {
|
||||
throw new UnprocessableEntityHttpException($this->productTradingClosedMessage($product));
|
||||
}
|
||||
|
||||
@@ -90,7 +90,8 @@ class LivePriceCacheService
|
||||
'main_product' => 0,
|
||||
'montzar' => 0,
|
||||
'zaarbox' => 0,
|
||||
'closed' => true,
|
||||
'closed' => false,
|
||||
'status' => 'no_quote',
|
||||
'time' => now(),
|
||||
];
|
||||
} else {
|
||||
@@ -123,6 +124,7 @@ class LivePriceCacheService
|
||||
'montzar' => $montzarSource,
|
||||
'zaarbox' => $zaarboxSource,
|
||||
'closed' => false,
|
||||
'status' => 'open',
|
||||
'time' => now(),
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user