Refactor marketplace settings to use structured fee rules. Update MarketplaceRequest, MarketplaceService, and MarketplaceSettings to handle fees as arrays with scope and value type. Enhance frontend components to accommodate new fee structure and validation logic for improved user experience.

This commit is contained in:
Yoga Pangestu 2026-06-13 01:20:12 +07:00
parent 584387504c
commit 7d721cab31
10 changed files with 495 additions and 222 deletions

View File

@ -0,0 +1,21 @@
<?php
namespace App\Enums;
use App\Traits\ProvidesEnumOptions;
enum MarketplaceFeeScope: string
{
use ProvidesEnumOptions;
case PRODUCT = 'product';
case TRANSACTION = 'transaction';
public function label(): string
{
return match ($this) {
self::PRODUCT => 'Per Produk',
self::TRANSACTION => 'Per Transaksi',
};
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Enums;
use App\Traits\ProvidesEnumOptions;
enum MarketplaceFeeValueType: string
{
use ProvidesEnumOptions;
case FLAT = 'flat';
case PERCENT = 'percent';
public function label(): string
{
return match ($this) {
self::FLAT => 'Flat (Rp)',
self::PERCENT => 'Persentase (%)',
};
}
}

View File

@ -2,8 +2,12 @@
namespace App\Http\Requests\Admin\System\Setting;
use App\Enums\MarketplaceFeeScope;
use App\Enums\MarketplaceFeeValueType;
use App\Enums\Permission;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
class MarketplaceRequest extends FormRequest
{
@ -17,40 +21,63 @@ public function authorize(): bool
*/
public function rules(): array
{
return [
'tiktok_shop_enabled' => ['required', 'boolean'],
'tiktok_shop_admin_fee' => ['required', 'numeric', 'min:0', 'max:100'],
'tiktok_shop_transaction_fee' => ['required', 'numeric', 'min:0', 'max:100'],
'tiktok_shop_payment_fee' => ['required', 'numeric', 'min:0', 'max:100'],
'tiktok_shop_affiliate_commission' => ['required', 'numeric', 'min:0', 'max:100'],
'tiktok_shop_shipping_subsidy' => ['required', 'numeric', 'min:0', 'max:100'],
'tiktok_shop_vat_rate' => ['required', 'numeric', 'min:0', 'max:100'],
$rules = [];
'shopee_enabled' => ['required', 'boolean'],
'shopee_commission_fee' => ['required', 'numeric', 'min:0', 'max:100'],
'shopee_transaction_fee' => ['required', 'numeric', 'min:0', 'max:100'],
'shopee_service_fee' => ['required', 'numeric', 'min:0', 'max:100'],
'shopee_payment_fee' => ['required', 'numeric', 'min:0', 'max:100'],
'shopee_affiliate_commission' => ['required', 'numeric', 'min:0', 'max:100'],
'shopee_shipping_subsidy' => ['required', 'numeric', 'min:0', 'max:100'],
'shopee_voucher_fee' => ['required', 'numeric', 'min:0', 'max:100'],
];
foreach ($this->feeFieldKeys() as $key => $label) {
$rules["{$key}.scope"] = ['required', Rule::enum(MarketplaceFeeScope::class)];
$rules["{$key}.value_type"] = ['required', Rule::enum(MarketplaceFeeValueType::class)];
$rules["{$key}.value"] = ['required', 'numeric', 'min:0'];
}
return $rules;
}
public function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator): void {
foreach ($this->feeFieldKeys() as $key => $label) {
$valueType = $this->input("{$key}.value_type");
$value = $this->input("{$key}.value");
if ($valueType === MarketplaceFeeValueType::PERCENT->value && is_numeric($value) && (float) $value > 100) {
$validator->errors()->add("{$key}.value", "{$label} tidak boleh lebih dari 100%.");
}
if ($valueType === MarketplaceFeeValueType::FLAT->value && is_numeric($value) && (float) $value != (int) $value) {
$validator->errors()->add("{$key}.value", "{$label} harus berupa nominal rupiah tanpa desimal.");
}
}
});
}
/**
* @return array<string, string>
*/
public function attributes(): array
{
$attributes = [];
foreach ($this->feeFieldKeys() as $key => $label) {
$attributes["{$key}.scope"] = "dasar {$label}";
$attributes["{$key}.value_type"] = "tipe {$label}";
$attributes["{$key}.value"] = $label;
}
return $attributes;
}
/**
* @return array<string, string>
*/
private function feeFieldKeys(): array
{
return [
'tiktok_shop_enabled' => 'aktif',
'tiktok_shop_admin_fee' => 'biaya admin TikTok Shop',
'tiktok_shop_transaction_fee' => 'biaya transaksi TikTok Shop',
'tiktok_shop_payment_fee' => 'biaya pembayaran TikTok Shop',
'tiktok_shop_affiliate_commission' => 'komisi afiliasi TikTok Shop',
'tiktok_shop_shipping_subsidy' => 'subsidi ongkir TikTok Shop',
'tiktok_shop_vat_rate' => 'PPN / pajak TikTok Shop',
'shopee_enabled' => 'aktif',
'shopee_commission_fee' => 'komisi Shopee',
'shopee_transaction_fee' => 'biaya transaksi Shopee',
'shopee_service_fee' => 'biaya layanan Shopee',

View File

@ -4,29 +4,59 @@
use App\Enums\OrderChannel;
use App\Settings\MarketplaceSettings;
use App\Support\Marketplace\MarketplaceFeeRule;
class MarketplaceService
{
/**
* @return list<string>
*/
private function tiktokFeeKeys(): array
{
return [
'tiktok_shop_admin_fee',
'tiktok_shop_transaction_fee',
'tiktok_shop_payment_fee',
'tiktok_shop_affiliate_commission',
'tiktok_shop_shipping_subsidy',
'tiktok_shop_vat_rate',
];
}
/**
* @return list<string>
*/
private function shopeeFeeKeys(): array
{
return [
'shopee_commission_fee',
'shopee_transaction_fee',
'shopee_service_fee',
'shopee_payment_fee',
'shopee_affiliate_commission',
'shopee_shipping_subsidy',
'shopee_voucher_fee',
];
}
public function marketplaceData(): array
{
$settings = app(MarketplaceSettings::class);
return [
'tiktok_shop_enabled' => $settings->tiktok_shop_enabled,
'tiktok_shop_admin_fee' => $settings->tiktok_shop_admin_fee,
'tiktok_shop_transaction_fee' => $settings->tiktok_shop_transaction_fee,
'tiktok_shop_payment_fee' => $settings->tiktok_shop_payment_fee,
'tiktok_shop_affiliate_commission' => $settings->tiktok_shop_affiliate_commission,
'tiktok_shop_shipping_subsidy' => $settings->tiktok_shop_shipping_subsidy,
'tiktok_shop_vat_rate' => $settings->tiktok_shop_vat_rate,
'shopee_enabled' => $settings->shopee_enabled,
'shopee_commission_fee' => $settings->shopee_commission_fee,
'shopee_transaction_fee' => $settings->shopee_transaction_fee,
'shopee_service_fee' => $settings->shopee_service_fee,
'shopee_payment_fee' => $settings->shopee_payment_fee,
'shopee_affiliate_commission' => $settings->shopee_affiliate_commission,
'shopee_shipping_subsidy' => $settings->shopee_shipping_subsidy,
'shopee_voucher_fee' => $settings->shopee_voucher_fee,
'tiktok_shop_admin_fee' => $this->presentFeeRule($settings->tiktok_shop_admin_fee),
'tiktok_shop_transaction_fee' => $this->presentFeeRule($settings->tiktok_shop_transaction_fee),
'tiktok_shop_payment_fee' => $this->presentFeeRule($settings->tiktok_shop_payment_fee),
'tiktok_shop_affiliate_commission' => $this->presentFeeRule($settings->tiktok_shop_affiliate_commission),
'tiktok_shop_shipping_subsidy' => $this->presentFeeRule($settings->tiktok_shop_shipping_subsidy),
'tiktok_shop_vat_rate' => $this->presentFeeRule($settings->tiktok_shop_vat_rate),
'shopee_commission_fee' => $this->presentFeeRule($settings->shopee_commission_fee),
'shopee_transaction_fee' => $this->presentFeeRule($settings->shopee_transaction_fee),
'shopee_service_fee' => $this->presentFeeRule($settings->shopee_service_fee),
'shopee_payment_fee' => $this->presentFeeRule($settings->shopee_payment_fee),
'shopee_affiliate_commission' => $this->presentFeeRule($settings->shopee_affiliate_commission),
'shopee_shipping_subsidy' => $this->presentFeeRule($settings->shopee_shipping_subsidy),
'shopee_voucher_fee' => $this->presentFeeRule($settings->shopee_voucher_fee),
];
}
@ -34,22 +64,13 @@ public function updateMarketplace(array $validated): void
{
$settings = app(MarketplaceSettings::class);
$settings->tiktok_shop_enabled = $validated['tiktok_shop_enabled'];
$settings->tiktok_shop_admin_fee = $validated['tiktok_shop_admin_fee'];
$settings->tiktok_shop_transaction_fee = $validated['tiktok_shop_transaction_fee'];
$settings->tiktok_shop_payment_fee = $validated['tiktok_shop_payment_fee'];
$settings->tiktok_shop_affiliate_commission = $validated['tiktok_shop_affiliate_commission'];
$settings->tiktok_shop_shipping_subsidy = $validated['tiktok_shop_shipping_subsidy'];
$settings->tiktok_shop_vat_rate = $validated['tiktok_shop_vat_rate'];
foreach ($this->tiktokFeeKeys() as $key) {
$settings->{$key} = $this->normalizeFeeRule($validated[$key]);
}
$settings->shopee_enabled = $validated['shopee_enabled'];
$settings->shopee_commission_fee = $validated['shopee_commission_fee'];
$settings->shopee_transaction_fee = $validated['shopee_transaction_fee'];
$settings->shopee_service_fee = $validated['shopee_service_fee'];
$settings->shopee_payment_fee = $validated['shopee_payment_fee'];
$settings->shopee_affiliate_commission = $validated['shopee_affiliate_commission'];
$settings->shopee_shipping_subsidy = $validated['shopee_shipping_subsidy'];
$settings->shopee_voucher_fee = $validated['shopee_voucher_fee'];
foreach ($this->shopeeFeeKeys() as $key) {
$settings->{$key} = $this->normalizeFeeRule($validated[$key]);
}
$settings->save();
}
@ -64,24 +85,46 @@ public function snapshotForChannel(OrderChannel $channel): ?array
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,
'fees' => [
'commission_fee' => $this->presentFeeRule($settings->shopee_commission_fee),
'transaction_fee' => $this->presentFeeRule($settings->shopee_transaction_fee),
'service_fee' => $this->presentFeeRule($settings->shopee_service_fee),
'payment_fee' => $this->presentFeeRule($settings->shopee_payment_fee),
'affiliate_commission' => $this->presentFeeRule($settings->shopee_affiliate_commission),
'shipping_subsidy' => $this->presentFeeRule($settings->shopee_shipping_subsidy),
'voucher_fee' => $this->presentFeeRule($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,
'fees' => [
'admin_fee' => $this->presentFeeRule($settings->tiktok_shop_admin_fee),
'transaction_fee' => $this->presentFeeRule($settings->tiktok_shop_transaction_fee),
'payment_fee' => $this->presentFeeRule($settings->tiktok_shop_payment_fee),
'affiliate_commission' => $this->presentFeeRule($settings->tiktok_shop_affiliate_commission),
'shipping_subsidy' => $this->presentFeeRule($settings->tiktok_shop_shipping_subsidy),
'vat_rate' => $this->presentFeeRule($settings->tiktok_shop_vat_rate),
],
],
OrderChannel::STORE => null,
};
}
/**
* @param array{scope: string, value_type: string, value: float|int|string} $data
* @return array{scope: string, value_type: string, value: float}
*/
private function presentFeeRule(array $data): array
{
return MarketplaceFeeRule::fromArray($data)->toArray();
}
/**
* @param array{scope: string, value_type: string, value: float|int|string} $data
* @return array{scope: string, value_type: string, value: float}
*/
private function normalizeFeeRule(array $data): array
{
return MarketplaceFeeRule::fromArray($data)->toArray();
}
}

View File

@ -6,35 +6,31 @@
class MarketplaceSettings extends Settings
{
public bool $tiktok_shop_enabled;
public array $tiktok_shop_admin_fee;
public float $tiktok_shop_admin_fee;
public array $tiktok_shop_transaction_fee;
public float $tiktok_shop_transaction_fee;
public array $tiktok_shop_payment_fee;
public float $tiktok_shop_payment_fee;
public array $tiktok_shop_affiliate_commission;
public float $tiktok_shop_affiliate_commission;
public array $tiktok_shop_shipping_subsidy;
public float $tiktok_shop_shipping_subsidy;
public array $tiktok_shop_vat_rate;
public float $tiktok_shop_vat_rate;
public array $shopee_commission_fee;
public bool $shopee_enabled;
public array $shopee_transaction_fee;
public float $shopee_commission_fee;
public array $shopee_service_fee;
public float $shopee_transaction_fee;
public array $shopee_payment_fee;
public float $shopee_service_fee;
public array $shopee_affiliate_commission;
public float $shopee_payment_fee;
public array $shopee_shipping_subsidy;
public float $shopee_affiliate_commission;
public float $shopee_shipping_subsidy;
public float $shopee_voucher_fee;
public array $shopee_voucher_fee;
public static function group(): string
{

View File

@ -0,0 +1,48 @@
<?php
namespace App\Support\Marketplace;
use App\Enums\MarketplaceFeeScope;
use App\Enums\MarketplaceFeeValueType;
readonly class MarketplaceFeeRule
{
public function __construct(
public MarketplaceFeeScope $scope,
public MarketplaceFeeValueType $valueType,
public float $value,
) {}
/**
* @param array{scope: string, value_type: string, value: float|int|string} $data
*/
public static function fromArray(array $data): self
{
return new self(
scope: MarketplaceFeeScope::from($data['scope']),
valueType: MarketplaceFeeValueType::from($data['value_type']),
value: (float) $data['value'],
);
}
public static function defaultPercent(float $value): self
{
return new self(
scope: MarketplaceFeeScope::TRANSACTION,
valueType: MarketplaceFeeValueType::PERCENT,
value: $value,
);
}
/**
* @return array{scope: string, value_type: string, value: float}
*/
public function toArray(): array
{
return [
'scope' => $this->scope->value,
'value_type' => $this->valueType->value,
'value' => $this->value,
];
}
}

View File

@ -1,5 +1,6 @@
<?php
use App\Support\Marketplace\MarketplaceFeeRule;
use Spatie\LaravelSettings\Migrations\SettingsBlueprint;
use Spatie\LaravelSettings\Migrations\SettingsMigration;
@ -24,22 +25,20 @@ public function up(): void
});
$this->migrator->inGroup('marketplace', function (SettingsBlueprint $blueprint): void {
$blueprint->add('tiktok_shop_enabled', true);
$blueprint->add('tiktok_shop_admin_fee', 5.0);
$blueprint->add('tiktok_shop_transaction_fee', 1.0);
$blueprint->add('tiktok_shop_payment_fee', 0.7);
$blueprint->add('tiktok_shop_affiliate_commission', 0.0);
$blueprint->add('tiktok_shop_shipping_subsidy', 0.0);
$blueprint->add('tiktok_shop_vat_rate', 11.0);
$blueprint->add('tiktok_shop_admin_fee', MarketplaceFeeRule::defaultPercent(5.0)->toArray());
$blueprint->add('tiktok_shop_transaction_fee', MarketplaceFeeRule::defaultPercent(1.0)->toArray());
$blueprint->add('tiktok_shop_payment_fee', MarketplaceFeeRule::defaultPercent(0.7)->toArray());
$blueprint->add('tiktok_shop_affiliate_commission', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
$blueprint->add('tiktok_shop_shipping_subsidy', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
$blueprint->add('tiktok_shop_vat_rate', MarketplaceFeeRule::defaultPercent(11.0)->toArray());
$blueprint->add('shopee_enabled', true);
$blueprint->add('shopee_commission_fee', 6.0);
$blueprint->add('shopee_transaction_fee', 2.0);
$blueprint->add('shopee_service_fee', 0.0);
$blueprint->add('shopee_payment_fee', 0.0);
$blueprint->add('shopee_affiliate_commission', 0.0);
$blueprint->add('shopee_shipping_subsidy', 0.0);
$blueprint->add('shopee_voucher_fee', 0.0);
$blueprint->add('shopee_commission_fee', MarketplaceFeeRule::defaultPercent(6.0)->toArray());
$blueprint->add('shopee_transaction_fee', MarketplaceFeeRule::defaultPercent(2.0)->toArray());
$blueprint->add('shopee_service_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
$blueprint->add('shopee_payment_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
$blueprint->add('shopee_affiliate_commission', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
$blueprint->add('shopee_shipping_subsidy', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
$blueprint->add('shopee_voucher_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
});
}
};

View File

@ -0,0 +1,123 @@
<script setup lang="ts">
import { computed } from 'vue';
import {
Field,
FieldError,
FieldLabel,
} from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import { RupiahInput } from '@/components/ui/rupiah-input';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import type { MarketplaceFeeRule } from '@/types/setting';
const props = defineProps<{
id: string;
label: string;
modelValue: MarketplaceFeeRule;
errors?: string[];
}>();
const emit = defineEmits<{
(event: 'update:modelValue', value: MarketplaceFeeRule): void;
}>();
const isPercent = computed(() => props.modelValue.value_type === 'percent');
function update(partial: Partial<MarketplaceFeeRule>) {
emit('update:modelValue', {
...props.modelValue,
...partial,
});
}
function updateValue(value: string | number) {
update({
value: props.modelValue.value_type === 'flat'
? Number(value) || 0
: Number(value),
});
}
</script>
<template>
<Field class="sm:col-span-2">
<FieldLabel :for="`${id}-value`">{{ label }}</FieldLabel>
<div class="grid gap-3 sm:grid-cols-3">
<Field>
<FieldLabel :for="`${id}-scope`" class="text-xs text-muted-foreground">
Dasar
</FieldLabel>
<Select
:model-value="modelValue.scope"
@update:model-value="update({ scope: $event as MarketplaceFeeRule['scope'] })"
>
<SelectTrigger :id="`${id}-scope`">
<SelectValue placeholder="Pilih dasar" />
</SelectTrigger>
<SelectContent>
<SelectItem value="transaction">
Per Transaksi
</SelectItem>
<SelectItem value="product">
Per Produk
</SelectItem>
</SelectContent>
</Select>
</Field>
<Field>
<FieldLabel :for="`${id}-value-type`" class="text-xs text-muted-foreground">
Tipe
</FieldLabel>
<Select
:model-value="modelValue.value_type"
@update:model-value="update({ value_type: $event as MarketplaceFeeRule['value_type'] })"
>
<SelectTrigger :id="`${id}-value-type`">
<SelectValue placeholder="Pilih tipe" />
</SelectTrigger>
<SelectContent>
<SelectItem value="percent">
Persentase (%)
</SelectItem>
<SelectItem value="flat">
Flat (Rp)
</SelectItem>
</SelectContent>
</Select>
</Field>
<Field>
<FieldLabel :for="`${id}-value`" class="text-xs text-muted-foreground">
Nilai
</FieldLabel>
<RupiahInput
v-if="!isPercent"
:id="`${id}-value`"
:model-value="modelValue.value"
placeholder="0"
@update:model-value="updateValue"
/>
<Input
v-else
:id="`${id}-value`"
:model-value="modelValue.value"
type="number"
step="0.01"
min="0"
max="100"
@update:model-value="updateValue"
/>
</Field>
</div>
<FieldError :errors="errors" />
</Field>
</template>

View File

@ -3,19 +3,16 @@ import { useForm } from '@inertiajs/vue3';
import { Save, ShoppingBag, Store } from '@lucide/vue';
import { ref } from 'vue';
import { toast } from 'vue-sonner';
import MarketplaceFeeField from '@/components/admin/setting/MarketplaceFeeField.vue';
import { Button } from '@/components/ui/button';
import {
Card,
CardContent
} from '@/components/ui/card';
import {
Field, FieldError,
FieldGroup,
FieldLabel,
FieldSet
} from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import { Switch } from '@/components/ui/switch';
import { formErrors } from '@/lib/form';
import { cn } from '@/lib/utils';
import type {
@ -39,24 +36,30 @@ const platformItems: Array<{
];
const form = useForm({
tiktok_shop_enabled: props.data.tiktok_shop_enabled,
tiktok_shop_admin_fee: props.data.tiktok_shop_admin_fee,
tiktok_shop_transaction_fee: props.data.tiktok_shop_transaction_fee,
tiktok_shop_payment_fee: props.data.tiktok_shop_payment_fee,
tiktok_shop_affiliate_commission: props.data.tiktok_shop_affiliate_commission,
tiktok_shop_shipping_subsidy: props.data.tiktok_shop_shipping_subsidy,
tiktok_shop_vat_rate: props.data.tiktok_shop_vat_rate,
tiktok_shop_admin_fee: { ...props.data.tiktok_shop_admin_fee },
tiktok_shop_transaction_fee: { ...props.data.tiktok_shop_transaction_fee },
tiktok_shop_payment_fee: { ...props.data.tiktok_shop_payment_fee },
tiktok_shop_affiliate_commission: { ...props.data.tiktok_shop_affiliate_commission },
tiktok_shop_shipping_subsidy: { ...props.data.tiktok_shop_shipping_subsidy },
tiktok_shop_vat_rate: { ...props.data.tiktok_shop_vat_rate },
shopee_enabled: props.data.shopee_enabled,
shopee_commission_fee: props.data.shopee_commission_fee,
shopee_transaction_fee: props.data.shopee_transaction_fee,
shopee_service_fee: props.data.shopee_service_fee,
shopee_payment_fee: props.data.shopee_payment_fee,
shopee_affiliate_commission: props.data.shopee_affiliate_commission,
shopee_shipping_subsidy: props.data.shopee_shipping_subsidy,
shopee_voucher_fee: props.data.shopee_voucher_fee,
shopee_commission_fee: { ...props.data.shopee_commission_fee },
shopee_transaction_fee: { ...props.data.shopee_transaction_fee },
shopee_service_fee: { ...props.data.shopee_service_fee },
shopee_payment_fee: { ...props.data.shopee_payment_fee },
shopee_affiliate_commission: { ...props.data.shopee_affiliate_commission },
shopee_shipping_subsidy: { ...props.data.shopee_shipping_subsidy },
shopee_voucher_fee: { ...props.data.shopee_voucher_fee },
});
function feeErrors(key: string): string[] {
return [
...formErrors(form, `${key}.scope`),
...formErrors(form, `${key}.value_type`),
...formErrors(form, `${key}.value`),
];
}
function submit() {
form.put('/admin/system/setting/marketplace', {
preserveScroll: true,
@ -87,55 +90,47 @@ function submit() {
<CardContent>
<FieldSet>
<FieldGroup class="grid gap-4 sm:grid-cols-2">
<Field>
<FieldLabel for="tiktok_shop_admin_fee">Biaya Admin (%)</FieldLabel>
<Input id="tiktok_shop_admin_fee" v-model="form.tiktok_shop_admin_fee" type="number"
step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'tiktok_shop_admin_fee')" />
</Field>
<MarketplaceFeeField
id="tiktok_shop_admin_fee"
v-model="form.tiktok_shop_admin_fee"
label="Biaya Admin"
:errors="feeErrors('tiktok_shop_admin_fee')"
/>
<Field>
<FieldLabel for="tiktok_shop_transaction_fee">Biaya Transaksi (%)</FieldLabel>
<Input id="tiktok_shop_transaction_fee" v-model="form.tiktok_shop_transaction_fee"
type="number" step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'tiktok_shop_transaction_fee')" />
</Field>
<MarketplaceFeeField
id="tiktok_shop_transaction_fee"
v-model="form.tiktok_shop_transaction_fee"
label="Biaya Transaksi"
:errors="feeErrors('tiktok_shop_transaction_fee')"
/>
<Field>
<FieldLabel for="tiktok_shop_payment_fee">Biaya Pembayaran (%)</FieldLabel>
<Input id="tiktok_shop_payment_fee" v-model="form.tiktok_shop_payment_fee"
type="number" step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'tiktok_shop_payment_fee')" />
</Field>
<MarketplaceFeeField
id="tiktok_shop_payment_fee"
v-model="form.tiktok_shop_payment_fee"
label="Biaya Pembayaran"
:errors="feeErrors('tiktok_shop_payment_fee')"
/>
<Field>
<FieldLabel for="tiktok_shop_affiliate_commission">Komisi Afiliasi (%)</FieldLabel>
<Input id="tiktok_shop_affiliate_commission"
v-model="form.tiktok_shop_affiliate_commission" type="number" step="0.01"
min="0" max="100" />
<FieldError :errors="formErrors(form, 'tiktok_shop_affiliate_commission')" />
</Field>
<MarketplaceFeeField
id="tiktok_shop_affiliate_commission"
v-model="form.tiktok_shop_affiliate_commission"
label="Komisi Afiliasi"
:errors="feeErrors('tiktok_shop_affiliate_commission')"
/>
<Field>
<FieldLabel for="tiktok_shop_shipping_subsidy">Subsidi Ongkir (%)</FieldLabel>
<Input id="tiktok_shop_shipping_subsidy" v-model="form.tiktok_shop_shipping_subsidy"
type="number" step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'tiktok_shop_shipping_subsidy')" />
</Field>
<MarketplaceFeeField
id="tiktok_shop_shipping_subsidy"
v-model="form.tiktok_shop_shipping_subsidy"
label="Subsidi Ongkir"
:errors="feeErrors('tiktok_shop_shipping_subsidy')"
/>
<Field>
<FieldLabel for="tiktok_shop_vat_rate">PPN / Pajak (%)</FieldLabel>
<Input id="tiktok_shop_vat_rate" v-model="form.tiktok_shop_vat_rate" type="number"
step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'tiktok_shop_vat_rate')" />
</Field>
<div class="flex items-center gap-2">
<Switch id="tiktok_shop_enabled" v-model:checked="form.tiktok_shop_enabled" />
<FieldLabel for="tiktok_shop_enabled" class="mb-0 text-sm">
Aktif
</FieldLabel>
</div>
<MarketplaceFeeField
id="tiktok_shop_vat_rate"
v-model="form.tiktok_shop_vat_rate"
label="PPN / Pajak"
:errors="feeErrors('tiktok_shop_vat_rate')"
/>
</FieldGroup>
</FieldSet>
</CardContent>
@ -145,62 +140,54 @@ function submit() {
<CardContent>
<FieldSet>
<FieldGroup class="grid gap-4 sm:grid-cols-2">
<Field>
<FieldLabel for="shopee_commission_fee">Komisi Shopee (%)</FieldLabel>
<Input id="shopee_commission_fee" v-model="form.shopee_commission_fee" type="number"
step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'shopee_commission_fee')" />
</Field>
<MarketplaceFeeField
id="shopee_commission_fee"
v-model="form.shopee_commission_fee"
label="Komisi Shopee"
:errors="feeErrors('shopee_commission_fee')"
/>
<Field>
<FieldLabel for="shopee_transaction_fee">Biaya Transaksi (%)</FieldLabel>
<Input id="shopee_transaction_fee" v-model="form.shopee_transaction_fee"
type="number" step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'shopee_transaction_fee')" />
</Field>
<MarketplaceFeeField
id="shopee_transaction_fee"
v-model="form.shopee_transaction_fee"
label="Biaya Transaksi"
:errors="feeErrors('shopee_transaction_fee')"
/>
<Field>
<FieldLabel for="shopee_service_fee">Biaya Layanan (%)</FieldLabel>
<Input id="shopee_service_fee" v-model="form.shopee_service_fee" type="number"
step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'shopee_service_fee')" />
</Field>
<MarketplaceFeeField
id="shopee_service_fee"
v-model="form.shopee_service_fee"
label="Biaya Layanan"
:errors="feeErrors('shopee_service_fee')"
/>
<Field>
<FieldLabel for="shopee_payment_fee">Biaya Pembayaran (%)</FieldLabel>
<Input id="shopee_payment_fee" v-model="form.shopee_payment_fee" type="number"
step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'shopee_payment_fee')" />
</Field>
<MarketplaceFeeField
id="shopee_payment_fee"
v-model="form.shopee_payment_fee"
label="Biaya Pembayaran"
:errors="feeErrors('shopee_payment_fee')"
/>
<Field>
<FieldLabel for="shopee_affiliate_commission">Komisi Afiliasi Shopee (%)
</FieldLabel>
<Input id="shopee_affiliate_commission" v-model="form.shopee_affiliate_commission"
type="number" step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'shopee_affiliate_commission')" />
</Field>
<MarketplaceFeeField
id="shopee_affiliate_commission"
v-model="form.shopee_affiliate_commission"
label="Komisi Afiliasi Shopee"
:errors="feeErrors('shopee_affiliate_commission')"
/>
<Field>
<FieldLabel for="shopee_shipping_subsidy">Subsidi Ongkir (%)</FieldLabel>
<Input id="shopee_shipping_subsidy" v-model="form.shopee_shipping_subsidy"
type="number" step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'shopee_shipping_subsidy')" />
</Field>
<MarketplaceFeeField
id="shopee_shipping_subsidy"
v-model="form.shopee_shipping_subsidy"
label="Subsidi Ongkir"
:errors="feeErrors('shopee_shipping_subsidy')"
/>
<Field>
<FieldLabel for="shopee_voucher_fee">Biaya Voucher / Diskon (%)</FieldLabel>
<Input id="shopee_voucher_fee" v-model="form.shopee_voucher_fee" type="number"
step="0.01" min="0" max="100" />
<FieldError :errors="formErrors(form, 'shopee_voucher_fee')" />
</Field>
<div class="flex items-center gap-2">
<Switch id="shopee_enabled" v-model:checked="form.shopee_enabled" />
<FieldLabel for="shopee_enabled" class="mb-0 text-sm">
Aktif
</FieldLabel>
</div>
<MarketplaceFeeField
id="shopee_voucher_fee"
v-model="form.shopee_voucher_fee"
label="Biaya Voucher / Diskon"
:errors="feeErrors('shopee_voucher_fee')"
/>
</FieldGroup>
</FieldSet>
</CardContent>

View File

@ -2,6 +2,16 @@ export type SettingSection = 'system' | 'social' | 'marketplace';
export type MarketplacePlatform = 'tiktok_shop' | 'shopee';
export type MarketplaceFeeScope = 'product' | 'transaction';
export type MarketplaceFeeValueType = 'flat' | 'percent';
export type MarketplaceFeeRule = {
scope: MarketplaceFeeScope;
value_type: MarketplaceFeeValueType;
value: number;
};
export type SystemSettingsData = {
app_name: string;
about_app: string;
@ -19,19 +29,17 @@ export type SocialMediaSettingsData = {
};
export type MarketplaceSettingsData = {
tiktok_shop_enabled: boolean;
tiktok_shop_admin_fee: number;
tiktok_shop_transaction_fee: number;
tiktok_shop_payment_fee: number;
tiktok_shop_affiliate_commission: number;
tiktok_shop_shipping_subsidy: number;
tiktok_shop_vat_rate: number;
shopee_enabled: boolean;
shopee_commission_fee: number;
shopee_transaction_fee: number;
shopee_service_fee: number;
shopee_payment_fee: number;
shopee_affiliate_commission: number;
shopee_shipping_subsidy: number;
shopee_voucher_fee: number;
tiktok_shop_admin_fee: MarketplaceFeeRule;
tiktok_shop_transaction_fee: MarketplaceFeeRule;
tiktok_shop_payment_fee: MarketplaceFeeRule;
tiktok_shop_affiliate_commission: MarketplaceFeeRule;
tiktok_shop_shipping_subsidy: MarketplaceFeeRule;
tiktok_shop_vat_rate: MarketplaceFeeRule;
shopee_commission_fee: MarketplaceFeeRule;
shopee_transaction_fee: MarketplaceFeeRule;
shopee_service_fee: MarketplaceFeeRule;
shopee_payment_fee: MarketplaceFeeRule;
shopee_affiliate_commission: MarketplaceFeeRule;
shopee_shipping_subsidy: MarketplaceFeeRule;
shopee_voucher_fee: MarketplaceFeeRule;
};