From fe1549e0a57b03b3efbfe5b0a205cfc598b570c8 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 28 Jun 2026 00:01:54 +0700 Subject: [PATCH] feat: add order status management to OrderRequest and OrderService, update frontend forms for status handling --- .../Requests/Admin/Manage/OrderRequest.php | 9 +++++++++ app/Services/Manage/OrderService.php | 15 ++++++++++++++- resources/js/constants/order-status.ts | 1 + .../js/pages/admin/manage/orders/Edit.vue | 1 + .../admin/manage/orders/form/OrderPosForm.vue | 19 +++++++++++++++++++ 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/app/Http/Requests/Admin/Manage/OrderRequest.php b/app/Http/Requests/Admin/Manage/OrderRequest.php index d19f987..882df26 100644 --- a/app/Http/Requests/Admin/Manage/OrderRequest.php +++ b/app/Http/Requests/Admin/Manage/OrderRequest.php @@ -3,6 +3,7 @@ namespace App\Http\Requests\Admin\Manage; use App\Enums\OrderChannel; +use App\Enums\OrderStatus; use App\Enums\PaymentType; use App\Enums\Permission; use App\Enums\PriceType; @@ -39,6 +40,7 @@ public function rules(): array 'shopee_order_id' => [Rule::requiredIf(fn () => $this->channel === OrderChannel::SHOPEE->value), 'string', 'max:100'], 'discount' => ['nullable', 'integer', 'min:0'], 'notes' => ['nullable', 'string'], + 'status' => ['nullable', Rule::enum(OrderStatus::class)], ]; if ($this->isMethod('PUT') || $this->isMethod('PATCH')) { @@ -71,6 +73,7 @@ public function attributes(): array 'shopee_order_id' => 'ID pesanan Shopee', 'discount' => 'diskon', 'notes' => 'keterangan', + 'status' => 'status pesanan', 'items' => 'produk', 'items.*.product_variant_id' => 'varian produk', 'items.*.quantity' => 'jumlah', @@ -85,6 +88,12 @@ public function withValidator(Validator $validator): void $validator->errors()->add('customer_id', 'Pelanggan wajib diisi jika marketing dipilih.'); } + if ($this->filled('status') && $this->status === OrderStatus::COMPLETED->value) { + if (! $this->user()?->can(Permission::ORDERS_COMPLETE->value)) { + $validator->errors()->add('status', 'Anda tidak memiliki izin untuk menandai pesanan sebagai selesai.'); + } + } + if ($this->isMethod('PUT') || $this->isMethod('PATCH')) { /** @var Order $order */ $order = $this->route('order'); diff --git a/app/Services/Manage/OrderService.php b/app/Services/Manage/OrderService.php index 5cab355..c516d8d 100644 --- a/app/Services/Manage/OrderService.php +++ b/app/Services/Manage/OrderService.php @@ -421,6 +421,10 @@ public function create(array $validated, User $user): Order $totalAmount = max($subtotal - $discount, 0); $channel = OrderChannel::from($validated['channel']); + $status = isset($validated['status']) + ? OrderStatus::from($validated['status']) + : OrderStatus::PENDING; + $order = Order::create([ 'customer_id' => $validated['customer_id'] ?? null, 'marketing_id' => $validated['marketing_id'] ?? null, @@ -428,7 +432,7 @@ public function create(array $validated, User $user): Order 'price_type' => $priceType, 'payment_type' => PaymentType::from($validated['payment_type']), 'is_affiliate' => $validated['is_affiliate'] ?? false, - 'status' => OrderStatus::PENDING, + 'status' => $status, 'tiktok_order_id' => $validated['tiktok_order_id'] ?? null, 'shopee_order_id' => $validated['shopee_order_id'] ?? null, 'created_by_id' => $user->id, @@ -547,6 +551,15 @@ public function update(Order $order, array $validated): void ); $order->total_amount = $totalAmount; $order->notes = $validated['notes'] ?? null; + + if (isset($validated['status'])) { + $newStatus = OrderStatus::from($validated['status']); + + if ($order->status->canTransitionTo($newStatus) || $newStatus === $order->status) { + $order->status = $newStatus; + } + } + $order->save(); foreach ($lineItems as $itemData) { diff --git a/resources/js/constants/order-status.ts b/resources/js/constants/order-status.ts index fccbfcf..50bcb15 100644 --- a/resources/js/constants/order-status.ts +++ b/resources/js/constants/order-status.ts @@ -1,4 +1,5 @@ export const OrderStatus = { + PENDING: 'pending', PROCESSING: 'processing', COMPLETED: 'completed', CANCELLED: 'cancelled', diff --git a/resources/js/pages/admin/manage/orders/Edit.vue b/resources/js/pages/admin/manage/orders/Edit.vue index 6dacb96..d0c360d 100644 --- a/resources/js/pages/admin/manage/orders/Edit.vue +++ b/resources/js/pages/admin/manage/orders/Edit.vue @@ -37,6 +37,7 @@ const initialData = computed(() => ({ shopee_order_id: props.order.shopee_order_id ?? '', discount: String(props.order.discount), notes: props.order.notes ?? '', + status: props.order.status, items: props.order.items.map((item) => ({ product_variant_id: item.product_variant_id, product_name: item.product_name, diff --git a/resources/js/pages/admin/manage/orders/form/OrderPosForm.vue b/resources/js/pages/admin/manage/orders/form/OrderPosForm.vue index 00277fa..8975e49 100644 --- a/resources/js/pages/admin/manage/orders/form/OrderPosForm.vue +++ b/resources/js/pages/admin/manage/orders/form/OrderPosForm.vue @@ -42,6 +42,7 @@ import { Textarea } from '@/components/ui/textarea'; import { useCan } from '@/composables/useCan'; import { OrderChannel } from '@/constants/order-channel'; import { OrderPaymentType } from '@/constants/order-payment-type'; +import { OrderStatus } from '@/constants/order-status'; import { PaperSize } from '@/constants/paper-size'; import { StockQuality } from '@/constants/stock-quality'; import { apiFetch } from '@/lib/api'; @@ -75,6 +76,7 @@ const props = defineProps<{ shopee_order_id: string; discount: string; notes: string; + status: string; items: OrderCartItem[]; }; draftItems?: OrderCartItem[]; @@ -126,6 +128,7 @@ const form = useForm({ shopee_order_id: '', discount: '', notes: '', + status: OrderStatus.PENDING, }); const isStoreChannel = computed(() => form.channel === 'store'); @@ -146,6 +149,7 @@ function populateForm() { form.shopee_order_id = props.initialData.shopee_order_id; form.discount = props.initialData.discount; form.notes = props.initialData.notes; + form.status = props.initialData.status || OrderStatus.PENDING; cart.value = props.initialData.items.map((item) => ({ ...item, stock_quality: item.stock_quality ?? StockQuality.GOOD, @@ -457,6 +461,7 @@ function buildFormData(): FormData { formData.append('discount', parseRupiah(form.discount)); formData.append('notes', form.notes); + formData.append('status', form.status); if (isCreateMode.value && printAfterSave.value) { formData.append('print', '1'); @@ -823,6 +828,20 @@ function submit() { + +
+ + +
+

+ Aktifkan jika pesanan sudah selesai diproses. +

+ +
+ Keterangan