diff --git a/app/Http/Requests/Admin/Manage/OrderRequest.php b/app/Http/Requests/Admin/Manage/OrderRequest.php index d87473b..09ef1d5 100644 --- a/app/Http/Requests/Admin/Manage/OrderRequest.php +++ b/app/Http/Requests/Admin/Manage/OrderRequest.php @@ -39,6 +39,7 @@ public function rules(): array 'tiktok_order_id' => [Rule::requiredIf(fn () => $this->channel === OrderChannel::TIKTOK->value), 'string', 'max:100'], 'shopee_order_id' => [Rule::requiredIf(fn () => $this->channel === OrderChannel::SHOPEE->value), 'string', 'max:100'], 'discount' => ['nullable', 'integer', 'min:0'], + 'nego_price' => ['nullable', 'integer', 'min:0'], 'notes' => ['nullable', 'string'], 'status' => ['nullable', Rule::enum(OrderStatus::class)], ]; @@ -72,6 +73,7 @@ public function attributes(): array 'tiktok_order_id' => 'ID pesanan TikTok Shop', 'shopee_order_id' => 'ID pesanan Shopee', 'discount' => 'diskon', + 'nego_price' => 'harga nego', 'notes' => 'keterangan', 'status' => 'status pesanan', 'items' => 'produk', diff --git a/app/Models/Order.php b/app/Models/Order.php index 27eb30a..080e576 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -22,6 +22,7 @@ #[Appends([ 'subtotal_formatted', 'discount_formatted', + 'nego_price_formatted', 'total_amount_formatted', 'created_at_formatted', 'channel_label', @@ -45,6 +46,7 @@ protected function casts(): array 'status' => OrderStatus::class, 'subtotal' => 'integer', 'discount' => 'integer', + 'nego_price' => 'integer', 'marketplace_settings_snapshot' => 'array', 'total_amount' => 'integer', ]; @@ -96,6 +98,13 @@ public function discountFormatted(): Attribute ); } + public function negoPriceFormatted(): Attribute + { + return Attribute::make( + get: fn () => $this->nego_price !== null ? 'Rp '.number_format($this->nego_price, 0, ',', '.') : null, + ); + } + public function totalAmountFormatted(): Attribute { return Attribute::make( diff --git a/app/Services/Manage/OrderService.php b/app/Services/Manage/OrderService.php index b1381bb..2adf610 100644 --- a/app/Services/Manage/OrderService.php +++ b/app/Services/Manage/OrderService.php @@ -437,7 +437,8 @@ public function create(array $validated, User $user): Order $subtotal = $draftItems->sum('subtotal'); $discount = (int) ($validated['discount'] ?? 0); - $totalAmount = max($subtotal - $discount, 0); + $negoPrice = isset($validated['nego_price']) && $validated['nego_price'] !== '' ? (int) $validated['nego_price'] : null; + $totalAmount = $negoPrice !== null ? max($negoPrice, 0) : max($subtotal - $discount, 0); $channel = OrderChannel::from($validated['channel']); $status = isset($validated['status']) @@ -457,6 +458,7 @@ public function create(array $validated, User $user): Order 'created_by_id' => $user->id, 'subtotal' => $subtotal, 'discount' => $discount, + 'nego_price' => $negoPrice, 'marketplace_settings_snapshot' => $this->marketplaceService->buildOrderSnapshot( $channel, $totalAmount, @@ -549,7 +551,8 @@ public function update(Order $order, array $validated): void $lineItems = $this->buildLineItems($validated['items'], $priceType); $subtotal = array_sum(array_column($lineItems, 'subtotal')); $discount = (int) ($validated['discount'] ?? 0); - $totalAmount = max($subtotal - $discount, 0); + $negoPrice = isset($validated['nego_price']) && $validated['nego_price'] !== '' ? (int) $validated['nego_price'] : null; + $totalAmount = $negoPrice !== null ? max($negoPrice, 0) : max($subtotal - $discount, 0); $channel = OrderChannel::from($validated['channel']); $order->customer_id = $validated['customer_id'] ?? null; @@ -562,6 +565,7 @@ public function update(Order $order, array $validated): void $order->shopee_order_id = $validated['shopee_order_id'] ?? null; $order->subtotal = $subtotal; $order->discount = $discount; + $order->nego_price = $negoPrice; $order->marketplace_settings_snapshot = $this->marketplaceService->buildOrderSnapshot( $channel, $totalAmount, diff --git a/database/migrations/2026_06_28_104300_add_nego_price_to_orders_table.php b/database/migrations/2026_06_28_104300_add_nego_price_to_orders_table.php new file mode 100644 index 0000000..1b720be --- /dev/null +++ b/database/migrations/2026_06_28_104300_add_nego_price_to_orders_table.php @@ -0,0 +1,22 @@ +unsignedBigInteger('nego_price')->nullable()->after('discount'); + }); + } + + public function down(): void + { + Schema::table('orders', function (Blueprint $table): void { + $table->dropColumn('nego_price'); + }); + } +}; diff --git a/resources/js/lib/thermal-printer/encode-order-receipt.ts b/resources/js/lib/thermal-printer/encode-order-receipt.ts index 8fc68d1..45623c8 100644 --- a/resources/js/lib/thermal-printer/encode-order-receipt.ts +++ b/resources/js/lib/thermal-printer/encode-order-receipt.ts @@ -97,9 +97,14 @@ export function encodeOrderReceipt( const summaryRows: string[][] = [ ['Subtotal', order.subtotal_formatted], ['Diskon', order.discount_formatted], - ['Total', order.total_amount_formatted], ]; + if (order.nego_price_formatted) { + summaryRows.push(['Harga Nego', order.nego_price_formatted]); + } + + summaryRows.push(['Total', order.total_amount_formatted]); + encoder.table( [ { width: labelColumnWidth, align: 'left' }, diff --git a/resources/js/pages/admin/manage/orders/Edit.vue b/resources/js/pages/admin/manage/orders/Edit.vue index d0c360d..cbe8482 100644 --- a/resources/js/pages/admin/manage/orders/Edit.vue +++ b/resources/js/pages/admin/manage/orders/Edit.vue @@ -36,6 +36,7 @@ const initialData = computed(() => ({ tiktok_order_id: props.order.tiktok_order_id ?? '', shopee_order_id: props.order.shopee_order_id ?? '', discount: String(props.order.discount), + nego_price: props.order.nego_price != null ? String(props.order.nego_price) : '', notes: props.order.notes ?? '', status: props.order.status, items: props.order.items.map((item) => ({ diff --git a/resources/js/pages/admin/manage/orders/Show.vue b/resources/js/pages/admin/manage/orders/Show.vue index f59a68c..318c3f1 100644 --- a/resources/js/pages/admin/manage/orders/Show.vue +++ b/resources/js/pages/admin/manage/orders/Show.vue @@ -142,6 +142,10 @@ const summaryRows = computed(() => { rows.push({ label: 'Diskon', value: `-${props.order.discount_formatted}` }); } + if (props.order.nego_price != null && props.order.nego_price > 0) { + rows.push({ label: 'Harga Nego', value: props.order.nego_price_formatted }); + } + return rows; }); diff --git a/resources/js/pages/admin/manage/orders/form/OrderPosForm.vue b/resources/js/pages/admin/manage/orders/form/OrderPosForm.vue index f2bd209..4f58ee0 100644 --- a/resources/js/pages/admin/manage/orders/form/OrderPosForm.vue +++ b/resources/js/pages/admin/manage/orders/form/OrderPosForm.vue @@ -75,6 +75,7 @@ const props = defineProps<{ tiktok_order_id: string; shopee_order_id: string; discount: string; + nego_price: string; notes: string; status: string; items: OrderCartItem[]; @@ -131,6 +132,7 @@ const form = useForm({ tiktok_order_id: '', shopee_order_id: '', discount: '', + nego_price: '', notes: '', status: OrderStatus.PENDING, }); @@ -152,6 +154,7 @@ function populateForm() { form.tiktok_order_id = props.initialData.tiktok_order_id; form.shopee_order_id = props.initialData.shopee_order_id; form.discount = props.initialData.discount; + form.nego_price = props.initialData.nego_price; form.notes = props.initialData.notes; form.status = props.initialData.status || OrderStatus.PENDING; cart.value = props.initialData.items.map((item) => ({ @@ -260,7 +263,13 @@ const subtotal = computed(() => ); const discountAmount = computed(() => Number(parseRupiah(form.discount)) || 0); -const totalAmount = computed(() => Math.max(subtotal.value - discountAmount.value, 0)); +const negoPriceAmount = computed(() => Number(parseRupiah(form.nego_price)) || 0); +const totalAmount = computed(() => { + if (negoPriceAmount.value > 0) { + return negoPriceAmount.value; + } + return Math.max(subtotal.value - discountAmount.value, 0); +}); function getVariantPrice(variant: ProductVariantItem): ProductPriceItem | undefined { return variant.prices.find((price) => price.type === form.price_type); @@ -475,6 +484,7 @@ function buildFormData(): FormData { } formData.append('discount', parseRupiah(form.discount)); + formData.append('nego_price', parseRupiah(form.nego_price)); formData.append('notes', form.notes); formData.append('status', form.status); @@ -841,6 +851,12 @@ function submit() { + + Harga Nego + +

