More works on products

This commit is contained in:
Deon George 2022-02-01 16:40:46 +11:00
parent 1e9f15b40f
commit b9b4416737
36 changed files with 952 additions and 312 deletions

View File

@ -186,11 +186,11 @@ class AdminController extends Controller
$validation = $request->validate([
'name' => 'required|string|min:2|max:255',
'active' => 'sometimes|accepted',
'address1' => 'required|string|min:2|max:255',
'address1' => 'nullable|string|min:2|max:255',
'address2' => 'nullable|string|min:2|max:255',
'city' => 'required|string|min:2|max:64',
'state' => 'required|string|min:2|max:32',
'postcode' => 'required|string|min:2|max:8',
'city' => 'nullable|string|min:2|max:64',
'state' => 'nullable|string|min:2|max:32',
'postcode' => 'nullable|string|min:2|max:8',
'supplier_details.notes' => 'nullable|string|min:3',
'supplier_details.accounts' => 'nullable|email',
'supplier_details.support' => 'nullable|email',

View File

@ -207,7 +207,7 @@ class ServiceController extends Controller
* @param Request $request
* @param Service $o
* @return RedirectResponse
* @todo revalidate
* @deprecated - use update()
*/
public function domain_edit(Request $request,Service $o)
{
@ -254,4 +254,27 @@ class ServiceController extends Controller
return view('r.service.domain.list')
->with('o',$o);
}
/**
* Update details about a service
*
* @param Request $request
* @param Service $o
* @return RedirectResponse
* @todo This needs to be reworked, to take into account our different service types
* @todo Add Validation
*/
public function update(Request $request,Service $o)
{
if ($request->post($o->type->type)) {
$o->type->forceFill($request->post($o->type->type))->save();
}
if ($request->post('date_start'))
$o->date_start = $request->post('date_start');
$o->save();
return redirect()->back()->with('success','Record Updated');
}
}

View File

@ -2,75 +2,56 @@
namespace App\Interfaces;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Collection;
interface ProductItem
{
/* RELATIONS */
public function product();
public function supplied();
/**
* Supplier that provides this offering
* Return the traffic inclusion with the service
*
* @return BelongsTo
* @return mixed
*/
//public function supplier_detail(): BelongsTo;
public function allowance(): Collection;
/**
* Available products created from this supplier offering
* Render the traffic inclusion as a string
*
* @return BelongsToMany
* @return mixed
*/
//public function types(): BelongsToMany;
/* ATTRIBUTES */
public function allowance_string(): string;
/**
* Return the billing interval base cost including tax
* Return the contract term for this product when sold as a service
*
* @return float
*/
public function getBaseCostTaxableAttribute(): float;
/**
* Return the billing interval that the supplier charges
*
* @return string
*/
public function getBillingIntervalAttribute(): int;
/**
* The term that the supplier imposes on this service being connected
*
* @return int
* @return int Months
*/
public function getContractTermAttribute(): int;
/**
* Suppliers offering name (short)
*
* @return string
*/
public function getNameAttribute(): string;
/**
* Suppliers offering name (long)
*
* @return string
*/
public function getNameLongAttribute(): string;
/**
* Return the setup cost including tax
* Return the product cost
*
* @return float
*/
public function getSetupCostTaxableAttribute(): float;
public function getCostAttribute(): float;
/**
* Return the type of offering this is.
* Return the supplier class
* If there is a model relationship return:
* return $this->getRelationValue('supplier');
* otherwise return a stdClass with name
*
* @return string
* @return mixed
*/
public function getTypeAttribute();
public function getSupplierAttribute();
/**
* Does this offering capture usage information
*
* @return bool
*/
public function hasUsage(): bool;
}

View File

@ -1,56 +0,0 @@
<?php
namespace App\Interfaces;
use Illuminate\Support\Collection;
/**
* @deprecated - rename to productItem if still required
*/
interface ProductSupplier
{
/**
* Return the traffic inclusion with the service
*
* @return mixed
*/
public function allowance(): Collection;
/**
* Render the traffic inclusion as a string
*
* @return mixed
*/
public function allowance_string(): string;
/**
* Return the contract term for this product when sold as a service
*
* @return int Months
*/
public function getContractTermAttribute(): int;
/**
* Return the product cost
*
* @return float
*/
public function getCostAttribute(): float;
/**
* Return the supplier class
* If there is a model relationship return:
* return $this->getRelationValue('supplier');
* otherwise return a stdClass with name
*
* @return mixed
*/
public function getSupplierAttribute();
/**
* Does this offering capture usage information
*
* @return bool
*/
public function hasUsage(): bool;
}

View File

@ -2,9 +2,6 @@
namespace App\Interfaces;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
interface SupplierItem
{
/* RELATIONS */
@ -12,16 +9,16 @@ interface SupplierItem
/**
* Supplier that provides this offering
*
* @return BelongsTo
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function supplier_detail(): BelongsTo;
public function supplier_detail();
/**
* Available products created from this supplier offering
*
* @return BelongsToMany
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function types(): BelongsToMany;
public function types();
/* ATTRIBUTES */

View File

@ -1,12 +0,0 @@
<?php
namespace App\Models\Base;
use Illuminate\Database\Eloquent\Model;
/**
* @deprecated
*/
abstract class ProductType extends Model
{
}

View File

@ -5,6 +5,9 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Leenooks\Traits\ScopeActive;
/**
* @deprecated
*/
class DomainRegistrar extends Model
{
use ScopeActive;

View File

@ -5,6 +5,9 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Leenooks\Traits\ScopeActive;
/**
* @deprecated
*/
class DomainTld extends Model
{
use ScopeActive;
@ -24,4 +27,9 @@ class DomainTld extends Model
{
return strtoupper($value);
}
public function getPriceGroupAttribute($value): array
{
return unserialize($value);
}
}

View File

@ -8,6 +8,7 @@ use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Leenooks\Traits\ScopeActive;
use App\Interfaces\IDs;
@ -299,7 +300,7 @@ class Product extends Model implements IDs
*/
public function hasUsage(): bool
{
return $this->type->supplied->hasUsage();
return $this->type->hasUsage();
}
/**
@ -324,12 +325,24 @@ class Product extends Model implements IDs
$timeperiod = $this->getBillingIntervalAttribute();
// If the price doesnt exist for $go->id, use $go->id = 0 which is all users.
if (! $price=Arr::get($this->pricing,sprintf('%d.%d.%s',$timeperiod,$go->id,$type)))
$price = Arr::get($this->pricing,sprintf('%d.%d.%s',$timeperiod,0,$type));
if (! $price=Arr::get($this->pricing,sprintf('%d.%d.%s',$timeperiod,$go->id,$type))) {
$alt_tp = $timeperiod;
while (is_null($price=Arr::get($this->pricing,sprintf('%d.%d.%s',$alt_tp,0,$type))) && ($alt_tp >= 0)) {
$alt_tp--;
}
if (! is_null($price) && $alt_tp !== $timeperiod) {
$price = $price*Invoice::billing_change($alt_tp,$timeperiod);
}
}
// @todo - if price doesnt exist for the time period, reduce down to timeperiod 1 and multiply appropriately.
if (is_null($price))
abort(500,sprintf('Price is NULL, we need to find it timeperiod[%s] group[%s]',$timeperiod,$go->id));
if (is_null($price)) {
Log::error(sprintf('Price is still null for [%d] timeperiod [%d] group [%d]',$this->id,$timeperiod,$go->id));
$price = 0;
}
return round($price,2);
}

View File

@ -4,18 +4,13 @@ namespace App\Models\Product;
use Illuminate\Support\Collection;
use App\Interfaces\ProductSupplier;
use App\Models\Base\ProductType;
use App\Models\{Product,Supplier};
use App\Interfaces\ProductItem;
use App\Models\Supplier;
use App\Models\Service\Broadband as ServiceBroadband;
use App\Models\Supplier\Broadband as SupplierBroadband;
use App\Traits\{OrderServiceOptions,SiteID};
class Broadband extends ProductType implements ProductSupplier
final class Broadband extends Type implements ProductItem
{
use SiteID;
use OrderServiceOptions;
protected $table = 'product_broadband';
// Information required during the order process
@ -34,20 +29,11 @@ class Broadband extends ProductType implements ProductSupplier
],
];
// The model that is referenced when this product is ordered
protected string $order_model = ServiceBroadband::class;
/* RELATIONS */
/**
* The product that sells this type
*
* @return \Illuminate\Database\Eloquent\Relations\MorphOne
*/
public function product()
{
return $this->morphOne(Product::class, null,'model','model_id');
}
/**
* The offering supplied with this product
*
@ -123,6 +109,7 @@ class Broadband extends ProductType implements ProductSupplier
*
* @return string
*/
// @todo To check
public function allowance_string(): string
{
$result = '';

View File

@ -4,14 +4,30 @@ namespace App\Models\Product;
use Illuminate\Support\Collection;
use App\Interfaces\ProductSupplier;
use App\Models\Base\ProductType;
use App\Traits\NextKey;
use App\Interfaces\ProductItem;
use App\Models\Service\Domain as ServiceDomain;
use App\Models\Supplier\Domain as SupplierDomain;
class Domain extends ProductType implements ProductSupplier
final class Domain extends Type implements ProductItem
{
use NextKey;
const RECORD_ID = '';
protected $table = 'product_domain';
// The model that is referenced when this product is ordered
protected string $order_model = ServiceDomain::class;
/* RELATIONS */
/**
* The offering supplied with this product
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function supplied()
{
return $this->hasOne(SupplierDomain::class,'id','supplier_domain_id');
}
/* INTERFACES */
public function allowance(): Collection
{

View File

@ -2,10 +2,33 @@
namespace App\Models\Product;
use App\Models\Base\ProductType;
use Illuminate\Support\Collection;
class Generic extends ProductType
use App\Interfaces\ProductItem;
use App\Models\Service\Generic as ServiceGeneric;
use App\Models\Supplier\Generic as SupplierGeneric;
final class Generic extends Type implements ProductItem
{
protected $table = 'product_generic';
// The model that is referenced when this product is ordered
protected string $order_model = ServiceGeneric::class;
/* RELATIONS */
/**
* The offering supplied with this product
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function supplied()
{
return $this->hasOne(SupplierGeneric::class,'id','supplier_generic_id');
}
/* INTERFACES */
public function getContractTermAttribute(): int
{
return 0;
@ -20,4 +43,24 @@ class Generic extends ProductType
{
return FALSE;
}
public function allowance(): Collection
{
// TODO: Implement allowance() method.
}
public function allowance_string(): string
{
// TODO: Implement allowance_string() method.
}
public function getCostAttribute(): float
{
// TODO: Implement getCostAttribute() method.
}
public function getSupplierAttribute()
{
// TODO: Implement getSupplierAttribute() method.
}
}

View File

@ -2,13 +2,32 @@
namespace App\Models\Product;
use App\Models\Base\ProductType;
use App\Traits\NextKey;
use Illuminate\Support\Collection;
class Host extends ProductType
use App\Interfaces\ProductItem;
use App\Models\Service\Host as ServiceHost;
use App\Models\Supplier\Host as SupplierHost;
final class Host extends Type implements ProductItem
{
use NextKey;
const RECORD_ID = '';
protected $table = 'product_host';
// The model that is referenced when this product is ordered
protected string $order_model = ServiceHost::class;
/* RELATIONS */
/**
* The offering supplied with this product
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function supplied()
{
return $this->hasOne(SupplierHost::class,'id','supplier_host_id');
}
/* INTERFACES */
public function getContractTermAttribute(): int
{
@ -24,4 +43,24 @@ class Host extends ProductType
{
return FALSE;
}
public function allowance(): Collection
{
// TODO: Implement allowance() method.
}
public function allowance_string(): string
{
// TODO: Implement allowance_string() method.
}
public function getCostAttribute(): float
{
// TODO: Implement getCostAttribute() method.
}
public function getSupplierAttribute()
{
// TODO: Implement getSupplierAttribute() method.
}
}

View File

@ -4,16 +4,30 @@ namespace App\Models\Product;
use Illuminate\Support\Collection;
use App\Interfaces\ProductSupplier;
use App\Models\Base\ProductType;
use App\Traits\NextKey;
use App\Interfaces\ProductItem;
use App\Models\Service\SSL as ServiceSSL;
use App\Models\Supplier\SSL as SupplierSSL;
class SSL extends ProductType implements ProductSupplier
final class SSL extends Type implements ProductItem
{
use NextKey;
const RECORD_ID = 'ssl';
protected $table = 'product_ssl';
protected $table = 'ab_ssl';
// The model that is referenced when this product is ordered
protected string $order_model = ServiceSSL::class;
/* RELATIONS */
/**
* The offering supplied with this product
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function supplied()
{
return $this->hasOne(SupplierSSL::class,'id','supplier_ssl_id');
}
/* INTERFACES */
public function allowance(): Collection
{

View File

@ -0,0 +1,25 @@
<?php
namespace App\Models\Product;
use Illuminate\Database\Eloquent\Model;
use App\Models\Product;
use App\Traits\{OrderServiceOptions,SiteID};
abstract class Type extends Model
{
use SiteID,OrderServiceOptions;
/* RELATIONS */
/**
* The product that sells this type
*
* @return \Illuminate\Database\Eloquent\Relations\MorphOne
*/
public function product()
{
return $this->morphOne(Product::class, null,'model','model_id');
}
}

View File

@ -2,16 +2,15 @@
namespace App\Models\Product;
use App\Models\Base\ProductType;
use App\Traits\NextKey;
use App\Traits\OrderServiceOptions;
use Illuminate\Support\Collection;
class Voip extends ProductType
use App\Interfaces\ProductItem;
use App\Models\Service\Voip as ServiceVoip;
use App\Models\Supplier\Voip as SupplierVoip;
final class Voip extends Type implements ProductItem
{
use NextKey;
const RECORD_ID = '';
use OrderServiceOptions;
protected $table = 'product_voip';
protected $order_attributes = [
'options.phonenumber'=>[
@ -40,7 +39,22 @@ class Voip extends ProductType
],
];
protected $order_model = \App\Models\Service\Voip::class;
// The model that is referenced when this product is ordered
protected string $order_model = ServiceVoip::class;
/* RELATIONS */
/**
* The offering supplied with this product
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function supplied()
{
return $this->hasOne(SupplierVoip::class,'id','supplier_voip_id');
}
/* INTERFACES */
public function getContractTermAttribute(): int
{
@ -56,4 +70,24 @@ class Voip extends ProductType
{
return TRUE;
}
public function allowance(): Collection
{
// TODO: Implement allowance() method.
}
public function allowance_string(): string
{
// TODO: Implement allowance_string() method.
}
public function getCostAttribute(): float
{
// TODO: Implement getCostAttribute() method.
}
public function getSupplierAttribute()
{
// TODO: Implement getSupplierAttribute() method.
}
}

View File

@ -183,7 +183,7 @@ class Service extends Model implements IDs
'PAYMENT-CHECK' => [
'fail'=>'ORDER-HOLD',
'next'=>[
'ORDER-SENT'=>[],
'ORDER-SENT'=>['wholesaler'],
],
'system'=>TRUE,
'method'=>'action_payment_check',

View File

@ -7,7 +7,7 @@ use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Leenooks\Traits\ScopeActive;
use App\Models\Supplier\{Broadband,Ethernet,HSPA};
use App\Models\Supplier\{Broadband,Domain,Ethernet,Generic,Host,HSPA,Voip};
class Supplier extends Model
{
@ -31,19 +31,19 @@ class Supplier extends Model
],
'domainname' => [
'name' => 'Domain Name',
//'class' => Domain::class,
'class' => Domain::class,
],
'generic' => [
'name' => 'Generic',
//'class' => Generic::class,
'class' => Generic::class,
],
'hosting' => [
'name' => 'Hosting',
//'class' => Host::class,
'class' => Host::class,
],
'voip' => [
'name' => 'VOIP Telephone',
//'class' => Voip::class,
'class' => Voip::class,
],
];
@ -67,7 +67,7 @@ class Supplier extends Model
// See if we have any configurations
foreach (self::offering_types as $key => $type) {
if (! $class = Arr::get($type,'class'))
if (! ($class=Arr::get($type,'class')))
continue;
if (Arr::get($this->detail->connections,$key)) {

View File

@ -2,23 +2,14 @@
namespace App\Models\Supplier;
use App\Traits\ProductDetails;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Leenooks\Traits\ScopeActive;
use App\Interfaces\SupplierItem;
use App\Models\{Invoice,Supplier,SupplierDetail,Tax};
use App\Models\Product\Broadband as ProductBroadband;
use App\Traits\SiteID;
class Broadband extends Model implements SupplierItem
class Broadband extends Type implements SupplierItem
{
use SiteID,ScopeActive,ProductDetails;
protected $casts = [
'offpeak_start' => 'datetime:H:i',
'offpeak_end' => 'datetime:H:i',
@ -44,19 +35,9 @@ class Broadband extends Model implements SupplierItem
/* INTERFACES */
public function supplier_detail(): BelongsTo
public function types()
{
return $this->belongsTo(SupplierDetail::class);
}
public function types(): BelongsToMany
{
return $this->belongsToMany(ProductBroadband::class,'supplier_broadband','id','id','id','supplier_broadband_id');
}
public function getBaseCostTaxableAttribute(): float
{
return Tax::tax_calc($this->attributes['base_cost'],config('site')->taxes);
return $this->belongsToMany(ProductBroadband::class,$this->table,'id','id','id',$this->table.'_id');
}
public function getBillingIntervalAttribute(): int
@ -64,48 +45,6 @@ class Broadband extends Model implements SupplierItem
return 1; // Monthly
}
/**
* This contract term is the highest of
* + The defined contract_term
* + The default months in a billing interval
*
* @return int
*/
public function getContractTermAttribute(): int
{
return max(Invoice::billing_period(self::getBillingIntervalAttribute()),Arr::get($this->attributes,'contract_term'));
}
public function getMinCostAttribute(): float
{
return $this->attributes['setup_cost']+$this->attributes['base_cost']*Invoice::billing_term($this->getContractTermAttribute(),$this->getBillingIntervalAttribute());
}
public function getMinCostTaxableAttribute(): float
{
return Tax::tax_calc($this->getMinCostAttribute(),config('site')->taxes);
}
public function getNameAttribute(): string
{
return $this->product_id ?: 'Supplier PID Unknown';
}
public function getNameLongAttribute(): string
{
return $this->product_desc ?: 'Supplier NAME Unknown';
}
public function getSetupCostTaxableAttribute(): float
{
return Tax::tax_calc($this->attributes['setup_cost'],config('site')->taxes);
}
public function getTypeAttribute(): string
{
return Arr::get(collect(Supplier::offering_types)->firstWhere('class',get_class($this)),'name','Unknown');
}
/* METHODS */
/**

View File

@ -0,0 +1,36 @@
<?php
namespace App\Models\Supplier;
use App\Interfaces\SupplierItem;
use App\Models\Product\Domain as ProductDomain;
use App\Models\TLD;
final class Domain extends Type implements SupplierItem
{
protected $table = 'supplier_domain';
/* INTERFACES */
public function types()
{
return $this->belongsToMany(ProductDomain::class,$this->table,'id','id','id',$this->table.'_id');
}
public function getBillingIntervalAttribute(): int
{
return 4; // Yearly
}
public function getNameAttribute(): string
{
return sprintf('%s: %s',$this->product_id,$this->tld->name);
}
/* RELATIONS */
public function tld()
{
return $this->belongsTo(TLD::class);
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,71 @@
<?php
namespace App\Models\Supplier;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Leenooks\Traits\ScopeActive;
use App\Models\{Invoice,Supplier,SupplierDetail,Tax};
use App\Traits\{ProductDetails,SiteID};
abstract class Type extends Model
{
use SiteID,ScopeActive,ProductDetails;
/* RELATIONS */
public function supplier_detail()
{
return $this->belongsTo(SupplierDetail::class);
}
/* ATTRIBUTES */
public function getBaseCostTaxableAttribute(): float
{
return Tax::tax_calc($this->attributes['base_cost'],config('site')->taxes);
}
/**
* This contract term is the highest of
* + The defined contract_term
* + The default months in a billing interval
*
* @return int
*/
public function getContractTermAttribute(): int
{
return max(Invoice::billing_period(static::getBillingIntervalAttribute()),Arr::get($this->attributes,'contract_term'));
}
public function getMinCostAttribute(): float
{
return $this->attributes['setup_cost']+$this->attributes['base_cost']*Invoice::billing_term($this->getContractTermAttribute(),$this->getBillingIntervalAttribute());
}
public function getMinCostTaxableAttribute(): float
{
return Tax::tax_calc($this->getMinCostAttribute(),config('site')->taxes);
}
public function getNameAttribute(): string
{
return $this->product_id ?: 'Supplier PID Unknown';
}
public function getNameLongAttribute(): string
{
return $this->product_desc ?: 'Supplier NAME Unknown';
}
public function getSetupCostTaxableAttribute(): float
{
return Tax::tax_calc($this->attributes['setup_cost'],config('site')->taxes);
}
public function getTypeAttribute(): string
{
return Arr::get(collect(Supplier::offering_types)->firstWhere('class',get_class($this)),'name','Unknown');
}
}

View File

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

17
app/Models/TLD.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class TLD extends Model
{
protected $table = 'tlds';
/* ATTRIBUTES */
public function getNameAttribute($value): string
{
return strtoupper($value);
}
}

View File

@ -1,17 +1,20 @@
<?php
/**
* Creates and returns the Service Options Model for an Order.
*/
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
/**
* Creates and returns the Service Options Model for an Order.
*
* Example
*/
trait OrderServiceOptions
{
/*
protected $order_attributes = [
// Information required during the order process
protected array $order_attributes = [
'options.input'=>[
'request'=>'options.input',
'key'=>'column',
@ -20,7 +23,7 @@ trait OrderServiceOptions
],
];
protected $order_model = NULL;
protected string $order_model = NULL;
*/
public function orderValidation(Request $request): ?Model

View File

@ -16,6 +16,6 @@ trait ProductDetails
*/
public function getBillingIntervalStringAttribute(): string
{
return Invoice::billing_name(self::getBillingIntervalAttribute());
return Invoice::billing_name(static::getBillingIntervalAttribute());
}
}

View File

@ -13,7 +13,6 @@ class OptimizeProduct extends Migration
*/
public function up()
{
/*
Schema::table('ab_product', function (Blueprint $table) {
$table->dropForeign(['site_id']);
$table->dropIndex(['id','site_id']);
@ -30,11 +29,13 @@ class OptimizeProduct extends Migration
$table->dateTime('updated_at')->nullable()->after('created_at');
});
DB::statement('ALTER TABLE suppliers MODIFY address1 varchar(255),MODIFY city varchar(255),MODIFY state varchar(255),MODIFY postcode varchar(255)');
Schema::table('supplier_details', function (Blueprint $table) {
$table->jsonb('connections')->nullable();
});
foreach (\Illuminate\Support\Facades\DB::select('SELECT * FROM AB_ADSL_SUPPLIER') as $o) {
foreach (\Illuminate\Support\Facades\DB::select('SELECT * FROM ab_adsl_supplier') as $o) {
switch($o->name) {
case 'PeopleAgent':
$type = 'broadband';
@ -66,15 +67,7 @@ class OptimizeProduct extends Migration
}
$so = \App\Models\Supplier::where('name',$name)->singleOrNew();
if (! $so->exists) {
$so->name = $name;
$so->address1 = '...';
$so->city = '...';
$so->state = '...';
$so->postcode = '...';
}
$so->active = $so->active ?: $o->active;
$so->save();
@ -134,7 +127,7 @@ class OptimizeProduct extends Migration
\Illuminate\Support\Facades\DB::select("UPDATE products SET model='App\\\\Models\\\\Product\\\\Broadband' where model='App\\\\Models\\\\Product\\\\Adsl'");
// Convert to use the new supplier
foreach (\Illuminate\Support\Facades\DB::select('SELECT * FROM AB_ADSL_SUPPLIER') as $o) {
foreach (\Illuminate\Support\Facades\DB::select('SELECT * FROM ab_adsl_supplier') as $o) {
switch ($o->name) {
case 'PeopleAgent':
$so = \App\Models\Supplier::where('name','People Telecom')->singleOrFail();
@ -278,9 +271,347 @@ class OptimizeProduct extends Migration
Schema::table('products', function (Blueprint $table) {
$table->dropColumn(['date_orig','date_last','group_avail','avail_category','price_recurr_day','price_recurr_weekday','prod_plugin_file']);
});
*/
Schema::dropIfExists('ab_voip_plan');
abort(500,'here');
Schema::create('tlds',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->string('name',64)->unique();
});
Schema::create('supplier_domain',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->boolean('active');
$table->integer('supplier_detail_id')->unsigned();
$table->string('product_id',16);
$table->string('product_desc',128)->nullable();
$table->float('base_cost');
$table->float('setup_cost')->nullable();
$table->integer('contract_term')->unsigned()->nullable();
$table->integer('tld_id')->unsigned();
$table->text('whois_url')->nullable();
$table->text('config')->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['tld_id'])->references(['id'])->on('tlds');
$table->foreign(['supplier_detail_id','site_id'])->references(['id','site_id'])->on('supplier_details');
});
Schema::create('supplier_host',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->boolean('active');
$table->integer('supplier_detail_id')->unsigned();
$table->string('product_id',16);
$table->string('product_desc',128)->nullable();
$table->float('base_cost');
$table->float('setup_cost')->nullable();
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_detail_id','site_id'])->references(['id','site_id'])->on('supplier_details');
});
Schema::create('supplier_ssl',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->boolean('active');
$table->integer('supplier_detail_id')->unsigned();
$table->string('product_id',16);
$table->string('product_desc',128)->nullable();
$table->float('base_cost');
$table->float('setup_cost')->nullable();
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_detail_id','site_id'])->references(['id','site_id'])->on('supplier_details');
});
Schema::create('supplier_generic',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->boolean('active');
$table->integer('supplier_detail_id')->unsigned();
$table->string('product_id',16);
$table->string('product_desc',128)->nullable();
$table->float('base_cost');
$table->float('setup_cost')->nullable();
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_detail_id','site_id'])->references(['id','site_id'])->on('supplier_details');
});
Schema::create('supplier_voip',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->boolean('active');
$table->integer('supplier_detail_id')->unsigned();
$table->string('product_id',16);
$table->string('product_desc',128)->nullable();
$table->float('base_cost');
$table->float('setup_cost')->nullable();
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_detail_id','site_id'])->references(['id','site_id'])->on('supplier_details');
});
Schema::create('product_domain',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->integer('supplier_domain_id')->unsigned();
$table->string('name',64);
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_domain_id','site_id'])->references(['id','site_id'])->on('supplier_domain');
});
Schema::create('product_host',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->integer('supplier_host_id')->unsigned();
$table->string('name',64);
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_host_id','site_id'])->references(['id','site_id'])->on('supplier_host');
});
Schema::create('product_ssl',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->integer('supplier_ssl_id')->unsigned();
$table->string('name',64);
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_ssl_id','site_id'])->references(['id','site_id'])->on('supplier_ssl');
});
Schema::create('product_generic',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->integer('supplier_generic_id')->unsigned();
$table->string('name',64);
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_generic_id','site_id'])->references(['id','site_id'])->on('supplier_generic');
});
Schema::create('product_voip',function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->integer('site_id')->unsigned();
$table->integer('supplier_voip_id')->unsigned();
$table->string('name',64);
$table->integer('contract_term')->unsigned()->nullable();
$table->index(['id','site_id']);
$table->foreign(['site_id'])->references(['id'])->on('sites');
$table->foreign(['supplier_voip_id','site_id'])->references(['id','site_id'])->on('supplier_voip');
});
// Setup Domains
foreach (\Illuminate\Support\Facades\DB::select('SELECT * FROM ab_domain_tld') as $o) {
$oo = new \App\Models\TLD;
if ($o->date_orig)
$oo->created_at = \Carbon\Carbon::createFromTimestamp($o->date_orig);
if ($o->date_last)
$oo->created_at = \Carbon\Carbon::createFromTimestamp($o->date_last);
$oo->name = strtolower($o->name);
$oo->save();
};
foreach (\Illuminate\Support\Facades\DB::select('SELECT * FROM ab_domain_registrar') as $o) {
$so = \App\Models\Supplier::where('name',$o->name)->singleOrNew();
$so->name = $o->name;
$so->active = $so->active ?: $o->active;
$so->save();
$sdo = \App\Models\SupplierDetail::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)
->where('supplier_id',$so->id)
->where('site_id',1)
->firstOrNew();
$sdo->site_id = 1;
$connects = collect();
if ($o->whitelabel_url)
$connects->put('whitelabel_url',$o->whitelabel_url);
if ($o->manage_url)
$connects->put('manage_url',$o->manage_url);
$sdo->connections = $connects;
$so->detail()->save($sdo);
foreach (\App\Models\TLD::cursor() as $tldo) {
$sd = \App\Models\Supplier\Domain::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)
->where('tld_id',$tldo->id)
->where('site_id',$sdo->site_id)
->where('supplier_detail_id',$sdo->id)
->firstOrNew();
$sd->supplier_detail_id = $sdo->id;
$sd->tld_id = $tldo->id;
$sd->site_id = $sdo->site_id;
$sd->active = TRUE;
$sd->product_id = 'Domain Name';
$sd->product_desc = 'Domain Name License';
$sd->base_cost = '.01';
$sd->contract_term = 12;
$sd->save();
$pd = \App\Models\Product\Domain::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)
->where('site_id',$sdo->site_id)
->where('supplier_domain_id',$sd->id)
->firstOrNew();
$pd->supplier_domain_id = $sd->id;
$pd->site_id = $sd->site_id;
$pd->name = $sd->name;
$pd->save();
}
}
// SSL
$so = \App\Models\Supplier::where('name','Graytech Hosting Pty Ltd')->firstOrNew();
$so->name = 'Graytech Hosting Pty Ltd';
$so->active = TRUE;
$so->save();
$sdo = \App\Models\SupplierDetail::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)
->where('site_id','1')
->where('supplier_id',$so->id)
->firstOrNew();
$sdo->site_id = 1;
$so->detail()->save($sdo);
$o = new \App\Models\Supplier\SSL;
$o->site_id = $sdo->site_id;
$o->active = TRUE;
$o->product_id = 'Graytech SSL';
$o->base_cost = 0;
$o->setup_cost = 0;
$o->supplier_detail_id = $sdo->id;
$o->save();
$oo = new \App\Models\Product\SSL;
$oo->site_id = $sdo->site_id;
$oo->supplier_ssl_id = $o->id;
$oo->name = 'Graytech SSL';
$oo->save();
$o = new \App\Models\Supplier\Host;
$o->site_id = $sdo->site_id;
$o->active = TRUE;
$o->product_id = 'Graytech Hosting';
$o->base_cost = 0;
$o->setup_cost = 0;
$o->supplier_detail_id = $sdo->id;
$o->save();
$oo = new \App\Models\Product\Host;
$oo->site_id = $sdo->site_id;
$oo->supplier_host_id = $o->id;
$oo->name = 'Graytech Hosting';
$oo->save();
$so = \App\Models\Supplier::where('name','crazydomain')->firstOrFail();
$sdo = \App\Models\SupplierDetail::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)
->where('site_id','1')
->where('supplier_id',$so->id)
->firstOrNew();
$sdo->site_id = 1;
$so->detail()->save($sdo);
$o = new \App\Models\Supplier\Host;
$o->site_id = $sdo->site_id;
$o->active = TRUE;
$o->product_id = 'CD Host';
$o->base_cost = 0;
$o->supplier_detail_id = $sdo->id;
$o->save();
$oo = new \App\Models\Product\Host;
$oo->site_id = $sdo->site_id;
$oo->supplier_host_id = $o->id;
$oo->name = 'Crazy Domains Hosting';
$oo->save();
// VOIP
$so = \App\Models\Supplier::where('name','Exetel')->firstOrFail();
$sdo = \App\Models\SupplierDetail::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)
->where('site_id','1')
->where('supplier_id',$so->id)
->firstOrNew();
$sdo->site_id = 1;
$so->detail()->save($sdo);
$o = new \App\Models\Supplier\Voip;
$o->site_id = $sdo->site_id;
$o->active = TRUE;
$o->product_id = 'VOIP $10';
$o->base_cost = 9.09;
$o->setup_cost = 0;
$o->supplier_detail_id = $sdo->id;
$o->save();
$oo = new \App\Models\Product\Voip;
$oo->site_id = $sdo->site_id;
$oo->supplier_voip_id = $o->id;
$oo->name = 'VOIP $10';
$oo->save();
$o = new \App\Models\Supplier\Voip;
$o->site_id = $sdo->site_id;
$o->active = TRUE;
$o->product_id = 'VOIP';
$o->base_cost = 0;
$o->setup_cost = 0;
$o->supplier_detail_id = $sdo->id;
$o->save();
$oo = new \App\Models\Product\Voip;
$oo->site_id = $sdo->site_id;
$oo->supplier_voip_id = $o->id;
$oo->name = 'VOIP';
$oo->save();
$o = new \App\Models\Supplier\Voip;
$o->site_id = $sdo->site_id;
$o->active = TRUE;
$o->product_id = 'VOIP B-100';
$o->product_desc = 'VOIP Business 100 Lines';
$o->base_cost = 22.727;
$o->setup_cost = 0;
$o->supplier_detail_id = $sdo->id;
$o->save();
$oo = new \App\Models\Product\Voip;
$oo->site_id = $sdo->site_id;
$oo->supplier_voip_id = $o->id;
$oo->name = 'VOIP B-10';
$oo->save();
// Manually run this, since we havent worked out site_id when running migrate.
// update products set model_id=49,model='App\\Models\\Product\\Domain' where id=78;
}
/**
@ -290,6 +621,6 @@ class OptimizeProduct extends Migration
*/
public function down()
{
//abort(500,'Cant go back');
abort(500,'Cant go back');
}
}

