Add gold credit feature gated by SuperAdmin enable_gold_credit.
Port tables, APIs, and overdue cron from goldali, default the flag off, and keep customer routes behind auth. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\DB\Te\TableEngine;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\GoldCredit;
|
||||
use App\Models\GoldCreditInstallment;
|
||||
use App\Models\GoldCreditRequest;
|
||||
use App\Services\GoldCreditService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GoldCreditController extends Controller
|
||||
{
|
||||
public function __construct(private GoldCreditService $service)
|
||||
{
|
||||
}
|
||||
|
||||
private function ensureEnabled()
|
||||
{
|
||||
if (! app(\App\Services\ConfigService::class)->isGoldCreditEnabled()) {
|
||||
abort(403, 'اعتبار طلایی برای این نسخه فعال نیست');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$data = $request->validate([
|
||||
'customer_id' => 'required|integer|exists:customers,id',
|
||||
'gold_amount' => 'required|numeric|min:0.001',
|
||||
'months' => 'required|integer|min:1|max:120',
|
||||
'interest_type' => 'nullable|in:none,percent,fixed_gram',
|
||||
'interest_value' => 'nullable|numeric|min:0',
|
||||
'delivery_method' => 'nullable|in:auto,manual,in_person',
|
||||
'notes' => 'nullable|string',
|
||||
'has_check' => 'nullable|boolean',
|
||||
'has_contract' => 'nullable|boolean',
|
||||
'check_note' => 'nullable|string|max:255',
|
||||
'contract_note' => 'nullable|string|max:255',
|
||||
'penalty_type' => 'nullable|in:rial,gold',
|
||||
'penalty_amount' => 'nullable|numeric|min:0',
|
||||
'grace_hours' => 'nullable|integer|min:0|max:720',
|
||||
]);
|
||||
|
||||
$credit = $this->service->createCredit($data, auth()->id(), 'admin_direct');
|
||||
return response()->json($credit);
|
||||
}
|
||||
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$data = $request->validate([
|
||||
'gold_amount' => 'nullable|numeric|min:0.001',
|
||||
'months' => 'nullable|integer|min:1|max:120',
|
||||
'interest_type' => 'nullable|in:none,percent,fixed_gram',
|
||||
'interest_value' => 'nullable|numeric|min:0',
|
||||
'notes' => 'nullable|string',
|
||||
'status' => 'nullable|in:cancelled',
|
||||
'has_check' => 'nullable|boolean',
|
||||
'has_contract' => 'nullable|boolean',
|
||||
'check_note' => 'nullable|string|max:255',
|
||||
'contract_note' => 'nullable|string|max:255',
|
||||
'penalty_type' => 'nullable|in:rial,gold',
|
||||
'penalty_amount' => 'nullable|numeric|min:0',
|
||||
'grace_hours' => 'nullable|integer|min:0|max:720',
|
||||
]);
|
||||
|
||||
$credit = $this->service->updateCredit($id, $data);
|
||||
return response()->json($credit);
|
||||
}
|
||||
|
||||
public function table(Request $request)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$data = $request->all();
|
||||
if (isset($data['select']) && is_null($data['select'])) {
|
||||
$data['select'] = [];
|
||||
}
|
||||
|
||||
$query = GoldCredit::with(['customer:id,name,mobile', 'creator:id,name'])
|
||||
->whereIn('status', ['pending', 'active', 'completed']);
|
||||
|
||||
TableEngine::create($query, $data)
|
||||
->initSearch(['notes', 'customer.name', 'customer.mobile'])
|
||||
->select(['*'])
|
||||
->export($query);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function requestsTable(Request $request)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$data = $request->all();
|
||||
if (isset($data['select']) && is_null($data['select'])) {
|
||||
$data['select'] = [];
|
||||
}
|
||||
|
||||
$query = GoldCreditRequest::with(['customer:id,name,mobile']);
|
||||
|
||||
TableEngine::create($query, $data)
|
||||
->initSearch(['note', 'admin_note', 'customer.name', 'customer.mobile'])
|
||||
->select(['*'])
|
||||
->export($query);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function customerInstallments(Request $request, int $customerId)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$credit = GoldCredit::with('installments')
|
||||
->where('customer_id', $customerId)
|
||||
->whereIn('status', ['pending', 'active', 'completed'])
|
||||
->orderByDesc('id')
|
||||
->first();
|
||||
|
||||
if (!$credit) {
|
||||
return response()->json(['rows' => [], 'total' => 0, 'credit' => null]);
|
||||
}
|
||||
|
||||
$this->service->refreshOverdueStatuses($credit);
|
||||
|
||||
return response()->json([
|
||||
'rows' => $credit->installments,
|
||||
'total' => $credit->installments->count(),
|
||||
'credit' => $credit,
|
||||
]);
|
||||
}
|
||||
|
||||
public function approveRequest(Request $request, int $id)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$data = $request->validate([
|
||||
'gold_amount' => 'nullable|numeric|min:0.001',
|
||||
'months' => 'required|integer|min:1|max:120',
|
||||
'interest_type' => 'nullable|in:none,percent,fixed_gram',
|
||||
'interest_value' => 'nullable|numeric|min:0',
|
||||
'delivery_method' => 'nullable|in:auto,manual,in_person',
|
||||
'admin_note' => 'nullable|string',
|
||||
'notes' => 'nullable|string',
|
||||
'has_check' => 'nullable|boolean',
|
||||
'has_contract' => 'nullable|boolean',
|
||||
'check_note' => 'nullable|string|max:255',
|
||||
'contract_note' => 'nullable|string|max:255',
|
||||
'penalty_type' => 'nullable|in:rial,gold',
|
||||
'penalty_amount' => 'nullable|numeric|min:0',
|
||||
'grace_hours' => 'nullable|integer|min:0|max:720',
|
||||
]);
|
||||
|
||||
$credit = $this->service->approveRequest($id, $data, auth()->id());
|
||||
return response()->json($credit);
|
||||
}
|
||||
|
||||
public function rejectRequest(Request $request, int $id)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$data = $request->validate([
|
||||
'admin_note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$result = $this->service->rejectRequest($id, $data['admin_note'] ?? null);
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
public function payInstallments(Request $request)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$data = $request->validate([
|
||||
'gold_credit_id' => 'required|integer|exists:gold_credits,id',
|
||||
'installment_ids' => 'required|array|min:1',
|
||||
'installment_ids.*' => 'integer|exists:gold_credit_installments,id',
|
||||
'pay_method' => 'required|in:gold,rial,mixed',
|
||||
'gold_amount' => 'nullable|numeric|min:0',
|
||||
'rial_amount' => 'nullable|integer|min:0',
|
||||
]);
|
||||
|
||||
$credit = GoldCredit::findOrFail($data['gold_credit_id']);
|
||||
$result = $this->service->payInstallments(
|
||||
$credit,
|
||||
$data['installment_ids'],
|
||||
$data['pay_method'],
|
||||
$data['gold_amount'] ?? null,
|
||||
$data['rial_amount'] ?? null,
|
||||
auth()->id()
|
||||
);
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
public function preview(Request $request)
|
||||
{
|
||||
$this->ensureEnabled();
|
||||
|
||||
$data = $request->validate([
|
||||
'gold_amount' => 'required|numeric|min:0.001',
|
||||
'months' => 'required|integer|min:1|max:120',
|
||||
'interest_type' => 'nullable|in:none,percent,fixed_gram',
|
||||
'interest_value' => 'nullable|numeric|min:0',
|
||||
]);
|
||||
|
||||
$plan = $this->service->buildInstallmentPlan(
|
||||
(float) $data['gold_amount'],
|
||||
(int) $data['months'],
|
||||
$data['interest_type'] ?? 'none',
|
||||
(float) ($data['interest_value'] ?? 0)
|
||||
);
|
||||
|
||||
return response()->json($plan);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user