diff --git a/app/Console/Commands/ServiceList.php b/app/Console/Commands/ServiceList.php index 1ed9693..6d3b033 100644 --- a/app/Console/Commands/ServiceList.php +++ b/app/Console/Commands/ServiceList.php @@ -68,7 +68,7 @@ class ServiceList extends Command $this->info(sprintf($header, $o->lid, $o->product->category_name, - substr($o->product->getNameAttribute(),0,35), + substr($o->product->name,0,35), substr($o->name_short,0,40), $o->active ? 'active' : 'inactive', $o->status, diff --git a/app/Models/Product.php b/app/Models/Product.php index c68ac03..69c6a0f 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -10,14 +10,13 @@ use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\File; -use Illuminate\Support\Str; use Intuit\Exceptions\NotTokenException; use Intuit\Traits\ProviderTokenTrait; use Leenooks\Traits\ScopeActive; use App\Casts\CollectionOrNull; use App\Interfaces\{IDs,ProductItem}; -use App\Traits\{ProductDetails,ProviderRef}; +use App\Traits\ProviderRef; /** * Class Product @@ -33,17 +32,28 @@ use App\Traits\{ProductDetails,ProviderRef}; * Attributes for products: * + lid : Local ID for product (part number) * + sid : System ID for product (part number) - * + base_charge : Default billing amount * - * + billing_interval : Default Billing Interval - * + billing_interval_string: Default Billing Interval in human-readable form + * + base_charge : Default billing amount + * + base_cost : Cost for this service + * + * + billing_interval : Its the max of what we define, or what the supplier bills us at + * * + category : Type of product supplied + * + category_lc : Category name in lower case * + category_name : Type of product supplied (Friendly Name for display, not for internal logic) + * + * + contract_term : Contract term for this product + * * + description : Product description (description.description_full => description_full) - * + min_charge : Minimum charge taking into account billing interval and setup charges + * + has_usage : Does this product instrument usage + * + * + min_cost : Minimum cost for this product + * * + name : Details of our product (description.description_short => name_detail) * + pid : Product ID for our Product (description.name => name_short) - * + setup_charge : Charge to setup this product + * + * + setup_cost : Charge by supplier to setup this product + * * + supplier : Supplier for this offering * * Attributes for product types (type - Product/*) @@ -66,7 +76,7 @@ use App\Traits\{ProductDetails,ProviderRef}; */ class Product extends Model implements IDs { - use HasFactory,ProductDetails,ScopeActive,ProviderRef,ProviderTokenTrait; + use HasFactory,ScopeActive,ProviderRef,ProviderTokenTrait; protected $casts = [ 'pricing' => CollectionOrNull::class, @@ -77,10 +87,27 @@ class Product extends Model implements IDs return match ($key) { 'base_cost' => round($this->supplied->base_cost,2)*Invoice::billing_change($this->type->billing_interval,$this->billing_interval) ?: 0, + 'billing_interval' => max($this->price_recur_default,$this->type->billing_interval), + 'billing_interval_name' => Invoice::billing_name($this->billing_interval), + 'category' => $this->supplied->category, 'category_lc' => strtolower($this->category), 'category_name' => $this->supplied->category_name, + 'contract_term' => $this->type->contract_term, + + 'description' => $this->translate->description, + + 'has_usage' => $this->type->hasUsage(), + + 'min_cost' => $this->supplied->min_cost, + + 'name' => $this->translate->name_detail, + + 'pid' => $this->translate->name_short, + + 'setup_cost' => $this->supplied->setup_cost ?: 0, + default => parent::__get($key), }; } @@ -174,80 +201,6 @@ class Product extends Model implements IDs /* ATTRIBUTES */ - /** - * Our default billing interval - * Its the max of what we define, or what the supplier bills us at - * - * @return int - */ - public function getBillingIntervalAttribute(): int - { - return max($this->price_recur_default,$this->type->billing_interval); - } - - /** - * How long must this product be purchased for as a service. - * - * @return int - */ - public function getContractTermAttribute(): int - { - return $this->type->contract_term; - } - - /** - * This product full description - * - * @return string - */ - public function getDescriptionAttribute(): string - { - return $this->translate->description; - } - - /** - * Get the minimum charge for this product - * - * @param int|null $timeperiod - * @param Group|null $go - * @return float - */ - public function getMinChargeAttribute(int $timeperiod=NULL,Group $go=NULL): float - { - return $this->getSetupChargeAttribute($timeperiod,$go) - + $this->base_charge($timeperiod,$go)*Invoice::billing_change($this->billing_interval,$this->type->billing_interval)*$this->type->contract_term; - } - - /** - * Get the minimum cost for this product - * - * @return float - */ - public function getMinCostAttribute(): float - { - return $this->supplied->min_cost; - } - - /** - * Our products short descriptive name - * - * @return string - */ - public function getNameAttribute(): string - { - return $this->translate->name_detail; - } - - /** - * Our products PID - * - * @return string - */ - public function getPIDAttribute(): string - { - return $this->translate->name_short; - } - /** * Suppliers product * @@ -268,28 +221,6 @@ class Product extends Model implements IDs return $this->supplied->supplier; } - /** - * The charge to setup this service - * - * @param int|null $timeperiod - * @param Group|null $go - * @return float - */ - public function getSetupChargeAttribute(int $timeperiod=NULL,Group $go=NULL): float - { - return $this->_charge('setup',$timeperiod,$go); - } - - /** - * The cost to setup this service - * - * @return float - */ - public function getSetupCostAttribute(): float - { - return $this->supplied->setup_cost ?: 0; - } - /* METHODS */ /** @@ -387,24 +318,16 @@ class Product extends Model implements IDs } /** - * Return a normalize price dependent on the product, ie: Broadband = Monthly, Domain = Yearly, etc + * Get the minimum charge for this product * - * @note: By definition products are normalised, as their cost price is based on the default billing interval + * @param int|null $timeperiod + * @param Group|null $go * @return float */ - public function cost_normalized(): float + public function min_charge(int $timeperiod=NULL,Group $go=NULL): float { - return number_format(config('site')->taxed($this->supplied->base_cost),2); - } - - /** - * Return if this product captures usage data - * - * @return bool - */ - public function hasUsage(): bool - { - return $this->type->hasUsage(); + return $this->setup_charge($timeperiod,$go) + + $this->base_charge($timeperiod,$go)*Invoice::billing_change($this->billing_interval,$this->type->billing_interval)*$this->contract_term; } /** @@ -417,4 +340,16 @@ class Product extends Model implements IDs { return $this->type->orderValidation($request); } + + /** + * The charge to setup this service + * + * @param int|null $timeperiod + * @param Group|null $go + * @return float + */ + public function setup_charge(?int $timeperiod=NULL,?Group $go=NULL): float + { + return $this->_charge('setup',$timeperiod,$go); + } } \ No newline at end of file diff --git a/app/Models/Product/Type.php b/app/Models/Product/Type.php index 6ec8ab7..e390164 100644 --- a/app/Models/Product/Type.php +++ b/app/Models/Product/Type.php @@ -10,7 +10,7 @@ use App\Traits\{OrderServiceOptions,ProductDetails,SiteID}; abstract class Type extends Model { - use SiteID,ProductDetails,OrderServiceOptions; + use SiteID,OrderServiceOptions; /* RELATIONS */ diff --git a/app/Models/Service.php b/app/Models/Service.php index d036856..d81791e 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -301,7 +301,7 @@ class Service extends Model implements IDs 'billing_interval' => $this->recur_schedule ?: $this->product->billing_interval, 'billing_interval_name' => Invoice::billing_name($this->billing_interval), - 'contract_term' => max($this->supplied->contract_term,$this->product->type->contract_term), + 'contract_term' => max($this->product->contract_term,$this->supplied->contract_term), 'is_active' => $this->active || ($this->order_status && (! in_array($this->order_status,self::INACTIVE_STATUS))), 'is_billed' => (! ($this->external_billing || $this->suspend_billing || ($this->price === 0))), @@ -1058,7 +1058,7 @@ class Service extends Model implements IDs // Connection charges are only charged once, so ignore if if we have already billed them if ((! $this->invoiced_items()->where('item_type',InvoiceItem::INVOICEITEM_SETUP)->count()) && (InvoiceItem::distinct('invoice_id')->where('service_id',$this->id)->count() < 2) - && $this->product->getSetupChargeAttribute($this->billing_interval,$this->account->group)) + && $this->product->setup_charge($this->billing_interval,$this->account->group)) { $ii = new InvoiceItem; @@ -1066,7 +1066,7 @@ class Service extends Model implements IDs $ii->service_id = $this->id; $ii->product_id = $this->product_id; $ii->item_type = InvoiceItem::INVOICEITEM_SETUP; - $ii->price_base = $this->product->getSetupChargeAttribute($this->billing_interval,$this->account->group); + $ii->price_base = $this->product->setup_charge($this->billing_interval,$this->account->group); $ii->start_at = $this->invoice_next; $ii->stop_at = $this->invoice_next; $ii->quantity = 1; diff --git a/app/Models/Supplier/Type.php b/app/Models/Supplier/Type.php index 2be12c1..203651c 100644 --- a/app/Models/Supplier/Type.php +++ b/app/Models/Supplier/Type.php @@ -28,6 +28,7 @@ abstract class Type extends Model { return match ($key) { 'category' => (new \ReflectionClass($this))->getShortName(), + 'category_lc' => strtolower($this->category), 'category_name' => static::category_name ?: $this->category, default => parent::__get($key), diff --git a/app/Traits/ProductDetails.php b/app/Traits/ProductDetails.php deleted file mode 100644 index dd8146f..0000000 --- a/app/Traits/ProductDetails.php +++ /dev/null @@ -1,21 +0,0 @@ -Accounting