View File

@ -0,0 +1,71 @@
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Number</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
</div>
<input type="text" class="form-control" name="broadband[service_number]" value="{{ $o->service_number ?? '' }}">
</div>
</div>
</div>
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Username</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="broadband[service_username]" value="{{ $o->service_username ?? '' }}">
</div>
</div>
</div>
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Password</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<input type="text" class="form-control" name="broadband[service_password]" value="{{ $o->service_password ?? '' }}">
</div>
</div>
</div>
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Connect Date</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="date" class="form-control" name="broadband[service_connect_date]" value="{{ $o->service_connect_date ? $o->service_connect_date->format('Y-m-d') : '' }}">
</div>
</div>
</div>
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Contract Date</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="date" class="form-control" name="broadband[service_contract_date]" value="{{ $o->service_contract_date ? $o->service_contract_date->format('Y-m-d') : '' }}">
</div>
</div>
</div>
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Billing Start Date</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="date" class="form-control" name="date_start" value="{{ $o->service->date_start ? $o->service->date_start->format('Y-m-d') : '' }}">
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
<!-- $o = Supplier::class -->
<div class="row">
<div class="col-5 col-sm-3">
<div class="col-5 col-sm-2">
<div class="nav flex-column nav-tabs h-100" role="tablist" aria-orientation="vertical">
@foreach($o->offeringTypes() as $key => $offering)
<a class="nav-link @if($loop->first)active @endif" id="offering-{{ $key }}-tab" data-toggle="pill" href="#offering-{{ $key }}-profile" role="tab" aria-controls="offering-{{ $key }}-tab" aria-selected="true">{{ $offering->type }}</a>
@ -8,7 +8,7 @@
</div>
</div>
<div class="col-7 col-sm-9">
<div class="col-7 col-sm-10">
<div class="tab-content">
@foreach($o->offeringTypes() as $key => $offering)
<div class="tab-pane text-left fade show @if($loop->first)active @endif" id="offering-{{ $key }}-profile" role="tabpanel" aria-labelledby="offering-{{ $key }}-tab">

