Optimising product category and category names

This commit is contained in:
Deon George 2022-06-12 11:21:20 +10:00
parent 360c1e46a1
commit cc94426902
36 changed files with 269 additions and 156 deletions

View File

@ -40,22 +40,23 @@ class ServiceList extends Command
'Type', 'Type',
'Product', 'Product',
'Name', 'Name',
'active', 'Active',
'status', 'Status',
'invoice next', 'Next Invoice',
'start date', 'Start Date',
'stop date', 'Stop Date',
'connect date', 'Connect Date',
'first invoice' 'First Invoice'
)); ));
foreach (Service::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->with(['site'])->cursor() as $o) { foreach (Service::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->with(['site'])->cursor() as $o) {
//dd($o,$o->site);
if ((! $this->option('inactive')) AND ! $o->isActive()) if ((! $this->option('inactive')) AND ! $o->isActive())
continue; continue;
Config::set('site',$o->site); Config::set('site',$o->site);
if ($this->option('type') AND ($o->product->getProductTypeAttribute() !== $this->option('type'))) if ($this->option('type') AND ($o->product->getCategoryAttribute() !== $this->option('type')))
continue; continue;
$c = $o->invoice_items->filter(function($item) {return $item->item_type === 0; })->sortby('start_at')->first(); $c = $o->invoice_items->filter(function($item) {return $item->item_type === 0; })->sortby('start_at')->first();
@ -67,14 +68,14 @@ class ServiceList extends Command
$this->info(sprintf($header, $this->info(sprintf($header,
$o->sid, $o->sid,
$o->product->getProductTypeAttribute(), $o->product->getCategoryNameAttribute(),
substr($o->product->getNameAttribute(),0,35), substr($o->product->getNameAttribute(),0,35),
substr($o->name_short,0,40), substr($o->name_short,0,40),
$o->active ? 'active' : 'inactive', $o->active ? 'active' : 'inactive',
$o->status, $o->status,
$o->invoice_next ? $o->invoice_next->format('Y-m-d') : NULL, $o->invoice_next?->format('Y-m-d'),
$o->start_at ? $o->start_at->format('Y-m-d') : NULL, $o->start_at?->format('Y-m-d'),
$o->stop_at ? $o->stop_at->format('Y-m-d') : NULL, $o->stop_at?->format('Y-m-d'),
($o->type AND $o->type->connect_at) ? $o->type->connect_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, ($c && $c->date_start) ? $c->date_start->format('Y-m-d') : NULL,
)); ));

View File

@ -294,12 +294,12 @@ class ServiceController extends Controller
*/ */
public function update(Request $request,Service $o) public function update(Request $request,Service $o)
{ {
if ($request->post($o->type->type)) { if ($request->post($o->product->category)) {
$o->type->forceFill($request->post($o->type->type))->save(); $o->type->forceFill($request->post($o->product->category))->save();
} }
if ($request->post('start_at')) if ($request->post('start_at'))
$o->date_start = $request->start_at; $o->start_at = $request->start_at;
$o->save(); $o->save();

View File

@ -77,11 +77,4 @@ interface SupplierItem
* @return float * @return float
*/ */
public function getSetupCostTaxableAttribute(): float; public function getSetupCostTaxableAttribute(): float;
/**
* Return the type of offering this is.
*
* @return string
*/
public function getTypeAttribute();
} }

View File

@ -149,6 +149,11 @@ class Account extends Model implements IDs
return $this->company ?: ($this->user_id ? $this->user->getSurFirstNameAttribute() : 'LID:'.$this->id); return $this->company ?: ($this->user_id ? $this->user->getSurFirstNameAttribute() : 'LID:'.$this->id);
} }
/**
* Return the type of account this is - if it has a company name, then its a business account.
*
* @return string
*/
public function getTypeAttribute() public function getTypeAttribute()
{ {
return $this->company ? 'Business' : 'Private'; return $this->company ? 'Business' : 'Private';

View File

@ -26,6 +26,8 @@ use App\Traits\{ProductDetails,SiteID};
* Attributes for products: * Attributes for products:
* + lid : Local ID for product (part number) * + lid : Local ID for product (part number)
* + sid : System ID for product (part number) * + sid : System ID for product (part number)
* + category : Type of product supplied
* + category_name : Type of product supplied (Friendly Name for display, not for internal logic)
* + supplied : Supplier product provided for this offering * + supplied : Supplier product provided for this offering
* + supplier : Supplier for this offering * + supplier : Supplier for this offering
* + name : Brief Name for our product // @todo we should change this to be consistent with service * + name : Brief Name for our product // @todo we should change this to be consistent with service
@ -97,6 +99,7 @@ class Product extends Model implements IDs
/** /**
* Return a child model with details of the service * Return a child model with details of the service
* This will return a product/* model.
* *
* @return \Illuminate\Database\Eloquent\Relations\MorphTo * @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/ */
@ -176,6 +179,29 @@ class Product extends Model implements IDs
return max($this->price_recur_default,$this->getSuppliedAttribute()->getBillingIntervalAttribute()); return max($this->price_recur_default,$this->getSuppliedAttribute()->getBillingIntervalAttribute());
} }
/**
* Return the type of service is provided. eg: Broadband, Phone.
*
* @return string
* @todo Does type need to be a mandatory attribute on a model - then we can remove this condition
*/
public function getCategoryAttribute(): string
{
return $this->type ? $this->type->getCategoryAttribute() : 'generic';
}
/**
* This will return the category of the product (eg: domain, hosting, etc) which is the basis for all
* other logic of these types.
*
* @return string
* @todo Does type need to be a mandatory attribute on a model - then we can remove this condition
*/
public function getCategoryNameAttribute(): string
{
return $this->type ? $this->type->getCategoryNameAttribute() : 'Generic';
}
/** /**
* How long must this product be purchased for as a service. * How long must this product be purchased for as a service.
* *
@ -241,17 +267,6 @@ class Product extends Model implements IDs
return $this->description->description_full; return $this->description->description_full;
} }
/**
* Get our product type
*
* @return string
* @todo is the test of type and type->supplied necessary? (It seems some hosting entries have no type, are they old?)
*/
public function getProductTypeAttribute(): string
{
return ($this->type && $this->type->supplied) ? $this->getSuppliedAttribute()->getTypeAttribute() : 'Unknown';
}
/** /**
* Suppliers * Suppliers
* *

View File

@ -15,6 +15,8 @@ final class Broadband extends Type implements ProductItem
protected $table = 'product_broadband'; protected $table = 'product_broadband';
protected const category_name = 'Broadband';
// Information required during the order process // Information required during the order process
protected array $order_attributes = [ protected array $order_attributes = [
'options.address'=>[ 'options.address'=>[

View File

@ -12,6 +12,8 @@ final class Domain extends Type implements ProductItem
{ {
protected $table = 'product_domain'; protected $table = 'product_domain';
protected const category_name = 'Domain Name';
// The model that is referenced when this product is ordered // The model that is referenced when this product is ordered
protected string $order_model = ServiceDomain::class; protected string $order_model = ServiceDomain::class;
@ -57,11 +59,6 @@ final class Domain extends Type implements ProductItem
return ''; return '';
} }
public function getTypeAttribute()
{
return 'Domain Name';
}
public function hasUsage(): bool public function hasUsage(): bool
{ {
return FALSE; return FALSE;

View File

@ -12,6 +12,8 @@ final class Email extends Type implements ProductItem
{ {
protected $table = 'product_email'; protected $table = 'product_email';
protected const category_name = 'Email Hosting';
// The model that is referenced when this product is ordered // The model that is referenced when this product is ordered
protected string $order_model = ServiceEmail::class; protected string $order_model = ServiceEmail::class;
@ -57,11 +59,6 @@ final class Email extends Type implements ProductItem
return ''; return '';
} }
public function getTypeAttribute()
{
return 'Domain Name';
}
public function hasUsage(): bool public function hasUsage(): bool
{ {
return FALSE; return FALSE;

View File

@ -12,6 +12,8 @@ final class Generic extends Type implements ProductItem
{ {
protected $table = 'product_generic'; protected $table = 'product_generic';
protected const category_name = 'Generic';
// The model that is referenced when this product is ordered // The model that is referenced when this product is ordered
protected string $order_model = ServiceGeneric::class; protected string $order_model = ServiceGeneric::class;
@ -34,11 +36,6 @@ final class Generic extends Type implements ProductItem
return 0; return 0;
} }
public function getTypeAttribute()
{
return 'Generic';
}
public function hasUsage(): bool public function hasUsage(): bool
{ {
return FALSE; return FALSE;

View File

@ -12,6 +12,8 @@ final class Host extends Type implements ProductItem
{ {
protected $table = 'product_host'; protected $table = 'product_host';
protected const category_name = 'Web Hosting';
// The model that is referenced when this product is ordered // The model that is referenced when this product is ordered
protected string $order_model = ServiceHost::class; protected string $order_model = ServiceHost::class;
@ -34,11 +36,6 @@ final class Host extends Type implements ProductItem
return 12; return 12;
} }
public function getTypeAttribute()
{
return 'Hosting';
}
public function hasUsage(): bool public function hasUsage(): bool
{ {
return FALSE; return FALSE;

View File

@ -12,6 +12,8 @@ final class Phone extends Type implements ProductItem
{ {
protected $table = 'product_phone'; protected $table = 'product_phone';
protected const category_name = 'Telephone';
protected array $order_attributes = [ protected array $order_attributes = [
'options.phonenumber'=>[ 'options.phonenumber'=>[
'request'=>'options.phonenumber', 'request'=>'options.phonenumber',
@ -62,11 +64,6 @@ final class Phone extends Type implements ProductItem
return 12; return 12;
} }
public function getTypeAttribute()
{
return 'PHONE';
}
public function hasUsage(): bool public function hasUsage(): bool
{ {
return FALSE; return FALSE;

View File

@ -12,6 +12,8 @@ final class SSL extends Type implements ProductItem
{ {
protected $table = 'product_ssl'; protected $table = 'product_ssl';
protected const category_name = 'SSL Certificate';
// The model that is referenced when this product is ordered // The model that is referenced when this product is ordered
protected string $order_model = ServiceSSL::class; protected string $order_model = ServiceSSL::class;
@ -61,11 +63,6 @@ final class SSL extends Type implements ProductItem
return $o; return $o;
} }
public function getTypeAttribute()
{
return 'SSL Certificate';
}
public function hasUsage(): bool public function hasUsage(): bool
{ {
return FALSE; return FALSE;

View File

@ -26,4 +26,25 @@ abstract class Type extends Model
{ {
return $this->morphOne(Product::class, null,'model','model_id'); return $this->morphOne(Product::class, null,'model','model_id');
} }
/**
* This will return the category of the product (eg: domain, hosting, etc) which is the basis for all
* other logic of these types.
*
* @return string
*/
final public function getCategoryAttribute(): string
{
return strtolower((new \ReflectionClass($this))->getShortName());
}
/**
* Return a friendly name for this product, used for display
*
* @return string
*/
final public function getCategoryNameAttribute(): string
{
return static::category_name;
}
} }

