added some feature for accounting and price

This commit is contained in:
2026-06-28 15:16:39 +03:30
parent 9f92466ada
commit 3801e5ee88
11 changed files with 423 additions and 39 deletions
+59
View File
@@ -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 ? 'فروش آبشده' : 'معامله');
}
}
+28 -5
View File
@@ -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));
}
+3 -1
View File
@@ -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(),
];
}