Giant Update

This commit is contained in:
Wian Drs
2026-07-31 13:57:11 +07:00
parent f68d967c8b
commit b0d08211ec
112 changed files with 6674 additions and 3 deletions
@@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests\Billing;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexBillingRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'search' => ['nullable', 'string', 'max:255'],
'status' => ['nullable', 'string', 'max:30'],
'date_from' => ['nullable', 'date'],
'date_to' => ['nullable', 'date', 'after_or_equal:date_from'],
'page' => ['nullable', 'integer', 'min:1'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
'sort_by' => ['nullable', Rule::in(['id', 'name', 'invoice_number', 'issue_date', 'isolation_date', 'total', 'balance', 'status', 'created_at', 'paid_at'])],
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Requests\Billing;
use Illuminate\Foundation\Http\FormRequest;
class PayInvoiceRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'amount' => ['required', 'numeric', 'gt:0'],
'payment_method' => ['nullable', 'string', 'max:50'],
'payment_reference' => ['nullable', 'string', 'max:255'],
'paid_at' => ['nullable', 'date'],
'notes' => ['nullable', 'string'],
];
}
}
@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\Billing;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreBillingProfileRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'name' => ['required', 'string', 'max:255'],
'schedule_type' => ['required', Rule::in(['fixed_date', 'installation_date'])],
'invoice_day' => ['required_if:schedule_type,fixed_date', 'nullable', 'integer', 'between:1,28'],
'send_day' => ['required_if:schedule_type,fixed_date', 'nullable', 'integer', 'between:1,28', 'gte:invoice_day'],
'warning_day' => ['required_if:schedule_type,fixed_date', 'nullable', 'integer', 'between:1,28', 'gte:send_day'],
'isolation_day' => ['required_if:schedule_type,fixed_date', 'nullable', 'integer', 'between:1,28', 'gte:warning_day'],
'invoice_days_before' => ['required_if:schedule_type,installation_date', 'nullable', 'integer', 'between:0,90'],
'send_days_before' => ['required_if:schedule_type,installation_date', 'nullable', 'integer', 'between:0,90', 'lte:invoice_days_before'],
'warning_days_before' => ['required_if:schedule_type,installation_date', 'nullable', 'integer', 'between:0,90', 'lte:send_days_before'],
'isolation_days_after' => ['required_if:schedule_type,installation_date', 'nullable', 'integer', 'between:0,90'],
'tax_type' => ['required', Rule::in(['inclusive', 'exclusive', 'non_tax'])],
'tax_rate' => ['nullable', 'numeric', 'between:0,100'],
'status' => ['nullable', Rule::in(['active', 'inactive'])],
'notes' => ['nullable', 'string'],
];
}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests\Billing;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreInvoiceRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'customer_id' => ['required', 'integer', 'exists:customers,id'],
'invoice_number' => ['nullable', 'string', 'max:100'],
'period_start' => ['required', 'date'],
'period_end' => ['required', 'date', 'after_or_equal:period_start'],
'issue_date' => ['required', 'date'],
'send_date' => ['nullable', 'date', 'after_or_equal:issue_date'],
'warning_date' => ['nullable', 'date', 'after_or_equal:send_date'],
'isolation_date' => ['nullable', 'date', 'after_or_equal:warning_date'],
'subtotal' => ['required', 'numeric', 'min:0'],
'notes' => ['nullable', 'string'],
'metadata' => ['nullable', 'array'],
'status' => ['nullable', Rule::in(['draft', 'published', 'sent', 'warning', 'overdue', 'paid', 'cancelled'])],
];
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Http\Requests\Billing;
class UpdateBillingProfileRequest extends StoreBillingProfileRequest
{
public function rules(): array
{
return collect(parent::rules())->map(function ($rules) {
$rules = is_array($rules) ? $rules : [$rules];
if (($index = array_search('required', $rules, true)) !== false) {
$rules[$index] = 'sometimes';
}
return $rules;
})->all();
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Http\Requests\Billing;
class UpdateInvoiceRequest extends StoreInvoiceRequest
{
public function rules(): array
{
return collect(parent::rules())->map(function ($rules) {
$rules = is_array($rules) ? $rules : [$rules];
if (($index = array_search('required', $rules, true)) !== false) {
$rules[$index] = 'sometimes';
}
return $rules;
})->all();
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Requests\Customer;
use Illuminate\Foundation\Http\FormRequest;
class ActivateCustomerRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'package_profile_id' => ['required', 'integer', 'exists:nas_package_profiles,id'],
'nas_mikrotik_id' => ['required', 'integer', 'exists:nas_mikrotiks,id'],
'billing_profile_id' => ['required', 'integer', 'exists:billing_profiles,id'],
'topology_id' => ['nullable', 'integer', 'min:1'],
'external_username' => ['nullable', 'string', 'max:255'],
];
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Http\Requests\Customer;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexCustomerRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'search' => ['nullable', 'string', 'max:255'],
'source' => ['nullable', Rule::in(['manual', 'mikrotik', 'radius'])],
'page' => ['nullable', 'integer', 'min:1'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
'sort_by' => ['nullable', Rule::in(['id', 'customer_code', 'name', 'email', 'whatsapp_number', 'status', 'order_stage', 'created_at', 'activated_at'])],
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,48 @@
<?php
namespace App\Http\Requests\Customer;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreCustomerRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'user_id' => ['nullable', 'integer', 'exists:users,id'],
'customer_code' => ['nullable', 'string', 'max:100'],
'name' => ['required', 'string', 'max:255'],
'identity_number' => ['nullable', 'string', 'max:100'],
'email' => ['nullable', 'email', 'max:255'],
'whatsapp_number' => ['nullable', 'string', 'max:50'],
'installation_address' => ['nullable', 'string'],
'provinsi_id' => ['nullable', 'integer', 'exists:wilayah_provinsi,id'],
'kabupaten_id' => ['nullable', 'integer', 'exists:wilayah_kabupaten,id'],
'kecamatan_id' => ['nullable', 'integer', 'exists:wilayah_kecamatan,id'],
'desa_id' => ['nullable', 'integer', 'exists:wilayah_desa,id'],
'latitude' => ['nullable', 'numeric', 'between:-90,90'],
'longitude' => ['nullable', 'numeric', 'between:-180,180'],
'package_profile_id' => ['nullable', 'integer', 'exists:nas_package_profiles,id'],
'nas_mikrotik_id' => ['nullable', 'integer', 'exists:nas_mikrotiks,id'],
'billing_profile_id' => ['nullable', 'integer', 'min:1'],
'topology_id' => ['nullable', 'integer', 'min:1'],
'external_username' => ['nullable', 'string', 'max:255'],
'source' => ['nullable', Rule::in(['manual', 'mikrotik', 'radius'])],
'order_stage' => ['nullable', Rule::in(['registration', 'data_completion', 'ready_activation', 'activation_failed'])],
'notes' => ['nullable', 'string'],
'images' => ['nullable', 'array', 'max:20'],
'images.*.stored_file_id' => ['required', 'integer', 'exists:stored_files,id'],
'images.*.category' => ['required', Rule::in(['house', 'installation', 'modem', 'odp', 'cable', 'identity', 'other'])],
'images.*.caption' => ['nullable', 'string', 'max:255'],
'images.*.is_cover' => ['nullable', 'boolean'],
'images.*.sort_order' => ['nullable', 'integer', 'min:0', 'max:1000'],
];
}
}
@@ -0,0 +1,14 @@
<?php
namespace App\Http\Requests\Customer;
class UpdateCustomerRequest extends StoreCustomerRequest
{
public function rules(): array
{
$rules = parent::rules();
$rules['name'] = ['sometimes', 'required', 'string', 'max:255'];
return $rules;
}
}
+6 -2
View File
@@ -13,11 +13,13 @@ class StoreFileRequest extends FormRequest
public function rules(): array
{
$maxSize = $this->input('category') === 'customer-image' ? 500 : 20480;
return [
'file' => [
'required',
'file',
'max:20480',
"max:{$maxSize}",
'mimes:jpg,jpeg,png,webp,gif,pdf,doc,docx,xls,xlsx,csv,txt,zip',
],
'category' => ['nullable', 'string', 'max:80', 'regex:/^[a-z0-9_-]+$/'],
@@ -27,7 +29,9 @@ class StoreFileRequest extends FormRequest
public function messages(): array
{
return [
'file.max' => 'Ukuran file maksimal 20 MB.',
'file.max' => $this->input('category') === 'customer-image'
? 'Gambar customer maksimal 500 KB setelah kompresi.'
: 'Ukuran file maksimal 20 MB.',
'file.mimes' => 'Jenis file tidak didukung.',
'category.regex' => 'Kategori hanya boleh berisi huruf kecil, angka, garis bawah, atau tanda hubung.',
];
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Requests\Notification;
use Illuminate\Foundation\Http\FormRequest;
class IndexNotificationRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'search' => ['nullable', 'string', 'max:255'],
'status' => ['nullable', 'string', 'max:30'],
'unread' => ['nullable', 'boolean'],
'page' => ['nullable', 'integer', 'min:1'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
];
}
}
@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Notification;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class SaveNotificationPreferencesRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'preferences' => ['required', 'array'],
'preferences.*.tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'preferences.*.notification_event_id' => ['required', 'integer', 'exists:notification_events,id'],
'preferences.*.notification_channel_id' => ['nullable', 'integer', 'exists:notification_channels,id'],
'preferences.*.channel' => ['required', Rule::in(['system', 'whatsapp_official', 'whatsapp_unofficial', 'email', 'telegram'])],
'preferences.*.enabled' => ['required', 'boolean'],
'preferences.*.priority' => ['nullable', 'integer', 'between:1,20'],
'preferences.*.send_delay_minutes' => ['nullable', 'integer', 'between:0,10080'],
'preferences.*.quiet_hours_start' => ['nullable', 'date_format:H:i'],
'preferences.*.quiet_hours_end' => ['nullable', 'date_format:H:i'],
];
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests\Notification;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreCustomerContactRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'type' => ['required', Rule::in(['email', 'whatsapp', 'telegram'])],
'value' => ['required', 'string', 'max:255'],
'label' => ['nullable', 'string', 'max:100'],
'is_primary' => ['nullable', 'boolean'],
'is_verified' => ['nullable', 'boolean'],
'can_receive_transactional' => ['nullable', 'boolean'],
'can_receive_broadcast' => ['nullable', 'boolean'],
'opted_out_at' => ['nullable', 'date'],
];
}
}
@@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests\Notification;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreNotificationBroadcastRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'name' => ['required_without:preview', 'string', 'max:255'],
'channel' => ['required', Rule::in(['system', 'whatsapp_official', 'whatsapp_unofficial', 'email', 'telegram'])],
'notification_template_id' => ['nullable', 'integer', 'exists:notification_templates,id'],
'notification_channel_id' => ['nullable', 'integer', 'exists:notification_channels,id'],
'subject' => ['nullable', 'string', 'max:255'],
'body' => ['required_without:notification_template_id', 'nullable', 'string', 'max:20000'],
'scheduled_at' => ['nullable', 'date'],
'filters' => ['nullable', 'array'],
'filters.customer_status' => ['nullable', 'array'],
'filters.customer_status.*' => [Rule::in(['order', 'active', 'inactive', 'unmanaged'])],
'filters.source' => ['nullable', Rule::in(['manual', 'nas'])],
'filters.package_profile_id' => ['nullable', 'integer'],
'filters.billing_profile_id' => ['nullable', 'integer'],
'filters.topology_node_id' => ['nullable', 'integer', 'exists:topology_nodes,id'],
'filters.provinsi_id' => ['nullable', 'integer'],
'filters.kabupaten_id' => ['nullable', 'integer'],
'filters.kecamatan_id' => ['nullable', 'integer'],
'filters.desa_id' => ['nullable', 'integer'],
];
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests\Notification;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreNotificationChannelRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'channel' => ['required', Rule::in(['system', 'whatsapp_official', 'whatsapp_unofficial', 'email', 'telegram'])],
'provider' => ['nullable', 'string', 'max:50'],
'name' => ['required', 'string', 'max:255'],
'enabled' => ['nullable', 'boolean'],
'is_default' => ['nullable', 'boolean'],
'credentials' => ['nullable', 'array'],
'credentials.*' => ['nullable', 'string', 'max:4000'],
'settings' => ['nullable', 'array'],
];
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Notification;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreNotificationTemplateRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'notification_event_id' => ['required', 'integer', 'exists:notification_events,id'],
'notification_channel_id' => ['nullable', 'integer', 'exists:notification_channels,id'],
'channel' => ['required', Rule::in(['system', 'whatsapp_official', 'whatsapp_unofficial', 'email', 'telegram'])],
'name' => ['required', 'string', 'max:255'],
'subject' => ['nullable', 'string', 'max:255'],
'body' => ['required', 'string', 'max:20000'],
'provider_template_name' => ['nullable', 'string', 'max:255'],
'provider_template_id' => ['nullable', 'string', 'max:255'],
'language' => ['nullable', 'string', 'max:10'],
'approval_status' => ['nullable', Rule::in(['not_required', 'pending', 'approved', 'rejected'])],
'enabled' => ['nullable', 'boolean'],
];
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Http\Requests\Payment;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexPaymentRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'search' => ['nullable', 'string', 'max:100'], 'status' => ['nullable', 'string', 'max:30'],
'provider_code' => ['nullable', 'string', 'max:50'], 'purpose' => ['nullable', 'string', 'max:30'],
'date_from' => ['nullable', 'date'], 'date_to' => ['nullable', 'date', 'after_or_equal:date_from'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
'sort_by' => ['nullable', Rule::in(['id', 'transaction_number', 'amount', 'status', 'created_at', 'paid_at'])],
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests\Payment;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class SaveTenantPaymentSettingRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'payment_mode' => ['required', Rule::in(['disabled', 'tenant_gateway', 'platform_gateway'])],
'tenant_gateway_account_id' => ['nullable', 'integer', 'exists:payment_gateway_accounts,id'],
'platform_gateway_account_id' => ['nullable', 'integer', 'exists:payment_gateway_accounts,id'],
'fee_bearer' => ['required', Rule::in(['customer', 'tenant', 'platform'])],
'default_expiry_minutes' => ['required', 'integer', 'min:5', 'max:10080'],
'enabled_methods' => ['nullable', 'array'],
'enabled_methods.*' => ['string', 'max:50'],
];
}
}
@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Payment;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreGatewayAccountRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'payment_provider_id' => ['required', 'integer', 'exists:payment_providers,id'],
'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
'scope' => ['required', Rule::in(['tenant', 'platform'])],
'name' => ['required', 'string', 'max:150'],
'environment' => ['required', Rule::in(['sandbox', 'production'])],
'credentials' => ['nullable', 'array'],
'credentials.*' => ['nullable', 'string', 'max:4000'],
'webhook_secret' => ['nullable', 'string', 'max:4000'],
'settings' => ['nullable', 'array'],
'enabled' => ['sometimes', 'boolean'],
'is_default' => ['sometimes', 'boolean'],
];
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests\Topology;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class IndexTopologyRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'search' => ['nullable', 'string', 'max:255'],
'status' => ['nullable', 'string', 'max:30'],
'device_type_id' => ['nullable', 'integer', 'exists:topology_device_types,id'],
'link_type' => ['nullable', Rule::in(['fiber', 'wireless', 'ethernet', 'logical'])],
'bbox' => ['nullable', 'regex:/^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?$/'],
'page' => ['nullable', 'integer', 'min:1'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
'sort_by' => ['nullable', Rule::in(['id', 'code', 'name', 'status', 'category', 'link_type', 'installed_at', 'created_at'])],
'sort_direction' => ['nullable', Rule::in(['asc', 'desc'])],
];
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Http\Requests\Topology;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreCustomerConnectionRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'customer_id' => ['required', 'integer', 'exists:customers,id'],
'odp_node_id' => ['required', 'integer', 'exists:topology_nodes,id'],
'odp_port_id' => ['nullable', 'integer', 'exists:topology_ports,id'],
'drop_cable_link_id' => ['nullable', 'integer', 'exists:topology_links,id'],
'connected_at' => ['nullable', 'date'],
'status' => ['nullable', Rule::in(['active', 'inactive'])],
'metadata' => ['nullable', 'array'],
];
}
}
@@ -0,0 +1,89 @@
<?php
namespace App\Http\Requests\Topology;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreTopologyRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return match ($this->route()->defaults['topology_resource'] ?? null) {
'device-type' => [
...$this->tenantRule(),
'code' => ['required', 'string', 'max:50'],
'name' => ['required', 'string', 'max:255'],
'category' => ['required', Rule::in(['site', 'termination', 'closure', 'distribution', 'splitter', 'other'])],
'can_have_ports' => ['nullable', 'boolean'],
'can_have_splitters' => ['nullable', 'boolean'],
'icon' => ['nullable', 'string', 'max:100'],
'color' => ['nullable', 'regex:/^#[0-9a-fA-F]{6}$/'],
'status' => ['nullable', Rule::in(['active', 'inactive'])],
],
'node' => [
...$this->tenantRule(),
'device_type_id' => ['required', 'integer', 'exists:topology_device_types,id'],
'parent_node_id' => ['nullable', 'integer', 'exists:topology_nodes,id'],
'code' => ['required', 'string', 'max:100'],
'name' => ['required', 'string', 'max:255'],
'description' => ['nullable', 'string'],
'status' => ['nullable', Rule::in(['active', 'inactive', 'maintenance', 'damaged'])],
'latitude' => ['required', 'numeric', 'between:-90,90'],
'longitude' => ['required', 'numeric', 'between:-180,180'],
'address' => ['nullable', 'string'],
'provinsi_id' => ['nullable', 'integer', 'exists:wilayah_provinsi,id'],
'kabupaten_id' => ['nullable', 'integer', 'exists:wilayah_kabupaten,id'],
'kecamatan_id' => ['nullable', 'integer', 'exists:wilayah_kecamatan,id'],
'desa_id' => ['nullable', 'integer', 'exists:wilayah_desa,id'],
'capacity' => ['nullable', 'integer', 'min:0'],
'installed_at' => ['nullable', 'date'],
'diagram_x' => ['nullable', 'numeric'],
'diagram_y' => ['nullable', 'numeric'],
'metadata' => ['nullable', 'array'],
],
'link' => [
...$this->tenantRule(),
'source_node_id' => ['required', 'integer', 'exists:topology_nodes,id', 'different:target_node_id'],
'source_port_id' => ['nullable', 'integer', 'exists:topology_ports,id'],
'target_node_id' => ['required', 'integer', 'exists:topology_nodes,id'],
'target_port_id' => ['nullable', 'integer', 'exists:topology_ports,id'],
'code' => ['required', 'string', 'max:100'],
'name' => ['required', 'string', 'max:255'],
'link_type' => ['required', Rule::in(['fiber', 'wireless', 'ethernet', 'logical'])],
'fiber_type' => ['nullable', 'string', 'max:50'],
'core_count' => ['nullable', 'integer', 'min:1'],
'cable_length' => ['nullable', 'numeric', 'min:0'],
'measured_length' => ['nullable', 'numeric', 'min:0'],
'path_geojson' => ['nullable', 'array'],
'path_geojson.type' => ['required_with:path_geojson', Rule::in(['LineString'])],
'path_geojson.coordinates' => ['required_with:path_geojson', 'array', 'min:2'],
'path_geojson.coordinates.*' => ['array', 'size:2'],
'path_geojson.coordinates.*.*' => ['numeric'],
'status' => ['nullable', Rule::in(['active', 'inactive', 'maintenance', 'damaged'])],
'installed_at' => ['nullable', 'date'],
'metadata' => ['nullable', 'array'],
],
'port' => [
'name' => ['required', 'string', 'max:100'],
'port_number' => ['required', 'integer', 'min:1'],
'port_type' => ['required', Rule::in(['fiber', 'ethernet', 'pon', 'uplink', 'splitter', 'other'])],
'direction' => ['required', Rule::in(['input', 'output', 'bidirectional'])],
'capacity' => ['nullable', 'integer', 'min:1'],
'status' => ['nullable', Rule::in(['available', 'used', 'reserved', 'damaged'])],
'metadata' => ['nullable', 'array'],
],
default => [],
};
}
private function tenantRule(): array
{
return ['tenant_id' => ['nullable', 'integer', 'exists:tenants,id']];
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Http\Requests\Topology;
class UpdateTopologyRequest extends StoreTopologyRequest
{
public function rules(): array
{
return collect(parent::rules())->map(function ($rules) {
$rules = is_array($rules) ? $rules : [$rules];
if (($index = array_search('required', $rules, true)) !== false) {
$rules[$index] = 'sometimes';
}
return $rules;
})->all();
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Requests\Wallet;
use Illuminate\Foundation\Http\FormRequest;
class StoreWithdrawalRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'amount' => ['required', 'numeric', 'min:10000'], 'fee' => ['nullable', 'numeric', 'min:0'],
'bank_code' => ['required', 'string', 'max:30'], 'account_number' => ['required', 'string', 'max:50'],
'account_name' => ['required', 'string', 'max:150'],
];
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Http\Requests\Wallet;
use Illuminate\Foundation\Http\FormRequest;
class TransferWalletRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return ['destination_wallet_id' => ['required', 'integer', 'exists:wallets,id'], 'amount' => ['required', 'numeric', 'min:1']];
}
}