View File

@ -1,6 +1,6 @@
<!-- $o = Supplier::class -->
<div class="row">
<div class="col-5 col-sm-3">
<div class="col-5 col-sm-2">
<div class="nav flex-column nav-tabs h-100" role="tablist" aria-orientation="vertical">
@foreach($o->offeringTypes() as $key => $offering)
<a class="nav-link @if($loop->first)active @endif" id="products-{{ $key }}-tab" data-toggle="pill" href="#products-{{ $key }}-profile" role="tab" aria-controls="products-{{ $key }}-tab" aria-selected="true">{{ $offering->type }}</a>
@ -8,7 +8,7 @@
</div>
</div>
<div class="col-7 col-sm-9">
<div class="col-7 col-sm-10">
<div class="tab-content">
@foreach($o->offeringTypes() as $key => $offering)
<div class="tab-pane text-left fade show @if($loop->first)active @endif" id="products-{{ $key }}-profile" role="tabpanel" aria-labelledby="products-{{ $key }}-tab">

View File

@ -1,35 +0,0 @@
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Number</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
</div>
<input type="text" class="form-control" name="broadband[service_number]" value="{{ $o->service_number ?? '' }}">
</div>
</div>
</div>
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Username</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="broadband[service_username]" value="{{ $o->service_username ?? '' }}">
</div>
</div>
</div>
<div class="form-group row">
<label for="reference" class="col-sm-3 col-form-label text-right">Service Password</label>
<div class="col-sm-6">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<input type="text" class="form-control" name="broadband[service_password]" value="{{ $o->service_password ?? '' }}">
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
<!-- $o = Product::class -->
<div class="col-md-12">
<p>{!! $o->description !!}</p>
<p>{!! $o->name_long !!}</p>
</div>
<table class="table table-condensed">

View File

@ -1,6 +1,6 @@
<!-- $o = Product::class -->
<div class="col-md-12">
<p>{!! $o->description !!}</p>
<p>{!! $o->name_long !!}</p>
</div>
<table class="table table-condensed">

View File

@ -57,7 +57,7 @@ Route::group(['middleware'=>['theme:adminlte-be','auth','role:wholesaler'],'pref
Route::match(['get','post'],'payment/addedit/{o?}',[AdminController::class,'pay_addedit']);
Route::get('payment/unapplied',[AdminController::class,'pay_unapplied']);
Route::post('service/edit/{o}',[ServiceController::class,'domain_edit'])
Route::post('service/edit/{o}',[ServiceController::class,'update'])
->where('o','[0-9]+')
->middleware('can:update,o');
//Route::get('accounting/connect','AccountingController@connect');