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:
parent
584387504c
commit
7d721cab31
21
app/Enums/MarketplaceFeeScope.php
Normal file
21
app/Enums/MarketplaceFeeScope.php
Normal 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',
|
||||
};
|
||||
}
|
||||
}
|
||||
21
app/Enums/MarketplaceFeeValueType.php
Normal file
21
app/Enums/MarketplaceFeeValueType.php
Normal 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 (%)',
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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',
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
48
app/Support/Marketplace/MarketplaceFeeRule.php
Normal file
48
app/Support/Marketplace/MarketplaceFeeRule.php
Normal 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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
123
resources/js/components/admin/setting/MarketplaceFeeField.vue
Normal file
123
resources/js/components/admin/setting/MarketplaceFeeField.vue
Normal 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>
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user