fix wallet
This commit is contained in:
@@ -392,6 +392,12 @@ class ProductController extends SuperController
|
||||
$data['show_in_assets'] = !empty($data['show_in_assets']);
|
||||
}
|
||||
|
||||
if (!Product::hasUseLastPriceIfZeroColumn()) {
|
||||
unset($data['use_last_price_if_zero']);
|
||||
} elseif (array_key_exists('use_last_price_if_zero', $data)) {
|
||||
$data['use_last_price_if_zero'] = !empty($data['use_last_price_if_zero']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,9 +47,13 @@ class ReportController extends Controller
|
||||
|
||||
public function updatePrise()
|
||||
{
|
||||
// $difference = config('fee.single');
|
||||
$difference = Setting::where('key', 'fee_single')->first()->value;
|
||||
$difference = (float) (Setting::where('key', 'fee_single')->value('value') ?? config('fee.single', 0));
|
||||
$lastPrice = Price::latest()->first();
|
||||
|
||||
if (!$lastPrice) {
|
||||
return response()->json();
|
||||
}
|
||||
|
||||
$PriceTriggers = PriceTrigger::where("is_active", true)->get();
|
||||
foreach ($PriceTriggers as $PriceTrigger) {
|
||||
$priseGold = $PriceTrigger->dirction == 1
|
||||
@@ -58,6 +62,9 @@ class ReportController extends Controller
|
||||
|
||||
if (eval('return $priseGold ' . $PriceTrigger->price_condition . ' $PriceTrigger->target_price;')) {
|
||||
$customer = Customer::find($PriceTrigger->customer_id);
|
||||
if (!$customer) {
|
||||
continue;
|
||||
}
|
||||
$message = "قیمت طلا به " . number_format($priseGold, -1) . " در هر گرم رسید\n" .$this->Config('name_fa');
|
||||
if ($PriceTrigger->action == 'email') {
|
||||
Mail::to("$customer->email")->send(new YourMailableClass($message, '', '', '', ''));
|
||||
|
||||
@@ -19,6 +19,7 @@ class Product extends Model
|
||||
private static ?bool $priceColumnExists = null;
|
||||
private static ?bool $orderLimitColumnsExist = null;
|
||||
private static ?bool $showInAssetsColumnExists = null;
|
||||
private static ?bool $useLastPriceIfZeroColumnExists = null;
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
@@ -36,6 +37,9 @@ class Product extends Model
|
||||
if (!static::hasShowInAssetsColumn()) {
|
||||
unset($product->attributes['show_in_assets']);
|
||||
}
|
||||
if (!static::hasUseLastPriceIfZeroColumn()) {
|
||||
unset($product->attributes['use_last_price_if_zero']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,6 +113,24 @@ class Product extends Model
|
||||
return static::$showInAssetsColumnExists;
|
||||
}
|
||||
|
||||
public static function hasUseLastPriceIfZeroColumn(): bool
|
||||
{
|
||||
if (static::$useLastPriceIfZeroColumnExists !== null) {
|
||||
return static::$useLastPriceIfZeroColumnExists;
|
||||
}
|
||||
|
||||
try {
|
||||
static::$useLastPriceIfZeroColumnExists = Schema::hasColumn(
|
||||
(new static)->getTable(),
|
||||
'use_last_price_if_zero'
|
||||
);
|
||||
} catch (\Throwable) {
|
||||
static::$useLastPriceIfZeroColumnExists = false;
|
||||
}
|
||||
|
||||
return static::$useLastPriceIfZeroColumnExists;
|
||||
}
|
||||
|
||||
public function orderLimitsEnabled(): bool
|
||||
{
|
||||
if (!static::hasOrderLimitColumns() || !($this->order_limit_enabled ?? false)) {
|
||||
@@ -160,6 +182,7 @@ class Product extends Model
|
||||
'for_barayand', // Whether it is for Barayand (boolean).
|
||||
'show', // Whether to show the record (boolean).
|
||||
'show_in_assets', // Show balance on customer assets page cards
|
||||
'use_last_price_if_zero', // Keep last DB price when automatic provider returns zero
|
||||
'open_sell', // Whether selling is open (boolean).
|
||||
'auto_open_at', // Whether selling is open (boolean).
|
||||
'auto_close_at', // Whether selling is open (boolean).
|
||||
@@ -180,11 +203,17 @@ class Product extends Model
|
||||
'bubble',
|
||||
];
|
||||
|
||||
protected $attributes = [
|
||||
'show_in_assets' => false,
|
||||
'use_last_price_if_zero' => false,
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'can_canceled' => 'boolean', // Cast to boolean.
|
||||
'active' => 'boolean', // Cast to boolean.
|
||||
'show' => 'boolean', // Cast to boolean.
|
||||
'show_in_assets' => 'boolean',
|
||||
'use_last_price_if_zero' => 'boolean',
|
||||
'for_barayand' => '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`).
|
||||
|
||||
@@ -16,6 +16,11 @@ class AssetSummaryService
|
||||
3 => 'مس',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private readonly ConfigService $configService
|
||||
) {
|
||||
}
|
||||
|
||||
public function buildForCustomer(int $customerId, int $ownerType): array
|
||||
{
|
||||
$catalog = Product::query()
|
||||
@@ -35,8 +40,11 @@ class AssetSummaryService
|
||||
$hasCountBased = $this->catalogHasCountBased($catalog);
|
||||
$hasWeightBased = $this->catalogHasWeightBased($catalog);
|
||||
|
||||
$inventoryCards = $this->buildInventoryCards($userWallets);
|
||||
$metalTotals = $this->buildMetalTotals($userWallets, $mainWallet, $metalIds, $weightUnit);
|
||||
$inventoryCards = array_merge(
|
||||
$this->buildMeltedInventoryCards($catalog, $mainWallet, $metalIds, $weightUnit, $userWallets),
|
||||
$this->buildInventoryCards($userWallets)
|
||||
);
|
||||
$metalTotals = $this->buildMetalTotals($userWallets, $mainWallet, $metalIds, $weightUnit, $catalog);
|
||||
$cashWallet = (float) ($mainWallet->cash ?? 0);
|
||||
$assetsRialValue = $this->sumAssetsRialValue($userWallets);
|
||||
$totalRialValue = $cashWallet + $assetsRialValue;
|
||||
@@ -83,6 +91,131 @@ class AssetSummaryService
|
||||
return $catalog->contains(fn (Product $product) => !$this->isCountBasedProduct($product));
|
||||
}
|
||||
|
||||
private function buildMeltedInventoryCards(
|
||||
Collection $catalog,
|
||||
?Wallet $mainWallet,
|
||||
array $metalIds,
|
||||
string $weightUnit,
|
||||
Collection $userWallets
|
||||
): array {
|
||||
$cards = [];
|
||||
$mainWalletGrams = Controller::weightToGrams((float) ($mainWallet->gold ?? 0));
|
||||
$assignedMetalIds = [];
|
||||
$metalsWithProductWallets = $this->metalIdsWithVisibleProductWallet($userWallets);
|
||||
|
||||
foreach ($this->resolveMeltedProducts($catalog) as $product) {
|
||||
if (!$this->shouldShowInAssets($product)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$metalId = (int) ($product->metal_id ?? 0);
|
||||
if (
|
||||
$metalId <= 0
|
||||
|| in_array($metalId, $assignedMetalIds, true)
|
||||
|| in_array($metalId, $metalsWithProductWallets, true)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$meltedGrams = $this->meltedGramsForMetal($mainWalletGrams, $metalId, $metalIds, $catalog);
|
||||
if ($meltedGrams <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$assignedMetalIds[] = $metalId;
|
||||
$productPayload = $this->productPayload($product);
|
||||
|
||||
$cards[] = [
|
||||
'product_id' => (int) $product->id,
|
||||
'title' => (string) $product->title,
|
||||
'group_type' => $this->meltedGroupTypeLabel($product),
|
||||
'metal_id' => $metalId,
|
||||
'quantity' => round(Controller::gramsToTradeUnit($meltedGrams), 3),
|
||||
'unit' => Controller::productQuantityUnit($productPayload),
|
||||
'display_type' => 'weight',
|
||||
'unit_weight' => $this->productUnitWeightLabel($product),
|
||||
'show_in_assets' => true,
|
||||
'is_melted' => true,
|
||||
'file' => $this->filePayload($product),
|
||||
];
|
||||
}
|
||||
|
||||
return $cards;
|
||||
}
|
||||
|
||||
/**
|
||||
* محصولات آبشده: دسته «آبشده»/«کاتد مس» + محصول اصلی تنظیمات (main_product).
|
||||
*/
|
||||
private function resolveMeltedProducts(Collection $catalog): Collection
|
||||
{
|
||||
$mainProductId = $this->configService->mainProductId();
|
||||
|
||||
return $catalog
|
||||
->filter(fn (Product $product) => $this->isMeltedCatalogProduct($product, $mainProductId))
|
||||
->sortBy(fn (Product $product) => $this->isMainMeltedProduct($product, $mainProductId) ? 0 : 1)
|
||||
->values();
|
||||
}
|
||||
|
||||
private function isMeltedCatalogProduct(Product $product, ?int $mainProductId): bool
|
||||
{
|
||||
if ($mainProductId && (int) $product->id === (int) $mainProductId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->isMeltedTradeProduct($product);
|
||||
}
|
||||
|
||||
private function isMainMeltedProduct(Product $product, ?int $mainProductId): bool
|
||||
{
|
||||
return $mainProductId !== null && (int) $product->id === (int) $mainProductId;
|
||||
}
|
||||
|
||||
private function isMeltedTradeProduct(Product $product): bool
|
||||
{
|
||||
$group = trim((string) ($product->group_type ?? ''));
|
||||
|
||||
return in_array($group, ['آبشده', 'کاتد مس'], true);
|
||||
}
|
||||
|
||||
private function meltedGroupTypeLabel(Product $product): string
|
||||
{
|
||||
$group = trim((string) ($product->group_type ?? ''));
|
||||
|
||||
return $group !== '' ? $group : 'آبشده';
|
||||
}
|
||||
|
||||
private function hasVisibleMeltedProductForMetal(Collection $catalog, int $metalId): bool
|
||||
{
|
||||
return $this->resolveMeltedProducts($catalog)->contains(
|
||||
fn (Product $product) => (int) ($product->metal_id ?? 0) === (int) $metalId
|
||||
&& $this->shouldShowInAssets($product)
|
||||
);
|
||||
}
|
||||
|
||||
/** فلزهایی که کاربر موجودی روی کیف محصول دارد — کارت آبشده جدا لازم نیست. */
|
||||
private function metalIdsWithVisibleProductWallet(Collection $userWallets): array
|
||||
{
|
||||
$metalIds = [];
|
||||
|
||||
foreach ($userWallets as $walletLine) {
|
||||
if ($walletLine->product_id === null || (float) $walletLine->gold <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$product = $walletLine->product;
|
||||
if (!$product || !$this->shouldShowInAssets($product)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$metalId = (int) ($product->metal_id ?? 0);
|
||||
if ($metalId > 0) {
|
||||
$metalIds[] = $metalId;
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($metalIds));
|
||||
}
|
||||
|
||||
private function buildInventoryCards(Collection $userWallets): array
|
||||
{
|
||||
$cards = [];
|
||||
@@ -121,7 +254,8 @@ class AssetSummaryService
|
||||
Collection $userWallets,
|
||||
?Wallet $mainWallet,
|
||||
array $metalIds,
|
||||
string $weightUnit
|
||||
string $weightUnit,
|
||||
Collection $catalog
|
||||
): array {
|
||||
if ($metalIds === []) {
|
||||
return [];
|
||||
@@ -152,7 +286,7 @@ class AssetSummaryService
|
||||
);
|
||||
}
|
||||
|
||||
$meltedGrams = $this->meltedGramsForMetal($mainWalletGrams, $metalId, $metalIds);
|
||||
$meltedGrams = $this->meltedGramsForMetal($mainWalletGrams, $metalId, $metalIds, $catalog);
|
||||
$productWeight = round(Controller::gramsToTradeUnit($productGrams), 3);
|
||||
$meltedWeight = round(Controller::gramsToTradeUnit($meltedGrams), 3);
|
||||
|
||||
@@ -170,12 +304,20 @@ class AssetSummaryService
|
||||
return $totals;
|
||||
}
|
||||
|
||||
private function meltedGramsForMetal(float $mainWalletGrams, int $metalId, array $catalogMetalIds): float
|
||||
{
|
||||
private function meltedGramsForMetal(
|
||||
float $mainWalletGrams,
|
||||
int $metalId,
|
||||
array $catalogMetalIds,
|
||||
Collection $catalog
|
||||
): float {
|
||||
if ($mainWalletGrams <= 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (!$this->hasVisibleMeltedProductForMetal($catalog, $metalId)) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (count($catalogMetalIds) === 1) {
|
||||
return (int) $catalogMetalIds[0] === (int) $metalId ? $mainWalletGrams : 0.0;
|
||||
}
|
||||
@@ -209,7 +351,7 @@ class AssetSummaryService
|
||||
private function shouldShowInAssets(Product $product): bool
|
||||
{
|
||||
if (Product::hasShowInAssetsColumn()) {
|
||||
return (bool) ($product->show_in_assets ?? true);
|
||||
return (bool) ($product->show_in_assets ?? false);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -33,7 +33,17 @@ class ProductPriceService
|
||||
}
|
||||
|
||||
$offsetPercent = self::offsetPercent($product);
|
||||
$data = ['price' => self::adjustedTotal($basePrice, $baseProfit, $offsetPercent)];
|
||||
$adjustedPrice = self::adjustedTotal($basePrice, $baseProfit, $offsetPercent);
|
||||
|
||||
if (
|
||||
$adjustedPrice <= 0
|
||||
&& Product::hasUseLastPriceIfZeroColumn()
|
||||
&& ($product->use_last_price_if_zero ?? false)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = ['price' => $adjustedPrice];
|
||||
|
||||
if (\Illuminate\Support\Facades\Schema::hasColumn($product->getTable(), 'price_profit')) {
|
||||
$data['price_profit'] = 0;
|
||||
|
||||
Reference in New Issue
Block a user