55 lines
1.9 KiB
PHP
55 lines
1.9 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
/**
|
|
* One Stripe Price a priced catalogue row has had, live or superseded.
|
|
*
|
|
* Two of them are live at any moment, not one: `reverse_charge` says whether a
|
|
* row is the DOMESTIC GROSS Price, which is what the website quotes and what
|
|
* everybody who is charged VAT pays, or the BARE NET one, which is the whole of
|
|
* what a business in another member state with a verified VAT id owes. Which of
|
|
* the two a checkout uses is TaxTreatment's decision — see
|
|
* App\Services\Billing\PlanPrices.
|
|
*
|
|
* `plan_prices.stripe_price_id` points at the domestic one, because that is the
|
|
* ordinary sale and it must have a single source; the net one is only ever read
|
|
* from here. And because a Price id is unique in this table, joining it on
|
|
* `subscriptions.stripe_price_id` is what says which of the two a running
|
|
* contract is actually billed on.
|
|
*
|
|
* The rest is history, and it exists because a Stripe Price cannot be edited.
|
|
* When the amount a row is charged at changes — a change to the VAT rate moves
|
|
* the gross Price and leaves the net one alone — a new Price is minted, the old
|
|
* row is archived, and the old Price stays in Stripe for as long as a contract is
|
|
* still billing on it. See the migrations for why that history has to be
|
|
* readable.
|
|
*/
|
|
class StripePlanPrice extends Model
|
|
{
|
|
protected $guarded = [];
|
|
|
|
protected function casts(): array
|
|
{
|
|
return [
|
|
'charged_cents' => 'integer',
|
|
'reverse_charge' => 'boolean',
|
|
'archived_at' => 'datetime',
|
|
];
|
|
}
|
|
|
|
public function planPrice(): BelongsTo
|
|
{
|
|
return $this->belongsTo(PlanPrice::class);
|
|
}
|
|
|
|
/** Is this the Price the catalogue is selling on right now? */
|
|
public function isLive(): bool
|
|
{
|
|
return $this->archived_at === null;
|
|
}
|
|
}
|