feat(convert): let customers list and change pending requests

History is limited to the signed-in customer. Update and delete only apply while the request is still pending.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-11-03 13:04:08 +03:30
co-authored by Cursor
parent 7b81adc096
commit 9769f2ffad
3 changed files with 139 additions and 16 deletions
@@ -10,6 +10,16 @@ use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
class CopperConvertRequestController extends Controller
{
public function index(CopperConvertRequestService $service)
{
$customer = auth('customer')->user();
if (!$customer instanceof Customer) {
throw new UnprocessableEntityHttpException('مشتری یافت نشد.');
}
return response()->json($service->listForCustomer($customer));
}
public function store(Request $request, CopperConvertRequestService $service)
{
$customer = auth('customer')->user();
@@ -35,4 +45,45 @@ class CopperConvertRequestController extends Controller
return response()->json($row);
}
public function update(Request $request, int $id, CopperConvertRequestService $service)
{
$customer = $this->customer();
self::assertCustomerIdentityVerified($customer);
if (!$customer->trade_active) {
throw new UnprocessableEntityHttpException('امکان سفارش برای شما غیرفعال است.');
}
$source = (string) $request->input('source');
if (!in_array($source, ['katod', 'maftoul', 'shamsh'], true)) {
throw new UnprocessableEntityHttpException('نوع دارایی نامعتبر است.');
}
$row = $service->update(
$customer,
$id,
$source,
max(0, (int) $request->input('rings15')),
max(0, (int) $request->input('rings25'))
);
return response()->json($row);
}
public function destroy(int $id, CopperConvertRequestService $service)
{
$service->remove($this->customer(), $id);
return response()->json(['ok' => true]);
}
private function customer(): Customer
{
$customer = auth('customer')->user();
if (!$customer instanceof Customer) {
throw new UnprocessableEntityHttpException('مشتری یافت نشد.');
}
return $customer;
}
}
+85 -16
View File
@@ -30,22 +30,32 @@ class CopperConvertRequestService
$quote = $this->quote($customer, $source, $rings15, $rings25);
return CopperConvertRequest::query()->create([
'customer_id' => $customer->id,
'status' => 'pending',
'source' => $source,
'source_product_id' => $quote['source']->id,
'asset_unit' => $quote['unit'],
'consumed_amount' => $quote['consumed'],
'leftover_amount' => $quote['leftover'],
'source_unit_price' => $quote['source_unit_price'],
'wire15_product_id' => $quote['wire15']?->id,
'wire15_rings' => $rings15,
'wire15_unit_price' => $quote['price15'],
'wire25_product_id' => $quote['wire25']?->id,
'wire25_rings' => $rings25,
'wire25_unit_price' => $quote['price25'],
]);
return CopperConvertRequest::query()->create(
$this->quoteAttributes($customer, $source, $rings15, $rings25, $quote)
);
}
public function update(Customer $customer, int $id, string $source, int $rings15, int $rings25): CopperConvertRequest
{
if ($rings15 < 1 && $rings25 < 1) {
throw new UnprocessableEntityHttpException('حداقل یک حلقه انتخاب کنید.');
}
return DB::transaction(function () use ($customer, $id, $source, $rings15, $rings25) {
$row = $this->ownedPending($customer, $id);
$quote = $this->quote($customer, $source, $rings15, $rings25);
$row->fill($this->quoteAttributes($customer, $source, $rings15, $rings25, $quote));
$row->save();
return $row;
});
}
public function remove(Customer $customer, int $id): void
{
DB::transaction(function () use ($customer, $id) {
$this->ownedPending($customer, $id)->delete();
});
}
public function listForAdmin(): array
@@ -82,6 +92,29 @@ class CopperConvertRequestService
->all();
}
public function listForCustomer(Customer $customer): array
{
return CopperConvertRequest::query()
->where('customer_id', $customer->id)
->orderByDesc('id')
->limit(50)
->get()
->map(function (CopperConvertRequest $row) {
return [
'id' => $row->id,
'status' => $row->status,
'source' => $row->source,
'asset_unit' => $row->asset_unit,
'consumed_amount' => $row->consumed_amount,
'leftover_amount' => $row->leftover_amount,
'wire15_rings' => $row->wire15_rings,
'wire25_rings' => $row->wire25_rings,
'created_at' => optional($row->created_at)->toDateTimeString(),
];
})
->all();
}
public function approve(int $id, int $adminId): CopperConvertRequest
{
$row = DB::transaction(function () use ($id, $adminId) {
@@ -166,6 +199,42 @@ class CopperConvertRequestService
}
}
private function ownedPending(Customer $customer, int $id): CopperConvertRequest
{
$row = CopperConvertRequest::query()
->where('customer_id', $customer->id)
->lockForUpdate()
->find($id);
if (!$row) {
throw new UnprocessableEntityHttpException('درخواست تبدیل پیدا نشد.');
}
if ($row->status !== 'pending') {
throw new UnprocessableEntityHttpException('فقط درخواست در انتظار تایید قابل تغییر است.');
}
return $row;
}
private function quoteAttributes(Customer $customer, string $source, int $rings15, int $rings25, array $quote): array
{
return [
'customer_id' => $customer->id,
'status' => 'pending',
'source' => $source,
'source_product_id' => $quote['source']->id,
'asset_unit' => $quote['unit'],
'consumed_amount' => $quote['consumed'],
'leftover_amount' => $quote['leftover'],
'source_unit_price' => $quote['source_unit_price'],
'wire15_product_id' => $quote['wire15']?->id,
'wire15_rings' => $rings15,
'wire15_unit_price' => $quote['price15'],
'wire25_product_id' => $quote['wire25']?->id,
'wire25_rings' => $rings25,
'wire25_unit_price' => $quote['price25'],
];
}
private function sourceLabel(string $source): string
{
if ($source === 'katod') {