More work on ordering

This commit is contained in:
Deon George
2018-08-11 15:09:41 +10:00
parent 499d44289e
commit 5373e6b246
33 changed files with 730 additions and 163 deletions

View File

@@ -3,9 +3,13 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Product;
use Igaster\LaravelTheme\Facades\Theme;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Database\Eloquent\Model;
use App\Models\{Product,Service};
use App\User;
class OrderController extends Controller
{
@@ -30,5 +34,50 @@ class OrderController extends Controller
public function submit(Request $request)
{
Validator::make($request->all(),[
'product_id'=>'required|exists:ab_product,id',
])
->sometimes('order_email','required|email',function($input) use ($request) {
return ($input->order_email AND ! $input->order_email_manual) OR (! $input->order_email_manual);
})
->sometimes('order_email_manual','required|email',function($input) use ($request) {
return $input->order_email_manual AND ! $input->order_email;
})->validate();
// Check the plugin details.
$po = Product::findOrFail($request->post('product_id'));
// Check we have the custom attributes for the product
$options = $po->orderValidation($request);
$uo = User::where('email','=',$request->post('order_email') ?: $request->post('order_email_manual'))->firstOrFail();
$ao = $request->input('account_id')
? $uo->accounts->where('account_id',$request->input('account_id'))
: $uo->accounts->first();
$so = new Service;
$so->id = Service::NextId();
// @todo Make this automatic
$so->site_id = config('SITE_SETUP')->id;
$so->product_id = $request->post('product_id');
$so->order_status = 'ORDER-SUBMIT';
$so->orderby_id = Auth::user()->id;
if ($options->order_info)
{
$so->order_info = $options->order_info;
unset($options->order_info);
}
$so = $ao->services()->save($so);
if ($options instanceOf Model) {
$options->service_id = $so->id;
$options->save();
}
return view('order_received',['o'=>$so]);
}
}

View File

@@ -20,4 +20,9 @@ class ResellerServicesController extends Controller
{
return ['data'=>Auth::user()->all_clients()->values()];
}
public function service_movements()
{
return ['data'=>Auth::user()->all_client_service_movements()->values()];
}
}

