Added in email hosting, and other misc cosmetic fixes

This commit is contained in:
Deon George
2022-04-02 18:06:34 +11:00
parent 7775105da6
commit a4ed29b560
35 changed files with 1181 additions and 104 deletions

View File

@@ -9,7 +9,6 @@ use App\Models\Service;
abstract class ServiceType extends Model
{
public $timestamps = FALSE;
public $dateFormat = 'U';
/**
* @NOTE: The service_id column could be discarded, if the id column=service_id

View File

@@ -2,16 +2,18 @@
namespace App\Models;
use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Leenooks\Traits\ScopeActive;
use App\Interfaces\IDs;
use App\Interfaces\{IDs,ProductItem};
use App\Traits\{ProductDetails,SiteID};
/**
@@ -23,6 +25,7 @@ use App\Traits\{ProductDetails,SiteID};
*
* Attributes for products:
* + lid : Local ID for product (part number)
* + sid : System ID for product (part number)
* + supplied : Supplier product provided for this offering
* + supplier : Supplier for this offering
* + name : Brief Name for our product
@@ -36,6 +39,7 @@ use App\Traits\{ProductDetails,SiteID};
* + base_charge_taxable : Default billing amount including taxes
* + min_charge : Minimum cost taking into account billing interval and setup costs
* + min_charge_taxable : Minimum cost taking into account billing interval and setup costs including taxes
* + type : Returns the underlying product object, representing the type of product
*
* Attributes for product types (type - Product/*)
* + name : Short Name for our Product
@@ -66,6 +70,8 @@ class Product extends Model implements IDs
'pricing'=>'collection',
];
protected $with = ['description'];
/* RELATIONS */
/**
@@ -145,7 +151,7 @@ class Product extends Model implements IDs
*/
public function getBaseCostAttribute(): float
{
return round($this->type->supplied->base_cost*Invoice::billing_change($this->type->supplied->getBillingIntervalAttribute(),$this->getBillingIntervalAttribute()) ?: 0,2);
return round($this->getSuppliedAttribute()->base_cost*Invoice::billing_change($this->getSuppliedAttribute()->getBillingIntervalAttribute(),$this->getBillingIntervalAttribute()) ?: 0,2);
}
/**
@@ -167,7 +173,7 @@ class Product extends Model implements IDs
*/
public function getBillingIntervalAttribute(): int
{
return max($this->price_recur_default,$this->type->supplied->getBillingIntervalAttribute());
return max($this->price_recur_default,$this->getSuppliedAttribute()->getBillingIntervalAttribute());
}
/**
@@ -239,10 +245,31 @@ class Product extends Model implements IDs
* Get our product type
*
* @return string
* @todo is the test of type and type->supplied necessary?
*/
public function getProductTypeAttribute(): string
{
return ($this->type && $this->type->supplied) ? $this->type->supplied->getTypeAttribute() : 'Unknown';
return ($this->type && $this->type->supplied) ? $this->getSuppliedAttribute()->getTypeAttribute() : 'Unknown';
}
/**
* Suppliers
*
* @return Model
*/
public function getSupplierAttribute(): Model
{
return $this->getSuppliedAttribute()->supplier_detail->supplier;
}
/**
* Suppliers product
*
* @return Model
*/
public function getSuppliedAttribute(): Model
{
return $this->type->supplied;
}
/**
@@ -277,7 +304,7 @@ class Product extends Model implements IDs
*/
public function getSetupCostAttribute(): float
{
return $this->type->supplied->setup_cost ?: 0;
return $this->getSuppliedAttribute()->setup_cost ?: 0;
}
/**
@@ -294,13 +321,33 @@ class Product extends Model implements IDs
/* METHODS */
/**
* Return if this product captures usage data
* Return a list of available product types
*
* @return bool
* @return Collection
*/
public function hasUsage(): bool
function availableTypes(): Collection
{
return $this->type->hasUsage();
$models = collect(File::allFiles(app_path()))
->map(function ($item) {
$path = $item->getRelativePathName();
$class = sprintf('%s%s',
Container::getInstance()->getNamespace(),
strtr(substr($path, 0, strrpos($path, '.')), '/', '\\'));
return $class;
})
->filter(function ($class) {
$valid = FALSE;
if (class_exists($class)) {
$reflection = new \ReflectionClass($class);
$valid = $reflection->isSubclassOf(ProductItem::class) && (! $reflection->isAbstract());
}
return $valid;
});
return $models->values();
}
/**
@@ -347,6 +394,16 @@ class Product extends Model implements IDs
return round($price,2);
}
/**
* Return if this product captures usage data
*
* @return bool
*/
public function hasUsage(): bool
{
return $this->type->hasUsage();
}
/**
* When receiving an order, validate that we have all the required information for the product type
*

View File

@@ -3,6 +3,7 @@
namespace App\Models\Product;
use Illuminate\Support\Collection;
use Leenooks\Traits\ScopeActive;
use App\Interfaces\ProductItem;
use App\Models\Supplier;
@@ -11,6 +12,8 @@ use App\Models\Supplier\Broadband as SupplierBroadband;
final class Broadband extends Type implements ProductItem
{
use ScopeActive;
protected $table = 'product_broadband';
// Information required during the order process
@@ -44,17 +47,6 @@ final class Broadband extends Type implements ProductItem
return $this->hasOne(SupplierBroadband::class,'id','supplier_broadband_id');
}
/**
* The supplier
*
* @return \Illuminate\Database\Eloquent\Relations\HasOneThrough
*/
// @todo To check
public function supplier()
{
return $this->hasOneThrough(Supplier::class,SupplierBroadband::class,'id','id','adsl_supplier_plan_id','supplier_id');
}
/* INTERFACES */
/**

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Models\Product;
use Illuminate\Support\Collection;
use App\Interfaces\ProductItem;
use App\Models\Service\Email as ServiceEmail;
use App\Models\Supplier\Email as SupplierEmail;
final class Email extends Type implements ProductItem
{
protected $table = 'product_email';
// The model that is referenced when this product is ordered
protected string $order_model = ServiceEmail::class;
/* RELATIONS */
/**
* The offering supplied with this product
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function supplied()
{
return $this->hasOne(SupplierEmail::class,'id','supplier_email_id');
}
/* INTERFACES */
public function allowance(): Collection
{
// N/A
return collect();
}
public function allowance_string(): string
{
// N/A
return '';
}
public function getContractTermAttribute(): int
{
return 12;
}
public function getCostAttribute(): float
{
// N/A
return 0;
}
public function getSupplierAttribute()
{
return '';
}
public function getTypeAttribute()
{
return 'Domain Name';
}
public function hasUsage(): bool
{
return FALSE;
}
}

