added merge wallet
This commit is contained in:
@@ -74,10 +74,13 @@ class CustomerController extends SuperController
|
|||||||
public function funds(Request $request,$customer_id)
|
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)
|
TableEngine::create($query_table, $request)
|
||||||
->initSearch($this->search)
|
->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);
|
->export($query_table);
|
||||||
return response()->json($query_table);
|
return response()->json($query_table);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,11 +42,15 @@ class AssetSummaryService
|
|||||||
|
|
||||||
$catalogById = $catalog->keyBy('id');
|
$catalogById = $catalog->keyBy('id');
|
||||||
|
|
||||||
|
// محصولات متصل به کیف اصلی (main_wallet_products) — موجودیشان = gold کیف اصلی
|
||||||
|
$mainWalletProductIds = $this->configService->mainWalletProductIds();
|
||||||
|
|
||||||
|
$metalsWithProductWallet = $this->metalIdsWithProductWallet($userWallets, $catalogById, $mainWalletProductIds);
|
||||||
$inventoryCards = array_merge(
|
$inventoryCards = array_merge(
|
||||||
$this->buildMeltedInventoryCards($catalog, $catalogById, $mainWallet, $metalIds),
|
$this->buildMeltedInventoryCards($catalog, $catalogById, $mainWallet, $metalIds, $metalsWithProductWallet, $mainWalletProductIds),
|
||||||
$this->buildInventoryCards($userWallets, $catalogById)
|
$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);
|
$cashWallet = (float) ($mainWallet->cash ?? 0);
|
||||||
$assetsRialValue = $this->sumAssetsRialValue($userWallets, $catalogById);
|
$assetsRialValue = $this->sumAssetsRialValue($userWallets, $catalogById);
|
||||||
$totalRialValue = $cashWallet + $assetsRialValue;
|
$totalRialValue = $cashWallet + $assetsRialValue;
|
||||||
@@ -97,15 +101,51 @@ class AssetSummaryService
|
|||||||
Collection $catalog,
|
Collection $catalog,
|
||||||
Collection $catalogById,
|
Collection $catalogById,
|
||||||
?Wallet $mainWallet,
|
?Wallet $mainWallet,
|
||||||
array $metalIds
|
array $metalIds,
|
||||||
|
array $metalsWithProductWallet = [],
|
||||||
|
array $mainWalletProductIds = []
|
||||||
): array {
|
): array {
|
||||||
$cards = [];
|
$cards = [];
|
||||||
$mainWalletGrams = Controller::weightToGrams((float) ($mainWallet->gold ?? 0));
|
$mainWalletGrams = Controller::weightToGrams((float) ($mainWallet->gold ?? 0));
|
||||||
$assignedMetalIds = [];
|
$assignedMetalIds = [];
|
||||||
$mainProductId = $this->configService->mainProductId();
|
$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) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +226,48 @@ class AssetSummaryService
|
|||||||
return $group !== '' ? $group : 'آبشده';
|
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(
|
private function resolveDisplayProductForMetal(
|
||||||
Collection $catalog,
|
Collection $catalog,
|
||||||
@@ -208,7 +290,7 @@ class AssetSummaryService
|
|||||||
return $catalog->first(fn (Product $product) => (int) ($product->metal_id ?? 0) === $metalId);
|
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 = [];
|
$cards = [];
|
||||||
|
|
||||||
@@ -217,6 +299,11 @@ class AssetSummaryService
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// محصول متصل به کیف اصلی دارایی جدا ندارد — کارتش از کیف اصلی ساخته میشود
|
||||||
|
if (in_array((int) $walletLine->product_id, $mainWalletProductIds, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$product = $walletLine->product;
|
$product = $walletLine->product;
|
||||||
if (!$product) {
|
if (!$product) {
|
||||||
continue;
|
continue;
|
||||||
@@ -248,7 +335,9 @@ class AssetSummaryService
|
|||||||
?Wallet $mainWallet,
|
?Wallet $mainWallet,
|
||||||
array $metalIds,
|
array $metalIds,
|
||||||
string $weightUnit,
|
string $weightUnit,
|
||||||
Collection $catalogById
|
Collection $catalogById,
|
||||||
|
array $metalsWithProductWallet = [],
|
||||||
|
array $mainWalletProductIds = []
|
||||||
): array {
|
): array {
|
||||||
if ($metalIds === []) {
|
if ($metalIds === []) {
|
||||||
return [];
|
return [];
|
||||||
@@ -257,6 +346,13 @@ class AssetSummaryService
|
|||||||
$mainWalletGrams = Controller::weightToGrams((float) ($mainWallet->gold ?? 0));
|
$mainWalletGrams = Controller::weightToGrams((float) ($mainWallet->gold ?? 0));
|
||||||
$totals = [];
|
$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) {
|
foreach ($metalIds as $metalId) {
|
||||||
$productGrams = 0.0;
|
$productGrams = 0.0;
|
||||||
|
|
||||||
@@ -265,6 +361,11 @@ class AssetSummaryService
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// کیف محصولاتِ متصل به کیف اصلی جداگانه شمرده نمیشود
|
||||||
|
if (in_array((int) $walletLine->product_id, $mainWalletProductIds, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$catalogProduct = $this->catalogProduct($walletLine->product, $catalogById);
|
$catalogProduct = $this->catalogProduct($walletLine->product, $catalogById);
|
||||||
if ((int) ($catalogProduct->metal_id ?? 0) !== (int) $metalId) {
|
if ((int) ($catalogProduct->metal_id ?? 0) !== (int) $metalId) {
|
||||||
continue;
|
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);
|
$productWeight = round(Controller::gramsToTradeUnit($productGrams), 3);
|
||||||
$meltedWeight = round(Controller::gramsToTradeUnit($meltedGrams), 3);
|
$meltedWeight = round(Controller::gramsToTradeUnit($meltedGrams), 3);
|
||||||
$totalWeight = round($productWeight + $meltedWeight, 3);
|
$totalWeight = round($productWeight + $meltedWeight, 3);
|
||||||
|
|||||||
@@ -116,6 +116,38 @@ class ConfigService
|
|||||||
return in_array($default, self::PRICE_PROVIDERS, true) ? $default : 'montzar';
|
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، بعد const.
|
||||||
* مقدار settings میتواند id عددی (مثل 13) یا reading_method (مثل estjt_...) باشد.
|
* مقدار 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';
|
||||||
@@ -294,6 +294,30 @@ AND NOT EXISTS (
|
|||||||
SELECT 1 FROM `settings` WHERE `key` = 'unit' LIMIT 1
|
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';
|
-- UPDATE `settings` SET `value` = 'کیلوگرم' WHERE `key` = 'unit';
|
||||||
|
|||||||
Reference in New Issue
Block a user