More Product Model optimisation

This commit is contained in:
2023-05-05 15:48:24 +10:00
parent 96f799f535
commit 820ff2be00
37 changed files with 161 additions and 592 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}
/**

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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.
return FALSE;
}
public function getSupplierAttribute()
{
// TODO: Implement getSupplierAttribute() method.
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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';
}

View File

@@ -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);
}
}

View File

@@ -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 */
/**

View File

@@ -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 */
/**

View File

@@ -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;
}

View File

@@ -4,5 +4,5 @@ namespace App\Models\Supplier;
class Ethernet extends Broadband
{
protected const category_name = 'Broadband Ethernet';
protected const category_name = 'Ethernet';
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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) {