DB::afterCommit( fn () => app(CacheServiceInterface::class)->clearByModule('customer') ); static::saved($flushRepositoryCache); static::deleted($flushRepositoryCache); static::restored($flushRepositoryCache); } /** * Chỉ định cột sẽ nhận UUID. * Mặc định HasUuids dùng cột 'id', mình đổi sang 'uuid'. */ public function uniqueIds() { return ['uuid']; } /** * Điểm tích luỹ cộng cho một khoản nạp: 1 credit / 100 VNĐ. * Trước đây khớp sao kê tự động cộng credit bằng nguyên số tiền còn duyệt tay cộng * amount/100, cùng một khoản ra hai kết quả lệch nhau 100 lần — nay đi chung một chỗ. */ public static function creditFor(int $amount): int { return (int) floor(max(0, $amount) / 100); } protected $fillable = [ 'fullname', 'username', 'avatar', 'address', 'address_2', 'state', 'city', 'postcode', 'country', 'company', 'phone', 'email', 'email_verified_at', 'email_verify', 'email_verify_code', 'email_verify_code_expired_at', 'email_hash', 'email_marketing', 'receive_deposit', 'identity_number', 'front_identity_number', 'back_identity_number', 'password', 'note', 'type', 'credit', 'total', 'total_pending', 'remember_token', 'status', 'gender', 'birthday', 'province_code', 'ward_code', 'tax_code', 'invoice_company', 'invoice_address', 'invoice_email', ]; /** * Appends for API */ protected $appends = [ 'point', 'gender_label', ]; protected $casts = [ 'gender' => \App\Enums\Client\ClientGender::class, 'email_verified_at' => 'datetime', 'two_factor_enabled' => 'boolean', 'birthday' => 'date', ]; /** * The attributes that should be hidden for serialization. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; /** * Quan hệ với ModuleHosting (Hosting). */ public function hosting() { return $this->hasMany(ModuleHosting::class); } /** * Quan hệ với ModuleDomain (Domain). */ public function domain() { return $this->hasMany(ModuleDomain::class); } /** * Quan hệ với ModuleVmware (VPS). */ public function vps() { return $this->hasMany(ModuleVmware::class); } /** * Quan hệ với Service (tbl.services). */ public function service() { return $this->hasMany(Service::class); } /** * Quan hệ với Invoice. */ public function invoice() { return $this->hasMany(Invoice::class); } /** * Quan hệ với Ticket. */ public function ticket() { return $this->hasMany(Ticket::class); } /** * Quan hệ với Mail. */ public function mail() { return $this->hasMany(Mail::class); } /** * Quan hệ với File. */ public function file() { return $this->hasMany(File::class, 'customer_id'); } /** * Quan hệ với Order. */ public function order() { return $this->hasMany(Order::class); } /** * Quan hệ với Transaction. */ public function transaction() { return $this->hasMany(Transaction::class); } /** * Quan hệ với InvoiceItem. */ public function invoiceItem() { return $this->hasMany(InvoiceItem::class); } /** * Quan hệ với Log. */ public function log() { return $this->hasMany(Log::class); } public function acceptsMarketingEmail(): bool { return (bool) $this->email_marketing; } public function getReceiveDepositBoolAttribute() { return (bool) $this->receive_deposit; } public function getPointAttribute() { return (string) floor($this->total / 100); } public function getNameAttribute() { return $this->fullname; } public function getCmndBeforeAttribute() { return $this->front_identity_number ?? ''; } public function getCmndAfterAttribute() { return $this->back_identity_number ?? ''; } public function getCmndAttribute() { return $this->identity_number; } public function getOffMailMarketingAttribute() { return $this->email_marketing; } public function province() { return $this->belongsTo(Province::class, 'province_code', 'code'); } public function ward() { return $this->belongsTo(Ward::class, 'ward_code', 'code'); } public function getGenderLabelAttribute() { return $this->gender?->label() ?? 'Khác'; } public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return ['pv' => $this->passwordVersion()]; } /** * Dấu vân tay của hash mật khẩu, nhúng vào JWT. Đổi/đặt lại mật khẩu → giá trị đổi → * mọi access token cũ bị ApiAuthCheck từ chối (không cần blacklist). */ public function passwordVersion(): string { return substr(hash('sha256', (string) $this->password), 0, 16); } }