Account next invoice, and authorisations
This commit is contained in:
parent
59a8ef2476
commit
21ea60c4f9
@ -1,7 +1,7 @@
|
|||||||
# This file is a template, and might need editing before it works on your project.
|
# This file is a template, and might need editing before it works on your project.
|
||||||
# Official framework image. Look for the different tagged releases at:
|
# Official framework image. Look for the different tagged releases at:
|
||||||
# https://hub.docker.com/r/library/php
|
# https://hub.docker.com/r/library/php
|
||||||
image: registry.leenooks.net/leenooks/php:7.2-fpm-plus
|
image: registry.leenooks.net/leenooks/php:7.3-fpm-plus
|
||||||
|
|
||||||
# Pick zero or more services to be used on all builds.
|
# Pick zero or more services to be used on all builds.
|
||||||
# Only needed when using a docker container to run your tests in.
|
# Only needed when using a docker container to run your tests in.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Exceptions;
|
namespace App\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
@ -46,6 +47,10 @@ class Handler extends ExceptionHandler
|
|||||||
*/
|
*/
|
||||||
public function render($request, Exception $exception)
|
public function render($request, Exception $exception)
|
||||||
{
|
{
|
||||||
|
// We'll render a 404 for any authorisation exceptions to hide the fact that the resource exists
|
||||||
|
if ($exception instanceof AuthorizationException)
|
||||||
|
abort(404,'Not here...');
|
||||||
|
|
||||||
return parent::render($request, $exception);
|
return parent::render($request, $exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
app/Http/Controllers/User/AccountController.php
Normal file
43
app/Http/Controllers/User/AccountController.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\User;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\{Account,Invoice};
|
||||||
|
|
||||||
|
class AccountController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Show the users next invoice
|
||||||
|
*/
|
||||||
|
public function view_invoice_next(Account $o)
|
||||||
|
{
|
||||||
|
$io = new Invoice;
|
||||||
|
$io->account = $o;
|
||||||
|
|
||||||
|
// Get the account services
|
||||||
|
$s = $o->services(TRUE)
|
||||||
|
->with(['invoice_items','charges'])
|
||||||
|
->get()
|
||||||
|
->filter(function($item) {
|
||||||
|
return ! $item->suspend_billing AND ! $item->external_billing;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get our invoice due date for this invoice
|
||||||
|
$io->due_date = $s->min(function($item) { return $item->invoice_next; });
|
||||||
|
|
||||||
|
// @todo The days in advance is an application parameter
|
||||||
|
$io->date_orig = $io->due_date->subDays(30);
|
||||||
|
|
||||||
|
// Work out items to add to this invoice, plus any in the next additional days
|
||||||
|
$days = now()->diffInDays($io->due_date)+1+7;
|
||||||
|
foreach ($s as $so)
|
||||||
|
{
|
||||||
|
if ($so->isInvoiceDueSoon($days))
|
||||||
|
foreach ($so->next_invoice_items() as $o)
|
||||||
|
$io->items->push($o);
|
||||||
|
}
|
||||||
|
|
||||||
|
return View('u.invoice',['o'=>$io]);
|
||||||
|
}
|
||||||
|
}
|
@ -60,9 +60,11 @@ class Account extends Model
|
|||||||
return $this->hasMany(Payment::class);
|
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()
|
public function user()
|
||||||
@ -150,7 +152,7 @@ class Account extends Model
|
|||||||
|
|
||||||
public function getServicesCountHtmlAttribute()
|
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()
|
public function getSwitchUrlAttribute()
|
||||||
|
@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
class Charge extends Model
|
class Charge extends Model
|
||||||
{
|
{
|
||||||
protected $table = 'ab_charge';
|
protected $table = 'ab_charge';
|
||||||
|
protected $dates = ['date_charge'];
|
||||||
|
public $dateFormat = 'U';
|
||||||
|
|
||||||
public function getNameAttribute()
|
public function getNameAttribute()
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,11 @@ class Country extends Model
|
|||||||
return $this->belongsTo(Currency::class);
|
return $this->belongsTo(Currency::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function taxes()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Tax::class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The accounts in this country
|
* The accounts in this country
|
||||||
*/
|
*/
|
||||||
|
@ -143,6 +143,8 @@ class Invoice extends Model
|
|||||||
{
|
{
|
||||||
$return = collect();
|
$return = collect();
|
||||||
|
|
||||||
|
$this->items->load(['service']);
|
||||||
|
|
||||||
foreach ($this->items->filter(function ($item) use ($po) {
|
foreach ($this->items->filter(function ($item) use ($po) {
|
||||||
return $item->product_id == $po->id;
|
return $item->product_id == $po->id;
|
||||||
}) as $o)
|
}) as $o)
|
||||||
|
@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
class InvoiceItem extends Model
|
class InvoiceItem extends Model
|
||||||
{
|
{
|
||||||
protected $dates = ['date_start','date_stop'];
|
protected $dates = ['date_start','date_stop'];
|
||||||
|
public $dateFormat = 'U';
|
||||||
protected $table = 'ab_invoice_item';
|
protected $table = 'ab_invoice_item';
|
||||||
protected $with = ['taxes'];
|
protected $with = ['taxes'];
|
||||||
|
|
||||||
@ -32,6 +33,8 @@ class InvoiceItem extends Model
|
|||||||
return $this->hasMany(InvoiceItemTax::class);
|
return $this->hasMany(InvoiceItemTax::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ATTRIBUTES **/
|
||||||
|
|
||||||
public function getItemTypeNameAttribute()
|
public function getItemTypeNameAttribute()
|
||||||
{
|
{
|
||||||
$types = [
|
$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()
|
public function getSubTotalAttribute()
|
||||||
{
|
{
|
||||||
return $this->quantity * $this->price_base;
|
return $this->quantity * $this->price_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTaxAttribute()
|
public function getTaxAttribute()
|
||||||
{
|
{
|
||||||
if (! $this->_tax)
|
if (! $this->_tax)
|
||||||
@ -102,4 +93,36 @@ class InvoiceItem extends Model
|
|||||||
{
|
{
|
||||||
return $this->tax + $this->sub_total;
|
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()
|
private function getDefaultLanguage()
|
||||||
{
|
{
|
||||||
return config('SITE_SETUP')->language();
|
return config('SITE_SETUP')->language;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDescriptionAttribute()
|
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)
|
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()
|
public function PricePeriods()
|
||||||
|
@ -30,6 +30,7 @@ class Service extends Model
|
|||||||
protected $appends = [
|
protected $appends = [
|
||||||
'account_name',
|
'account_name',
|
||||||
'admin_service_id_url',
|
'admin_service_id_url',
|
||||||
|
'billing_price',
|
||||||
'name_short',
|
'name_short',
|
||||||
'next_invoice',
|
'next_invoice',
|
||||||
'product_category',
|
'product_category',
|
||||||
@ -43,6 +44,7 @@ class Service extends Model
|
|||||||
'account_name',
|
'account_name',
|
||||||
'admin_service_id_url',
|
'admin_service_id_url',
|
||||||
'active',
|
'active',
|
||||||
|
'billing_price',
|
||||||
'data_orig',
|
'data_orig',
|
||||||
'id',
|
'id',
|
||||||
'name_short',
|
'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 **/
|
/** ATTRIBUTES **/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -229,7 +241,11 @@ class Service extends Model
|
|||||||
|
|
||||||
public function getBillingPriceAttribute(): float
|
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
|
* @param float $value
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function addTax(float $value): float
|
private function addTax(float $value): float
|
||||||
{
|
{
|
||||||
return round($value*1.1,2);
|
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));
|
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 = collect();
|
||||||
|
|
||||||
$result->push([
|
$o = new InvoiceItem;
|
||||||
'item'=>0,
|
$o->active = TRUE;
|
||||||
'desc'=>sprintf('Product/Service [%s->%s]',
|
$o->service_id = $this->id;
|
||||||
$this->invoice_next->format('Y-m-d'),
|
$o->product_id = $this->product_id;
|
||||||
$this->invoice_next_end->format('Y-m-d')),
|
$o->quantity = 1;
|
||||||
'amt'=>$this->getBillingPriceAttribute()]);
|
$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([
|
$o = new InvoiceItem;
|
||||||
'item'=>5, // @tod Charges
|
$o->active = TRUE;
|
||||||
'desc'=>sprintf('%d@%3.2f - %s',$o->quantity,$this->addTax($o->amount),$o->name),
|
$o->service_id = $oo->service_id;
|
||||||
'amt'=>$this->addTax($o->amount*$o->quantity)]);
|
$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;
|
return $result;
|
||||||
|
@ -10,7 +10,7 @@ class Site extends Model
|
|||||||
protected $table = 'ab_setup';
|
protected $table = 'ab_setup';
|
||||||
public $timestamps = FALSE;
|
public $timestamps = FALSE;
|
||||||
|
|
||||||
protected $with = ['details'];
|
protected $with = ['details','language'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'address'=>'array',
|
'address'=>'array',
|
||||||
@ -23,9 +23,6 @@ class Site extends Model
|
|||||||
|
|
||||||
public function language()
|
public function language()
|
||||||
{
|
{
|
||||||
if (! $this->id)
|
|
||||||
return Language::find(1);
|
|
||||||
|
|
||||||
return $this->belongsTo(Language::class);
|
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',
|
'clients_intro'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore',
|
||||||
|
'language_id'=>1,
|
||||||
'page_tabs'=>[
|
'page_tabs'=>[
|
||||||
[
|
[
|
||||||
'title'=>'Title 1',
|
'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';
|
||||||
|
}
|
@ -23,7 +23,7 @@
|
|||||||
"laravel/passport": "^7.3",
|
"laravel/passport": "^7.3",
|
||||||
"laravel/socialite": "^4.1",
|
"laravel/socialite": "^4.1",
|
||||||
"laravel/tinker": "^1.0",
|
"laravel/tinker": "^1.0",
|
||||||
"leenooks/laravel": "^0.3.2",
|
"leenooks/laravel": "^0.3.10",
|
||||||
"quickbooks/v3-php-sdk": "^5.0",
|
"quickbooks/v3-php-sdk": "^5.0",
|
||||||
"spatie/laravel-demo-mode": "^2.2",
|
"spatie/laravel-demo-mode": "^2.2",
|
||||||
"spatie/laravel-failed-job-monitor": "^3.0",
|
"spatie/laravel-failed-job-monitor": "^3.0",
|
||||||
|
20
composer.lock
generated
20
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "8d997e88df489137705fe8a879e16642",
|
"content-hash": "ef180c81ebb0ec6d711835337143759d",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "acacha/user",
|
"name": "acacha/user",
|
||||||
@ -1270,16 +1270,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "igaster/laravel-theme",
|
"name": "igaster/laravel-theme",
|
||||||
"version": "v2.0.11",
|
"version": "v2.0.12",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/igaster/laravel-theme.git",
|
"url": "https://github.com/igaster/laravel-theme.git",
|
||||||
"reference": "0b8be5dba752bbd9e8f1de31efb4a300aa19790e"
|
"reference": "f75d323e1310c8506eff0f67814861cf9ced6567"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/igaster/laravel-theme/zipball/0b8be5dba752bbd9e8f1de31efb4a300aa19790e",
|
"url": "https://api.github.com/repos/igaster/laravel-theme/zipball/f75d323e1310c8506eff0f67814861cf9ced6567",
|
||||||
"reference": "0b8be5dba752bbd9e8f1de31efb4a300aa19790e",
|
"reference": "f75d323e1310c8506eff0f67814861cf9ced6567",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1325,7 +1325,7 @@
|
|||||||
"themes",
|
"themes",
|
||||||
"views"
|
"views"
|
||||||
],
|
],
|
||||||
"time": "2019-02-27T22:56:34+00:00"
|
"time": "2019-07-03T05:25:33+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "intervention/image",
|
"name": "intervention/image",
|
||||||
@ -2357,16 +2357,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "leenooks/laravel",
|
"name": "leenooks/laravel",
|
||||||
"version": "0.3.9",
|
"version": "0.3.10",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://dev.leenooks.net/leenooks/laravel",
|
"url": "https://dev.leenooks.net/leenooks/laravel",
|
||||||
"reference": "6d876f2c946f5b182e4efe6c8f89038385818ea1"
|
"reference": "1efdfca55f77c3a473b5009a5abca11f8cbd97b1"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"acacha/user": "^0.2.2",
|
"acacha/user": "^0.2.2",
|
||||||
"creativeorange/gravatar": "^1.0",
|
"creativeorange/gravatar": "^1.0",
|
||||||
"igaster/laravel-theme": "^2.0",
|
"igaster/laravel-theme": "^2.0.12",
|
||||||
"orchestra/asset": "^3.6"
|
"orchestra/asset": "^3.6"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -2399,7 +2399,7 @@
|
|||||||
"laravel",
|
"laravel",
|
||||||
"leenooks"
|
"leenooks"
|
||||||
],
|
],
|
||||||
"time": "2019-06-17T01:44:56+00:00"
|
"time": "2019-07-03T07:16:46+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maximebf/debugbar",
|
"name": "maximebf/debugbar",
|
||||||
|
@ -31,12 +31,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@section('page-scripts')
|
@section('page-scripts')
|
||||||
@css('https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
@css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
||||||
@js('https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
@js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
||||||
@css('https://cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
@css('//cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
||||||
@js('https://cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
@js('//cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
||||||
@css('https://cdn.datatables.net/rowgroup/1.0.2/css/rowGroup.dataTables.min.css','dt-rowgroup-css','jq-dt-css')
|
|
||||||
@js('https://cdn.datatables.net/rowgroup/1.0.2/js/dataTables.rowGroup.min.js','dt-rowgroup-js','jq-dt-js')
|
|
||||||
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
||||||
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
||||||
|
|
||||||
|
@ -24,10 +24,10 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
@section('page-scripts')
|
@section('page-scripts')
|
||||||
@css('https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
@css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
||||||
@js('https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
@js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
||||||
@css('https://cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','jq-dt-r-css','jq-dt-css')
|
@css('//cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','jq-dt-r-css','jq-dt-css')
|
||||||
@js('https://cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','jq-dt-r-js','jq-dt-js')
|
@js('//cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','jq-dt-r-js','jq-dt-js')
|
||||||
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
||||||
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
||||||
|
|
||||||
|
@ -26,12 +26,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@section('page-scripts')
|
@section('page-scripts')
|
||||||
@css('https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
@css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
||||||
@js('https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
@js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
||||||
@css('https://cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
@css('//cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
||||||
@js('https://cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
@js('//cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
||||||
@css('https://cdn.datatables.net/rowgroup/1.0.2/css/rowGroup.dataTables.min.css','dt-rowgroup-css','jq-dt-css')
|
|
||||||
@js('https://cdn.datatables.net/rowgroup/1.0.2/js/dataTables.rowGroup.min.js','dt-rowgroup-js','jq-dt-js')
|
|
||||||
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
||||||
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
<th>Product</th>
|
<th>Product</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Next Invoice</th>
|
<th>Next Invoice</th>
|
||||||
|
{{-- <th>Amount</th> --}}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
@ -32,12 +33,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@section('page-scripts')
|
@section('page-scripts')
|
||||||
@css('https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
@css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
||||||
@js('https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
@js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
||||||
@css('https://cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
@css('//cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
||||||
@js('https://cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
@js('//cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
||||||
@css('https://cdn.datatables.net/rowgroup/1.0.2/css/rowGroup.dataTables.min.css','dt-rowgroup-css','jq-dt-css')
|
@css('//cdn.datatables.net/rowgroup/1.0.2/css/rowGroup.dataTables.min.css','dt-rowgroup-css','jq-dt-css')
|
||||||
@js('https://cdn.datatables.net/rowgroup/1.0.2/js/dataTables.rowGroup.min.js','dt-rowgroup-js','jq-dt-js')
|
@js('//cdn.datatables.net/rowgroup/1.0.2/js/dataTables.rowGroup.min.js','dt-rowgroup-js','jq-dt-js')
|
||||||
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
||||||
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
||||||
|
|
||||||
@ -54,7 +55,8 @@
|
|||||||
{ data: "name_short" },
|
{ data: "name_short" },
|
||||||
{ data: "product_name" },
|
{ data: "product_name" },
|
||||||
{ data: "status" },
|
{ data: "status" },
|
||||||
{ data: "next_invoice" }
|
{ data: "next_invoice" },
|
||||||
|
{{-- { data: "billing_price", render: $.fn.dataTable.render.number(',','.',2,'$') } --}}
|
||||||
],
|
],
|
||||||
language: {
|
language: {
|
||||||
emptyTable: "No Active Services"
|
emptyTable: "No Active Services"
|
||||||
|
@ -6,11 +6,12 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="3">{{ $o->name }}</th><th class="text-right">{{ number_format($o->next_invoice_items()->sum('amt'),2) }}</th>
|
<th colspan="3">{{ $o->name }}</th><th class="text-right">${{ number_format($o->next_invoice_items()->sum('total'),2) }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
@foreach ($o->next_invoice_items() as $oo)
|
|
||||||
|
@foreach ($o->next_invoice_items() as $io)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="pt-0 pb-1"> </td><td class="pt-0 pb-1">{{ $oo['desc'] }}</td><td class="text-right pt-0 pb-1">{{ number_format($oo['amt'],2) }}</td>
|
<td class="pt-0 pb-1"> </td><td class="pt-0 pb-1">{{ $io->item_type_name }}</td><td class="text-right pt-0 pb-1">${{ number_format($io->total,2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</table>
|
</table>
|
||||||
|
@ -33,12 +33,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@section('page-scripts')
|
@section('page-scripts')
|
||||||
@css('https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
@css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
||||||
@js('https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
@js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
||||||
@css('https://cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
@css('//cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
||||||
@js('https://cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
@js('//cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
||||||
@css('https://cdn.datatables.net/rowgroup/1.0.2/css/rowGroup.dataTables.min.css','dt-rowgroup-css','jq-dt-css')
|
|
||||||
@js('https://cdn.datatables.net/rowgroup/1.0.2/js/dataTables.rowGroup.min.js','dt-rowgroup-js','jq-dt-js')
|
|
||||||
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
||||||
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
||||||
|
|
||||||
|
@ -34,12 +34,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@section('page-scripts')
|
@section('page-scripts')
|
||||||
@css('https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
@css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
|
||||||
@js('https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
@js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
|
||||||
@css('https://cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
@css('//cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
|
||||||
@js('https://cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
@js('//cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
|
||||||
@css('https://cdn.datatables.net/rowgroup/1.0.2/css/rowGroup.dataTables.min.css','dt-rowgroup-css','jq-dt-css')
|
@css('//cdn.datatables.net/rowgroup/1.0.2/css/rowGroup.dataTables.min.css','dt-rowgroup-css','jq-dt-css')
|
||||||
@js('https://cdn.datatables.net/rowgroup/1.0.2/js/dataTables.rowGroup.min.js','dt-rowgroup-js','jq-dt-js')
|
@js('//cdn.datatables.net/rowgroup/1.0.2/js/dataTables.rowGroup.min.js','dt-rowgroup-js','jq-dt-js')
|
||||||
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
|
||||||
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
<th class="text-right" colspan="3">Subtotal</th>
|
<th class="text-right" colspan="3">Subtotal</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach ($o->products() as $po)
|
@foreach ($o->products() as $po)
|
||||||
<tr id="invoice-services">
|
<tr id="invoice-services">
|
||||||
@ -152,15 +153,17 @@
|
|||||||
<th colspan="2">Total:</th>
|
<th colspan="2">Total:</th>
|
||||||
<td class="text-right">${{ number_format($o->total,$o->currency()->rounding) }}</td>
|
<td class="text-right">${{ number_format($o->total,$o->currency()->rounding) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
@if($o->id)
|
||||||
<th> </th>
|
<tr>
|
||||||
<th>Payments:</th>
|
<th> </th>
|
||||||
<td class="text-right">${{ number_format($o->paid,$o->currency()->rounding) }}</td>
|
<th>Payments:</th>
|
||||||
</tr>
|
<td class="text-right">${{ number_format($o->paid,$o->currency()->rounding) }}</td>
|
||||||
<tr>
|
</tr>
|
||||||
<th colspan="2">Account Due:</th>
|
<tr>
|
||||||
<td class="text-right">${{ number_format($o->due,$o->currency()->rounding) }}</td>
|
<th colspan="2">Account Due:</th>
|
||||||
</tr>
|
<td class="text-right">${{ number_format($o->due,$o->currency()->rounding) }}</td>
|
||||||
|
</tr>
|
||||||
|
@endif
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.col -->
|
<!-- /.col -->
|
||||||
@ -171,10 +174,12 @@
|
|||||||
<div class="row d-print-none">
|
<div class="row d-print-none">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<a href="javascript:window.print();" target="_blank" class="btn btn-default"><i class="fa fa-print"></i> Print</a>
|
<a href="javascript:window.print();" target="_blank" class="btn btn-default"><i class="fa fa-print"></i> Print</a>
|
||||||
<button type="button" class="btn btn-success pull-right"><i class="fa fa-credit-card"></i> Submit Payment</button>
|
@if($o->id)
|
||||||
<a href="{{ url(sprintf('u/invoice/%s/pdf',$o->id)) }}" class="btn btn-primary pull-right" style="margin-right: 5px;">
|
<button type="button" class="btn btn-success pull-right"><i class="fa fa-credit-card"></i> Submit Payment</button>
|
||||||
<i class="fa fa-download"></i> Download PDF
|
<a href="{{ url(sprintf('u/invoice/%s/pdf',$o->id)) }}" class="btn btn-primary pull-right" style="margin-right: 5px;">
|
||||||
</a>
|
<i class="fa fa-download"></i> Download PDF
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -35,15 +35,22 @@ Route::group(['middleware'=>['theme:adminlte-be','auth','role:reseller'],'prefix
|
|||||||
Route::get('supplier/create', 'SuppliersController@create');
|
Route::get('supplier/create', 'SuppliersController@create');
|
||||||
Route::post('supplier/store', 'SuppliersController@store');
|
Route::post('supplier/store', 'SuppliersController@store');
|
||||||
Route::get('switch/start/{id}','\Leenooks\Controllers\AdminController@user_switch_start')->name('switch.user.stop');
|
Route::get('switch/start/{id}','\Leenooks\Controllers\AdminController@user_switch_start')->name('switch.user.stop');
|
||||||
Route::get('home/{o}', 'UserHomeController@user');
|
//Route::get('home/{o}', 'UserHomeController@user');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Our User Routes
|
// Our User Routes
|
||||||
Route::group(['middleware'=>['theme:adminlte-be','auth'],'prefix'=>'u'], function() {
|
Route::group(['middleware'=>['theme:adminlte-be','auth'],'prefix'=>'u'], function() {
|
||||||
Route::get('home', 'UserHomeController@home');
|
Route::get('home', 'UserHomeController@home');
|
||||||
Route::get('invoice/{o}', 'UserHomeController@invoice');
|
Route::get('account/{o}', 'User\AccountController@view')
|
||||||
Route::get('invoice/{o}/pdf','UserHomeController@invoice_pdf');
|
->middleware('can:view,o');
|
||||||
Route::get('service/{o}', 'UserHomeController@service');
|
Route::get('account/{o}/invoice', 'User\AccountController@view_invoice_next')
|
||||||
|
->middleware('can:view,o');
|
||||||
|
Route::get('invoice/{o}', 'UserHomeController@invoice')
|
||||||
|
->middleware('can:view,o');
|
||||||
|
Route::get('invoice/{o}/pdf','UserHomeController@invoice_pdf')
|
||||||
|
->middleware('can:view,o');
|
||||||
|
Route::get('service/{o}', 'UserHomeController@service')
|
||||||
|
->middleware('can:view,o');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Frontend Routes (Non-Authed Users)
|
// Frontend Routes (Non-Authed Users)
|
||||||
|
Loading…
Reference in New Issue
Block a user