diff --git a/app/Console/Commands/ServiceList.php b/app/Console/Commands/ServiceList.php index 601e321..8e1d946 100644 --- a/app/Console/Commands/ServiceList.php +++ b/app/Console/Commands/ServiceList.php @@ -33,7 +33,7 @@ class ServiceList extends Command */ public function handle() { - $header = '|%13s|%-10s|%-35s|%-40s|%8s|%10s|%15s|%10s|%10s|%12s|%14s|'; + $header = '|%13s|%-14s|%-35s|%-40s|%8s|%17s|%12s|%12s|%12s|%12s|%14s|'; $this->warn(sprintf($header, 'ID', @@ -58,24 +58,24 @@ class ServiceList extends Command if ($this->option('type') AND ($o->product->getProductTypeAttribute() !== $this->option('type'))) continue; - $c = $o->invoice_items->filter(function($item) {return $item->item_type === 0; })->sortby('date_start')->first(); + $c = $o->invoice_items->filter(function($item) {return $item->item_type === 0; })->sortby('start_at')->first(); - if ($this->option('fix') AND ! $o->date_start AND $c AND $c->date_start AND $o->type AND $o->type->service_connect_date AND $c->date_start->format('Y-m-d') == $o->type->service_connect_date->format('Y-m-d')) { - $o->date_start = $o->type->service_connect_date; + if ($this->option('fix') AND ! $o->start_at AND $c AND $c->start_at AND $o->type AND $o->type->connect_at AND $c->start_at->format('Y-m-d') == $o->type->connect_at->format('Y-m-d')) { + $o->start_at = $o->type->connect_at; $o->save(); } $this->info(sprintf($header, $o->sid, $o->product->getProductTypeAttribute(), - $o->product->getNameAttribute(), - $o->name_short, + substr($o->product->getNameAttribute(),0,35), + substr($o->name_short,0,40), $o->active ? 'active' : 'inactive', $o->status, $o->invoice_next ? $o->invoice_next->format('Y-m-d') : NULL, - $o->date_start ? $o->date_start->format('Y-m-d') : NULL, - $o->date_end ? $o->date_end->format('Y-m-d') : NULL, - ($o->type AND $o->type->service_connect_date) ? $o->type->service_connect_date->format('Y-m-d') : NULL, + $o->start_at ? $o->start_at->format('Y-m-d') : NULL, + $o->stop_at ? $o->stop_at->format('Y-m-d') : NULL, + ($o->type AND $o->type->connect_at) ? $o->type->connect_at->format('Y-m-d') : NULL, ($c && $c->date_start) ? $c->date_start->format('Y-m-d') : NULL, )); } diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 7a11382..ea34afa 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -28,7 +28,7 @@ class AdminController extends Controller $request->validate([ 'account_id' => 'required|exists:accounts,id', 'charge_date' => 'required|date', - 'service_id' => 'required|exists:ab_service,id', + 'service_id' => 'required|exists:services,id', 'quantity' => 'required|numeric|not_in:0', 'amount' => 'required|numeric|min:0.01', 'sweep_type' => 'required|numeric|in:'.implode(',',array_keys(Charge::sweep)), diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index 929bf57..faebccf 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -20,7 +20,7 @@ class ProductController extends Controller { switch ($request->type) { case 'App\Models\Product\Broadband': - return Product\Broadband::select(['id','supplier_broadband_id']) + return Product\Broadband::select(['id','supplier_item_id']) ->with(['supplied.supplier_detail.supplier']) ->get() ->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier_detail->supplier->name,$item->supplied->name)]; }) @@ -28,7 +28,7 @@ class ProductController extends Controller ->values(); case 'App\Models\Product\Email': - return Product\Email::select(['id','supplier_email_id']) + return Product\Email::select(['id','supplier_item_id']) ->with(['supplied.supplier_detail.supplier']) ->get() ->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier_detail->supplier->name,$item->supplied->name)]; }) @@ -36,7 +36,7 @@ class ProductController extends Controller ->values(); case 'App\Models\Product\Host': - return Product\Host::select(['id','supplier_host_id']) + return Product\Host::select(['id','supplier_item_id']) ->with(['supplied.supplier_detail.supplier']) ->get() ->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier_detail->supplier->name,$item->supplied->name)]; }) diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 4897e44..114fd77 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -7,7 +7,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Gate; -use App\Models\{Account,Invoice,Payment,Service,Service\Adsl,Service\Voip,User}; +use App\Models\{Account,Invoice,Payment,Service,Service\Broadband,Service\Phone,User}; class SearchController extends Controller { @@ -65,8 +65,8 @@ class SearchController extends Controller $result->push(['name'=>sprintf('%s: %s',$o->sid,$o->account->name),'value'=>'/u/invoice/'.$o->id,'category'=>'Invoices']); } - # Look for an ADSL/NBN Service - foreach (Service\Broadband::Search($request->input('term')) + # Look for an Broadband Service + foreach (Broadband::Search($request->input('term')) ->whereIN('account_id',$accounts) ->orderBy('service_number') ->limit(10)->get() as $o) @@ -74,13 +74,13 @@ class SearchController extends Controller $result->push(['name'=>sprintf('%s (%s)',$o->service_name,$o->service->sid),'value'=>'/u/service/'.$o->id,'category'=>'Broadband']); } - # Look for an VOIP Service - foreach (Voip::Search($request->input('term')) + # Look for an Phone Service + foreach (Phone::Search($request->input('term')) ->whereIN('account_id',$accounts) ->orderBy('service_number') ->limit(10)->get() as $o) { - $result->push(['name'=>sprintf('%s (%s)',$o->service_name,$o->service->sid),'value'=>'/u/service/'.$o->id,'category'=>'VOIP']); + $result->push(['name'=>sprintf('%s (%s)',$o->service_name,$o->service->sid),'value'=>'/u/service/'.$o->id,'category'=>'Phone']); } # Look for Domain Name diff --git a/app/Http/Controllers/ServiceController.php b/app/Http/Controllers/ServiceController.php index 60f6426..a81a59d 100644 --- a/app/Http/Controllers/ServiceController.php +++ b/app/Http/Controllers/ServiceController.php @@ -246,8 +246,8 @@ class ServiceController extends Controller { $o = Service\Domain::serviceActive() ->serviceUserAuthorised(Auth::user()) - ->select('service_domains.*') - ->join('ab_service',['ab_service.id'=>'service_domains.service_id']) + ->select('service_domain.*') + ->join('services',['services.id'=>'service_domain.service_id']) ->with(['service.account','registrar']) ->get(); @@ -260,8 +260,8 @@ class ServiceController extends Controller // @todo Need to add the with path when calculating next_billed and price $o = Service\Email::serviceActive() ->serviceUserAuthorised(Auth::user()) - ->select('service_emails.*') - ->join('ab_service',['ab_service.id'=>'service_emails.service_id']) + ->select('service_email.*') + ->join('services',['services.id'=>'service_email.service_id']) ->with(['service.account','service.product.type.supplied.supplier_detail.supplier','tld']) ->get(); @@ -274,8 +274,8 @@ class ServiceController extends Controller // @todo Need to add the with path when calculating next_billed and price $o = Service\Host::serviceActive() ->serviceUserAuthorised(Auth::user()) - ->select('ab_service__hosting.*') - ->join('ab_service',['ab_service.id'=>'ab_service__hosting.service_id']) + ->select('service_host.*') + ->join('services',['services.id'=>'service_host.service_id']) ->with(['service.account','service.product.type.supplied.supplier_detail.supplier','tld']) ->get(); diff --git a/app/Interfaces/ServiceItem.php b/app/Interfaces/ServiceItem.php index 7146c32..1a58feb 100644 --- a/app/Interfaces/ServiceItem.php +++ b/app/Interfaces/ServiceItem.php @@ -6,6 +6,13 @@ use Carbon\Carbon; interface ServiceItem { + /** + * Months the service is contracted for. + * + * @return int + */ + public function getContractTermAttribute(): int; + /** * Return the Service Description. * @@ -16,7 +23,7 @@ interface ServiceItem /** * Date the service expires */ - public function getServiceExpireAttribute(): Carbon; + public function getServiceExpireAttribute(): ?Carbon; /** * Return the Service Name. @@ -25,6 +32,13 @@ interface ServiceItem */ public function getServiceNameAttribute(): string; + /** + * Has this service expired + * + * @return bool + */ + public function hasExpired(): bool; + /** * Is this service in a contract * diff --git a/app/Jobs/BroadbandTraffic.php b/app/Jobs/BroadbandTraffic.php index 77fed58..03a90f7 100644 --- a/app/Jobs/BroadbandTraffic.php +++ b/app/Jobs/BroadbandTraffic.php @@ -90,11 +90,11 @@ final class BroadbandTraffic implements ShouldQueue // Find the right service dependant on the dates we supplied the service $oo = Adsl::where('service_username',$row[$o->getColumnKey('Login')]) ->select(DB::raw('ab_service__adsl.*')) - ->join('ab_service','ab_service.id','=','service_id') - ->where('ab_service.date_start','<=',$date->format('U')) + ->join('services','services.id','=','service_id') + ->where('services.start_at','<=',$date) ->where(function($query) use ($date) { - $query->whereNULL('ab_service.date_end') - ->orWhere('ab_service.date_end','<=',$date->format('U')); + $query->whereNULL('services.stop_at') + ->orWhere('services.stop_at','<=',$date); }) ->get(); diff --git a/app/Mail/CancelRequest.php b/app/Mail/CancelRequest.php index a0f63a2..33b8417 100644 --- a/app/Mail/CancelRequest.php +++ b/app/Mail/CancelRequest.php @@ -36,12 +36,12 @@ class CancelRequest extends Mailable public function build() { switch (get_class($this->service->type)) { - case 'App\Models\Service\Adsl': - $subject = sprintf('CANCEL NBN: %s',$this->service->type->service_address); + case 'App\Models\Service\Broadband': + $subject = sprintf('Cancel BROADBAND: %s',$this->service->type->service_address); break; - case 'App\Models\Service\Voip': - $subject = sprintf('CANCEL VOIP: %s',$this->service->type->service_number); + case 'App\Models\Service\Phone': + $subject = sprintf('Cancel PHONE: %s',$this->service->type->service_number); break; default: diff --git a/app/Mail/ChangeRequest.php b/app/Mail/ChangeRequest.php index 25cf2c5..d7cb383 100644 --- a/app/Mail/ChangeRequest.php +++ b/app/Mail/ChangeRequest.php @@ -36,12 +36,12 @@ class ChangeRequest extends Mailable public function build() { switch (get_class($this->service->type)) { - case 'App\Models\Service\Adsl': - $subject = sprintf('Change NBN: %s',$this->service->type->service_address); + case 'App\Models\Service\Broadband': + $subject = sprintf('Change BROADBAND: %s',$this->service->type->service_address); break; - case 'App\Models\Service\Voip': - $subject = sprintf('Change VOIP: %s',$this->service->type->service_number); + case 'App\Models\Service\Phone': + $subject = sprintf('Change PHONE: %s',$this->service->type->service_number); break; default: diff --git a/app/Mail/OrderRequest.php b/app/Mail/OrderRequest.php index 29ac5ac..f4a1e0a 100644 --- a/app/Mail/OrderRequest.php +++ b/app/Mail/OrderRequest.php @@ -36,12 +36,12 @@ class OrderRequest extends Mailable public function build() { switch (get_class($this->service->type)) { - case 'App\Models\Service\Adsl': - $subject = sprintf('NBN: %s',$this->service->type->service_address); + case 'App\Models\Service\Broadband': + $subject = sprintf('Order BROADBAND: %s',$this->service->type->service_address); break; - case 'App\Models\Service\Voip': - $subject = sprintf('VOIP: %s',$this->service->type->service_number); + case 'App\Models\Service\Phone': + $subject = sprintf('Order PHONE: %s',$this->service->type->service_number); break; default: diff --git a/app/Mail/OrderRequestApprove.php b/app/Mail/OrderRequestApprove.php index 91fcb96..a373f2a 100644 --- a/app/Mail/OrderRequestApprove.php +++ b/app/Mail/OrderRequestApprove.php @@ -35,11 +35,12 @@ class OrderRequestApprove extends Mailable */ public function build() { + // @todo This is not consistent with Cancel/Change Request switch ($this->service->category) { - case 'ADSL': $subject = sprintf('%s: %s',$this->service->category,$this->service->service_adsl->service_address); + case 'BROADBAND': $subject = sprintf('%s: %s',$this->service->category,$this->service->type->service_address); break; - case 'VOIP': $subject = sprintf('%s: %s',$this->service->category,$this->service->service_voip->service_number); + case 'PHONE': $subject = sprintf('%s: %s',$this->service->category,$this->service->type->service_number); break; default: diff --git a/app/Models/Base/ServiceType.php b/app/Models/Base/ServiceType.php index 9fa7636..19a46cc 100644 --- a/app/Models/Base/ServiceType.php +++ b/app/Models/Base/ServiceType.php @@ -2,14 +2,34 @@ namespace App\Models\Base; +use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; -use App\Models\Service; +use App\Interfaces\ServiceItem; +use App\Models\{Account,Service}; +use App\Models\Supplier\Type; +use App\Traits\{ScopeServiceActive,ScopeServiceUserAuthorised}; -abstract class ServiceType extends Model +abstract class ServiceType extends Model implements ServiceItem { + use ScopeServiceActive,ScopeServiceUserAuthorised; + + protected $dates = [ + 'expire_at', + ]; public $timestamps = FALSE; + /* RELATIONS */ + + /** + * Account this service belongs to + * @return \Illuminate\Database\Eloquent\Relations\HasOneThrough + */ + public function account() + { + return $this->hasOneThrough(Account::class,Service::class); + } + /** * @NOTE: The service_id column could be discarded, if the id column=service_id * @return \Illuminate\Database\Eloquent\Relations\MorphOne @@ -19,27 +39,61 @@ abstract class ServiceType extends Model return $this->morphOne(Service::class,'type','model','id','service_id'); } - /** SCOPES */ + /* SCOPES */ /** * Search for a record * * @param $query * @param string $term - * @return + * @return mixed */ public function scopeSearch($query,string $term) { return $query ->with(['service']) - ->join('ab_service','ab_service.id','=',$this->getTable().'.service_id') - ->Where('ab_service.id','like','%'.$term.'%'); + ->join('services','services.id','=',$this->getTable().'.service_id') + ->Where('services.id','like','%'.$term.'%'); } - /** ATTRIBUTES **/ + /* INTERFACE */ + + public function getContractTermAttribute(): int + { + return $this->service->offering->contract_term; + } + + public function getServiceExpireAttribute(): ?Carbon + { + return $this->expire_at ?: $this->service->invoice_next_at; + } + + public function hasExpired(): bool + { + return (! $this->inContract()) && ($this->service->invoice_next_at && $this->service->invoice_next_at->isPast()); + } + + public function inContract(): bool + { + return $this->expire_at && $this->expire_at->isFuture(); + } + + /* ATTRIBUTES */ public function getTypeAttribute() { return strtolower((new \ReflectionClass($this))->getShortName()); } + + /* METHODS */ + + /** + * The supplier's service that we provide + * + * @return Type + */ + public function supplied(): Type + { + return $this->service->product->type->supplied; + } } \ No newline at end of file diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 3d83208..cbb5ba8 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -163,7 +163,8 @@ class Invoice extends Model implements IDs public function items() { return $this->hasMany(InvoiceItem::class) - ->where('active',TRUE); + ->where('active',TRUE) + ->with(['taxes','product']); } public function payments() @@ -402,8 +403,7 @@ class Invoice extends Model implements IDs $return->push($po); } - $lo = $this->account->user->language; - return $return->sortBy(function ($item) use ($lo) { + return $return->sortBy(function ($item) { return $item->name; }); } diff --git a/app/Models/Product/Broadband.php b/app/Models/Product/Broadband.php index 893352d..c623bc9 100644 --- a/app/Models/Product/Broadband.php +++ b/app/Models/Product/Broadband.php @@ -10,6 +10,7 @@ use App\Models\Supplier; use App\Models\Service\Broadband as ServiceBroadband; use App\Models\Supplier\Broadband as SupplierBroadband; +// @todo does this need to extend Type? Perhaps have a ProductType consistent with ServiceType. final class Broadband extends Type implements ProductItem { use ScopeActive; @@ -44,7 +45,7 @@ final class Broadband extends Type implements ProductItem */ public function supplied() { - return $this->hasOne(SupplierBroadband::class,'id','supplier_broadband_id'); + return $this->hasOne(SupplierBroadband::class,'id','supplier_item_id'); } /* INTERFACES */ diff --git a/app/Models/Product/Domain.php b/app/Models/Product/Domain.php index cc5534a..a4fdabc 100644 --- a/app/Models/Product/Domain.php +++ b/app/Models/Product/Domain.php @@ -24,7 +24,7 @@ final class Domain extends Type implements ProductItem */ public function supplied() { - return $this->hasOne(SupplierDomain::class,'id','supplier_domain_id'); + return $this->hasOne(SupplierDomain::class,'id','supplier_item_id'); } /* INTERFACES */ diff --git a/app/Models/Product/Email.php b/app/Models/Product/Email.php index 8198c7f..7d3b955 100644 --- a/app/Models/Product/Email.php +++ b/app/Models/Product/Email.php @@ -24,7 +24,7 @@ final class Email extends Type implements ProductItem */ public function supplied() { - return $this->hasOne(SupplierEmail::class,'id','supplier_email_id'); + return $this->hasOne(SupplierEmail::class,'id','supplier_item_id'); } /* INTERFACES */ diff --git a/app/Models/Product/Generic.php b/app/Models/Product/Generic.php index b853029..0750957 100644 --- a/app/Models/Product/Generic.php +++ b/app/Models/Product/Generic.php @@ -24,7 +24,7 @@ final class Generic extends Type implements ProductItem */ public function supplied() { - return $this->hasOne(SupplierGeneric::class,'id','supplier_generic_id'); + return $this->hasOne(SupplierGeneric::class,'id','supplier_item_id'); } /* INTERFACES */ diff --git a/app/Models/Product/Host.php b/app/Models/Product/Host.php index 3e9ae2a..093a0c8 100644 --- a/app/Models/Product/Host.php +++ b/app/Models/Product/Host.php @@ -24,7 +24,7 @@ final class Host extends Type implements ProductItem */ public function supplied() { - return $this->hasOne(SupplierHost::class,'id','supplier_host_id'); + return $this->hasOne(SupplierHost::class,'id','supplier_item_id'); } /* INTERFACES */ diff --git a/app/Models/Product/Voip.php b/app/Models/Product/Phone.php similarity index 80% rename from app/Models/Product/Voip.php rename to app/Models/Product/Phone.php index 68788da..1b6c84b 100644 --- a/app/Models/Product/Voip.php +++ b/app/Models/Product/Phone.php @@ -5,18 +5,18 @@ namespace App\Models\Product; use Illuminate\Support\Collection; use App\Interfaces\ProductItem; -use App\Models\Service\Voip as ServiceVoip; -use App\Models\Supplier\Voip as SupplierVoip; +use App\Models\Service\Phone as ServicePhone; +use App\Models\Supplier\Phone as SupplierPhone; -final class Voip extends Type implements ProductItem +final class Phone extends Type implements ProductItem { - protected $table = 'product_voip'; + protected $table = 'product_phone'; protected array $order_attributes = [ 'options.phonenumber'=>[ 'request'=>'options.phonenumber', 'key'=>'service_number', - 'validation'=>'nullable|size:10|unique:ab_service__voip,service_number', + 'validation'=>'nullable|size:10|unique:service_phone,service_number', 'validation_message'=>'Phone Number is a required field.', ], 'options.supplier'=>[ @@ -40,7 +40,7 @@ final class Voip extends Type implements ProductItem ]; // The model that is referenced when this product is ordered - protected string $order_model = ServiceVoip::class; + protected string $order_model = ServicePhone::class; /* RELATIONS */ @@ -51,19 +51,20 @@ final class Voip extends Type implements ProductItem */ public function supplied() { - return $this->hasOne(SupplierVoip::class,'id','supplier_voip_id'); + return $this->hasOne(SupplierPhone::class,'id','supplier_item_id'); } /* INTERFACES */ public function getContractTermAttribute(): int { + // @todo Get this from the DB return 12; } public function getTypeAttribute() { - return 'VOIP'; + return 'PHONE'; } public function hasUsage(): bool diff --git a/app/Models/Product/SSL.php b/app/Models/Product/SSL.php index f7f4858..5e44d7f 100644 --- a/app/Models/Product/SSL.php +++ b/app/Models/Product/SSL.php @@ -24,7 +24,7 @@ final class SSL extends Type implements ProductItem */ public function supplied() { - return $this->hasOne(SupplierSSL::class,'id','supplier_ssl_id'); + return $this->hasOne(SupplierSSL::class,'id','supplier_item_id'); } /* INTERFACES */ @@ -52,19 +52,9 @@ final class SSL extends Type implements ProductItem return 0; } - public function getProductAttribute() - { - $o = new \stdClass(); - $o->product_id = 'INT'; - $o->setup_cost = 0; - $o->base_cost = 0; - $o->contract_term = 0; // @todo - - return $o; - } - public function getSupplierAttribute() { + abort(500,'deprecated'); $o = new \stdClass(); $o->name = 'Internal'; diff --git a/app/Models/Product/Type.php b/app/Models/Product/Type.php index 992d645..72e0a0f 100644 --- a/app/Models/Product/Type.php +++ b/app/Models/Product/Type.php @@ -7,6 +7,10 @@ use Illuminate\Database\Eloquent\Model; use App\Models\Product; 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. + */ abstract class Type extends Model { use SiteID,OrderServiceOptions; diff --git a/app/Models/Service.php b/app/Models/Service.php index fee7277..262a6da 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -18,35 +18,35 @@ use Leenooks\Carbon; use Symfony\Component\HttpKernel\Exception\HttpException; use App\Interfaces\IDs; -use App\Traits\NextKey; /** * Class Service * Services that belong to an account * * Attributes for services: - * + additional_cost : Pending additional charges for this service (excluding setup) + * + 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_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 + * + 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 * + sid : System ID for service * + * = Terminology: + * - Offering, what product we supply (we make offerings from supplier's supplied products) - in the DB these are products/* + * - Supplied, our supplier's product that is providing the service - in the DB these are supplier/* + * - Type, what service we are providing, made up of a product we supply - in the DB these are service/* + * * @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,NextKey; - - const RECORD_ID = 'service'; - public $incrementing = FALSE; - - protected $table = 'ab_service'; - const CREATED_AT = 'date_orig'; - const UPDATED_AT = 'date_last'; + use HasFactory; protected $appends = [ 'account_name', @@ -59,17 +59,16 @@ class Service extends Model implements IDs 'status', ]; - protected $dates = [ - 'date_last_invoice', - 'date_next_invoice', - 'date_start', - 'date_end', - ]; - protected $casts = [ 'order_info'=>AsCollection::class, ]; - public $dateFormat = 'U'; + + protected $dates = [ + 'invoice_last_at', + 'invoice_next_at', + 'start_at', + 'stop_at', + ]; protected $visible = [ 'account_name', @@ -484,7 +483,6 @@ class Service extends Model implements IDs * Return the auto billing details * * @return mixed - * @deprecated use billing directly? */ public function getAutoPayAttribute() { @@ -536,6 +534,33 @@ class Service extends Model implements IDs return Invoice::billing_name($this->getBillingIntervalAttribute()); } + /** + * The date the contract ends + * + * Service contracts end the later of the start_date + contract_term or the expire date. + * + * @return Carbon + */ + public function getContractEndAttribute(): ?\Carbon\Carbon + { + // If we have no start date or expire date, then NULL; + if (! $this->start_at && ! $this->type->expire_at) + return NULL; + + // If we dont have a start date, use the expire date + if (! $this->start_at) + return $this->type->expire_at; + + $end = $this->start_at->addMonths($this->getContractTermAttribute()); + + // If we dont have an expire date, use the start date + contract_term + if (! $this->type->expire_at) + return $end; + + // We have both, so it's the later of the two. + return ($end < $this->type->expire_at) ? $this->type->expire_at : $end; + } + /** * 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(); @@ -544,7 +569,7 @@ class Service extends Model implements IDs */ public function getContractTermAttribute(): int { - abort(500,'To implement (Dec 2021)'); + return $this->product->type->supplied->contract_term ?: 0; } /** @@ -570,7 +595,7 @@ class Service extends Model implements IDs $date = $last ? $last->addDay() : ($this->date_next_invoice ? $this->date_next_invoice->clone() - : ($this->date_start ?: Carbon::now())); + : ($this->start_at ?: Carbon::now())); return request()->wantsJson() ? $date->format('Y-m-d') : $date; } @@ -705,8 +730,9 @@ class Service extends Model implements IDs : NULL; // For SSL Certificates, the invoice_to date is the expiry date of the Cert - if (is_null($result) AND $this->type AND $this->type->type == 'ssl' AND $this->type->valid_to) - return $this->type->valid_to; + // @todo can we use the expire_at attribute? + if (is_null($result) AND $this->type AND $this->type->type == 'ssl' AND $this->type->expire_at) + return $this->type->expire_at; return $result; } @@ -751,6 +777,17 @@ class Service extends Model implements IDs return $this->getInvoiceNextAttribute(); } + /** + * The product we supply for this service + * + * @return Model + * @todo Remove all references to product->type to use this method + */ + public function getOfferingAttribute(): Model + { + return $this->product->type; + } + public function getOrderInfoNotesAttribute(): ?string { return $this->getOrderInfoValue('notes'); @@ -954,6 +991,16 @@ class Service extends Model implements IDs 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 * @@ -1397,11 +1444,11 @@ class Service extends Model implements IDs switch ($this->product->prod_plugin_file) { - case 'ADSL': return $this->service_adsl; + 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 'VOIP': return $this->service_voip; + case 'PHONE': return $this->service_voip; default: return NULL; } diff --git a/app/Models/Service/Broadband.php b/app/Models/Service/Broadband.php index ad0288e..d09620a 100644 --- a/app/Models/Service/Broadband.php +++ b/app/Models/Service/Broadband.php @@ -6,24 +6,64 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; use Leenooks\Carbon; -use App\Interfaces\{ServiceItem,ServiceUsage}; +use App\Interfaces\ServiceUsage; use App\Models\Base\ServiceType; use App\Models\Supplier\Broadband as SupplierBroadband; -use App\Traits\NextKey; +use App\Models\Supplier\Type; -class Broadband extends ServiceType implements ServiceItem,ServiceUsage +/** + * Class Broadband (Service) + * Services that are Internet Broadband + */ +class Broadband extends ServiceType implements ServiceUsage { - private const LOGKEY = 'MSA'; - - use NextKey; - const RECORD_ID = 'service__adsl'; + private const LOGKEY = 'MSB'; protected $dates = [ - 'service_connect_date', - 'service_contract_date' + 'connect_at', + 'expire_at', ]; - public $dateFormat = 'U'; - protected $table = 'ab_service__adsl'; + protected $table = 'service_broadband'; + + /* ABSTRACT */ + + /** + * Search for a record + * + * @param $query + * @param string $term + * @return mixed + */ + public function scopeSearch($query,string $term) + { + // Build our where clause + return parent::scopeSearch($query,$term) + ->orwhere('service_number','like','%'.$term.'%') + ->orWhere('service_address','like','%'.$term.'%') + ->orWhere('ipaddress','like','%'.$term.'%'); + } + + /* INTERFACES */ + + /** + * Return the service address + * + * @return string + */ + public function getServiceDescriptionAttribute(): string + { + return strtoupper($this->service_address) ?: '-'; + } + + /** + * Return the service number + * + * @return string + */ + public function getServiceNameAttribute(): string + { + return $this->service_number ?: ($this->service_address ?: '-'); + } /* RELATIONS */ @@ -38,79 +78,37 @@ class Broadband extends ServiceType implements ServiceItem,ServiceUsage return $this->hasMany(AdslTraffic::class,'ab_service_adsl_id'); } - /* SCOPES */ - - /** - * Search for a record - * - * @param $query - * @param string $term - * @return - */ - public function scopeSearch($query,string $term) - { - // Build our where clause - return parent::scopeSearch($query,$term) - ->orwhere('service_number','like','%'.$term.'%') - ->orWhere('service_address','like','%'.$term.'%') - ->orWhere('ipaddress','like','%'.$term.'%'); - } + /* ATTRIBUTES */ /** * @deprecated use $o->service_name; * @return mixed|string */ - - /* ATTRIBUTES */ - public function getNameAttribute() { + abort(500,'deprecated - use $o->service_name'); return $this->service_number ?: $this->service_address; } /** - * Return the service address + * The type of technology used to provide this Internet Service * - * @return string + * @param $value + * @return null|string */ - public function getServiceDescriptionAttribute(): string + public function getTechnologyAttribute($value): ?string { - return strtoupper($this->service_address) ?: 'NO Service Address'; - } - - public function getServiceExpireAttribute(): \Carbon\Carbon - { - // TODO: Implement getServiceExpireAttribute() method. - } - - /** - * Return the service number - * - * @return string - */ - public function getServiceNameAttribute(): string - { - return $this->service_number ?: $this->service_address; + return $value ?: $this->supplied()->technology; } /* METHODS */ - /** - * Is this service currently in a contract - * - * @return bool - */ - public function inContract(): bool - { - return $this->service_contract_date AND $this->service_contract_date->addMonths($this->contract_term)->isFuture(); - } - /** * Return the suppliers offering that this service is providing * - * @return SupplierBroadband + * @return Type */ - public function supplied(): SupplierBroadband + public function supplied(): Type { return $this->provided_adsl_plan_id ? SupplierBroadband::findOrFail($this->provided_adsl_plan_id) @@ -184,4 +182,4 @@ class Broadband extends ServiceType implements ServiceItem,ServiceUsage return $result; } -} +} \ No newline at end of file diff --git a/app/Models/Service/Domain.php b/app/Models/Service/Domain.php index c99ae99..cf52f36 100644 --- a/app/Models/Service/Domain.php +++ b/app/Models/Service/Domain.php @@ -2,97 +2,25 @@ namespace App\Models\Service; -use Carbon\Carbon; - use App\Models\Base\ServiceType; -use App\Models\{Account,DomainRegistrar,DomainTld,Service}; -use App\Interfaces\ServiceItem; -use App\Traits\{NextKey,ScopeServiceActive,ScopeServiceUserAuthorised}; +use App\Traits\ServiceDomains; +use App\Models\DomainRegistrar; /** * Class Domain (Service) - * Services that domain names - * - * Attributes for services: - * + service_description : Description as shown in a Service Context - * + service_expire : The date the service expires - * + service_name : Name as shown in a Service Context - * - * @package App\Models\Service + * Services that are managed Domain Names */ -class Domain extends ServiceType implements ServiceItem +class Domain extends ServiceType { - use ScopeServiceActive,ScopeServiceUserAuthorised; + use ServiceDomains; - protected $dates = [ - 'domain_expire', - ]; - public $dateFormat = 'U'; - protected $table = 'service_domains'; + protected $table = 'service_domain'; protected $with = ['tld']; - /* INTERFACES */ - - public function getServiceDescriptionAttribute(): string - { - // N/A - return 'Domain Name'; - } - - public function getServiceExpireAttribute(): Carbon - { - return $this->domain_expire; - } - - /** - * The name of the domain with its TLD - * - * @return string - */ - public function getServiceNameAttribute(): string - { - return strtoupper(sprintf('%s.%s',$this->domain_name,$this->tld->name)); - } - - public function inContract(): bool - { - return $this->domain_expire->isFuture(); - } - /* RELATIONS */ - public function account() - { - return $this->hasOneThrough(Account::class,Service::class); - } - public function registrar() { return $this->belongsTo(DomainRegistrar::class,'domain_registrar_id'); } - public function tld() - { - return $this->belongsTo(DomainTld::class,'domain_tld_id'); - } - - /* SCOPES */ - - /** - * Search for a record - * - * @param $query - * @param string $term - * @return mixed - */ - public function scopeSearch($query,string $term) - { - // If we have a period in the name, we'll ignore everything after it. - $term = strstr($term,'.',TRUE) ?: $term; - - // Build our where clause - return parent::scopeSearch($query,$term) - ->orwhere('domain_name','like','%'.$term.'%'); - } - - /* ATTRIBUTES */ } \ No newline at end of file diff --git a/app/Models/Service/Email.php b/app/Models/Service/Email.php index abfb661..a61dacb 100644 --- a/app/Models/Service/Email.php +++ b/app/Models/Service/Email.php @@ -2,64 +2,17 @@ namespace App\Models\Service; -use Carbon\Carbon; - use App\Models\Base\ServiceType; -use App\Models\{Account, DomainRegistrar, DomainTld, Service, TLD}; -use App\Interfaces\ServiceItem; -use App\Traits\{NextKey,ScopeServiceActive,ScopeServiceUserAuthorised}; +use App\Traits\ServiceDomains; /** * Class Email (Service) - * Services that email hostings - * - * Attributes for services: - * + service_description : Description as shown in a Service Context - * + service_expire : The date the service expires - * + service_name : Name as shown in a Service Context - * - * @package App\Models\Service + * Services that are Email Hosting */ -class Email extends ServiceType implements ServiceItem +class Email extends ServiceType { - use ScopeServiceActive,ScopeServiceUserAuthorised; + use ServiceDomains; - protected $dates = ['expire_at']; - protected $table = 'service_emails'; - - /* INTERFACES */ - - public function getServiceDescriptionAttribute(): string - { - // N/A - return 'Email Hosting'; - } - - public function getServiceExpireAttribute(): Carbon - { - return $this->expire_at ?: $this->service->next_invoice; - } - - /** - * The name of the domain with its TLD - * - * @return string - * // @todo - */ - public function getServiceNameAttribute(): string - { - return strtoupper(sprintf('%s.%s',$this->domain_name,$this->tld->name)); - } - - public function inContract(): bool - { - return $this->expire_at && $this->expire_at->isFuture(); - } - - /* RELATIONS */ - - public function tld() - { - return $this->belongsTo(TLD::class); - } + protected $table = 'service_email'; + protected $with = ['tld']; } \ No newline at end of file diff --git a/app/Models/Service/Generic.php b/app/Models/Service/Generic.php index 3efbecb..9a76a76 100644 --- a/app/Models/Service/Generic.php +++ b/app/Models/Service/Generic.php @@ -4,8 +4,21 @@ namespace App\Models\Service; use App\Models\Base\ServiceType; +// @todo Document how this is used. class Generic extends ServiceType { protected $table = 'service__generic'; public $timestamps = FALSE; + + /* INTERFACE */ + + public function getServiceDescriptionAttribute(): string + { + return 'Generic'; + } + + public function getServiceNameAttribute(): string + { + return 'Generic'; + } } diff --git a/app/Models/Service/Host.php b/app/Models/Service/Host.php index 45f4c3b..017196a 100644 --- a/app/Models/Service/Host.php +++ b/app/Models/Service/Host.php @@ -2,55 +2,25 @@ namespace App\Models\Service; -use Carbon\Carbon; - -use App\Interfaces\ServiceItem; use App\Models\Base\ServiceType; -use App\Models\DomainTld; +use App\Traits\ServiceDomains; use App\Models\HostServer; -use App\Traits\NextKey; -use App\Traits\{ScopeServiceActive,ScopeServiceUserAuthorised}; -class Host extends ServiceType implements ServiceItem +/** + * Class Host (Service) + * Services that are Web Hosting + */ +class Host extends ServiceType { - use ScopeServiceActive,ScopeServiceUserAuthorised; - use NextKey; - const RECORD_ID = 'service__hosting'; + use ServiceDomains; - protected $dates = [ - 'host_expire', - ]; - public $dateFormat = 'U'; - protected $table = 'ab_service__hosting'; + protected $table = 'service_host'; + protected $with = ['tld']; + + /* RELATIONS */ public function provider() { return $this->belongsTo(HostServer::class,'host_server_id'); } - - public function tld() - { - return $this->belongsTo(DomainTld::class,'domain_tld_id'); - } - - public function getServiceDescriptionAttribute(): string - { - // N/A - return 'Hosting'; - } - - public function getServiceExpireAttribute(): Carbon - { - return $this->host_expire; - } - - public function getServiceNameAttribute(): string - { - return sprintf('%s.%s',strtoupper($this->domain_name),strtoupper($this->tld->name)); - } - - public function inContract(): bool - { - return $this->host_expire->isFuture(); - } } \ No newline at end of file diff --git a/app/Models/Service/Phone.php b/app/Models/Service/Phone.php new file mode 100644 index 0000000..ace0256 --- /dev/null +++ b/app/Models/Service/Phone.php @@ -0,0 +1,70 @@ +orwhere('service_number','like','%'.$term.'%') + ->orWhere('service_address','like','%'.$term.'%'); + } + + /* INTERFACES */ + + /** + * Return the service address + * + * @return string + */ + public function getServiceDescriptionAttribute(): string + { + return strtoupper($this->service_address) ?: '-'; + } + + /** + * Return the service number + * + * @return string + */ + public function getServiceNameAttribute(): string + { + return $this->service_number ?: ($this->service_address ?: '-'); + } + + /* ATTRIBUTES */ + + /** + * The type of technology used to provide this Internet Service + * + * @param $value + * @return null|string + */ + public function getTechnologyAttribute($value): ?string + { + return $value ?: $this->supplied()->technology; + } +} \ No newline at end of file diff --git a/app/Models/Service/SSL.php b/app/Models/Service/SSL.php index 232b293..f9434dc 100644 --- a/app/Models/Service/SSL.php +++ b/app/Models/Service/SSL.php @@ -5,19 +5,20 @@ namespace App\Models\Service; use Illuminate\Support\Arr; use Carbon\Carbon; -use App\Interfaces\ServiceItem; use App\Models\Base\ServiceType; -use App\Traits\NextKey; -class SSL extends ServiceType implements ServiceItem +/** + * Class SSL (Service) + * Services that are provide an SSL Certificate + */ +class SSL extends ServiceType { - use NextKey; - const RECORD_ID = 'service__ssl'; + protected $table = 'service_ssl'; - protected $table = 'ab_service__ssl'; - - protected $crt_parse = NULL; protected $public_key = NULL; + protected $crt_parse = NULL; + + /* STATIC */ public static function boot() { @@ -33,11 +34,27 @@ class SSL extends ServiceType implements ServiceItem }); } - public function getValidToAttribute() + /* ABSTRACT */ + + /** + * Search for a record + * + * @param $query + * @param string $term + * @return mixed + */ + public function scopeSearch($query,string $term) { - return $this->cert ? Carbon::createFromTimestamp($this->crt_parse->get('validTo_time_t')) : NULL; + // @todo } + /* INTERFACES */ + + /** + * Return the Cert DN + * + * @return string + */ public function getServiceDescriptionAttribute(): string { if ($this->cert) @@ -58,11 +75,19 @@ class SSL extends ServiceType implements ServiceItem } } - public function getServiceExpireAttribute(): Carbon + /** + * Return the Certificate Expiry Date + */ + public function getServiceExpireAttribute(): ?Carbon { - // TODO: Implement getServiceExpireAttribute() method. + return $this->cert ? Carbon::createFromTimestamp($this->crt_parse->get('validTo_time_t')) : NULL; } + /** + * Return the Cert Name + * + * @return string + */ public function getServiceNameAttribute(): string { return $this->cert @@ -70,9 +95,24 @@ class SSL extends ServiceType implements ServiceItem : Arr::get(openssl_csr_get_subject($this->csr),'CN',''); } + /** + * Certificates have no contract and can be cancelled anytime. + * + * @return bool + */ public function inContract(): bool { - // N/A return FALSE; } + + /* METHODS */ + + /** + * @return Carbon|null + * @deprecated use getServiceExpireAttribute() + */ + public function getValidToAttribute() + { + abort(500,'use getServiceExpireAttribute'); + } } \ No newline at end of file diff --git a/app/Models/Service/Voip.php b/app/Models/Service/Voip.php deleted file mode 100644 index 1aef1b4..0000000 --- a/app/Models/Service/Voip.php +++ /dev/null @@ -1,72 +0,0 @@ -orwhere('service_number','like','%'.$term.'%') - ->orWhere('service_address','like','%'.$term.'%'); - } - - /* ATTRIBUTES */ - - /** - * Return the service address - * - * @return string - */ - public function getServiceDescriptionAttribute(): string - { - return $this->service_address ?: 'VOIP'; - } - - public function getServiceExpireAttribute(): Carbon - { - // TODO: Implement getServiceExpireAttribute() method. - } - - /** - * Return the service number - * - * @return string - */ - public function getServiceNameAttribute(): string - { - return $this->service_number ?: ($this->service_address ?: 'Unknown'); - } - - /* METHODS */ - - public function inContract(): bool - { - return $this->service_contract_date AND $this->service_contract_date->addMonths($this->contract_term)->isFuture(); - } -} \ No newline at end of file diff --git a/app/Models/ServiceChange.php b/app/Models/ServiceChange.php new file mode 100644 index 0000000..a8c55e0 --- /dev/null +++ b/app/Models/ServiceChange.php @@ -0,0 +1,16 @@ + 'Hosting', 'class' => Host::class, ], - 'voip' => [ - 'name' => 'VOIP Telephone', - 'class' => Voip::class, + 'phone' => [ + 'name' => 'Phone', + 'class' => Phone::class, + ], + 'ssl' => [ + 'name' => 'SSL', + 'class' => SSL::class, ], ]; /* RELATIONS */ + // @todo Need to put in an integrity constraint to support the hasOne() + // @todo Some suppliers have multiple different configuration urls/passwords and contacts for different types of services, perhaps this should be hasMany()? + // EG: Crazy Domains, "domains" and "hosting". public function detail() { return $this->hasOne(SupplierDetail::class); diff --git a/app/Models/Supplier/Broadband.php b/app/Models/Supplier/Broadband.php index f70fabb..e30c0f8 100644 --- a/app/Models/Supplier/Broadband.php +++ b/app/Models/Supplier/Broadband.php @@ -8,6 +8,7 @@ use Illuminate\Support\Collection; use App\Interfaces\SupplierItem; use App\Models\Product\Broadband as ProductBroadband; +// @todo does this need to extend Type? Perhaps have a SupplierType consistent with ServiceType. class Broadband extends Type implements SupplierItem { protected $casts = [ @@ -37,7 +38,7 @@ class Broadband extends Type implements SupplierItem public function types() { - return $this->belongsToMany(ProductBroadband::class,$this->table,'id','id','id',$this->table.'_id'); + return $this->belongsToMany(ProductBroadband::class,$this->table,'id','id','id','supplier_item_id'); } public function getBillingIntervalAttribute(): int diff --git a/app/Models/Supplier/Domain.php b/app/Models/Supplier/Domain.php index ab85783..999b5c4 100644 --- a/app/Models/Supplier/Domain.php +++ b/app/Models/Supplier/Domain.php @@ -24,7 +24,7 @@ final class Domain extends Type implements SupplierItem public function types() { - return $this->belongsToMany(ProductDomain::class,$this->table,'id','id','id',$this->table.'_id'); + return $this->belongsToMany(ProductDomain::class,$this->table,'id','id','id','supplier_item_id'); } /* RELATIONS */ diff --git a/app/Models/Supplier/Email.php b/app/Models/Supplier/Email.php index 6602f5c..c9ffc7a 100644 --- a/app/Models/Supplier/Email.php +++ b/app/Models/Supplier/Email.php @@ -18,6 +18,6 @@ final class Email extends Type implements SupplierItem public function types() { - return $this->belongsToMany(ProductEmail::class,$this->table,'id','id','id',$this->table.'_id'); + return $this->belongsToMany(ProductEmail::class,$this->table,'id','id','id','supplier_item_id'); } } \ No newline at end of file diff --git a/app/Models/Supplier/Generic.php b/app/Models/Supplier/Generic.php index 73e6417..706611b 100644 --- a/app/Models/Supplier/Generic.php +++ b/app/Models/Supplier/Generic.php @@ -13,7 +13,7 @@ final class Generic extends Type implements SupplierItem public function types() { - return $this->belongsToMany(ProductGeneric::class,$this->table,'id','id','id',$this->table.'_id'); + return $this->belongsToMany(ProductGeneric::class,$this->table,'id','id','id','supplier_item_id'); } public function getBillingIntervalAttribute(): int diff --git a/app/Models/Supplier/Host.php b/app/Models/Supplier/Host.php index 48f6b7a..ea70067 100644 --- a/app/Models/Supplier/Host.php +++ b/app/Models/Supplier/Host.php @@ -13,7 +13,7 @@ final class Host extends Type implements SupplierItem public function types() { - return $this->belongsToMany(ProductHost::class,$this->table,'id','id','id',$this->table.'_id'); + return $this->belongsToMany(ProductHost::class,$this->table,'id','id','id','supplier_item_id'); } public function getBillingIntervalAttribute(): int diff --git a/app/Models/Supplier/Voip.php b/app/Models/Supplier/Phone.php similarity index 61% rename from app/Models/Supplier/Voip.php rename to app/Models/Supplier/Phone.php index cd9b1b3..e4b5424 100644 --- a/app/Models/Supplier/Voip.php +++ b/app/Models/Supplier/Phone.php @@ -3,17 +3,17 @@ namespace App\Models\Supplier; use App\Interfaces\SupplierItem; -use App\Models\Product\Voip as ProductVoip; +use App\Models\Product\Phone as ProductVoip; -final class Voip extends Type implements SupplierItem +final class Phone extends Type implements SupplierItem { - protected $table = 'supplier_voip'; + protected $table = 'supplier_phone'; /* INTERFACES */ public function types() { - return $this->belongsToMany(ProductVoip::class,$this->table,'id','id','id',$this->table.'_id'); + return $this->belongsToMany(ProductVoip::class,$this->table,'id','id','id','supplier_item_id'); } public function getBillingIntervalAttribute(): int diff --git a/app/Models/Supplier/SSL.php b/app/Models/Supplier/SSL.php index 2098479..1072530 100644 --- a/app/Models/Supplier/SSL.php +++ b/app/Models/Supplier/SSL.php @@ -13,7 +13,7 @@ final class SSL extends Type implements SupplierItem public function types() { - return $this->belongsToMany(ProductSSL::class,$this->table,'id','id','id',$this->table.'_id'); + return $this->belongsToMany(ProductSSL::class,$this->table,'id','id','id','supplier_item_id'); } public function getBillingIntervalAttribute(): int diff --git a/app/Traits/ScopeServiceActive.php b/app/Traits/ScopeServiceActive.php index 5350dfd..35eddc3 100644 --- a/app/Traits/ScopeServiceActive.php +++ b/app/Traits/ScopeServiceActive.php @@ -15,10 +15,10 @@ trait ScopeServiceActive public function scopeServiceActive($query) { return $query->where(function($q) { - return $q->where('ab_service.active',TRUE) + return $q->where('services.active',TRUE) ->orWhere(function($q) { return $q->whereNotNull('order_status') - ->whereNotIn('ab_service.order_status',Service::INACTIVE_STATUS); + ->whereNotIn('services.order_status',Service::INACTIVE_STATUS); }); }); } diff --git a/app/Traits/ScopeServiceUserAuthorised.php b/app/Traits/ScopeServiceUserAuthorised.php index ad6f4ca..ba9e1b6 100644 --- a/app/Traits/ScopeServiceUserAuthorised.php +++ b/app/Traits/ScopeServiceUserAuthorised.php @@ -16,6 +16,6 @@ trait ScopeServiceUserAuthorised public function scopeServiceUserAuthorised($query,User $uo) { return $query - ->whereIN('ab_service.account_id',$uo->all_accounts()->pluck('id')->unique()->toArray()); + ->whereIN('services.account_id',$uo->all_accounts()->pluck('id')->unique()->toArray()); } } diff --git a/app/Traits/ServiceDomains.php b/app/Traits/ServiceDomains.php new file mode 100644 index 0000000..6e48122 --- /dev/null +++ b/app/Traits/ServiceDomains.php @@ -0,0 +1,59 @@ +domain_name,$this->tld->name)); + } + + /* RELATIONS */ + + public function tld() + { + return $this->belongsTo(TLD::class); + } + + /* SCOPES */ + + /** + * Search for a record + * + * @param $query + * @param string $term + * @return mixed + */ + public function scopeSearch($query,string $term) + { + // If we have a period in the name, we'll ignore everything after it. + $term = strstr($term,'.',TRUE) ?: $term; + + // Build our where clause + return parent::scopeSearch($query,$term) + ->orwhere('domain_name','like','%'.$term.'%'); + } +} \ No newline at end of file diff --git a/database/migrations/2021_12_20_225017_optimize_product.php b/database/migrations/2021_12_20_225017_optimize_product.php index 6a49afb..f1b8e25 100644 --- a/database/migrations/2021_12_20_225017_optimize_product.php +++ b/database/migrations/2021_12_20_225017_optimize_product.php @@ -570,7 +570,7 @@ class OptimizeProduct extends Migration $sdo->site_id = $site->site_id; $so->detail()->save($sdo); - $o = new \App\Models\Supplier\Voip; + $o = new \App\Models\Supplier\Phone; $o->site_id = $sdo->site_id; $o->active = TRUE; $o->product_id = 'VOIP $10'; @@ -579,13 +579,13 @@ class OptimizeProduct extends Migration $o->supplier_detail_id = $sdo->id; $o->save(); - $oo = new \App\Models\Product\Voip; + $oo = new \App\Models\Product\Phone; $oo->site_id = $sdo->site_id; $oo->supplier_voip_id = $o->id; $oo->name = 'VOIP $10'; $oo->save(); - $o = new \App\Models\Supplier\Voip; + $o = new \App\Models\Supplier\Phone; $o->site_id = $sdo->site_id; $o->active = TRUE; $o->product_id = 'VOIP'; @@ -594,13 +594,13 @@ class OptimizeProduct extends Migration $o->supplier_detail_id = $sdo->id; $o->save(); - $oo = new \App\Models\Product\Voip; + $oo = new \App\Models\Product\Phone; $oo->site_id = $sdo->site_id; $oo->supplier_voip_id = $o->id; $oo->name = 'VOIP'; $oo->save(); - $o = new \App\Models\Supplier\Voip; + $o = new \App\Models\Supplier\Phone; $o->site_id = $sdo->site_id; $o->active = TRUE; $o->product_id = 'VOIP B-100'; @@ -610,7 +610,7 @@ class OptimizeProduct extends Migration $o->supplier_detail_id = $sdo->id; $o->save(); - $oo = new \App\Models\Product\Voip; + $oo = new \App\Models\Product\Phone; $oo->site_id = $sdo->site_id; $oo->supplier_voip_id = $o->id; $oo->name = 'VOIP B-10'; diff --git a/database/migrations/2022_04_19_121452_rename_service_tables.php b/database/migrations/2022_04_19_121452_rename_service_tables.php new file mode 100644 index 0000000..6f42bd7 --- /dev/null +++ b/database/migrations/2022_04_19_121452_rename_service_tables.php @@ -0,0 +1,337 @@ +dropPrimary(); + $table->dropForeign('ab_service_site_id_foreign'); + $table->primary(['id','site_id']); + $table->dropIndex('ab_service_site_id_foreign'); + $table->dropIndex('ab_service_id_site_id_index'); + $table->datetime('created_at')->nullable()->after('id'); + $table->datetime('updated_at')->nullable()->after('created_at'); + $table->date('invoice_last_at')->nullable()->after('date_last_invoice'); + $table->date('invoice_next_at')->nullable()->after('date_next_invoice'); + $table->date('start_at')->nullable()->after('date_start'); + $table->date('stop_at')->nullable()->after('date_end'); + }); + + DB::statement('ALTER TABLE ab_service RENAME TO services'); + DB::statement('ALTER TABLE services MODIFY account_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE services MODIFY account_billing_id int unsigned DEFAULT NULL'); + DB::statement('ALTER TABLE services MODIFY product_id int unsigned NOT NULL'); + DB::statement('UPDATE services SET taxable=1'); + DB::statement('UPDATE services SET active=0 WHERE active IS NULL'); + DB::statement('ALTER TABLE services MODIFY active tinyint(1) NOT NULL,MODIFY suspend_billing tinyint(1) DEFAULT NULL,MODIFY external_billing tinyint(1) DEFAULT NULL,MODIFY taxable tinyint(1) DEFAULT NULL'); + DB::statement('ALTER TABLE services RENAME COLUMN orderby_id TO ordered_by'); + DB::statement('ALTER TABLE services MODIFY ordered_by int unsigned'); + + // Convert out dates + foreach (\App\Models\Service::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->date_orig) + $o->created_at = \Carbon\Carbon::createFromTimestamp($o->date_orig); + if ($o->date_last) + $o->updated_at = \Carbon\Carbon::createFromTimestamp($o->date_last); + if ($o->date_last_invoice) + $o->invoice_last_at = \Carbon\Carbon::createFromTimestamp($o->date_last_invoice); + if ($o->date_next_invoice) + $o->invoice_next_at = \Carbon\Carbon::createFromTimestamp($o->date_next_invoice); + if ($o->date_start) + $o->start_at = \Carbon\Carbon::createFromTimestamp($o->date_start); + if ($o->date_end) + $o->stop_at = \Carbon\Carbon::createFromTimestamp($o->date_end); + $o->save(); + } + + Schema::table('services', function (Blueprint $table) { + $table->dropColumn(['date_orig','date_last','date_last_invoice','date_next_invoice','date_start','date_end','queue','price_group']); + $table->foreign(['account_id','site_id'])->references(['id','site_id'])->on('accounts'); + $table->foreign(['product_id','site_id'])->references(['id','site_id'])->on('products'); + $table->foreign(['ordered_by','site_id'])->references(['id','site_id'])->on('users'); + $table->foreign(['site_id'])->references(['id'])->on('sites'); + }); + + DB::statement('ALTER TABLE service_domains RENAME TO service_domain'); + DB::statement('ALTER TABLE service_emails RENAME TO service_email'); + + Schema::table('ab_service_change', function (Blueprint $table) { + $table->dropPrimary(); + $table->primary(['id','site_id']); + $table->dropForeign('ab_service_change_site_id_foreign'); + $table->dropIndex('ab_service_change_site_id_foreign'); + $table->dropIndex('ab_service_change_id_site_id_index'); + }); + + DB::statement('ALTER TABLE ab_service_change RENAME TO service__change'); + DB::statement('ALTER TABLE service__change MODIFY service_id int unsigned'); + DB::statement('ALTER TABLE service__change MODIFY product_id int unsigned'); + DB::statement('ALTER TABLE service__change MODIFY ordered_by int unsigned'); + + Schema::table('service__change', function (Blueprint $table) { + $table->date('ordered_at')->nullable()->after('ordered_by'); + $table->date('effective_at')->nullable()->after('ordered_at'); + + $table->foreign(['product_id','site_id'])->references(['id','site_id'])->on('products'); + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + $table->foreign(['ordered_by','site_id'])->references(['id','site_id'])->on('users'); + }); + + // Convert out dates + foreach (\App\Models\ServiceChange::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->date_ordered) + $o->ordered_at = \Carbon\Carbon::createFromTimestamp($o->date_ordered); + if ($o->date_effective) + $o->effective_at = \Carbon\Carbon::createFromTimestamp($o->date_effective); + $o->save(); + } + + DB::statement('ALTER TABLE service__change MODIFY ordered_at int unsigned NOT NULL'); + DB::statement('ALTER TABLE service__change MODIFY effective_at int unsigned NOT NULL'); + + Schema::table('service__change', function (Blueprint $table) { + $table->dropColumn(['date_ordered','date_effective']); + }); + + DB::statement('ALTER TABLE service__generic MODIFY service_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service__generic MODIFY product_id int unsigned DEFAULT NULL'); + DB::statement('UPDATE service__generic SET product_id=NULL WHERE product_id=0'); + Schema::table('service__generic', function (Blueprint $table) { + $table->dropPrimary(); + $table->primary(['id','site_id']); + $table->dropForeign('service__generic_site_id_foreign'); + $table->dropIndex('service__generic_site_id_foreign'); + $table->dropIndex('service__generic_id_site_id_index'); + + $table->foreign(['product_id','site_id'])->references(['id','site_id'])->on('products'); + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + }); + + DB::statement('ALTER TABLE service_domain MODIFY service_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service_domain MODIFY domain_tld_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service_domain MODIFY domain_registrar_id int unsigned DEFAULT NULL'); + DB::statement('ALTER TABLE service_domain MODIFY domain_name varchar(128) NOT NULL'); + DB::statement('ALTER TABLE service_domain RENAME COLUMN domain_tld_id TO tld_id'); + + Schema::table('service_domain', function (Blueprint $table) { + $table->dropPrimary(); + $table->primary(['id','site_id']); + $table->dropForeign('service_domains_site_id_foreign'); + $table->dropIndex('service_domains_site_id_foreign'); + $table->dropIndex('service_domains_id_site_id_index'); + + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + $table->foreign(['tld_id'])->references(['id'])->on('tlds'); + + $table->date('expire_at')->nullable()->after('domain_expire'); + }); + + // Convert out dates + foreach (\App\Models\Service\Domain::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->domain_expire) + $o->expire_at = \Carbon\Carbon::createFromTimestamp($o->domain_expire); + $o->save(); + } + + Schema::table('service_domain', function (Blueprint $table) { + $table->dropColumn(['registrar_lastsync','domain_expire']); + }); + + DB::statement('ALTER TABLE service_email DROP PRIMARY KEY,ADD PRIMARY KEY (id,site_id)'); + + Schema::table('service_email', function (Blueprint $table) { + $table->unique(['domain_name','tld_id']); + $table->dropForeign('service_emails_site_id_foreign'); + $table->dropForeign('service_emails_service_id_foreign'); + $table->dropForeign('service_emails_tld_id_foreign'); + + $table->foreign(['tld_id'])->references(['id'])->on('tlds'); + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + }); + + DB::statement('ALTER TABLE ab_service__hosting RENAME TO service_host'); + DB::statement('ALTER TABLE service_host RENAME COLUMN domain_tld_id TO tld_id'); + DB::statement('ALTER TABLE service_host MODIFY service_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service_host MODIFY tld_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service_host MODIFY host_server_id int unsigned DEFAULT NULL'); + + DB::statement('ALTER TABLE service_host MODIFY domain_name varchar(128) NOT NULL'); + + Schema::table('service_host', function (Blueprint $table) { + $table->dropPrimary(); + $table->primary(['id','site_id']); + $table->dropForeign('ab_service__hosting_site_id_foreign'); + $table->dropIndex('ab_service__hosting_site_id_foreign'); + $table->dropIndex('ab_service__hosting_id_site_id_index'); + + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + $table->foreign(['tld_id'])->references(['id'])->on('tlds'); + + $table->date('expire_at')->nullable()->after('host_expire'); + }); + + // Convert our dates + foreach (\App\Models\Service\Host::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->server_data && (strlen($o->server_data) > 8) && gzuncompress($o->server_data)) + $o->server_data = NULL; + if ($o->host_expire) + $o->expire_at = \Carbon\Carbon::createFromTimestamp($o->host_expire); + $o->save(); + } + + Schema::table('service_host', function (Blueprint $table) { + $table->dropColumn(['host_expire','server_data_date']); + }); + + DB::statement('ALTER TABLE product_broadband RENAME COLUMN supplier_broadband_id TO supplier_item_id'); + DB::statement('ALTER TABLE product_domain RENAME COLUMN supplier_domain_id TO supplier_item_id'); + DB::statement('ALTER TABLE product_email RENAME COLUMN supplier_email_id TO supplier_item_id'); + DB::statement('ALTER TABLE product_host RENAME COLUMN supplier_host_id TO supplier_item_id'); + DB::statement('ALTER TABLE product_ssl RENAME COLUMN supplier_ssl_id TO supplier_item_id'); + DB::statement('ALTER TABLE product_generic RENAME COLUMN supplier_generic_id TO supplier_item_id'); + + DB::statement('ALTER TABLE product_voip RENAME TO product_phone'); + DB::statement('ALTER TABLE product_phone RENAME COLUMN supplier_voip_id TO supplier_item_id'); + + Schema::table('product_phone', function (Blueprint $table) { + $table->dropPrimary(); + $table->primary(['id','site_id']); + $table->dropForeign('product_voip_supplier_voip_id_site_id_foreign'); + $table->dropForeign('product_voip_site_id_foreign'); + $table->dropIndex('product_voip_supplier_voip_id_site_id_foreign'); + $table->dropIndex('product_voip_site_id_foreign'); + $table->dropIndex('product_voip_id_site_id_index'); + }); + + DB::statement('ALTER TABLE supplier_voip RENAME TO supplier_phone'); + Schema::table('supplier_phone', function (Blueprint $table) { + $table->dropPrimary(); + $table->primary(['id','site_id']); + $table->dropForeign('supplier_voip_supplier_detail_id_site_id_foreign'); + $table->dropForeign('supplier_voip_site_id_foreign'); + $table->dropIndex('supplier_voip_id_site_id_index'); + + $table->foreign(['supplier_detail_id','site_id'])->references(['id','site_id'])->on('supplier_details'); + + $table->string('technology')->nullable(); + }); + + Schema::table('product_phone', function (Blueprint $table) { + $table->foreign(['supplier_item_id','site_id'])->references(['id','site_id'])->on('supplier_phone'); + + $table->string('technology')->nullable(); + }); + + DB::statement('ALTER TABLE ab_service__voip RENAME TO service_phone'); + DB::statement('ALTER TABLE service_phone MODIFY service_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service_phone MODIFY service_number varchar(10) NOT NULL'); + DB::statement('ALTER TABLE service_phone MODIFY site_id int unsigned NOT NULL'); + + Schema::table('service_phone', function (Blueprint $table) { + $table->primary(['id','site_id']); + $table->date('connect_at')->nullable()->after('contract_term'); + $table->date('expire_at')->nullable()->after('connect_at'); + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + $table->string('technology')->nullable(); + }); + + DB::statement('ALTER TABLE service_phone MODIFY id int unsigned auto_increment'); + + // Convert our dates + foreach (\App\Models\Service\Phone::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->service_connect_date) + $o->connect_at = \Carbon\Carbon::createFromTimestamp($o->service_connect_date); + if ($o->getRawOriginal('contract_term') === 0) + $o->contract_term = NULL; + if ($o->service_contract_date && $o->getRawOriginal('contract_term')) + $o->expire_at = \Carbon\Carbon::createFromTimestamp($o->service_contract_date)->addMonths($o->getRawOriginal('contract_term')); + $o->save(); + } + + Schema::table('service_phone', function (Blueprint $table) { + $table->dropColumn(['service_connect_date','service_contract_date','contract_term']); + }); + + DB::statement('ALTER TABLE ab_service__adsl RENAME TO service_broadband'); + DB::statement('ALTER TABLE service_broadband MODIFY service_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service_broadband MODIFY service_stats_collect tinyint(1) DEFAULT NULL'); + DB::statement('ALTER TABLE service_broadband RENAME COLUMN service_stats_lastupdate TO service_stats_at'); + // @todo drop column provided_adsl_plan_id + + Schema::table('service_broadband', function (Blueprint $table) { + $table->dropPrimary(); + $table->primary(['id','site_id']); + $table->date('connect_at')->nullable()->after('contract_term'); + $table->date('expire_at')->nullable()->after('connect_at'); + $table->ipAddress('ip6address')->nullable()->after('ipaddress'); + $table->string('technology')->nullable(); + + $table->dropForeign('ab_service__adsl_site_id_foreign'); + $table->dropIndex('ab_service__adsl_site_id_foreign'); + $table->dropIndex('ab_service__adsl_id_site_id_index'); + + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + }); + + // Convert our dates + foreach (\App\Models\Service\Broadband::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->service_connect_date) + $o->connect_at = \Carbon\Carbon::createFromTimestamp($o->service_connect_date); + if ($o->getRawOriginal('contract_term') === 0) + $o->contract_term = NULL; + if ($o->service_contract_date && $o->getRawOriginal('contract_term')) + $o->expire_at = \Carbon\Carbon::createFromTimestamp($o->service_contract_date)->addMonths($o->getRawOriginal('contract_term')); + $o->save(); + } + + Schema::table('service_broadband', function (Blueprint $table) { + $table->dropColumn(['service_connect_date','service_contract_date','contract_term']); + }); + + Schema::table('supplier_broadband', function (Blueprint $table) { + $table->string('technology')->nullable(); + }); + + DB::select("UPDATE services SET model='App\\\\Models\\\\Service\\\\Phone' where model='App\\\\Models\\\\Service\\\\Voip'"); + DB::select("UPDATE products SET model='App\\\\Models\\\\Product\\\\Phone' where model='App\\\\Models\\\\Product\\\\Voip'"); + + DB::statement('ALTER TABLE ab_service__ssl RENAME TO service_ssl'); + DB::statement('ALTER TABLE service_ssl MODIFY service_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service_ssl MODIFY ssl_ca_id int unsigned DEFAULT NULL'); + + Schema::table('service_ssl', function (Blueprint $table) { + $table->dropPrimary(); + $table->primary(['id','site_id']); + + $table->dropForeign('ab_service__ssl_site_id_foreign'); + $table->dropIndex('ab_service__ssl_site_id_foreign'); + $table->dropIndex('ab_service__ssl_id_site_id_index'); + + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + }); + + foreach (DB::select('SELECT * FROM products where model="App\\\\Models\\\\Product\\\\SSL"') as $o) { + DB::select('UPDATE services set model="App\\\\Models\\\\Service\\\\SSL" WHERE product_id='.$o->id); + }; + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + abort(500,'Cant go back'); + } +} diff --git a/resources/views/email/admin/order/approve.blade.php b/resources/views/email/admin/order/approve.blade.php index 9d7595c..ca4b9c5 100644 --- a/resources/views/email/admin/order/approve.blade.php +++ b/resources/views/email/admin/order/approve.blade.php @@ -9,17 +9,16 @@ Please order the following... | Service ID | {!! $service->service_id_url !!} | | Product | {{ $service->product_name }} | @switch($service->product_category) -@case('ADSL') +@case('BROADBAND') | Address | {{ $service->type->service_address }} | @break; -@case('VOIP') +@case('PHONE') | Number | {{ $service->type->service_number }} | | Supplier Details | {{ $service->order_info->join(':') }} | @break; @endswitch @endcomponent - **NOTES:** {{ $notes }} Thanks,
diff --git a/resources/views/email/admin/order/reject.blade.php b/resources/views/email/admin/order/reject.blade.php index 02c3da4..8f9bb23 100644 --- a/resources/views/email/admin/order/reject.blade.php +++ b/resources/views/email/admin/order/reject.blade.php @@ -4,21 +4,20 @@ @component('mail::panel') @component('mail::table') - | Service | Details | - | :---------- | :---------------- | - | Account | {{ $service->account_name }} ({!! $service->account->account_id_url !!}) | - | Service ID | {!! $service->service_id_url !!} | - | Product | {{ $service->product_name }} | - @switch($service->category) - @case('ADSL') - | Address | {{ is_object($service->service_voip) ? $service->service_voip->service_address : 'Not Supplied' }} | - @break; - @case('VOIP') - | Address | {{ is_object($service->service_voip) ? $service->service_voip->service_address : 'Not Supplied' }} | - | Supplier Details | {{ join(':',$service->order_info) }} | - @break; - @endswitch - +| Service | Details | +| :---------- | :---------------- | +| Account | {{ $service->account_name }} ({!! $service->account->account_id_url !!}) | +| Service ID | {!! $service->service_id_url !!} | +| Product | {{ $service->product_name }} | +@switch($service->category) +@case('BROADBAND') +| Address | {{ is_object($service->type) ? $service->type->service_address : 'Not Supplied' }} | +@break; +@case('PHONE') +| Address | {{ is_object($service->type) ? $service->type->service_address : 'Not Supplied' }} | +| Supplier Details | {{ join(':',$service->order_info) }} | +@break; +@endswitch @endcomponent **REASON:** {{ $reason }} diff --git a/resources/views/email/admin/service/cancel.blade.php b/resources/views/email/admin/service/cancel.blade.php index 03bb467..6c62f9e 100644 --- a/resources/views/email/admin/service/cancel.blade.php +++ b/resources/views/email/admin/service/cancel.blade.php @@ -9,17 +9,16 @@ Please cancel the following... | Service ID | {!! $service->service_id_url !!} | | Product | {{ $service->product_name }} | @switch($service->product_category) -@case('ADSL') +@case('BROADBAND') | Address | {{ $service->type->service_address }} | @break; -@case('VOIP') +@case('PHONE') | Number | {{ $service->type->service_number }} | | Supplier Details | {{ $service->order_info->join(':') }} | @break; @endswitch @endcomponent - **NOTES:** {{ $notes }} Thanks,
diff --git a/resources/views/email/admin/service/change.blade.php b/resources/views/email/admin/service/change.blade.php index 03ed39d..e098aab 100644 --- a/resources/views/email/admin/service/change.blade.php +++ b/resources/views/email/admin/service/change.blade.php @@ -9,17 +9,16 @@ Please change the following... | Service ID | {!! $service->service_id_url !!} | | Product | {{ $service->product_name }} | @switch($service->product_category) -@case('ADSL') +@case('BROADBAND') | Address | {{ $service->type->service_address }} | @break; -@case('VOIP') +@case('PHONE') | Number | {{ $service->type->service_number }} | | Supplier Details | {{ $service->order_info->join(':') }} | @break; @endswitch @endcomponent - **NOTES:** {{ $notes }} Thanks,
diff --git a/resources/views/theme/backend/adminlte/a/service/widgets/phone/update.blade.php b/resources/views/theme/backend/adminlte/a/service/widgets/phone/update.blade.php new file mode 100644 index 0000000..34d9746 --- /dev/null +++ b/resources/views/theme/backend/adminlte/a/service/widgets/phone/update.blade.php @@ -0,0 +1,72 @@ + +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
\ No newline at end of file diff --git a/resources/views/theme/backend/adminlte/a/service/widgets/voip/update.blade.php b/resources/views/theme/backend/adminlte/a/service/widgets/voip/update.blade.php deleted file mode 100644 index be6c89f..0000000 --- a/resources/views/theme/backend/adminlte/a/service/widgets/voip/update.blade.php +++ /dev/null @@ -1,72 +0,0 @@ - -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
\ 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 0e5fb4e..3f767ac 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 @@ -19,11 +19,12 @@
- +
+ @@ -36,11 +37,12 @@ @foreach ($o as $oo) - service_expire->isPast()) class="table-danger" @endif> + hasExpired()) class="table-danger" @endif> + - + @@ -67,14 +69,14 @@
Service ID AccountProduct Domain Expires Registrar
{{ $oo->service->sid }} {{ $oo->service->account->name }}{{ $oo->service->product->name }} {{ $oo->service_name }}{{ $oo->service_expire->format('Y-m-d') }}{{ $oo->service_expire ? $oo->service_expire->format('Y-m-d') : '-' }} {{ $oo->registrar->name }} {{ $oo->registrar_ns }} @if ($oo->service->isBilled()) {{ $oo->service->invoice_next->format('Y-m-d') }} @else - @endif