Optimise Invoice
This commit is contained in:
parent
29bccbf72f
commit
f561139d45
@ -102,7 +102,7 @@ class Account extends Model implements IDs
|
|||||||
public function invoices()
|
public function invoices()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Invoice::class)
|
return $this->hasMany(Invoice::class)
|
||||||
->with(['items.taxes','paymentitems.payment']);
|
->with(['items.taxes','payment_items.payment']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,14 +10,6 @@ class Country extends Model
|
|||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
|
||||||
/**
|
|
||||||
* The currency this country belongs to
|
|
||||||
*/
|
|
||||||
public function currency()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Currency::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function taxes()
|
public function taxes()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Tax::class);
|
return $this->hasMany(Tax::class);
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Currency extends Model
|
|
||||||
{
|
|
||||||
public $timestamps = FALSE;
|
|
||||||
|
|
||||||
const ROUND_HALF_UP = 1;
|
|
||||||
const ROUND_HALF_DOWN = 2;
|
|
||||||
const ROUND_HALF_EVEN = 3;
|
|
||||||
const ROUND_HALF_ODD = 4;
|
|
||||||
|
|
||||||
/* RELATIONS */
|
|
||||||
|
|
||||||
public function country()
|
|
||||||
{
|
|
||||||
return $this->hasOne(Country::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* METHODS */
|
|
||||||
|
|
||||||
public function round($value,$mode=self::ROUND_HALF_UP)
|
|
||||||
{
|
|
||||||
return round($value,$this->rounding,$mode);
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,6 +7,7 @@ use Clarkeash\Doorman\Facades\Doorman;
|
|||||||
use Clarkeash\Doorman\Models\Invite;
|
use Clarkeash\Doorman\Models\Invite;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Leenooks\Casts\LeenooksCarbon;
|
use Leenooks\Casts\LeenooksCarbon;
|
||||||
use Leenooks\Traits\ScopeActive;
|
use Leenooks\Traits\ScopeActive;
|
||||||
|
|
||||||
@ -19,16 +20,16 @@ use App\Traits\PushNew;
|
|||||||
* Invoices that belong to an Account
|
* Invoices that belong to an Account
|
||||||
*
|
*
|
||||||
* Attributes for services:
|
* Attributes for services:
|
||||||
|
* + created_at : Date the invoice was created
|
||||||
* + due : Balance due on an invoice
|
* + due : Balance due on an invoice
|
||||||
* + due_date : Date the invoice is due
|
* + due_at : Date the invoice is due
|
||||||
* + invoice_date : Date the invoice was created
|
|
||||||
* + lid : Local ID for invoice
|
* + lid : Local ID for invoice
|
||||||
* + paid : Total of payments received (excluding pending)
|
* + paid : Total of payments received (excluding pending)
|
||||||
* + paid_date : Date the invoice was paid in full
|
* + paid_date : Date the invoice was paid in full
|
||||||
* + paid_pending : Total of pending payments received
|
* + paid_pending : Total of pending payments received
|
||||||
* + sid : System ID for invoice
|
* + sid : System ID for invoice
|
||||||
* + sub_total : Invoice sub-total before taxes
|
* + sub_total : Invoice sub-total before taxes
|
||||||
* + total_tax : Invoices total of taxes
|
* + tax_total : Invoices total of taxes
|
||||||
* + total : Invoice total
|
* + total : Invoice total
|
||||||
*
|
*
|
||||||
* @package App\Models
|
* @package App\Models
|
||||||
@ -97,13 +98,13 @@ class Invoice extends Model implements IDs
|
|||||||
// Array of items that can be updated with PushNew
|
// Array of items that can be updated with PushNew
|
||||||
protected $pushable = ['items'];
|
protected $pushable = ['items'];
|
||||||
|
|
||||||
/*
|
|
||||||
protected $with = [
|
protected $with = [
|
||||||
'account.country.currency',
|
'items_active:id,start_at,stop_at,quantity,price_base,discount_amt,item_type,product_id,service_id,invoice_id',
|
||||||
'items.taxes',
|
'items_active.taxes:id,invoice_item_id,amount,tax_id',
|
||||||
'paymentitems'
|
'items_active.product:id',
|
||||||
|
'items_active.product.translate:id,product_id,name_short,name_detail',
|
||||||
|
'payment_items_active:id,amount,payment_id,invoice_id',
|
||||||
];
|
];
|
||||||
*/
|
|
||||||
|
|
||||||
/* STATIC METHODS */
|
/* STATIC METHODS */
|
||||||
|
|
||||||
@ -181,29 +182,58 @@ class Invoice extends Model implements IDs
|
|||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account this invoice belongs to
|
||||||
|
*/
|
||||||
public function account()
|
public function account()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Account::class);
|
return $this->belongsTo(Account::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Items on this invoice belongs to
|
||||||
|
*/
|
||||||
public function items()
|
public function items()
|
||||||
{
|
{
|
||||||
return $this->hasMany(InvoiceItem::class)
|
return $this->hasMany(InvoiceItem::class)
|
||||||
->where('active',TRUE)
|
|
||||||
->with(['taxes','product']);
|
->with(['taxes','product']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active items on this invoice belongs to
|
||||||
|
*/
|
||||||
|
public function items_active()
|
||||||
|
{
|
||||||
|
return $this->items()
|
||||||
|
->where('active',TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payments applied to this invoice
|
||||||
|
*/
|
||||||
public function payments()
|
public function payments()
|
||||||
{
|
{
|
||||||
return $this->hasManyThrough(Payment::class,PaymentItem::class,NULL,'id',NULL,'payment_id')
|
return $this->hasManyThrough(Payment::class,PaymentItem::class,NULL,'id',NULL,'payment_id')
|
||||||
->active();
|
->where('active',TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function paymentitems()
|
/**
|
||||||
|
* Payment items attached to this invoice
|
||||||
|
*/
|
||||||
|
public function payment_items()
|
||||||
{
|
{
|
||||||
return $this->hasMany(PaymentItem::class);
|
return $this->hasMany(PaymentItem::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function payment_items_active()
|
||||||
|
{
|
||||||
|
return $this->payment_items()
|
||||||
|
->where('payment_items.active',TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3rd party provider details to this invoice (eg: accounting providers)
|
||||||
|
*/
|
||||||
public function providers()
|
public function providers()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(ProviderOauth::class,'invoice__provider')
|
return $this->belongsToMany(ProviderOauth::class,'invoice__provider')
|
||||||
@ -236,31 +266,6 @@ class Invoice extends Model implements IDs
|
|||||||
return sprintf('%3.2f',$this->getTotalAttribute()-$this->getPaidAttribute());
|
return sprintf('%3.2f',$this->getTotalAttribute()-$this->getPaidAttribute());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
* @todo Change references to due_at to use due_date
|
|
||||||
*/
|
|
||||||
public function getDueDateAttribute(): Carbon
|
|
||||||
{
|
|
||||||
return $this->due_at;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Date the invoices was created
|
|
||||||
*
|
|
||||||
* @return Carbon
|
|
||||||
*/
|
|
||||||
public function getInvoiceDateAttribute(): Carbon
|
|
||||||
{
|
|
||||||
return $this->created_at;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo Move this to a site configuration
|
|
||||||
public function getInvoiceTextAttribute()
|
|
||||||
{
|
|
||||||
return sprintf('Thank you for using %s for your Internet Services.',config('site')->site_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total of payments received for this invoice
|
* Total of payments received for this invoice
|
||||||
* excluding pending payments
|
* excluding pending payments
|
||||||
@ -269,9 +274,7 @@ class Invoice extends Model implements IDs
|
|||||||
*/
|
*/
|
||||||
public function getPaidAttribute(): float
|
public function getPaidAttribute(): float
|
||||||
{
|
{
|
||||||
return $this->paymentitems
|
return $this->payment_items_active->sum('amount');
|
||||||
->filter(function($item) { return ! $item->payment->pending_status && $item->payment->active; })
|
|
||||||
->sum('amount');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,11 +285,13 @@ class Invoice extends Model implements IDs
|
|||||||
*/
|
*/
|
||||||
public function getPaidDateAttribute(): ?Carbon
|
public function getPaidDateAttribute(): ?Carbon
|
||||||
{
|
{
|
||||||
|
// If the invoice still has a due balance, its not paid
|
||||||
if ($this->getDueAttribute())
|
if ($this->getDueAttribute())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
$o = $this->payments
|
$o = $this
|
||||||
->filter(function($item) { return ! $item->pending_status; })
|
->payments
|
||||||
|
->filter(fn($item)=>(! $item->pending_status))
|
||||||
->last();
|
->last();
|
||||||
|
|
||||||
return $o?->paid_at;
|
return $o?->paid_at;
|
||||||
@ -299,8 +304,8 @@ class Invoice extends Model implements IDs
|
|||||||
*/
|
*/
|
||||||
public function getPaidPendingAttribute(): float
|
public function getPaidPendingAttribute(): float
|
||||||
{
|
{
|
||||||
return $this->paymentitems
|
return $this->payment_items
|
||||||
->filter(function($item) { return $item->payment->pending_status; })
|
->filter(fn($item)=>$item->payment->pending_status)
|
||||||
->sum('amount');
|
->sum('amount');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,28 +316,17 @@ class Invoice extends Model implements IDs
|
|||||||
*/
|
*/
|
||||||
public function getSubTotalAttribute(): float
|
public function getSubTotalAttribute(): float
|
||||||
{
|
{
|
||||||
return $this->items->where('active',TRUE)->sum('sub_total');
|
return $this->items_active->sum('sub_total');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the invoices taxes total
|
* Get the invoices taxes total
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
* @deprecated use getTotalTaxAttribute();
|
|
||||||
*/
|
*/
|
||||||
public function getTaxTotalAttribute(): float
|
public function getTaxTotalAttribute(): float
|
||||||
{
|
{
|
||||||
return $this->getTotalTaxAttribute();
|
return $this->items_active->sum('tax');
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the invoices taxes total
|
|
||||||
*
|
|
||||||
* @return float
|
|
||||||
*/
|
|
||||||
public function getTotalTaxAttribute(): float
|
|
||||||
{
|
|
||||||
return $this->items->where('active',TRUE)->sum('tax');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -342,17 +336,11 @@ class Invoice extends Model implements IDs
|
|||||||
*/
|
*/
|
||||||
public function getTotalAttribute(): float
|
public function getTotalAttribute(): float
|
||||||
{
|
{
|
||||||
return $this->getSubTotalAttribute()+$this->getTotalTaxAttribute();
|
return $this->getSubTotalAttribute()+$this->getTaxTotalAttribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
|
|
||||||
// @todo This shouldnt be here - current should be handled at an account level.
|
|
||||||
public function currency()
|
|
||||||
{
|
|
||||||
return $this->account->country->currency;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a download link for non-auth downloads
|
* Return a download link for non-auth downloads
|
||||||
*
|
*
|
||||||
@ -366,57 +354,37 @@ class Invoice extends Model implements IDs
|
|||||||
$tokendate = ($x=Carbon::now()->addDays(21)) > ($y=$this->due_at->addDays(21)) ? $x : $y;
|
$tokendate = ($x=Carbon::now()->addDays(21)) > ($y=$this->due_at->addDays(21)) ? $x : $y;
|
||||||
|
|
||||||
// Extend the expire date
|
// Extend the expire date
|
||||||
if ($io AND ($tokendate > $io->valid_until)) {
|
if ($io && ($tokendate > $io->valid_until)) {
|
||||||
$io->valid_until = $tokendate;
|
$io->valid_until = $tokendate;
|
||||||
$io->save();
|
$io->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
$code = (! $io) ? Doorman::generate()->for($this->account->user->email)->uses(0)->expiresOn($tokendate)->make()->first()->code : $io->code;
|
$code = (! $io)
|
||||||
|
? Doorman::generate()
|
||||||
|
->for($this->account->user->email)
|
||||||
|
->uses(0)
|
||||||
|
->expiresOn($tokendate)
|
||||||
|
->make()
|
||||||
|
->first()
|
||||||
|
->code
|
||||||
|
: $io->code;
|
||||||
|
|
||||||
return url('u/invoice',[$this->id,'email',$code]);
|
return url('u/invoice',[$this->id,'email',$code]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo document
|
/**
|
||||||
public function products()
|
* Return all the items on an invoice for a particular service and product
|
||||||
|
*
|
||||||
|
* @param Product $po
|
||||||
|
* @param Service $so
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function product_service_items(Product $po,Service $so): Collection
|
||||||
{
|
{
|
||||||
$return = collect();
|
return $this
|
||||||
|
->items_active
|
||||||
foreach ($this->items->groupBy('product_id') as $o) {
|
->filter(fn($item)=>($item->product_id === $po->id) && ($item->service_id === $so->id))
|
||||||
$po = $o->first()->product;
|
->sortBy('item_type');
|
||||||
$po->count = count($o->pluck('service_id')->unique());
|
|
||||||
|
|
||||||
$return->push($po);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return->sortBy(function ($item) {
|
|
||||||
return $item->name;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo document
|
|
||||||
public function product_services(Product $po)
|
|
||||||
{
|
|
||||||
$return = collect();
|
|
||||||
|
|
||||||
$this->items->load(['service']);
|
|
||||||
|
|
||||||
foreach ($this->items->filter(function ($item) use ($po) {
|
|
||||||
return $item->product_id == $po->id;
|
|
||||||
}) as $o)
|
|
||||||
{
|
|
||||||
$so = $o->service;
|
|
||||||
$return->push($so);
|
|
||||||
};
|
|
||||||
|
|
||||||
return $return->unique()->sortBy('name');
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo document
|
|
||||||
public function product_service_items(Product $po,Service $so)
|
|
||||||
{
|
|
||||||
return $this->items->filter(function ($item) use ($po,$so) {
|
|
||||||
return $item->product_id == $po->id AND $item->service_id == $so->id;
|
|
||||||
})->filter()->sortBy('item_type');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -439,6 +407,7 @@ class Invoice extends Model implements IDs
|
|||||||
*
|
*
|
||||||
* @param array $options
|
* @param array $options
|
||||||
* @return bool
|
* @return bool
|
||||||
|
* @todo Change this to a saving event
|
||||||
*/
|
*/
|
||||||
public function save(array $options = [])
|
public function save(array $options = [])
|
||||||
{
|
{
|
||||||
@ -453,4 +422,29 @@ class Invoice extends Model implements IDs
|
|||||||
|
|
||||||
return parent::save($options);
|
return parent::save($options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group the invoice items by product ID, returning the number of products and total
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function summary_products(): Collection
|
||||||
|
{
|
||||||
|
$return = collect();
|
||||||
|
|
||||||
|
foreach ($this->items_active->groupBy('product_id') as $o) {
|
||||||
|
$po = $o->first()->product;
|
||||||
|
$po->count = count($o->pluck('service_id')->unique());
|
||||||
|
|
||||||
|
$return->push([
|
||||||
|
'product' => $o->first()->product,
|
||||||
|
'services' => $o->pluck('service_id')->unique(),
|
||||||
|
'sub_total' => $o->sum('sub_total'),
|
||||||
|
'tax_total' => $o->sum('tax'),
|
||||||
|
'total' => $o->sum('total'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return->sortBy('product.name');
|
||||||
|
}
|
||||||
}
|
}
|
@ -125,7 +125,7 @@ class InvoiceItem extends Model
|
|||||||
*/
|
*/
|
||||||
public function getSubTotalAttribute(): float
|
public function getSubTotalAttribute(): float
|
||||||
{
|
{
|
||||||
return sprintf('%3.2f',$this->quantity * $this->price_base - $this->discount_amt);
|
return sprintf('%3.2f',$this->quantity * ($this->price_base - $this->discount_amt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,11 +44,6 @@ class Site extends Model
|
|||||||
return $this->belongsTo(Country::class);
|
return $this->belongsTo(Country::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function currency()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Currency::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function details()
|
public function details()
|
||||||
{
|
{
|
||||||
return $this->hasMany(SiteDetail::class,NULL,'site_id');
|
return $this->hasMany(SiteDetail::class,NULL,'site_id');
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'language_id' => 1,
|
'language_id' => 1,
|
||||||
|
'invoice_text' => 'Thank you for using our Internet Services.',
|
||||||
];
|
];
|
@ -6,8 +6,8 @@ A new invoice has been generated on your account. A summary of that invoice is b
|
|||||||
@component('mail::table')
|
@component('mail::table')
|
||||||
| # | ID | Name | Amount |
|
| # | ID | Name | Amount |
|
||||||
| -: | - |:-----| ------:|
|
| -: | - |:-----| ------:|
|
||||||
@foreach ($invoice->products() as $po)
|
@foreach ($invoice->summary_products() as $item)
|
||||||
| {{ $po->count }} | {{ $po->product_id }} | {{ $po->name }} | ${{ number_format($invoice->items->filter(function($item) use ($po) {return $item->product_id == $po->id; })->sum('total'),$invoice->currency()->rounding) }} |
|
| {{ $item['services']->count() }} | {{ $item['product']->lid }} | {{ $item['product']->name }} | ${{ number_format($item['total'],2) }} |
|
||||||
@endforeach
|
@endforeach
|
||||||
||| Sub Total | ${{ number_format($invoice->sub_total,2) }} |
|
||| Sub Total | ${{ number_format($invoice->sub_total,2) }} |
|
||||||
||| Tax | ${{ number_format($invoice->tax_total,2) }} |
|
||| Tax | ${{ number_format($invoice->tax_total,2) }} |
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
@if(($x=$o->invoices()
|
@if(($x=$o->invoices()
|
||||||
->where('active',TRUE)
|
->where('active',TRUE)
|
||||||
->orderBy('due_at')
|
->orderBy('due_at')
|
||||||
->with(['items.taxes','paymentitems.payment','account'])
|
->with(['items.taxes','payment_items.payment','account'])
|
||||||
->get()
|
->get()
|
||||||
->filter(function($item) use ($pid) { return $item->due > 0 || $item->payments->search(function($item) use ($pid) { return $item->id == $pid; }) !== FALSE; }))->count())
|
->filter(function($item) use ($pid) { return $item->due > 0 || $item->payments->search(function($item) use ($pid) { return $item->id == $pid; }) !== FALSE; }))->count())
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
@ -22,12 +22,12 @@
|
|||||||
@foreach ($x as $io)
|
@foreach ($x as $io)
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="{{ url('u/invoice',[$io->id]) }}">{{ $io->sid }}</a></td>
|
<td><a href="{{ url('u/invoice',[$io->id]) }}">{{ $io->sid }}</a></td>
|
||||||
<td>{{ $io->invoice_date->format('Y-m-d') }}</td>
|
<td>{{ $io->created_at->format('Y-m-d') }}</td>
|
||||||
<td>{{ $io->due_at->format('Y-m-d') }}</td>
|
<td>{{ $io->due_at->format('Y-m-d') }}</td>
|
||||||
<td>{{ number_format($io->total,2) }}</td>
|
<td>{{ number_format($io->total,2) }}</td>
|
||||||
<td>{{ number_format($io->due,2) }}</td>
|
<td>{{ number_format($io->due,2) }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<input type="text" class="text-right invoice" name="invoices[{{ $io->id }}][id]" value="{{ number_format(($x=$io->paymentitems->filter(function($item) use ($pid) { return $item->payment_id == $pid; })) ? $x->sum('amount') : 0,2) }}">
|
<input type="text" class="text-right invoice" name="invoices[{{ $io->id }}][id]" value="{{ number_format(($x=$io->payment_items->filter(function($item) use ($pid) { return $item->payment_id == $pid; })) ? $x->sum('amount') : 0,2) }}">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
<!-- $o = Account::class -->
|
<!-- $o = Account::class -->
|
||||||
|
@php
|
||||||
|
$o->load(['services_active.invoiced_service_items_active_recent']);
|
||||||
|
@endphp
|
||||||
|
|
||||||
<!-- Show active services -->
|
<!-- Show active services -->
|
||||||
<div class="card card-light">
|
<div class="card card-light">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@ -6,7 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@if (($x=$o->services->where('active',TRUE))->count())
|
@if (($x=$o->services_active)->count())
|
||||||
<table class="table table-striped table-hover w-100" id="services_active_{{ $ao->id }}">
|
<table class="table table-striped table-hover w-100" id="services_active_{{ $ao->id }}">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
@php
|
||||||
|
use App\Models\{Checkout,Service};
|
||||||
|
@endphp
|
||||||
|
|
||||||
<!-- $o = Invoice::class -->
|
<!-- $o = Invoice::class -->
|
||||||
@extends('adminlte::layouts.app')
|
@extends('adminlte::layouts.app')
|
||||||
|
|
||||||
@ -58,7 +62,7 @@
|
|||||||
<div class="ml-auto col-3">
|
<div class="ml-auto col-3">
|
||||||
<table class="table table-borderless text-right" style="font-size: 1.1rem;">
|
<table class="table table-borderless text-right" style="font-size: 1.1rem;">
|
||||||
<tr >
|
<tr >
|
||||||
<td class="p-0">Issue Date:</td><td class="p-0"><strong>{{ $o->invoice_date->format('Y-m-d') }}</strong></td>
|
<td class="p-0">Issue Date:</td><td class="p-0"><strong>{{ $o->created_at->format('Y-m-d') }}</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr >
|
<tr >
|
||||||
<td class="p-0">Account:</td><td class="p-0"><strong>{{ $o->account->sid }}</strong></td>
|
<td class="p-0">Account:</td><td class="p-0"><strong>{{ $o->account->sid }}</strong></td>
|
||||||
@ -70,12 +74,12 @@
|
|||||||
<td class="p-0">Payment Due:</td><td class="p-0"><strong>{{ $o->due_at->format('Y-m-d') }}</strong></td>
|
<td class="p-0">Payment Due:</td><td class="p-0"><strong>{{ $o->due_at->format('Y-m-d') }}</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="p-0">This Invoice Due:</td><td class="p-0"><strong>${{ number_format($o->total,$o->currency()->rounding) }}</strong></td>
|
<td class="p-0">This Invoice Due:</td><td class="p-0"><strong>${{ number_format($o->total,2) }}</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{--
|
{{--
|
||||||
<!-- @todo -->
|
<!-- @todo -->
|
||||||
<tr>
|
<tr>
|
||||||
<td class="p-0">Total Account Due:</td><td class="p-0"><strong>${{ number_format($o->account->due,$o->currency()->rounding) }}</strong></td>
|
<td class="p-0">Total Account Due:</td><td class="p-0"><strong>${{ number_format($o->account->due,2) }}</strong></td>
|
||||||
</tr>
|
</tr>
|
||||||
--}}
|
--}}
|
||||||
</table>
|
</table>
|
||||||
@ -97,29 +101,29 @@
|
|||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach ($o->products() as $po)
|
@foreach($o->summary_products() as $item)
|
||||||
<tr id="invoice-services">
|
<tr id="invoice-services">
|
||||||
<td>{{ $po->count }}</td>
|
<td>{{ $item['services']->count() }}</td>
|
||||||
<td>#{{ $po->lid }}</td>
|
<td>#{{ $item['product']->lid }}</td>
|
||||||
<td colspan="2">{{ $po->name }}</td>
|
<td colspan="2">{{ $item['product']->name }}</td>
|
||||||
<td colspan="3" class="text-right">${{ number_format($o->items->filter(function($item) use ($po) {return $item->product_id == $po->id; })->sum('total'),$o->currency()->rounding) }}</td>
|
<td colspan="3" class="text-right">${{ number_format($item['total'],2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@foreach ($o->product_services($po) as $so)
|
@foreach(Service::whereIn('id',$item['services'])->get() as $so)
|
||||||
<tr id="invoice-service-items" class="invoice-services @if($o->products()->count() > 1) d-print-table-row @endif">
|
<tr id="invoice-service-items" class="invoice-services @if($item['services']->count() > 1) d-print-table-row @endif">
|
||||||
<td colspan="2"> </td>
|
<td colspan="2"> </td>
|
||||||
<td colspan="2">Service: <strong>{{ $so->sid }}: [{{ $so->name }}]</strong></td>
|
<td colspan="2">Service: <strong>{{ $so->sid }}: [{{ $so->name }}]</strong></td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td class="text-right">${{ number_format($o->product_service_items($po,$so)->sum('total'),$o->currency()->rounding) }}</td>
|
<td class="text-right">${{ number_format($o->product_service_items($item['product'],$so)->sum('total'),2) }}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@foreach ($o->product_service_items($po,$so) as $io)
|
@foreach($o->product_service_items($item['product'],$so) as $io)
|
||||||
<tr class="invoice-service-items d-print-table-row">
|
<tr class="invoice-service-items d-print-table-row">
|
||||||
<td colspan="2"> </td>
|
<td colspan="2"> </td>
|
||||||
<td width="5%"> </td>
|
<td width="5%"> </td>
|
||||||
<td>{{ $io->item_type_name }}</td>
|
<td>{{ $io->item_type_name }}</td>
|
||||||
<td class="text-right">${{ number_format($io->total,$o->currency()->rounding) }}</td>
|
<td class="text-right">${{ number_format($io->total,2) }}</td>
|
||||||
<td colspan="2"> </td>
|
<td colspan="2"> </td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -141,7 +145,7 @@
|
|||||||
<p class="lead">Payment Methods:</p>
|
<p class="lead">Payment Methods:</p>
|
||||||
|
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
@foreach (\App\Models\Checkout::available() as $cho)
|
@foreach(Checkout::available() as $cho)
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 50px;"><i class="fa-2x fa-fw {{ $cho->icon }}"></i></td>
|
<td style="width: 50px;"><i class="fa-2x fa-fw {{ $cho->icon }}"></i></td>
|
||||||
<td>{{ $cho->name }}</td>
|
<td>{{ $cho->name }}</td>
|
||||||
@ -152,7 +156,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p class="text-muted well well-sm no-shadow" style="position: absolute;bottom: 0;left: 0;">
|
<p class="text-muted well well-sm no-shadow" style="position: absolute;bottom: 0;left: 0;">
|
||||||
{!! $o->invoice_text !!}
|
{{ config('osb.invoice_text') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -161,12 +165,12 @@
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="3" style="width:50%">Subtotal:</th>
|
<th colspan="3" style="width:50%">Subtotal:</th>
|
||||||
<td colspan="2" class="text-right">${{ number_format($o->sub_total,$o->currency()->rounding) }}</td>
|
<td colspan="2" class="text-right">${{ number_format($o->sub_total,2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th>Tax (GST 10%)</th>
|
<th>Tax (GST 10%)</th>
|
||||||
<td colspan="2" class="text-right">${{ number_format($o->total_tax,$o->currency()->rounding) }}</td>
|
<td colspan="2" class="text-right">${{ number_format($o->tax_total,2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
@ -176,23 +180,23 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">Total:</th>
|
<th colspan="2">Total:</th>
|
||||||
<td colspan="2" class="text-right">${{ number_format($o->total,$o->currency()->rounding) }}</td>
|
<td colspan="2" class="text-right">${{ number_format($o->total,2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@if($o->id)
|
@if($o->id)
|
||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th>Payments To Clear:</th>
|
<th>Payments To Clear:</th>
|
||||||
<td colspan="2" class="text-right">${{ number_format($o->paid_pending,$o->currency()->rounding) }}</td>
|
<td colspan="2" class="text-right">${{ number_format($o->paid_pending,2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th>Payments:</th>
|
<th>Payments:</th>
|
||||||
<td>#{{ $o->payments->pluck('id')->join(', #') }}</td>
|
<td>#{{ $o->payment_items_active->pluck('payment_id')->join(', #') }}</td>
|
||||||
<td class="text-right">${{ number_format($o->paid,$o->currency()->rounding) }}</td>
|
<td class="text-right">${{ number_format($o->paid,2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="font-size: 145%">
|
<tr style="font-size: 145%">
|
||||||
<th colspan="2">Invoice Due:</th>
|
<th colspan="2">Invoice Due:</th>
|
||||||
<td colspan="2" class="text-right">${{ number_format($o->due,$o->currency()->rounding) }}</td>
|
<td colspan="2" class="text-right">${{ number_format($o->due,2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endif
|
@endif
|
||||||
</table>
|
</table>
|
||||||
|
Loading…
Reference in New Issue
Block a user