fixed kilo in metals
This commit is contained in:
@@ -16,6 +16,7 @@ use Rooyesh\Wallet\interfaces\WalletInterface;
|
|||||||
use Rooyesh\Wallet\models\Transaction;
|
use Rooyesh\Wallet\models\Transaction;
|
||||||
use Rooyesh\Wallet\models\Wallet;
|
use Rooyesh\Wallet\models\Wallet;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
|
use App\Services\BalanceReportService;
|
||||||
use App\Services\ConfigService;
|
use App\Services\ConfigService;
|
||||||
use App\Services\WalletBalanceService;
|
use App\Services\WalletBalanceService;
|
||||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||||
@@ -133,19 +134,27 @@ class CustomerController extends SuperController
|
|||||||
return response()->json(true);
|
return response()->json(true);
|
||||||
}
|
}
|
||||||
public function tableWallets(Request $request){
|
public function tableWallets(Request $request){
|
||||||
$query_table = Customer::with(['wallet','referral'])->where("is_archive",false)/*->where('type',1)*/;
|
$query_table = Customer::with(['wallet.product:id,metal_id', 'referral'])->where("is_archive",false)/*->where('type',1)*/;
|
||||||
TableEngine::create($query_table, $request)
|
TableEngine::create($query_table, $request)
|
||||||
->initSearch($this->search)
|
->initSearch($this->search)
|
||||||
->select(['*',Customer::$SELECT_TYPE_STR])
|
->select(['*',Customer::$SELECT_TYPE_STR])
|
||||||
->export($query_table);
|
->export($query_table);
|
||||||
|
|
||||||
$balanceService = app(WalletBalanceService::class);
|
$balanceService = app(WalletBalanceService::class);
|
||||||
$mainWalletProductIds = app(ConfigService::class)->mainWalletProductIds();
|
$balanceReport = app(BalanceReportService::class);
|
||||||
|
$catalogMetalIds = $balanceService->catalogMetalIds();
|
||||||
|
$query_table['catalogMetals'] = $balanceReport->catalogMetalsMeta();
|
||||||
|
|
||||||
if (isset($query_table['rows'])) {
|
if (isset($query_table['rows'])) {
|
||||||
$query_table['rows'] = collect($query_table['rows'])->map(function ($row) use ($balanceService, $mainWalletProductIds) {
|
$query_table['rows'] = collect($query_table['rows'])->map(function ($row) use ($balanceService, $catalogMetalIds) {
|
||||||
$wallets = collect($row['wallet'] ?? []);
|
$wallets = collect($row['wallet'] ?? []);
|
||||||
$row['wallet_cash'] = $balanceService->mainWalletCash($wallets);
|
$row['wallet_cash'] = $balanceService->mainWalletCash($wallets);
|
||||||
$row['wallet_gold'] = $balanceService->totalGoldWeight($wallets, $mainWalletProductIds);
|
$metalMap = $balanceService->buildCustomerWalletMetalDisplayMap($wallets, $catalogMetalIds);
|
||||||
|
$row['wallet_metal_gold'] = $metalMap;
|
||||||
|
foreach ($catalogMetalIds as $metalId) {
|
||||||
|
$row['wallet_metal_gold_' . $metalId] = $metalMap[(string) $metalId] ?? 0.0;
|
||||||
|
}
|
||||||
|
$row['wallet_gold'] = array_sum($metalMap);
|
||||||
|
|
||||||
return $row;
|
return $row;
|
||||||
})->values();
|
})->values();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
|||||||
use App\Http\Controllers\Admin\TahesabController;
|
use App\Http\Controllers\Admin\TahesabController;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Services\WalletBalanceService;
|
||||||
use Hekmatinasser\Verta\Verta;
|
use Hekmatinasser\Verta\Verta;
|
||||||
|
|
||||||
|
|
||||||
@@ -301,28 +302,42 @@ class WalletController extends Controller
|
|||||||
public function indexWallet(Request $request)
|
public function indexWallet(Request $request)
|
||||||
{
|
{
|
||||||
$lastPrice = (float) (Price::latest()->first()?->price ?? 0);
|
$lastPrice = (float) (Price::latest()->first()?->price ?? 0);
|
||||||
|
$balanceService = app(WalletBalanceService::class);
|
||||||
|
$catalogMetalIds = $balanceService->catalogMetalIds();
|
||||||
|
$mainWalletMetalId = $balanceService->resolveMainWalletMetalId();
|
||||||
|
|
||||||
// همان فیلتر/جستجوی جدول — بدون صفحهبندی — برای مجموع ردیفهای قابل مشاهده
|
// همان فیلتر/جستجوی جدول — بدون صفحهبندی — برای مجموع ردیفهای قابل مشاهده
|
||||||
$sumQuery = Wallet::query();
|
$sumQuery = Wallet::query();
|
||||||
TableEngine::create($sumQuery, $request->all())
|
TableEngine::create($sumQuery, $request->all())
|
||||||
->initSearch(['customer.name']);
|
->initSearch(['customer.name']);
|
||||||
|
|
||||||
$totalGold = (float) (clone $sumQuery)->sum('gold');
|
$sumRows = (clone $sumQuery)->with('product:id,metal_id')->get();
|
||||||
|
$metalBalances = $balanceService->buildWalletMetalSums($sumRows, $catalogMetalIds);
|
||||||
|
$totalGold = array_sum(array_column($metalBalances, 'gold'));
|
||||||
|
$totalGoldToCash = array_sum(array_column($metalBalances, 'goldToCash'));
|
||||||
$totalCash = (float) (clone $sumQuery)->sum('cash');
|
$totalCash = (float) (clone $sumQuery)->sum('cash');
|
||||||
|
|
||||||
$sums = [
|
$sums = [
|
||||||
'gold' => round($totalGold, 2),
|
'gold' => round($totalGold, 2),
|
||||||
'goldToCash' => round($totalGold * $lastPrice, 2),
|
'goldToCash' => round($totalGoldToCash, 2),
|
||||||
'cash' => round($totalCash, 2),
|
'cash' => round($totalCash, 2),
|
||||||
'cashToGold' => $lastPrice > 0 ? round($totalCash / $lastPrice, 2) : 0,
|
'cashToGold' => $lastPrice > 0 ? round($totalCash / $lastPrice, 2) : 0,
|
||||||
|
'metalBalances' => $metalBalances,
|
||||||
];
|
];
|
||||||
|
|
||||||
$records = Wallet::with('customer');
|
$records = Wallet::with(['customer', 'product:id,metal_id']);
|
||||||
TableEngine::create($records, $request->all())
|
TableEngine::create($records, $request->all())
|
||||||
->initSearch(['customer.name'])
|
->initSearch(['customer.name'])
|
||||||
->select(['*'])
|
->select(['*'])
|
||||||
->export($records);
|
->export($records);
|
||||||
|
|
||||||
|
if (isset($records['rows'])) {
|
||||||
|
foreach ($records['rows'] as &$row) {
|
||||||
|
$balanceService->enrichWalletTableRow($row, $catalogMetalIds, $mainWalletMetalId);
|
||||||
|
}
|
||||||
|
unset($row);
|
||||||
|
}
|
||||||
|
|
||||||
$records['sums'] = $sums;
|
$records['sums'] = $sums;
|
||||||
|
|
||||||
return response()->json($records);
|
return response()->json($records);
|
||||||
|
|||||||
@@ -33,6 +33,35 @@ class BalanceReportService
|
|||||||
return self::METAL_LABELS[$metalId] ?? "فلز {$metalId}";
|
return self::METAL_LABELS[$metalId] ?? "فلز {$metalId}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** واحد نمایش موجودی/تراز هر فلز در ادمین — مس کیلوگرم، بقیه گرم */
|
||||||
|
public function metalDisplayUnit(int $metalId): string
|
||||||
|
{
|
||||||
|
return (int) $metalId === 3 ? 'کیلوگرم' : 'گرم';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gramsToMetalDisplay(float $grams, int $metalId): float
|
||||||
|
{
|
||||||
|
return (int) $metalId === 3 ? $grams / 1000.0 : $grams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
public function catalogMetalsMeta(): array
|
||||||
|
{
|
||||||
|
$items = [];
|
||||||
|
foreach ($this->catalogMetalIds() as $metalId) {
|
||||||
|
$metalId = (int) $metalId;
|
||||||
|
$items[] = [
|
||||||
|
'metal_id' => $metalId,
|
||||||
|
'label' => $this->metalLabel($metalId),
|
||||||
|
'display_unit' => $this->metalDisplayUnit($metalId),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<int, array{gold: float, cash: float}>
|
* @return array<int, array{gold: float, cash: float}>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Price;
|
||||||
|
use App\Models\Product;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,8 +15,10 @@ use Illuminate\Support\Collection;
|
|||||||
*/
|
*/
|
||||||
class WalletBalanceService
|
class WalletBalanceService
|
||||||
{
|
{
|
||||||
public function __construct(private ConfigService $configService)
|
public function __construct(
|
||||||
{
|
private ConfigService $configService,
|
||||||
|
private BalanceReportService $balanceReportService
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mainWalletProductIds(): array
|
public function mainWalletProductIds(): array
|
||||||
@@ -79,6 +84,240 @@ class WalletBalanceService
|
|||||||
return $sum;
|
return $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return list<int> */
|
||||||
|
public function catalogMetalIds(): array
|
||||||
|
{
|
||||||
|
$ids = $this->balanceReportService->catalogMetalIds();
|
||||||
|
|
||||||
|
return $ids !== [] ? $ids : [1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveMainWalletMetalId(): int
|
||||||
|
{
|
||||||
|
$mainWalletProductIds = $this->mainWalletProductIds();
|
||||||
|
if ($mainWalletProductIds !== []) {
|
||||||
|
$product = Product::query()
|
||||||
|
->whereIn('id', $mainWalletProductIds)
|
||||||
|
->orderBy('id')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return max(1, (int) ($product?->metal_id ?? 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
$metalIds = $this->catalogMetalIds();
|
||||||
|
|
||||||
|
return count($metalIds) === 1 ? (int) $metalIds[0] : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* فلز مرتبط با یک ردیف کیف در جدول ادمین.
|
||||||
|
*
|
||||||
|
* @param Collection|array<int, mixed>|null $wallets
|
||||||
|
*/
|
||||||
|
public function resolveWalletLineMetalId(mixed $line, ?int $mainWalletMetalId = null): int
|
||||||
|
{
|
||||||
|
$fundId = $this->lineValue($line, 'fund_id');
|
||||||
|
$productId = $this->lineValue($line, 'product_id');
|
||||||
|
|
||||||
|
if ($fundId !== null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($productId !== null) {
|
||||||
|
$product = $this->lineProduct($line);
|
||||||
|
$metalId = (int) ($product?->metal_id ?? 0);
|
||||||
|
|
||||||
|
return $metalId > 0 ? $metalId : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $mainWalletMetalId ?? $this->resolveMainWalletMetalId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<int> $catalogMetalIds
|
||||||
|
* @return array<string, float>
|
||||||
|
*/
|
||||||
|
public function walletLineMetalGoldMap(
|
||||||
|
mixed $line,
|
||||||
|
array $catalogMetalIds,
|
||||||
|
?int $mainWalletMetalId = null
|
||||||
|
): array {
|
||||||
|
$map = [];
|
||||||
|
foreach ($catalogMetalIds as $metalId) {
|
||||||
|
$map[(string) $metalId] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$goldGrams = $this->walletLineGoldGrams($line);
|
||||||
|
if ($goldGrams <= 0) {
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
$metalId = $this->resolveWalletLineMetalId($line, $mainWalletMetalId);
|
||||||
|
$map[(string) $metalId] = round(
|
||||||
|
$this->balanceReportService->gramsToMetalDisplay($goldGrams, $metalId),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection|array<int, mixed> $walletLines
|
||||||
|
* @param list<int> $catalogMetalIds
|
||||||
|
* @return array<string, float> جمع به گرم
|
||||||
|
*/
|
||||||
|
public function sumWalletMetalGrams(Collection|array $walletLines, array $catalogMetalIds): array
|
||||||
|
{
|
||||||
|
$buckets = [];
|
||||||
|
foreach ($catalogMetalIds as $metalId) {
|
||||||
|
$buckets[(string) (int) $metalId] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mainWalletMetalId = $this->resolveMainWalletMetalId();
|
||||||
|
foreach ($this->walletLines($walletLines) as $line) {
|
||||||
|
$goldGrams = $this->walletLineGoldGrams($line);
|
||||||
|
if ($goldGrams <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$metalId = (string) $this->resolveWalletLineMetalId($line, $mainWalletMetalId);
|
||||||
|
$buckets[$metalId] = ($buckets[$metalId] ?? 0.0) + $goldGrams;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $buckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection|array<int, mixed> $walletLines
|
||||||
|
* @param list<int> $catalogMetalIds
|
||||||
|
* @return list<array{metal_id: int, label: string, gold: float, display_unit: string, goldToCash: float}>
|
||||||
|
*/
|
||||||
|
public function buildWalletMetalSums(Collection|array $walletLines, array $catalogMetalIds): array
|
||||||
|
{
|
||||||
|
$gramBuckets = $this->sumWalletMetalGrams($walletLines, $catalogMetalIds);
|
||||||
|
|
||||||
|
$items = [];
|
||||||
|
foreach ($catalogMetalIds as $metalId) {
|
||||||
|
$metalId = (int) $metalId;
|
||||||
|
$goldGrams = (float) ($gramBuckets[(string) $metalId] ?? 0.0);
|
||||||
|
$displayGold = round($this->balanceReportService->gramsToMetalDisplay($goldGrams, $metalId), 3);
|
||||||
|
$price = $this->livePricePerGram($metalId);
|
||||||
|
$items[] = [
|
||||||
|
'metal_id' => $metalId,
|
||||||
|
'label' => $this->balanceReportService->metalLabel($metalId),
|
||||||
|
'gold' => $displayGold,
|
||||||
|
'display_unit' => $this->balanceReportService->metalDisplayUnit($metalId),
|
||||||
|
'goldToCash' => round($goldGrams * $price, 2),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection|array<int, mixed> $walletLines
|
||||||
|
* @param list<int> $catalogMetalIds
|
||||||
|
* @return array<string, float> مقادیر نمایشی
|
||||||
|
*/
|
||||||
|
public function buildCustomerWalletMetalDisplayMap(Collection|array $walletLines, array $catalogMetalIds): array
|
||||||
|
{
|
||||||
|
$gramBuckets = $this->sumWalletMetalGrams($walletLines, $catalogMetalIds);
|
||||||
|
$map = [];
|
||||||
|
|
||||||
|
foreach ($catalogMetalIds as $metalId) {
|
||||||
|
$metalId = (int) $metalId;
|
||||||
|
$goldGrams = (float) ($gramBuckets[(string) $metalId] ?? 0.0);
|
||||||
|
$map[(string) $metalId] = round(
|
||||||
|
$this->balanceReportService->gramsToMetalDisplay($goldGrams, $metalId),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<int> $catalogMetalIds
|
||||||
|
*/
|
||||||
|
public function enrichWalletTableRow(mixed &$row, array $catalogMetalIds, int $mainWalletMetalId): void
|
||||||
|
{
|
||||||
|
$metalMap = $this->walletLineMetalGoldMap($row, $catalogMetalIds, $mainWalletMetalId);
|
||||||
|
|
||||||
|
if (is_array($row)) {
|
||||||
|
$row['metal_gold'] = $metalMap;
|
||||||
|
foreach ($catalogMetalIds as $metalId) {
|
||||||
|
$row['metal_gold_' . $metalId] = $metalMap[(string) $metalId] ?? 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_object($row)) {
|
||||||
|
$row->metal_gold = $metalMap;
|
||||||
|
foreach ($catalogMetalIds as $metalId) {
|
||||||
|
$row->{'metal_gold_' . $metalId} = $metalMap[(string) $metalId] ?? 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function livePricePerGram(int $metalId): float
|
||||||
|
{
|
||||||
|
if ($metalId === 1) {
|
||||||
|
$live = (int) app(ProductDisplayPriceService::class)->resolveAppBasePrice();
|
||||||
|
if ($live > 0) {
|
||||||
|
return (float) $live;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) (Price::latest('id')->value('price') ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$product = Product::query()
|
||||||
|
->where('active', 1)
|
||||||
|
->where('metal_id', $metalId)
|
||||||
|
->where('price', '>', 0)
|
||||||
|
->orderBy('id')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$product) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$unitPrice = (float) $product->price + (float) ($product->price_profit ?? 0);
|
||||||
|
$amount = (float) ($product->amount ?? 1);
|
||||||
|
|
||||||
|
return $amount > 0 ? $unitPrice * $amount : $unitPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function lineProduct(mixed $line): ?object
|
||||||
|
{
|
||||||
|
if (is_object($line) && isset($line->product)) {
|
||||||
|
return $line->product;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($line) && isset($line['product'])) {
|
||||||
|
$product = $line['product'];
|
||||||
|
|
||||||
|
return is_object($product) ? $product : (object) $product;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function walletLineGoldGrams(mixed $line): float
|
||||||
|
{
|
||||||
|
$gold = (float) ($this->lineValue($line, 'gold') ?? 0);
|
||||||
|
if ($gold <= 0) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$product = $this->lineProduct($line);
|
||||||
|
if ($product !== null) {
|
||||||
|
return Controller::productLineWeightToGrams($product, $gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Controller::weightToGrams($gold);
|
||||||
|
}
|
||||||
|
|
||||||
/** @param Collection|array<int, mixed>|null $wallets */
|
/** @param Collection|array<int, mixed>|null $wallets */
|
||||||
private function mainWalletLine(Collection|array|null $wallets): mixed
|
private function mainWalletLine(Collection|array|null $wallets): mixed
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user