From 8ed9e382903d963f09ccc900a31b73d27dd02294 Mon Sep 17 00:00:00 2001 From: Deon George Date: Fri, 22 Apr 2022 10:36:41 +1000 Subject: [PATCH] Removed redundant functions from Service::class --- app/Http/Controllers/SearchController.php | 63 +- app/Models/Account.php | 47 +- app/Models/Invoice.php | 11 + app/Models/Product.php | 2 +- app/Models/Product/Type.php | 2 +- app/Models/Service.php | 569 +++++++----------- .../views/email/admin/order/approve.blade.php | 10 +- .../views/email/admin/order/reject.blade.php | 4 +- .../email/admin/service/cancel.blade.php | 10 +- .../email/admin/service/change.blade.php | 10 +- .../a/service/widgets/update.blade.php | 2 +- .../common/service/widget/info.blade.php | 38 -- .../adminlte/r/service/domain/list.blade.php | 2 +- .../adminlte/r/service/email/list.blade.php | 2 +- .../adminlte/r/service/host/list.blade.php | 2 +- .../r/service/order/provision_plan.blade.php | 4 +- .../adminlte/r/service/order/sent.blade.php | 4 +- .../adminlte/u/invoice/widgets/next.blade.php | 2 +- .../u/service/cancel_request.blade.php | 4 +- .../u/service/change_request.blade.php | 4 +- .../backend/adminlte/u/service/home.blade.php | 7 +- .../u/service/widgets/active.blade.php | 4 +- .../widgets/broadband/details.blade.php | 4 +- .../service/widgets/domain/details.blade.php | 2 +- .../u/service/widgets/email/details.blade.php | 2 +- .../u/service/widgets/host/details.blade.php | 2 +- .../u/service/widgets/information.blade.php | 2 +- .../u/service/widgets/phone/details.blade.php | 4 +- .../u/service/widgets/ssl/details.blade.php | 2 +- 29 files changed, 307 insertions(+), 514 deletions(-) delete mode 100644 resources/views/theme/backend/adminlte/common/service/widget/info.blade.php diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 4cbdbcf..1593482 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -35,70 +35,73 @@ class SearchController extends Controller ->orderBy('firstname') ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s %s',$o->sid,$o->name),'value'=>'/u/home/'.$o->id,'category'=>'Users']); + $result->push(['name'=>sprintf('%s (%s)',$o->lid,$o->name),'value'=>'/u/home/'.$o->id,'category'=>'Users']); } # Look for Account foreach (Account::Search($request->input('term')) - ->whereIN('user_id',$user_ids) - ->orderBy('company') - ->limit(10)->get() as $o) + ->whereIN('user_id',$user_ids) + ->orderBy('company') + ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s %s',$o->sid,$o->company),'value'=>'/u/home/'.$o->user_id,'category'=>'Accounts']); + $result->push(['name'=>sprintf('%s (%s)',$o->lid,$o->company),'value'=>'/u/home/'.$o->user_id,'category'=>'Accounts']); } # Look for a Service foreach (Service::Search($request->input('term')) - ->whereIN('account_id',$account_ids) - ->orderBy('id') - ->limit(10)->get() as $o) + ->whereIN('account_id',$account_ids) + ->orderBy('id') + ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s (%s)',$o->name,$o->sid),'value'=>'/u/service/'.$o->id,'category'=>'Services']); + $result->push(['name'=>sprintf('%s (%s)',$o->name,$o->lid),'value'=>'/u/service/'.$o->id,'category'=>'Services']); } # Look for an Invoice foreach (Invoice::Search($request->input('term')) - ->whereIN('account_id',$account_ids) - ->orderBy('id') - ->limit(10)->get() as $o) + ->whereIN('account_id',$account_ids) + ->orderBy('id') + ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s: %s',$o->sid,$o->account->name),'value'=>'/u/invoice/'.$o->id,'category'=>'Invoices']); + $result->push(['name'=>sprintf('%s: %s',$o->lid,$o->account->name),'value'=>'/u/invoice/'.$o->id,'category'=>'Invoices']); } - # Look for an Broadband Service + # Look for a Broadband Service foreach (Broadband::Search($request->input('term')) - ->whereIN('account_id',$account_ids) - ->orderBy('service_number') - ->limit(10)->get() as $o) + ->whereIN('account_id',$account_ids) + ->orderBy('service_number') + ->with(['service']) + ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s (%s)',$o->service_name,$o->service->sid),'value'=>'/u/service/'.$o->id,'category'=>'Broadband']); + $result->push(['name'=>sprintf('%s (%s)',$o->service->name,$o->service->lid),'value'=>'/u/service/'.$o->service_id,'category'=>'Broadband']); } - # Look for an Phone Service + # Look for a Phone Service foreach (Phone::Search($request->input('term')) - ->whereIN('account_id',$account_ids) - ->orderBy('service_number') - ->limit(10)->get() as $o) + ->whereIN('account_id',$account_ids) + ->orderBy('service_number') + ->with(['service']) + ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s (%s)',$o->service_name,$o->service->sid),'value'=>'/u/service/'.$o->id,'category'=>'Phone']); + $result->push(['name'=>sprintf('%s (%s)',$o->service->name,$o->service->lid),'value'=>'/u/service/'.$o->service_id,'category'=>'Phone']); } # Look for Domain Name foreach (Service\Domain::Search($request->input('term')) - ->whereIN('account_id',$account_ids) - ->orderBy('domain_name') - ->limit(10)->get() as $o) + ->whereIN('account_id',$account_ids) + ->orderBy('domain_name') + ->with(['service']) + ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s (%s)',$o->service_name,$o->service->sid),'value'=>'/u/service/'.$o->id,'category'=>'Domains']); + $result->push(['name'=>sprintf('%s (%s)',$o->service->name,$o->service->lid),'value'=>'/u/service/'.$o->service_id,'category'=>'Domains']); } if (Gate::any(['wholesaler'],new Payment)) { # Look for Payments foreach (Payment::Search($request->input('term')) - ->whereIN('account_id',$account_ids) - ->limit(10)->get() as $o) + ->whereIN('account_id',$account_ids) + ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s ($%s)',$o->id,number_format($o->total,2)),'value'=>'/a/payment/addedit/'.$o->id,'category'=>'Payments']); + $result->push(['name'=>sprintf('%s: %s $%s',$o->lid,$o->account->name,number_format($o->total,2)),'value'=>'/a/payment/addedit/'.$o->id,'category'=>'Payments']); } } diff --git a/app/Models/Account.php b/app/Models/Account.php index 3f9670b..5d03261 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -125,12 +125,6 @@ class Account extends Model implements IDs /* ATTRIBUTES */ - public function getActiveDisplayAttribute($value) - { - abort(500,'deprecated'); - return sprintf('%s',$this->active ? 'success' : 'danger',$this->active ? 'Active' : 'Inactive'); - } - /** * Get the address for the account * @@ -160,31 +154,7 @@ class Account extends Model implements IDs return $this->company ? 'Business' : 'Private'; } - /** - * Return the Admin URL to manage the account - * - * @return string - * @deprecated - */ - public function getUrlAdminAttribute(): string - { - abort(500,'deprecated'); - return sprintf('%s',$this->id,$this->account_id); - } - - /** - * Return the User URL to manage the account - * - * @return string - * @deprecated - */ - public function getUrlUserAttribute(): string - { - abort(500,'deprecated'); - return sprintf('%s',$this->id,$this->account_id); - } - - /* GENERAL METHODS */ + /* METHODS */ /** * Get the due invoices on an account @@ -197,19 +167,4 @@ class Account extends Model implements IDs return $item->active AND $item->due > 0; }); } - - /** - * Get the external account ID for a specific integration - * - * @param External\Integrations $o - * @return mixed - */ - public function ExternalAccounting(External\Integrations $o) - { - return $this - ->external() - ->where('id','=',$o->id) - ->where('site_id','=',$this->site_id) - ->first(); - } } \ No newline at end of file diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index cbb5ba8..e67934b 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -45,7 +45,18 @@ class Invoice extends Model implements IDs protected $dates = ['date_orig','due_date']; public $dateFormat = 'U'; + public const BILL_WEEKLY = 0; + public const BILL_MONTHLY = 1; + public const BILL_QUARTERLY = 2; + public const BILL_SEMI_YEARLY = 3; + public const BILL_YEARLY = 4; + public const BILL_TWOYEARS = 5; + public const BILL_THREEYEARS = 6; + public const BILL_FOURYEARS = 7; + public const BILL_FIVEYEARS = 8; + /* Our available billing periods */ + // @todo change this to a function - with billing_name()? public const billing_periods = [ 0 => [ 'name' => 'Weekly', diff --git a/app/Models/Product.php b/app/Models/Product.php index f14f900..89da219 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -28,7 +28,7 @@ use App\Traits\{ProductDetails,SiteID}; * + sid : System ID for product (part number) * + supplied : Supplier product provided for this offering * + supplier : Supplier for this offering - * + name : Brief Name for our product + * + name : Brief Name for our product // @todo we should change this to be consistent with service * + name_short : Product ID for our Product * + name_long : Long Name for our product * + billing_interval : Default Billing Interval diff --git a/app/Models/Product/Type.php b/app/Models/Product/Type.php index 72e0a0f..092fe92 100644 --- a/app/Models/Product/Type.php +++ b/app/Models/Product/Type.php @@ -9,7 +9,7 @@ use App\Traits\{OrderServiceOptions,SiteID}; /** * @todo These tables have a base_cost/setup_cost/contract_term columns - how is that different to the supplier_tables? - * @todo Ensure our terminology is consistent - we have a "cost", we "charge" clients. + * @todo Ensure our terminology is consistent - we have a "cost", we "charge" clients, and we have a "price" which is not official charges nor a cost. */ abstract class Type extends Model { diff --git a/app/Models/Service.php b/app/Models/Service.php index a7919e5..fe0721c 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -26,15 +26,18 @@ use App\Traits\ScopeServiceUserAuthorised; * * Attributes for services: * + additional_cost : Pending additional charges for this service (excluding setup) //@todo check all these are still valid - * + billing_cost : Charge for this service each invoice period + * + billing_charge : Charge for this service each invoice period // @todo change to "charge" * + billing_interval : The period that this service is billed for by default * + billing_interval_string : The period that this service is billed for by default as a name + * + category : The type of service this is, eg: broadband, phone * + contract_term : The term that this service must be active * + contract_end : The date that the contract ends for this service * + name : Service short name with service address * + name_short : Service Product short name, eg: phone number, domain name, certificate CN * + name_detail : Service Detail, eg: service_address + * + product : Our product that is providing this service * + sid : System ID for service + * + supplied : The model of the supplier's product used for this service. * * = Terminology: * - Offering, what product we supply (we make offerings from supplier's supplied products) - in the DB these are products/* @@ -44,7 +47,6 @@ use App\Traits\ScopeServiceUserAuthorised; * @package App\Models * @todo "Billing Start Date" = "connection date" for sub types?? */ -// @todo All the methods/attributes in this file need to be checked. class Service extends Model implements IDs { use HasFactory,ScopeServiceUserAuthorised; @@ -254,6 +256,28 @@ class Service extends Model implements IDs ], ]; + /* INTERFACES */ + + /** + * Service Local ID + * + * @return string + */ + public function getLIDattribute(): string + { + return sprintf('%05s',$this->id); + } + + /** + * Services System ID + * + * @return string + */ + public function getSIDAttribute(): string + { + return sprintf('%02s-%04s.%s',$this->site_id,$this->account_id,$this->getLIDattribute()); + } + /* RELATIONS */ /** @@ -304,7 +328,6 @@ class Service extends Model implements IDs /** * Invoices for this service - * */ public function invoices($active=TRUE) { @@ -342,17 +365,6 @@ class Service extends Model implements IDs return $this->belongsTo(Product::class); } - /** - * The site this service is configured for - * - * @todo It may be more appropriate to get this from the account->user attribute (ie: for mail actions) - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function site() - { - return $this->belongsTo(Site::class); - } - /** * Return a child model with details of the service * @@ -405,7 +417,7 @@ class Service extends Model implements IDs * * @param $query * @param string $term - * @return + * @return mixed */ public function scopeSearch($query,string $term) { @@ -415,27 +427,11 @@ class Service extends Model implements IDs /* ATTRIBUTES */ /** - * Name of the account for this service + * How much do we charge for this service, base on the current recur schedule * - * @return mixed - * @deprecated use $this->>account->name directly + * @return float */ - public function getAccountNameAttribute(): string - { - return $this->account->name; - } - - /** - * Return the auto billing details - * - * @return mixed - */ - public function getAutoPayAttribute() - { - return $this->billing; - } - - public function getBillingPriceAttribute(): float + public function getBillingChargeAttribute(): float { // @todo Temporary for services that dont have recur_schedule set. if (is_null($this->recur_schedule) OR is_null($this->product->getBaseChargeAttribute($this->recur_schedule,$this->account->group))) @@ -444,22 +440,6 @@ class Service extends Model implements IDs return $this->addTax(is_null($this->price) ? $this->product->getBaseChargeAttribute($this->recur_schedule,$this->account->group) : $this->price); } - public function getBillingMonthlyPriceAttribute(): float - { - $d = 0; - switch ($this->recur_schedule) { - case 0: $d = 12/52; break; - case 1: $d = 1; break; - case 2: $d = 3; break; - case 3: $d = 6; break; - case 4: $d = 12; break; - case 5: $d = 24; break; - case 6: $d = 36; break; - } - - return number_format($this->getBillingPriceAttribute()/$d,2); - } - /** * Return the service billing period * @@ -480,6 +460,78 @@ class Service extends Model implements IDs return Invoice::billing_name($this->getBillingIntervalAttribute()); } + /** + * Determine a monthly price for a service, even if it is billed at a different frequency + * + * @return float + * @throws Exception + */ + public function getBillingMonthlyPriceAttribute(): float + { + $d = 1; + switch ($this->recur_schedule) { + case Invoice::BILL_WEEKLY: + $d = 12/52; + break; + + case Invoice::BILL_MONTHLY: + $d = 1; + break; + + case Invoice::BILL_QUARTERLY: + $d = 3; + break; + + case Invoice::BILL_SEMI_YEARLY: + $d = 6; + break; + + case Invoice::BILL_YEARLY: + $d = 12; + break; + + case Invoice::BILL_TWOYEARS: + $d = 24; + break; + + case Invoice::BILL_THREEYEARS: + $d = 36; + break; + + case Invoice::BILL_FOURYEARS: + $d = 48; + break; + + case Invoice::BILL_FIVEYEARS: + $d = 60; + break; + + default: + throw new Exception('Unknown recur_schedule'); + } + + return number_format($this->getBillingChargeAttribute()/$d,2); + } + + /** + * Return the type of service is provided. eg: Broadband, Phone. + * + * @return string + */ + public function getCategoryAttribute(): string + { + switch ($x=$this->type->getTypeAttribute()) { + case 'ssl': + $type = 'SSL'; + break; + + default: + $type = ucfirst($x); + } + + return $type; + } + /** * The date the contract ends * @@ -509,13 +561,13 @@ class Service extends Model implements IDs /** * This function will determine the minimum contract term for a service, which is the maximum of - * this::type->contract_term, or the product->type->contract_term(); + * supplier->type->contract_term, or the product->type->contract_term; * * @return int */ public function getContractTermAttribute(): int { - return $this->product->type->supplied->contract_term ?: 0; + return $this->getSuppliedAttribute()->contract_term; } /** @@ -526,24 +578,22 @@ class Service extends Model implements IDs */ public function getExpiresAttribute(): string { + abort(500,'Not implemented'); return 'TBA'; } /** * Return the date for the next invoice * - * @todo Change date_next_invoice to connect_date/invoice_start_date * @return Carbon|string */ - public function getInvoiceNextAttribute() + public function getInvoiceNextAttribute(): \Carbon\Carbon { $last = $this->getInvoiceToAttribute(); - $date = $last + return $last ? $last->addDay() : ($this->date_next_invoice ? $this->date_next_invoice->clone() : ($this->start_at ?: Carbon::now())); - - return request()->wantsJson() ? $date->format('Y-m-d') : $date; } /** @@ -555,58 +605,65 @@ class Service extends Model implements IDs public function getInvoiceNextEndAttribute() { switch ($this->recur_schedule) { - // Weekly - case 0: $date = $this->product->price_recur_strict - ? $this->getInvoiceNextAttribute()->endOfWeek() - : $this->getInvoiceNextAttribute()->addWeek()->subDay(); + case Invoice::BILL_WEEKLY: + $date = $this->product->price_recur_strict + ? $this->getInvoiceNextAttribute()->endOfWeek() + : $this->getInvoiceNextAttribute()->addWeek()->subDay(); break; - // Monthly - case 1: + case Invoice::BILL_MONTHLY: $date = $this->product->price_recur_strict ? $this->getInvoiceNextAttribute()->endOfMonth() : $this->getInvoiceNextAttribute()->addMonth()->subDay(); break; - // Quarterly - case 2: + case Invoice::BILL_QUARTERLY: $date = $this->product->price_recur_strict ? $this->getInvoiceNextAttribute()->endOfQuarter() : $this->getInvoiceNextAttribute()->addQuarter()->subDay(); break; - // Half Yearly - case 3: + case Invoice::BILL_SEMI_YEARLY: $date = $this->product->price_recur_strict ? $this->getInvoiceNextAttribute()->endOfHalf() : $this->getInvoiceNextAttribute()->addQuarter(2)->subDay(); break; - // Yearly - case 4: + case Invoice::BILL_YEARLY: $date = $this->product->price_recur_strict ? $this->getInvoiceNextAttribute()->endOfYear() : $this->getInvoiceNextAttribute()->addYear()->subDay(); break; - // Two Yearly - case 5: - if (! $this->product->price_recur_strict) + case Invoice::BILL_TWOYEARS: + if (! $this->product->price_recur_strict) { $date = $this->getInvoiceNextAttribute()->addYear(2)->subDay(); - else { + + } else { $date = $this->getInvoiceNextAttribute()->addYear(2)->subDay()->endOfYear(); - if ($date->clone()->addDay()->year % 2) { + if ($date->clone()->addDay()->year%2) $date = $date->subYear(); - } } break; - // Three Yearly // NOTE: price_recur_strict ignored - case 6: $date = $this->getInvoiceNextAttribute()->addYear(3)->subDay(); break; + case Invoice::BILL_THREEYEARS: + $date = $this->getInvoiceNextAttribute()->addYear(3)->subDay(); + break; - default: throw new Exception('Unknown recur_schedule'); + // NOTE: price_recur_strict ignored + case Invoice::BILL_FOURYEARS: + $date = $this->getInvoiceNextAttribute()->addYear(4)->subDay(); + break; + + // NOTE: price_recur_strict ignored + case Invoice::BILL_FIVEYEARS: + $date = $this->getInvoiceNextAttribute()->addYear(5)->subDay(); + break; + + default: + throw new Exception('Unknown recur_schedule'); } // If the invoice has an end date, our invoice period shouldnt be greater than that. @@ -616,7 +673,13 @@ class Service extends Model implements IDs return $date; } - public function getInvoiceNextQuantityAttribute() + /** + * Determine how much quantity (at the charge rate) is requite for the next invoice + * + * @return float + * @throws Exception + */ + public function getInvoiceNextQuantityAttribute(): float { // If we are not rounding to the first day of the cycle, then it is always a full cycle if (! $this->product->price_recur_strict) @@ -625,42 +688,44 @@ class Service extends Model implements IDs $n = $this->invoice_next->diff($this->invoice_next_end)->days+1; switch ($this->recur_schedule) { - // Weekly - case 0: + case Invoice::BILL_WEEKLY: $d = $this->invoice_next->addWeek()->startOfWeek()->diff($this->invoice_next_end->startOfWeek())->days; break; - // Monthly - case 1: + case Invoice::BILL_MONTHLY: $d = $this->invoice_next->addMonth()->startOfMonth()->diff($this->invoice_next_end->startOfMonth())->days; break; - // Quarterly - case 2: + case Invoice::BILL_QUARTERLY: $d = $this->invoice_next->addQuarter()->startOfQuarter()->diff($this->invoice_next_end->startOfQuarter())->days; break; - // Half Yearly - case 3: + case Invoice::BILL_SEMI_YEARLY: $d = $this->invoice_next->addQuarter(2)->startOfHalf()->diff($this->invoice_next_end->startOfHalf())->days; break; - // Yearly - case 4: + case Invoice::BILL_YEARLY: $d = $this->invoice_next->addYear()->startOfYear()->diff($this->invoice_next_end->startOfYear())->days; break; - // Two Yearly - case 5: + case Invoice::BILL_TWOYEARS: $d = $this->invoice_next->addYear(2)->startOfYear()->diff($this->invoice_next_end->subyear(2))->days-1; break; - // Three Yearly - case 6: + case Invoice::BILL_THREEYEARS: $d = $this->invoice_next->addYear(3)->startOfYear()->diff($this->invoice_next_end->subyear(3))->days-1; break; - default: throw new Exception('Unknown recur_schedule'); + case Invoice::BILL_FOURYEARS: + $d = $this->invoice_next->addYear(3)->startOfYear()->diff($this->invoice_next_end->subyear(4))->days-1; + break; + + case Invoice::BILL_FIVEYEARS: + $d = $this->invoice_next->addYear(3)->startOfYear()->diff($this->invoice_next_end->subyear(5))->days-1; + break; + + default: + throw new Exception('Unknown recur_schedule'); } return round($n/$d,2); @@ -669,7 +734,7 @@ class Service extends Model implements IDs /** * Get the date that the service has been invoiced to */ - public function getInvoiceToAttribute() + public function getInvoiceToAttribute(): ?\Carbon\Carbon { $result = ($x=$this->invoice_items->filter(function($item) { return $item->item_type === 0;}))->count() ? $x->last()->date_stop @@ -684,15 +749,10 @@ class Service extends Model implements IDs } /** - * Service Local ID + * The full name for a service, comprised of the short name and the description * * @return string */ - public function getLIDattribute(): string - { - return sprintf('%05s',$this->id); - } - public function getNameAttribute(): string { return $this->getNameShortAttribute().(($x=$this->getNameDetailAttribute()) ? ': '.$x : ''); @@ -707,27 +767,28 @@ class Service extends Model implements IDs */ public function getNameShortAttribute() { - return $this->type ? $this->type->service_name : $this->id; - } - - public function getNameDetailAttribute() - { - return $this->type ? $this->type->service_address : $this->id; + return $this->type->getServiceNameAttribute() ?: 'SID:'.$this->sid; } /** - * @deprecated see getInvoiceNextAttribute() + * Return the service description. + * For: + * + Broadband, this is the service address + * + Domains, blank + * + Hosting, blank + * + SSL, blank + * + * @return string */ - public function getNextInvoiceAttribute() + public function getNameDetailAttribute() { - return $this->getInvoiceNextAttribute(); + return $this->type->getServiceDescriptionAttribute(); } /** * The product we supply for this service * * @return Model - * @todo Remove all references to product->type to use this method */ public function getOfferingAttribute(): Model { @@ -746,130 +807,31 @@ class Service extends Model implements IDs /** * Work out when this service has been paid to. - * - * @todo This might need to be optimised */ - public function getPaidToAttribute() + public function getPaidToAttribute(): Carbon { - foreach ($this->invoices->reverse() as $o) { - if ($o->due == 0) { - return $o->items - ->filter(function($item) { - return $item->item_type === 0; - }) - ->last() - ->date_stop; - } - } + foreach ($this->invoices->reverse() as $o) + if ($o->due == 0) + break; + + return $o->items + ->filter(function($item) { + return $item->item_type === 0; + }) + ->last() + ->date_stop; } /** - * Get the Product's Category for this service + * Return the billing recurring configuration for this service * - * @deprecated use product->getProductTypeAttribute() directly + * @param $value + * @return int */ - public function getProductCategoryAttribute(): string - { - return $this->product->getProductTypeAttribute(); - } - - /** - * Get the Product's Short Name for the service - * - * @return string - * @deprecated use product->name directly - */ - public function getProductNameAttribute(): string - { - return $this->product->getNameAttribute(); - } - public function getRecurScheduleAttribute($value): int { - // If recur_schedule not set, default to 2 - return $value ?? 2; - } - - /** - * @deprecated see getSIDAttribute() - */ - public function getServiceIdAttribute(): string - { - return $this->getSIDAttribute(); - } - - /** - * @deprecated see getUrlUserAttribute() - */ - public function getServiceIdUrlAttribute() - { - return $this->getUrlUserAttribute(); - } - - /** - * @deprecated see getServiceIdAttribute() - */ - public function getServiceNumberAttribute() - { - return $this->getSIDAttribute(); - } - - /** - * Services System ID - * - * @return string - */ - public function getSIDAttribute(): string - { - return sprintf('%02s-%04s.%s',$this->site_id,$this->account_id,$this->getLIDattribute()); - } - - /** - * Return the service description. - * For: - * + Broadband, this is the service address - * + Domains, blank - * + Hosting, blank - * + SSL, blank - * - * @return string - */ - public function getSDescAttribute(): string - { - return ($this->type AND $this->type->service_description) - ? $this->type->service_description - : 'Service Description NOT Defined for :'.($this->type ? $this->type->type : $this->id); - } - - /** - * Return the service name. - * For: - * + Broadband, this is the service number - * + Domains, this is the full domain name - * + Hosting, this is the full domain name - * + SSL, this is the DN - * - * @return string - */ - public function getSNameAttribute(): string - { - return ($this->type AND $this->type->service_name) - ? $this->type->service_name - : 'Service Name NOT Defined for :'.($this->type ? $this->type->type : $this->id); - } - - /** - * Return the service product type - * This is used for view specific details - * - * @return string - * @todo I think this can be removed - and dynamically determined - */ - public function getSTypeAttribute(): string - { - switch($this->product->model) { - default: return $this->type->type; - } + // If recur_schedule not set, default to quarterly + return $value ?? Invoice::BILL_QUARTERLY; } /** @@ -886,21 +848,10 @@ class Service extends Model implements IDs } /** - * Return the detailed order Status, with order reference numbers. - * - * @return string - */ - public function getStatusDetailAttribute(): string - { - return in_array($this->order_status,['ORDER-SENT','ORDER-HOLD','ORDERED']) - ? sprintf('%s: #%s',$this->order_status,Arr::get($this->order_info,'order_reference','Unknown')) - : ''; - } - - /** - * Return a HTML status box + * Return an HTML status box * * @return string + * @todo Add in the other status' */ public function getStatusHTMLAttribute(): string { @@ -925,60 +876,15 @@ class Service extends Model implements IDs : $this->status; } - /** - * Return the type of service is provided. + * Return the product that supplies this service + * ie: product/* * - * @return string + * @return Model */ - public function getServiceTypeAttribute(): string + public function getSuppliedAttribute(): Model { - // @todo This is temporary, while we clean the database. - return ($this->product->type && $this->product->type->supplied) ? $this->product->type->supplied->getTypeAttribute() : '** TBA **'; - } - - /** - * Get the service providers offering that we are providing for this service - * - * @return Model|null - */ - public function getSupplierProductAttribute(): ?Model - { - dd($this->product,$this->product->type,$this->product->type->supplied); - } - - /** - * URL used by an admin to administer the record - * - * @return string - */ - public function getUrlAdminAttribute(): string - { - return sprintf('%s',$this->id,$this->service_id); - } - - /** - * URL used by an user to see the record - * - * @return string - */ - public function getUrlUserAttribute(): string - { - return sprintf('%s',$this->id,$this->service_id); - } - - /* SETTERS */ - - // @todo is this required? - public function setDateOrigAttribute($value) - { - $this->attributes['date_orig'] = $value->timestamp; - } - - // @todo is this required? - public function setDateLastAttribute($value) - { - $this->attributes['date_last'] = $value->timestamp; + return $this->getOfferingAttribute()->supplied; } /* METHODS */ @@ -1114,6 +1020,19 @@ class Service extends Model implements IDs : collect(); } + /** + * Add applicable tax to the cost + * + * @todo This needs to be calculated, not fixed at 1.1 + * @todo move all tax calculations into product + * @param float $value + * @return float + */ + private function addTax(float $value): float + { + return round($value*1.1,2); + } + private function getOrderInfoValue(string $key): ?string { return $this->order_info ? $this->order_info->get($key) : NULL; @@ -1160,27 +1079,6 @@ class Service extends Model implements IDs return collect($result); } - /** - * Add applicable tax to the cost - * - * @todo This needs to be calculated, not fixed at 1.1 - * @param float $value - * @return float - */ - private function addTax(float $value): float - { - return round($value*1.1,2); - } - - public function invoices_due(): DatabaseCollection - { - $this->load('invoice_items.invoice'); - - return $this->invoice_items->filter(function($item) { - return $item->invoice->due > 0; - }); - } - /** * Does this service have traffic data to be graphed * @@ -1207,6 +1105,7 @@ class Service extends Model implements IDs * * @param string $role * @return bool + * @todo Can we use the gates to achieve this? */ public function isAuthorised(string $role): bool { @@ -1263,17 +1162,16 @@ class Service extends Model implements IDs /** * Should this service be invoiced soon * - * @todo get the number of days from account setup - * @todo Use self::isBilled(); + * @param int $days * @return bool */ public function isInvoiceDueSoon($days=30): bool { - return (! $this->external_billing) AND (! $this->suspend_billing) AND $this->getInvoiceNextAttribute()->lessThan(now()->addDays($days)); + return $this->isBilled() AND $this->getInvoiceNextAttribute()->lessThan(now()->addDays($days)); } /** - * Identify if a service is being ordered + * Identify if a service is being ordered, ie: not active yet nor cancelled * * @return bool */ @@ -1288,14 +1186,14 @@ class Service extends Model implements IDs * Generate a collection of invoice_item objects that will be billed for the next invoice * * @param bool $future Next item to be billed (not in the next x days) + * @param Carbon|null $billdate * @return Collection * @throws Exception - * @todo Use self::isBilled(); * @todo This query is expensive. */ public function next_invoice_items(bool $future,Carbon $billdate=NULL): Collection { - if ($this->wasCancelled() OR $this->suspend_billing OR $this->external_billing OR (! $future AND ! $this->active)) + if ($this->wasCancelled() OR (! $this->isBilled()) OR (! $future AND ! $this->active)) return collect(); if (is_null($billdate)) @@ -1378,43 +1276,6 @@ class Service extends Model implements IDs return $this->invoice_items->filter(function($item) { return ! $item->exists; }); } - /** - * This function will return the associated service model for the product type - * @deprecated use $this->type - */ - private function ServicePlugin() - { - abort(500,'deprecated'); - // @todo: All services should be linked to a product. This might require data cleaning for old services not linked to a product. - if (! is_object($this->product)) - return NULL; - - switch ($this->product->prod_plugin_file) - { - case 'BROADBAND': return $this->service_broadband; - case 'DOMAIN': return $this->service_domain; - case 'HOST': return $this->service_host; - case 'SSL': return $this->service_ssl; - case 'PHONE': return $this->service_voip; - - default: return NULL; - } - } - - /** - * Store order info details - * - * @param string $key - * @param string $value - */ - public function setOrderInfo(string $key,?string $value): void - { - $x = is_null($this->order_info) ? collect() : $this->order_info; - $x->put($key,$value); - - $this->order_info = $x; - } - /** * Service that was cancelled or never provisioned * @@ -1424,4 +1285,4 @@ class Service extends Model implements IDs { return in_array($this->order_status,self::INACTIVE_STATUS); } -} +} \ No newline at end of file diff --git a/resources/views/email/admin/order/approve.blade.php b/resources/views/email/admin/order/approve.blade.php index 3a9aeb4..83b73b0 100644 --- a/resources/views/email/admin/order/approve.blade.php +++ b/resources/views/email/admin/order/approve.blade.php @@ -5,14 +5,14 @@ Please order the following... | Service | Details | | :---------- | :---------------- | | Logged User | {{ Auth::user()->id }} | -| Account | {{ $service->account_name }} | +| Account | {{ $service->account->name }} | | Service ID | {{ $service->sid }} | -| Product | {{ $service->product_name }} | -@switch($service->product_category) -@case('BROADBAND') +| Product | {{ $service->product->name }} | +@switch($service->category) +@case('Broadband') | Address | {{ $service->type->service_address }} | @break; -@case('PHONE') +@case('Phone') | Number | {{ $service->type->service_number }} | | Supplier Details | {{ $service->order_info->join(':') }} | @break; diff --git a/resources/views/email/admin/order/reject.blade.php b/resources/views/email/admin/order/reject.blade.php index 660678f..206d780 100644 --- a/resources/views/email/admin/order/reject.blade.php +++ b/resources/views/email/admin/order/reject.blade.php @@ -6,9 +6,9 @@ @component('mail::table') | Service | Details | | :---------- | :---------------- | -| Account | {{ $service->account_name }} | +| Account | {{ $service->account->name }} | | Service ID | {{ $service->sid }} | -| Product | {{ $service->product_name }} | +| Product | {{ $service->product->name }} | @switch($service->category) @case('BROADBAND') | Address | {{ is_object($service->type) ? $service->type->service_address : 'Not Supplied' }} | diff --git a/resources/views/email/admin/service/cancel.blade.php b/resources/views/email/admin/service/cancel.blade.php index d78301a..8447691 100644 --- a/resources/views/email/admin/service/cancel.blade.php +++ b/resources/views/email/admin/service/cancel.blade.php @@ -5,14 +5,14 @@ Please cancel the following... | Service | Details | | :---------- | :---------------- | | Logged User | {{ Auth::user()->id }} | -| Account | {{ $service->account_name }} | +| Account | {{ $service->account->name }} | | Service ID | {{ $service->sid }} | -| Product | {{ $service->product_name }} | -@switch($service->product_category) -@case('BROADBAND') +| Product | {{ $service->product->name }} | +@switch($service->category) +@case('Broadband') | Address | {{ $service->type->service_address }} | @break; -@case('PHONE') +@case('Phone') | Number | {{ $service->type->service_number }} | | Supplier Details | {{ $service->order_info->join(':') }} | @break; diff --git a/resources/views/email/admin/service/change.blade.php b/resources/views/email/admin/service/change.blade.php index 7ef557a..eae5997 100644 --- a/resources/views/email/admin/service/change.blade.php +++ b/resources/views/email/admin/service/change.blade.php @@ -5,14 +5,14 @@ Please change the following... | Service | Details | | :---------- | :---------------- | | Logged User | {{ Auth::user()->id }} -| Account | {{ $service->account_name }} | +| Account | {{ $service->account->name }} | | Service ID | {{ $service->sid }} | -| Product | {{ $service->product_name }} | -@switch($service->product_category) -@case('BROADBAND') +| Product | {{ $service->product->name }} | +@switch($service->category) +@case('Broadband') | Address | {{ $service->type->service_address }} | @break; -@case('PHONE') +@case('Phone') | Number | {{ $service->type->service_number }} | | Supplier Details | {{ $service->order_info->join(':') }} | @break; diff --git a/resources/views/theme/backend/adminlte/a/service/widgets/update.blade.php b/resources/views/theme/backend/adminlte/a/service/widgets/update.blade.php index ffbbf8a..57c879a 100644 --- a/resources/views/theme/backend/adminlte/a/service/widgets/update.blade.php +++ b/resources/views/theme/backend/adminlte/a/service/widgets/update.blade.php @@ -5,7 +5,7 @@
@csrf - @includeIf('a.service.widgets.'.$o->stype.'.update',['o'=>$o->type]) + @includeIf('a.service.widgets.'.$o->type->type.'.update',['o'=>$o->type])
diff --git a/resources/views/theme/backend/adminlte/common/service/widget/info.blade.php b/resources/views/theme/backend/adminlte/common/service/widget/info.blade.php deleted file mode 100644 index a4a3736..0000000 --- a/resources/views/theme/backend/adminlte/common/service/widget/info.blade.php +++ /dev/null @@ -1,38 +0,0 @@ -
-
- Service Information -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account{{ $o->account->name }}
Active{!! $o->status_html !!}
Billing Period{{ $o->billing_period }}
Billing Amount${{ number_format($o->billing_price,2) }}
Invoiced To{{ $o->invoice_to ? $o->invoice_to->format('Y-m-d') : '' }}
Next Invoice{{ $o->invoice_next ? $o->invoice_next->format('Y-m-d') : '' }}
Current Invoices Due${{ number_format($o->invoices_due()->sum('due'),2) }} ({{ $o->invoices_due()->count() }})
-
-
\ No newline at end of file diff --git a/resources/views/theme/backend/adminlte/r/service/domain/list.blade.php b/resources/views/theme/backend/adminlte/r/service/domain/list.blade.php index 3f767ac..850a6c2 100644 --- a/resources/views/theme/backend/adminlte/r/service/domain/list.blade.php +++ b/resources/views/theme/backend/adminlte/r/service/domain/list.blade.php @@ -41,7 +41,7 @@ {{ $oo->service->sid }} {{ $oo->service->account->name }} {{ $oo->service->product->name }} - {{ $oo->service_name }} + {{ $oo->service->name }} {{ $oo->service_expire ? $oo->service_expire->format('Y-m-d') : '-' }} {{ $oo->registrar->name }} {{ $oo->registrar_ns }} diff --git a/resources/views/theme/backend/adminlte/r/service/email/list.blade.php b/resources/views/theme/backend/adminlte/r/service/email/list.blade.php index 862a300..8312834 100644 --- a/resources/views/theme/backend/adminlte/r/service/email/list.blade.php +++ b/resources/views/theme/backend/adminlte/r/service/email/list.blade.php @@ -43,7 +43,7 @@ {{ $oo->service->sid }} {{ $oo->service->account->name }} {{ $oo->service->product->name }} - {{ $oo->service_name }} + {{ $oo->service->name }} {{ $oo->service_expire ? $oo->service_expire->format('Y-m-d') : '-' }} {{ $oo->service->product->supplier->name }} {{ $oo->admin_url }} diff --git a/resources/views/theme/backend/adminlte/r/service/host/list.blade.php b/resources/views/theme/backend/adminlte/r/service/host/list.blade.php index 4ca401a..9f8db1f 100644 --- a/resources/views/theme/backend/adminlte/r/service/host/list.blade.php +++ b/resources/views/theme/backend/adminlte/r/service/host/list.blade.php @@ -40,7 +40,7 @@ {{ $oo->service->sid }} {{ $oo->service->account->name }} {{ $oo->service->product->name }} - {{ $oo->service_name }} + {{ $oo->service->name }} {{ $oo->service_expire ? $oo->service_expire->format('Y-m-d') : '-' }} {{ $oo->service->product->supplier->name }} @if ($oo->service->isBilled()) {{ $oo->service->invoice_next->format('Y-m-d') }} @else - @endif diff --git a/resources/views/theme/backend/adminlte/r/service/order/provision_plan.blade.php b/resources/views/theme/backend/adminlte/r/service/order/provision_plan.blade.php index 15a67d8..b6f9c8d 100644 --- a/resources/views/theme/backend/adminlte/r/service/order/provision_plan.blade.php +++ b/resources/views/theme/backend/adminlte/r/service/order/provision_plan.blade.php @@ -11,7 +11,7 @@ Service: {{ $o->sid }} {{ $o->product->name }} @endsection @section('contentheader_description') - {{ $o->sname }}: {{ $o->sdesc }} + {{ $o->name }} @endsection @section('main-content') @@ -38,7 +38,7 @@
- @includeIf('u.service.widgets.'.$o->stype.'.order',['o'=>$o->type]) + @includeIf('u.service.widgets.'.$o->type->type.'.order',['o'=>$o->type])
diff --git a/resources/views/theme/backend/adminlte/r/service/order/sent.blade.php b/resources/views/theme/backend/adminlte/r/service/order/sent.blade.php index aa3e377..78a26bb 100644 --- a/resources/views/theme/backend/adminlte/r/service/order/sent.blade.php +++ b/resources/views/theme/backend/adminlte/r/service/order/sent.blade.php @@ -11,7 +11,7 @@ Service: {{ $o->sid }} {{ $o->product->name }} @endsection @section('contentheader_description') - {{ $o->sname }}: {{ $o->sdesc }} + {{ $o->name }} @endsection @section('main-content') @@ -38,7 +38,7 @@
- @includeIf('u.service.widgets.'.$o->stype.'.order',['o'=>$o->type]) + @includeIf('u.service.widgets.'.$o->type->type.'.order',['o'=>$o->type])
diff --git a/resources/views/theme/backend/adminlte/u/invoice/widgets/next.blade.php b/resources/views/theme/backend/adminlte/u/invoice/widgets/next.blade.php index 8b4d0e9..1c4af45 100644 --- a/resources/views/theme/backend/adminlte/u/invoice/widgets/next.blade.php +++ b/resources/views/theme/backend/adminlte/u/invoice/widgets/next.blade.php @@ -13,7 +13,7 @@ @foreach ($oo->groupBy('service_id') as $ooo) {{ $ooo->first()->service->sid }} - {{ $ooo->first()->service->sname }}: {{ $ooo->first()->service->sdesc }} + {{ $ooo->first()->service->name }} @foreach ($ooo as $io) diff --git a/resources/views/theme/backend/adminlte/u/service/cancel_request.blade.php b/resources/views/theme/backend/adminlte/u/service/cancel_request.blade.php index 66c78a5..5dccd9c 100644 --- a/resources/views/theme/backend/adminlte/u/service/cancel_request.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/cancel_request.blade.php @@ -11,7 +11,7 @@ Service: {{ $o->sid }} {{ $o->product->name }} @endsection @section('contentheader_description') - {{ $o->sname }}: {{ $o->sdesc }} + {{ $o->name }} @endsection @section('main-content') @@ -44,7 +44,7 @@
{{-- - @includeIf('u.service.widgets.'.$o->stype.'.order',['o'=>$o->type]) + @includeIf('u.service.widgets.'.$o->type->type.'.order',['o'=>$o->type]) --}}
diff --git a/resources/views/theme/backend/adminlte/u/service/change_request.blade.php b/resources/views/theme/backend/adminlte/u/service/change_request.blade.php index 0e73b04..ee1cb5d 100644 --- a/resources/views/theme/backend/adminlte/u/service/change_request.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/change_request.blade.php @@ -11,7 +11,7 @@ Service: {{ $o->sid }} {{ $o->product->name }} @endsection @section('contentheader_description') - {{ $o->sname }}: {{ $o->sdesc }} + {{ $o->name }} @endsection @section('main-content') @@ -43,7 +43,7 @@
- @includeIf('u.service.widgets.'.$o->stype.'.change',['o'=>$o->type]) + @includeIf('u.service.widgets.'.$o->type->type.'.change',['o'=>$o->type])
diff --git a/resources/views/theme/backend/adminlte/u/service/home.blade.php b/resources/views/theme/backend/adminlte/u/service/home.blade.php index ea4b2ed..0583940 100644 --- a/resources/views/theme/backend/adminlte/u/service/home.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/home.blade.php @@ -11,14 +11,15 @@ Service: {{ $o->sid }} {{ $o->product->name }} @endsection @section('contentheader_description') - {{ $o->sname }}: {{ $o->sdesc }} + {{ $o->name }} @endsection @section('main-content')
+
- @includeIf('u.service.widgets.'.$o->stype.'.details',['o'=>$o->type]) + @includeIf('u.service.widgets.'.$o->type->type.'.details',['o'=>$o->type]) @include('u.service.widgets.information')
@@ -77,7 +78,7 @@ @if ($o->hasUsage())
@if ($o->type->usage(30)->count()) - @include('u.service.widgets.'.$o->stype.'.usagegraph',['o'=>$o->type]) + @include('u.service.widgets.'.$o->type->type.'.usagegraph',['o'=>$o->type]) @endif
@endif diff --git a/resources/views/theme/backend/adminlte/u/service/widgets/active.blade.php b/resources/views/theme/backend/adminlte/u/service/widgets/active.blade.php index a58c7e9..071aa6e 100644 --- a/resources/views/theme/backend/adminlte/u/service/widgets/active.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/widgets/active.blade.php @@ -22,10 +22,10 @@ @foreach ($o->services as $oo) {{ $oo->sid }} - {{ $oo->service_type }} + {{ $oo->category }} {{ $oo->name_short }} {{ $oo->product->name }} - {{ $oo->external_billing ? '-' : $oo->next_invoice->format('Y-m-d') }} + {{ $oo->external_billing ? '-' : $oo->invoice_next->format('Y-m-d') }} @endforeach diff --git a/resources/views/theme/backend/adminlte/u/service/widgets/broadband/details.blade.php b/resources/views/theme/backend/adminlte/u/service/widgets/broadband/details.blade.php index 5de961d..30344f1 100644 --- a/resources/views/theme/backend/adminlte/u/service/widgets/broadband/details.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/widgets/broadband/details.blade.php @@ -16,11 +16,11 @@ - + - + diff --git a/resources/views/theme/backend/adminlte/u/service/widgets/domain/details.blade.php b/resources/views/theme/backend/adminlte/u/service/widgets/domain/details.blade.php index 3e08d59..3b33239 100644 --- a/resources/views/theme/backend/adminlte/u/service/widgets/domain/details.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/widgets/domain/details.blade.php @@ -16,7 +16,7 @@
Address{{ $o->service_description }}{{ $o->service_address }}
Service Number{{ $o->service_name }}{{ $o->service_number }}
Service Username
- + diff --git a/resources/views/theme/backend/adminlte/u/service/widgets/email/details.blade.php b/resources/views/theme/backend/adminlte/u/service/widgets/email/details.blade.php index faf3f96..650255e 100644 --- a/resources/views/theme/backend/adminlte/u/service/widgets/email/details.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/widgets/email/details.blade.php @@ -16,7 +16,7 @@
Domain Name{{ $o->service_name }}{{ $o->service->name }}
Registrar URL
- + @if($o->service_connect_date) diff --git a/resources/views/theme/backend/adminlte/u/service/widgets/host/details.blade.php b/resources/views/theme/backend/adminlte/u/service/widgets/host/details.blade.php index 6c56394..504f6df 100644 --- a/resources/views/theme/backend/adminlte/u/service/widgets/host/details.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/widgets/host/details.blade.php @@ -16,7 +16,7 @@
Domain Name{{ $o->service_name }}{{ $o->service->name }}
- + @if($o->provider->whitelabel_url) diff --git a/resources/views/theme/backend/adminlte/u/service/widgets/information.blade.php b/resources/views/theme/backend/adminlte/u/service/widgets/information.blade.php index 56b379f..857b427 100644 --- a/resources/views/theme/backend/adminlte/u/service/widgets/information.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/widgets/information.blade.php @@ -67,7 +67,7 @@ - + @elseif($o->wasCancelled()) diff --git a/resources/views/theme/backend/adminlte/u/service/widgets/phone/details.blade.php b/resources/views/theme/backend/adminlte/u/service/widgets/phone/details.blade.php index 541eccc..d8ef762 100644 --- a/resources/views/theme/backend/adminlte/u/service/widgets/phone/details.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/widgets/phone/details.blade.php @@ -16,11 +16,11 @@
Domain Name{{ $o->service_name }}{{ $o->service->name }}
Payment Method@if ($o->autopay)Direct Debit @else Invoice @endif@if ($o->billing)Direct Debit @else Invoice @endif
- + - + diff --git a/resources/views/theme/backend/adminlte/u/service/widgets/ssl/details.blade.php b/resources/views/theme/backend/adminlte/u/service/widgets/ssl/details.blade.php index 756078e..a4c7607 100644 --- a/resources/views/theme/backend/adminlte/u/service/widgets/ssl/details.blade.php +++ b/resources/views/theme/backend/adminlte/u/service/widgets/ssl/details.blade.php @@ -15,7 +15,7 @@
Address{{ $o->service_description }}{{ $o->service_address }}
Service Number{{ $o->service_name }}{{ $o->service_number }}
Service Username
- +
Cert{{ $o->service_description }}{{ $o->name_detail }}
Cancel Notice