big update all menus

This commit is contained in:
Wian Drs
2026-08-07 09:16:13 +07:00
parent 75342dc7b7
commit e7575ba1c0
101 changed files with 3451 additions and 89 deletions
+7
View File
@@ -31,6 +31,8 @@ class Customer extends Model
return $this->belongsTo(User::class);
}
public function salesUser() { return $this->belongsTo(User::class, 'sales_user_id'); }
public function provinsi()
{
return $this->belongsTo(WilayahProvinsi::class, 'provinsi_id');
@@ -61,6 +63,11 @@ class Customer extends Model
return $this->belongsTo(NasMikrotik::class, 'nas_mikrotik_id');
}
public function nasAccount()
{
return $this->hasOne(CustomerNasAccount::class);
}
public function images()
{
return $this->hasMany(CustomerImage::class)->orderByDesc('is_cover')->orderBy('sort_order');
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CustomerNasAccount extends Model
{
protected $guarded = ['id'];
protected $hidden = ['password'];
protected function casts(): array
{
return [
'password' => 'encrypted',
'last_synced_at' => 'datetime',
'validity_started_at' => 'datetime', 'first_login_at' => 'datetime', 'expires_at' => 'datetime',
'last_reconciled_at' => 'datetime', 'remote_state' => 'array',
];
}
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function mikrotik()
{
return $this->belongsTo(NasMikrotik::class, 'nas_mikrotik_id');
}
public function packageProfile()
{
return $this->belongsTo(NasPackageProfile::class, 'nas_package_profile_id');
}
public function packageProfileTarget()
{
return $this->belongsTo(NasPackageProfileTarget::class, 'nas_package_profile_target_id');
}
}
+4
View File
@@ -0,0 +1,4 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ItemBarcode extends Model { protected $guarded=['id']; protected function casts():array{return ['initial_qty'=>'decimal:2','remaining_qty'=>'decimal:2'];} protected static function booted():void{static::updated(function(self $barcode){if(!$barcode->wasChanged('remaining_qty'))return;$item=$barcode->item;if(!$item||$item->status==='draft')return;$remaining=(float)$item->barcodes()->sum('remaining_qty');$item->update(['status'=>$remaining>0?'active':'depleted','is_active'=>$remaining>0]);});} public function item(){return $this->belongsTo(WarehouseItem::class,'warehouse_item_id');} }
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ItemCode extends Model
{
protected $guarded = ['id'];
protected function casts(): array
{
return ['need_serial_number' => 'boolean', 'minimum_stock' => 'decimal:2', 'is_active' => 'boolean'];
}
public function items() { return $this->hasMany(WarehouseItem::class); }
}
+4
View File
@@ -0,0 +1,4 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ItemMovement extends Model { protected $guarded=['id']; protected function casts():array{return ['qty'=>'decimal:2'];} }
+4
View File
@@ -0,0 +1,4 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ItemStockLog extends Model { protected $guarded=['id']; protected function casts():array{return ['qty_before'=>'decimal:2','qty_change'=>'decimal:2','qty_after'=>'decimal:2','barcode_qty_before'=>'decimal:2','barcode_qty_change'=>'decimal:2','barcode_qty_after'=>'decimal:2'];} }
+2
View File
@@ -16,6 +16,7 @@ class MenuGroupMenu extends Model
'can_update',
'can_delete',
'can_approve',
'can_activate',
'can_export',
];
@@ -25,6 +26,7 @@ class MenuGroupMenu extends Model
'can_update' => 'boolean',
'can_delete' => 'boolean',
'can_approve' => 'boolean',
'can_activate' => 'boolean',
'can_export' => 'boolean',
];
+18 -1
View File
@@ -12,11 +12,28 @@ class NasMikrotik extends Model
protected function casts(): array
{
return ['api_password' => 'encrypted', 'radius_secret' => 'encrypted'];
return [
'api_password' => 'encrypted',
'radius_secret' => 'encrypted',
'last_checked_at' => 'datetime',
'last_connected_at' => 'datetime',
'next_health_check_at' => 'datetime',
'health_details' => 'array',
];
}
public function tenant()
{
return $this->belongsTo(Tenant::class);
}
public function customerAccounts()
{
return $this->hasMany(CustomerNasAccount::class);
}
public function effectiveBackendMode(): string
{
return $this->backend_mode_override ?: ($this->tenant->nasSetting?->backend_mode ?: 'routeros_api');
}
}
+4 -1
View File
@@ -10,11 +10,14 @@ class NasPackageProfile extends Model
protected function casts(): array
{
return ['price' => 'decimal:2'];
return ['price' => 'decimal:2', 'service_parameters' => 'array', 'dns_servers' => 'array', 'mac_lock_required' => 'boolean'];
}
public function tenant()
{
return $this->belongsTo(Tenant::class);
}
public function targets() { return $this->hasMany(NasPackageProfileTarget::class); }
public function scripts() { return $this->belongsToMany(NasScriptPolicy::class, 'nas_package_profile_scripts')->withPivot(['event', 'nas_script_policy_version_id', 'enabled']); }
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class NasPackageProfileTarget extends Model
{
protected $guarded = ['id'];
protected function casts(): array { return ['desired_snapshot' => 'array', 'remote_snapshot' => 'array', 'last_checked_at' => 'datetime', 'last_synced_at' => 'datetime']; }
public function packageProfile() { return $this->belongsTo(NasPackageProfile::class, 'nas_package_profile_id'); }
public function mikrotik() { return $this->belongsTo(NasMikrotik::class, 'nas_mikrotik_id'); }
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class NasScriptPolicy extends Model
{
protected $guarded = ['id'];
protected function casts(): array { return ['allowed_variables' => 'array', 'enabled' => 'boolean']; }
public function versions() { return $this->hasMany(NasScriptPolicyVersion::class); }
public function latestVersion() { return $this->hasOne(NasScriptPolicyVersion::class)->ofMany('version', 'max'); }
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class NasScriptPolicyVersion extends Model
{
protected $guarded = ['id'];
public function policy() { return $this->belongsTo(NasScriptPolicy::class, 'nas_script_policy_id'); }
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class RadiusCluster extends Model
{
protected $guarded = ['id'];
protected $hidden = ['provisioning_api_token'];
protected function casts(): array { return ['auth_endpoints'=>'array','accounting_endpoints'=>'array','coa_endpoints'=>'array','provisioning_api_token'=>'encrypted','last_checked_at'=>'datetime']; }
}
+3 -1
View File
@@ -21,4 +21,6 @@ class TechnicianConsumable extends Model
'assigned_at',
'assigned_by'
];
}
public function user() { return $this->belongsTo(User::class); }
}
+3 -1
View File
@@ -18,4 +18,6 @@ class TechnicianMaterial extends Model
'assigned_at',
'assigned_by',
];
}
public function user() { return $this->belongsTo(User::class); }
}
+3
View File
@@ -24,4 +24,7 @@ class Tenant extends Model
{
return $this->hasOne(TenantPaymentSetting::class);
}
public function nasSetting() { return $this->hasOne(TenantNasSetting::class); }
public function installationSetting() { return $this->hasOne(TenantInstallationSetting::class); }
}
+3
View File
@@ -0,0 +1,3 @@
<?php
namespace App\Models;use Illuminate\Database\Eloquent\Model;
class TenantInstallationSetting extends Model{protected $fillable=['tenant_id','activation_mode','ktp_ocr_enabled','ocr_provider','ocr_api_key'];protected $hidden=['ocr_api_key'];protected function casts():array{return['ktp_ocr_enabled'=>'boolean','ocr_api_key'=>'encrypted'];}public function tenant(){return $this->belongsTo(Tenant::class);}}
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class TenantNasSetting extends Model
{
protected $guarded = ['id'];
protected $hidden = ['external_radius_secret','external_provisioning_api_token'];
protected function casts(): array { return ['external_radius_secret'=>'encrypted','external_provisioning_api_token'=>'encrypted','accounting_enabled'=>'boolean','coa_enabled'=>'boolean','last_checked_at'=>'datetime']; }
public function tenant() { return $this->belongsTo(Tenant::class); }
public function radiusCluster() { return $this->belongsTo(RadiusCluster::class); }
}
+21
View File
@@ -13,6 +13,7 @@ class Ticket extends Model
'ticket_no',
'ticket_type_id',
'customer_id',
'source','installation_step','verified_by','verified_at','verification_notes',
'title',
'description',
'priority',
@@ -26,8 +27,19 @@ class Ticket extends Model
'rejection_reason',
'resolved_at',
'closed_at',
'tenant_id',
];
protected function casts(): array
{
return [
'assigned_at' => 'datetime',
'resolved_at' => 'datetime',
'closed_at' => 'datetime',
'verified_at' => 'datetime',
];
}
/*
|--------------------------------------------------------------------------
| Relationships
@@ -41,4 +53,13 @@ class Ticket extends Model
'ticket_type_id'
);
}
public function customer() { return $this->belongsTo(Customer::class); }
public function tenant() { return $this->belongsTo(Tenant::class); }
public function creator() { return $this->belongsTo(User::class, 'created_by'); }
public function assignments() { return $this->hasMany(TicketAssignment::class); }
public function logs() { return $this->hasMany(TicketLog::class)->orderByDesc('id'); }
public function materials() { return $this->hasMany(TicketMaterial::class)->with('user:id,name')->orderByDesc('id'); }
public function attachments() { return $this->hasMany(TicketAttachment::class)->with('file:id,uuid,original_name,mime_type,size')->orderBy('id'); }
}
+3
View File
@@ -16,4 +16,7 @@ class TicketAssignment extends Model
'assigned_at',
'status'
];
protected function casts(): array { return ['is_leader' => 'boolean', 'assigned_at' => 'datetime']; }
public function user() { return $this->belongsTo(User::class); }
}
+4
View File
@@ -0,0 +1,4 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class TicketAttachment extends Model { protected $guarded=['id']; public function file(){return $this->belongsTo(StoredFile::class,'stored_file_id');} public function uploader(){return $this->belongsTo(User::class,'uploaded_by');} }
+4 -1
View File
@@ -6,5 +6,8 @@ use Illuminate\Database\Eloquent\Model;
class TicketMaterial extends Model
{
//
public $timestamps = false;
protected $fillable=['ticket_id','ticket_log_id','technician_material_id','technician_consumable_id','material_name','qty','notes','used_by','created_at'];
protected function casts():array{return ['qty'=>'decimal:2','created_at'=>'datetime'];}
public function user(){return $this->belongsTo(User::class,'used_by');}
}
+1
View File
@@ -12,6 +12,7 @@ class UserTenant extends Model
'user_id',
'tenant_id',
'role',
'department',
'is_default',
];
+4
View File
@@ -0,0 +1,4 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Warehouse extends Model { protected $guarded=['id']; protected function casts():array{return ['is_active'=>'boolean'];} public function items(){return $this->hasMany(WarehouseItem::class);} }
+4
View File
@@ -0,0 +1,4 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class WarehouseItem extends Model { protected $guarded=['id']; protected function casts():array{return ['is_active'=>'boolean','minimum_stock'=>'decimal:2','received_qty'=>'decimal:2','received_at'=>'date','posted_at'=>'datetime'];} public function warehouse(){return $this->belongsTo(Warehouse::class);} public function itemCode(){return $this->belongsTo(ItemCode::class);} public function barcodes(){return $this->hasMany(ItemBarcode::class);} public function movements(){return $this->hasMany(ItemMovement::class)->latest();} }