More work on ordering
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
}
|
@@ -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
30
app/Models/AdslPlan.php
Normal 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');
|
||||
}
|
||||
}
|
15
app/Models/AdslSupplierPlan.php
Normal file
15
app/Models/AdslSupplierPlan.php
Normal 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
35
app/Models/PlanVoip.php
Normal 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;
|
||||
}
|
@@ -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'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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()
|
||||
{
|
||||
|
@@ -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()
|
||||
{
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
24
app/Traits/NextKey.php
Normal 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;
|
||||
}
|
||||
}
|
50
app/Traits/OrderServiceOptions.php
Normal file
50
app/Traits/OrderServiceOptions.php
Normal 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;
|
||||
}
|
||||
}
|
48
app/User.php
48
app/User.php
@@ -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));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user