View File

@@ -8,6 +8,8 @@ class ProductTranslate extends Model
{
protected $table = 'ab_product_translate';
public $timestamps = FALSE;
public function getDescriptionFullAttribute($value)
{
return unserialize($value);

View File

@@ -27,6 +27,7 @@ use App\Interfaces\IDs;
* + additional_cost : Pending additional charges for this service (excluding setup)
* + billing_cost : Charge for this service each invoice period
* + billing_interval : The period that this service is billed for by default
* + billing_interval_string : The period that this service is billed for by default as a name
* + name : Service short name with service address
* + name_short : Service Product short name, eg: phone number, domain name, certificate CN
* + name_detail : Service Detail, eg: service_address
@@ -880,11 +881,11 @@ class Service extends Model implements IDs
* This is used for view specific details
*
* @return string
* @todo I think this can be removed - and dynamically determined
*/
public function getSTypeAttribute(): string
{
switch($this->product->model) {
case 'App\Models\Product\Broadband': return 'broadband';
default: return $this->type->type;
}
}

View File

@@ -10,6 +10,7 @@ class AdslTraffic extends Model
protected $table = 'ab_service__adsl_traffic';
public $timestamps = FALSE;
protected $dates = ['date'];
public $dateFormat = 'U';
private $traffic_end = 14;
public function broadband()

View File

@@ -22,6 +22,7 @@ class Broadband extends ServiceType implements ServiceItem,ServiceUsage
'service_connect_date',
'service_contract_date'
];
public $dateFormat = 'U';
protected $table = 'ab_service__adsl';
/* RELATIONS */

View File

@@ -27,46 +27,11 @@ class Domain extends ServiceType implements ServiceItem
protected $dates = [
'domain_expire',
];
public $dateFormat = 'U';
protected $table = 'service_domains';
protected $with = ['tld'];
/* RELATIONS */
public function account()
{
return $this->hasOneThrough(Account::class,Service::class);
}
public function registrar()
{
return $this->belongsTo(DomainRegistrar::class,'domain_registrar_id');
}
public function tld()
{
return $this->belongsTo(DomainTld::class,'domain_tld_id');
}
/* SCOPES */
/**
* Search for a record
*
* @param $query
* @param string $term
* @return mixed
*/
public function scopeSearch($query,string $term)
{
// If we have a period in the name, we'll ignore everything after it.
$term = strstr($term,'.',TRUE) ?: $term;
// Build our where clause
return parent::scopeSearch($query,$term)
->orwhere('domain_name','like','%'.$term.'%');
}
/* ATTRIBUTES */
/* INTERFACES */
public function getServiceDescriptionAttribute(): string
{
@@ -93,4 +58,41 @@ class Domain extends ServiceType implements ServiceItem
{
return $this->domain_expire->isFuture();
}
/* RELATIONS */
public function account()
{
return $this->hasOneThrough(Account::class,Service::class);
}
public function registrar()
{
return $this->belongsTo(DomainRegistrar::class,'domain_registrar_id');
}
public function tld()
{
return $this->belongsTo(DomainTld::class,'domain_tld_id');
}
/* SCOPES */
/**
* Search for a record
*
* @param $query
* @param string $term
* @return mixed
*/
public function scopeSearch($query,string $term)
{
// If we have a period in the name, we'll ignore everything after it.
$term = strstr($term,'.',TRUE) ?: $term;
// Build our where clause
return parent::scopeSearch($query,$term)
->orwhere('domain_name','like','%'.$term.'%');
}
/* ATTRIBUTES */
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Models\Service;
use Carbon\Carbon;
use App\Models\Base\ServiceType;
use App\Models\{Account, DomainRegistrar, DomainTld, Service, TLD};
use App\Interfaces\ServiceItem;
use App\Traits\{NextKey,ScopeServiceActive,ScopeServiceUserAuthorised};
/**
* Class Email (Service)
* Services that email hostings
*
* Attributes for services:
* + service_description : Description as shown in a Service Context
* + service_expire : The date the service expires
* + service_name : Name as shown in a Service Context
*
* @package App\Models\Service
*/
class Email extends ServiceType implements ServiceItem
{
use ScopeServiceActive,ScopeServiceUserAuthorised;
protected $dates = ['expire_at'];
protected $table = 'service_emails';
/* INTERFACES */
public function getServiceDescriptionAttribute(): string
{
// N/A
return 'Email Hosting';
}
public function getServiceExpireAttribute(): Carbon
{
return $this->expire_at ?: $this->service->next_invoice;
}
/**
* The name of the domain with its TLD
*
* @return string
* // @todo
*/
public function getServiceNameAttribute(): string
{
return strtoupper(sprintf('%s.%s',$this->domain_name,$this->tld->name));
}
public function inContract(): bool
{
return $this->expire_at && $this->expire_at->isFuture();
}
/* RELATIONS */
public function tld()
{
return $this->belongsTo(TLD::class);
}
}

View File

@@ -17,6 +17,7 @@ class Host extends ServiceType implements ServiceItem
protected $dates = [
'host_expire',
];
public $dateFormat = 'U';
protected $table = 'ab_service__hosting';
public function provider()

View File

@@ -16,6 +16,7 @@ class Voip extends ServiceType implements ServiceItem
'service_connect_date',
'service_contract_date',
];
public $dateFormat = 'U';
protected $table = 'ab_service__voip';
/* SCOPES */

View File

@@ -7,7 +7,7 @@ use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Leenooks\Traits\ScopeActive;
use App\Models\Supplier\{Broadband,Domain,Ethernet,Generic,Host,HSPA,Voip};
use App\Models\Supplier\{Broadband,Domain,Email,Ethernet,Generic,Host,HSPA,Voip};
class Supplier extends Model
{
@@ -33,6 +33,10 @@ class Supplier extends Model
'name' => 'Domain Name',
'class' => Domain::class,
],
'email' => [
'name' => 'Email Hosting',
'class' => Email::class,
],
'generic' => [
'name' => 'Generic',
'class' => Generic::class,

View File

@@ -12,11 +12,6 @@ final class Domain extends Type implements SupplierItem
/* INTERFACES */
public function types()
{
return $this->belongsToMany(ProductDomain::class,$this->table,'id','id','id',$this->table.'_id');
}
public function getBillingIntervalAttribute(): int
{
return 4; // Yearly
@@ -27,6 +22,11 @@ final class Domain extends Type implements SupplierItem
return sprintf('%s: %s',$this->product_id,$this->tld->name);
}
public function types()
{
return $this->belongsToMany(ProductDomain::class,$this->table,'id','id','id',$this->table.'_id');
}
/* RELATIONS */
public function tld()

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Models\Supplier;
use App\Interfaces\SupplierItem;
use App\Models\Product\Email as ProductEmail;
final class Email extends Type implements SupplierItem
{
protected $table = 'supplier_email';
/* INTERFACES */
public function getBillingIntervalAttribute(): int
{
return 4; // Yearly
}
public function types()
{
return $this->belongsToMany(ProductEmail::class,$this->table,'id','id','id',$this->table.'_id');
}
}