Account next invoice, and authorisations
This commit is contained in:
@@ -60,9 +60,11 @@ class Account extends Model
|
||||
return $this->hasMany(Payment::class);
|
||||
}
|
||||
|
||||
public function services()
|
||||
public function services($active=FALSE)
|
||||
{
|
||||
return $this->hasMany(Service::class);
|
||||
$query = $this->hasMany(Service::class);
|
||||
|
||||
return $active ? $query->where('active','=',TRUE) : $query;
|
||||
}
|
||||
|
||||
public function user()
|
||||
@@ -150,7 +152,7 @@ class Account extends Model
|
||||
|
||||
public function getServicesCountHtmlAttribute()
|
||||
{
|
||||
return sprintf('%s <small>/%s</small>',$this->services->where('active',TRUE)->count(),$this->services->count());
|
||||
return sprintf('%s <small>/%s</small>',$this->services()->noEagerLoads()->where('active',TRUE)->count(),$this->services()->noEagerLoads()->count());
|
||||
}
|
||||
|
||||
public function getSwitchUrlAttribute()
|
||||
|
@@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class Charge extends Model
|
||||
{
|
||||
protected $table = 'ab_charge';
|
||||
protected $dates = ['date_charge'];
|
||||
public $dateFormat = 'U';
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
|
@@ -17,6 +17,11 @@ class Country extends Model
|
||||
return $this->belongsTo(Currency::class);
|
||||
}
|
||||
|
||||
public function taxes()
|
||||
{
|
||||
return $this->hasMany(Tax::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* The accounts in this country
|
||||
*/
|
||||
|
@@ -143,6 +143,8 @@ class Invoice extends Model
|
||||
{
|
||||
$return = collect();
|
||||
|
||||
$this->items->load(['service']);
|
||||
|
||||
foreach ($this->items->filter(function ($item) use ($po) {
|
||||
return $item->product_id == $po->id;
|
||||
}) as $o)
|
||||
|
@@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class InvoiceItem extends Model
|
||||
{
|
||||
protected $dates = ['date_start','date_stop'];
|
||||
public $dateFormat = 'U';
|
||||
protected $table = 'ab_invoice_item';
|
||||
protected $with = ['taxes'];
|
||||
|
||||
@@ -32,6 +33,8 @@ class InvoiceItem extends Model
|
||||
return $this->hasMany(InvoiceItemTax::class);
|
||||
}
|
||||
|
||||
/** ATTRIBUTES **/
|
||||
|
||||
public function getItemTypeNameAttribute()
|
||||
{
|
||||
$types = [
|
||||
@@ -69,22 +72,10 @@ class InvoiceItem extends Model
|
||||
}
|
||||
}
|
||||
|
||||
public function module_text()
|
||||
{
|
||||
switch ($this->module_id)
|
||||
{
|
||||
// Charges Module
|
||||
case 30: return Charge::findOrFail($this->module_ref)->name;
|
||||
|
||||
default: abort(500,'Unable to handle '.$this->module_id);
|
||||
}
|
||||
|
||||
}
|
||||
public function getSubTotalAttribute()
|
||||
{
|
||||
return $this->quantity * $this->price_base;
|
||||
}
|
||||
|
||||
public function getTaxAttribute()
|
||||
{
|
||||
if (! $this->_tax)
|
||||
@@ -102,4 +93,36 @@ class InvoiceItem extends Model
|
||||
{
|
||||
return $this->tax + $this->sub_total;
|
||||
}
|
||||
|
||||
/** FUNCTIONS **/
|
||||
|
||||
/**
|
||||
* Add taxes to this record
|
||||
*/
|
||||
public function addTaxes()
|
||||
{
|
||||
// Refuse to change an existing record
|
||||
if ($this->exists)
|
||||
throw new \Exception('Refusing to add Taxes to existing record');
|
||||
|
||||
foreach($this->service->account->country->taxes as $to)
|
||||
{
|
||||
$iit = new InvoiceItemTax;
|
||||
$iit->tax_id = $to->id;
|
||||
$iit->amount = round($this->quantity*$this->price_base*$to->rate,3);
|
||||
$this->taxes->push($iit);
|
||||
}
|
||||
}
|
||||
|
||||
public function module_text()
|
||||
{
|
||||
switch ($this->module_id)
|
||||
{
|
||||
// Charges Module
|
||||
case 30: return Charge::findOrFail($this->module_ref)->name;
|
||||
|
||||
default: abort(500,'Unable to handle '.$this->module_id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
91
app/Models/Policies/AccountPolicy.php
Normal file
91
app/Models/Policies/AccountPolicy.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Policies;
|
||||
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\User;
|
||||
|
||||
class AccountPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Account $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function view(User $user, Account $o)
|
||||
{
|
||||
// If this is a service for an account managed by a user.
|
||||
return ($user->accounts->pluck('id')->search($o->id))
|
||||
|
||||
// The user is the wholesaler
|
||||
OR $user->isWholesaler()
|
||||
|
||||
// The user is the reseller
|
||||
OR $user->all_accounts()->pluck('id')->search($o->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create services.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function create(User $user)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Account $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(User $user, Account $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Account $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete(User $user, Account $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Account $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function restore(User $user, Account $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Account $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function forceDelete(User $user, Account $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
}
|
91
app/Models/Policies/InvoicePolicy.php
Normal file
91
app/Models/Policies/InvoicePolicy.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Policies;
|
||||
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\User;
|
||||
|
||||
class InvoicePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Invoice $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function view(User $user, Invoice $o)
|
||||
{
|
||||
// If this is a service for an account managed by a user.
|
||||
return ($user->invoices->pluck('id')->search($o->id))
|
||||
|
||||
// The user is the wholesaler
|
||||
OR $user->isWholesaler()
|
||||
|
||||
// The user is the reseller
|
||||
OR $user->all_accounts()->pluck('id')->search($o->account_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create services.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function create(User $user)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Invoice $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(User $user, Invoice $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Invoice $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete(User $user, Invoice $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Invoice $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function restore(User $user, Invoice $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Invoice $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function forceDelete(User $user, Invoice $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
}
|
91
app/Models/Policies/ServicePolicy.php
Normal file
91
app/Models/Policies/ServicePolicy.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Policies;
|
||||
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
use App\Models\Service;
|
||||
use App\User;
|
||||
|
||||
class ServicePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Service $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function view(User $user, Service $o)
|
||||
{
|
||||
// If this is a service for an account managed by a user.
|
||||
return ($user->services->pluck('id')->search($o->id))
|
||||
|
||||
// The user is the wholesaler
|
||||
OR $user->isWholesaler()
|
||||
|
||||
// The user is the reseller
|
||||
OR $user->all_accounts()->pluck('id')->search($o->account_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create services.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function create(User $user)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Service $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(User $user, Service $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Service $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete(User $user, Service $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Service $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function restore(User $user, Service $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the service.
|
||||
*
|
||||
* @param \App\User $user
|
||||
* @param Service $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function forceDelete(User $user, Service $o)
|
||||
{
|
||||
return $user->isWholesaler();
|
||||
}
|
||||
}
|
@@ -79,7 +79,7 @@ class Product extends Model
|
||||
|
||||
private function getDefaultLanguage()
|
||||
{
|
||||
return config('SITE_SETUP')->language();
|
||||
return config('SITE_SETUP')->language;
|
||||
}
|
||||
|
||||
public function getDescriptionAttribute()
|
||||
@@ -179,9 +179,21 @@ class Product extends Model
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the price for this product based on the period being requested.
|
||||
*
|
||||
* If the price period doesnt exist, we'll take the default period (0) which should.
|
||||
*
|
||||
* @param int $period
|
||||
* @return mixed
|
||||
*/
|
||||
public function price(int $period)
|
||||
{
|
||||
return Arr::get($this->price_array,sprintf('%s.1.price_base',$period));
|
||||
return Arr::get(
|
||||
$this->price_array,
|
||||
sprintf('%s.1.price_base',$period),
|
||||
Arr::get($this->price_array,sprintf('%s.0.price_base',$period))
|
||||
);
|
||||
}
|
||||
|
||||
public function PricePeriods()
|
||||
|
@@ -30,6 +30,7 @@ class Service extends Model
|
||||
protected $appends = [
|
||||
'account_name',
|
||||
'admin_service_id_url',
|
||||
'billing_price',
|
||||
'name_short',
|
||||
'next_invoice',
|
||||
'product_category',
|
||||
@@ -43,6 +44,7 @@ class Service extends Model
|
||||
'account_name',
|
||||
'admin_service_id_url',
|
||||
'active',
|
||||
'billing_price',
|
||||
'data_orig',
|
||||
'id',
|
||||
'name_short',
|
||||
@@ -207,6 +209,16 @@ class Service extends Model
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable to perform queries without eager loading
|
||||
*
|
||||
* @param $query
|
||||
* @return mixed
|
||||
*/
|
||||
public function scopeNoEagerLoads($query){
|
||||
return $query->setEagerLoads([]);
|
||||
}
|
||||
|
||||
/** ATTRIBUTES **/
|
||||
|
||||
/**
|
||||
@@ -229,7 +241,11 @@ class Service extends Model
|
||||
|
||||
public function getBillingPriceAttribute(): float
|
||||
{
|
||||
return $this->addTax($this->price ?: $this->product->price($this->recur_schedule));
|
||||
// @todo Temporary for services that dont have recur_schedule set.
|
||||
if (is_null($this->recur_schedule) OR is_null($this->product->price($this->recur_schedule)))
|
||||
$this->price=0;
|
||||
|
||||
return $this->addTax(is_null($this->price) ? $this->product->price($this->recur_schedule) : $this->price);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,7 +497,7 @@ class Service extends Model
|
||||
* @param float $value
|
||||
* @return float
|
||||
*/
|
||||
public function addTax(float $value): float
|
||||
private function addTax(float $value): float
|
||||
{
|
||||
return round($value*1.1,2);
|
||||
}
|
||||
@@ -506,23 +522,51 @@ class Service extends Model
|
||||
return $this->active OR ($this->order_status AND ! in_array($this->order_status,$this->inactive_status));
|
||||
}
|
||||
|
||||
public function next_invoice_items()
|
||||
/**
|
||||
* Should this service be invoiced soon
|
||||
*
|
||||
* @todo get the number of days from account setup
|
||||
* @return bool
|
||||
*/
|
||||
public function isInvoiceDueSoon($days=30): bool
|
||||
{
|
||||
return (! $this->external_billing) AND (! $this->suspend_billing) AND $this->getInvoiceNextAttribute()->lessThan(now()->addDays($days));
|
||||
}
|
||||
|
||||
public function next_invoice_items(): \Illuminate\Support\Collection
|
||||
{
|
||||
$result = collect();
|
||||
|
||||
$result->push([
|
||||
'item'=>0,
|
||||
'desc'=>sprintf('Product/Service [%s->%s]',
|
||||
$this->invoice_next->format('Y-m-d'),
|
||||
$this->invoice_next_end->format('Y-m-d')),
|
||||
'amt'=>$this->getBillingPriceAttribute()]);
|
||||
$o = new InvoiceItem;
|
||||
$o->active = TRUE;
|
||||
$o->service_id = $this->id;
|
||||
$o->product_id = $this->product_id;
|
||||
$o->quantity = 1;
|
||||
$o->item_type = 0;
|
||||
$o->price_base = $this->price ?: $this->product->price($this->recur_schedule); // @todo change to a method in this class
|
||||
$o->recurring_schedule = $this->recur_schedule;
|
||||
$o->date_start = $this->invoice_next;
|
||||
$o->date_stop = $this->invoice_next_end;
|
||||
|
||||
foreach ($this->charges->filter(function($item) { return ! $item->processed; }) as $o)
|
||||
$o->addTaxes();
|
||||
$result->push($o);
|
||||
|
||||
foreach ($this->charges->filter(function($item) { return ! $item->processed; }) as $oo)
|
||||
{
|
||||
$result->push([
|
||||
'item'=>5, // @tod Charges
|
||||
'desc'=>sprintf('%d@%3.2f - %s',$o->quantity,$this->addTax($o->amount),$o->name),
|
||||
'amt'=>$this->addTax($o->amount*$o->quantity)]);
|
||||
$o = new InvoiceItem;
|
||||
$o->active = TRUE;
|
||||
$o->service_id = $oo->service_id;
|
||||
$o->product_id = $this->product_id;
|
||||
$o->quantity = $oo->quantity;
|
||||
$o->item_type = $oo->type;
|
||||
$o->price_base = $oo->amount;
|
||||
$o->date_start = $oo->date_charge;
|
||||
$o->date_stop = $oo->date_charge;
|
||||
$o->module_id = 30; // @todo This shouldnt be hard coded
|
||||
$o->module_ref = $oo->id;
|
||||
|
||||
$o->addTaxes();
|
||||
$result->push($o);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@@ -10,7 +10,7 @@ class Site extends Model
|
||||
protected $table = 'ab_setup';
|
||||
public $timestamps = FALSE;
|
||||
|
||||
protected $with = ['details'];
|
||||
protected $with = ['details','language'];
|
||||
|
||||
protected $casts = [
|
||||
'address'=>'array',
|
||||
@@ -23,9 +23,6 @@ class Site extends Model
|
||||
|
||||
public function language()
|
||||
{
|
||||
if (! $this->id)
|
||||
return Language::find(1);
|
||||
|
||||
return $this->belongsTo(Language::class);
|
||||
}
|
||||
|
||||
@@ -151,6 +148,7 @@ class Site extends Model
|
||||
],
|
||||
],
|
||||
'clients_intro'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore',
|
||||
'language_id'=>1,
|
||||
'page_tabs'=>[
|
||||
[
|
||||
'title'=>'Title 1',
|
||||
|
12
app/Models/Tax.php
Normal file
12
app/Models/Tax.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Tax extends Model
|
||||
{
|
||||
protected $table = 'ab_tax';
|
||||
const CREATED_AT = 'date_orig';
|
||||
const UPDATED_AT = 'date_last';
|
||||
}
|
Reference in New Issue
Block a user