Introduce cost and cost override into service model. Update service internal view to show cost/billing left on contracted services

This commit is contained in:
2025-05-16 11:10:28 +10:00
parent 48d7968d0c
commit 4c24f09195
2 changed files with 93 additions and 10 deletions

View File

@@ -45,6 +45,7 @@ use App\Traits\{ScopeAccountUserAuthorised,ScopeServiceActive,SiteID};
*
* Methods:
* + isChargeOverridden : Has the price been overridden?
* + isCostOverridden : Has the cost been overridden?
* + isPending : Is this a pending active service
*
* @package App\Models
@@ -535,6 +536,11 @@ class Service extends Model implements IDs
return $this->account->taxed($this->billing_charge());
}
public function getBillingCostAttribute(): float
{
return $this->account->taxed($this->billing_cost());
}
/**
* Determine a monthly price for a service, even if it is billed at a different frequency
*
@@ -543,7 +549,16 @@ class Service extends Model implements IDs
*/
public function getBillingChargeNormalisedAttribute(): float
{
return number_format($this->getBillingChargeAttribute()*Invoice::billing_change($this->getBillingIntervalAttribute(),$this->offering->billing_interval),2);
return number_format(
$this->getBillingChargeAttribute()*Invoice::billing_change($this->getBillingIntervalAttribute(),$this->offering->billing_interval),
2);
}
public function getBillingCostNormalisedAttribute(): float
{
return number_format(
$this->getBillingCostAttribute()*Invoice::billing_change($this->getBillingIntervalAttribute(),$this->offering->billing_interval),
2);
}
/**
@@ -567,7 +582,7 @@ class Service extends Model implements IDs
}
/**
* Return the earliest date that the service can be cancelled
* Return the earliest date that the service can be canceled as per contract/billing intervals
*
* @return Carbon
*/
@@ -916,17 +931,21 @@ class Service extends Model implements IDs
/**
* Provide billing charge to a future date
*
* If $date is earlier than our contract end date, then our charge is to the contract end date.
* If $date is after our contract end date:
* + and we are still in contract, then our charge is to contract end date plus additional time, else
* + then our charge is the months to the $date
*
* @param Carbon $date
* @return float
* @throws Exception
*/
public function billing_charge_to(Carbon $date): float
{
// if the date is less than the paid to, but less than the cancel date to, return cancel-paid to charge
// If the date is greater than the paid to, and less than the cancel date to, return cancel-paid to charge
if ($this->getPaidToAttribute()->lessThan($this->getCancelDateAttribute())) {
$max = max($date,$this->getPaidToAttribute())->clone();
$d = $max->diffInDays($this->getCancelDateAttribute());
$max = max($date,$this->getCancelDateAttribute())->clone();
if ($this->getPaidToAttribute()->lessThan($max)) {
$d = $this->getPaidToAttribute()->diffInDays($max);
return $this->account->taxed($d/30*$this->getBillingChargeNormalisedAttribute());
}
@@ -934,6 +953,42 @@ class Service extends Model implements IDs
return 0;
}
/**
* The amount we are charged for the client to have this service
* @return float
*/
public function billing_cost(): float
{
return is_null($this->cost)
? $this->product->getBaseCostAttribute()
: $this->cost;
}
/**
* Calculate our costs to keep this service to a future date
*
* If $date is earlier than the contract end date, then our cost is to the contract end date.
* If $date is after the contract end date:
* + and we are still in contract, then our cost is to contract end date plus additional time, else
* + then our cost is the months to the $date
*
* @param Carbon $date
* @return float
* @throws Exception
*/
public function billing_cost_to(Carbon $date): float
{
$max = max($date,$this->getCancelDateAttribute())->clone();
if ($this->getInvoicedToAttribute()->lessThan($max)) {
$d = $this->getInvoicedToAttribute()->diffInDays($max);
return $this->account->taxed($d/30*$this->getBillingCostNormalisedAttribute());
}
return 0;
}
/**
* Get the stage parameters
*
@@ -1065,6 +1120,11 @@ class Service extends Model implements IDs
return ! is_null($this->price);
}
public function isCostOverridden(): bool
{
return ! is_null($this->cost);
}
public function isContract(): bool
{
return $this->getContractEndAttribute()->greaterThan(Carbon::now());