diff --git a/app/Http/Requests/Admin/Manage/OrderRequest.php b/app/Http/Requests/Admin/Manage/OrderRequest.php index b99b406..e9a9081 100644 --- a/app/Http/Requests/Admin/Manage/OrderRequest.php +++ b/app/Http/Requests/Admin/Manage/OrderRequest.php @@ -31,7 +31,6 @@ public function rules(): array 'channel' => ['required', Rule::enum(OrderChannel::class)], 'price_type' => ['required', Rule::enum(PriceType::class)], 'discount' => ['nullable', 'integer', 'min:0'], - 'marketplace_fee' => ['nullable', 'integer', 'min:0'], 'notes' => ['nullable', 'string'], ]; @@ -58,7 +57,6 @@ public function attributes(): array 'channel' => 'channel', 'price_type' => 'tipe harga', 'discount' => 'diskon', - 'marketplace_fee' => 'biaya marketplace', 'notes' => 'keterangan', 'items' => 'produk', 'items.*.product_variant_id' => 'varian produk', diff --git a/app/Models/Order.php b/app/Models/Order.php index 1d0f9ad..3a5ad43 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -19,7 +19,6 @@ #[Appends([ 'subtotal_formatted', 'discount_formatted', - 'marketplace_fee_formatted', 'total_amount_formatted', 'created_at_formatted', 'channel_label', @@ -40,7 +39,7 @@ protected function casts(): array 'status' => OrderStatus::class, 'subtotal' => 'integer', 'discount' => 'integer', - 'marketplace_fee' => 'integer', + 'marketplace_settings_snapshot' => 'array', 'total_amount' => 'integer', ]; } @@ -86,13 +85,6 @@ public function discountFormatted(): Attribute ); } - public function marketplaceFeeFormatted(): Attribute - { - return Attribute::make( - get: fn () => 'Rp '.number_format($this->marketplace_fee, 0, ',', '.'), - ); - } - public function totalAmountFormatted(): Attribute { return Attribute::make( diff --git a/app/Services/Manage/OrderService.php b/app/Services/Manage/OrderService.php index 2956fc6..8b1d48e 100644 --- a/app/Services/Manage/OrderService.php +++ b/app/Services/Manage/OrderService.php @@ -12,6 +12,7 @@ use App\Models\ProductPrice; use App\Models\ProductVariant; use App\Models\User; +use App\Services\System\Setting\MarketplaceService; use App\Support\Media\MediaPresenter; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; @@ -22,6 +23,10 @@ class OrderService { + public function __construct( + private readonly MarketplaceService $marketplaceService, + ) {} + /** * @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery */ @@ -283,18 +288,18 @@ public function create(array $validated, User $user): Order $subtotal = $draftItems->sum('subtotal'); $discount = (int) ($validated['discount'] ?? 0); - $marketplaceFee = (int) ($validated['marketplace_fee'] ?? 0); - $totalAmount = max($subtotal - $discount - $marketplaceFee, 0); + $totalAmount = max($subtotal - $discount, 0); + $channel = OrderChannel::from($validated['channel']); $order = Order::create([ 'customer_id' => $validated['customer_id'] ?? null, - 'channel' => $validated['channel'], + 'channel' => $channel, 'price_type' => $priceType, 'status' => OrderStatus::PENDING, 'created_by_id' => $user->id, 'subtotal' => $subtotal, 'discount' => $discount, - 'marketplace_fee' => $marketplaceFee, + 'marketplace_settings_snapshot' => $this->marketplaceService->snapshotForChannel($channel), 'total_amount' => $totalAmount, 'notes' => $validated['notes'] ?? null, ]); @@ -333,15 +338,15 @@ 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); - $marketplaceFee = (int) ($validated['marketplace_fee'] ?? 0); - $totalAmount = max($subtotal - $discount - $marketplaceFee, 0); + $totalAmount = max($subtotal - $discount, 0); + $channel = OrderChannel::from($validated['channel']); $order->customer_id = $validated['customer_id'] ?? null; - $order->channel = $validated['channel']; + $order->channel = $channel; $order->price_type = $priceType; $order->subtotal = $subtotal; $order->discount = $discount; - $order->marketplace_fee = $marketplaceFee; + $order->marketplace_settings_snapshot = $this->marketplaceService->snapshotForChannel($channel); $order->total_amount = $totalAmount; $order->notes = $validated['notes'] ?? null; $order->save(); diff --git a/app/Services/System/Setting/MarketplaceService.php b/app/Services/System/Setting/MarketplaceService.php index 504942e..6c7c96e 100644 --- a/app/Services/System/Setting/MarketplaceService.php +++ b/app/Services/System/Setting/MarketplaceService.php @@ -2,6 +2,7 @@ namespace App\Services\System\Setting; +use App\Enums\OrderChannel; use App\Settings\MarketplaceSettings; class MarketplaceService @@ -52,4 +53,35 @@ public function updateMarketplace(array $validated): void $settings->save(); } + + /** + * @return array|null + */ + public function snapshotForChannel(OrderChannel $channel): ?array + { + $settings = app(MarketplaceSettings::class); + + return match ($channel) { + OrderChannel::SHOPEE => [ + 'platform' => 'shopee', + 'commission_fee' => $settings->shopee_commission_fee, + 'transaction_fee' => $settings->shopee_transaction_fee, + 'service_fee' => $settings->shopee_service_fee, + 'payment_fee' => $settings->shopee_payment_fee, + 'affiliate_commission' => $settings->shopee_affiliate_commission, + 'shipping_subsidy' => $settings->shopee_shipping_subsidy, + 'voucher_fee' => $settings->shopee_voucher_fee, + ], + OrderChannel::TIKTOK => [ + 'platform' => 'tiktok', + 'admin_fee' => $settings->tiktok_shop_admin_fee, + 'transaction_fee' => $settings->tiktok_shop_transaction_fee, + 'payment_fee' => $settings->tiktok_shop_payment_fee, + 'affiliate_commission' => $settings->tiktok_shop_affiliate_commission, + 'shipping_subsidy' => $settings->tiktok_shop_shipping_subsidy, + 'vat_rate' => $settings->tiktok_shop_vat_rate, + ], + OrderChannel::STORE => null, + }; + } } diff --git a/database/migrations/2026_06_12_100001_create_orders_table.php b/database/migrations/2026_06_12_100001_create_orders_table.php index 1110dab..a824761 100644 --- a/database/migrations/2026_06_12_100001_create_orders_table.php +++ b/database/migrations/2026_06_12_100001_create_orders_table.php @@ -22,6 +22,7 @@ public function up(): void $table->enum('status', array_column(OrderStatus::cases(), 'value'))->default(OrderStatus::PENDING->value); $table->unsignedBigInteger('subtotal'); $table->unsignedBigInteger('discount')->default(0); + $table->json('marketplace_settings_snapshot')->nullable(); $table->unsignedBigInteger('total_amount'); $table->text('notes')->nullable(); diff --git a/resources/js/components/admin/manage/orders/OrderGroupedTable.vue b/resources/js/components/admin/manage/orders/OrderGroupedTable.vue index 0c874b0..09363a2 100644 --- a/resources/js/components/admin/manage/orders/OrderGroupedTable.vue +++ b/resources/js/components/admin/manage/orders/OrderGroupedTable.vue @@ -113,10 +113,6 @@ function statusVariant(status: string): 'default' | 'secondary' | 'destructive' }} Diskon {{ order.discount_formatted }} - - Biaya MP {{ order.marketplace_fee_formatted - }} - Total {{ order.total_amount_formatted }} diff --git a/resources/js/components/admin/manage/orders/OrderPosForm.vue b/resources/js/components/admin/manage/orders/OrderPosForm.vue index b7ff9de..26d1137 100644 --- a/resources/js/components/admin/manage/orders/OrderPosForm.vue +++ b/resources/js/components/admin/manage/orders/OrderPosForm.vue @@ -49,7 +49,6 @@ const props = defineProps<{ channel: string; price_type: string; discount: string; - marketplace_fee: string; notes: string; items: OrderCartItem[]; }; @@ -69,12 +68,10 @@ const form = useForm({ channel: 'store', price_type: 'ecer', discount: '', - marketplace_fee: '', notes: '', }); const isStoreChannel = computed(() => form.channel === 'store'); -const isMarketplaceChannel = computed(() => form.channel === 'shopee' || form.channel === 'tiktok'); function populateForm() { if (!props.initialData) { @@ -85,7 +82,6 @@ function populateForm() { form.channel = props.initialData.channel; form.price_type = props.initialData.price_type; form.discount = props.initialData.discount; - form.marketplace_fee = props.initialData.marketplace_fee; form.notes = props.initialData.notes; cart.value = props.initialData.items.map((item) => ({ ...item })); } @@ -177,8 +173,7 @@ const subtotal = computed(() => ); const discountAmount = computed(() => Number(parseRupiah(form.discount)) || 0); -const marketplaceFeeAmount = computed(() => Number(parseRupiah(form.marketplace_fee)) || 0); -const totalAmount = computed(() => Math.max(subtotal.value - discountAmount.value - marketplaceFeeAmount.value, 0)); +const totalAmount = computed(() => Math.max(subtotal.value - discountAmount.value, 0)); function getVariantPrice(variant: ProductVariantItem): ProductPriceItem | undefined { return variant.prices.find((price) => price.type === form.price_type); @@ -319,7 +314,6 @@ function buildFormData(): FormData { formData.append('channel', form.channel); formData.append('price_type', form.price_type); formData.append('discount', parseRupiah(form.discount)); - formData.append('marketplace_fee', parseRupiah(form.marketplace_fee)); formData.append('notes', form.notes); if (props.method === 'put') { @@ -552,11 +546,6 @@ function submit() { - - Biaya Marketplace - - -
Total Rp {{ formatRupiah(totalAmount) }} diff --git a/resources/js/lib/thermal-printer/encode-order-receipt.ts b/resources/js/lib/thermal-printer/encode-order-receipt.ts index 82dac20..8fc68d1 100644 --- a/resources/js/lib/thermal-printer/encode-order-receipt.ts +++ b/resources/js/lib/thermal-printer/encode-order-receipt.ts @@ -40,7 +40,6 @@ export function encodeOrderReceipt( const createdBy = order.created_by?.profile?.full_name ?? order.created_by?.username ?? '-'; - const isMarketplace = order.channel !== 'store'; encoder.initialize() .align('center') @@ -98,14 +97,9 @@ export function encodeOrderReceipt( const summaryRows: string[][] = [ ['Subtotal', order.subtotal_formatted], ['Diskon', order.discount_formatted], + ['Total', order.total_amount_formatted], ]; - if (isMarketplace) { - summaryRows.push(['Biaya MP', order.marketplace_fee_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 cb7628e..c83b730 100644 --- a/resources/js/pages/admin/manage/orders/Edit.vue +++ b/resources/js/pages/admin/manage/orders/Edit.vue @@ -20,7 +20,6 @@ const initialData = computed(() => ({ channel: props.order.channel, price_type: props.order.price_type, discount: String(props.order.discount), - marketplace_fee: String(props.order.marketplace_fee), notes: props.order.notes ?? '', items: props.order.items.map((item) => ({ product_variant_id: item.product_variant_id, diff --git a/resources/js/types/order.ts b/resources/js/types/order.ts index ec8a98c..3d7742c 100644 --- a/resources/js/types/order.ts +++ b/resources/js/types/order.ts @@ -47,7 +47,6 @@ export type OrderListItem = { available_actions: OrderStatusAction[]; subtotal_formatted: string; discount_formatted: string; - marketplace_fee_formatted: string; total_amount_formatted: string; notes: string | null; created_at_formatted: string; @@ -81,7 +80,6 @@ export type OrderEditItem = { price_type: string; status: string; discount: number; - marketplace_fee: number; notes: string | null; items: Array<{ product_variant_id: number;