2026-07-21 21:23:26 +03:30
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers\Customer;
|
|
|
|
|
|
|
|
|
|
use App\Http\Controllers\Controller;
|
|
|
|
|
use App\Models\ConditionalOrder;
|
|
|
|
|
use App\Models\Customer;
|
|
|
|
|
use App\Models\Product;
|
|
|
|
|
use App\Services\ConditionalOrderService;
|
|
|
|
|
use App\Services\ConfigService;
|
2026-07-22 13:32:26 +03:30
|
|
|
use App\Support\ConditionalOrderValidation;
|
2026-07-21 21:23:26 +03:30
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
|
|
|
|
|
|
|
|
|
class ConditionalOrderController extends Controller
|
|
|
|
|
{
|
|
|
|
|
public function index()
|
|
|
|
|
{
|
|
|
|
|
$customer = $this->authCustomer();
|
|
|
|
|
app(ConditionalOrderService::class)->assertCustomerCanUse($customer);
|
|
|
|
|
|
|
|
|
|
$items = ConditionalOrder::query()
|
|
|
|
|
->with('product')
|
|
|
|
|
->where('customer_id', $customer->id)
|
|
|
|
|
->orderByDesc('id')
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
return response()->json($items);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function store(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$customer = $this->authCustomer();
|
|
|
|
|
$service = app(ConditionalOrderService::class);
|
|
|
|
|
$service->assertCustomerCanUse($customer);
|
|
|
|
|
$service->assertWithinLimit($customer);
|
|
|
|
|
|
|
|
|
|
$data = $this->validatedPayload($request);
|
|
|
|
|
$data['customer_id'] = $customer->id;
|
|
|
|
|
|
|
|
|
|
$fee = 0;
|
|
|
|
|
DB::beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
$fee = $service->chargeRegistrationFee($customer);
|
|
|
|
|
$order = ConditionalOrder::create([
|
|
|
|
|
...$data,
|
|
|
|
|
'is_active' => $data['is_active'] ?? true,
|
|
|
|
|
'status' => ConditionalOrder::STATUS_PENDING,
|
|
|
|
|
'fee_charged' => $fee,
|
|
|
|
|
]);
|
|
|
|
|
DB::commit();
|
|
|
|
|
} catch (\Throwable $e) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
throw $e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response()->json($order->load('product'), 201);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function update(Request $request, int $id)
|
|
|
|
|
{
|
|
|
|
|
$customer = $this->authCustomer();
|
|
|
|
|
app(ConditionalOrderService::class)->assertCustomerCanUse($customer);
|
|
|
|
|
|
|
|
|
|
$order = ConditionalOrder::query()
|
|
|
|
|
->where('customer_id', $customer->id)
|
|
|
|
|
->findOrFail($id);
|
|
|
|
|
|
|
|
|
|
if ($order->status !== ConditionalOrder::STATUS_PENDING) {
|
|
|
|
|
throw new UnprocessableEntityHttpException('فقط سفارش در انتظار قابل ویرایش است.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data = $this->validatedPayload($request, true);
|
|
|
|
|
unset($data['customer_id']);
|
|
|
|
|
$order->update($data);
|
|
|
|
|
|
|
|
|
|
return response()->json($order->fresh()->load('product'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function destroy(int $id)
|
|
|
|
|
{
|
|
|
|
|
$customer = $this->authCustomer();
|
|
|
|
|
app(ConditionalOrderService::class)->assertCustomerCanUse($customer);
|
|
|
|
|
|
|
|
|
|
$order = ConditionalOrder::query()
|
|
|
|
|
->where('customer_id', $customer->id)
|
|
|
|
|
->findOrFail($id);
|
|
|
|
|
$order->delete();
|
|
|
|
|
|
|
|
|
|
return response()->json(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function toggleActive(int $id)
|
|
|
|
|
{
|
|
|
|
|
$customer = $this->authCustomer();
|
|
|
|
|
app(ConditionalOrderService::class)->assertCustomerCanUse($customer);
|
|
|
|
|
|
|
|
|
|
$order = ConditionalOrder::query()
|
|
|
|
|
->where('customer_id', $customer->id)
|
|
|
|
|
->findOrFail($id);
|
|
|
|
|
|
|
|
|
|
if ($order->status !== ConditionalOrder::STATUS_PENDING) {
|
|
|
|
|
throw new UnprocessableEntityHttpException('فقط سفارش در انتظار قابل فعال/غیرفعالسازی است.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$order->is_active = ! $order->is_active;
|
|
|
|
|
$order->save();
|
|
|
|
|
|
|
|
|
|
return response()->json(['is_active' => (bool) $order->is_active]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function authCustomer(): Customer
|
|
|
|
|
{
|
|
|
|
|
$customer = auth('customer')->user();
|
|
|
|
|
if (! $customer) {
|
|
|
|
|
throw new UnprocessableEntityHttpException('احراز هویت نامعتبر است.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $customer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function validatedPayload(Request $request, bool $partial = false): array
|
|
|
|
|
{
|
|
|
|
|
$rules = [
|
|
|
|
|
'product_id' => ($partial ? 'sometimes|' : '') . 'required|integer|exists:products,id',
|
|
|
|
|
'direction' => ($partial ? 'sometimes|' : '') . 'required|integer|in:1,2',
|
|
|
|
|
'price_condition' => ($partial ? 'sometimes|' : '') . 'required|in:gte,lte',
|
|
|
|
|
'trigger_price' => ($partial ? 'sometimes|' : '') . 'required|numeric|min:1',
|
|
|
|
|
'amount' => 'nullable|numeric|min:0',
|
|
|
|
|
'number' => 'nullable|numeric|min:0',
|
2026-07-22 13:32:26 +03:30
|
|
|
'expires_at' => 'nullable|date',
|
2026-07-21 21:23:26 +03:30
|
|
|
'description' => 'nullable|string|max:2000',
|
|
|
|
|
'is_active' => 'sometimes|boolean',
|
|
|
|
|
];
|
|
|
|
|
|
2026-07-22 13:32:26 +03:30
|
|
|
$data = $request->validate(
|
|
|
|
|
$rules,
|
|
|
|
|
ConditionalOrderValidation::messages(),
|
|
|
|
|
ConditionalOrderValidation::attributes()
|
|
|
|
|
);
|
2026-07-21 21:23:26 +03:30
|
|
|
|
|
|
|
|
$amount = isset($data['amount']) ? (float) $data['amount'] : null;
|
|
|
|
|
$number = isset($data['number']) ? (float) $data['number'] : null;
|
|
|
|
|
|
|
|
|
|
if (! $partial && ($amount === null || $amount <= 0) && ($number === null || $number <= 0)) {
|
|
|
|
|
throw new UnprocessableEntityHttpException('مقدار گرم یا تعداد را وارد کنید.');
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-22 13:32:26 +03:30
|
|
|
if (! empty($data['expires_at'])) {
|
|
|
|
|
try {
|
|
|
|
|
$expires = \Illuminate\Support\Carbon::parse($data['expires_at']);
|
|
|
|
|
} catch (\Throwable $e) {
|
|
|
|
|
throw new UnprocessableEntityHttpException('زمان اعتبار تاریخ معتبری نیست.');
|
|
|
|
|
}
|
|
|
|
|
if ($expires->lte(now())) {
|
|
|
|
|
throw new UnprocessableEntityHttpException('زمان اعتبار باید بعد از الان باشد.');
|
|
|
|
|
}
|
|
|
|
|
$data['expires_at'] = $expires->format('Y-m-d H:i:s');
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-21 21:23:26 +03:30
|
|
|
$productId = (int) ($data['product_id'] ?? $request->input('product_id') ?? 0);
|
|
|
|
|
$product = $productId > 0 ? Product::find($productId) : null;
|
|
|
|
|
if ($product && $amount !== null && $amount > 0 && ($number === null || $number <= 0)) {
|
|
|
|
|
$group = trim((string) ($product->group_type ?? ''));
|
|
|
|
|
$isMelted = in_array($group, ['آبشده', 'کاتد مس'], true)
|
|
|
|
|
|| (bool) ($product->trade_by_quantity ?? false)
|
|
|
|
|
|| ((int) $product->id === (int) app(ConfigService::class)->mainProductId());
|
|
|
|
|
|
|
|
|
|
if (! $isMelted && (float) ($product->amount ?? 0) > 0) {
|
|
|
|
|
$data['number'] = $amount;
|
|
|
|
|
$data['amount'] = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
|
|
|
|
}
|