fix: resolve copper unit kilogram display and asset valuation calculations

This commit is contained in:
2026-11-07 12:24:19 +03:30
parent 7dd5304638
commit 808c272e0c
3 changed files with 83 additions and 25 deletions
+12 -5
View File
@@ -503,19 +503,26 @@ class Controller extends BaseController
/** واحد وزن معاملات فلز — در بورس مس پیش‌فرض کیلوگرم است */ /** واحد وزن معاملات فلز — در بورس مس پیش‌فرض کیلوگرم است */
public static function tradeWeightUnit(): string public static function tradeWeightUnit(): string
{ {
return self::resolveTradeWeightUnit( $value = app(ConfigService::class)->getString('unit');
app(ConfigService::class)->getString('unit') $resolved = self::resolveTradeWeightUnit($value);
);
// در بورس مس واحد پایه همیشه کیلوگرم است
if ($resolved === 'گرم' || empty($value)) {
return 'کیلوگرم';
}
return $resolved;
} }
public static function resolveTradeWeightUnit(?string $value): string public static function resolveTradeWeightUnit(?string $value): string
{ {
$unit = trim((string) $value); $unit = trim((string) $value);
if ($unit === 'گرم' || $unit === 'gram' || $unit === 'g') { if ($unit === 'کیلوگرم' || $unit === 'kg' || $unit === 'kilogram') {
return 'گرم'; return 'کیلوگرم';
} }
// در بورس مس واحد مبنا کیلوگرم است
return 'کیلوگرم'; return 'کیلوگرم';
} }
+56 -19
View File
@@ -148,11 +148,17 @@ class AssetSummaryService
float $assetsRialValue, float $assetsRialValue,
float $totalRialValue float $totalRialValue
): array { ): array {
$goldMetal = collect($metalTotals)->first(fn (array $row) => (int) ($row['metal_id'] ?? 0) === 1); $mainMetalId = $this->walletBalanceService->resolveMainWalletMetalId();
$goldWeight = (float) ($goldMetal['total_weight'] ?? 0); $primaryMetal = collect($metalTotals)->first(fn (array $row) => (int) ($row['metal_id'] ?? 0) === (int) $mainMetalId)
$liveGoldPrice = $this->resolveLivePricePerUnit(1); ?? collect($metalTotals)->first(fn (array $row) => (int) ($row['metal_id'] ?? 0) === 3)
$goldRialValue = $goldWeight > 0 && $liveGoldPrice > 0 ?? collect($metalTotals)->first(fn (array $row) => (int) ($row['metal_id'] ?? 0) === 1)
? round($goldWeight * $liveGoldPrice, 0) ?? collect($metalTotals)->first();
$activeMetalId = (int) ($primaryMetal['metal_id'] ?? $mainMetalId);
$metalWeight = (float) ($primaryMetal['total_weight'] ?? 0);
$livePrice = $this->resolveLivePricePerUnit($activeMetalId);
$metalRialValue = $metalWeight > 0 && $livePrice > 0
? round($metalWeight * $livePrice, 0)
: 0.0; : 0.0;
$averageBuyPrice = null; $averageBuyPrice = null;
@@ -161,7 +167,7 @@ class AssetSummaryService
$unrealizedProfitPercent = null; $unrealizedProfitPercent = null;
$unrealizedProfitGold = null; $unrealizedProfitGold = null;
if ($goldWeight > 0) { if ($metalWeight > 0) {
$buyOrders = Order::query() $buyOrders = Order::query()
->where('customer_id', $customerId) ->where('customer_id', $customerId)
->where('direction', 1) ->where('direction', 1)
@@ -174,14 +180,14 @@ class AssetSummaryService
if ($totalBought > 0 && $weightedSum > 0) { if ($totalBought > 0 && $weightedSum > 0) {
$averageBuyPrice = round($weightedSum / $totalBought, 0); $averageBuyPrice = round($weightedSum / $totalBought, 0);
$costBasisRial = round($averageBuyPrice * $goldWeight, 0); $costBasisRial = round($averageBuyPrice * $metalWeight, 0);
$unrealizedProfitRial = round($goldRialValue - $costBasisRial, 0); $unrealizedProfitRial = round($metalRialValue - $costBasisRial, 0);
if ($costBasisRial > 0) { if ($costBasisRial > 0) {
$unrealizedProfitPercent = round(($unrealizedProfitRial / $costBasisRial) * 100, 2); $unrealizedProfitPercent = round(($unrealizedProfitRial / $costBasisRial) * 100, 2);
} }
// سود طلایی: همان سود ریالی تبدیل‌شده به وزن طلا با قیمت زندهٔ امروز // سود وزنی: همان سود ریالی تبدیل‌شده به وزن فلز با قیمت زندهٔ امروز
if ($liveGoldPrice > 0) { if ($livePrice > 0) {
$unrealizedProfitGold = round($unrealizedProfitRial / $liveGoldPrice, 4); $unrealizedProfitGold = round($unrealizedProfitRial / $livePrice, 4);
} }
} }
} }
@@ -190,14 +196,17 @@ class AssetSummaryService
'total_rial_value' => round($totalRialValue, 0), 'total_rial_value' => round($totalRialValue, 0),
'cash_rial' => round($cashWallet, 0), 'cash_rial' => round($cashWallet, 0),
'metal_rial_value' => round($assetsRialValue, 0), 'metal_rial_value' => round($assetsRialValue, 0),
'gold_weight' => round($goldWeight, 3), 'gold_weight' => round($metalWeight, 3),
'gold_rial_value' => $goldRialValue, 'gold_rial_value' => $metalRialValue,
'copper_weight' => round($metalWeight, 3),
'copper_rial_value' => $metalRialValue,
'average_buy_price' => $averageBuyPrice, 'average_buy_price' => $averageBuyPrice,
'cost_basis_rial' => $costBasisRial, 'cost_basis_rial' => $costBasisRial,
'unrealized_profit_rial' => $unrealizedProfitRial, 'unrealized_profit_rial' => $unrealizedProfitRial,
'unrealized_profit_percent' => $unrealizedProfitPercent, 'unrealized_profit_percent' => $unrealizedProfitPercent,
'unrealized_profit_gold' => $unrealizedProfitGold, 'unrealized_profit_gold' => $unrealizedProfitGold,
'live_gold_price' => round($liveGoldPrice, 0), 'live_gold_price' => round($livePrice, 0),
'live_copper_price' => round($livePrice, 0),
]; ];
} }
@@ -743,11 +752,9 @@ class AssetSummaryService
return 0.0; return 0.0;
} }
if (count($catalogMetalIds) === 1) { $mainMetalId = $this->walletBalanceService->resolveMainWalletMetalId();
return (int) $catalogMetalIds[0] === (int) $metalId ? $mainWalletGrams : 0.0;
}
return (int) $metalId === 1 ? $mainWalletGrams : 0.0; return (int) $metalId === (int) $mainMetalId ? $mainWalletGrams : 0.0;
} }
/** /**
@@ -797,8 +804,33 @@ class AssetSummaryService
private function resolveLivePricePerUnit(int $metalId): float private function resolveLivePricePerUnit(int $metalId): float
{ {
$prices = app(ProductDisplayPriceService::class);
$mainMetalId = $this->walletBalanceService->resolveMainWalletMetalId();
if ($metalId === 3 || $metalId === $mainMetalId) {
$copperProduct = Product::query()
->where('active', 1)
->where('metal_id', $metalId)
->orderBy('id')
->first();
if ($copperProduct) {
$base = (float) $prices->resolveOrderBasePrice($copperProduct);
if ($base > 0) {
return $base;
}
}
$live = (float) $prices->resolveAppBasePrice();
if ($live > 0) {
return $live;
}
return (float) (Price::latest('id')->value('price') ?? 0);
}
if ($metalId === 1) { if ($metalId === 1) {
$live = (int) app(ProductDisplayPriceService::class)->resolveAppBasePrice(); $live = (int) $prices->resolveAppBasePrice();
if ($live > 0) { if ($live > 0) {
return (float) $live; return (float) $live;
} }
@@ -817,6 +849,11 @@ class AssetSummaryService
return 0.0; return 0.0;
} }
$base = (float) $prices->resolveOrderBasePrice($product);
if ($base > 0) {
return $base;
}
$unitPrice = $this->productDisplayUnitPrice($product); $unitPrice = $this->productDisplayUnitPrice($product);
$amount = (float) ($product->amount ?? 1); $amount = (float) ($product->amount ?? 1);
+15 -1
View File
@@ -317,10 +317,24 @@ class WalletBalanceService
->orderBy('id') ->orderBy('id')
->first(); ->first();
return max(1, (int) ($product?->metal_id ?? 1)); if ($product && (int) ($product->metal_id ?? 0) > 0) {
return (int) $product->metal_id;
}
}
// در بورس مس، مس فلز اصلی پلتفرم است
$hasCopperProduct = Product::query()
->where('active', 1)
->where('metal_id', 3)
->exists();
if ($hasCopperProduct) {
return 3;
} }
$metalIds = $this->catalogMetalIds(); $metalIds = $this->catalogMetalIds();
if (in_array(3, $metalIds, true)) {
return 3;
}
return count($metalIds) === 1 ? (int) $metalIds[0] : 1; return count($metalIds) === 1 ? (int) $metalIds[0] : 1;
} }