diff --git a/app/Models/Account.php b/app/Models/Account.php
index df71a29..a233d68 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -102,7 +102,7 @@ class Account extends Model implements IDs
public function invoices()
{
return $this->hasMany(Invoice::class)
- ->with(['items.taxes','paymentitems.payment']);
+ ->with(['items.taxes','payment_items.payment']);
}
/**
diff --git a/app/Models/Country.php b/app/Models/Country.php
index 781e823..155cac7 100644
--- a/app/Models/Country.php
+++ b/app/Models/Country.php
@@ -10,14 +10,6 @@ class Country extends Model
/* RELATIONS */
- /**
- * The currency this country belongs to
- */
- public function currency()
- {
- return $this->belongsTo(Currency::class);
- }
-
public function taxes()
{
return $this->hasMany(Tax::class);
diff --git a/app/Models/Currency.php b/app/Models/Currency.php
deleted file mode 100644
index 22195b4..0000000
--- a/app/Models/Currency.php
+++ /dev/null
@@ -1,29 +0,0 @@
-hasOne(Country::class);
- }
-
- /* METHODS */
-
- public function round($value,$mode=self::ROUND_HALF_UP)
- {
- return round($value,$this->rounding,$mode);
- }
-}
\ No newline at end of file
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index 560b522..323f71a 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -7,6 +7,7 @@ use Clarkeash\Doorman\Facades\Doorman;
use Clarkeash\Doorman\Models\Invite;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
+use Illuminate\Support\Collection;
use Leenooks\Casts\LeenooksCarbon;
use Leenooks\Traits\ScopeActive;
@@ -19,16 +20,16 @@ use App\Traits\PushNew;
* Invoices that belong to an Account
*
* Attributes for services:
+ * + created_at : Date the invoice was created
* + due : Balance due on an invoice
- * + due_date : Date the invoice is due
- * + invoice_date : Date the invoice was created
+ * + due_at : Date the invoice is due
* + lid : Local ID for invoice
* + paid : Total of payments received (excluding pending)
* + paid_date : Date the invoice was paid in full
* + paid_pending : Total of pending payments received
* + sid : System ID for invoice
* + sub_total : Invoice sub-total before taxes
- * + total_tax : Invoices total of taxes
+ * + tax_total : Invoices total of taxes
* + total : Invoice total
*
* @package App\Models
@@ -97,13 +98,13 @@ class Invoice extends Model implements IDs
// Array of items that can be updated with PushNew
protected $pushable = ['items'];
- /*
protected $with = [
- 'account.country.currency',
- 'items.taxes',
- 'paymentitems'
+ 'items_active:id,start_at,stop_at,quantity,price_base,discount_amt,item_type,product_id,service_id,invoice_id',
+ 'items_active.taxes:id,invoice_item_id,amount,tax_id',
+ '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 */
@@ -181,29 +182,58 @@ class Invoice extends Model implements IDs
/* RELATIONS */
+ /**
+ * Account this invoice belongs to
+ */
public function account()
{
return $this->belongsTo(Account::class);
}
+ /**
+ * Items on this invoice belongs to
+ */
public function items()
{
return $this->hasMany(InvoiceItem::class)
- ->where('active',TRUE)
->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()
{
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);
}
+ 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()
{
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 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
* excluding pending payments
@@ -269,9 +274,7 @@ class Invoice extends Model implements IDs
*/
public function getPaidAttribute(): float
{
- return $this->paymentitems
- ->filter(function($item) { return ! $item->payment->pending_status && $item->payment->active; })
- ->sum('amount');
+ return $this->payment_items_active->sum('amount');
}
/**
@@ -282,11 +285,13 @@ class Invoice extends Model implements IDs
*/
public function getPaidDateAttribute(): ?Carbon
{
+ // If the invoice still has a due balance, its not paid
if ($this->getDueAttribute())
return NULL;
- $o = $this->payments
- ->filter(function($item) { return ! $item->pending_status; })
+ $o = $this
+ ->payments
+ ->filter(fn($item)=>(! $item->pending_status))
->last();
return $o?->paid_at;
@@ -299,8 +304,8 @@ class Invoice extends Model implements IDs
*/
public function getPaidPendingAttribute(): float
{
- return $this->paymentitems
- ->filter(function($item) { return $item->payment->pending_status; })
+ return $this->payment_items
+ ->filter(fn($item)=>$item->payment->pending_status)
->sum('amount');
}
@@ -311,28 +316,17 @@ class Invoice extends Model implements IDs
*/
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
*
* @return float
- * @deprecated use getTotalTaxAttribute();
*/
public function getTaxTotalAttribute(): float
{
- return $this->getTotalTaxAttribute();
- }
-
- /**
- * Get the invoices taxes total
- *
- * @return float
- */
- public function getTotalTaxAttribute(): float
- {
- return $this->items->where('active',TRUE)->sum('tax');
+ return $this->items_active->sum('tax');
}
/**
@@ -342,17 +336,11 @@ class Invoice extends Model implements IDs
*/
public function getTotalAttribute(): float
{
- return $this->getSubTotalAttribute()+$this->getTotalTaxAttribute();
+ return $this->getSubTotalAttribute()+$this->getTaxTotalAttribute();
}
/* 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
*
@@ -366,57 +354,37 @@ class Invoice extends Model implements IDs
$tokendate = ($x=Carbon::now()->addDays(21)) > ($y=$this->due_at->addDays(21)) ? $x : $y;
// Extend the expire date
- if ($io AND ($tokendate > $io->valid_until)) {
+ if ($io && ($tokendate > $io->valid_until)) {
$io->valid_until = $tokendate;
$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]);
}
- // @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();
-
- foreach ($this->items->groupBy('product_id') as $o) {
- $po = $o->first()->product;
- $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');
+ return $this
+ ->items_active
+ ->filter(fn($item)=>($item->product_id === $po->id) && ($item->service_id === $so->id))
+ ->sortBy('item_type');
}
/**
@@ -439,6 +407,7 @@ class Invoice extends Model implements IDs
*
* @param array $options
* @return bool
+ * @todo Change this to a saving event
*/
public function save(array $options = [])
{
@@ -453,4 +422,29 @@ class Invoice extends Model implements IDs
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');
+ }
}
\ No newline at end of file
diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php
index ed3ff91..c1a9abb 100644
--- a/app/Models/InvoiceItem.php
+++ b/app/Models/InvoiceItem.php
@@ -125,7 +125,7 @@ class InvoiceItem extends Model
*/
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));
}
/**
diff --git a/app/Models/Site.php b/app/Models/Site.php
index 360e3ea..d46b7c1 100644
--- a/app/Models/Site.php
+++ b/app/Models/Site.php
@@ -44,11 +44,6 @@ class Site extends Model
return $this->belongsTo(Country::class);
}
- public function currency()
- {
- return $this->belongsTo(Currency::class);
- }
-
public function details()
{
return $this->hasMany(SiteDetail::class,NULL,'site_id');
diff --git a/config/osb.php b/config/osb.php
index 5c2f2fd..56d8e5e 100644
--- a/config/osb.php
+++ b/config/osb.php
@@ -2,4 +2,5 @@
return [
'language_id' => 1,
+ 'invoice_text' => 'Thank you for using our Internet Services.',
];
\ No newline at end of file
diff --git a/resources/views/email/user/invoice.blade.php b/resources/views/email/user/invoice.blade.php
index 8d1160b..5c78e0c 100644
--- a/resources/views/email/user/invoice.blade.php
+++ b/resources/views/email/user/invoice.blade.php
@@ -6,8 +6,8 @@ A new invoice has been generated on your account. A summary of that invoice is b
@component('mail::table')
| # | ID | Name | Amount |
| -: | - |:-----| ------:|
-@foreach ($invoice->products() as $po)
-| {{ $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) }} |
+@foreach ($invoice->summary_products() as $item)
+| {{ $item['services']->count() }} | {{ $item['product']->lid }} | {{ $item['product']->name }} | ${{ number_format($item['total'],2) }} |
@endforeach
||| Sub Total | ${{ number_format($invoice->sub_total,2) }} |
||| Tax | ${{ number_format($invoice->tax_total,2) }} |
diff --git a/resources/views/theme/backend/adminlte/a/payment/widgets/invoices.blade.php b/resources/views/theme/backend/adminlte/a/payment/widgets/invoices.blade.php
index 00cbb09..9fccc01 100644
--- a/resources/views/theme/backend/adminlte/a/payment/widgets/invoices.blade.php
+++ b/resources/views/theme/backend/adminlte/a/payment/widgets/invoices.blade.php
@@ -3,7 +3,7 @@
@if(($x=$o->invoices()
->where('active',TRUE)
->orderBy('due_at')
- ->with(['items.taxes','paymentitems.payment','account'])
+ ->with(['items.taxes','payment_items.payment','account'])
->get()
->filter(function($item) use ($pid) { return $item->due > 0 || $item->payments->search(function($item) use ($pid) { return $item->id == $pid; }) !== FALSE; }))->count())
@@ -22,12 +22,12 @@
@foreach ($x as $io)
{{ $io->sid }} |
- {{ $io->invoice_date->format('Y-m-d') }} |
+ {{ $io->created_at->format('Y-m-d') }} |
{{ $io->due_at->format('Y-m-d') }} |
{{ number_format($io->total,2) }} |
{{ number_format($io->due,2) }} |
-
+
|
@endforeach
diff --git a/resources/views/theme/backend/adminlte/account/widget/service_active.blade.php b/resources/views/theme/backend/adminlte/account/widget/service_active.blade.php
index fd7e8e6..a1d1d19 100644
--- a/resources/views/theme/backend/adminlte/account/widget/service_active.blade.php
+++ b/resources/views/theme/backend/adminlte/account/widget/service_active.blade.php
@@ -1,4 +1,8 @@
+@php
+ $o->load(['services_active.invoiced_service_items_active_recent']);
+@endphp
+
- @if (($x=$o->services->where('active',TRUE))->count())
+ @if (($x=$o->services_active)->count())
diff --git a/resources/views/theme/backend/adminlte/invoice/view.blade.php b/resources/views/theme/backend/adminlte/invoice/view.blade.php
index 05f0a22..82e5270 100644
--- a/resources/views/theme/backend/adminlte/invoice/view.blade.php
+++ b/resources/views/theme/backend/adminlte/invoice/view.blade.php
@@ -1,3 +1,7 @@
+@php
+ use App\Models\{Checkout,Service};
+@endphp
+
@extends('adminlte::layouts.app')
@@ -49,7 +53,7 @@
{!! $o->account->address->join('
') !!}
Email: {{ $o->account->user->email }}
- @if ($o->account->phone)
+ @if($o->account->phone)
Phone: {{ $o->account->phone }}
@endif
@@ -58,7 +62,7 @@
- Issue Date: | {{ $o->invoice_date->format('Y-m-d') }} |
+ Issue Date: | {{ $o->created_at->format('Y-m-d') }} |
Account: | {{ $o->account->sid }} |
@@ -70,12 +74,12 @@
Payment Due: | {{ $o->due_at->format('Y-m-d') }} |
- This Invoice Due: | ${{ number_format($o->total,$o->currency()->rounding) }} |
+ This Invoice Due: | ${{ number_format($o->total,2) }} |
{{--
- Total Account Due: | ${{ number_format($o->account->due,$o->currency()->rounding) }} |
+ Total Account Due: | ${{ number_format($o->account->due,2) }} |
--}}
@@ -97,29 +101,29 @@
- @foreach ($o->products() as $po)
+ @foreach($o->summary_products() as $item)
- {{ $po->count }} |
- #{{ $po->lid }} |
- {{ $po->name }} |
- ${{ number_format($o->items->filter(function($item) use ($po) {return $item->product_id == $po->id; })->sum('total'),$o->currency()->rounding) }} |
+ {{ $item['services']->count() }} |
+ #{{ $item['product']->lid }} |
+ {{ $item['product']->name }} |
+ ${{ number_format($item['total'],2) }} |
- @foreach ($o->product_services($po) as $so)
-
+ @foreach(Service::whereIn('id',$item['services'])->get() as $so)
+
|
Service: {{ $so->sid }}: [{{ $so->name }}] |
|
- ${{ number_format($o->product_service_items($po,$so)->sum('total'),$o->currency()->rounding) }} |
+ ${{ number_format($o->product_service_items($item['product'],$so)->sum('total'),2) }} |
|
- @foreach ($o->product_service_items($po,$so) as $io)
+ @foreach($o->product_service_items($item['product'],$so) as $io)
|
|
{{ $io->item_type_name }} |
- ${{ number_format($io->total,$o->currency()->rounding) }} |
+ ${{ number_format($io->total,2) }} |
|
@endforeach
@@ -141,18 +145,18 @@
Payment Methods:
- @foreach (\App\Models\Checkout::available() as $cho)
-
- |
- {{ $cho->name }} |
- {{ $cho->description }} |
- @includeIf('theme.backend.adminlte.payment.widget.plugin.'.strtolower($cho->plugin),['o'=>$cho]) |
-
- @endforeach
+ @foreach(Checkout::available() as $cho)
+
+ |
+ {{ $cho->name }} |
+ {{ $cho->description }} |
+ @includeIf('theme.backend.adminlte.payment.widget.plugin.'.strtolower($cho->plugin),['o'=>$cho]) |
+
+ @endforeach
- {!! $o->invoice_text !!}
+ {{ config('osb.invoice_text') }}
@@ -161,12 +165,12 @@
Subtotal: |
- ${{ number_format($o->sub_total,$o->currency()->rounding) }} |
+ ${{ number_format($o->sub_total,2) }} |
|
Tax (GST 10%) |
- ${{ number_format($o->total_tax,$o->currency()->rounding) }} |
+ ${{ number_format($o->tax_total,2) }} |
|
@@ -176,23 +180,23 @@
Total: |
- ${{ number_format($o->total,$o->currency()->rounding) }} |
+ ${{ number_format($o->total,2) }} |
@if($o->id)
|
Payments To Clear: |
- ${{ number_format($o->paid_pending,$o->currency()->rounding) }} |
+ ${{ number_format($o->paid_pending,2) }} |
|
Payments: |
- #{{ $o->payments->pluck('id')->join(', #') }} |
- ${{ number_format($o->paid,$o->currency()->rounding) }} |
+ #{{ $o->payment_items_active->pluck('payment_id')->join(', #') }} |
+ ${{ number_format($o->paid,2) }} |
Invoice Due: |
- ${{ number_format($o->due,$o->currency()->rounding) }} |
+ ${{ number_format($o->due,2) }} |
@endif