30
app/Models/AdslPlan.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\OrderServiceOptions;
class AdslPlan extends Model
{
use OrderServiceOptions;
protected $table = 'ab_adsl_plan';
protected $order_attributes = [
'options.address'=>[
'request'=>'options.address',
'key'=>'service_address',
'validation'=>'required|string:10',
'validation_message'=>'Address is a required field.',
],
];
protected $order_model = ServiceAdsl::class;
public function product()
{
return $this->hasOne(AdslSupplierPlan::class,'id','adsl_supplier_plan_id');
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class AdslSupplierPlan extends Model
{
protected $table = 'ab_adsl_supplier_plan';
public function getNameAttribute()
{
return $this->speed;
}
}

35
app/Models/PlanVoip.php Normal file
View File

@@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\OrderServiceOptions;
class PlanVoip extends Model
{
use OrderServiceOptions;
protected $order_attributes = [
'options.phonenumber'=>[
'request'=>'options.phonenumber',
'key'=>'service_number',
'validation'=>'required|min:10',
'validation_message'=>'Phone Number is a required field.',
],
'options.supplier'=>[
'request'=>'options.supplier',
'key'=>'order_info.supplier',
'validation'=>'required|min:4',
'validation_message'=>'Phone Supplier is a required field.',
],
'options.supplieraccnum'=>[
'request'=>'options.supplieraccnum',
'key'=>'order_info.supplieraccnum',
'validation'=>'required|min:4',
'validation_message'=>'Phone Supplier Account Number is a required field.',
],
];
protected $order_model = ServiceVoip::class;
}

View File

@@ -4,6 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
class Product extends Model
{
@@ -25,22 +26,93 @@ class Product extends Model
return $this->prod_plugin_file;
}
public function getContractTermAttribute()
{
switch ($this->prod_plugin_file) {
case 'ADSL': return $this->plugin()->contract_term;
// @todo Incorporate into DB
case 'VOIP': return 12;
// @todo Change this after contracts implemented.
default:
return 'TBA';
}
}
public function getDefaultBillingAttribute()
{
return array_get($this->PricePeriods(),$this->price_recurr_default);
}
public function getDefaultCostAttribute()
{
// @todo Integrate this into a Tax::class
return array_get($this->price_array,sprintf('%s.1.price_base',$this->price_recurr_default))*1.1;
}
private function getDefaultLanguage()
{
return config('SITE_SETUP')->language;
}
public function getDescriptionAttribute()
{
// @todo If the user has selected a specific language.
return $this->description($this->getDefaultLanguage());
}
public function getMinimumCostAttribute()
{
$table = [
0=>4,
1=>1,
2=>1/3,
3=>1/6,
4=>1/12,
5=>1/24,
6=>1/36,
7=>1/48,
8=>1/60,
];
return $this->setup_cost + ( $this->default_cost * array_get($table,$this->price_recurr_default) * $this->contract_term);
}
public function getNameAttribute()
{
return $this->name(Auth::user()->language);
}
public function getProductTypeAttribute()
{
return $this->plugin()->product->name;
}
public function getPriceArrayAttribute()
{
return unserialize($this->price_group);
}
public function getPriceTypeAttribute()
{
$table = [
0=>_('One-time Charge'),
1=>_('Recurring Membership/Subscription'),
2=>_('Trial for Membership/Subscription'),
];
}
public function getProductIdAttribute()
{
return sprintf('#%04s',$this->id);
}
public function getSetupCostAttribute()
{
// @todo Integrate this into a Tax::class
return array_get($this->price_array,sprintf('%s.1.price_setup',$this->price_recurr_default))*1.1;
}
public function scopeActive()
{
return $this->where('active',TRUE);
@@ -54,9 +126,34 @@ class Product extends Model
return $this->descriptions->where('language_id',$lo->id)->first()->description_short;
}
private function getDefaultLanguage()
public function orderValidation(Request $request)
{
return config('SITE_SETUP')->language;
return $this->plugin()->orderValidation($request);
}
private function plugin()
{
switch ($this->prod_plugin_file) {
case 'ADSL':
return AdslPlan::findOrFail($this->prod_plugin_data);
case 'VOIP':
return new PlanVoip;
}
}
public function PricePeriods()
{
return [
0=>_('Weekly'),
1=>_('Monthly'),
2=>_('Quarterly'),
3=>_('Semi-Annually'),
4=>_('Annually'),
5=>_('Two years'),
6=>_('Three Years'),
7=>_('Four Years'),
8=>_('Five Years'),
];
}
/**

View File

@@ -3,14 +3,25 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\NextKey;
class Service extends Model
{
use NextKey;
protected $table = 'ab_service';
protected $with = ['product.descriptions','account.language','service_adsl','service_domain.tld','service_ssl','service_voip'];
protected $dates = ['date_last_invoice','date_next_invoice'];
protected $casts = [
'order_info'=>'array',
];
public $incrementing = FALSE;
const CREATED_AT = 'date_orig';
const UPDATED_AT = 'date_last';
protected $appends = [
'account_name',
'category',
'name',
'next_invoice',
@@ -19,7 +30,9 @@ class Service extends Model
'service_id_url',
'status',
];
protected $visible = [
'account_name',
'active',
'category',
'data_orig',
@@ -32,6 +45,10 @@ class Service extends Model
'status',
];
private $inactive_status = [
'CANCELLED',
];
public function account()
{
return $this->belongsTo(Account::class);
@@ -70,9 +87,16 @@ class Service extends Model
/**
* Only query active categories
*/
public function scopeActive()
public function scopeActive($query)
{
return $this->where('active',TRUE);
return $query->where(function () use ($query) {
return $query->where('active',TRUE)->orWhereNotIn('order_status',$this->inactive_status);
});
}
public function getAccountNameAttribute()
{
return $this->account->company;
}
public function getCategoryAttribute()
@@ -82,10 +106,10 @@ class Service extends Model
public function getNameAttribute()
{
if (! isset($this->getServiceDetail()->name))
if (! isset($this->ServicePlugin()->name))
return 'Unknown';
return $this->getServiceDetail()->name;
return $this->ServicePlugin()->name;
}
public function getNextInvoiceAttribute()
@@ -98,28 +122,6 @@ class Service extends Model
return $this->product->name($this->account->language);
}
/**
* This function will return the associated service model for the product type
*/
public function getServiceDetail()
{
switch ($this->product->prod_plugin_file)
{
case 'ADSL': return $this->service_adsl;
case 'DOMAIN': return $this->service_domain;
case 'HOST': return $this->service_host;
case 'SSL': return $this->service_ssl;
case 'VOIP': return $this->service_voip;
default: return NULL;
}
}
public function getStatusAttribute()
{
return $this->active ? 'Active' : 'Inactive';
}
public function getServiceExpireAttribute()
{
return 'TBA';
@@ -139,4 +141,41 @@ class Service extends Model
{
return sprintf('%02s.%04s.%04s',$this->site_id,$this->account_id,$this->id);
}
public function getStatusAttribute()
{
return $this->order_status ? $this->order_status : ( $this->active ? 'Active' : 'Inactive');
}
public function setDateOrigAttribute($value)
{
$this->attributes['date_orig'] = $value->timestamp;
}
public function setDateLastAttribute($value)
{
$this->attributes['date_last'] = $value->timestamp;
}
public function isActive()
{
return $this->active OR ($this->order_status AND ! in_array($this->order_status,$this->inactive_status));
}
/**
* This function will return the associated service model for the product type
*/
private function ServicePlugin()
{
switch ($this->product->prod_plugin_file)
{
case 'ADSL': return $this->service_adsl;
case 'DOMAIN': return $this->service_domain;
case 'HOST': return $this->service_host;
case 'SSL': return $this->service_ssl;
case 'VOIP': return $this->service_voip;
default: return NULL;
}
}
}

View File

@@ -3,13 +3,17 @@
namespace App\Models;
use App\Models\Service_Model as Model;
use App\Traits\NextKey;
class ServiceAdsl extends Model
{
use NextKey;
protected $table = 'ab_service__adsl';
public $timestamps = FALSE;
public function getNameAttribute()
{
return $this->service_number;
return $this->service_number ?: $this->service_address;
}
}

View File

@@ -3,10 +3,14 @@
namespace App\Models;
use App\Models\Service_Model as Model;
use App\Traits\NextKey;
class ServiceDomain extends Model
{
use NextKey;
protected $table = 'ab_service__domain';
public $timestamps = FALSE;
public function tld()
{

View File

@@ -3,10 +3,14 @@
namespace App\Models;
use App\Models\Service_Model as Model;
use App\Traits\NextKey;
class ServiceHost extends Model
{
use NextKey;
protected $table = 'ab_service__hosting';
public $timestamps = FALSE;
public function getNameAttribute()
{

View File

@@ -3,10 +3,13 @@
namespace App\Models;
use App\Models\Service_Model as Model;
use App\Traits\NextKey;
use App\Classes\SSL;
class ServiceSsl extends Model
{
use NextKey;
protected $table = 'ab_service__ssl';
protected $_o = NULL;

View File

@@ -3,10 +3,13 @@
namespace App\Models;
use App\Models\Service_Model as Model;
use App\Traits\NextKey;
class ServiceVoip extends Model
{
use NextKey;
protected $table = 'ab_service__voip';
public $timestamps = FALSE;
public function getNameAttribute()
{

24
app/Traits/NextKey.php Normal file
View File

@@ -0,0 +1,24 @@
<?php
/**
* Works out the next ID to use for an Eloquent Table.
*/
namespace App\Traits;
trait NextKey
{
public static function boot()
{
parent::boot();
static::creating(function($model)
{
$model->id = self::NextId();
});
}
public static function NextId()
{
return (new self)->max('id')+1;
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* Creates and returns the Service Options Model for an Order.
*/
namespace App\Traits;
use Illuminate\Http\Request;
trait OrderServiceOptions
{
/*
protected $order_attributes = [
'options.input'=>[
'request'=>'options.input',
'key'=>'column',
'validation'=>'required|string:10',
'validation_message'=>'It is a required field.',
],
];
protected $order_model = NULL;
*/
public function orderValidation(Request $request)
{
if (! isset($this->order_attributes))
return NULL;
$request->validate(collect($this->order_attributes)->pluck('validation','request')->toArray());
if (! isset($this->order_model))
return NULL;
$o = new $this->order_model;
$x = [];
foreach ($this->order_attributes as $k => $v)
{
$x[$v['key']] = $request->input($k);
}
$o->forceFill(array_undot($x));
// @todo Make this automatic
$o->site_id = config('SITE_SETUP')->id;
return $o;
}
}

View File

@@ -9,6 +9,7 @@ use Laravel\Passport\HasApiTokens;
use Leenooks\Carbon;
use Leenooks\Traits\UserSwitch;
use App\Notifications\ResetPasswordNotification;
use App\Models\Service;
class User extends Authenticatable
{
@@ -159,8 +160,9 @@ class User extends Authenticatable
public function getServicesActiveAttribute()
{
return $this->services
->where('active',TRUE);
return $this->services->filter(function($item) {
return $item->isActive();
});
}
public function getServicesCountHtmlAttribute()
@@ -188,6 +190,11 @@ class User extends Authenticatable
return sprintf('<a href="/u/account/view/%s">%s</a>',$this->id,$this->user_id);
}
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
/** Scopes **/
public function scopeActive()
@@ -195,6 +202,17 @@ class User extends Authenticatable
return $this->where('active',TRUE);
}
/**
* Determine if the user is an admin of the account with $id
*
* @param $id
* @return bool
*/
public function isAdmin($id)
{
return $id AND $this->isReseller() AND in_array($id,$this->all_accounts()->pluck('id')->toArray());
}
/** Functions */
public function all_accounts()
@@ -208,7 +226,6 @@ class User extends Authenticatable
return $result->flatten();
}
public function all_clients($level=0)
{
$result = collect();
@@ -229,6 +246,16 @@ class User extends Authenticatable
return $result->flatten();
}
public function all_client_service_movements()
{
$s = Service::active()->where('order_status','!=','ACTIVE');
$aa = $this->all_accounts()->pluck('id')->unique()->toArray();
return $s->get()->filter(function($item) use ($aa) {
return in_array($item->account_id,$aa);
});
}
// List all the agents, including agents of agents
public function all_agents($level=0)
{
@@ -250,17 +277,6 @@ class User extends Authenticatable
return $result->flatten();
}
/**
* Determine if the user is an admin of the account with $id
*
* @param $id
* @return bool
*/
public function isAdmin($id)
{
return $id AND $this->isReseller() AND in_array($id,$this->all_accounts()->pluck('id')->toArray());
}
/**
* Determine if the logged in user is a reseller or wholesaler
*
@@ -285,8 +301,4 @@ class User extends Authenticatable
elseif (! $this->all_agents()->count() AND ! $this->all_clients()->count())
return 'customer';
}
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
}