Merge origin/Abshode_Khanegi and resolve WalletController conflict.
Keep unified charge API from remote while preserving main-wallet metal detection for deposits and transaction labels via BalanceReportService. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -20,8 +20,9 @@ use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
use App\Http\Controllers\Admin\TahesabController;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Services\BalanceReportService;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\TransactionMetalService;
|
||||
use App\Services\WalletBalanceService;
|
||||
use Hekmatinasser\Verta\Verta;
|
||||
|
||||
|
||||
@@ -221,10 +222,172 @@ class WalletController extends Controller
|
||||
return response()->json(true);
|
||||
}
|
||||
|
||||
public function index(Request $request, TransactionMetalService $transactionMetalService)
|
||||
/** گزینههای شارژ کیف پول — نقدی + محصولات فعال */
|
||||
public function chargeTargets()
|
||||
{
|
||||
$records = Transaction::with(['customer', 'wallet.product:id,metal_id', 'product:id,metal_id'])
|
||||
->whereNull('fund_id');
|
||||
$configService = app(ConfigService::class);
|
||||
$mainWalletProductIds = $configService->mainWalletProductIds();
|
||||
$balanceReport = app(BalanceReportService::class);
|
||||
|
||||
$targets = [
|
||||
[
|
||||
'key' => 'money',
|
||||
'kind' => 'money',
|
||||
'label' => 'نقدی (ریال)',
|
||||
'unit' => 'ریال',
|
||||
],
|
||||
];
|
||||
|
||||
$products = Product::query()
|
||||
->where('active', 1)
|
||||
->orderBy('metal_id')
|
||||
->orderBy('id')
|
||||
->get(['id', 'title', 'unit', 'metal_id', 'group_type', 'trade_by_quantity', 'amount', 'direct_price']);
|
||||
|
||||
foreach ($products as $product) {
|
||||
$usesMainWallet = in_array((int) $product->id, $mainWalletProductIds, true);
|
||||
$label = (string) $product->title;
|
||||
if ($usesMainWallet) {
|
||||
$label .= ' (کیف اصلی)';
|
||||
}
|
||||
|
||||
$targets[] = [
|
||||
'key' => 'product:' . $product->id,
|
||||
'kind' => 'metal',
|
||||
'product_id' => (int) $product->id,
|
||||
'label' => $label,
|
||||
'unit' => $this->resolveProductChargeUnit($product),
|
||||
'metal_id' => max(1, (int) ($product->metal_id ?? 1)),
|
||||
'uses_main_wallet' => $usesMainWallet,
|
||||
'trade_by_quantity' => (bool) $product->trade_by_quantity,
|
||||
'group_type' => (string) ($product->group_type ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'targets' => $targets,
|
||||
'catalogMetals' => $balanceReport->catalogMetalsMeta(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* شارژ یکپارچه کیف پول — نقدی یا محصول (با رعایت کیف اصلی برای آبشده).
|
||||
*/
|
||||
public function charge_wallet(Request $request)
|
||||
{
|
||||
$productId = (int) $request->input('product_id', 0);
|
||||
if ($productId > 0) {
|
||||
return $this->chargeProductMetal($request, $productId);
|
||||
}
|
||||
|
||||
return $this->charge($request);
|
||||
}
|
||||
|
||||
private function chargeProductMetal(Request $request, int $productId)
|
||||
{
|
||||
$data = $request->all();
|
||||
$product = Product::findOrFail($productId);
|
||||
$customer = Customer::findOrFail($data['customer_id']);
|
||||
$deposit = ((float) ($data['value'] ?? 0)) > 0;
|
||||
|
||||
$effectiveProductId = Controller::effectiveProductWalletId($productId);
|
||||
$wallet_interface = new WalletInterface(
|
||||
(int) $data['customer_id'],
|
||||
(int) $customer->type,
|
||||
null,
|
||||
$effectiveProductId
|
||||
);
|
||||
$wallet = $wallet_interface->wallet;
|
||||
|
||||
if (!$deposit && $wallet !== null && (float) $wallet->gold < abs((float) $data['value'])) {
|
||||
throw new UnprocessableEntityHttpException('مقدار موجودی کمتر از درخواست شماست');
|
||||
}
|
||||
|
||||
$goldBlock = 0;
|
||||
$user = auth()->user();
|
||||
$unitLabel = $this->resolveProductChargeUnit($product);
|
||||
|
||||
$Withdraw = Withdraw::create([
|
||||
'user_id' => $user->id,
|
||||
'customer_id' => $customer->id,
|
||||
'gold' => $data['value'],
|
||||
'note' => $data['note'] ?? null,
|
||||
'sts' => 4,
|
||||
]);
|
||||
|
||||
new TransactionInterface($wallet_interface, [
|
||||
'cash' => 0,
|
||||
'gold' => $data['value'],
|
||||
'product_id' => $productId,
|
||||
'expire_at' => now(),
|
||||
'note' => $data['note'] ?? null,
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'active' => true,
|
||||
], 7, $deposit, false, $goldBlock);
|
||||
|
||||
if ($this->Config('send_to_tahesab') == 'true') {
|
||||
try {
|
||||
$data['direction'] = $deposit ? 1 : 0;
|
||||
$tahesab = new TahesabController();
|
||||
$tahesab->walletGold($data);
|
||||
} catch (\Exception $e) {
|
||||
return response($e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
$status = $deposit ? ' شارژ شد ' : ' کسر شد ';
|
||||
$formatted = self::formatSmsGoldWeight($data['value']);
|
||||
|
||||
if ($this->Config('charge_notif') == 'true') {
|
||||
$message = 'کیف پول کاربر ' . $customer->name . ' به مقدار ' . $formatted . ' ' . $unitLabel . ' در تاریخ ' . verta()->format('Y/n/j H:i:s') . $status . 'بابت' . "\n"
|
||||
. ($data['note'] ?? '')
|
||||
. "\n"
|
||||
. $this->Config('name_fa');
|
||||
User::where('send_sms', 1)->get()->each(function ($admin) use ($message) {
|
||||
$this->send($admin->mobile, $message);
|
||||
});
|
||||
}
|
||||
|
||||
$message = 'کیف پول شما به اندازه ' . $formatted . ' ' . $unitLabel . ' در تاریخ ' . verta()->format('Y/n/j H:i:s') . $status . ' بابت' . "\n"
|
||||
. ($data['note'] ?? '')
|
||||
. "\n"
|
||||
. $this->Config('name_fa');
|
||||
$this->Send($customer->mobile, $message);
|
||||
|
||||
return response()->json(true);
|
||||
}
|
||||
|
||||
private function resolveProductChargeUnit(Product $product): string
|
||||
{
|
||||
$payload = Controller::productUnitPayload($product);
|
||||
|
||||
if (
|
||||
Controller::usesQuantityTrade($payload)
|
||||
&& !Controller::isWeightBasedProductUnit($payload['unit'] ?? null)
|
||||
) {
|
||||
$unit = trim((string) ($payload['unit'] ?? ''));
|
||||
|
||||
return $unit !== '' ? $unit : 'عدد';
|
||||
}
|
||||
|
||||
if (Controller::isWeightBasedProductUnit($payload['unit'] ?? null)) {
|
||||
return trim((string) $payload['unit']);
|
||||
}
|
||||
|
||||
return Controller::productStorageWeightUnit($product);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$balanceReport = app(BalanceReportService::class);
|
||||
$balanceService = app(WalletBalanceService::class);
|
||||
$catalogMetalIds = $balanceService->catalogMetalIds();
|
||||
|
||||
$records = Transaction::with([
|
||||
'customer',
|
||||
'wallet.product:id,metal_id',
|
||||
'product:id,title,metal_id,group_type,unit,amount,trade_by_quantity,direct_price',
|
||||
])->whereNull('fund_id');
|
||||
TableEngine::create($records, $request->all())
|
||||
->initSearch(['order_id', 'customer.name'])
|
||||
->select([
|
||||
@@ -232,9 +395,13 @@ class WalletController extends Controller
|
||||
])->export($records);
|
||||
|
||||
if (isset($records['rows'])) {
|
||||
$records['rows'] = $transactionMetalService->enrichTransactionRows($records['rows']);
|
||||
foreach ($records['rows'] as &$row) {
|
||||
$balanceReport->enrichTransactionTableRow($row, $catalogMetalIds);
|
||||
}
|
||||
unset($row);
|
||||
}
|
||||
$records['catalogMetals'] = $transactionMetalService->catalogMetals();
|
||||
|
||||
$records['catalogMetals'] = $balanceReport->catalogMetalsMeta();
|
||||
|
||||
return response()->json($records);
|
||||
}
|
||||
@@ -289,28 +456,42 @@ class WalletController extends Controller
|
||||
public function indexWallet(Request $request)
|
||||
{
|
||||
$lastPrice = (float) (Price::latest()->first()?->price ?? 0);
|
||||
$balanceService = app(WalletBalanceService::class);
|
||||
$catalogMetalIds = $balanceService->catalogMetalIds();
|
||||
$mainWalletMetalId = $balanceService->resolveMainWalletMetalId();
|
||||
|
||||
// همان فیلتر/جستجوی جدول — بدون صفحهبندی — برای مجموع ردیفهای قابل مشاهده
|
||||
$sumQuery = Wallet::query();
|
||||
TableEngine::create($sumQuery, $request->all())
|
||||
->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');
|
||||
|
||||
$sums = [
|
||||
'gold' => round($totalGold, 2),
|
||||
'goldToCash' => round($totalGold * $lastPrice, 2),
|
||||
'goldToCash' => round($totalGoldToCash, 2),
|
||||
'cash' => round($totalCash, 2),
|
||||
'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())
|
||||
->initSearch(['customer.name'])
|
||||
->select(['*'])
|
||||
->export($records);
|
||||
|
||||
if (isset($records['rows'])) {
|
||||
foreach ($records['rows'] as &$row) {
|
||||
$balanceService->enrichWalletTableRow($row, $catalogMetalIds, $mainWalletMetalId);
|
||||
}
|
||||
unset($row);
|
||||
}
|
||||
|
||||
$records['sums'] = $sums;
|
||||
|
||||
return response()->json($records);
|
||||
|
||||
Reference in New Issue
Block a user