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',
'Product',
'Name',
'active',
'status',
'invoice next',
'start date',
'stop date',
'connect date',
'first invoice'
'Active',
'Status',
'Next Invoice',
'Start Date',
'Stop Date',
'Connect Date',
'First Invoice'
));
foreach (Service::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->with(['site'])->cursor() as $o) {
//dd($o,$o->site);
if ((! $this->option('inactive')) AND ! $o->isActive())
continue;
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;
$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,
$o->sid,
$o->product->getProductTypeAttribute(),
$o->product->getCategoryNameAttribute(),
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->start_at ? $o->start_at->format('Y-m-d') : NULL,
$o->stop_at ? $o->stop_at->format('Y-m-d') : NULL,
$o->invoice_next?->format('Y-m-d'),
$o->start_at?->format('Y-m-d'),
$o->stop_at?->format('Y-m-d'),
($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,
));

View File

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

View File

@ -77,11 +77,4 @@ interface SupplierItem
* @return 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 the type of account this is - if it has a company name, then its a business account.
*
* @return string
*/
public function getTypeAttribute()
{
return $this->company ? 'Business' : 'Private';

View File

@ -26,6 +26,8 @@ use App\Traits\{ProductDetails,SiteID};
* Attributes for products:
* + lid : Local 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
* + supplier : Supplier for this offering
* + 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
* This will return a product/* model.
*
* @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 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.
*
@ -241,17 +267,6 @@ class Product extends Model implements IDs
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
*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,4 +26,25 @@ abstract class Type extends Model
{
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\Traits\ScopeServiceUserAuthorised;
use App\Traits\SiteID;
/**
* Class Service
@ -50,7 +51,7 @@ use App\Traits\ScopeServiceUserAuthorised;
*/
class Service extends Model implements IDs
{
use HasFactory,ScopeServiceUserAuthorised;
use HasFactory,ScopeServiceUserAuthorised,SiteID;
protected $casts = [
'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 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
*
@ -707,16 +689,9 @@ class Service extends Model implements IDs
*/
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
: 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 SupplierType
* @todo This column provided_adsl_plan_id should either be deprecated or renamed.
*/
public function supplied(): SupplierType
{
return $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);
}
public function getTypeAttribute()
{
return strtolower((new \ReflectionClass($this))->getShortName());
}
/* METHODS */
/**
@ -105,6 +100,6 @@ abstract class Type extends Model implements ServiceItem
*/
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;
/* 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 = [
'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);
}
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">
<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" 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>
--}}
<li class="nav-item"><a class="nav-link" href="#services" data-toggle="tab">Services</a></li>
</ul>
</div>
@ -40,19 +36,9 @@
@include('a.product.widgets.detail')
</div>
{{--
<div class="tab-pane fade" id="products" role="tabpanel">
@include('a.product.widgets.products')
<div class="tab-pane fade" id="services" role="tabpanel">
@include('a.product.widgets.services')
</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>

View File

@ -41,7 +41,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</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>
@ -53,7 +53,10 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</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') : '' }}">
-->
</div>
</div>
</div>

View File

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

View File

@ -3,54 +3,86 @@
<thead>
<tr>
<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>&nbsp;</th>
@if ($s->exists)
<th>&nbsp;</th>
@endif
</tr>
</thead>
<tbody>
<tr>
<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>{{ $s->type }}</td>
@if ($s->exists)
<td>{{ $o->product->category_name }}</td>
@endif
</tr>
<tr>
<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($b=\App\Models\Tax::tax_calc($o->product->setup_charge,$o->account->taxes),2) }}</td>
<td>{!! markup($a,$b) !!}</td>
@else
<td>-</td>
@endif
</tr>
<tr>
<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>&nbsp;</td>
@if ($s->exists)
<td>&nbsp;</td>
@endif
</tr>
<tr>
<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>{!! markup($a,$b) !!}</td>
@if ($s->exists)
<td>{!! markup($a,$b) !!}</td>
@endif
</tr>
<tr>
<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>{!! markup($a,$b) !!}</td>
@if ($s->exists)
<td>{!! markup($a,$b) !!}</td>
@endif
</tr>
<tr>
<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>&nbsp;</td>
@if ($s->exists)
<td>&nbsp;</td>
@endif
</tr>
<tr>
<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($b=\App\Models\Tax::tax_calc($o->product->getMinChargeAttribute($o->billing_interval),$o->account->taxes),2) }}</td>
<td>{!! markup($a,$b) !!}</td>
@else
<td>-</td>
@endif
</tr>
</tbody>
</table>

View File

@ -5,7 +5,7 @@
<form class="g-0 needs-validation" method="POST" action="{{ url('a/service/edit',[$o->id]) }}">
@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="col-12">

View File

@ -38,7 +38,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">
<label for="notes" class="col-sm-2 col-form-label text-right">Notes</label>

View File

@ -38,7 +38,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">
<label for="notes" class="col-sm-2 col-form-label text-right">Notes</label>

View File

@ -44,7 +44,7 @@
</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">

View File

@ -43,7 +43,7 @@
</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">
<label for="notes" class="col-2 col-form-label text-right">Notes</label>

View File

@ -19,7 +19,7 @@
<!-- Service Details -->
<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')
</div>
@ -78,7 +78,7 @@
@if ($o->hasUsage())
<div class="tab-pane fade {{ (! $o->isBilled() && (! session()->has('service_update'))) ? 'active show' : '' }}" id="traffic" role="tabpanel">
@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
</div>
@endif

View File

@ -11,7 +11,7 @@
<thead>
<tr>
<th>ID</th>
<th>Type</th>
<th>Category</th>
<th>Service</th>
<th>Product</th>
<th>Next Invoice</th>
@ -22,7 +22,7 @@
@foreach ($o->services as $oo)
<tr>
<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->product->name }}</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}}]-->
@if(View::exists('order.widget.info.'.strtolower($o->product_type)))
<!-- $o = Product::class [{{$o->category}}]-->
@if(View::exists('order.widget.info.'.$o->category))
<div class="box box-primary">
<div class="box-body">
{{-- Return Category Requirements --}}
@include('order.widget.info.'.strtolower($o->product_type))
@include('order.widget.info.'.$o->category)
{{-- Return Supplier Requirements --}}
{{-- Return Product Requirements --}}

View File

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

@ -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">
<tr>
<th>Type</th>
<td class="text-right">{{ $o->product_type }}</td>
<td class="text-right">{{ $o->category_name }}</td>
</tr>
<tr>
<th>Setup Charges</th>

View File

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