View File

@ -20,6 +20,7 @@ use Leenooks\Carbon as LeenooksCarbon;
use App\Interfaces\IDs; use App\Interfaces\IDs;
use App\Traits\ScopeServiceUserAuthorised; use App\Traits\ScopeServiceUserAuthorised;
use App\Traits\SiteID;
/** /**
* Class Service * Class Service
@ -50,7 +51,7 @@ use App\Traits\ScopeServiceUserAuthorised;
*/ */
class Service extends Model implements IDs class Service extends Model implements IDs
{ {
use HasFactory,ScopeServiceUserAuthorised; use HasFactory,ScopeServiceUserAuthorised,SiteID;
protected $casts = [ protected $casts = [
'order_info'=>AsCollection::class, 'order_info'=>AsCollection::class,
@ -472,25 +473,6 @@ class Service extends Model implements IDs
return number_format($this->getBillingChargeAttribute()/Arr::get(Invoice::billing_periods,$this->recur_schedule.'.interval',1),2); return number_format($this->getBillingChargeAttribute()/Arr::get(Invoice::billing_periods,$this->recur_schedule.'.interval',1),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 * The date the contract ends
* *
@ -707,16 +689,9 @@ class Service extends Model implements IDs
*/ */
public function getInvoiceToAttribute(): ?LeenooksCarbon public function getInvoiceToAttribute(): ?LeenooksCarbon
{ {
$result = ($x=$this->invoice_items->filter(function($item) { return $item->item_type === 0;}))->count() return ($x=$this->invoice_items->filter(function($item) { return $item->item_type === 0;}))->count()
? $x->last()->stop_at ? $x->last()->stop_at
: NULL; : NULL;
// For SSL Certificates, the invoice_to date is the expiry date of the Cert
// @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;
} }
/** /**

View File

@ -105,12 +105,13 @@ class Broadband extends Type implements ServiceUsage
* Return the suppliers offering that this service is providing * Return the suppliers offering that this service is providing
* *
* @return SupplierType * @return SupplierType
* @todo This column provided_adsl_plan_id should either be deprecated or renamed.
*/ */
public function supplied(): SupplierType public function supplied(): SupplierType
{ {
return $this->provided_adsl_plan_id return $this->provided_adsl_plan_id
? SupplierBroadband::findOrFail($this->provided_adsl_plan_id) ? SupplierBroadband::findOrFail($this->provided_adsl_plan_id)
: $this->service->product->type->supplied; : $this->service->offering->supplied;
} }
/** /**

View File

@ -91,11 +91,6 @@ abstract class Type extends Model implements ServiceItem
return LeenooksCarbon::create($value); return LeenooksCarbon::create($value);
} }
public function getTypeAttribute()
{
return strtolower((new \ReflectionClass($this))->getShortName());
}
/* METHODS */ /* METHODS */
/** /**
@ -105,6 +100,6 @@ abstract class Type extends Model implements ServiceItem
*/ */
public function supplied(): SupplierType public function supplied(): SupplierType
{ {
return $this->service->product->type->supplied; return $this->service->offering->supplied ?: new \App\Models\Supplier\Generic();
} }
} }

View File

@ -16,7 +16,11 @@ class Supplier extends Model
public $timestamps = FALSE; public $timestamps = FALSE;
/* The offerings we provide */ /**
* The offerings we provide
* @todo Use the product/* category instead of this const. The assumption is the supplier/* type is the same as the product/* type.
* @deprecated - use the product/* category instead.
*/
public const offering_types = [ public const offering_types = [
'broadband' => [ 'broadband' => [
'name' => 'Broadband', 'name' => 'Broadband',

View File

@ -63,9 +63,4 @@ abstract class Type extends Model
{ {
return Tax::tax_calc($this->attributes['setup_cost'],config('site')->taxes); return Tax::tax_calc($this->attributes['setup_cost'],config('site')->taxes);
} }
public function getTypeAttribute(): string
{
return Arr::get(collect(Supplier::offering_types)->firstWhere('class',get_class($this)),'name','Unknown');
}
} }

View File

@ -26,11 +26,7 @@
<div class="card-header bg-dark d-flex p-0"> <div class="card-header bg-dark d-flex p-0">
<ul class="nav nav-pills w-100 p-2"> <ul class="nav nav-pills w-100 p-2">
<li class="nav-item"><a class="nav-link active" href="#details" data-toggle="tab">Detail</a></li> <li class="nav-item"><a class="nav-link active" href="#details" data-toggle="tab">Detail</a></li>
{{-- <li class="nav-item"><a class="nav-link" href="#services" data-toggle="tab">Services</a></li>
<li class="nav-item"><a class="nav-link" href="#products" data-toggle="tab">Products</a></li>
<li class="nav-item"><a class="nav-link" href="#offerings" data-toggle="tab">Offerings</a></li>
<li class="nav-item"><a class="nav-link" href="#connections" data-toggle="tab">Connections</a></li>
--}}
</ul> </ul>
</div> </div>
@ -40,19 +36,9 @@
@include('a.product.widgets.detail') @include('a.product.widgets.detail')
</div> </div>
{{-- <div class="tab-pane fade" id="services" role="tabpanel">
<div class="tab-pane fade" id="products" role="tabpanel"> @include('a.product.widgets.services')
@include('a.product.widgets.products')
</div> </div>
<div class="tab-pane fade" id="offerings" role="tabpanel">
@include('a.product.widgets.offerings')
</div>
<div class="tab-pane fade" id="connections" role="tabpanel">
@include('a.product.widgets.connections')
</div>
--}}
</div> </div>
</div> </div>
</div> </div>

View File

@ -41,7 +41,7 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div> </div>
<input type="date" class="form-control" name="broadband[service_connect_date]" value="{{ $o->service_connect_date ? $o->service_connect_date->format('Y-m-d') : '' }}"> <input type="date" class="form-control" name="broadband[connect_at]" value="{{ $o->connect_at ? $o->connect_at->format('Y-m-d') : '' }}">
</div> </div>
</div> </div>
</div> </div>
@ -53,7 +53,10 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div> </div>
<!-- @todo We changed contract_date in the DB, what happened to it and how do we work it out now -->
<!--
<input type="date" class="form-control" name="broadband[service_contract_date]" value="{{ $o->service_contract_date ? $o->service_contract_date->format('Y-m-d') : '' }}"> <input type="date" class="form-control" name="broadband[service_contract_date]" value="{{ $o->service_contract_date ? $o->service_contract_date->format('Y-m-d') : '' }}">
-->
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
<!-- o = App\Models\Service\Email::class --> <!-- o = App\Models\Service\Host::class -->
<div class="row"> <div class="row">
<!-- DOMAIN NAME --> <!-- DOMAIN NAME -->
<div class="col-6"> <div class="col-6">

View File

@ -3,54 +3,86 @@
<thead> <thead>
<tr> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>{{ ($s=$o->supplied)->supplier_detail->supplier->name }}</th> @if (($s=$o->supplied) && $s->exists)
<th>{{ $s->supplier_detail->supplier->name }}</th>
@endif
<th>Us</th> <th>Us</th>
<th>&nbsp;</th> @if ($s->exists)
<th>&nbsp;</th>
@endif
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<th>Product</th> <th>Product</th>
<td>#{{ $s->id }}: {{ $s->name }}</td> @if ($s->exists)
<td>#{{ $s->id }}: {{ $s->name }}</td>
@endif
<td>#{{ $o->product->id }}: {{ $o->product->name }}</td> <td>#{{ $o->product->id }}: {{ $o->product->name }}</td>
<td>{{ $s->type }}</td> @if ($s->exists)
<td>{{ $o->product->category_name }}</td>
@endif
</tr> </tr>
<tr> <tr>
<th>Setup</th> <th>Setup</th>
@if ($s->exists)
<td>${{ number_format($a=\App\Models\Tax::tax_calc($s->setup_cost,$o->account->taxes),2) }}</td> <td>${{ number_format($a=\App\Models\Tax::tax_calc($s->setup_cost,$o->account->taxes),2) }}</td>
<td>${{ number_format($b=\App\Models\Tax::tax_calc($o->product->setup_charge,$o->account->taxes),2) }}</td> <td>${{ number_format($b=\App\Models\Tax::tax_calc($o->product->setup_charge,$o->account->taxes),2) }}</td>
<td>{!! markup($a,$b) !!}</td> <td>{!! markup($a,$b) !!}</td>
@else
<td>-</td>
@endif
</tr> </tr>
<tr> <tr>
<th>Billed</th> <th>Billed</th>
<td>{{ $s->billing_interval_string }}</td> @if ($s->exists)
<td>{{ $s->billing_interval_string }}</td>
@endif
<td>{{ $o->billing_interval_string }}</td> <td>{{ $o->billing_interval_string }}</td>
<td>&nbsp;</td> @if ($s->exists)
<td>&nbsp;</td>
@endif
</tr> </tr>
<tr> <tr>
<th>Billing Price</th> <th>Billing Price</th>
<td>${{ number_format($a=\App\Models\Tax::tax_calc($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,$o->product->billing_interval),$o->account->taxes),2) }}</td> @if ($s->exists)
<td>${{ number_format($a=\App\Models\Tax::tax_calc($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,$o->product->billing_interval),$o->account->taxes),2) }}</td>
@endif
<td>${{ number_format($b=$o->billing_charge,2) }}</td> <td>${{ number_format($b=$o->billing_charge,2) }}</td>
<td>{!! markup($a,$b) !!}</td> @if ($s->exists)
<td>{!! markup($a,$b) !!}</td>
@endif
</tr> </tr>
<tr> <tr>
<th>Monthly Price</th> <th>Monthly Price</th>
<td>${{ number_format($a=\App\Models\Tax::tax_calc($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,1),$o->account->taxes),2) }}</td> @if ($s->exists)
<td>${{ number_format($a=\App\Models\Tax::tax_calc($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,1),$o->account->taxes),2) }}</td>
@endif
<td>${{ number_format($b=$o->billing_monthly_price,2) }}</td> <td>${{ number_format($b=$o->billing_monthly_price,2) }}</td>
<td>{!! markup($a,$b) !!}</td> @if ($s->exists)
<td>{!! markup($a,$b) !!}</td>
@endif
</tr> </tr>
<tr> <tr>
<th>Contract</th> <th>Contract</th>
<td>{{ $s->contract_term }} months</td> @if ($s->exists)
<td>{{ $s->contract_term }} months</td>
@endif
<td>{{ $o->contract_term }} months</td> <td>{{ $o->contract_term }} months</td>
<td>&nbsp;</td> @if ($s->exists)
<td>&nbsp;</td>
@endif
</tr> </tr>
<tr> <tr>
<th>Min Price</th> <th>Min Price</th>
@if ($s->exists)
<td>${{ number_format($a=\App\Models\Tax::tax_calc($s->min_cost,$o->account->taxes),2) }}</td> <td>${{ number_format($a=\App\Models\Tax::tax_calc($s->min_cost,$o->account->taxes),2) }}</td>
<td>${{ number_format($b=\App\Models\Tax::tax_calc($o->product->getMinChargeAttribute($o->billing_interval),$o->account->taxes),2) }}</td> <td>${{ number_format($b=\App\Models\Tax::tax_calc($o->product->getMinChargeAttribute($o->billing_interval),$o->account->taxes),2) }}</td>
<td>{!! markup($a,$b) !!}</td> <td>{!! markup($a,$b) !!}</td>
@else
<td>-</td>
@endif
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -5,7 +5,7 @@
<form class="g-0 needs-validation" method="POST" action="{{ url('a/service/edit',[$o->id]) }}"> <form class="g-0 needs-validation" method="POST" action="{{ url('a/service/edit',[$o->id]) }}">
@csrf @csrf
@includeIf('a.service.widgets.'.$o->type->type.'.update',['o'=>$o->type]) @includeIf('a.service.widgets.'.$o->product->category.'.update',['o'=>$o->type])
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">

View File

@ -38,7 +38,7 @@
</div> </div>
</div> </div>
@includeIf('u.service.widgets.'.$o->type->type.'.order',['o'=>$o->type]) @includeIf('u.service.widgets.'.$o->product->category.'.order',['o'=>$o->type])
<div class="form-group row"> <div class="form-group row">
<label for="notes" class="col-sm-2 col-form-label text-right">Notes</label> <label for="notes" class="col-sm-2 col-form-label text-right">Notes</label>

View File

@ -38,7 +38,7 @@
</div> </div>
</div> </div>
@includeIf('u.service.widgets.'.$o->type->type.'.order',['o'=>$o->type]) @includeIf('u.service.widgets.'.$o->product->category.'.order',['o'=>$o->type])
<div class="form-group row"> <div class="form-group row">
<label for="notes" class="col-sm-2 col-form-label text-right">Notes</label> <label for="notes" class="col-sm-2 col-form-label text-right">Notes</label>

View File

@ -44,7 +44,7 @@
</div> </div>
{{-- {{--
@includeIf('u.service.widgets.'.$o->type->type.'.order',['o'=>$o->type]) @includeIf('u.service.widgets.'.$o->product->category.'.order',['o'=>$o->type])
--}} --}}
<div class="form-group row"> <div class="form-group row">

View File

@ -43,7 +43,7 @@
</div> </div>
</div> </div>
@includeIf('u.service.widgets.'.$o->type->type.'.change',['o'=>$o->type]) @includeIf('u.service.widgets.'.$o->product->category.'.change',['o'=>$o->type])
<div class="form-group row"> <div class="form-group row">
<label for="notes" class="col-2 col-form-label text-right">Notes</label> <label for="notes" class="col-2 col-form-label text-right">Notes</label>

View File

@ -19,7 +19,7 @@
<!-- Service Details --> <!-- Service Details -->
<div class="col-5"> <div class="col-5">
@includeIf('u.service.widgets.'.$o->type->type.'.details',['o'=>$o->type]) @includeIf('u.service.widgets.'.$o->product->category.'.details',['o'=>$o->type])
@include('u.service.widgets.information') @include('u.service.widgets.information')
</div> </div>
@ -78,7 +78,7 @@
@if ($o->hasUsage()) @if ($o->hasUsage())
<div class="tab-pane fade {{ (! $o->isBilled() && (! session()->has('service_update'))) ? 'active show' : '' }}" id="traffic" role="tabpanel"> <div class="tab-pane fade {{ (! $o->isBilled() && (! session()->has('service_update'))) ? 'active show' : '' }}" id="traffic" role="tabpanel">
@if ($o->type->usage(30)->count()) @if ($o->type->usage(30)->count())
@include('u.service.widgets.'.$o->type->type.'.usagegraph',['o'=>$o->type]) @include('u.service.widgets.'.$o->product->category.'.usagegraph',['o'=>$o->type])
@endif @endif
</div> </div>
@endif @endif

View File

@ -11,7 +11,7 @@
<thead> <thead>
<tr> <tr>
<th>ID</th> <th>ID</th>
<th>Type</th> <th>Category</th>
<th>Service</th> <th>Service</th>
<th>Product</th> <th>Product</th>
<th>Next Invoice</th> <th>Next Invoice</th>
@ -22,7 +22,7 @@
@foreach ($o->services as $oo) @foreach ($o->services as $oo)
<tr> <tr>
<td><a href="{{ url('u/service',[$oo->id]) }}">{{ $oo->sid }}</a></td> <td><a href="{{ url('u/service',[$oo->id]) }}">{{ $oo->sid }}</a></td>
<td>{{ $oo->category }}</td> <td>{{ $oo->product->category_name }}</td>
<td>{{ $oo->name_short }}</td> <td>{{ $oo->name_short }}</td>
<td>{{ $oo->product->name }}</td> <td>{{ $oo->product->name }}</td>
<td>{{ $oo->external_billing ? '-' : $oo->invoice_next->format('Y-m-d') }}</td> <td>{{ $oo->external_billing ? '-' : $oo->invoice_next->format('Y-m-d') }}</td>

View File

@ -1,9 +1,9 @@
<!-- $o = Product::class [{{$o->product_type}}]--> <!-- $o = Product::class [{{$o->category}}]-->
@if(View::exists('order.widget.info.'.strtolower($o->product_type))) @if(View::exists('order.widget.info.'.$o->category))
<div class="box box-primary"> <div class="box box-primary">
<div class="box-body"> <div class="box-body">
{{-- Return Category Requirements --}} {{-- Return Category Requirements --}}
@include('order.widget.info.'.strtolower($o->product_type)) @include('order.widget.info.'.$o->category)
{{-- Return Supplier Requirements --}} {{-- Return Supplier Requirements --}}
{{-- Return Product Requirements --}} {{-- Return Product Requirements --}}

View File

@ -6,7 +6,7 @@
<table class="table table-condensed"> <table class="table table-condensed">
<tr> <tr>
<th>Type</th> <th>Type</th>
<td class="text-right">{{ $o->product_type }}</td> <td class="text-right">{{ $o->category_name }}</td>
</tr> </tr>
<tr> <tr>
<th>Setup Charges <sup>*</sup></th> <th>Setup Charges <sup>*</sup></th>
@ -30,9 +30,13 @@
</tr> </tr>
<tfoot> <tfoot>
<tr><td colspan="2"><sup> <tr>
* Additional setup charges may apply for complex installations.<br> <td colspan="2">
+ Additional charges may apply for regional installations. <sup>
</sup></td></tr> * Additional setup charges may apply for complex installations.<br>
+ Additional charges may apply for regional installations.
</sup>
</td>
</tr>
</tfoot> </tfoot>
</table> </table>

View File

@ -0,0 +1,33 @@
<!-- $o = Product::class -->
<div class="col-md-12">
<p>{!! $o->name_long !!}</p>
</div>
<table class="table table-condensed">
<tr>
<th>Type</th>
<td class="text-right">{{ $o->category_name }}</td>
</tr>
<tr>
<th>Setup Charges <sup>*</sup></th>
<td class="text-right">${{ number_format($o->setup_charge_taxable,2) }}</td>
</tr>
<tr>
<th>Cost <sup>+</sup></th>
<td class="text-right">${{ number_format($o->base_charge_taxable,2) }}</td>
</tr>
<tr>
<th>Default Billing</th>
<td class="text-right">{{ $o->billing_interval_string }}</td>
</tr>
<tr>
<th>Contract Term</th>
<td class="text-right">{{ $o->contract_term }} mths</td>
</tr>
<tr>
<th>Minimum Costs <sup>+*</sup></th>
<td class="text-right">${{ number_format($o->min_charge_taxable,2) }}</td>
</tr>
<tfoot>
</table>

View File

@ -0,0 +1,33 @@
<!-- $o = Product::class -->
<div class="col-md-12">
<p>{!! $o->name_long !!}</p>
</div>
<table class="table table-condensed">
<tr>
<th>Type</th>
<td class="text-right">{{ $o->category_name }}</td>
</tr>
<tr>
<th>Setup Charges <sup>*</sup></th>
<td class="text-right">${{ number_format($o->setup_charge_taxable,2) }}</td>
</tr>
<tr>
<th>Cost <sup>+</sup></th>
<td class="text-right">${{ number_format($o->base_charge_taxable,2) }}</td>
</tr>
<tr>
<th>Default Billing</th>
<td class="text-right">{{ $o->billing_interval_string }}</td>
</tr>
<tr>
<th>Contract Term</th>
<td class="text-right">{{ $o->contract_term }} mths</td>
</tr>
<tr>
<th>Minimum Costs <sup>+*</sup></th>
<td class="text-right">${{ number_format($o->min_charge_taxable,2) }}</td>
</tr>
<tfoot>
</table>

View File

@ -0,0 +1,33 @@
<!-- $o = Product::class -->
<div class="col-md-12">
<p>{!! $o->name_long !!}</p>
</div>
<table class="table table-condensed">
<tr>
<th>Type</th>
<td class="text-right">{{ $o->category_name }}</td>
</tr>
<tr>
<th>Setup Charges <sup>*</sup></th>
<td class="text-right">${{ number_format($o->setup_charge_taxable,2) }}</td>
</tr>
<tr>
<th>Cost <sup>+</sup></th>
<td class="text-right">${{ number_format($o->base_charge_taxable,2) }}</td>
</tr>
<tr>
<th>Default Billing</th>
<td class="text-right">{{ $o->billing_interval_string }}</td>
</tr>
<tr>
<th>Contract Term</th>
<td class="text-right">{{ $o->contract_term }} mths</td>
</tr>
<tr>
<th>Minimum Costs <sup>+*</sup></th>
<td class="text-right">${{ number_format($o->min_charge_taxable,2) }}</td>
</tr>
<tfoot>
</table>

View File

@ -6,7 +6,7 @@
<table class="table table-condensed"> <table class="table table-condensed">
<tr> <tr>
<th>Type</th> <th>Type</th>
<td class="text-right">{{ $o->product_type }}</td> <td class="text-right">{{ $o->category_name }}</td>
</tr> </tr>
<tr> <tr>
<th>Setup Charges</th> <th>Setup Charges</th>

View File

@ -1,5 +1,5 @@
<!-- $o = Product::class --> <!-- $o = Product::class [{{$o->category}}] -->
@if(View::exists('order.widget.order.'.strtolower($o->product_type))) @if(View::exists('order.widget.order.'.$o->category))
<div class="box box-primary"> <div class="box box-primary">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title">Order Configuration</h3> <h3 class="box-title">Order Configuration</h3>
@ -7,7 +7,7 @@
<div class="box-body"> <div class="box-body">
{{-- Return Category Requirements --}} {{-- Return Category Requirements --}}
@include('order.widget.order.'.strtolower($o->product_type)) @include('order.widget.order.'.$o->category)
{{-- Return Supplier Requirements --}} {{-- Return Supplier Requirements --}}
{{-- Return Product Requirements --}} {{-- Return Product Requirements --}}