fix amount 8
This commit is contained in:
@@ -386,6 +386,12 @@ class ProductController extends SuperController
|
|||||||
$data['max_order_cash'] = $hasMax ? (int) $max : null;
|
$data['max_order_cash'] = $hasMax ? (int) $max : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Product::hasShowInAssetsColumn()) {
|
||||||
|
unset($data['show_in_assets']);
|
||||||
|
} elseif (array_key_exists('show_in_assets', $data)) {
|
||||||
|
$data['show_in_assets'] = !empty($data['show_in_assets']);
|
||||||
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ProductController extends SuperController
|
|||||||
$query->where('owner', $user->id);
|
$query->where('owner', $user->id);
|
||||||
})->with(['wallet' => function ($query) use ($user) {
|
})->with(['wallet' => function ($query) use ($user) {
|
||||||
$query->where('owner', $user->id);
|
$query->where('owner', $user->id);
|
||||||
}])->get();
|
}, 'file'])->get();
|
||||||
|
|
||||||
// Prepare the response
|
// Prepare the response
|
||||||
$user['rows'] = $products->map(function ($product) {
|
$user['rows'] = $products->map(function ($product) {
|
||||||
@@ -46,6 +46,10 @@ class ProductController extends SuperController
|
|||||||
'group_type' => $product->group_type ?? null,
|
'group_type' => $product->group_type ?? null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if ($product->relationLoaded('file') && $product->file) {
|
||||||
|
$product->file->setAttribute('full_src', $product->file->src);
|
||||||
|
}
|
||||||
|
|
||||||
return $product;
|
return $product;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use App\Models\BankAccount;
|
|||||||
use App\Models\Price;
|
use App\Models\Price;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Http\Controllers\Admin\TahesabController;
|
use App\Http\Controllers\Admin\TahesabController;
|
||||||
|
use App\Services\AssetSummaryService;
|
||||||
use App\Services\ZaarboxPriceService;
|
use App\Services\ZaarboxPriceService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
@@ -47,6 +48,15 @@ class WalletController extends Controller
|
|||||||
return response()->json($wallet);
|
return response()->json($wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function assetsSummary(AssetSummaryService $assetSummaryService)
|
||||||
|
{
|
||||||
|
$user = auth('customer')->user();
|
||||||
|
|
||||||
|
return response()->json(
|
||||||
|
$assetSummaryService->buildForCustomer((int) $user->id, (int) $user->type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function priceData(Request $request, ZaarboxPriceService $zaarboxPriceService)
|
public function priceData(Request $request, ZaarboxPriceService $zaarboxPriceService)
|
||||||
{
|
{
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class Product extends Model
|
|||||||
private static ?bool $priceOffsetColumnExists = null;
|
private static ?bool $priceOffsetColumnExists = null;
|
||||||
private static ?bool $priceColumnExists = null;
|
private static ?bool $priceColumnExists = null;
|
||||||
private static ?bool $orderLimitColumnsExist = null;
|
private static ?bool $orderLimitColumnsExist = null;
|
||||||
|
private static ?bool $showInAssetsColumnExists = null;
|
||||||
|
|
||||||
protected static function booted(): void
|
protected static function booted(): void
|
||||||
{
|
{
|
||||||
@@ -32,6 +33,9 @@ class Product extends Model
|
|||||||
$product->attributes['max_order_cash']
|
$product->attributes['max_order_cash']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (!static::hasShowInAssetsColumn()) {
|
||||||
|
unset($product->attributes['show_in_assets']);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +91,24 @@ class Product extends Model
|
|||||||
return static::$orderLimitColumnsExist;
|
return static::$orderLimitColumnsExist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function hasShowInAssetsColumn(): bool
|
||||||
|
{
|
||||||
|
if (static::$showInAssetsColumnExists !== null) {
|
||||||
|
return static::$showInAssetsColumnExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
static::$showInAssetsColumnExists = Schema::hasColumn(
|
||||||
|
(new static)->getTable(),
|
||||||
|
'show_in_assets'
|
||||||
|
);
|
||||||
|
} catch (\Throwable) {
|
||||||
|
static::$showInAssetsColumnExists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::$showInAssetsColumnExists;
|
||||||
|
}
|
||||||
|
|
||||||
public function orderLimitsEnabled(): bool
|
public function orderLimitsEnabled(): bool
|
||||||
{
|
{
|
||||||
if (!static::hasOrderLimitColumns() || !($this->order_limit_enabled ?? false)) {
|
if (!static::hasOrderLimitColumns() || !($this->order_limit_enabled ?? false)) {
|
||||||
@@ -137,6 +159,7 @@ class Product extends Model
|
|||||||
'active', // The active status of the record (boolean).
|
'active', // The active status of the record (boolean).
|
||||||
'for_barayand', // Whether it is for Barayand (boolean).
|
'for_barayand', // Whether it is for Barayand (boolean).
|
||||||
'show', // Whether to show the record (boolean).
|
'show', // Whether to show the record (boolean).
|
||||||
|
'show_in_assets', // Show balance on customer assets page cards
|
||||||
'open_sell', // Whether selling is open (boolean).
|
'open_sell', // Whether selling is open (boolean).
|
||||||
'auto_open_at', // Whether selling is open (boolean).
|
'auto_open_at', // Whether selling is open (boolean).
|
||||||
'auto_close_at', // Whether selling is open (boolean).
|
'auto_close_at', // Whether selling is open (boolean).
|
||||||
@@ -161,6 +184,7 @@ class Product extends Model
|
|||||||
'can_canceled' => 'boolean', // Cast to boolean.
|
'can_canceled' => 'boolean', // Cast to boolean.
|
||||||
'active' => 'boolean', // Cast to boolean.
|
'active' => 'boolean', // Cast to boolean.
|
||||||
'show' => 'boolean', // Cast to boolean.
|
'show' => 'boolean', // Cast to boolean.
|
||||||
|
'show_in_assets' => 'boolean',
|
||||||
'for_barayand' => 'boolean', // Cast to boolean.
|
'for_barayand' => 'boolean', // Cast to boolean.
|
||||||
'open_sell' => 'boolean', // Cast to boolean.
|
'open_sell' => 'boolean', // Cast to boolean.
|
||||||
'auto_sell' => 'boolean', // Cast to boolean (you mentioned this in your casts but it's missing in `$fillable`).
|
'auto_sell' => 'boolean', // Cast to boolean (you mentioned this in your casts but it's missing in `$fillable`).
|
||||||
|
|||||||
@@ -0,0 +1,256 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Product;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Rooyesh\Wallet\models\Wallet;
|
||||||
|
|
||||||
|
class AssetSummaryService
|
||||||
|
{
|
||||||
|
private const METAL_LABELS = [
|
||||||
|
1 => 'طلا',
|
||||||
|
2 => 'نقره',
|
||||||
|
3 => 'مس',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function buildForCustomer(int $customerId, int $ownerType): array
|
||||||
|
{
|
||||||
|
$catalog = Product::query()
|
||||||
|
->where('active', 1)
|
||||||
|
->with('file')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$userWallets = Wallet::query()
|
||||||
|
->with(['product.file'])
|
||||||
|
->where('owner', $customerId)
|
||||||
|
->where('owner_type', $ownerType)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$mainWallet = $userWallets->first(fn (Wallet $w) => $w->product_id === null);
|
||||||
|
$metalIds = $this->catalogMetalIds($catalog);
|
||||||
|
$weightUnit = Controller::tradeWeightUnit();
|
||||||
|
$hasCountBased = $this->catalogHasCountBased($catalog);
|
||||||
|
$hasWeightBased = $this->catalogHasWeightBased($catalog);
|
||||||
|
|
||||||
|
$inventoryCards = $this->buildInventoryCards($userWallets);
|
||||||
|
$metalTotals = $this->buildMetalTotals($userWallets, $mainWallet, $metalIds, $weightUnit);
|
||||||
|
$cashWallet = (float) ($mainWallet->cash ?? 0);
|
||||||
|
$assetsRialValue = $this->sumAssetsRialValue($userWallets);
|
||||||
|
$totalRialValue = $cashWallet + $assetsRialValue;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'meta' => [
|
||||||
|
'metal_ids' => $metalIds,
|
||||||
|
'metal_count' => count($metalIds),
|
||||||
|
'has_count_based_products' => $hasCountBased,
|
||||||
|
'has_weight_based_products' => $hasWeightBased,
|
||||||
|
'weight_unit' => $weightUnit,
|
||||||
|
'single_metal' => count($metalIds) === 1,
|
||||||
|
],
|
||||||
|
'cash_wallet' => round($cashWallet, 0),
|
||||||
|
'inventory_cards' => $inventoryCards,
|
||||||
|
'count_products' => $hasCountBased
|
||||||
|
? array_values(array_filter($inventoryCards, fn (array $row) => ($row['display_type'] ?? '') === 'count'))
|
||||||
|
: [],
|
||||||
|
'metal_totals' => $metalTotals,
|
||||||
|
'assets_rial_value' => round($assetsRialValue, 0),
|
||||||
|
'total_rial_value' => round($totalRialValue, 0),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function catalogMetalIds(Collection $catalog): array
|
||||||
|
{
|
||||||
|
return $catalog
|
||||||
|
->pluck('metal_id')
|
||||||
|
->filter(fn ($id) => (int) $id > 0)
|
||||||
|
->map(fn ($id) => (int) $id)
|
||||||
|
->unique()
|
||||||
|
->sort()
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function catalogHasCountBased(Collection $catalog): bool
|
||||||
|
{
|
||||||
|
return $catalog->contains(fn (Product $product) => $this->isCountBasedProduct($product));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function catalogHasWeightBased(Collection $catalog): bool
|
||||||
|
{
|
||||||
|
return $catalog->contains(fn (Product $product) => !$this->isCountBasedProduct($product));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildInventoryCards(Collection $userWallets): array
|
||||||
|
{
|
||||||
|
$cards = [];
|
||||||
|
|
||||||
|
foreach ($userWallets as $walletLine) {
|
||||||
|
if ($walletLine->product_id === null || (float) $walletLine->gold <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$product = $walletLine->product;
|
||||||
|
if (!$product || !$this->shouldShowInAssets($product)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$productPayload = $this->productPayload($product);
|
||||||
|
$isCountBased = $this->isCountBasedProduct($product);
|
||||||
|
|
||||||
|
$cards[] = [
|
||||||
|
'product_id' => (int) $product->id,
|
||||||
|
'title' => (string) $product->title,
|
||||||
|
'group_type' => (string) ($product->group_type ?? ''),
|
||||||
|
'metal_id' => (int) ($product->metal_id ?? 0),
|
||||||
|
'quantity' => round((float) $walletLine->gold, 3),
|
||||||
|
'unit' => Controller::productQuantityUnit($productPayload),
|
||||||
|
'display_type' => $isCountBased ? 'count' : 'weight',
|
||||||
|
'unit_weight' => $this->productUnitWeightLabel($product),
|
||||||
|
'show_in_assets' => true,
|
||||||
|
'file' => $this->filePayload($product),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildMetalTotals(
|
||||||
|
Collection $userWallets,
|
||||||
|
?Wallet $mainWallet,
|
||||||
|
array $metalIds,
|
||||||
|
string $weightUnit
|
||||||
|
): array {
|
||||||
|
if ($metalIds === []) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$mainWalletGrams = Controller::weightToGrams((float) ($mainWallet->gold ?? 0));
|
||||||
|
$totals = [];
|
||||||
|
|
||||||
|
foreach ($metalIds as $metalId) {
|
||||||
|
$productGrams = 0.0;
|
||||||
|
|
||||||
|
foreach ($userWallets as $walletLine) {
|
||||||
|
if ($walletLine->product_id === null || !$walletLine->product) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int) $walletLine->product->metal_id !== (int) $metalId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((string) ($walletLine->product->group_type ?? '') === 'سکه') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$productGrams += Controller::productLineWeightToGrams(
|
||||||
|
$walletLine->product,
|
||||||
|
$walletLine->gold
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$meltedGrams = $this->meltedGramsForMetal($mainWalletGrams, $metalId, $metalIds);
|
||||||
|
$productWeight = round(Controller::gramsToTradeUnit($productGrams), 3);
|
||||||
|
$meltedWeight = round(Controller::gramsToTradeUnit($meltedGrams), 3);
|
||||||
|
|
||||||
|
$totals[] = [
|
||||||
|
'metal_id' => (int) $metalId,
|
||||||
|
'metal_label' => self::METAL_LABELS[$metalId] ?? 'فلز',
|
||||||
|
'label' => 'کل دارایی ' . (self::METAL_LABELS[$metalId] ?? 'فلز'),
|
||||||
|
'product_weight' => $productWeight,
|
||||||
|
'melted_weight' => $meltedWeight,
|
||||||
|
'total_weight' => round($productWeight + $meltedWeight, 3),
|
||||||
|
'unit' => $weightUnit,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $totals;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function meltedGramsForMetal(float $mainWalletGrams, int $metalId, array $catalogMetalIds): float
|
||||||
|
{
|
||||||
|
if ($mainWalletGrams <= 0) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($catalogMetalIds) === 1) {
|
||||||
|
return (int) $catalogMetalIds[0] === (int) $metalId ? $mainWalletGrams : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $metalId === 1 ? $mainWalletGrams : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sumAssetsRialValue(Collection $userWallets): float
|
||||||
|
{
|
||||||
|
$total = 0.0;
|
||||||
|
|
||||||
|
foreach ($userWallets as $walletLine) {
|
||||||
|
if ($walletLine->product_id === null || !$walletLine->product) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$product = $walletLine->product;
|
||||||
|
$qty = (float) $walletLine->gold;
|
||||||
|
$metalId = (int) ($product->metal_id ?? 0);
|
||||||
|
|
||||||
|
if ($metalId === 1) {
|
||||||
|
$total += (float) ($product->price ?? 0) * $qty;
|
||||||
|
} elseif ($metalId === 2 || $metalId === 3) {
|
||||||
|
$total += ((float) ($product->price ?? 0) * (float) ($product->amount ?? 1)) * $qty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shouldShowInAssets(Product $product): bool
|
||||||
|
{
|
||||||
|
if (Product::hasShowInAssetsColumn()) {
|
||||||
|
return (bool) ($product->show_in_assets ?? true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isCountBasedProduct(Product $product): bool
|
||||||
|
{
|
||||||
|
return Controller::isCountBasedProduct($this->productPayload($product));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function productPayload(Product $product): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'unit' => $product->unit ?? null,
|
||||||
|
'direct_price' => $product->direct_price ?? null,
|
||||||
|
'group_type' => $product->group_type ?? null,
|
||||||
|
'amount' => $product->amount ?? null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function productUnitWeightLabel(Product $product): ?string
|
||||||
|
{
|
||||||
|
if (!Controller::hasProductUnitWeight($this->productPayload($product))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = (float) ($product->amount ?? 0);
|
||||||
|
$unit = Controller::productStorageWeightUnit($product);
|
||||||
|
|
||||||
|
return trim($amount . ' ' . $unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function filePayload(Product $product): ?array
|
||||||
|
{
|
||||||
|
if (!$product->relationLoaded('file') || !$product->file) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $product->file->toArray();
|
||||||
|
$file['full_src'] = $product->file->src ?? null;
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
-- نمایش موجودی محصول در صفحه داراییها
|
||||||
|
-- USE دیتابیس_خودتان;
|
||||||
|
|
||||||
|
SET @db = DATABASE();
|
||||||
|
|
||||||
|
SET @sql = IF(
|
||||||
|
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'products' AND COLUMN_NAME = 'show_in_assets') = 0,
|
||||||
|
'ALTER TABLE `products` ADD COLUMN `show_in_assets` TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''نمایش در صفحه داراییها'' AFTER `show`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
+2
-1
@@ -57,7 +57,8 @@ Route::middleware('auth:customer')->group(function () {
|
|||||||
Route::get('/active_finger', [CustomerController::class, 'active_finger']);
|
Route::get('/active_finger', [CustomerController::class, 'active_finger']);
|
||||||
|
|
||||||
//------------------wallet
|
//------------------wallet
|
||||||
Route::get('wallet/me', [WalletController::class, 'walletMe']);
|
Route::get('wallet/me', [WalletController::class, 'walletMe']);
|
||||||
|
Route::get('wallet/assets', [WalletController::class, 'assetsSummary']);
|
||||||
Route::post('wallet/withdraw', [WalletController::class, 'withdraw']);
|
Route::post('wallet/withdraw', [WalletController::class, 'withdraw']);
|
||||||
Route::post('wallet/withdraw_physical', [WalletController::class, 'withdraw_physical']);
|
Route::post('wallet/withdraw_physical', [WalletController::class, 'withdraw_physical']);
|
||||||
Route::post('/wallet/withdraw/table', [WalletController::class, 'indexWithdraw']);
|
Route::post('/wallet/withdraw/table', [WalletController::class, 'indexWithdraw']);
|
||||||
|
|||||||
Reference in New Issue
Block a user