'طلا', 2 => 'نقره', 3 => 'مس', ]; /** @return list */ 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}"; } /** واحد نمایش موجودی/تراز هر فلز در ادمین — مس کیلوگرم، بقیه گرم */ public function metalDisplayUnit(int $metalId): string { return (int) $metalId === 3 ? 'کیلوگرم' : 'گرم'; } public function gramsToMetalDisplay(float $grams, int $metalId): float { return (int) $metalId === 3 ? $grams / 1000.0 : $grams; } /** * @return array */ public function catalogMetalsMeta(): array { $items = []; foreach ($this->catalogMetalIds() as $metalId) { $metalId = (int) $metalId; $items[] = [ 'metal_id' => $metalId, 'label' => $this->metalLabel($metalId), 'display_unit' => $this->metalDisplayUnit($metalId), ]; } return $items; } /** * @return array */ 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 $metalIds * @return array */ 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 $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 $limanBuckets * @param array $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 $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; } }