Compare commits

..

4 Commits

Author SHA1 Message Date
b37045acca PHP deprecation fixes, assigning null arguments in methods
All checks were successful
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 41s
Create Docker Image / Final Docker Image Manifest (push) Successful in 9s
2025-05-22 18:37:04 +10:00
251aefa947 Move some product product\supplier and product\type::class methods into __get(), no functional changes 2025-05-22 18:17:27 +10:00
72b11172c8 Move some service\type::class methods into __get(), no functional changes 2025-05-22 17:57:39 +10:00
1e496a2863 Remove Interface ID and implement the lid/sid methods in __get() 2025-05-22 17:31:00 +10:00
35 changed files with 165 additions and 317 deletions

View File

@ -54,7 +54,7 @@ class InvoiceController extends Controller
* @param string|null $code * @param string|null $code
* @return View * @return View
*/ */
public function view(Invoice $o,string $code=NULL): View public function view(Invoice $o,?string $code=NULL): View
{ {
if ($code) { if ($code) {
try { try {

View File

@ -159,7 +159,7 @@ class SupplierController extends Controller
* @param int|null $id * @param int|null $id
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/ */
public function product_view_type(Request $request,string $type,int $id=NULL) public function product_view_type(Request $request,string $type,?int $id=NULL)
{ {
$o = $id ? Supplier::offeringTypeClass($type)->findOrFail($id) : NULL; $o = $id ? Supplier::offeringTypeClass($type)->findOrFail($id) : NULL;

View File

@ -1,20 +0,0 @@
<?php
namespace App\Interfaces;
interface IDs
{
/**
* Return the local ID of the item
*
* @return mixed
*/
public function getLIDAttribute(): string;
/**
* Return the system ID of the item
*
* @return mixed
*/
public function getSIDAttribute(): string;
}

View File

@ -6,13 +6,6 @@ use Carbon\Carbon;
interface ServiceItem interface ServiceItem
{ {
/**
* Months the service is contracted for.
*
* @return int
*/
public function getContractTermAttribute(): int;
/** /**
* Return the Service Description. * Return the Service Description.
* *
@ -20,29 +13,10 @@ interface ServiceItem
*/ */
public function getServiceDescriptionAttribute(): string; public function getServiceDescriptionAttribute(): string;
/**
* Date the service expires
*/
public function getServiceExpireAttribute(): ?Carbon;
/** /**
* Return the Service Name. * Return the Service Name.
* *
* @return string * @return string
*/ */
public function getServiceNameAttribute(): string; public function getServiceNameAttribute(): string;
/**
* Has this service expired
*
* @return bool
*/
public function hasExpired(): bool;
/**
* Is this service in a contract
*
* @return bool
*/
public function inContract(): bool;
} }

View File

@ -23,7 +23,7 @@ class CancelRequest extends Mailable
* @param Service $o * @param Service $o
* @param string|NULL $notes * @param string|NULL $notes
*/ */
public function __construct(Service $o,string $notes=NULL) public function __construct(Service $o,?string $notes=NULL)
{ {
$this->service = $o; $this->service = $o;
$this->notes = $notes; $this->notes = $notes;

View File

@ -23,7 +23,7 @@ class ChangeRequest extends Mailable
* @param Service $o * @param Service $o
* @param string|NULL $notes * @param string|NULL $notes
*/ */
public function __construct(Service $o,string $notes=NULL) public function __construct(Service $o,?string $notes=NULL)
{ {
$this->service = $o; $this->service = $o;
$this->notes = $notes; $this->notes = $notes;

View File

@ -22,10 +22,20 @@ use App\Interfaces\IDs;
* + name : Account Name * + name : Account Name
* + taxes : Taxes Applicable to this account * + taxes : Taxes Applicable to this account
*/ */
class Account extends Model implements IDs class Account extends Model
{ {
use HasFactory,ScopeActive; use HasFactory,ScopeActive;
public function __get($key): mixed
{
return match ($key) {
'lid' => sprintf('%04s',$this->id),
'sid' => sprintf('%02s-%s',$this->site_id,$this->lid),
default => parent::__get($key),
};
}
/* STATIC */ /* STATIC */
/** /**
@ -34,7 +44,7 @@ class Account extends Model implements IDs
* @param Collection|NULL $invoices * @param Collection|NULL $invoices
* @return Collection * @return Collection
*/ */
public static function InvoicesCredit(Collection $invoices=NULL): Collection public static function InvoicesCredit(?Collection $invoices=NULL): Collection
{ {
return (new self) return (new self)
->invoiceSummaryCredit($invoices,TRUE) ->invoiceSummaryCredit($invoices,TRUE)
@ -47,25 +57,13 @@ class Account extends Model implements IDs
* @param Collection|NULL $invoices * @param Collection|NULL $invoices
* @return Collection * @return Collection
*/ */
public static function InvoicesDue(Collection $invoices=NULL): Collection public static function InvoicesDue(?Collection $invoices=NULL): Collection
{ {
return (new self) return (new self)
->invoiceSummaryDue($invoices,TRUE) ->invoiceSummaryDue($invoices,TRUE)
->get(); ->get();
} }
/* INTERFACES */
public function getLIDAttribute(): string
{
return sprintf('%04s',$this->id);
}
public function getSIDAttribute(): string
{
return sprintf('%02s-%s',$this->site_id,$this->getLIDAttribute());
}
/* RELATIONS */ /* RELATIONS */
/** /**
@ -253,7 +251,7 @@ class Account extends Model implements IDs
/* METHODS */ /* METHODS */
public function invoice_next(Carbon $date=NULL): Collection public function invoice_next(?Carbon $date=NULL): Collection
{ {
$svs = $this $svs = $this
->services_active ->services_active
@ -309,7 +307,7 @@ class Account extends Model implements IDs
* @param bool $all * @param bool $all
* @return Builder * @return Builder
*/ */
public function invoiceSummary(Collection $invoices=NULL,bool $all=FALSE): Builder public function invoiceSummary(?Collection $invoices=NULL,bool $all=FALSE): Builder
{ {
return (new Invoice) return (new Invoice)
->select([ ->select([
@ -357,19 +355,19 @@ class Account extends Model implements IDs
->with(['account']); ->with(['account']);
} }
public function invoiceSummaryDue(Collection $invoices=NULL,bool $all=FALSE): Builder public function invoiceSummaryDue(?Collection $invoices=NULL,bool $all=FALSE): Builder
{ {
return $this->invoiceSummary($invoices,$all) return $this->invoiceSummary($invoices,$all)
->havingRaw('ROUND(CAST(SUM(item_total)-COALESCE(invoices.discount_amt,0)-SUM(payments) AS NUMERIC),2) > 0'); ->havingRaw('ROUND(CAST(SUM(item_total)-COALESCE(invoices.discount_amt,0)-SUM(payments) AS NUMERIC),2) > 0');
} }
public function invoiceSummaryCredit(Collection $invoices=NULL,bool $all=FALSE): Builder public function invoiceSummaryCredit(?Collection $invoices=NULL,bool $all=FALSE): Builder
{ {
return $this->invoiceSummary($invoices,$all) return $this->invoiceSummary($invoices,$all)
->havingRaw('ROUND(CAST(SUM(item_total)-COALESCE(invoices.discount_amt,0)-SUM(payments) AS NUMERIC),2) < 0'); ->havingRaw('ROUND(CAST(SUM(item_total)-COALESCE(invoices.discount_amt,0)-SUM(payments) AS NUMERIC),2) < 0');
} }
public function invoiceSummaryPast(Collection $invoices=NULL,bool $all=FALSE): Builder public function invoiceSummaryPast(?Collection $invoices=NULL,bool $all=FALSE): Builder
{ {
return $this->invoiceSummary($invoices,$all) return $this->invoiceSummary($invoices,$all)
->join('payment_items',['payment_items.invoice_id'=>'invoices.id']) ->join('payment_items',['payment_items.invoice_id'=>'invoices.id'])

View File

@ -36,7 +36,7 @@ use App\Traits\{PushNew,SiteID};
* *
* @package App\Models * @package App\Models
*/ */
class Invoice extends Model implements IDs class Invoice extends Model
{ {
use PushNew,ScopeActive,SiteID; use PushNew,ScopeActive,SiteID;
@ -109,6 +109,16 @@ class Invoice extends Model implements IDs
'payment_items_active.payment:id,paid_at', 'payment_items_active.payment:id,paid_at',
]; ];
public function __get($key): mixed
{
return match ($key) {
'lid' => sprintf('%06s',$this->id),
'sid' => sprintf('%02s-%04s-%s',$this->site_id,$this->account_id,$this->lid),
default => parent::__get($key),
};
}
/* STATIC METHODS */ /* STATIC METHODS */
public static function boot() public static function boot()
@ -317,28 +327,6 @@ class Invoice extends Model implements IDs
return round(($d-Arr::get($period,'start')->diffInDays($start)-$end->diffInDays(Arr::get($period,'end')))/$d,2); return round(($d-Arr::get($period,'start')->diffInDays($start)-$end->diffInDays(Arr::get($period,'end')))/$d,2);
} }
/* INTERFACES */
/**
* Invoice Local ID
*
* @return string
*/
public function getLIDAttribute(): string
{
return sprintf('%06s',$this->id);
}
/**
* Invoice System ID
*
* @return string
*/
public function getSIDAttribute(): string
{
return sprintf('%02s-%04s-%s',$this->site_id,$this->account_id,$this->getLIDAttribute());
}
/* RELATIONS */ /* RELATIONS */
/** /**

View File

@ -22,7 +22,7 @@ use App\Traits\{ProviderRef,PushNew,ScopeAccountUserAuthorised,SiteID};
* *
* @package App\Models * @package App\Models
*/ */
class Payment extends Model implements IDs class Payment extends Model
{ {
use ProviderRef,PushNew,ScopeActive,ScopeAccountUserAuthorised,SiteID; use ProviderRef,PushNew,ScopeActive,ScopeAccountUserAuthorised,SiteID;
@ -36,26 +36,14 @@ class Payment extends Model implements IDs
// Any balance below this we'll assume its all used. // Any balance below this we'll assume its all used.
private const threshold = 0.05; private const threshold = 0.05;
/* INTERFACES */ public function __get($key): mixed
/**
* Payment Local ID
*
* @return string
*/
public function getLIDattribute(): string
{ {
return sprintf('%06s',$this->id); return match ($key) {
} 'lid' => sprintf('%06s',$this->id),
'sid' => sprintf('%02s-%04s#%s',$this->site_id,$this->account_id,$this->lid),
/** default => parent::__get($key),
* Payment System ID };
*
* @return string
*/
public function getSIDAttribute(): string
{
return sprintf('%02s-%04s#%s',$this->site_id,$this->account_id,$this->getLIDattribute());
} }
/* RELATIONS */ /* RELATIONS */

View File

@ -54,6 +54,7 @@ use App\Traits\ProviderRef;
* *
* + setup_cost : Charge by supplier to setup this product * + setup_cost : Charge by supplier to setup this product
* *
* + supplied : Suppliers product supplied
* + supplier : Supplier for this offering * + supplier : Supplier for this offering
* *
* Attributes for product types (type - Product/*) * Attributes for product types (type - Product/*)
@ -74,7 +75,7 @@ use App\Traits\ProviderRef;
* ] * ]
* ] * ]
*/ */
class Product extends Model implements IDs class Product extends Model
{ {
use HasFactory,ScopeActive,ProviderRef,ProviderTokenTrait; use HasFactory,ScopeActive,ProviderRef,ProviderTokenTrait;
@ -104,10 +105,15 @@ class Product extends Model implements IDs
'name' => $this->translate->name_detail, 'name' => $this->translate->name_detail,
'lid' => sprintf('%04s',$this->id),
'pid' => $this->translate->name_short, 'pid' => $this->translate->name_short,
'sid' => sprintf('%02s-%s',$this->site_id,$this->lid),
'setup_cost' => $this->supplied->setup_cost ?: 0, 'setup_cost' => $this->supplied->setup_cost ?: 0,
'supplied' => $this->type->supplied,
'supplier' => $this->supplied->supplier,
default => parent::__get($key), default => parent::__get($key),
}; };
} }
@ -187,40 +193,6 @@ class Product extends Model implements IDs
return $this->morphTo(null,'model','model_id'); return $this->morphTo(null,'model','model_id');
} }
/* INTERFACES */
public function getLIDAttribute(): string
{
return sprintf('%04s',$this->id);
}
public function getSIDAttribute(): string
{
return sprintf('%02s-%s',$this->site_id,$this->getLIDattribute());
}
/* ATTRIBUTES */
/**
* Suppliers product
*
* @return Model
*/
public function getSuppliedAttribute(): Model
{
return $this->type->supplied;
}
/**
* Suppliers of this product
*
* @return Model|null
*/
public function getSupplierAttribute(): ?Model
{
return $this->supplied->supplier;
}
/* METHODS */ /* METHODS */
/** /**
@ -234,7 +206,7 @@ class Product extends Model implements IDs
* @param Group|NULL $go * @param Group|NULL $go
* @return float * @return float
*/ */
private function _charge(string $type,int $timeperiod=NULL,Group $go=NULL): float private function _charge(string $type,?int $timeperiod=NULL,?Group $go=NULL): float
{ {
// We'll cache this for performance // We'll cache this for performance
static $default = NULL; static $default = NULL;
@ -324,7 +296,7 @@ class Product extends Model implements IDs
* @param Group|null $go * @param Group|null $go
* @return float * @return float
*/ */
public function min_charge(int $timeperiod=NULL,Group $go=NULL): float public function min_charge(?int $timeperiod=NULL,?Group $go=NULL): float
{ {
return $this->setup_charge($timeperiod,$go) return $this->setup_charge($timeperiod,$go)
+ $this->base_charge($timeperiod,$go)*Invoice::billing_change($this->billing_interval,$this->type->billing_interval)*$this->contract_term; + $this->base_charge($timeperiod,$go)*Invoice::billing_change($this->billing_interval,$this->type->billing_interval)*$this->contract_term;

View File

@ -5,12 +5,11 @@ namespace App\Models\Product;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Leenooks\Traits\ScopeActive; use Leenooks\Traits\ScopeActive;
use App\Interfaces\ProductItem;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Service\Broadband as ServiceBroadband; use App\Models\Service\Broadband as ServiceBroadband;
use App\Models\Supplier\Broadband as SupplierBroadband; use App\Models\Supplier\Broadband as SupplierBroadband;
final class Broadband extends Type implements ProductItem final class Broadband extends Type
{ {
use ScopeActive; use ScopeActive;

View File

@ -4,12 +4,11 @@ namespace App\Models\Product;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use App\Interfaces\ProductItem;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Service\Domain as ServiceDomain; use App\Models\Service\Domain as ServiceDomain;
use App\Models\Supplier\Domain as SupplierDomain; use App\Models\Supplier\Domain as SupplierDomain;
final class Domain extends Type implements ProductItem final class Domain extends Type
{ {
protected $table = 'product_domain'; protected $table = 'product_domain';

View File

@ -4,12 +4,11 @@ namespace App\Models\Product;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use App\Interfaces\ProductItem;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Service\Email as ServiceEmail; use App\Models\Service\Email as ServiceEmail;
use App\Models\Supplier\Email as SupplierEmail; use App\Models\Supplier\Email as SupplierEmail;
final class Email extends Type implements ProductItem final class Email extends Type
{ {
protected $table = 'product_email'; protected $table = 'product_email';

View File

@ -4,12 +4,11 @@ namespace App\Models\Product;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use App\Interfaces\ProductItem;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Service\Generic as ServiceGeneric; use App\Models\Service\Generic as ServiceGeneric;
use App\Models\Supplier\Generic as SupplierGeneric; use App\Models\Supplier\Generic as SupplierGeneric;
final class Generic extends Type implements ProductItem final class Generic extends Type
{ {
protected $table = 'product_generic'; protected $table = 'product_generic';

View File

@ -4,12 +4,11 @@ namespace App\Models\Product;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use App\Interfaces\ProductItem;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Service\Host as ServiceHost; use App\Models\Service\Host as ServiceHost;
use App\Models\Supplier\Host as SupplierHost; use App\Models\Supplier\Host as SupplierHost;
final class Host extends Type implements ProductItem final class Host extends Type
{ {
protected $table = 'product_host'; protected $table = 'product_host';

View File

@ -4,12 +4,11 @@ namespace App\Models\Product;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use App\Interfaces\ProductItem;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Service\Phone as ServicePhone; use App\Models\Service\Phone as ServicePhone;
use App\Models\Supplier\Phone as SupplierPhone; use App\Models\Supplier\Phone as SupplierPhone;
final class Phone extends Type implements ProductItem final class Phone extends Type
{ {
protected $table = 'product_phone'; protected $table = 'product_phone';

View File

@ -4,12 +4,11 @@ namespace App\Models\Product;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use App\Interfaces\ProductItem;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Service\SSL as ServiceSSL; use App\Models\Service\SSL as ServiceSSL;
use App\Models\Supplier\SSL as SupplierSSL; use App\Models\Supplier\SSL as SupplierSSL;
final class SSL extends Type implements ProductItem final class SSL extends Type
{ {
protected $table = 'product_ssl'; protected $table = 'product_ssl';

View File

@ -3,15 +3,31 @@
namespace App\Models\Product; namespace App\Models\Product;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use App\Interfaces\ProductItem;
use App\Models\Product; use App\Models\Product;
use App\Traits\{OrderServiceOptions,ProductDetails,SiteID}; use App\Traits\{OrderServiceOptions,SiteID};
abstract class Type extends Model /**
* Class Supplier\Type
*
* Attributes for supplier types:
* + billing_interval : The Billing interval that the supplier normally uses for this offering
*/
abstract class Type extends Model implements ProductItem
{ {
use SiteID,OrderServiceOptions; use SiteID,OrderServiceOptions;
public function __get($key): mixed
{
return match ($key) {
'billing_interval' => static::DefaultBill,
default => parent::__get($key),
};
}
/* RELATIONS */ /* RELATIONS */
/** /**
@ -36,24 +52,15 @@ abstract class Type extends Model
/* ATTRIBUTES */ /* ATTRIBUTES */
/**
* The Billing interval that the supplier normally uses for this offering
*
* @return int
*/
public function getBillingIntervalAttribute(): int
{
return static::DefaultBill;
}
/** /**
* The product contract term is the highest of our defined contract_term (in Products/*) vs the suppliers * The product contract term is the highest of our defined contract_term (in Products/*) vs the suppliers
* contract term (defined in Supplier/*). * contract term (defined in Supplier/*).
* *
* @param int $val
* @return int * @return int
*/ */
public function getContractTermAttribute(): int public function getContractTermAttribute(int $val): int
{ {
return max(Arr::get($this->attributes,'contract_term',0),$this->supplied->contract_term); return max($val,$this->supplied->contract_term);
} }
} }

View File

@ -65,7 +65,7 @@ use App\Traits\{ScopeAccountUserAuthorised,ScopeServiceActive,SiteID};
* + sid : System ID for service * + sid : System ID for service
* + supplied : The model of the supplier's product used for this service. * + supplied : The model of the supplier's product used for this service.
*/ */
class Service extends Model implements IDs class Service extends Model
{ {
use HasFactory,ScopeAccountUserAuthorised,ScopeServiceActive,SiteID; use HasFactory,ScopeAccountUserAuthorised,ScopeServiceActive,SiteID;
@ -313,6 +313,9 @@ class Service extends Model implements IDs
'is_pending_change' => $this->active && $this->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->count(), 'is_pending_change' => $this->active && $this->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->count(),
'is_pending_cancel' => $this->active && in_array(strtolower($this->order_status),['cancel-request','cancel-pending']), 'is_pending_cancel' => $this->active && in_array(strtolower($this->order_status),['cancel-request','cancel-pending']),
'lid' => sprintf('%05s',$this->id),
'sid' => sprintf('%02s-%04s.%s',$this->site_id,$this->account_id,$this->lid),
'status' => $this->active 'status' => $this->active
? strtolower($this->order_status) ? strtolower($this->order_status)
: ((strtolower($this->order_status) === 'cancelled') ? 'cancelled' : 'inactive'), : ((strtolower($this->order_status) === 'cancelled') ? 'cancelled' : 'inactive'),
@ -341,28 +344,6 @@ class Service extends Model implements IDs
->get(); ->get();
} }
/* INTERFACES */
/**
* Service Local ID
*
* @return string
*/
public function getLIDAttribute(): string
{
return sprintf('%05s',$this->id);
}
/**
* Services System ID
*
* @return string
*/
public function getSIDAttribute(): string
{
return sprintf('%02s-%04s.%s',$this->site_id,$this->account_id,$this->getLIDattribute());
}
/* RELATIONS */ /* RELATIONS */
/** /**
@ -1047,7 +1028,7 @@ class Service extends Model implements IDs
* @return Collection * @return Collection
* @throws Exception * @throws Exception
*/ */
public function next_invoice_items(Carbon $billdate=NULL): Collection public function next_invoice_items(?Carbon $billdate=NULL): Collection
{ {
if ($this->is_cancelled || (! $this->is_billed)) if ($this->is_cancelled || (! $this->is_billed))
return collect(); return collect();

View File

@ -44,6 +44,8 @@ class Broadband extends Type implements ServiceUsage
return $this->service_number ?: ($this->service_address ?: '-'); return $this->service_number ?: ($this->service_address ?: '-');
} }
/* RELATIONS */
/** /**
* The usage information for broadband * The usage information for broadband
* *

View File

@ -17,6 +17,15 @@ class SSL extends Type
protected $public_key = NULL; protected $public_key = NULL;
protected $crt_parse = NULL; protected $crt_parse = NULL;
public function __get($key): mixed
{
return match ($key) {
'in_contract' => FALSE,
default => parent::__get($key),
};
}
/* STATIC METHODS */ /* STATIC METHODS */
public static function boot() public static function boot()
@ -82,25 +91,4 @@ class SSL extends Type
? Arr::get($this->crt_parse,'subject.CN') ? Arr::get($this->crt_parse,'subject.CN')
: Arr::get(openssl_csr_get_subject($this->csr),'CN',''); : Arr::get(openssl_csr_get_subject($this->csr),'CN','');
} }
/**
* Certificates have no contract and can be cancelled anytime.
*
* @return bool
*/
public function inContract(): bool
{
return FALSE;
}
/* METHODS */
/**
* @return Carbon|null
* @deprecated use getServiceExpireAttribute()
*/
public function getValidToAttribute()
{
abort(500,'use getServiceExpireAttribute');
}
} }

View File

@ -22,6 +22,17 @@ abstract class Type extends Model implements ServiceItem
public $timestamps = FALSE; public $timestamps = FALSE;
public function __get($key): mixed
{
return match ($key) {
'contract_term' => $this->service->offering->contract_term,
'has_expired' => (! $this->in_contract) && ($this->service->invoice_next && $this->service->invoice_next->isPast()),
'in_contract' => $this->expire_at && $this->expire_at->isFuture(),
default => parent::__get($key),
};
}
/* RELATIONS */ /* RELATIONS */
/** /**
@ -50,11 +61,17 @@ abstract class Type extends Model implements ServiceItem
->where('site_id',$this->site_id); ->where('site_id',$this->site_id);
} }
/* INTERFACE */ /* ATTRIBUTES */
public function getContractTermAttribute(): int /**
* We need to cast some dates to LeenooksCarbon to get access to startOfHalf()/endOfHalf() methods
*
* @param $value
* @return LeenooksCarbon|null
*/
public function getExpireAtAttribute($value): ?LeenooksCarbon
{ {
return $this->service->offering->contract_term; return $value ? LeenooksCarbon::create($value) : NULL;
} }
public function getServiceExpireAttribute(): ?LeenooksCarbon public function getServiceExpireAttribute(): ?LeenooksCarbon
@ -62,43 +79,8 @@ abstract class Type extends Model implements ServiceItem
return $this->expire_at ?: $this->service->invoice_next_at; return $this->expire_at ?: $this->service->invoice_next_at;
} }
public function hasExpired(): bool
{
return (! $this->inContract())
&& ($this->service->invoice_next && $this->service->invoice_next->isPast());
}
public function inContract(): bool
{
return $this->expire_at
&& $this->expire_at->isFuture();
}
/* ATTRIBUTES */
/**
* We need to cast some dates to LeenooksCarbon to get access to startOfHalf()/endOfHalf() methods
*
* @param $value
* @return LeenooksCarbon
*/
public function getExpireAtAttribute($value): ?LeenooksCarbon
{
return $value ? LeenooksCarbon::create($value) : NULL;
}
/* METHODS */ /* METHODS */
/**
* Validation used to accept form input
*
* @return mixed
*/
public function validation(): array
{
return [];
}
/** /**
* The supplier's service that we provide * The supplier's service that we provide
* *
@ -119,4 +101,14 @@ abstract class Type extends Model implements ServiceItem
{ {
return collect(); return collect();
} }
/**
* Validation used to accept form input
*
* @return mixed
*/
public function validation(): array
{
return [];
}
} }

View File

@ -40,7 +40,7 @@ class Supplier extends Model
* @param Supplier|null $so * @param Supplier|null $so
* @return Collection * @return Collection
*/ */
public static function offeringTypes(self $so=NULL): Collection public static function offeringTypes(?self $so=NULL): Collection
{ {
$result = collect(); $result = collect();

View File

@ -73,7 +73,7 @@ class Broadband extends Type
* @param bool $ceil Round the numbers to integers * @param bool $ceil Round the numbers to integers
* @return array|string * @return array|string
*/ */
public function allowance(Collection $config=NULL,array $data=[],bool $ceil=TRUE) public function allowance(?Collection $config=NULL,array $data=[],bool $ceil=TRUE)
{ {
$map = collect(self::traffic_map); $map = collect(self::traffic_map);
$merge = collect(self::traffic_merge); $merge = collect(self::traffic_merge);

View File

@ -16,11 +16,13 @@ final class Domain extends Type
// The model of the product that is supplied by this model // The model of the product that is supplied by this model
const ProductModel = ProductDomain::class; const ProductModel = ProductDomain::class;
/* INTERFACES */ public function __get($key): mixed
public function getNameAttribute(): string
{ {
return sprintf('%s: %s',$this->product_id,$this->tld->name); return match ($key) {
'name' => sprintf('%s: %s',$this->product_id,$this->tld->name),
default => parent::__get($key),
};
} }
/* STATIC */ /* STATIC */

View File

@ -3,11 +3,10 @@
namespace App\Models\Supplier; namespace App\Models\Supplier;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Leenooks\Traits\ScopeActive; use Leenooks\Traits\ScopeActive;
use App\Models\{Invoice, Supplier, SupplierDetail}; use App\Models\{Supplier,SupplierDetail};
use App\Traits\SiteID; use App\Traits\SiteID;
/** /**
@ -31,6 +30,12 @@ abstract class Type extends Model
'category_lc' => strtolower($this->category), 'category_lc' => strtolower($this->category),
'category_name' => static::category_name ?: $this->category, 'category_name' => static::category_name ?: $this->category,
'min_cost' => $this->setup_cost+$this->base_cost*$this->contract_term,
'name' => $this->product_id ?: 'Supplier PID Unknown',
'name_long' => $this->product_desc ?: 'Supplier NAME Unknown',
'supplier' => $this->supplier_detail->supplier,
default => parent::__get($key), default => parent::__get($key),
}; };
} }
@ -59,31 +64,11 @@ abstract class Type extends Model
return $val ?: 1; return $val ?: 1;
} }
public function getMinCostAttribute(): float
{
return $this->setup_cost+$this->base_cost*$this->contract_term;
}
public function getNameAttribute(): string
{
return $this->product_id ?: 'Supplier PID Unknown';
}
public function getNameLongAttribute(): string
{
return $this->product_desc ?: 'Supplier NAME Unknown';
}
public function getSetupCostAttribute(?float $val): float public function getSetupCostAttribute(?float $val): float
{ {
return $val ?: 0; return $val ?: 0;
} }
public function getSupplierAttribute(): Model
{
return $this->supplier_detail->supplier;
}
public function validation(): array public function validation(): array
{ {
return [ return [

View File

@ -20,7 +20,7 @@ use App\Traits\SiteID;
* Attributes for users: * Attributes for users:
* + role : User's role * + role : User's role
*/ */
class User extends Authenticatable implements IDs class User extends Authenticatable
{ {
use HasFactory,HasApiTokens,Notifiable,UserSwitch,ScopeActive,SiteID; use HasFactory,HasApiTokens,Notifiable,UserSwitch,ScopeActive,SiteID;
@ -63,6 +63,16 @@ class User extends Authenticatable implements IDs
'customer', 'customer',
]; ];
public function __get($key): mixed
{
return match ($key) {
'lid' => sprintf('#%04s',$this->id),
'sid' => sprintf('%02s-%s',$this->site_id,$this->lid),
default => parent::__get($key),
};
}
/* OVERRIDES */ /* OVERRIDES */
/** /**
@ -76,18 +86,6 @@ class User extends Authenticatable implements IDs
->onQueue('user')); ->onQueue('user'));
} }
/* INTERFACES */
public function getLIDAttribute(): string
{
return sprintf('#%04s',$this->id);
}
public function getSIDAttribute(): string
{
return sprintf('%02s-%s',$this->site_id,$this->getLIDAttribute());
}
/* RELATIONS */ /* RELATIONS */
/** /**
@ -242,7 +240,7 @@ class User extends Authenticatable implements IDs
* @param User|null $user * @param User|null $user
* @return bool * @return bool
*/ */
public function isAdmin(User $user=NULL): bool public function isAdmin(?User $user=NULL): bool
{ {
return $user->exists return $user->exists
&& $this->isReseller() && $this->isReseller()

View File

@ -1,21 +1,21 @@
<?php <?php
/**
* Add a ScopeAuthorised to an Eloquent Model
* This will help limit the scope of accounts that a user can see.
*/
namespace App\Traits; namespace App\Traits;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use App\Models\User; use App\Models\User;
/**
* Add a ScopeAuthorised to an Eloquent Model
* This will help limit the scope of accounts that a user can see.
*/
trait ScopeAccountUserAuthorised trait ScopeAccountUserAuthorised
{ {
/** /**
* Only query records that the user is authorised to see * Only query records that the user is authorised to see
*/ */
public function scopeAccountUserAuthorised($query,string $table=NULL,User $uo=NULL) public function scopeAccountUserAuthorised($query,?string $table=NULL,?User $uo=NULL)
{ {
if (! $uo) if (! $uo)
$uo = Auth::user(); $uo = Auth::user();

View File

@ -37,7 +37,7 @@
<tbody> <tbody>
@foreach ($o as $oo) @foreach ($o as $oo)
<tr @if ($oo->hasExpired()) class="table-danger" @endif> <tr @if ($oo->has_expired) class="table-danger" @endif>
<td><a href="{{ url('u/service',[$oo->service_id]) }}">{{ $oo->service->sid }}</td> <td><a href="{{ url('u/service',[$oo->service_id]) }}">{{ $oo->service->sid }}</td>
<td>{{ $oo->service->account->name }}</td> <td>{{ $oo->service->account->name }}</td>
<td>{{ $oo->service->product->name }}</td> <td>{{ $oo->service->product->name }}</td>

View File

@ -39,7 +39,7 @@
<tbody> <tbody>
@foreach ($o as $oo) @foreach ($o as $oo)
<tr @if ($oo->hasExpired()) class="table-danger" @endif> <tr @if ($oo->has_expired) class="table-danger" @endif>
<td><a href="{{ url('u/service',[$oo->service_id]) }}">{{ $oo->service->sid }}</td> <td><a href="{{ url('u/service',[$oo->service_id]) }}">{{ $oo->service->sid }}</td>
<td>{{ $oo->service->account->name }}</td> <td>{{ $oo->service->account->name }}</td>
<td>{{ $oo->service->product->name }}</td> <td>{{ $oo->service->product->name }}</td>

View File

@ -36,7 +36,7 @@
<tbody> <tbody>
@foreach ($o as $oo) @foreach ($o as $oo)
<tr @if ($oo->hasExpired()) class="table-danger" @endif> <tr @if ($oo->has_expired) class="table-danger" @endif>
<td><a href="{{ url('u/service',[$oo->service_id]) }}">{{ $oo->service->sid }}</td> <td><a href="{{ url('u/service',[$oo->service_id]) }}">{{ $oo->service->sid }}</td>
<td>{{ $oo->service->account->name }}</td> <td>{{ $oo->service->account->name }}</td>
<td>{{ $oo->service->product->name }}</td> <td>{{ $oo->service->product->name }}</td>

View File

@ -62,7 +62,7 @@
<th>IP6 Address</th> <th>IP6 Address</th>
<td>{{ $o->ip6address ?: '-' }}</td> <td>{{ $o->ip6address ?: '-' }}</td>
</tr> </tr>
@if ($o->inContract()) @if ($o->in_contract)
<tr> <tr>
<th>Contract</th> <th>Contract</th>
<td>{{ $o->contract_term }} months</td> <td>{{ $o->contract_term }} months</td>
@ -74,7 +74,7 @@
@endif @endif
<tr> <tr>
<th>Cancel Notice</th> <th>Cancel Notice</th>
<td>1 month @if($o->inContract())<small>(after {{ $o->service_expire->subMonth()->format('Y-m-d') }})</small>@endif</td> <td>1 month @if($o->in_contract)<small>(after {{ $o->service_expire->subMonth()->format('Y-m-d') }})</small>@endif</td>
</tr> </tr>
@if(($x=$o->service->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->get()->pop())) @if(($x=$o->service->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->get()->pop()))

View File

@ -20,7 +20,7 @@
<td>{{ $o->service_connect_date->format('Y-m-d') }}</td> <td>{{ $o->service_connect_date->format('Y-m-d') }}</td>
</tr> </tr>
@endif @endif
@if ($o->inContract()) @if ($o->in_contract)
<tr> <tr>
<th>Contract Term</th> <th>Contract Term</th>
<td>{{ $o->service->contract_term }} months</td> <td>{{ $o->service->contract_term }} months</td>

View File

@ -34,7 +34,7 @@
<td>{{ $o->service_connect_date->format('Y-m-d') }}</td> <td>{{ $o->service_connect_date->format('Y-m-d') }}</td>
</tr> </tr>
@endif @endif
@if ($o->inContract()) @if ($o->in_contract)
<tr> <tr>
<th>Contract Term</th> <th>Contract Term</th>
<td>{{ $o->service->contract_term }} months</td> <td>{{ $o->service->contract_term }} months</td>

View File

@ -46,7 +46,7 @@
<td>{{ $o->service->product->type->allowance_string() }} Included Calls</td> <td>{{ $o->service->product->type->allowance_string() }} Included Calls</td>
</tr> </tr>
@endif @endif
@if ($o->inContract()) @if ($o->in_contract)
<tr> <tr>
<th>Contract</th> <th>Contract</th>
<td>{{ $o->contract_term }} months</td> <td>{{ $o->contract_term }} months</td>
@ -58,7 +58,7 @@
@endif @endif
<tr> <tr>
<th>Cancel Notice</th> <th>Cancel Notice</th>
<td>1 month @if($o->inContract())<small>(after {{ $o->service_expire->subMonth()->format('Y-m-d') }})</small>@endif</td> <td>1 month @if($o->in_contract)<small>(after {{ $o->service_expire->subMonth()->format('Y-m-d') }})</small>@endif</td>
</tr> </tr>
</table> </table>
</div> </div>