More Product Model optimisation
This commit is contained in:
parent
96f799f535
commit
820ff2be00
@ -20,30 +20,6 @@ interface ProductItem
|
||||
*/
|
||||
public function allowance_string(): string;
|
||||
|
||||
/**
|
||||
* Return the contract term for this product when sold as a service
|
||||
*
|
||||
* @return int Months
|
||||
*/
|
||||
public function getContractTermAttribute(): int;
|
||||
|
||||
/**
|
||||
* Return the product cost
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getCostAttribute(): float;
|
||||
|
||||
/**
|
||||
* Return the supplier class
|
||||
* If there is a model relationship return:
|
||||
* return $this->getRelationValue('supplier');
|
||||
* otherwise return a stdClass with name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSupplierAttribute();
|
||||
|
||||
/**
|
||||
* Does this offering capture usage information
|
||||
*
|
||||
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Interfaces;
|
||||
|
||||
interface SupplierItem
|
||||
{
|
||||
/* RELATIONS */
|
||||
|
||||
/**
|
||||
* Supplier that provides this offering
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function supplier_detail();
|
||||
|
||||
/**
|
||||
* Available products created from this supplier offering
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function products();
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
/**
|
||||
* Return the billing interval base cost including tax
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getBaseCostTaxableAttribute(): float;
|
||||
|
||||
/**
|
||||
* Return the billing interval that the supplier charges
|
||||
*
|
||||
* @return string
|
||||
* @deprecated use Product::normalizeBillingInterval()
|
||||
*/
|
||||
public function getBillingIntervalAttribute(): int;
|
||||
|
||||
/**
|
||||
* The term that the supplier imposes on this service being connected
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getContractTermAttribute(): int;
|
||||
|
||||
/**
|
||||
* The minimum cost of ordering this offering
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getMinCostAttribute(): float;
|
||||
|
||||
/**
|
||||
* The minimum cost of ordering this offering including taxes
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getMinCostTaxableAttribute(): float;
|
||||
|
||||
/**
|
||||
* Suppliers offering name (short)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNameAttribute(): string;
|
||||
|
||||
/**
|
||||
* Suppliers offering name (long)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNameLongAttribute(): string;
|
||||
|
||||
/**
|
||||
* Return the setup cost including tax
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSetupCostTaxableAttribute(): float;
|
||||
}
|
@ -193,4 +193,15 @@ class Account extends Model implements IDs
|
||||
return $item->active AND $item->due > 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the taxed value of a value
|
||||
*
|
||||
* @param float $value
|
||||
* @return float
|
||||
*/
|
||||
public function taxed(float $value): float
|
||||
{
|
||||
return Tax::calc($value,$this->taxes);
|
||||
}
|
||||
}
|
@ -41,11 +41,8 @@ use App\Traits\{ProductDetails,SiteID};
|
||||
* + billing_interval : Default Billing Interval
|
||||
* + billing_interval_string: Default Billing Interval in human-readable form
|
||||
* + setup_charge : Charge to setup this product
|
||||
* + setup_charge_taxable : Charge to setup this product including taxes
|
||||
* + base_charge : Default billing amount
|
||||
* + base_charge_taxable : Default billing amount including taxes
|
||||
* + min_charge : Minimum charge taking into account billing interval and setup charges
|
||||
* + min_charge_taxable : Minimum charge taking into account billing interval and setup charges including taxes
|
||||
*
|
||||
* Attributes for product types (type - Product/*)
|
||||
* + name : Short Name for our Product
|
||||
@ -65,7 +62,6 @@ use App\Traits\{ProductDetails,SiteID};
|
||||
* ]
|
||||
* ]
|
||||
*
|
||||
* @todo doesnt appear that price_type is used - but could be used to have different offering types billed differently
|
||||
* @package App\Models
|
||||
*/
|
||||
class Product extends Model implements IDs
|
||||
@ -170,20 +166,6 @@ class Product extends Model implements IDs
|
||||
return $this->_charge('base',$timeperiod,$go);
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount we invoice each time period for this service, including taxes
|
||||
*
|
||||
* @param int|null $timeperiod
|
||||
* @param Group|null $go
|
||||
* @param Collection|NULL $taxes
|
||||
* @return float
|
||||
* @deprecated move to account::tax_calc
|
||||
*/
|
||||
public function getBaseChargeTaxableAttribute(int $timeperiod=NULL,Group $go=NULL,Collection $taxes=NULL): float
|
||||
{
|
||||
return Tax::tax_calc($this->getBaseChargeAttribute($timeperiod,$go),$taxes ?: config('site')->taxes);
|
||||
}
|
||||
|
||||
/**
|
||||
* The base cost of this product at the appropriate billing interval
|
||||
*
|
||||
@ -191,19 +173,7 @@ class Product extends Model implements IDs
|
||||
*/
|
||||
public function getBaseCostAttribute(): float
|
||||
{
|
||||
return $this->supplied->base_cost*Invoice::billing_change($this->supplied->billing_interval,$this->billing_interval) ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base cost of this product at the appropriate billing interval including taxes
|
||||
*
|
||||
* @param Collection|NULL $taxes
|
||||
* @return float
|
||||
* @deprecated move to account::tax_calc
|
||||
*/
|
||||
public function getBaseCostTaxableAttribute(Collection $taxes=NULL): float
|
||||
{
|
||||
return Tax::tax_calc($this->getBaseCostAttribute(),$taxes ?: config('site')->taxes);;
|
||||
return $this->supplied->base_cost*Invoice::billing_change($this->type->normalizeBillingInterval(),$this->billing_interval) ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,7 +184,7 @@ class Product extends Model implements IDs
|
||||
*/
|
||||
public function getBillingIntervalAttribute(): int
|
||||
{
|
||||
return max($this->price_recur_default,$this->supplied->billing_interval);
|
||||
return max($this->price_recur_default,$this->type->normalizeBillingInterval());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -272,20 +242,6 @@ class Product extends Model implements IDs
|
||||
return $this->getSetupChargeAttribute($timeperiod,$go)+$this->getBaseChargeAttribute($timeperiod,$go)*Invoice::billing_term($this->type->contract_term,$this->getBillingIntervalAttribute());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum cost of this product with taxes
|
||||
*
|
||||
* @param int|null $timeperiod
|
||||
* @param Group|null $go
|
||||
* @param Collection|NULL $taxes
|
||||
* @return float
|
||||
* @deprecated move to account::tax_calc
|
||||
*/
|
||||
public function getMinChargeTaxableAttribute(int $timeperiod=NULL,Group $go=NULL,Collection $taxes=NULL): float
|
||||
{
|
||||
return Tax::tax_calc($this->getMinChargeAttribute($timeperiod,$go),$taxes ?: config('site')->taxes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Our products short descriptive name
|
||||
*
|
||||
@ -348,20 +304,6 @@ class Product extends Model implements IDs
|
||||
return $this->_charge('setup',$timeperiod,$go);
|
||||
}
|
||||
|
||||
/**
|
||||
* The charge to setup this service including taxes
|
||||
*
|
||||
* @param int|null $timeperiod
|
||||
* @param Group|null $go
|
||||
* @param Collection|null $taxes
|
||||
* @return float
|
||||
* @deprecated move to account::tax_calc
|
||||
*/
|
||||
public function getSetupChargeTaxableAttribute(int $timeperiod=NULL,Group $go=NULL,Collection $taxes=NULL): float
|
||||
{
|
||||
return Tax::tax_calc($this->getSetupChargeAttribute($timeperiod,$go),$taxes ?: config('site')->taxes);
|
||||
}
|
||||
|
||||
/**
|
||||
* The cost to setup this service
|
||||
*
|
||||
@ -372,18 +314,6 @@ class Product extends Model implements IDs
|
||||
return $this->supplied->setup_cost ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The charge to setup this service
|
||||
*
|
||||
* @param Collection|null $taxes
|
||||
* @return float
|
||||
* @deprecated move to account::tax_calc
|
||||
*/
|
||||
public function getSetupCostTaxableAttribute(Collection $taxes=NULL): float
|
||||
{
|
||||
return Tax::tax_calc($this->getSetupCostAttribute(),$taxes ?: config('site')->taxes);;
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
|
||||
/**
|
||||
@ -457,11 +387,10 @@ class Product extends Model implements IDs
|
||||
*
|
||||
* @note: By definition products are normalised, as their cost price is based on the default billing interval
|
||||
* @return float
|
||||
* @todo Move tax calculations out
|
||||
*/
|
||||
public function cost_normalized(): float
|
||||
{
|
||||
return number_format(Tax::tax_calc($this->supplied->base_cost,config('site')->taxes),2);
|
||||
return number_format(config('site')->taxed($this->supplied->base_cost),2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,31 +118,6 @@ final class Broadband extends Type implements ProductItem
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The product contract term is the highest of
|
||||
* + This defined contract_term
|
||||
* + The suppliers contract_term
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
return max($this->attributes['contract_term'],$this->supplied->getContractTermAttribute());
|
||||
}
|
||||
|
||||
public function getCostAttribute(): float
|
||||
{
|
||||
abort(500,'deprecated');
|
||||
// @todo Tax shouldnt be hard coded
|
||||
return ($this->supplied->base_cost+$this->allowance_cost())*1.1;
|
||||
}
|
||||
|
||||
public function getSupplierAttribute()
|
||||
{
|
||||
abort(500,'deprecated');
|
||||
return $this->getRelationValue('supplier');
|
||||
}
|
||||
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
return TRUE;
|
||||
|
@ -51,22 +51,6 @@ final class Domain extends Type implements ProductItem
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
|
||||
public function getCostAttribute(): float
|
||||
{
|
||||
// N/A
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getSupplierAttribute()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
return FALSE;
|
||||
|
@ -35,22 +35,6 @@ final class Email extends Type implements ProductItem
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
|
||||
public function getCostAttribute(): float
|
||||
{
|
||||
// N/A
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getSupplierAttribute()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
return FALSE;
|
||||
|
@ -23,16 +23,6 @@ final class Generic extends Type implements ProductItem
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function allowance(): Collection
|
||||
{
|
||||
// TODO: Implement allowance() method.
|
||||
@ -43,13 +33,8 @@ final class Generic extends Type implements ProductItem
|
||||
// TODO: Implement allowance_string() method.
|
||||
}
|
||||
|
||||
public function getCostAttribute(): float
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
// TODO: Implement getCostAttribute() method.
|
||||
}
|
||||
|
||||
public function getSupplierAttribute()
|
||||
{
|
||||
// TODO: Implement getSupplierAttribute() method.
|
||||
return FALSE;
|
||||
}
|
||||
}
|
@ -23,16 +23,6 @@ final class Host extends Type implements ProductItem
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function allowance(): Collection
|
||||
{
|
||||
// TODO: Implement allowance() method.
|
||||
@ -44,14 +34,8 @@ final class Host extends Type implements ProductItem
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getCostAttribute(): float
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
// TODO: Implement getCostAttribute() method.
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getSupplierAttribute()
|
||||
{
|
||||
// TODO: Implement getSupplierAttribute() method.
|
||||
return FALSE;
|
||||
}
|
||||
}
|
@ -50,17 +50,6 @@ final class Phone extends Type implements ProductItem
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
// @todo Get this from the DB
|
||||
return 12;
|
||||
}
|
||||
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public function allowance(): Collection
|
||||
{
|
||||
// TODO: Implement allowance() method.
|
||||
@ -71,13 +60,8 @@ final class Phone extends Type implements ProductItem
|
||||
return "(TBA)";
|
||||
}
|
||||
|
||||
public function getCostAttribute(): float
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
// TODO: Implement getCostAttribute() method.
|
||||
}
|
||||
|
||||
public function getSupplierAttribute()
|
||||
{
|
||||
// TODO: Implement getSupplierAttribute() method.
|
||||
return FALSE;
|
||||
}
|
||||
}
|
@ -35,26 +35,6 @@ final class SSL extends Type implements ProductItem
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
|
||||
public function getCostAttribute(): float
|
||||
{
|
||||
// N/A
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getSupplierAttribute()
|
||||
{
|
||||
abort(500,'deprecated');
|
||||
$o = new \stdClass();
|
||||
$o->name = 'Internal';
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
public function hasUsage(): bool
|
||||
{
|
||||
return FALSE;
|
||||
|
@ -3,14 +3,11 @@
|
||||
namespace App\Models\Product;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
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, and we have a "price" which is not official charges nor a cost.
|
||||
*/
|
||||
abstract class Type extends Model
|
||||
{
|
||||
use SiteID,OrderServiceOptions;
|
||||
@ -37,9 +34,22 @@ abstract class Type extends Model
|
||||
return $this->hasOne(static::SupplierModel,'id','supplier_item_id');
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
/**
|
||||
* The product contract term is the highest of our defined contract_term (in Products/*) vs the suppliers
|
||||
* contract term (defined in Supplier/*).
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
return max(Arr::get($this->attributes,'contract_term',0),$this->supplied->contract_term);
|
||||
}
|
||||
|
||||
/* METHODs */
|
||||
|
||||
final function normalizeBillingInterval(): int
|
||||
final public function normalizeBillingInterval(): int
|
||||
{
|
||||
return static::DefaultBill;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ class ProductTranslate extends Model
|
||||
|
||||
public $timestamps = FALSE;
|
||||
|
||||
public function getDescriptionAttribute(string $val): string
|
||||
public function getDescriptionAttribute(?string $val): string
|
||||
{
|
||||
return $val ?: 'No Description';
|
||||
}
|
||||
|
@ -114,4 +114,15 @@ class Site extends Model
|
||||
? $this->details->get($x)->value
|
||||
: NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the taxed value of a value
|
||||
*
|
||||
* @param float $value
|
||||
* @return float
|
||||
*/
|
||||
public function taxed(float $value): float
|
||||
{
|
||||
return Tax::calc($value,$this->taxes);
|
||||
}
|
||||
}
|
@ -5,20 +5,22 @@ namespace App\Models\Supplier;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Interfaces\SupplierItem;
|
||||
use App\Models\Product\Broadband as ProductBroadband;
|
||||
|
||||
class Broadband extends Type implements SupplierItem
|
||||
class Broadband extends Type
|
||||
{
|
||||
protected const category_name = 'Broadband';
|
||||
|
||||
protected $table = 'supplier_broadband';
|
||||
|
||||
// The model of the product that is supplied by this model
|
||||
const ProductModel = ProductBroadband::class;
|
||||
|
||||
protected $casts = [
|
||||
'offpeak_start' => 'datetime:H:i',
|
||||
'offpeak_end' => 'datetime:H:i',
|
||||
];
|
||||
|
||||
protected $table = 'supplier_broadband';
|
||||
|
||||
// Map the table fields, with the extra fields
|
||||
public const traffic_map = [
|
||||
'base_up_offpeak' => 'extra_up_offpeak',
|
||||
@ -35,22 +37,6 @@ class Broadband extends Type implements SupplierItem
|
||||
'extra_down_peak' => 'base_down_peak',
|
||||
];
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @deprecated use Product::normalizeBillingInterval()
|
||||
*/
|
||||
public function getBillingIntervalAttribute(): int
|
||||
{
|
||||
return 1; // Monthly
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return $this->hasMany(ProductBroadband::class,'supplier_item_id','id');
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
|
||||
/**
|
||||
|
@ -4,33 +4,25 @@ namespace App\Models\Supplier;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Interfaces\SupplierItem;
|
||||
use App\Models\Product\Domain as ProductDomain;
|
||||
use App\Models\TLD;
|
||||
|
||||
final class Domain extends Type implements SupplierItem
|
||||
final class Domain extends Type
|
||||
{
|
||||
protected const category_name = 'Domain Name';
|
||||
protected const category_name = 'Domain';
|
||||
|
||||
protected $table = 'supplier_domain';
|
||||
|
||||
/* INTERFACES */
|
||||
// The model of the product that is supplied by this model
|
||||
const ProductModel = ProductDomain::class;
|
||||
|
||||
public function getBillingIntervalAttribute(): int
|
||||
{
|
||||
return 4; // Yearly
|
||||
}
|
||||
/* INTERFACES */
|
||||
|
||||
public function getNameAttribute(): string
|
||||
{
|
||||
return sprintf('%s: %s',$this->product_id,$this->tld->name);
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return $this->hasMany(ProductDomain::class,'supplier_item_id','id');
|
||||
}
|
||||
|
||||
/* STATIC */
|
||||
|
||||
/**
|
||||
|
@ -2,24 +2,14 @@
|
||||
|
||||
namespace App\Models\Supplier;
|
||||
|
||||
use App\Interfaces\SupplierItem;
|
||||
use App\Models\Product\Email as ProductEmail;
|
||||
|
||||
final class Email extends Type implements SupplierItem
|
||||
final class Email extends Type
|
||||
{
|
||||
protected const category_name = 'Email Hosting';
|
||||
protected const category_name = 'Email';
|
||||
|
||||
protected $table = 'supplier_email';
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
public function getBillingIntervalAttribute(): int
|
||||
{
|
||||
return 4; // Yearly
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return $this->hasMany(ProductEmail::class,'supplier_item_id','id');
|
||||
}
|
||||
// The model of the product that is supplied by this model
|
||||
const ProductModel = ProductEmail::class;
|
||||
}
|
@ -4,5 +4,5 @@ namespace App\Models\Supplier;
|
||||
|
||||
class Ethernet extends Broadband
|
||||
{
|
||||
protected const category_name = 'Broadband Ethernet';
|
||||
protected const category_name = 'Ethernet';
|
||||
}
|
@ -2,24 +2,14 @@
|
||||
|
||||
namespace App\Models\Supplier;
|
||||
|
||||
use App\Interfaces\SupplierItem;
|
||||
use App\Models\Product\Generic as ProductGeneric;
|
||||
|
||||
final class Generic extends Type implements SupplierItem
|
||||
final class Generic extends Type
|
||||
{
|
||||
protected const category_name = 'Generic';
|
||||
|
||||
protected $table = 'supplier_generic';
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
public function getBillingIntervalAttribute(): int
|
||||
{
|
||||
return 1; // Monthly
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return $this->hasMany(ProductGeneric::class,'supplier_item_id','id');
|
||||
}
|
||||
// The model of the product that is supplied by this model
|
||||
const ProductModel = ProductGeneric::class;
|
||||
}
|
@ -2,24 +2,14 @@
|
||||
|
||||
namespace App\Models\Supplier;
|
||||
|
||||
use App\Interfaces\SupplierItem;
|
||||
use App\Models\Product\Host as ProductHost;
|
||||
|
||||
final class Host extends Type implements SupplierItem
|
||||
final class Host extends Type
|
||||
{
|
||||
protected const category_name = 'Web Hosting';
|
||||
protected const category_name = 'Hosting';
|
||||
|
||||
protected $table = 'supplier_host';
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
public function getBillingIntervalAttribute(): int
|
||||
{
|
||||
return 4; // Yearly
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return $this->hasMany(ProductHost::class,'supplier_item_id','id');
|
||||
}
|
||||
// The model of the product that is supplied by this model
|
||||
const ProductModel = ProductHost::class;
|
||||
}
|
@ -2,24 +2,14 @@
|
||||
|
||||
namespace App\Models\Supplier;
|
||||
|
||||
use App\Interfaces\SupplierItem;
|
||||
use App\Models\Product\Phone as ProductVoip;
|
||||
|
||||
final class Phone extends Type implements SupplierItem
|
||||
final class Phone extends Type
|
||||
{
|
||||
protected const category_name = 'Telephone';
|
||||
protected const category_name = 'Phone';
|
||||
|
||||
protected $table = 'supplier_phone';
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
public function getBillingIntervalAttribute(): int
|
||||
{
|
||||
return 1; // Monthly
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return $this->hasMany(ProductVoip::class,'supplier_item_id','id');
|
||||
}
|
||||
// The model of the product that is supplied by this model
|
||||
const ProductModel = ProductVoip::class;
|
||||
}
|
@ -2,24 +2,14 @@
|
||||
|
||||
namespace App\Models\Supplier;
|
||||
|
||||
use App\Interfaces\SupplierItem;
|
||||
use App\Models\Product\SSL as ProductSSL;
|
||||
|
||||
final class SSL extends Type implements SupplierItem
|
||||
final class SSL extends Type
|
||||
{
|
||||
protected const category_name = 'SSL Certificate';
|
||||
protected const category_name = 'SSL';
|
||||
|
||||
protected $table = 'supplier_ssl';
|
||||
|
||||
/* INTERFACES */
|
||||
|
||||
public function getBillingIntervalAttribute(): int
|
||||
{
|
||||
return 4; // Yearly
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return $this->belongsToMany(ProductSSL::class,'supplier_item_id','id');
|
||||
}
|
||||
// The model of the product that is supplied by this model
|
||||
const ProductModel = ProductSSL::class;
|
||||
}
|
@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Leenooks\Traits\ScopeActive;
|
||||
|
||||
use App\Models\{Invoice,Supplier,SupplierDetail,Tax};
|
||||
use App\Models\{Invoice,SupplierDetail};
|
||||
use App\Traits\{ProductDetails,SiteID};
|
||||
|
||||
abstract class Type extends Model
|
||||
@ -15,16 +15,26 @@ abstract class Type extends Model
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
public function supplier_detail()
|
||||
/**
|
||||
* The offering supplied with this product
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
final public function products()
|
||||
{
|
||||
return $this->hasMany(static::ProductModel,'supplier_item_id','id');
|
||||
}
|
||||
|
||||
final public function supplier_detail()
|
||||
{
|
||||
return $this->belongsTo(SupplierDetail::class);
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
public function getBaseCostTaxableAttribute(): float
|
||||
public function getBaseCostAttribute(?float $val): float
|
||||
{
|
||||
return Tax::tax_calc($this->attributes['base_cost'],config('site')->taxes);
|
||||
return $val ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,7 +67,7 @@ abstract class Type extends Model
|
||||
*/
|
||||
public function getContractTermAttribute(): int
|
||||
{
|
||||
return max(Invoice::billing_period(static::getBillingIntervalAttribute()),Arr::get($this->attributes,'contract_term'));
|
||||
return max(Invoice::billing_period(static::getBillingIntervalAttribute()),Arr::get($this->attributes,'contract_term',0));
|
||||
}
|
||||
|
||||
public function getMinCostAttribute(): float
|
||||
@ -65,11 +75,6 @@ abstract class Type extends Model
|
||||
return $this->attributes['setup_cost']+$this->attributes['base_cost']*Invoice::billing_term($this->getContractTermAttribute(),$this->getBillingIntervalAttribute());
|
||||
}
|
||||
|
||||
public function getMinCostTaxableAttribute(): float
|
||||
{
|
||||
return Tax::tax_calc($this->getMinCostAttribute(),config('site')->taxes);
|
||||
}
|
||||
|
||||
public function getNameAttribute(): string
|
||||
{
|
||||
return $this->product_id ?: 'Supplier PID Unknown';
|
||||
@ -80,9 +85,9 @@ abstract class Type extends Model
|
||||
return $this->product_desc ?: 'Supplier NAME Unknown';
|
||||
}
|
||||
|
||||
public function getSetupCostTaxableAttribute(): float
|
||||
public function getSetupCostAttribute(?float $val): float
|
||||
{
|
||||
return Tax::tax_calc($this->attributes['setup_cost'],config('site')->taxes);
|
||||
return $val ?: 0;
|
||||
}
|
||||
|
||||
public function getSupplierAttribute(): Model
|
||||
|
@ -19,16 +19,14 @@ class Tax extends Model
|
||||
/* METHODS */
|
||||
|
||||
/**
|
||||
* Calculate Tax on a value
|
||||
* Calculate Tax on a value, and return that value with tax applied
|
||||
*
|
||||
* @param float $value
|
||||
* @param Collection $taxes
|
||||
* @return void
|
||||
* @return float
|
||||
*/
|
||||
public static function tax_calc(?float $value,Collection $taxes): float
|
||||
public static function calc(float $value,Collection $taxes): float
|
||||
{
|
||||
if (! $value)
|
||||
$value = 0;
|
||||
$tax = 0;
|
||||
|
||||
foreach ($taxes as $o) {
|
||||
|
@ -33,7 +33,6 @@ class ProductFactory extends Factory
|
||||
'taxable' => TRUE,
|
||||
'active' => TRUE,
|
||||
// 'position'
|
||||
// 'price_type'
|
||||
'pricing'=>json_encode([
|
||||
[
|
||||
'show'=>true,
|
||||
|
@ -19,6 +19,10 @@ return new class extends Migration
|
||||
DB::statement('ALTER TABLE supplier_generic MODIFY product_id varchar(32) NOT NULL, MODIFY product_desc text DEFAULT NULL');
|
||||
DB::statement('ALTER TABLE supplier_phone MODIFY product_id varchar(32) NOT NULL, MODIFY product_desc text DEFAULT NULL');
|
||||
DB::statement('ALTER TABLE supplier_ssl MODIFY product_id varchar(32) NOT NULL, MODIFY product_desc text DEFAULT NULL');
|
||||
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->dropColumn(['price_type']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,13 +29,14 @@
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@foreach (\App\Models\Service::active()->get() as $o)
|
||||
{{-- @todo This query is expensive still --}}
|
||||
@foreach (\App\Models\Service::active()->with(['type','product.type.supplied.supplier_detail.supplier','product.translate'])->get() as $o)
|
||||
<tr>
|
||||
<td><a href="{{ url('u/service',[$o->id]) }}">{{ $o->id }}</a></td>
|
||||
<td>{{ $o->name }}</td>
|
||||
<td>{{ $o->product->name }}</td>
|
||||
<td class="text-right">{{ number_format($o->billing_monthly_price,2) }}</td>
|
||||
<td class="text-right">{{ number_format(\App\Models\Tax::tax_calc(($s=$o->supplied)->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,1),$o->account->taxes),2) }}</td>
|
||||
<td class="text-right">{{ number_format($o->product->cost_normalized(),2) }}</td>
|
||||
<td class="text-right">{{ $o->category == 'broadband' ? number_format($o->type->usage_summary(0)->sum()/1000,1) : '-' }}</td>
|
||||
<td>{{ $o->product->supplier->name }}</td>
|
||||
</tr>
|
||||
|
@ -27,13 +27,14 @@
|
||||
<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($p->setup_charge,$o->account->taxes),2) }}</td>
|
||||
<td>${{ number_format($a=$o->account->taxed($s->setup_cost),2) }}</td>
|
||||
<td>${{ number_format($b=$o->account->taxed($p->setup_charge),2) }}</td>
|
||||
<td>{!! markup($a,$b) !!}</td>
|
||||
@else
|
||||
<td>-</td>
|
||||
@endif
|
||||
</tr>
|
||||
{{--
|
||||
<tr>
|
||||
<th>Billed</th>
|
||||
@if ($s->exists)
|
||||
@ -47,7 +48,7 @@
|
||||
<tr>
|
||||
<th>Billing Price</th>
|
||||
@if ($s->exists)
|
||||
<td>${{ number_format($a=\App\Models\Tax::tax_calc($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,$p->billing_interval),$o->account->taxes),2) }}</td>
|
||||
<td>${{ number_format($a=$o->account->taxed($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,$p->billing_interval)),2) }}</td>
|
||||
@endif
|
||||
<td>${{ number_format($b=$o->billing_charge,2) }}</td>
|
||||
@if ($s->exists)
|
||||
@ -57,9 +58,9 @@
|
||||
<tr>
|
||||
<th>Monthly Price</th>
|
||||
@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>
|
||||
<td>${{ number_format($a=$o->account->taxed($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,1)),2) }}</td>
|
||||
@endif
|
||||
<td @if($x=$o->isChargeOverriden()) class="text-danger" @endif>${{ number_format($b=($x ? $p->base_charge_taxable : $o->billing_monthly_price),2) }}</td>
|
||||
<td @if($x=$o->isChargeOverriden()) class="text-danger" @endif>${{ number_format($b=($x ? $o->account->taxed($p->base_charge) : $o->billing_monthly_price),2) }}</td>
|
||||
@if ($s->exists)
|
||||
<td>{!! markup($a,$b) !!}</td>
|
||||
@endif
|
||||
@ -77,12 +78,13 @@
|
||||
<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($p->getMinChargeAttribute($o->billing_interval),$o->account->taxes),2) }}</td>
|
||||
<td>${{ number_format($a=$o->account->taxed($s->min_cost),2) }}</td>
|
||||
<td>${{ number_format($b=$o->account->taxed($p->getMinChargeAttribute($o->billing_interval)),2) }}</td>
|
||||
<td>{!! markup($a,$b) !!}</td>
|
||||
@else
|
||||
<td>-</td>
|
||||
@endif
|
||||
</tr>
|
||||
--}}
|
||||
</tbody>
|
||||
</table>
|
@ -39,8 +39,8 @@
|
||||
<td>{{ $oo->name }}</td>
|
||||
<td>{{ $oo->name_long }}</td>
|
||||
<td class="text-right">{{ $oo->active ? 'YES' : 'NO' }}</td>
|
||||
<td class="text-right">{{ number_format($oo->setup_cost_taxable,2) }}</td>
|
||||
<td class="text-right">{{ number_format($oo->base_cost_taxable,2) }}</td>
|
||||
<td class="text-right">{{ number_format($site->taxed($oo->setup_cost),2) }}</td>
|
||||
<td class="text-right">{{ number_format($site->taxed($oo->base_cost),2) }}</td>
|
||||
<td class="text-right">{{ number_format($oo->products->count()) }}</td>
|
||||
<td class="text-right">{{ number_format($oo->products->pluck('products')->filter()->count()) }}</td>
|
||||
<td class="text-right">{{ number_format(($x=$oo->products->pluck('products')->flatten()->pluck('services')->flatten()->filter())->count()) }}</td>
|
||||
|
@ -42,10 +42,10 @@
|
||||
<td>{{ $po->name }}</td>
|
||||
<td class="text-right">{{ $po->active ? 'YES' : 'NO' }}</td>
|
||||
<td class="text-right">{{ $po->billing_interval_string }}</td>
|
||||
<td class="text-right">{{ number_format($po->setup_cost_taxable,2) }}</td>
|
||||
<td class="text-right">{{ number_format($po->base_cost_taxable,2) }}</td>
|
||||
<td class="text-right">{{ number_format($po->setup_charge_taxable,2) }}</td>
|
||||
<td class="text-right">{{ number_format($po->base_charge_taxable,2) }}</td>
|
||||
<td class="text-right">{{ number_format($site->taxed($po->setup_cost),2) }}</td>
|
||||
<td class="text-right">{{ number_format($site->taxed($po->base_cost),2) }}</td>
|
||||
<td class="text-right">{{ number_format($site->taxed($po->setup_charge),2) }}</td>
|
||||
<td class="text-right">{{ number_format($site->taxed($po->base_charge),2) }}</td>
|
||||
<td class="text-right">{{ number_format($po->services->count()) }}</td>
|
||||
<td class="text-right">{{ number_format($po->services->where('active')->count()) }}</td>
|
||||
</tr>
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
<div id="accordion">
|
||||
<!-- Reseller Choose Client -->
|
||||
@if ($user && $user->isReseller())
|
||||
@if ($user && $user->exists && $user->isReseller())
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Account</h4>
|
||||
@ -78,7 +78,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Non-Authed User -->
|
||||
@elseif ($user)
|
||||
@elseif ($user && $user->exists)
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
|
@ -8,13 +8,15 @@
|
||||
<th>Type</th>
|
||||
<td class="text-right">{{ $o->category_name }}</td>
|
||||
</tr>
|
||||
@if ($o->setup_charge)
|
||||
<tr>
|
||||
<th>Setup Charges <sup>*</sup></th>
|
||||
<td class="text-right">${{ number_format($o->setup_charge_taxable,2) }}</td>
|
||||
<td class="text-right">${{ number_format($user->exists ? $user->taxed($o->setup_charge) : Config::get('site')->taxed($o->setup_charge),2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
<tr>
|
||||
<th>Cost <sup>+</sup></th>
|
||||
<td class="text-right">${{ number_format($o->base_charge_taxable,2) }}</td>
|
||||
<td class="text-right">${{ number_format($user->exists ? $user->taxed($o->base_charge) : Config::get('site')->taxed($o->base_charge),2) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Default Billing</th>
|
||||
@ -26,8 +28,14 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Minimum Costs <sup>+*</sup></th>
|
||||
<td class="text-right">${{ number_format($o->min_charge_taxable,2) }}</td>
|
||||
<td class="text-right">${{ number_format($user->exists ? $user->taxed($o->min_charge) : Config::get('site')->taxed($o->min_charge),2) }}</td>
|
||||
</tr>
|
||||
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{!! $footer !!}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
@ -1,42 +1,7 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_detail !!}</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>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
@include('order.widget.info.base',['footer'=>'
|
||||
<sup>
|
||||
* Additional setup charges may apply for complex installations.<br>
|
||||
+ Additional charges may apply for regional installations.
|
||||
</sup>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
'])
|
@ -1,33 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_detail !!}</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>
|
||||
@include('order.widget.info.base',['footer'=>'
|
||||
<sup>
|
||||
* Depends on domain availability.<br>
|
||||
+ Domain availability may change the initial cost.
|
||||
</sup>'])
|
@ -1,33 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_detail !!}</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>
|
||||
@include('order.widget.info.base',['footer'=>'
|
||||
<sup>
|
||||
* Depends on domain availability.<br>
|
||||
+ Domain availability may change the initial cost.
|
||||
</sup>'])
|
@ -0,0 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
@include('order.widget.info.base',['footer'=>'
|
||||
<sup>
|
||||
* Depends on domain availability.<br>
|
||||
+ Domain availability may change the initial cost.
|
||||
</sup>'])
|
@ -1,31 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_detail !!}</p>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<td class="text-right">{{ $o->category_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Setup Charges</th>
|
||||
<td class="text-right">${{ number_format($o->setup_charge_taxable,2) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cost</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</th>
|
||||
<td class="text-right">${{ number_format($o->min_charge_taxable,2) }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
@include('order.widget.info.base',['footer'=>'
|
||||
<sup>
|
||||
* Depends on complex porting.<br>
|
||||
+ Complex porting involves additional charges.
|
||||
</sup>'])
|
Loading…
Reference in New Issue
Block a user