added merge wallet

This commit is contained in:
2026-06-10 16:57:31 +03:30
parent bb94f7a5ba
commit 285767fcd3
5 changed files with 202 additions and 10 deletions
@@ -74,10 +74,13 @@ class CustomerController extends SuperController
public function funds(Request $request,$customer_id)
{
$query_table = Wallet::with(['fund'])->where('owner', $customer_id); // Adjust columns as per your schema
// فقط کیف محصول‌ها (نه کیف اصلی) — هر ردیف = موجودی واقعی یک محصول/فلز
$query_table = Wallet::with(['product:id,title,metal_id,unit'])
->where('owner', $customer_id)
->whereNotNull('product_id');
TableEngine::create($query_table, $request)
->initSearch($this->search)
->select(['id', 'owner', 'cash', 'gold','fund_id','created_at', 'updated_at'])
->select(['id', 'owner', 'cash', 'gold', 'fund_id', 'product_id', 'created_at', 'updated_at'])
->export($query_table);
return response()->json($query_table);
}
+119 -8
View File
@@ -42,11 +42,15 @@ class AssetSummaryService
$catalogById = $catalog->keyBy('id');
// محصولات متصل به کیف اصلی (main_wallet_products) — موجودی‌شان = gold کیف اصلی
$mainWalletProductIds = $this->configService->mainWalletProductIds();
$metalsWithProductWallet = $this->metalIdsWithProductWallet($userWallets, $catalogById, $mainWalletProductIds);
$inventoryCards = array_merge(
$this->buildMeltedInventoryCards($catalog, $catalogById, $mainWallet, $metalIds),
$this->buildInventoryCards($userWallets, $catalogById)
$this->buildMeltedInventoryCards($catalog, $catalogById, $mainWallet, $metalIds, $metalsWithProductWallet, $mainWalletProductIds),
$this->buildInventoryCards($userWallets, $catalogById, $mainWalletProductIds)
);
$metalTotals = $this->buildMetalTotals($userWallets, $mainWallet, $metalIds, $weightUnit, $catalogById);
$metalTotals = $this->buildMetalTotals($userWallets, $mainWallet, $metalIds, $weightUnit, $catalogById, $metalsWithProductWallet, $mainWalletProductIds);
$cashWallet = (float) ($mainWallet->cash ?? 0);
$assetsRialValue = $this->sumAssetsRialValue($userWallets, $catalogById);
$totalRialValue = $cashWallet + $assetsRialValue;
@@ -97,15 +101,51 @@ class AssetSummaryService
Collection $catalog,
Collection $catalogById,
?Wallet $mainWallet,
array $metalIds
array $metalIds,
array $metalsWithProductWallet = [],
array $mainWalletProductIds = []
): array {
$cards = [];
$mainWalletGrams = Controller::weightToGrams((float) ($mainWallet->gold ?? 0));
$assignedMetalIds = [];
$mainProductId = $this->configService->mainProductId();
// حالت صریح: محصولات متصل به کیف اصلی — یک کارت واحد (نماینده = اولین محصول لیست)
if ($mainWalletProductIds !== []) {
$representative = $this->resolveMainWalletRepresentative($catalogById, $mainWalletProductIds);
if (!$representative) {
return [];
}
$mainWalletWeight = (float) ($mainWallet->gold ?? 0);
if ($mainWalletWeight <= 0) {
return [];
}
$productPayload = $this->productPayload($representative);
return [[
'product_id' => (int) $representative->id,
'title' => (string) $representative->title,
'group_type' => $this->meltedGroupTypeLabel($representative),
'metal_id' => (int) ($representative->metal_id ?? 0),
'quantity' => round($mainWalletWeight, 3),
'unit' => Controller::productQuantityUnit($productPayload),
'display_type' => 'weight',
'unit_weight' => $this->productUnitWeightLabel($representative),
'show_in_assets' => $this->shouldShowInAssets($representative),
'is_melted' => true,
'is_main_wallet' => true,
'file' => $this->filePayload($representative),
]];
}
foreach ($metalIds as $metalId) {
if ($metalId <= 0 || in_array($metalId, $assignedMetalIds, true)) {
if (
$metalId <= 0
|| in_array($metalId, $assignedMetalIds, true)
|| in_array((int) $metalId, $metalsWithProductWallet, true)
) {
continue;
}
@@ -186,6 +226,48 @@ class AssetSummaryService
return $group !== '' ? $group : 'آبشده';
}
/** اولین محصولِ لیست main_wallet_products که در کاتالوگ فعال است. */
private function resolveMainWalletRepresentative(Collection $catalogById, array $mainWalletProductIds): ?Product
{
foreach ($mainWalletProductIds as $productId) {
$product = $catalogById->get((int) $productId);
if ($product) {
return $product;
}
}
return null;
}
/** فلزهایی که کاربر روی کیف محصول موجودی دارد — برای جلوگیری از کارت آبشدهٔ تکراری. */
private function metalIdsWithProductWallet(Collection $userWallets, Collection $catalogById, array $mainWalletProductIds = []): array
{
$metalIds = [];
foreach ($userWallets as $walletLine) {
if ($walletLine->product_id === null || (float) $walletLine->gold <= 0) {
continue;
}
// کیف محصولاتِ متصل به کیف اصلی نادیده گرفته می‌شود
if (in_array((int) $walletLine->product_id, $mainWalletProductIds, true)) {
continue;
}
$product = $walletLine->product;
if (!$product) {
continue;
}
$metalId = (int) ($this->catalogProduct($product, $catalogById)->metal_id ?? 0);
if ($metalId > 0) {
$metalIds[] = $metalId;
}
}
return array_values(array_unique($metalIds));
}
/** محصول نمایشی برای موجودی کیف اصلی هر فلز. */
private function resolveDisplayProductForMetal(
Collection $catalog,
@@ -208,7 +290,7 @@ class AssetSummaryService
return $catalog->first(fn (Product $product) => (int) ($product->metal_id ?? 0) === $metalId);
}
private function buildInventoryCards(Collection $userWallets, Collection $catalogById): array
private function buildInventoryCards(Collection $userWallets, Collection $catalogById, array $mainWalletProductIds = []): array
{
$cards = [];
@@ -217,6 +299,11 @@ class AssetSummaryService
continue;
}
// محصول متصل به کیف اصلی دارایی جدا ندارد — کارتش از کیف اصلی ساخته می‌شود
if (in_array((int) $walletLine->product_id, $mainWalletProductIds, true)) {
continue;
}
$product = $walletLine->product;
if (!$product) {
continue;
@@ -248,7 +335,9 @@ class AssetSummaryService
?Wallet $mainWallet,
array $metalIds,
string $weightUnit,
Collection $catalogById
Collection $catalogById,
array $metalsWithProductWallet = [],
array $mainWalletProductIds = []
): array {
if ($metalIds === []) {
return [];
@@ -257,6 +346,13 @@ class AssetSummaryService
$mainWalletGrams = Controller::weightToGrams((float) ($mainWallet->gold ?? 0));
$totals = [];
// فلز نمایندهٔ کیف اصلی در حالت main_wallet_products
$mainWalletMetalId = null;
if ($mainWalletProductIds !== []) {
$representative = $this->resolveMainWalletRepresentative($catalogById, $mainWalletProductIds);
$mainWalletMetalId = $representative ? (int) ($representative->metal_id ?? 0) : null;
}
foreach ($metalIds as $metalId) {
$productGrams = 0.0;
@@ -265,6 +361,11 @@ class AssetSummaryService
continue;
}
// کیف محصولاتِ متصل به کیف اصلی جداگانه شمرده نمی‌شود
if (in_array((int) $walletLine->product_id, $mainWalletProductIds, true)) {
continue;
}
$catalogProduct = $this->catalogProduct($walletLine->product, $catalogById);
if ((int) ($catalogProduct->metal_id ?? 0) !== (int) $metalId) {
continue;
@@ -280,7 +381,17 @@ class AssetSummaryService
);
}
$meltedGrams = $this->meltedGramsForMetalTotal($mainWalletGrams, $metalId, $metalIds);
if ($mainWalletProductIds !== []) {
// حالت صریح: کیف اصلی فقط یک‌بار، زیر فلزِ محصول نماینده
$meltedGrams = ($mainWalletMetalId !== null && (int) $metalId === $mainWalletMetalId)
? $mainWalletGrams
: 0.0;
} else {
// کیف اصلی فقط برای فلزی که هیچ کیف محصولی ندارد به مجموع اضافه می‌شود.
$meltedGrams = in_array((int) $metalId, $metalsWithProductWallet, true)
? 0.0
: $this->meltedGramsForMetalTotal($mainWalletGrams, $metalId, $metalIds);
}
$productWeight = round(Controller::gramsToTradeUnit($productGrams), 3);
$meltedWeight = round(Controller::gramsToTradeUnit($meltedGrams), 3);
$totalWeight = round($productWeight + $meltedWeight, 3);
+32
View File
@@ -116,6 +116,38 @@ class ConfigService
return in_array($default, self::PRICE_PROVIDERS, true) ? $default : 'montzar';
}
/**
* محصولات متصل به کیف اصلی — setting `main_wallet_products`.
* مقدار: idها با کاما (مثل «13,25») یا آرایه JSON (مثل «[13,25]»).
* موجودی این محصولات = gold کیف اصلی (دارایی جدا ندارند).
* فقط opt-in: اگر ست نباشد آرایه خالی برمی‌گردد و رفتار قبلی حفظ می‌شود.
*/
public function mainWalletProductIds(): array
{
$raw = trim($this->getString('main_wallet_products', ''));
if ($raw === '') {
return [];
}
$decoded = json_decode($raw, true);
$parts = is_array($decoded) ? $decoded : explode(',', $raw);
$ids = [];
foreach ($parts as $part) {
$id = (int) trim((string) $part);
if ($id > 0) {
$ids[] = $id;
}
}
return array_values(array_unique($ids));
}
public function isMainWalletProduct(int $productId): bool
{
return in_array($productId, $this->mainWalletProductIds(), true);
}
/**
* شناسه محصول آبشده: اول settings، بعد const.
* مقدار settings می‌تواند id عددی (مثل 13) یا reading_method (مثل estjt_...) باشد.
@@ -0,0 +1,22 @@
-- ============================================================================
-- کلید main_wallet_products — اتصال محصولات به کیف اصلی (gold)
--
-- محصولاتی که id آن‌ها در این کلید است، دارایی جدا ندارند؛
-- موجودی‌شان همان gold کیف اصلی کاربر است (ساختار قدیم تک‌آبشده).
-- اگر چند id باشد، همگی یک موجودی مشترک (کیف اصلی) دارند و در صفحه
-- دارایی‌ها فقط یک کارت (محصول اولِ لیست) ساخته می‌شود.
--
-- مقدار: idها با کاما (مثل «13,25») یا آرایه JSON (مثل «[13,25]»)
-- خالی/غایب = رفتار قبلی بدون هیچ تغییری (بورس مس و پروژه‌های چند‌کیفه)
--
-- نمونه اجرا برای گلد علی:
-- UPDATE `settings` SET `value` = '13,25' WHERE `key` = 'main_wallet_products';
-- ============================================================================
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
SELECT 'main_wallet_products', '', 'محصولات متصل به کیف اصلی', 0, 1,
'idهای محصول با کاما (مثل 13,25). موجودی این محصولات = gold کیف اصلی. خالی = غیرفعال'
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'main_wallet_products' LIMIT 1);
-- اگر کلید از قبل وجود دارد، قابل ادیت نبودنش تضمین شود
UPDATE `settings` SET `can_edit` = 0 WHERE `key` = 'main_wallet_products';
+24
View File
@@ -294,6 +294,30 @@ AND NOT EXISTS (
SELECT 1 FROM `settings` WHERE `key` = 'unit' LIMIT 1
);
-- ---------------------------------------------------------------------------
-- settings — main_wallet_products: محصولات متصل به کیف اصلی (غیرقابل ادیت در پنل)
-- موجودی این محصولات = gold کیف اصلی. خالی = غیرفعال (رفتار پیش‌فرض چندکیفه)
-- مثال گلد علی: UPDATE settings SET value='13,25' WHERE `key`='main_wallet_products';
-- ---------------------------------------------------------------------------
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
SELECT
'main_wallet_products',
'',
'محصولات متصل به کیف اصلی',
0,
1,
'idهای محصول با کاما (مثل 13,25). موجودی این محصولات = gold کیف اصلی. خالی = غیرفعال'
FROM DUAL
WHERE EXISTS (
SELECT 1 FROM information_schema.TABLES
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'settings'
)
AND NOT EXISTS (
SELECT 1 FROM `settings` WHERE `key` = 'main_wallet_products' LIMIT 1
);
UPDATE `settings` SET `can_edit` = 0 WHERE `key` = 'main_wallet_products';
-- ---------------------------------------------------------------------------
-- پایان — برای بورس‌مس (اختیاری، جدا اجرا کنید):
-- UPDATE `settings` SET `value` = 'کیلوگرم' WHERE `key` = 'unit';