Refactor marketplace settings: remove MarketplaceFeeRule, update related database and UI components
- Deleted MarketplaceFeeRule class and its usage in settings migration. - Removed 'is_affiliate' field from orders and related factories. - Updated notifications table to use longText for body. - Adjusted role permissions by removing marketplace-related permissions. - Cleaned up admin settings page by removing marketplace settings section and related components. - Updated tests to reflect the removal of marketplace settings and ensure other settings remain unaffected.
This commit is contained in:
parent
0aae00a96b
commit
49841a662c
@ -206,7 +206,6 @@ ### Casting — Wajib untuk Semua Tipe
|
|||||||
'is_affiliate' => 'boolean',
|
'is_affiliate' => 'boolean',
|
||||||
|
|
||||||
// Array (JSON)
|
// Array (JSON)
|
||||||
'marketplace_settings_snapshot' => 'array',
|
|
||||||
'payload' => 'array',
|
'payload' => 'array',
|
||||||
|
|
||||||
// DateTime
|
// DateTime
|
||||||
|
|||||||
@ -26,7 +26,7 @@ ### `push_subscriptions` → PushSubscription
|
|||||||
- Relations: user(MorphTo)
|
- Relations: user(MorphTo)
|
||||||
|
|
||||||
### `notifications` → AppNotification
|
### `notifications` → AppNotification
|
||||||
`id` `user_id`(FK→users) `title` `body`(text,null) `url`(null) `is_read`(bool,default:false) `read_at`(datetime,null) `created_at` `updated_at`
|
`id` `user_id`(FK→users) `title` `body`(longText,null) `url`(null) `is_read`(bool,default:false) `read_at`(datetime,null) `created_at` `updated_at`
|
||||||
- Casts: is_read(bool), read_at(datetime)
|
- Casts: is_read(bool), read_at(datetime)
|
||||||
- Accessor: formatted_read_at → 'l, d F Y H:i'
|
- Accessor: formatted_read_at → 'l, d F Y H:i'
|
||||||
- Relations: user(BelongsTo→User)
|
- Relations: user(BelongsTo→User)
|
||||||
@ -167,8 +167,8 @@ ### `leave_requests` → LeaveRequest
|
|||||||
## Sales
|
## Sales
|
||||||
|
|
||||||
### `orders` → Order
|
### `orders` → Order
|
||||||
`id` `customer_id`(FK→customers,null) `marketing_id`(FK→users,null) `cash_transaction_id`(FK→cash_transactions,unique,null) `created_by_id`(FK→users) `order_number`(30,unique) `channel`(enum) `price_type`(enum) `status`(enum,default:pending) `payment_type`(enum,default:cash) `is_affiliate`(bool,default:false) `tiktok_order_id`(100,null) `shopee_order_id`(100,null) `subtotal`(ubig) `discount`(ubig,default:0) `nego_price`(ubig,null) `marketplace_settings_snapshot`(json,null) `total_amount`(ubig) `cogs`(ubig,default:0) `notes`(text,null) `created_at` `updated_at` `deleted_at`
|
`id` `customer_id`(FK→customers,null) `marketing_id`(FK→users,null) `cash_transaction_id`(FK→cash_transactions,unique,null) `created_by_id`(FK→users) `order_number`(30,unique) `channel`(enum) `price_type`(enum) `status`(enum,default:pending) `payment_type`(enum,default:cash) `tiktok_order_id`(100,null) `shopee_order_id`(100,null) `subtotal`(ubig) `discount`(ubig,default:0) `nego_price`(ubig,null) `total_amount`(ubig) `cogs`(ubig,default:0) `notes`(text,null) `created_at` `updated_at` `deleted_at`
|
||||||
- Casts: channel(OrderChannel), price_type(PriceType), status(OrderStatus), payment_type(PaymentType), is_affiliate(bool), subtotal(int), discount(int), nego_price(int), total_amount(int), cogs(int), marketplace_settings_snapshot(array)
|
- Casts: channel(OrderChannel), price_type(PriceType), status(OrderStatus), payment_type(PaymentType), subtotal(int), discount(int), nego_price(int), total_amount(int), cogs(int)
|
||||||
- Scopes: cancelled(), cash(), completed(), pending(), processing(), qris(), refunded(), retail(), shopee(), store(), tiktok(), transfer(), wholesale()
|
- Scopes: cancelled(), cash(), completed(), pending(), processing(), qris(), refunded(), retail(), shopee(), store(), tiktok(), transfer(), wholesale()
|
||||||
- Relations: cashTransaction(BelongsTo→CashTransaction), createdBy(BelongsTo→User), customer(BelongsTo→Customer), marketing(BelongsTo→User), orderItems(HasMany→OrderItem)
|
- Relations: cashTransaction(BelongsTo→CashTransaction), createdBy(BelongsTo→User), customer(BelongsTo→Customer), marketing(BelongsTo→User), orderItems(HasMany→OrderItem)
|
||||||
|
|
||||||
|
|||||||
@ -168,8 +168,6 @@ enum Permission: string
|
|||||||
case SETTINGS_UPDATE_HOMEPAGE = 'settings.update_homepage';
|
case SETTINGS_UPDATE_HOMEPAGE = 'settings.update_homepage';
|
||||||
case SETTINGS_VIEW_SOCIAL_MEDIA = 'settings.view_social_media';
|
case SETTINGS_VIEW_SOCIAL_MEDIA = 'settings.view_social_media';
|
||||||
case SETTINGS_UPDATE_SOCIAL_MEDIA = 'settings.update_social_media';
|
case SETTINGS_UPDATE_SOCIAL_MEDIA = 'settings.update_social_media';
|
||||||
case SETTINGS_VIEW_MARKETPLACE = 'settings.view_marketplace';
|
|
||||||
case SETTINGS_UPDATE_MARKETPLACE = 'settings.update_marketplace';
|
|
||||||
case SETTINGS_VIEW_HR = 'settings.view_hr';
|
case SETTINGS_VIEW_HR = 'settings.view_hr';
|
||||||
case SETTINGS_UPDATE_HR = 'settings.update_hr';
|
case SETTINGS_UPDATE_HR = 'settings.update_hr';
|
||||||
|
|
||||||
|
|||||||
@ -195,8 +195,6 @@ public function permissions(): array
|
|||||||
Permission::SETTINGS_UPDATE_SYSTEM,
|
Permission::SETTINGS_UPDATE_SYSTEM,
|
||||||
Permission::SETTINGS_VIEW_SOCIAL_MEDIA,
|
Permission::SETTINGS_VIEW_SOCIAL_MEDIA,
|
||||||
Permission::SETTINGS_UPDATE_SOCIAL_MEDIA,
|
Permission::SETTINGS_UPDATE_SOCIAL_MEDIA,
|
||||||
Permission::SETTINGS_VIEW_MARKETPLACE,
|
|
||||||
Permission::SETTINGS_UPDATE_MARKETPLACE,
|
|
||||||
Permission::SETTINGS_VIEW_HR,
|
Permission::SETTINGS_VIEW_HR,
|
||||||
Permission::SETTINGS_UPDATE_HR,
|
Permission::SETTINGS_UPDATE_HR,
|
||||||
Permission::SETTINGS_VIEW_HOMEPAGE,
|
Permission::SETTINGS_VIEW_HOMEPAGE,
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Admin\Settings\UpdateHomepageRequest;
|
use App\Http\Requests\Admin\Settings\UpdateHomepageRequest;
|
||||||
use App\Http\Requests\Admin\Settings\UpdateHRRequest;
|
use App\Http\Requests\Admin\Settings\UpdateHRRequest;
|
||||||
use App\Http\Requests\Admin\Settings\UpdateMarketplaceRequest;
|
|
||||||
use App\Http\Requests\Admin\Settings\UpdateSocialMediaRequest;
|
use App\Http\Requests\Admin\Settings\UpdateSocialMediaRequest;
|
||||||
use App\Http\Requests\Admin\Settings\UpdateSystemRequest;
|
use App\Http\Requests\Admin\Settings\UpdateSystemRequest;
|
||||||
use App\Services\Admin\AdminSettingsService;
|
use App\Services\Admin\AdminSettingsService;
|
||||||
@ -25,7 +24,6 @@ public function index(): Response
|
|||||||
'system' => $this->service->getSystemData(),
|
'system' => $this->service->getSystemData(),
|
||||||
'homepage' => $this->service->getHomepageData(),
|
'homepage' => $this->service->getHomepageData(),
|
||||||
'socialMedia' => $this->service->getSocialMediaData(),
|
'socialMedia' => $this->service->getSocialMediaData(),
|
||||||
'marketplace' => $this->service->getMarketplaceData(),
|
|
||||||
'hr' => $this->service->getHRData(),
|
'hr' => $this->service->getHRData(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -57,15 +55,6 @@ public function updateSocialMedia(UpdateSocialMediaRequest $request): RedirectRe
|
|||||||
return back();
|
return back();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateMarketplace(UpdateMarketplaceRequest $request): RedirectResponse
|
|
||||||
{
|
|
||||||
$this->service->updateMarketplace($request->validated());
|
|
||||||
|
|
||||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pengaturan marketplace berhasil diperbarui.']);
|
|
||||||
|
|
||||||
return back();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateHR(UpdateHRRequest $request): RedirectResponse
|
public function updateHR(UpdateHRRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
$this->service->updateHR($request->validated());
|
$this->service->updateHR($request->validated());
|
||||||
|
|||||||
@ -37,7 +37,6 @@ public function rules(): array
|
|||||||
'discount' => ['nullable', 'integer', 'min:0'],
|
'discount' => ['nullable', 'integer', 'min:0'],
|
||||||
'nego_price' => ['nullable', 'integer'],
|
'nego_price' => ['nullable', 'integer'],
|
||||||
'is_completed' => ['sometimes', 'boolean'],
|
'is_completed' => ['sometimes', 'boolean'],
|
||||||
'is_affiliate' => ['sometimes', 'boolean'],
|
|
||||||
'tiktok_order_id' => ['nullable', 'string', 'max:100'],
|
'tiktok_order_id' => ['nullable', 'string', 'max:100'],
|
||||||
'shopee_order_id' => ['nullable', 'string', 'max:100'],
|
'shopee_order_id' => ['nullable', 'string', 'max:100'],
|
||||||
'items' => ['required', 'array', 'min:1'],
|
'items' => ['required', 'array', 'min:1'],
|
||||||
@ -66,7 +65,6 @@ public function attributes(): array
|
|||||||
'discount' => 'diskon',
|
'discount' => 'diskon',
|
||||||
'nego_price' => 'harga nego',
|
'nego_price' => 'harga nego',
|
||||||
'is_completed' => 'pesanan selesai',
|
'is_completed' => 'pesanan selesai',
|
||||||
'is_affiliate' => 'affiliasi',
|
|
||||||
'tiktok_order_id' => 'id pesanan tiktok',
|
'tiktok_order_id' => 'id pesanan tiktok',
|
||||||
'shopee_order_id' => 'id pesanan shopee',
|
'shopee_order_id' => 'id pesanan shopee',
|
||||||
'items' => 'item produk',
|
'items' => 'item produk',
|
||||||
|
|||||||
@ -1,108 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Admin\Settings;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class UpdateMarketplaceRequest extends FormRequest
|
|
||||||
{
|
|
||||||
public function authorize(): bool
|
|
||||||
{
|
|
||||||
return $this->user()->can('settings.update_marketplace');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function feeRuleRules(): array
|
|
||||||
{
|
|
||||||
return ['required', 'array'];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function feeFieldRules(string $prefix): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"{$prefix}.base" => ['required', 'string', 'in:per_transaksi,per_produk'],
|
|
||||||
"{$prefix}.type" => ['required', 'string', 'in:flat,persentase'],
|
|
||||||
"{$prefix}.value" => ['required', 'numeric', 'min:0'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
$keys = [
|
|
||||||
'tiktok_shop_platform_commission',
|
|
||||||
'tiktok_shop_logistics_service_fee',
|
|
||||||
'tiktok_shop_dynamic_commission',
|
|
||||||
'tiktok_shop_order_processing_fee',
|
|
||||||
'tiktok_shop_affiliate',
|
|
||||||
'tiktok_shop_pre_order_service_fee',
|
|
||||||
'shopee_admin_fee',
|
|
||||||
'shopee_program_fee',
|
|
||||||
'shopee_shipping_savings',
|
|
||||||
'shopee_premium',
|
|
||||||
'shopee_service_fee',
|
|
||||||
'shopee_order_processing_fee',
|
|
||||||
'shopee_ams_commission_fee',
|
|
||||||
'shopee_pre_order',
|
|
||||||
'shopee_live_extra',
|
|
||||||
];
|
|
||||||
|
|
||||||
$rules = [];
|
|
||||||
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$rules[$key] = $this->feeRuleRules();
|
|
||||||
$rules = array_merge($rules, $this->feeFieldRules($key));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function attributes(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'tiktok_shop_platform_commission.base' => 'dasar komisi platform tiktok shop',
|
|
||||||
'tiktok_shop_platform_commission.type' => 'tipe komisi platform tiktok shop',
|
|
||||||
'tiktok_shop_platform_commission.value' => 'nilai komisi platform tiktok shop',
|
|
||||||
'tiktok_shop_logistics_service_fee.base' => 'dasar layanan logistik tiktok shop',
|
|
||||||
'tiktok_shop_logistics_service_fee.type' => 'tipe layanan logistik tiktok shop',
|
|
||||||
'tiktok_shop_logistics_service_fee.value' => 'nilai layanan logistik tiktok shop',
|
|
||||||
'tiktok_shop_dynamic_commission.base' => 'dasar komisi dinamis tiktok shop',
|
|
||||||
'tiktok_shop_dynamic_commission.type' => 'tipe komisi dinamis tiktok shop',
|
|
||||||
'tiktok_shop_dynamic_commission.value' => 'nilai komisi dinamis tiktok shop',
|
|
||||||
'tiktok_shop_order_processing_fee.base' => 'dasar pemrosesan pesanan tiktok shop',
|
|
||||||
'tiktok_shop_order_processing_fee.type' => 'tipe pemrosesan pesanan tiktok shop',
|
|
||||||
'tiktok_shop_order_processing_fee.value' => 'nilai pemrosesan pesanan tiktok shop',
|
|
||||||
'tiktok_shop_affiliate.base' => 'dasar affiliate tiktok shop',
|
|
||||||
'tiktok_shop_affiliate.type' => 'tipe affiliate tiktok shop',
|
|
||||||
'tiktok_shop_affiliate.value' => 'nilai affiliate tiktok shop',
|
|
||||||
'tiktok_shop_pre_order_service_fee.base' => 'dasar layanan po tiktok shop',
|
|
||||||
'tiktok_shop_pre_order_service_fee.type' => 'tipe layanan po tiktok shop',
|
|
||||||
'tiktok_shop_pre_order_service_fee.value' => 'nilai layanan po tiktok shop',
|
|
||||||
'shopee_admin_fee.base' => 'dasar biaya administrasi shopee',
|
|
||||||
'shopee_admin_fee.type' => 'tipe biaya administrasi shopee',
|
|
||||||
'shopee_admin_fee.value' => 'nilai biaya administrasi shopee',
|
|
||||||
'shopee_program_fee.base' => 'dasar biaya program shopee',
|
|
||||||
'shopee_program_fee.type' => 'tipe biaya program shopee',
|
|
||||||
'shopee_program_fee.value' => 'nilai biaya program shopee',
|
|
||||||
'shopee_shipping_savings.base' => 'dasar hemat biaya kirim shopee',
|
|
||||||
'shopee_shipping_savings.type' => 'tipe hemat biaya kirim shopee',
|
|
||||||
'shopee_shipping_savings.value' => 'nilai hemat biaya kirim shopee',
|
|
||||||
'shopee_premium.base' => 'dasar premi shopee',
|
|
||||||
'shopee_premium.type' => 'tipe premi shopee',
|
|
||||||
'shopee_premium.value' => 'nilai premi shopee',
|
|
||||||
'shopee_service_fee.base' => 'dasar biaya layanan shopee',
|
|
||||||
'shopee_service_fee.type' => 'tipe biaya layanan shopee',
|
|
||||||
'shopee_service_fee.value' => 'nilai biaya layanan shopee',
|
|
||||||
'shopee_order_processing_fee.base' => 'dasar biaya proses pesanan shopee',
|
|
||||||
'shopee_order_processing_fee.type' => 'tipe biaya proses pesanan shopee',
|
|
||||||
'shopee_order_processing_fee.value' => 'nilai biaya proses pesanan shopee',
|
|
||||||
'shopee_ams_commission_fee.base' => 'dasar biaya komisi ams shopee',
|
|
||||||
'shopee_ams_commission_fee.type' => 'tipe biaya komisi ams shopee',
|
|
||||||
'shopee_ams_commission_fee.value' => 'nilai biaya komisi ams shopee',
|
|
||||||
'shopee_pre_order.base' => 'dasar po shopee',
|
|
||||||
'shopee_pre_order.type' => 'tipe po shopee',
|
|
||||||
'shopee_pre_order.value' => 'nilai po shopee',
|
|
||||||
'shopee_live_extra.base' => 'dasar live extra shopee',
|
|
||||||
'shopee_live_extra.type' => 'tipe live extra shopee',
|
|
||||||
'shopee_live_extra.value' => 'nilai live extra shopee',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -34,13 +34,11 @@ protected function casts(): array
|
|||||||
'price_type' => PriceType::class,
|
'price_type' => PriceType::class,
|
||||||
'status' => OrderStatus::class,
|
'status' => OrderStatus::class,
|
||||||
'payment_type' => PaymentType::class,
|
'payment_type' => PaymentType::class,
|
||||||
'is_affiliate' => 'boolean',
|
|
||||||
'subtotal' => 'integer',
|
'subtotal' => 'integer',
|
||||||
'discount' => 'integer',
|
'discount' => 'integer',
|
||||||
'nego_price' => 'integer',
|
'nego_price' => 'integer',
|
||||||
'total_amount' => 'integer',
|
'total_amount' => 'integer',
|
||||||
'cogs' => 'integer',
|
'cogs' => 'integer',
|
||||||
'marketplace_settings_snapshot' => 'array',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ public function migrate(): array
|
|||||||
{
|
{
|
||||||
$results = [];
|
$results = [];
|
||||||
|
|
||||||
$results['orders'] = $this->migrateTable('orders', function ($row) {
|
$results['orders'] = $this->migrateTableWithoutColumns('orders', ['marketplace_settings_snapshot', 'is_affiliate'], function ($row) {
|
||||||
$row['cogs'] = $row['cogs'] ?? 0;
|
$row['cogs'] = $row['cogs'] ?? 0;
|
||||||
|
|
||||||
$row['price_type'] = match ($row['price_type']) {
|
$row['price_type'] = match ($row['price_type']) {
|
||||||
|
|||||||
@ -5,10 +5,8 @@
|
|||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
use App\Settings\HomepageSettings;
|
use App\Settings\HomepageSettings;
|
||||||
use App\Settings\HRSettings;
|
use App\Settings\HRSettings;
|
||||||
use App\Settings\MarketplaceSettings;
|
|
||||||
use App\Settings\SocialMediaSettings;
|
use App\Settings\SocialMediaSettings;
|
||||||
use App\Settings\SystemSettings;
|
use App\Settings\SystemSettings;
|
||||||
use App\Support\Marketplace\MarketplaceFeeRule;
|
|
||||||
|
|
||||||
class AdminSettingsService
|
class AdminSettingsService
|
||||||
{
|
{
|
||||||
@ -57,33 +55,6 @@ public function getSocialMediaData(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMarketplaceData(): array
|
|
||||||
{
|
|
||||||
$settings = app(MarketplaceSettings::class);
|
|
||||||
|
|
||||||
return [
|
|
||||||
'tiktok_shop' => [
|
|
||||||
'platform_commission' => $settings->tiktok_shop_platform_commission->toArray(),
|
|
||||||
'logistics_service_fee' => $settings->tiktok_shop_logistics_service_fee->toArray(),
|
|
||||||
'dynamic_commission' => $settings->tiktok_shop_dynamic_commission->toArray(),
|
|
||||||
'order_processing_fee' => $settings->tiktok_shop_order_processing_fee->toArray(),
|
|
||||||
'affiliate' => $settings->tiktok_shop_affiliate->toArray(),
|
|
||||||
'pre_order_service_fee' => $settings->tiktok_shop_pre_order_service_fee->toArray(),
|
|
||||||
],
|
|
||||||
'shopee' => [
|
|
||||||
'admin_fee' => $settings->shopee_admin_fee->toArray(),
|
|
||||||
'program_fee' => $settings->shopee_program_fee->toArray(),
|
|
||||||
'shipping_savings' => $settings->shopee_shipping_savings->toArray(),
|
|
||||||
'premium' => $settings->shopee_premium->toArray(),
|
|
||||||
'service_fee' => $settings->shopee_service_fee->toArray(),
|
|
||||||
'order_processing_fee' => $settings->shopee_order_processing_fee->toArray(),
|
|
||||||
'ams_commission_fee' => $settings->shopee_ams_commission_fee->toArray(),
|
|
||||||
'pre_order' => $settings->shopee_pre_order->toArray(),
|
|
||||||
'live_extra' => $settings->shopee_live_extra->toArray(),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHRData(): array
|
public function getHRData(): array
|
||||||
{
|
{
|
||||||
$settings = app(HRSettings::class);
|
$settings = app(HRSettings::class);
|
||||||
@ -121,37 +92,6 @@ public function updateSocialMedia(array $data): void
|
|||||||
$settings->save();
|
$settings->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateMarketplace(array $data): void
|
|
||||||
{
|
|
||||||
$settings = app(MarketplaceSettings::class);
|
|
||||||
|
|
||||||
$feeKeys = [
|
|
||||||
'tiktok_shop_platform_commission',
|
|
||||||
'tiktok_shop_logistics_service_fee',
|
|
||||||
'tiktok_shop_dynamic_commission',
|
|
||||||
'tiktok_shop_order_processing_fee',
|
|
||||||
'tiktok_shop_affiliate',
|
|
||||||
'tiktok_shop_pre_order_service_fee',
|
|
||||||
'shopee_admin_fee',
|
|
||||||
'shopee_program_fee',
|
|
||||||
'shopee_shipping_savings',
|
|
||||||
'shopee_premium',
|
|
||||||
'shopee_service_fee',
|
|
||||||
'shopee_order_processing_fee',
|
|
||||||
'shopee_ams_commission_fee',
|
|
||||||
'shopee_pre_order',
|
|
||||||
'shopee_live_extra',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($feeKeys as $key) {
|
|
||||||
if (isset($data[$key])) {
|
|
||||||
$settings->{$key} = MarketplaceFeeRule::from($data[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$settings->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateHR(array $data): void
|
public function updateHR(array $data): void
|
||||||
{
|
{
|
||||||
$settings = app(HRSettings::class);
|
$settings = app(HRSettings::class);
|
||||||
|
|||||||
@ -189,7 +189,6 @@ public function store(array $data): Order
|
|||||||
'price_type' => $priceType,
|
'price_type' => $priceType,
|
||||||
'status' => ($data['is_completed'] ?? false) ? OrderStatus::COMPLETED : OrderStatus::PENDING,
|
'status' => ($data['is_completed'] ?? false) ? OrderStatus::COMPLETED : OrderStatus::PENDING,
|
||||||
'payment_type' => $paymentType,
|
'payment_type' => $paymentType,
|
||||||
'is_affiliate' => $data['is_affiliate'] ?? false,
|
|
||||||
'tiktok_order_id' => $data['tiktok_order_id'] ?? null,
|
'tiktok_order_id' => $data['tiktok_order_id'] ?? null,
|
||||||
'shopee_order_id' => $data['shopee_order_id'] ?? null,
|
'shopee_order_id' => $data['shopee_order_id'] ?? null,
|
||||||
'subtotal' => $subtotal,
|
'subtotal' => $subtotal,
|
||||||
@ -265,7 +264,6 @@ public function update(Order $order, array $data): Order
|
|||||||
'price_type' => $priceType,
|
'price_type' => $priceType,
|
||||||
'status' => ($data['is_completed'] ?? false) ? OrderStatus::COMPLETED : OrderStatus::PENDING,
|
'status' => ($data['is_completed'] ?? false) ? OrderStatus::COMPLETED : OrderStatus::PENDING,
|
||||||
'payment_type' => $data['payment_type'] ?? $order->payment_type->value,
|
'payment_type' => $data['payment_type'] ?? $order->payment_type->value,
|
||||||
'is_affiliate' => $data['is_affiliate'] ?? false,
|
|
||||||
'tiktok_order_id' => $data['tiktok_order_id'] ?? null,
|
'tiktok_order_id' => $data['tiktok_order_id'] ?? null,
|
||||||
'shopee_order_id' => $data['shopee_order_id'] ?? null,
|
'shopee_order_id' => $data['shopee_order_id'] ?? null,
|
||||||
'subtotal' => $subtotal,
|
'subtotal' => $subtotal,
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Settings;
|
|
||||||
|
|
||||||
use App\Support\Marketplace\MarketplaceFeeRule;
|
|
||||||
use Spatie\LaravelSettings\Settings;
|
|
||||||
|
|
||||||
class MarketplaceSettings extends Settings
|
|
||||||
{
|
|
||||||
public MarketplaceFeeRule $tiktok_shop_platform_commission;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $tiktok_shop_logistics_service_fee;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $tiktok_shop_dynamic_commission;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $tiktok_shop_order_processing_fee;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $tiktok_shop_affiliate;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $tiktok_shop_pre_order_service_fee;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_admin_fee;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_program_fee;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_shipping_savings;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_premium;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_service_fee;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_order_processing_fee;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_ams_commission_fee;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_pre_order;
|
|
||||||
|
|
||||||
public MarketplaceFeeRule $shopee_live_extra;
|
|
||||||
|
|
||||||
public static function group(): string
|
|
||||||
{
|
|
||||||
return 'marketplace';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Support\Marketplace;
|
|
||||||
|
|
||||||
use Spatie\LaravelData\Data;
|
|
||||||
|
|
||||||
class MarketplaceFeeRule extends Data
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
public string $base = 'per_transaksi',
|
|
||||||
public string $type = 'persentase',
|
|
||||||
public float $value = 0.0,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public static function defaultPercent(float $value): static
|
|
||||||
{
|
|
||||||
return new static(
|
|
||||||
base: 'per_transaksi',
|
|
||||||
type: 'persentase',
|
|
||||||
value: $value,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'base' => $this->base,
|
|
||||||
'type' => $this->type,
|
|
||||||
'value' => (float) $this->value,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -21,7 +21,6 @@ public function definition(): array
|
|||||||
'price_type' => fake()->randomElement(['retail', 'wholesale']),
|
'price_type' => fake()->randomElement(['retail', 'wholesale']),
|
||||||
'status' => 'pending',
|
'status' => 'pending',
|
||||||
'payment_type' => fake()->randomElement(['cash', 'transfer', 'marketplace', 'qris']),
|
'payment_type' => fake()->randomElement(['cash', 'transfer', 'marketplace', 'qris']),
|
||||||
'is_affiliate' => false,
|
|
||||||
'subtotal' => $subtotal,
|
'subtotal' => $subtotal,
|
||||||
'discount' => $discount,
|
'discount' => $discount,
|
||||||
'total_amount' => $subtotal - $discount,
|
'total_amount' => $subtotal - $discount,
|
||||||
|
|||||||
@ -25,13 +25,11 @@ public function up(): void
|
|||||||
$table->enum('price_type', PriceType::values());
|
$table->enum('price_type', PriceType::values());
|
||||||
$table->enum('status', OrderStatus::values())->default(OrderStatus::PENDING->value);
|
$table->enum('status', OrderStatus::values())->default(OrderStatus::PENDING->value);
|
||||||
$table->enum('payment_type', PaymentType::values())->default(PaymentType::CASH->value);
|
$table->enum('payment_type', PaymentType::values())->default(PaymentType::CASH->value);
|
||||||
$table->boolean('is_affiliate')->default(false);
|
|
||||||
$table->string('tiktok_order_id', 100)->nullable();
|
$table->string('tiktok_order_id', 100)->nullable();
|
||||||
$table->string('shopee_order_id', 100)->nullable();
|
$table->string('shopee_order_id', 100)->nullable();
|
||||||
$table->unsignedBigInteger('subtotal');
|
$table->unsignedBigInteger('subtotal');
|
||||||
$table->unsignedBigInteger('discount')->default(0);
|
$table->unsignedBigInteger('discount')->default(0);
|
||||||
$table->unsignedBigInteger('nego_price')->nullable();
|
$table->unsignedBigInteger('nego_price')->nullable();
|
||||||
$table->json('marketplace_settings_snapshot')->nullable();
|
|
||||||
$table->unsignedBigInteger('total_amount');
|
$table->unsignedBigInteger('total_amount');
|
||||||
$table->unsignedBigInteger('cogs')->default(0);
|
$table->unsignedBigInteger('cogs')->default(0);
|
||||||
$table->text('notes')->nullable();
|
$table->text('notes')->nullable();
|
||||||
|
|||||||
@ -14,7 +14,7 @@ public function up(): void
|
|||||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||||
|
|
||||||
$table->string('title');
|
$table->string('title');
|
||||||
$table->text('body')->nullable();
|
$table->longText('body')->nullable();
|
||||||
$table->string('url')->nullable();
|
$table->string('url')->nullable();
|
||||||
$table->boolean('is_read')->default(false);
|
$table->boolean('is_read')->default(false);
|
||||||
$table->timestamp('read_at')->nullable();
|
$table->timestamp('read_at')->nullable();
|
||||||
|
|||||||
@ -36,7 +36,7 @@ public function run(): void
|
|||||||
'purchases' => ['view', 'create', 'update', 'delete'],
|
'purchases' => ['view', 'create', 'update', 'delete'],
|
||||||
'stok_opnames' => ['view', 'create', 'update', 'delete', 'submit', 'verify'],
|
'stok_opnames' => ['view', 'create', 'update', 'delete', 'submit', 'verify'],
|
||||||
'roles' => ['view', 'create', 'update', 'delete'],
|
'roles' => ['view', 'create', 'update', 'delete'],
|
||||||
'settings' => ['view_system', 'update_system', 'view_homepage', 'update_homepage', 'view_social_media', 'update_social_media', 'view_marketplace', 'update_marketplace', 'view_hr', 'update_hr'],
|
'settings' => ['view_system', 'update_system', 'view_homepage', 'update_homepage', 'view_social_media', 'update_social_media', 'view_hr', 'update_hr'],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($permissions as $module => $actions) {
|
foreach ($permissions as $module => $actions) {
|
||||||
@ -166,8 +166,6 @@ public function run(): void
|
|||||||
'settings.update_system',
|
'settings.update_system',
|
||||||
'settings.view_social_media',
|
'settings.view_social_media',
|
||||||
'settings.update_social_media',
|
'settings.update_social_media',
|
||||||
'settings.view_marketplace',
|
|
||||||
'settings.update_marketplace',
|
|
||||||
'settings.view_hr',
|
'settings.view_hr',
|
||||||
'settings.update_hr',
|
'settings.update_hr',
|
||||||
'settings.view_homepage',
|
'settings.view_homepage',
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Support\Marketplace\MarketplaceFeeRule;
|
|
||||||
use Spatie\LaravelSettings\Migrations\SettingsBlueprint;
|
use Spatie\LaravelSettings\Migrations\SettingsBlueprint;
|
||||||
use Spatie\LaravelSettings\Migrations\SettingsMigration;
|
use Spatie\LaravelSettings\Migrations\SettingsMigration;
|
||||||
|
|
||||||
@ -22,27 +21,6 @@ public function up(): void
|
|||||||
$blueprint->add('tiktok_url', null);
|
$blueprint->add('tiktok_url', null);
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->migrator->inGroup('marketplace', function (SettingsBlueprint $blueprint): void {
|
|
||||||
// TikTok Shop
|
|
||||||
$blueprint->add('tiktok_shop_platform_commission', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('tiktok_shop_logistics_service_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('tiktok_shop_dynamic_commission', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('tiktok_shop_order_processing_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('tiktok_shop_affiliate', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('tiktok_shop_pre_order_service_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
|
|
||||||
// Shopee
|
|
||||||
$blueprint->add('shopee_admin_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('shopee_program_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('shopee_shipping_savings', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('shopee_premium', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('shopee_service_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('shopee_order_processing_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('shopee_ams_commission_fee', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('shopee_pre_order', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
$blueprint->add('shopee_live_extra', MarketplaceFeeRule::defaultPercent(0.0)->toArray());
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->migrator->inGroup('hr', function (SettingsBlueprint $blueprint): void {
|
$this->migrator->inGroup('hr', function (SettingsBlueprint $blueprint): void {
|
||||||
$blueprint->add('scheduled_check_in_time', '08:00');
|
$blueprint->add('scheduled_check_in_time', '08:00');
|
||||||
$blueprint->add('scheduled_check_out_time', '17:00');
|
$blueprint->add('scheduled_check_out_time', '17:00');
|
||||||
|
|||||||
@ -103,7 +103,7 @@ const hrItems: NavMenuItem[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const sistemItems: NavMenuItem[] = [
|
const sistemItems: NavMenuItem[] = [
|
||||||
{ title: 'Pengaturan', href: '/admin/settings', icon: Settings, permission: ['settings.view_system', 'settings.view_homepage', 'settings.view_social_media', 'settings.view_marketplace', 'settings.view_hr'] },
|
{ title: 'Pengaturan', href: '/admin/settings', icon: Settings, permission: ['settings.view_system', 'settings.view_homepage', 'settings.view_social_media', 'settings.view_hr'] },
|
||||||
{ title: 'Role & Permission', href: rolesIndex.url(), icon: Shield, permission: 'roles.view' },
|
{ title: 'Role & Permission', href: rolesIndex.url(), icon: Shield, permission: 'roles.view' },
|
||||||
// { title: 'Log Aktivitas', href: '#', icon: Activity, permission: 'activity_logs.view' },
|
// { title: 'Log Aktivitas', href: '#', icon: Activity, permission: 'activity_logs.view' },
|
||||||
];
|
];
|
||||||
|
|||||||
@ -84,7 +84,6 @@ export type TransactionForEdit = {
|
|||||||
discount: number;
|
discount: number;
|
||||||
nego_price: number | null;
|
nego_price: number | null;
|
||||||
is_completed: boolean;
|
is_completed: boolean;
|
||||||
is_affiliate: boolean;
|
|
||||||
tiktok_order_id: string | null;
|
tiktok_order_id: string | null;
|
||||||
shopee_order_id: string | null;
|
shopee_order_id: string | null;
|
||||||
notes: string | null;
|
notes: string | null;
|
||||||
|
|||||||
@ -94,7 +94,6 @@ export default function TransactionCreate({
|
|||||||
const [discount, setDiscount] = useState(draft?.discount ?? 0);
|
const [discount, setDiscount] = useState(draft?.discount ?? 0);
|
||||||
const [negoPrice, setNegoPrice] = useState<number | null>(draft?.negoPrice ?? null);
|
const [negoPrice, setNegoPrice] = useState<number | null>(draft?.negoPrice ?? null);
|
||||||
const [isCompleted, setIsCompleted] = useState(draft?.isCompleted ?? false);
|
const [isCompleted, setIsCompleted] = useState(draft?.isCompleted ?? false);
|
||||||
const [isAffiliate, setIsAffiliate] = useState(draft?.isAffiliate ?? false);
|
|
||||||
const [notes, setNotes] = useState(draft?.notes ?? '');
|
const [notes, setNotes] = useState(draft?.notes ?? '');
|
||||||
const [photo, setPhoto] = useState<string | null>(draft?.photo ?? null);
|
const [photo, setPhoto] = useState<string | null>(draft?.photo ?? null);
|
||||||
const [photoUrl, setPhotoUrl] = useState<string | null>(
|
const [photoUrl, setPhotoUrl] = useState<string | null>(
|
||||||
@ -133,7 +132,6 @@ export default function TransactionCreate({
|
|||||||
discount,
|
discount,
|
||||||
negoPrice,
|
negoPrice,
|
||||||
isCompleted,
|
isCompleted,
|
||||||
isAffiliate,
|
|
||||||
tiktokOrderId: channel === 'tiktok' ? tiktokOrderId : '',
|
tiktokOrderId: channel === 'tiktok' ? tiktokOrderId : '',
|
||||||
shopeeOrderId: channel === 'shopee' ? shopeeOrderId : '',
|
shopeeOrderId: channel === 'shopee' ? shopeeOrderId : '',
|
||||||
selectedProductId,
|
selectedProductId,
|
||||||
@ -149,7 +147,7 @@ export default function TransactionCreate({
|
|||||||
[
|
[
|
||||||
stockType, channel, priceType, paymentType,
|
stockType, channel, priceType, paymentType,
|
||||||
customerId, marketingId, discount, negoPrice,
|
customerId, marketingId, discount, negoPrice,
|
||||||
isCompleted, isAffiliate, tiktokOrderId, shopeeOrderId,
|
isCompleted, tiktokOrderId, shopeeOrderId,
|
||||||
selectedProductId, quantities, notes, photo,
|
selectedProductId, quantities, notes, photo,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -293,7 +291,6 @@ export default function TransactionCreate({
|
|||||||
discount,
|
discount,
|
||||||
nego_price: negoPrice,
|
nego_price: negoPrice,
|
||||||
is_completed: isCompleted,
|
is_completed: isCompleted,
|
||||||
is_affiliate: isAffiliate,
|
|
||||||
tiktok_order_id: channel === 'tiktok' ? tiktokOrderId || null : null,
|
tiktok_order_id: channel === 'tiktok' ? tiktokOrderId || null : null,
|
||||||
shopee_order_id: channel === 'shopee' ? shopeeOrderId || null : null,
|
shopee_order_id: channel === 'shopee' ? shopeeOrderId || null : null,
|
||||||
items: Object.entries(quantitiesRef.current)
|
items: Object.entries(quantitiesRef.current)
|
||||||
@ -853,17 +850,6 @@ export default function TransactionCreate({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<Label htmlFor="is_affiliate">
|
|
||||||
Affiliasi
|
|
||||||
</Label>
|
|
||||||
<Switch
|
|
||||||
id="is_affiliate"
|
|
||||||
checked={isAffiliate}
|
|
||||||
onCheckedChange={setIsAffiliate}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label htmlFor="notes">
|
<Label htmlFor="notes">
|
||||||
Keterangan
|
Keterangan
|
||||||
|
|||||||
@ -90,7 +90,6 @@ export default function TransactionEdit({
|
|||||||
const [discount, setDiscount] = useState(transaction.discount);
|
const [discount, setDiscount] = useState(transaction.discount);
|
||||||
const [negoPrice, setNegoPrice] = useState<number | null>(transaction.nego_price);
|
const [negoPrice, setNegoPrice] = useState<number | null>(transaction.nego_price);
|
||||||
const [isCompleted, setIsCompleted] = useState(transaction.is_completed);
|
const [isCompleted, setIsCompleted] = useState(transaction.is_completed);
|
||||||
const [isAffiliate, setIsAffiliate] = useState(transaction.is_affiliate);
|
|
||||||
const [notes, setNotes] = useState(transaction.notes ?? '');
|
const [notes, setNotes] = useState(transaction.notes ?? '');
|
||||||
const [photo, setPhoto] = useState<string | null>(transaction.photo_key);
|
const [photo, setPhoto] = useState<string | null>(transaction.photo_key);
|
||||||
const [photoUrl, setPhotoUrl] = useState<string | null>(transaction.photo_url);
|
const [photoUrl, setPhotoUrl] = useState<string | null>(transaction.photo_url);
|
||||||
@ -263,7 +262,6 @@ export default function TransactionEdit({
|
|||||||
discount,
|
discount,
|
||||||
nego_price: negoPrice,
|
nego_price: negoPrice,
|
||||||
is_completed: isCompleted,
|
is_completed: isCompleted,
|
||||||
is_affiliate: isAffiliate,
|
|
||||||
tiktok_order_id: channel === 'tiktok' ? tiktokOrderId || null : null,
|
tiktok_order_id: channel === 'tiktok' ? tiktokOrderId || null : null,
|
||||||
shopee_order_id: channel === 'shopee' ? shopeeOrderId || null : null,
|
shopee_order_id: channel === 'shopee' ? shopeeOrderId || null : null,
|
||||||
items: Object.entries(quantitiesRef.current)
|
items: Object.entries(quantitiesRef.current)
|
||||||
@ -832,17 +830,6 @@ export default function TransactionEdit({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<Label htmlFor="edit-is_affiliate">
|
|
||||||
Affiliasi
|
|
||||||
</Label>
|
|
||||||
<Switch
|
|
||||||
id="edit-is_affiliate"
|
|
||||||
checked={isAffiliate}
|
|
||||||
onCheckedChange={setIsAffiliate}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label htmlFor="edit-notes">
|
<Label htmlFor="edit-notes">
|
||||||
Keterangan
|
Keterangan
|
||||||
|
|||||||
@ -54,7 +54,6 @@ const actionLabels: Record<string, string> = {
|
|||||||
'update-system': 'Update Sistem',
|
'update-system': 'Update Sistem',
|
||||||
'update-homepage': 'Update Homepage',
|
'update-homepage': 'Update Homepage',
|
||||||
'update-social-media': 'Update Media Sosial',
|
'update-social-media': 'Update Media Sosial',
|
||||||
'update-marketplace': 'Update Marketplace',
|
|
||||||
'update-hr': 'Update HR',
|
'update-hr': 'Update HR',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -64,7 +64,6 @@ const actionLabels: Record<string, string> = {
|
|||||||
'update-system': 'Update Sistem',
|
'update-system': 'Update Sistem',
|
||||||
'update-homepage': 'Update Homepage',
|
'update-homepage': 'Update Homepage',
|
||||||
'update-social-media': 'Update Media Sosial',
|
'update-social-media': 'Update Media Sosial',
|
||||||
'update-marketplace': 'Update Marketplace',
|
|
||||||
'update-hr': 'Update HR',
|
'update-hr': 'Update HR',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -10,25 +10,16 @@ import { Button } from '@/components/ui/button';
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import {
|
import {
|
||||||
updateHomepage,
|
updateHomepage,
|
||||||
updateHr,
|
updateHr,
|
||||||
updateMarketplace,
|
|
||||||
updateSocialMedia,
|
updateSocialMedia,
|
||||||
updateSystem,
|
updateSystem,
|
||||||
} from '@/routes/admin/settings';
|
} from '@/routes/admin/settings';
|
||||||
|
|
||||||
type MarketplaceFeeRule = {
|
|
||||||
base: string;
|
|
||||||
type: string;
|
|
||||||
value: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
system: {
|
system: {
|
||||||
app_name: string;
|
app_name: string;
|
||||||
@ -50,10 +41,6 @@ type Props = {
|
|||||||
facebook_url: string;
|
facebook_url: string;
|
||||||
tiktok_url: string;
|
tiktok_url: string;
|
||||||
};
|
};
|
||||||
marketplace: {
|
|
||||||
tiktok_shop: Record<string, MarketplaceFeeRule>;
|
|
||||||
shopee: Record<string, MarketplaceFeeRule>;
|
|
||||||
};
|
|
||||||
hr: {
|
hr: {
|
||||||
scheduled_check_in_time: string;
|
scheduled_check_in_time: string;
|
||||||
scheduled_check_out_time: string;
|
scheduled_check_out_time: string;
|
||||||
@ -240,252 +227,18 @@ const sidebarTabs = [
|
|||||||
{ key: 'sistem', label: 'Sistem' },
|
{ key: 'sistem', label: 'Sistem' },
|
||||||
{ key: 'homepage', label: 'Homepage' },
|
{ key: 'homepage', label: 'Homepage' },
|
||||||
{ key: 'media-sosial', label: 'Media Sosial' },
|
{ key: 'media-sosial', label: 'Media Sosial' },
|
||||||
{ key: 'marketplace', label: 'Marketplace' },
|
|
||||||
{ key: 'hr', label: 'HR' },
|
{ key: 'hr', label: 'HR' },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
type TabKey = (typeof sidebarTabs)[number]['key'];
|
type TabKey = (typeof sidebarTabs)[number]['key'];
|
||||||
|
|
||||||
function MarketplaceVariableInput({
|
|
||||||
label,
|
|
||||||
prefix,
|
|
||||||
data,
|
|
||||||
}: {
|
|
||||||
label: string;
|
|
||||||
prefix: string;
|
|
||||||
data: MarketplaceFeeRule;
|
|
||||||
}) {
|
|
||||||
const [type, setType] = useState(data.type);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col gap-3 rounded-md border p-3 md:flex-row md:items-start md:gap-4">
|
|
||||||
<span className="min-w-[160px] text-sm font-medium md:pt-2">
|
|
||||||
{label}
|
|
||||||
</span>
|
|
||||||
<div className="grid flex-1 grid-cols-1 gap-3 md:grid-cols-3">
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<span className="text-xs font-medium text-muted-foreground md:hidden">
|
|
||||||
Dasar
|
|
||||||
</span>
|
|
||||||
<RadioGroup
|
|
||||||
name={`${prefix}[base]`}
|
|
||||||
defaultValue={data.base}
|
|
||||||
className="flex gap-4"
|
|
||||||
>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem
|
|
||||||
value="per_transaksi"
|
|
||||||
id={`${prefix}-base-per_transaksi`}
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
htmlFor={`${prefix}-base-per_transaksi`}
|
|
||||||
className="text-xs font-normal"
|
|
||||||
>
|
|
||||||
Per Transaksi
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem
|
|
||||||
value="per_produk"
|
|
||||||
id={`${prefix}-base-per_produk`}
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
htmlFor={`${prefix}-base-per_produk`}
|
|
||||||
className="text-xs font-normal"
|
|
||||||
>
|
|
||||||
Per Produk
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
</RadioGroup>
|
|
||||||
</div>
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<span className="text-xs font-medium text-muted-foreground md:hidden">
|
|
||||||
Tipe
|
|
||||||
</span>
|
|
||||||
<RadioGroup
|
|
||||||
name={`${prefix}[type]`}
|
|
||||||
defaultValue={data.type}
|
|
||||||
onValueChange={setType}
|
|
||||||
className="flex gap-4"
|
|
||||||
>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem
|
|
||||||
value="flat"
|
|
||||||
id={`${prefix}-type-flat`}
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
htmlFor={`${prefix}-type-flat`}
|
|
||||||
className="text-xs font-normal"
|
|
||||||
>
|
|
||||||
Flat
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<RadioGroupItem
|
|
||||||
value="persentase"
|
|
||||||
id={`${prefix}-type-persentase`}
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
htmlFor={`${prefix}-type-persentase`}
|
|
||||||
className="text-xs font-normal"
|
|
||||||
>
|
|
||||||
Persentase
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
</RadioGroup>
|
|
||||||
</div>
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<span className="text-xs font-medium text-muted-foreground md:hidden">
|
|
||||||
Nilai
|
|
||||||
</span>
|
|
||||||
{type === 'flat' ? (
|
|
||||||
<RupiahInput
|
|
||||||
name={`${prefix}[value]`}
|
|
||||||
defaultValue={data.value}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Input
|
|
||||||
name={`${prefix}[value]`}
|
|
||||||
type="number"
|
|
||||||
step="0.01"
|
|
||||||
min="0"
|
|
||||||
defaultValue={data.value}
|
|
||||||
placeholder="0"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function MarketplaceColumnHeader() {
|
|
||||||
return (
|
|
||||||
<div className="hidden gap-3 px-3 pb-1 text-xs font-medium text-muted-foreground md:grid md:grid-cols-[160px_1fr] md:gap-4">
|
|
||||||
<span>Biaya</span>
|
|
||||||
<div className="grid flex-1 grid-cols-3 gap-3">
|
|
||||||
<span>Dasar</span>
|
|
||||||
<span>Tipe</span>
|
|
||||||
<span>Nilai</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function MarketplaceCard({
|
|
||||||
title,
|
|
||||||
variables,
|
|
||||||
}: {
|
|
||||||
title: string;
|
|
||||||
variables: { label: string; prefix: string; data: MarketplaceFeeRule }[];
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardHeader className="pb-3">
|
|
||||||
<CardTitle className="text-base">{title}</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="grid grid-cols-1 gap-2">
|
|
||||||
<MarketplaceColumnHeader />
|
|
||||||
{variables.map((v) => (
|
|
||||||
<MarketplaceVariableInput key={v.prefix} {...v} />
|
|
||||||
))}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AdminSettings({
|
export default function AdminSettings({
|
||||||
system,
|
system,
|
||||||
homepage,
|
homepage,
|
||||||
socialMedia,
|
socialMedia,
|
||||||
marketplace,
|
|
||||||
hr,
|
hr,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [activeTab, setActiveTab] = useState<TabKey>('sistem');
|
const [activeTab, setActiveTab] = useState<TabKey>('sistem');
|
||||||
const [marketplaceTab, setMarketplaceTab] = useState<
|
|
||||||
'tiktok-shop' | 'shopee'
|
|
||||||
>('tiktok-shop');
|
|
||||||
|
|
||||||
const tiktokShopVariables = [
|
|
||||||
{
|
|
||||||
label: 'Komisi Platform',
|
|
||||||
prefix: 'tiktok_shop_platform_commission',
|
|
||||||
data: marketplace.tiktok_shop.platform_commission,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Layanan Logistik',
|
|
||||||
prefix: 'tiktok_shop_logistics_service_fee',
|
|
||||||
data: marketplace.tiktok_shop.logistics_service_fee,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Komisi Dinamis',
|
|
||||||
prefix: 'tiktok_shop_dynamic_commission',
|
|
||||||
data: marketplace.tiktok_shop.dynamic_commission,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Pemrosesan Pesanan',
|
|
||||||
prefix: 'tiktok_shop_order_processing_fee',
|
|
||||||
data: marketplace.tiktok_shop.order_processing_fee,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Affiliate',
|
|
||||||
prefix: 'tiktok_shop_affiliate',
|
|
||||||
data: marketplace.tiktok_shop.affiliate,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Layanan PO',
|
|
||||||
prefix: 'tiktok_shop_pre_order_service_fee',
|
|
||||||
data: marketplace.tiktok_shop.pre_order_service_fee,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const shopeeVariables = [
|
|
||||||
{
|
|
||||||
label: 'Biaya Administrasi',
|
|
||||||
prefix: 'shopee_admin_fee',
|
|
||||||
data: marketplace.shopee.admin_fee,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Biaya Program',
|
|
||||||
prefix: 'shopee_program_fee',
|
|
||||||
data: marketplace.shopee.program_fee,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Hemat Biaya Kirim',
|
|
||||||
prefix: 'shopee_shipping_savings',
|
|
||||||
data: marketplace.shopee.shipping_savings,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Premi',
|
|
||||||
prefix: 'shopee_premium',
|
|
||||||
data: marketplace.shopee.premium,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Biaya Layanan',
|
|
||||||
prefix: 'shopee_service_fee',
|
|
||||||
data: marketplace.shopee.service_fee,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Biaya Proses Pesanan',
|
|
||||||
prefix: 'shopee_order_processing_fee',
|
|
||||||
data: marketplace.shopee.order_processing_fee,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Biaya Komisi AMS',
|
|
||||||
prefix: 'shopee_ams_commission_fee',
|
|
||||||
data: marketplace.shopee.ams_commission_fee,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'PO',
|
|
||||||
prefix: 'shopee_pre_order',
|
|
||||||
data: marketplace.shopee.pre_order,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Live Extra',
|
|
||||||
prefix: 'shopee_live_extra',
|
|
||||||
data: marketplace.shopee.live_extra,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -740,68 +493,6 @@ export default function AdminSettings({
|
|||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{activeTab === 'marketplace' && (
|
|
||||||
<Form
|
|
||||||
action={updateMarketplace()}
|
|
||||||
options={{ preserveScroll: true }}
|
|
||||||
onError={() => {
|
|
||||||
toast.error('Ada data yang belum sesuai, silakan periksa kembali input Anda.');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ processing }) => (
|
|
||||||
<div className="grid gap-6">
|
|
||||||
<Tabs
|
|
||||||
value={marketplaceTab}
|
|
||||||
onValueChange={(v) =>
|
|
||||||
setMarketplaceTab(
|
|
||||||
v as
|
|
||||||
| 'tiktok-shop'
|
|
||||||
| 'shopee',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<TabsList className="mb-3">
|
|
||||||
<TabsTrigger value="tiktok-shop">
|
|
||||||
TikTok Shop
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="shopee">
|
|
||||||
Shopee
|
|
||||||
</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
</Tabs>
|
|
||||||
<div
|
|
||||||
hidden={
|
|
||||||
marketplaceTab !== 'tiktok-shop'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MarketplaceCard
|
|
||||||
title="TikTok Shop"
|
|
||||||
variables={tiktokShopVariables}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
hidden={marketplaceTab !== 'shopee'}
|
|
||||||
>
|
|
||||||
<MarketplaceCard
|
|
||||||
title="Shopee"
|
|
||||||
variables={shopeeVariables}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
disabled={processing}
|
|
||||||
>
|
|
||||||
{processing
|
|
||||||
? 'Menyimpan...'
|
|
||||||
: 'Simpan'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{activeTab === 'hr' && (
|
{activeTab === 'hr' && (
|
||||||
<Form
|
<Form
|
||||||
action={updateHr()}
|
action={updateHr()}
|
||||||
|
|||||||
@ -116,11 +116,10 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
Route::prefix('settings')->name('admin.settings.')->group(function () {
|
Route::prefix('settings')->name('admin.settings.')->group(function () {
|
||||||
Route::get('/', [AdminSettingsController::class, 'index'])->name('index')->middleware('permission:settings.view_system|settings.view_homepage|settings.view_social_media|settings.view_marketplace|settings.view_hr');
|
Route::get('/', [AdminSettingsController::class, 'index'])->name('index')->middleware('permission:settings.view_system|settings.view_homepage|settings.view_social_media|settings.view_hr');
|
||||||
Route::put('system', [AdminSettingsController::class, 'updateSystem'])->name('update-system')->middleware('permission:settings.update_system');
|
Route::put('system', [AdminSettingsController::class, 'updateSystem'])->name('update-system')->middleware('permission:settings.update_system');
|
||||||
Route::put('homepage', [AdminSettingsController::class, 'updateHomepage'])->name('update-homepage')->middleware('permission:settings.update_homepage');
|
Route::put('homepage', [AdminSettingsController::class, 'updateHomepage'])->name('update-homepage')->middleware('permission:settings.update_homepage');
|
||||||
Route::put('social-media', [AdminSettingsController::class, 'updateSocialMedia'])->name('update-social-media')->middleware('permission:settings.update_social_media');
|
Route::put('social-media', [AdminSettingsController::class, 'updateSocialMedia'])->name('update-social-media')->middleware('permission:settings.update_social_media');
|
||||||
Route::put('marketplace', [AdminSettingsController::class, 'updateMarketplace'])->name('update-marketplace')->middleware('permission:settings.update_marketplace');
|
|
||||||
Route::put('hr', [AdminSettingsController::class, 'updateHR'])->name('update-hr')->middleware('permission:settings.update_hr');
|
Route::put('hr', [AdminSettingsController::class, 'updateHR'])->name('update-hr')->middleware('permission:settings.update_hr');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,8 @@
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Settings\HomepageSettings;
|
use App\Settings\HomepageSettings;
|
||||||
use App\Settings\HRSettings;
|
use App\Settings\HRSettings;
|
||||||
use App\Settings\MarketplaceSettings;
|
|
||||||
use App\Settings\SocialMediaSettings;
|
use App\Settings\SocialMediaSettings;
|
||||||
use App\Settings\SystemSettings;
|
use App\Settings\SystemSettings;
|
||||||
use App\Support\Marketplace\MarketplaceFeeRule;
|
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
use Inertia\Testing\AssertableInertia as Assert;
|
use Inertia\Testing\AssertableInertia as Assert;
|
||||||
|
|
||||||
@ -44,13 +42,6 @@
|
|||||||
$response->assertRedirect(route('login'));
|
$response->assertRedirect(route('login'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('guest cannot update marketplace settings', function () {
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 100],
|
|
||||||
]);
|
|
||||||
$response->assertRedirect(route('login'));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('guest cannot update hr settings', function () {
|
test('guest cannot update hr settings', function () {
|
||||||
$response = $this->put(route('admin.settings.update-hr'), [
|
$response = $this->put(route('admin.settings.update-hr'), [
|
||||||
'scheduled_check_in_time' => '09:00',
|
'scheduled_check_in_time' => '09:00',
|
||||||
@ -82,7 +73,6 @@
|
|||||||
->has('system')
|
->has('system')
|
||||||
->has('homepage')
|
->has('homepage')
|
||||||
->has('socialMedia')
|
->has('socialMedia')
|
||||||
->has('marketplace')
|
|
||||||
->has('hr')
|
->has('hr')
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -101,21 +91,6 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('settings page contains marketplace data', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$marketplace = app(MarketplaceSettings::class);
|
|
||||||
|
|
||||||
$response = $this->get(route('admin.settings.index'));
|
|
||||||
$response->assertInertia(fn (Assert $page) => $page
|
|
||||||
->where('marketplace.tiktok_shop.platform_commission.base', $marketplace->tiktok_shop_platform_commission->base)
|
|
||||||
->where('marketplace.tiktok_shop.platform_commission.type', $marketplace->tiktok_shop_platform_commission->type)
|
|
||||||
->where('marketplace.tiktok_shop.platform_commission.value', json_decode(json_encode($marketplace->tiktok_shop_platform_commission->value)))
|
|
||||||
->where('marketplace.shopee.admin_fee.base', $marketplace->shopee_admin_fee->base)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('settings page contains hr data', function () {
|
test('settings page contains hr data', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@ -389,243 +364,6 @@
|
|||||||
$response->assertSessionHasErrors('tiktok_url');
|
$response->assertSessionHasErrors('tiktok_url');
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| UPDATE MARKETPLACE
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
test('user can update marketplace settings with valid data', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$feeRule = ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 5000];
|
|
||||||
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => $feeRule,
|
|
||||||
'tiktok_shop_logistics_service_fee' => $feeRule,
|
|
||||||
'tiktok_shop_dynamic_commission' => $feeRule,
|
|
||||||
'tiktok_shop_order_processing_fee' => $feeRule,
|
|
||||||
'tiktok_shop_affiliate' => $feeRule,
|
|
||||||
'tiktok_shop_pre_order_service_fee' => $feeRule,
|
|
||||||
'shopee_admin_fee' => $feeRule,
|
|
||||||
'shopee_program_fee' => $feeRule,
|
|
||||||
'shopee_shipping_savings' => $feeRule,
|
|
||||||
'shopee_premium' => $feeRule,
|
|
||||||
'shopee_service_fee' => $feeRule,
|
|
||||||
'shopee_order_processing_fee' => $feeRule,
|
|
||||||
'shopee_ams_commission_fee' => $feeRule,
|
|
||||||
'shopee_pre_order' => $feeRule,
|
|
||||||
'shopee_live_extra' => $feeRule,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response
|
|
||||||
->assertSessionHasNoErrors()
|
|
||||||
->assertRedirect(route('admin.settings.index'));
|
|
||||||
|
|
||||||
$settings = app(MarketplaceSettings::class);
|
|
||||||
expect($settings->tiktok_shop_platform_commission->base)->toBe('per_transaksi');
|
|
||||||
expect($settings->tiktok_shop_platform_commission->type)->toBe('flat');
|
|
||||||
expect($settings->tiktok_shop_platform_commission->value)->toBe(5000.0);
|
|
||||||
expect($settings->shopee_admin_fee->base)->toBe('per_transaksi');
|
|
||||||
expect($settings->shopee_admin_fee->type)->toBe('flat');
|
|
||||||
expect($settings->shopee_admin_fee->value)->toBe(5000.0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('marketplace accepts percentage type', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$feeRule = ['base' => 'per_produk', 'type' => 'persentase', 'value' => 2.5];
|
|
||||||
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => $feeRule,
|
|
||||||
'tiktok_shop_logistics_service_fee' => $feeRule,
|
|
||||||
'tiktok_shop_dynamic_commission' => $feeRule,
|
|
||||||
'tiktok_shop_order_processing_fee' => $feeRule,
|
|
||||||
'tiktok_shop_affiliate' => $feeRule,
|
|
||||||
'tiktok_shop_pre_order_service_fee' => $feeRule,
|
|
||||||
'shopee_admin_fee' => $feeRule,
|
|
||||||
'shopee_program_fee' => $feeRule,
|
|
||||||
'shopee_shipping_savings' => $feeRule,
|
|
||||||
'shopee_premium' => $feeRule,
|
|
||||||
'shopee_service_fee' => $feeRule,
|
|
||||||
'shopee_order_processing_fee' => $feeRule,
|
|
||||||
'shopee_ams_commission_fee' => $feeRule,
|
|
||||||
'shopee_pre_order' => $feeRule,
|
|
||||||
'shopee_live_extra' => $feeRule,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response->assertSessionHasNoErrors();
|
|
||||||
|
|
||||||
$settings = app(MarketplaceSettings::class);
|
|
||||||
expect($settings->tiktok_shop_platform_commission->base)->toBe('per_produk');
|
|
||||||
expect($settings->tiktok_shop_platform_commission->type)->toBe('persentase');
|
|
||||||
expect($settings->tiktok_shop_platform_commission->value)->toBe(2.5);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('marketplace base field must be valid', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$feeRule = ['base' => 'invalid', 'type' => 'flat', 'value' => 0];
|
|
||||||
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => $feeRule,
|
|
||||||
'tiktok_shop_logistics_service_fee' => $feeRule,
|
|
||||||
'tiktok_shop_dynamic_commission' => $feeRule,
|
|
||||||
'tiktok_shop_order_processing_fee' => $feeRule,
|
|
||||||
'tiktok_shop_affiliate' => $feeRule,
|
|
||||||
'tiktok_shop_pre_order_service_fee' => $feeRule,
|
|
||||||
'shopee_admin_fee' => $feeRule,
|
|
||||||
'shopee_program_fee' => $feeRule,
|
|
||||||
'shopee_shipping_savings' => $feeRule,
|
|
||||||
'shopee_premium' => $feeRule,
|
|
||||||
'shopee_service_fee' => $feeRule,
|
|
||||||
'shopee_order_processing_fee' => $feeRule,
|
|
||||||
'shopee_ams_commission_fee' => $feeRule,
|
|
||||||
'shopee_pre_order' => $feeRule,
|
|
||||||
'shopee_live_extra' => $feeRule,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response->assertSessionHasErrors('tiktok_shop_platform_commission.base');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('marketplace type field must be valid', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$feeRule = ['base' => 'per_transaksi', 'type' => 'invalid', 'value' => 0];
|
|
||||||
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => $feeRule,
|
|
||||||
'tiktok_shop_logistics_service_fee' => $feeRule,
|
|
||||||
'tiktok_shop_dynamic_commission' => $feeRule,
|
|
||||||
'tiktok_shop_order_processing_fee' => $feeRule,
|
|
||||||
'tiktok_shop_affiliate' => $feeRule,
|
|
||||||
'tiktok_shop_pre_order_service_fee' => $feeRule,
|
|
||||||
'shopee_admin_fee' => $feeRule,
|
|
||||||
'shopee_program_fee' => $feeRule,
|
|
||||||
'shopee_shipping_savings' => $feeRule,
|
|
||||||
'shopee_premium' => $feeRule,
|
|
||||||
'shopee_service_fee' => $feeRule,
|
|
||||||
'shopee_order_processing_fee' => $feeRule,
|
|
||||||
'shopee_ams_commission_fee' => $feeRule,
|
|
||||||
'shopee_pre_order' => $feeRule,
|
|
||||||
'shopee_live_extra' => $feeRule,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response->assertSessionHasErrors('tiktok_shop_platform_commission.type');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('marketplace value must be numeric', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$feeRule = ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 'not-a-number'];
|
|
||||||
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => $feeRule,
|
|
||||||
'tiktok_shop_logistics_service_fee' => $feeRule,
|
|
||||||
'tiktok_shop_dynamic_commission' => $feeRule,
|
|
||||||
'tiktok_shop_order_processing_fee' => $feeRule,
|
|
||||||
'tiktok_shop_affiliate' => $feeRule,
|
|
||||||
'tiktok_shop_pre_order_service_fee' => $feeRule,
|
|
||||||
'shopee_admin_fee' => $feeRule,
|
|
||||||
'shopee_program_fee' => $feeRule,
|
|
||||||
'shopee_shipping_savings' => $feeRule,
|
|
||||||
'shopee_premium' => $feeRule,
|
|
||||||
'shopee_service_fee' => $feeRule,
|
|
||||||
'shopee_order_processing_fee' => $feeRule,
|
|
||||||
'shopee_ams_commission_fee' => $feeRule,
|
|
||||||
'shopee_pre_order' => $feeRule,
|
|
||||||
'shopee_live_extra' => $feeRule,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response->assertSessionHasErrors('tiktok_shop_platform_commission.value');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('marketplace value must be at least 0', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$feeRule = ['base' => 'per_transaksi', 'type' => 'flat', 'value' => -1];
|
|
||||||
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => $feeRule,
|
|
||||||
'tiktok_shop_logistics_service_fee' => $feeRule,
|
|
||||||
'tiktok_shop_dynamic_commission' => $feeRule,
|
|
||||||
'tiktok_shop_order_processing_fee' => $feeRule,
|
|
||||||
'tiktok_shop_affiliate' => $feeRule,
|
|
||||||
'tiktok_shop_pre_order_service_fee' => $feeRule,
|
|
||||||
'shopee_admin_fee' => $feeRule,
|
|
||||||
'shopee_program_fee' => $feeRule,
|
|
||||||
'shopee_shipping_savings' => $feeRule,
|
|
||||||
'shopee_premium' => $feeRule,
|
|
||||||
'shopee_service_fee' => $feeRule,
|
|
||||||
'shopee_order_processing_fee' => $feeRule,
|
|
||||||
'shopee_ams_commission_fee' => $feeRule,
|
|
||||||
'shopee_pre_order' => $feeRule,
|
|
||||||
'shopee_live_extra' => $feeRule,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response->assertSessionHasErrors('tiktok_shop_platform_commission.value');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('marketplace fee rule array is required', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => 'not-an-array',
|
|
||||||
'tiktok_shop_logistics_service_fee' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'tiktok_shop_dynamic_commission' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'tiktok_shop_order_processing_fee' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'tiktok_shop_affiliate' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'tiktok_shop_pre_order_service_fee' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_admin_fee' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_program_fee' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_shipping_savings' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_premium' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_service_fee' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_order_processing_fee' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_ams_commission_fee' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_pre_order' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
'shopee_live_extra' => ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response->assertSessionHasErrors('tiktok_shop_platform_commission');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('marketplace each fee key must be provided', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
$this->actingAs($user);
|
|
||||||
|
|
||||||
$feeRule = ['base' => 'per_transaksi', 'type' => 'flat', 'value' => 0];
|
|
||||||
|
|
||||||
$response = $this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => $feeRule,
|
|
||||||
// Missing other required keys
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response->assertSessionHasErrors([
|
|
||||||
'tiktok_shop_logistics_service_fee',
|
|
||||||
'tiktok_shop_dynamic_commission',
|
|
||||||
'tiktok_shop_order_processing_fee',
|
|
||||||
'tiktok_shop_affiliate',
|
|
||||||
'tiktok_shop_pre_order_service_fee',
|
|
||||||
'shopee_admin_fee',
|
|
||||||
'shopee_program_fee',
|
|
||||||
'shopee_shipping_savings',
|
|
||||||
'shopee_premium',
|
|
||||||
'shopee_service_fee',
|
|
||||||
'shopee_order_processing_fee',
|
|
||||||
'shopee_ams_commission_fee',
|
|
||||||
'shopee_pre_order',
|
|
||||||
'shopee_live_extra',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| UPDATE HR
|
| UPDATE HR
|
||||||
@ -777,36 +515,6 @@
|
|||||||
expect($settings->absent_penalty_amount)->toBeInt();
|
expect($settings->absent_penalty_amount)->toBeInt();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('marketplace settings default values are MarketplaceFeeRule', function () {
|
|
||||||
$settings = app(MarketplaceSettings::class);
|
|
||||||
|
|
||||||
expect($settings->tiktok_shop_platform_commission)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->tiktok_shop_logistics_service_fee)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->tiktok_shop_dynamic_commission)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->tiktok_shop_order_processing_fee)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->tiktok_shop_affiliate)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->tiktok_shop_pre_order_service_fee)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_admin_fee)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_program_fee)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_shipping_savings)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_premium)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_service_fee)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_order_processing_fee)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_ams_commission_fee)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_pre_order)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
expect($settings->shopee_live_extra)->toBeInstanceOf(MarketplaceFeeRule::class);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('marketplace fee rule to array contains correct keys', function () {
|
|
||||||
$rule = MarketplaceFeeRule::defaultPercent(0.0);
|
|
||||||
$array = $rule->toArray();
|
|
||||||
|
|
||||||
expect($array)->toHaveKeys(['base', 'type', 'value']);
|
|
||||||
expect($array['base'])->toBe('per_transaksi');
|
|
||||||
expect($array['type'])->toBe('persentase');
|
|
||||||
expect($array['value'])->toBe(0.0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('updating one setting group does not affect others', function () {
|
test('updating one setting group does not affect others', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@ -862,26 +570,6 @@
|
|||||||
'tiktok_url' => 'https://tiktok.com/@newdst',
|
'tiktok_url' => 'https://tiktok.com/@newdst',
|
||||||
])->assertSessionHasNoErrors();
|
])->assertSessionHasNoErrors();
|
||||||
|
|
||||||
// Update marketplace
|
|
||||||
$feeRule = ['base' => 'per_transaksi', 'type' => 'persentase', 'value' => 3.0];
|
|
||||||
$this->put(route('admin.settings.update-marketplace'), [
|
|
||||||
'tiktok_shop_platform_commission' => $feeRule,
|
|
||||||
'tiktok_shop_logistics_service_fee' => $feeRule,
|
|
||||||
'tiktok_shop_dynamic_commission' => $feeRule,
|
|
||||||
'tiktok_shop_order_processing_fee' => $feeRule,
|
|
||||||
'tiktok_shop_affiliate' => $feeRule,
|
|
||||||
'tiktok_shop_pre_order_service_fee' => $feeRule,
|
|
||||||
'shopee_admin_fee' => $feeRule,
|
|
||||||
'shopee_program_fee' => $feeRule,
|
|
||||||
'shopee_shipping_savings' => $feeRule,
|
|
||||||
'shopee_premium' => $feeRule,
|
|
||||||
'shopee_service_fee' => $feeRule,
|
|
||||||
'shopee_order_processing_fee' => $feeRule,
|
|
||||||
'shopee_ams_commission_fee' => $feeRule,
|
|
||||||
'shopee_pre_order' => $feeRule,
|
|
||||||
'shopee_live_extra' => $feeRule,
|
|
||||||
])->assertSessionHasNoErrors();
|
|
||||||
|
|
||||||
// Update HR
|
// Update HR
|
||||||
$this->put(route('admin.settings.update-hr'), [
|
$this->put(route('admin.settings.update-hr'), [
|
||||||
'scheduled_check_in_time' => '08:30',
|
'scheduled_check_in_time' => '08:30',
|
||||||
@ -894,13 +582,11 @@
|
|||||||
$system = app(SystemSettings::class);
|
$system = app(SystemSettings::class);
|
||||||
$homepage = app(HomepageSettings::class);
|
$homepage = app(HomepageSettings::class);
|
||||||
$socialMedia = app(SocialMediaSettings::class);
|
$socialMedia = app(SocialMediaSettings::class);
|
||||||
$marketplace = app(MarketplaceSettings::class);
|
|
||||||
$hr = app(HRSettings::class);
|
$hr = app(HRSettings::class);
|
||||||
|
|
||||||
expect($system->app_name)->toBe('DST Updated');
|
expect($system->app_name)->toBe('DST Updated');
|
||||||
expect($homepage->hero_image_url)->toBe('homepage/hero/2026/07/31/new-hero.jpg');
|
expect($homepage->hero_image_url)->toBe('homepage/hero/2026/07/31/new-hero.jpg');
|
||||||
expect($socialMedia->instagram_url)->toBe('https://instagram.com/newdst');
|
expect($socialMedia->instagram_url)->toBe('https://instagram.com/newdst');
|
||||||
expect($marketplace->tiktok_shop_platform_commission->value)->toBe(3.0);
|
|
||||||
expect($hr->scheduled_check_in_time)->toBe('08:30');
|
expect($hr->scheduled_check_in_time)->toBe('08:30');
|
||||||
expect($hr->late_penalty_amount)->toBe(15000);
|
expect($hr->late_penalty_amount)->toBe(15000);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
'payroll-adjustment' => ['create', 'delete'],
|
'payroll-adjustment' => ['create', 'delete'],
|
||||||
'leave-request' => ['view', 'create', 'update', 'delete', 'approve', 'reject'],
|
'leave-request' => ['view', 'create', 'update', 'delete', 'approve', 'reject'],
|
||||||
'attendance' => ['view', 'check-in', 'check-out', 'by-date'],
|
'attendance' => ['view', 'check-in', 'check-out', 'by-date'],
|
||||||
'settings' => ['view', 'update-system', 'update-homepage', 'update-social-media', 'update-marketplace', 'update-hr'],
|
'settings' => ['view', 'update-system', 'update-homepage', 'update-social-media', 'update-hr'],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($modules as $module => $actions) {
|
foreach ($modules as $module => $actions) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user