fixed taraz for all metals
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Order;
|
||||
use App\Models\Product;
|
||||
|
||||
class BalanceReportService
|
||||
{
|
||||
public const METAL_LABELS = [
|
||||
1 => 'طلا',
|
||||
2 => 'نقره',
|
||||
3 => 'مس',
|
||||
];
|
||||
|
||||
/** @return list<int> */
|
||||
public function catalogMetalIds(): array
|
||||
{
|
||||
return Product::query()
|
||||
->where('active', 1)
|
||||
->whereNotNull('metal_id')
|
||||
->where('metal_id', '>', 0)
|
||||
->distinct()
|
||||
->orderBy('metal_id')
|
||||
->pluck('metal_id')
|
||||
->map(static fn ($id) => (int) $id)
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
public function metalLabel(int $metalId): string
|
||||
{
|
||||
return self::METAL_LABELS[$metalId] ?? "فلز {$metalId}";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{gold: float, cash: float}>
|
||||
*/
|
||||
public function resolveOrderMetalSlices(Order $order): array
|
||||
{
|
||||
$order->loadMissing(['transactions.product']);
|
||||
|
||||
$slices = [];
|
||||
$txWithProduct = $order->transactions->filter(
|
||||
static fn ($tx) => $tx->product_id && abs((float) ($tx->gold ?? 0)) > 0
|
||||
);
|
||||
|
||||
if ($txWithProduct->isNotEmpty()) {
|
||||
foreach ($txWithProduct as $tx) {
|
||||
$metalId = (int) ($tx->product?->metal_id ?? 1);
|
||||
if ($metalId <= 0) {
|
||||
$metalId = 1;
|
||||
}
|
||||
$gold = abs((float) ($tx->gold ?? 0));
|
||||
if ($gold <= 0) {
|
||||
continue;
|
||||
}
|
||||
$slices[$metalId] = ($slices[$metalId] ?? 0.0) + $gold;
|
||||
}
|
||||
|
||||
$totalGold = array_sum($slices);
|
||||
$result = [];
|
||||
foreach ($slices as $metalId => $gold) {
|
||||
$cashShare = $totalGold > 0
|
||||
? (float) $order->total_price * ($gold / $totalGold)
|
||||
: 0.0;
|
||||
$result[(int) $metalId] = ['gold' => $gold, 'cash' => $cashShare];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$amount = (float) ($order->amount ?? 0);
|
||||
$totalPrice = (float) ($order->total_price ?? 0);
|
||||
if ($amount <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$metalId = 1;
|
||||
$tx = $order->transactions->first(static fn ($t) => $t->product_id);
|
||||
if ($tx?->product) {
|
||||
$metalId = max(1, (int) ($tx->product->metal_id ?? 1));
|
||||
}
|
||||
|
||||
return [$metalId => ['gold' => $amount, 'cash' => $totalPrice]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int> $metalIds
|
||||
* @return array<int, array{gold: float, cash: float, gold_abs: float, cash_abs: float}>
|
||||
*/
|
||||
public function initMetalBalanceBuckets(array $metalIds): array
|
||||
{
|
||||
$buckets = [];
|
||||
foreach ($metalIds as $metalId) {
|
||||
$buckets[(int) $metalId] = [
|
||||
'gold' => 0.0,
|
||||
'cash' => 0.0,
|
||||
'gold_abs' => 0.0,
|
||||
'cash_abs' => 0.0,
|
||||
];
|
||||
}
|
||||
|
||||
return $buckets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array{gold: float, cash: float, gold_abs: float, cash_abs: float}> $buckets
|
||||
*/
|
||||
public function applyOrderToBuckets(array &$buckets, Order $order): void
|
||||
{
|
||||
$slices = $this->resolveOrderMetalSlices($order);
|
||||
foreach ($slices as $metalId => $slice) {
|
||||
$metalId = (int) $metalId;
|
||||
if (! isset($buckets[$metalId])) {
|
||||
$buckets[$metalId] = [
|
||||
'gold' => 0.0,
|
||||
'cash' => 0.0,
|
||||
'gold_abs' => 0.0,
|
||||
'cash_abs' => 0.0,
|
||||
];
|
||||
}
|
||||
|
||||
$gold = (float) $slice['gold'];
|
||||
$cash = (float) $slice['cash'];
|
||||
|
||||
if ((int) $order->direction === 1) {
|
||||
$buckets[$metalId]['gold'] += $gold;
|
||||
$buckets[$metalId]['cash'] -= $cash;
|
||||
} elseif ((int) $order->direction === 2) {
|
||||
$buckets[$metalId]['gold'] -= $gold;
|
||||
$buckets[$metalId]['cash'] += $cash;
|
||||
}
|
||||
|
||||
$buckets[$metalId]['gold_abs'] += $gold;
|
||||
$buckets[$metalId]['cash_abs'] += $cash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array{gold: float, cash: float, gold_abs: float, cash_abs: float}> $limanBuckets
|
||||
* @param array<int, array{gold: float, cash: float, gold_abs: float, cash_abs: float}> $kalhorBuckets
|
||||
*/
|
||||
public function buildMetalBalancesResponse(array $limanBuckets, array $kalhorBuckets): array
|
||||
{
|
||||
$metalIds = array_values(array_unique(array_merge(
|
||||
array_keys($limanBuckets),
|
||||
array_keys($kalhorBuckets)
|
||||
)));
|
||||
sort($metalIds);
|
||||
|
||||
$items = [];
|
||||
$totalGoldBalance = 0.0;
|
||||
|
||||
foreach ($metalIds as $metalId) {
|
||||
$metalId = (int) $metalId;
|
||||
$liman = $limanBuckets[$metalId] ?? [
|
||||
'gold' => 0.0,
|
||||
'cash' => 0.0,
|
||||
'gold_abs' => 0.0,
|
||||
'cash_abs' => 0.0,
|
||||
];
|
||||
$kalhor = $kalhorBuckets[$metalId] ?? [
|
||||
'gold' => 0.0,
|
||||
'cash' => 0.0,
|
||||
'gold_abs' => 0.0,
|
||||
'cash_abs' => 0.0,
|
||||
];
|
||||
|
||||
$goldBalance = -$liman['gold'] + $kalhor['gold'];
|
||||
$cashBalance = -$liman['cash'] + $kalhor['cash'];
|
||||
$goldBalanceOfLiman = -$liman['gold'];
|
||||
$goldBalanceOfKalhor = $kalhor['gold'];
|
||||
|
||||
$items[] = [
|
||||
'metal_id' => $metalId,
|
||||
'label' => $this->metalLabel($metalId),
|
||||
'balance' => round($goldBalance, 4),
|
||||
'goldBalance' => round($goldBalance, 4),
|
||||
'cashBalance' => round($cashBalance, 2),
|
||||
'goldBalanceOfLiman' => round($goldBalanceOfLiman, 4),
|
||||
'goldBalanceOfKalhor' => round($goldBalanceOfKalhor, 4),
|
||||
];
|
||||
|
||||
$totalGoldBalance += $goldBalance;
|
||||
}
|
||||
|
||||
return [
|
||||
'items' => $items,
|
||||
'totalGoldBalance' => round($totalGoldBalance, 4),
|
||||
];
|
||||
}
|
||||
|
||||
/** @param array<int, array{gold: float, cash: float, gold_abs: float, cash_abs: float}> $buckets */
|
||||
public function applyKalhorSlice(
|
||||
array &$buckets,
|
||||
float $gold,
|
||||
float $cash,
|
||||
int $direction,
|
||||
int $metalId = 1
|
||||
): void {
|
||||
if (! isset($buckets[$metalId])) {
|
||||
$buckets[$metalId] = [
|
||||
'gold' => 0.0,
|
||||
'cash' => 0.0,
|
||||
'gold_abs' => 0.0,
|
||||
'cash_abs' => 0.0,
|
||||
];
|
||||
}
|
||||
|
||||
if ($direction === 2) {
|
||||
$buckets[$metalId]['gold'] += $gold;
|
||||
$buckets[$metalId]['cash'] -= $cash;
|
||||
} elseif ($direction === 1) {
|
||||
$buckets[$metalId]['gold'] -= $gold;
|
||||
$buckets[$metalId]['cash'] += $cash;
|
||||
}
|
||||
|
||||
$buckets[$metalId]['gold_abs'] += $gold;
|
||||
$buckets[$metalId]['cash_abs'] += $cash;
|
||||
}
|
||||
}
|
||||
@@ -97,27 +97,22 @@ class CategoryService
|
||||
{
|
||||
$names = $this->collectTargetCategoryNames();
|
||||
$created = 0;
|
||||
$order = 0;
|
||||
$maxOrder = (int) Category::max('sort_order');
|
||||
|
||||
foreach ($names as $name) {
|
||||
$order++;
|
||||
$existing = Category::where('name', $name)->first();
|
||||
|
||||
if ($existing) {
|
||||
if ((int) $existing->sort_order !== $order) {
|
||||
$existing->sort_order = $order;
|
||||
$existing->save();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$maxOrder++;
|
||||
Category::create([
|
||||
'name' => $name,
|
||||
'active' => 1,
|
||||
'show_in_filter' => 1,
|
||||
'show_in_select' => 1,
|
||||
'sort_order' => $order,
|
||||
'sort_order' => $maxOrder,
|
||||
]);
|
||||
$created++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user