Jika diisi, harga nego menjadi total akhir.

+ +
Total Rp {{ formatRupiah(totalAmount) }} diff --git a/resources/js/pages/admin/manage/orders/table/OrderGroupedTable.vue b/resources/js/pages/admin/manage/orders/table/OrderGroupedTable.vue index d00406d..6c3d73c 100644 --- a/resources/js/pages/admin/manage/orders/table/OrderGroupedTable.vue +++ b/resources/js/pages/admin/manage/orders/table/OrderGroupedTable.vue @@ -126,6 +126,8 @@ function statusVariant(status: string): 'default' | 'secondary' | 'destructive' }} Diskon {{ order.discount_formatted }} + Harga Nego {{ order.nego_price_formatted + }} Total {{ order.total_amount_formatted }} diff --git a/resources/js/types/order.ts b/resources/js/types/order.ts index 7109f84..46180b0 100644 --- a/resources/js/types/order.ts +++ b/resources/js/types/order.ts @@ -52,6 +52,7 @@ export type OrderListItem = { shopee_order_id: string | null; subtotal_formatted: string; discount_formatted: string; + nego_price_formatted: string | null; total_amount: number; total_amount_formatted: string; notes: string | null; @@ -118,6 +119,7 @@ export type OrderEditItem = { tiktok_order_id: string | null; shopee_order_id: string | null; discount: number; + nego_price: number | null; notes: string | null; items: Array<{ product_variant_id: number; @@ -152,6 +154,8 @@ export type OrderDetail = { subtotal_formatted: string; discount: number; discount_formatted: string; + nego_price: number | null; + nego_price_formatted: string | null; total_amount: number; total_amount_formatted: string; notes: string | null;