feat(service): huỷ dịch vụ, SSL, đổi mật khẩu hosting, lịch sử thanh toán theo hình thức
- Lịch sử thanh toán hoá đơn trả thêm `method` (tự động gia hạn / số dư / admin / chuyển khoản / hoàn tiền), bỏ đuôi `(method)` khỏi ghi chú - `DnsServer::panelUrl()` = https://<domain>/ dùng cho email cấp hosting và nút Plesk của khách - Order item trả thêm `uuid`/`type` của dịch vụ để FE dẫn tới trang quản lý - Yêu cầu huỷ dịch vụ, chứng chỉ SSL, lịch sử gia hạn, đổi mật khẩu hosting cho khách Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
a6b641015e
commit
b44a88bb52
@@ -37,6 +37,11 @@ class DnsServer extends Model
|
||||
return $this->domain ?: $this->ip_address;
|
||||
}
|
||||
|
||||
public function panelUrl(): string
|
||||
{
|
||||
return 'https://' . $this->publicHost() . '/';
|
||||
}
|
||||
|
||||
protected function scopeIsActive($query)
|
||||
{
|
||||
return $query->where('status', 'activated');
|
||||
|
||||
@@ -28,4 +28,12 @@ class ModuleHostingPleskClient extends Model
|
||||
{
|
||||
return $this->belongsTo(DnsServer::class, 'dns_manager_server_id');
|
||||
}
|
||||
|
||||
public static function forHosting($hosting): ?self
|
||||
{
|
||||
return static::query()
|
||||
->where('customer_id', $hosting->customer_id)
|
||||
->where('dns_manager_server_id', $hosting->dns_manager_server_id)
|
||||
->first();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,16 @@ class Service extends Model
|
||||
|
||||
protected $table = 'services';
|
||||
|
||||
public function cancellationRequests()
|
||||
{
|
||||
return $this->hasMany(ServiceCancellationRequest::class);
|
||||
}
|
||||
|
||||
public function sslCertificate()
|
||||
{
|
||||
return $this->hasOne(ServiceSslCertificate::class);
|
||||
}
|
||||
|
||||
public const HOSTING_ACCOUNT_RELATIONS = [
|
||||
'hostingAccount.server:id,name,ip_address,domain,panel_port',
|
||||
'hostingAccount.domain:id,domain_name',
|
||||
@@ -53,6 +63,7 @@ class Service extends Model
|
||||
'server_name',
|
||||
'status',
|
||||
'auto_renew',
|
||||
'cancel_at_expiry',
|
||||
'started_at',
|
||||
'expires_at',
|
||||
'suspended_at',
|
||||
@@ -71,6 +82,7 @@ class Service extends Model
|
||||
|
||||
protected $casts = [
|
||||
'auto_renew' => 'boolean',
|
||||
'cancel_at_expiry' => 'boolean',
|
||||
'started_at' => 'datetime',
|
||||
'expires_at' => 'datetime',
|
||||
'suspended_at' => 'datetime',
|
||||
|
||||
@@ -9,10 +9,18 @@ class ServiceAttachment extends Model
|
||||
{
|
||||
public const UPLOAD_RULE = 'required|file|mimes:jpg,jpeg,png,gif,webp,pdf,doc,docx,xls,xlsx,zip|max:51200';
|
||||
|
||||
public const AUDIENCE_ADMIN = 'admin';
|
||||
public const AUDIENCE_CUSTOMER = 'customer';
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $appends = ['url'];
|
||||
|
||||
public function scopeForCustomer($query)
|
||||
{
|
||||
return $query->where('audience', self::AUDIENCE_CUSTOMER);
|
||||
}
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->belongsTo(Service::class);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ServiceCancellationRequest extends Model
|
||||
{
|
||||
public const STATUS_PENDING = 'pending';
|
||||
|
||||
public const STATUS_APPROVED = 'approved';
|
||||
|
||||
public const STATUS_REJECTED = 'rejected';
|
||||
|
||||
protected $casts = ['resolved_at' => 'datetime'];
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->belongsTo(Service::class);
|
||||
}
|
||||
|
||||
public function customer()
|
||||
{
|
||||
return $this->belongsTo(Customer::class);
|
||||
}
|
||||
|
||||
public function scopePending($query)
|
||||
{
|
||||
return $query->where('status', self::STATUS_PENDING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ServiceSslCertificate extends Model
|
||||
{
|
||||
public const MAX_ENTRIES = 30;
|
||||
|
||||
public const MAX_FILE_BYTES = 524288;
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $casts = ['data' => 'encrypted:array'];
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->belongsTo(Service::class);
|
||||
}
|
||||
|
||||
public static function emptyData(): array
|
||||
{
|
||||
return ['fields' => [], 'files' => []];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user