From e1a4db700f03496a6c6fb7d7c0fb8d19356ea00d Mon Sep 17 00:00:00 2001 From: Deon George Date: Fri, 22 Apr 2022 14:41:18 +1000 Subject: [PATCH] Removed redundant functions from Invoice, optimised Invoice tables --- app/Http/Controllers/AdminController.php | 2 +- app/Http/Controllers/HomeController.php | 2 +- .../Controllers/User/AccountController.php | 6 +- app/Mail/InvoiceEmail.php | 2 +- app/Models/Invoice.php | 204 ++++++++---------- app/Models/InvoiceItem.php | 110 ++++------ app/Models/InvoiceItemTax.php | 17 +- app/Models/Service.php | 95 +++----- app/Models/Service/SSL.php | 5 +- app/Models/Service/Type.php | 15 +- app/Models/User.php | 20 +- ...022_04_22_122640_rename_invoice_tables.php | 124 +++++++++++ .../widgets/broadband/update.blade.php | 2 +- .../a/service/widgets/internal.blade.php | 60 ++---- .../common/invoice/widget/list.blade.php | 4 +- .../adminlte/r/invoice/widgets/due.blade.php | 6 +- .../r/service/order/provision_plan.blade.php | 2 +- .../backend/adminlte/u/invoice/home.blade.php | 4 +- .../adminlte/u/invoice/widgets/due.blade.php | 6 +- .../adminlte/u/invoice/widgets/list.blade.php | 8 +- .../u/service/widgets/information.blade.php | 10 +- tests/Feature/InvoiceTest.php | 6 +- 22 files changed, 361 insertions(+), 349 deletions(-) create mode 100644 database/migrations/2022_04_22_122640_rename_invoice_tables.php diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index ea34afa..fa2a1d0 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -97,7 +97,7 @@ class AdminController extends Controller if (collect($value)->sum() > $request->post('total_amt')) $fail('Allocation is greater than payment total.'); }], - 'invoices.*.id' => 'nullable|exists:ab_invoice,id', + 'invoices.*.id' => 'nullable|exists:invoices,id', ]); if (! $o->exists) { diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 0984756..28f0fef 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -54,7 +54,7 @@ class HomeController extends Controller */ public function invoice_pdf(Invoice $o) { - return PDF::loadView('u.invoice.home',['o'=>$o])->stream(sprintf('%s.pdf',$o->invoice_account_id)); + return PDF::loadView('u.invoice.home',['o'=>$o])->stream(sprintf('%s.pdf',$o->sid)); } /** diff --git a/app/Http/Controllers/User/AccountController.php b/app/Http/Controllers/User/AccountController.php index add8640..7655282 100644 --- a/app/Http/Controllers/User/AccountController.php +++ b/app/Http/Controllers/User/AccountController.php @@ -24,13 +24,13 @@ class AccountController extends Controller }); // Get our invoice due date for this invoice - $io->due_date = $s->min(function($item) { return $item->invoice_next; }); + $io->due_at = $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); + $io->created_at = $io->due_at->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; + $days = now()->diffInDays($io->due_at)+1+7; foreach ($s as $so) { if ($so->isInvoiceDueSoon($days)) diff --git a/app/Mail/InvoiceEmail.php b/app/Mail/InvoiceEmail.php index cc3bba8..1dfdbb6 100644 --- a/app/Mail/InvoiceEmail.php +++ b/app/Mail/InvoiceEmail.php @@ -38,7 +38,7 @@ class InvoiceEmail extends Mailable ->subject(sprintf( 'Invoice: %s - Total: $%s - Due: %s', $this->invoice->id, number_format($this->invoice->total,2), - $this->invoice->date_due)) + $this->invoice->due_at->format('Y-m-d'))) ->with([ 'user'=>$this->invoice->account->user, 'site'=>$this->invoice->account->user->site, diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index e67934b..3ff2033 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -25,7 +25,7 @@ use App\Traits\{NextKey,PushNew}; * + paid_date : Date the invoice was paid in full * + paid_pending : Total of pending payments received * + sid : System ID for invoice - * + total_sub : Invoice sub-total before taxes + * + sub_total : Invoice sub-total before taxes * + total_tax : Invoices total of taxes * + total : Invoice total * @@ -33,17 +33,11 @@ use App\Traits\{NextKey,PushNew}; */ class Invoice extends Model implements IDs { - use NextKey,PushNew,ScopeActive; + use PushNew,ScopeActive; - const RECORD_ID = 'invoice'; - public $incrementing = FALSE; - - protected $table = 'ab_invoice'; - const CREATED_AT = 'date_orig'; - const UPDATED_AT = 'date_last'; - - protected $dates = ['date_orig','due_date']; - public $dateFormat = 'U'; + protected $dates = [ + 'due_at', + ]; public const BILL_WEEKLY = 0; public const BILL_MONTHLY = 1; @@ -56,45 +50,44 @@ class Invoice extends Model implements IDs public const BILL_FIVEYEARS = 8; /* Our available billing periods */ - // @todo change this to a function - with billing_name()? public const billing_periods = [ - 0 => [ - 'name' => 'Weekly', - 'interval' => 0.25, - ], - 1 => [ - 'name' => 'Monthly', - 'interval' => 1, - ], - 2 => [ - 'name' => 'Quarterly', - 'interval' => 3, - ], - 3 => [ - 'name' => 'Semi-Annually', - 'interval' => 6, - ], - 4 => [ - 'name' => 'Annually', - 'interval' => 12, - ], - 5 => [ - 'name' => 'Two years', - 'interval' => 24, - ], - 6 => [ - 'name' => 'Three Years', - 'interval' => 36, - ], - 7 => [ - 'name' => 'Four Years', - 'interval' => 48, - ], - 8 => [ - 'name' => 'Five Years', - 'interval' => 60, - ], - ]; + self::BILL_WEEKLY => [ + 'name' => 'Weekly', + 'interval' => 0.25, + ], + self::BILL_MONTHLY => [ + 'name' => 'Monthly', + 'interval' => 1, + ], + self::BILL_QUARTERLY => [ + 'name' => 'Quarterly', + 'interval' => 3, + ], + self::BILL_SEMI_YEARLY => [ + 'name' => 'Semi-Annually', + 'interval' => 6, + ], + self::BILL_YEARLY => [ + 'name' => 'Annually', + 'interval' => 12, + ], + self::BILL_TWOYEARS => [ + 'name' => 'Two years', + 'interval' => 24, + ], + self::BILL_THREEYEARS => [ + 'name' => 'Three Years', + 'interval' => 36, + ], + self::BILL_FOURYEARS => [ + 'name' => 'Four Years', + 'interval' => 48, + ], + SELF::BILL_FIVEYEARS => [ + 'name' => 'Five Years', + 'interval' => 60, + ], + ]; // Array of items that can be updated with PushNew protected $pushable = ['items']; @@ -164,6 +157,28 @@ class Invoice extends Model implements IDs return ceil(($contract_term ?: 1)/(Arr::get(self::billing_periods,$source.'.interval') ?: 1)); } + /* INTERFACES */ + + /** + * Invoice Local ID + * + * @return string + */ + public function getLIDAttribute(): string + { + return sprintf('%06s',$this->id); + } + + /** + * Invoice System ID + * + * @return string + */ + public function getSIDAttribute(): string + { + return sprintf('%02s-%04s-%s',$this->site_id,$this->account_id,$this->getLIDAttribute()); + } + /* RELATIONS */ public function account() @@ -206,7 +221,7 @@ class Invoice extends Model implements IDs /** * Balance due on an invoice - * @return string + * @return float */ public function getDueAttribute(): float { @@ -215,11 +230,11 @@ class Invoice extends Model implements IDs /** * @return mixed - * @deprecated use self::due_date; + * @todo Change references to due_at to use due_date */ - public function getDateDueAttribute() + public function getDueDateAttribute(): Carbon { - return $this->due_date->format('Y-m-d'); + return $this->due_at; } /** @@ -229,17 +244,7 @@ class Invoice extends Model implements IDs */ public function getInvoiceDateAttribute(): Carbon { - return $this->date_orig; - } - - /** - * Get account System ID - * @return string - * @deprecated use getSIDAttribute() - */ - public function getInvoiceAccountIdAttribute() - { - return $this->getSIDAttribute(); + return $this->created_at; } // @todo Move this to a site configuration @@ -248,16 +253,6 @@ class Invoice extends Model implements IDs return sprintf('Thank you for using %s for your Internet Services.',config('site')->site_name); } - /** - * Invoice Local ID - * - * @return string - */ - public function getLIDAttribute(): string - { - return sprintf('%06s',$this->id); - } - /** * Total of payments received for this invoice * excluding pending payments @@ -286,7 +281,7 @@ class Invoice extends Model implements IDs ->filter(function($item) { return ! $item->pending_status; }) ->last(); - return $o ? $o->payment_date : NULL; + return $o?->payment_date; } /** @@ -301,44 +296,12 @@ class Invoice extends Model implements IDs ->sum('alloc_amt'); } - /** - * Total of pending payments received for this invoice - * - * @return mixed - * @deprecated use getPaidPendingAttribute() - */ - public function getPendingPaidAttribute(): float - { - return $this->getPaidPendingAttribute(); - } - - /** - * Invoice System ID - * - * @return string - */ - public function getSIDAttribute(): string - { - return sprintf('%02s-%04s-%s',$this->site_id,$this->account_id,$this->getLIDAttribute()); - } - /** * Get invoice subtotal before taxes * * @return float - * @deprecated use getTotalSubAttribute() */ public function getSubTotalAttribute(): float - { - return $this->getTotalSubAttribute(); - } - - /** - * Get invoice subtotal before taxes - * - * @return float - */ - public function getTotalSubAttribute(): float { return $this->items->where('active',TRUE)->sum('sub_total'); } @@ -371,9 +334,12 @@ class Invoice extends Model implements IDs */ public function getTotalAttribute(): float { - return $this->getTotalSubAttribute()+$this->getTotalTaxAttribute(); + return $this->getSubTotalAttribute()+$this->getTotalTaxAttribute(); } + /* METHODS */ + + // @todo This shouldnt be here - current should be handled at an account level. public function currency() { return $this->account->country->currency; @@ -389,7 +355,7 @@ class Invoice extends Model implements IDs // Re-use an existing code $io = Invite::where('for',$this->account->user->email)->first(); - $tokendate = ($x=Carbon::now()->addDays(21)) > ($y=$this->due_date->addDays(21)) ? $x : $y; + $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)) { @@ -402,12 +368,12 @@ class Invoice extends Model implements IDs return url('u/invoice',[$this->id,'email',$code]); } + // @todo document public function products() { $return = collect(); - foreach ($this->items->groupBy('product_id') as $o) - { + foreach ($this->items->groupBy('product_id') as $o) { $po = $o->first()->product; $po->count = count($o->pluck('service_id')->unique()); @@ -419,6 +385,7 @@ class Invoice extends Model implements IDs }); } + // @todo document public function product_services(Product $po) { $return = collect(); @@ -436,6 +403,7 @@ class Invoice extends Model implements IDs 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) { @@ -449,28 +417,28 @@ class Invoice extends Model implements IDs * @todo Ugly hack to update reminders */ public function reminders(string $key) { - $r = unserialize($this->reminders); + $r = json_decode($this->reminders); if (! Arr::get($r,$key)) { $r[$key] = time(); - return serialize($r); + return json_encode($r); } } /** - * Automatically set our due_date at save time. + * Automatically set our due_at at save time. * * @param array $options * @return bool */ public function save(array $options = []) { // Automatically set the date_due attribute for new records. - if (! $this->exists AND ! $this->due_date) { - $this->due_date = $this->items->min('date_start'); + if (! $this->exists AND ! $this->due_at) { + $this->due_at = $this->items->min('start_at'); // @todo This 7 days should be sysetm configurable - if (($x=Carbon::now()->addDay(7)) > $this->due_date) - $this->due_date = $x; + if (($x=Carbon::now()->addDay(7)) > $this->due_at) + $this->due_at = $x; } return parent::save($options); diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php index 0425c0c..becc6d7 100644 --- a/app/Models/InvoiceItem.php +++ b/app/Models/InvoiceItem.php @@ -5,9 +5,8 @@ namespace App\Models; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Arr; -use Leenooks\Carbon; +use Leenooks\Carbon as LeenooksCarbon; -use App\Traits\NextKey; use App\Traits\PushNew; /** @@ -15,24 +14,18 @@ use App\Traits\PushNew; * Items that belong on an invoice * * Attributes for services: - * + date_start : Start date - * + date_stop : End date * + sub_total : Value of item * + tax : Total of all taxes * + total : Total including taxes */ class InvoiceItem extends Model { - use NextKey,PushNew; - const RECORD_ID = 'invoice_item'; - public $incrementing = FALSE; + use PushNew; - protected $table = 'ab_invoice_item'; - const CREATED_AT = 'date_orig'; - const UPDATED_AT = 'date_last'; - - protected $dates = ['date_start','date_stop']; - public $dateFormat = 'U'; + protected $dates = [ + 'start_at', + 'stop_at', + ]; // Array of items that can be updated with PushNew protected $pushable = ['taxes']; @@ -60,11 +53,6 @@ class InvoiceItem extends Model return $this->belongsTo(Invoice::class); } - /** - * Product for this item - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ public function product() { return $this->belongsTo(Product::class); @@ -82,73 +70,51 @@ class InvoiceItem extends Model /* ATTRIBUTES */ - /** - * Start date for the invoice item line - * - * @param $value - * @return Carbon - * @throws \Exception - */ - public function getDateStartAttribute($value) - { - if (! is_null($value)) - return Carbon::createFromTimestamp($value); - } - - /** - * End date for the invoice item line - * - * @param $value - * @return Carbon - * @throws \Exception - */ - public function getDateStopAttribute($value) - { - if (! is_null($value)) - return Carbon::createFromTimestamp($value); - } - public function getItemTypeNameAttribute() { - // @todo use self::type - $types = [ - 1=>'Hardware', // * - 2=>'Service Relocation Fee', // * Must have corresponding SERVICE_ID - 3=>'Service Change', // * Must have corresponding SERVICE_ID - 4=>'Service Connection', // * Must have corresponding SERVICE_ID - 6=>'Service Cancellation', // * Must have corresponding SERVICE_ID - 7=>'Extra Product/Service Charge', // * Service Billing in advance, Must have corresponding SERVICE_ID - 8=>'Product Addition', // * Additional Product Customisation, Must have corresponding SERVICE_ID - 120=>'Credit/Debit Transfer', // * SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL : INVOICE_ID is NOT NULL - 123=>'Shipping', - 124=>'Late Payment Fee', // * SERVICE_ID is NULL, MODULE_ID = CHECKOUT MODULE, - 125=>'Payment Fee', // * SERVICE_ID is NULL, MODULE_ID = CHECKOUT MODULE, MODULE_REF = CHECKOUT NAME - 126=>'Other', // * MODEL_ID should be a module - 127=>'Rounding', // * SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL - ]; - - switch ($this->item_type) - { + switch ($this->item_type) { // * Line Charge Topic on Invoice. case 0: - if ($this->date_start) + if ($this->start_at) return sprintf('%s [%s]','Product/Service', - (($this->date_start == $this->date_stop) || (! $this->date_stop)) ? $this->date_start->format('Y-m-d') : sprintf('%s -> %s',$this->date_start->format('Y-m-d'),$this->date_stop->format('Y-m-d'))); + (($this->start_at == $this->stop_at) || (! $this->stop_at)) ? $this->start_at->format('Y-m-d') : sprintf('%s -> %s',$this->start_at->format('Y-m-d'),$this->stop_at->format('Y-m-d'))); else return 'Product/Service'; // * Excess Service Item, of item 0, must have corresponding SERVICE_ID case 5: return sprintf('%s [%s] (%s)','Excess Usage', - $this->date_start == $this->date_stop ? $this->date_start->format('Y-m-d') : sprintf('%s -> %s',$this->date_start->format('Y-m-d'),$this->date_stop->format('Y-m-d')), + $this->start_at == $this->stop_at ? $this->start_at->format('Y-m-d') : sprintf('%s -> %s',$this->start_at->format('Y-m-d'),$this->stop_at->format('Y-m-d')), $this->module_text() ); default: - return ($this->module_id == 30 ? 'Additional Charge: ' : '').Arr::get($types,$this->item_type,'Unknown'); + return ($this->module_id == 30 ? 'Additional Charge: ' : '').Arr::get(self::type,$this->item_type,'Unknown'); } } + /** + * We need to cast some dates to LeenooksCarbon to get access to startOfHalf()/endOfHalf() methods + * + * @param $value + * @return LeenooksCarbon + */ + public function getStartAtAttribute($value): LeenooksCarbon + { + return LeenooksCarbon::create($value); + } + + /** + * We need to cast some dates to LeenooksCarbon to get access to startOfHalf()/endOfHalf() methods + * + * @param $value + * @return LeenooksCarbon + */ + public function getStopAtAttribute($value): LeenooksCarbon + { + return LeenooksCarbon::create($value); + } + /** * Sub total of item * @@ -190,8 +156,7 @@ class InvoiceItem extends Model if ($this->exists) throw new \Exception('Refusing to add Taxes to existing record'); - foreach($taxes as $to) - { + foreach($taxes as $to) { $iit = new InvoiceItemTax; $iit->tax_id = $to->id; $iit->amount = round($this->quantity*$this->price_base*$to->rate,3); @@ -200,15 +165,12 @@ class InvoiceItem extends Model } } - public function module_text() - { - switch ($this->module_id) - { + 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); } - } } \ No newline at end of file diff --git a/app/Models/InvoiceItemTax.php b/app/Models/InvoiceItemTax.php index eb01ca7..2030070 100644 --- a/app/Models/InvoiceItemTax.php +++ b/app/Models/InvoiceItemTax.php @@ -4,23 +4,12 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; -use App\Traits\NextKey; use App\Traits\PushNew; class InvoiceItemTax extends Model { - use NextKey,PushNew; - const RECORD_ID = 'invoice_item_tax'; - public $incrementing = FALSE; + use PushNew; - protected $table = 'ab_invoice_item_tax'; - const CREATED_AT = 'date_orig'; - const UPDATED_AT = NULL; - - public $dateFormat = 'U'; - - public function invoice_item() - { - return $this->belongsTo(InvoiceItem::class); - } + protected $table = 'invoice_item_taxes'; + public $timestamps = FALSE; } \ No newline at end of file diff --git a/app/Models/Service.php b/app/Models/Service.php index c175b6e..083ce95 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -318,7 +318,7 @@ class Service extends Model implements IDs { $query = $this->hasMany(InvoiceItem::class) ->where('item_type','=',0) - ->orderBy('date_start'); + ->orderBy('start_at'); // @todo Change to $query->active(); if ($active) @@ -334,14 +334,14 @@ class Service extends Model implements IDs { $query = $this->hasManyThrough(Invoice::class,InvoiceItem::class,NULL,'id',NULL,'invoice_id') ->distinct('id') - ->where('ab_invoice.site_id','=',$this->site_id) - ->where('ab_invoice_item.site_id','=',$this->site_id) - ->orderBy('date_orig') - ->orderBy('due_date'); + ->where('invoices.site_id','=',$this->site_id) + ->where('invoice_items.site_id','=',$this->site_id) + ->orderBy('created_at') + ->orderBy('due_at'); if ($active) - $query->where('ab_invoice_item.active','=',TRUE) - ->where('ab_invoice.active','=',TRUE); + $query->where('invoice_items.active','=',TRUE) + ->where('invoices.active','=',TRUE); return $query; } @@ -469,49 +469,7 @@ class Service extends Model implements IDs */ public function getBillingMonthlyPriceAttribute(): float { - $d = 1; - switch ($this->recur_schedule) { - case Invoice::BILL_WEEKLY: - $d = 12/52; - break; - - case Invoice::BILL_MONTHLY: - $d = 1; - break; - - case Invoice::BILL_QUARTERLY: - $d = 3; - break; - - case Invoice::BILL_SEMI_YEARLY: - $d = 6; - break; - - case Invoice::BILL_YEARLY: - $d = 12; - break; - - case Invoice::BILL_TWOYEARS: - $d = 24; - break; - - case Invoice::BILL_THREEYEARS: - $d = 36; - break; - - case Invoice::BILL_FOURYEARS: - $d = 48; - break; - - case Invoice::BILL_FIVEYEARS: - $d = 60; - break; - - default: - throw new Exception('Unknown recur_schedule'); - } - - return number_format($this->getBillingChargeAttribute()/$d,2); + return number_format($this->getBillingChargeAttribute()/Arr::get(Invoice::billing_periods,$this->recur_schedule.'.interval',1),2); } /** @@ -593,7 +551,18 @@ class Service extends Model implements IDs $last = $this->getInvoiceToAttribute(); return $last ? $last->addDay() - : ($this->date_next_invoice ? $this->date_next_invoice->clone() : ($this->start_at ?: LeenooksCarbon::now())); + : ($this->invoice_next_at ? $this->invoice_next_at->clone() : ($this->start_at ?: LeenooksCarbon::now())); + } + + /** + * We need to cast some dates to LeenooksCarbon to get access to startOfHalf()/endOfHalf() methods + * + * @param $value + * @return LeenooksCarbon|null + */ + public function getInvoiceNextAtAttribute($value): ?LeenooksCarbon + { + return $value ? LeenooksCarbon::create($value) : NULL; } /** @@ -674,7 +643,7 @@ class Service extends Model implements IDs } /** - * Determine how much quantity (at the charge rate) is requite for the next invoice + * Determine how much quantity (at the charge rate) is required for the next invoice * * @return float * @throws Exception @@ -734,12 +703,12 @@ class Service extends Model implements IDs /** * Get the date that the service has been invoiced to * - * @return Carbon|null + * @return LeenooksCarbon|null */ - public function getInvoiceToAttribute(): ?Carbon + public function getInvoiceToAttribute(): ?LeenooksCarbon { $result = ($x=$this->invoice_items->filter(function($item) { return $item->item_type === 0;}))->count() - ? $x->last()->date_stop + ? $x->last()->stop_at : NULL; // For SSL Certificates, the invoice_to date is the expiry date of the Cert @@ -823,7 +792,7 @@ class Service extends Model implements IDs return $item->item_type === 0; }) ->last() - ->date_stop; + ->stop_at; } /** @@ -1228,8 +1197,8 @@ class Service extends Model implements IDs $o->item_type = 4; // @todo change to const or something $o->price_base = $this->product->getSetupChargeAttribute($this->recur_schedule,$this->account->group); //$o->recurring_schedule = $this->recur_schedule; - $o->date_start = $this->invoice_next; - $o->date_stop = $this->invoice_next; + $o->start_at = $this->invoice_next; + $o->stop_at = $this->invoice_next; $o->quantity = 1; $o->site_id = 1; // @todo @@ -1254,9 +1223,9 @@ class Service extends Model implements IDs $o->price_base = is_null($this->price) ? (is_null($this->price_override) ? $this->product->getBaseChargeAttribute($this->recur_schedule,$this->account->group) : $this->price_override) : $this->price; // @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; + $o->recur_schedule = $this->recur_schedule; + $o->start_at = $this->invoice_next; + $o->stop_at = $this->invoice_next_end; $o->quantity = $this->invoice_next_quantity; $o->site_id = 1; // @todo @@ -1277,8 +1246,8 @@ class Service extends Model implements IDs $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->start_at = $oo->date_charge; + $o->stop_at = $oo->date_charge; $o->module_id = 30; // @todo This shouldnt be hard coded $o->module_ref = $oo->id; $o->site_id = 1; // @todo diff --git a/app/Models/Service/SSL.php b/app/Models/Service/SSL.php index bd1e622..91ed9d6 100644 --- a/app/Models/Service/SSL.php +++ b/app/Models/Service/SSL.php @@ -4,6 +4,7 @@ namespace App\Models\Service; use Carbon\Carbon; use Illuminate\Support\Arr; +use Leenooks\Carbon as LeenooksCarbon; /** * Class SSL (Service) @@ -76,9 +77,9 @@ class SSL extends Type /** * Return the Certificate Expiry Date */ - public function getServiceExpireAttribute(): ?Carbon + public function getServiceExpireAttribute(): ?LeenooksCarbon { - return $this->cert ? Carbon::createFromTimestamp($this->crt_parse->get('validTo_time_t')) : NULL; + return $this->cert ? LeenooksCarbon::createFromTimestamp($this->crt_parse->get('validTo_time_t')) : NULL; } /** diff --git a/app/Models/Service/Type.php b/app/Models/Service/Type.php index 070e1d6..c953a2e 100644 --- a/app/Models/Service/Type.php +++ b/app/Models/Service/Type.php @@ -2,8 +2,8 @@ namespace App\Models\Service; -use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; +use Leenooks\Carbon as LeenooksCarbon; use App\Interfaces\ServiceItem; use App\Models\{Account,Service}; @@ -63,7 +63,7 @@ abstract class Type extends Model implements ServiceItem return $this->service->offering->contract_term; } - public function getServiceExpireAttribute(): ?Carbon + public function getServiceExpireAttribute(): ?LeenooksCarbon { return $this->expire_at ?: $this->service->invoice_next_at; } @@ -80,6 +80,17 @@ abstract class Type extends Model implements ServiceItem /* ATTRIBUTES */ + /** + * We need to cast some dates to LeenooksCarbon to get access to startOfHalf()/endOfHalf() methods + * + * @param $value + * @return LeenooksCarbon + */ + public function getExpireAtAttribute($value): LeenooksCarbon + { + return LeenooksCarbon::create($value); + } + public function getTypeAttribute() { return strtolower((new \ReflectionClass($this))->getShortName()); diff --git a/app/Models/User.php b/app/Models/User.php index b2e54f8..accb285 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -333,16 +333,16 @@ class User extends Authenticatable implements IDs */ private function query_invoice_items() { - return DB::table('ab_invoice_item') + return DB::table('invoice_items') ->select([ 'invoice_id', - DB::raw('ab_invoice_item.id AS invoice_item_id'), - DB::raw('IFNULL(ab_invoice_item.discount_amt,0) AS discount'), + DB::raw('invoice_items.id AS invoice_item_id'), + DB::raw('IFNULL(invoice_items.discount_amt,0) AS discount'), DB::raw('ROUND(CAST(quantity*price_base AS decimal(8,2)),2) AS base'), - DB::raw('ROUND(ab_invoice_item_tax.amount,2) AS tax'), + DB::raw('ROUND(invoice_item_taxes.amount,2) AS tax'), ]) - ->leftjoin('ab_invoice_item_tax',['ab_invoice_item_tax.invoice_item_id'=>'ab_invoice_item.id']) + ->leftjoin('invoice_item_taxes',['invoice_item_taxes.invoice_item_id'=>'invoice_items.id']) ->where('active',TRUE); } @@ -382,9 +382,9 @@ class User extends Authenticatable implements IDs DB::raw('false AS payment_fees'), ]) ->from($this->query_invoice_items(),'II') - ->join('ab_invoice',['ab_invoice.id'=>'II.invoice_id']) + ->join('invoices',['invoices.id'=>'II.invoice_id']) ->whereIN('account_id',$this->accounts->pluck('id')) - ->where('ab_invoice.active',TRUE) + ->where('invoices.active',TRUE) ->groupBy(['invoice_id']); $payments = (new Payment) @@ -420,8 +420,8 @@ class User extends Authenticatable implements IDs ->select([ 'account_id', 'id', - 'due_date', - 'date_orig', + 'due_at', + 'created_at', 'discount', 'invoice_base', 'invoice_tax', @@ -430,7 +430,7 @@ class User extends Authenticatable implements IDs 'payment_fees', DB::raw('ROUND(invoice_total-payments,2) AS balance'), ]) - ->join('ab_invoice',['ab_invoice.id'=>'invoice_id']) + ->join('invoices',['invoices.id'=>'invoice_id']) ->with(['items.taxes']) ->from($summary,'summary'); } diff --git a/database/migrations/2022_04_22_122640_rename_invoice_tables.php b/database/migrations/2022_04_22_122640_rename_invoice_tables.php new file mode 100644 index 0000000..1ef1eaa --- /dev/null +++ b/database/migrations/2022_04_22_122640_rename_invoice_tables.php @@ -0,0 +1,124 @@ +dropPrimary(); + $table->dropForeign('ab_invoice_site_id_foreign'); + $table->dropIndex('ab_invoice_site_id_foreign'); + $table->primary(['id','site_id']); + $table->dropIndex('ab_invoice_id_site_id_index'); + $table->datetime('created_at')->nullable()->after('id'); + $table->datetime('updated_at')->nullable()->after('created_at'); + $table->date('due_at')->nullable()->after('discount_amt'); + }); + + // Convert out dates + foreach (\App\Models\Invoice::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->date_orig) + $o->created_at = \Carbon\Carbon::createFromTimestamp($o->date_orig); + if ($o->date_last) + $o->updated_at = \Carbon\Carbon::createFromTimestamp($o->date_last); + if ($o->due_date) + $o->due_at = \Carbon\Carbon::createFromTimestamp($o->due_date); + if ($o->reminders) { + try { + $reminders = unserialize($o->reminders); + } catch (Exception $e) { + $reminders = unserialize(gzuncompress($o->reminders)); + } + + $o->reminders = $reminders; + } + $o->save(); + } + + Schema::table('invoices', function (Blueprint $table) { + $table->dropColumn(['date_orig','date_last','due_date']); + + $table->foreign(['account_id','site_id'])->references(['id','site_id'])->on('accounts'); + }); + + DB::statement('ALTER TABLE ab_invoice_item RENAME TO invoice_items'); + DB::statement('ALTER TABLE invoice_items MODIFY invoice_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE invoice_items MODIFY service_id int unsigned DEFAULT NULL'); + DB::statement('ALTER TABLE invoice_items MODIFY product_id int unsigned DEFAULT NULL'); + DB::statement('ALTER TABLE invoice_items MODIFY module_id int unsigned DEFAULT NULL'); + DB::statement('ALTER TABLE invoice_items MODIFY module_ref int unsigned DEFAULT NULL'); + DB::statement('ALTER TABLE invoice_items RENAME COLUMN recurring_schedule TO recur_schedule'); + + Schema::table('invoice_items', function (Blueprint $table) { + $table->dropPrimary(); + $table->dropForeign('ab_invoice_item_site_id_foreign'); + $table->dropIndex('ab_invoice_item_site_id_foreign'); + $table->primary(['id','site_id']); + $table->dropIndex('ab_invoice_item_id_site_id_index'); + $table->datetime('created_at')->nullable()->after('id'); + $table->datetime('updated_at')->nullable()->after('created_at'); + $table->date('start_at')->nullable()->after('recur_schedule'); + $table->date('stop_at')->nullable()->after('start_at'); + }); + + // Convert out dates + foreach (\App\Models\InvoiceItem::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->date_orig) + $o->created_at = \Carbon\Carbon::createFromTimestamp($o->date_orig); + if ($o->date_last) + $o->updated_at = \Carbon\Carbon::createFromTimestamp($o->date_last); + if ($o->date_start) + $o->start_at = \Carbon\Carbon::createFromTimestamp($o->date_start); + if ($o->date_stop) + $o->stop_at = \Carbon\Carbon::createFromTimestamp($o->date_stop); + $o->save(); + } + + Schema::table('invoice_items', function (Blueprint $table) { + $table->dropColumn(['date_orig','date_last','date_start','date_stop']); + + $table->foreign(['service_id','site_id'])->references(['id','site_id'])->on('services'); + $table->foreign(['invoice_id','site_id'])->references(['id','site_id'])->on('invoices'); + $table->foreign(['product_id','site_id'])->references(['id','site_id'])->on('products'); + }); + + DB::statement('ALTER TABLE ab_invoice_item_tax RENAME TO invoice_item_taxes'); + DB::statement('ALTER TABLE invoice_item_taxes MODIFY invoice_item_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE invoice_item_taxes MODIFY tax_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE invoice_item_taxes DROP PRIMARY KEY,ADD PRIMARY KEY (id,site_id)'); + + Schema::table('invoice_item_taxes', function (Blueprint $table) { + $table->dropForeign('ab_invoice_item_tax_site_id_foreign'); + $table->dropIndex('ab_invoice_item_tax_site_id_foreign'); + $table->dropIndex('ab_invoice_item_tax_id_site_id_index'); + $table->dropColumn(['date_orig']); + + $table->foreign(['invoice_item_id','site_id'])->references(['id','site_id'])->on('invoice_items'); + $table->foreign(['tax_id'])->references(['id'])->on('taxes'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + abort(500,'Cant go back'); + } +}; diff --git a/resources/views/theme/backend/adminlte/a/service/widgets/broadband/update.blade.php b/resources/views/theme/backend/adminlte/a/service/widgets/broadband/update.blade.php index 6bef20d..e1e7022 100644 --- a/resources/views/theme/backend/adminlte/a/service/widgets/broadband/update.blade.php +++ b/resources/views/theme/backend/adminlte/a/service/widgets/broadband/update.blade.php @@ -65,7 +65,7 @@
- + \ No newline at end of file diff --git a/resources/views/theme/backend/adminlte/a/service/widgets/internal.blade.php b/resources/views/theme/backend/adminlte/a/service/widgets/internal.blade.php index 66df046..b99438e 100644 --- a/resources/views/theme/backend/adminlte/a/service/widgets/internal.blade.php +++ b/resources/views/theme/backend/adminlte/a/service/widgets/internal.blade.php @@ -3,7 +3,7 @@   - {{ $o->product->type->supplied->supplier_detail->supplier->name }} + {{ ($s=$o->supplied)->supplier_detail->supplier->name }} Us   @@ -12,7 +12,7 @@ Product - #{{ ($s=$o->product->type->supplied)->id }}: {{ $s->name }} + #{{ $s->id }}: {{ $s->name }} #{{ $o->product->id }}: {{ $o->product->name }} {{ $s->type }} @@ -20,61 +20,45 @@ Setup ${{ number_format($a=\App\Models\Tax::tax_calc($s->setup_cost,$o->account->taxes),2) }} ${{ number_format($b=\App\Models\Tax::tax_calc($o->product->setup_charge,$o->account->taxes),2) }} - - @if ($a > $b) - ({{ number_format($a ? ($b-$a)/($b ?: 1)*100 : 100,1) }})% - @else - {{ number_format($a ? ($b-$a)/($b ?: 1)*100 : ($b ? 100: 0),1) }}% - @endif - + {!! markup($a,$b) !!} Billed {{ $s->billing_interval_string }} - {{ $o->product->billing_interval_string }} + {{ $o->billing_interval_string }}   - Billing Charge + Billing Price ${{ number_format($a=\App\Models\Tax::tax_calc($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,$o->product->billing_interval),$o->account->taxes),2) }} - ${{ number_format($b=\App\Models\Tax::tax_calc($o->product->getBaseChargeAttribute($o->billing_interval),$o->account->taxes),2) }} - - @if ($a > $b) - ({{ number_format($a ? ($b-$a)/($b ?: 1)*100 : 100,1) }})% - @else - {{ number_format($a ? ($b-$a)/($b ?: 1)*100 : ($b ? 100: 0),1) }}% - @endif - + ${{ number_format($b=$o->billing_charge,2) }} + {!! markup($a,$b) !!} - Monthly Cost + Monthly Price ${{ number_format($a=\App\Models\Tax::tax_calc($s->base_cost*\App\Models\Invoice::billing_change($s->billing_interval,1),$o->account->taxes),2) }} - ${{ number_format($b=\App\Models\Tax::tax_calc($o->product->getBaseChargeAttribute($o->billing_interval)*\App\Models\Invoice::billing_change($o->billing_interval,1),$o->account->taxes),2) }} - - @if ($a > $b) - ({{ number_format($a ? ($b-$a)/($b ?: 1)*100 : 100,1) }})% - @else - {{ number_format($a ? ($b-$a)/($b ?: 1)*100 : ($b ? 100: 0),1) }}% - @endif - + ${{ number_format($b=$o->billing_monthly_price,2) }} + {!! markup($a,$b) !!} Contract {{ $s->contract_term }} months - {{ $o->product->contract_term }} months + {{ $o->contract_term }} months   - Min Cost + Min Price ${{ number_format($a=\App\Models\Tax::tax_calc($s->min_cost,$o->account->taxes),2) }} ${{ number_format($b=\App\Models\Tax::tax_calc($o->product->getMinChargeAttribute($o->billing_interval),$o->account->taxes),2) }} - - @if ($a > $b) - ({{ number_format($a ? ($b-$a)/($b ?: 1)*100 : 100,1) }})% - @else - {{ number_format($a ? ($b-$a)/($b ?: 1)*100 : ($b ? 100: 0),1) }}% - @endif - + {!! markup($a,$b) !!} - \ No newline at end of file + + +@php +function markup($a,$b) { + return ($a > $b) + ? sprintf('(%3.1f%%)',$a ? ($b-$a)/($b ?: 1)*100 : 100) + : sprintf('%3.1f%%',$a ? ($b-$a)/($b ?: 1)*100 : ($b ? 100: 0)); +} +@endphp \ No newline at end of file diff --git a/resources/views/theme/backend/adminlte/common/invoice/widget/list.blade.php b/resources/views/theme/backend/adminlte/common/invoice/widget/list.blade.php index df0092f..a9f14d9 100644 --- a/resources/views/theme/backend/adminlte/common/invoice/widget/list.blade.php +++ b/resources/views/theme/backend/adminlte/common/invoice/widget/list.blade.php @@ -14,8 +14,8 @@ @foreach ($o->invoices as $io) {{ $io->id }} - {{ $io->date_orig->format('Y-m-d') }} - {{ $io->due_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->paid,2) }} ${{ number_format($io->due,2) }} diff --git a/resources/views/theme/backend/adminlte/r/invoice/widgets/due.blade.php b/resources/views/theme/backend/adminlte/r/invoice/widgets/due.blade.php index aa139f1..a095b8d 100644 --- a/resources/views/theme/backend/adminlte/r/invoice/widgets/due.blade.php +++ b/resources/views/theme/backend/adminlte/r/invoice/widgets/due.blade.php @@ -22,11 +22,11 @@ @foreach ($o->query_invoice_summary()->having('balance','>',0)->get() as $oo) - due_date->isPast()) class="table-danger" @endif> + due_at->isPast()) class="table-danger" @endif> {{ $oo->account->name }} {{ $oo->sid }} - {{ $oo->date_orig->format('Y-m-d') }} - {{ $oo->due_date->format('Y-m-d') }} + {{ $oo->created_at->format('Y-m-d') }} + {{ $oo->due_at->format('Y-m-d') }} ${{ number_format($oo->total,2) }} ${{ number_format($oo->paid,2) }} ${{ number_format($oo->due,2) }} diff --git a/resources/views/theme/backend/adminlte/r/service/order/provision_plan.blade.php b/resources/views/theme/backend/adminlte/r/service/order/provision_plan.blade.php index b6f9c8d..254e8e5 100644 --- a/resources/views/theme/backend/adminlte/r/service/order/provision_plan.blade.php +++ b/resources/views/theme/backend/adminlte/r/service/order/provision_plan.blade.php @@ -33,7 +33,7 @@
- + diff --git a/resources/views/theme/backend/adminlte/u/invoice/home.blade.php b/resources/views/theme/backend/adminlte/u/invoice/home.blade.php index b358f74..e595e5e 100644 --- a/resources/views/theme/backend/adminlte/u/invoice/home.blade.php +++ b/resources/views/theme/backend/adminlte/u/invoice/home.blade.php @@ -68,7 +68,7 @@ Invoice:{{ $o->lid }} - Payment Due:{{ $o->due_date->format('Y-m-d') }} + Payment Due:{{ $o->due_at->format('Y-m-d') }} This Invoice Due:${{ number_format($o->total,$o->currency()->rounding) }} @@ -157,7 +157,7 @@ - + diff --git a/resources/views/theme/backend/adminlte/u/invoice/widgets/due.blade.php b/resources/views/theme/backend/adminlte/u/invoice/widgets/due.blade.php index 6044785..4897869 100644 --- a/resources/views/theme/backend/adminlte/u/invoice/widgets/due.blade.php +++ b/resources/views/theme/backend/adminlte/u/invoice/widgets/due.blade.php @@ -21,11 +21,11 @@ @foreach ($x as $oo) - due_date->isPast()) class="table-danger" @endif> + due_at->isPast()) class="table-danger" @endif> - - + + diff --git a/resources/views/theme/backend/adminlte/u/invoice/widgets/list.blade.php b/resources/views/theme/backend/adminlte/u/invoice/widgets/list.blade.php index 3e829f6..c23e910 100644 --- a/resources/views/theme/backend/adminlte/u/invoice/widgets/list.blade.php +++ b/resources/views/theme/backend/adminlte/u/invoice/widgets/list.blade.php @@ -5,7 +5,7 @@
- @if(($x=$o->invoices()->where('ab_invoice.date_orig','>',\Carbon\Carbon::now()->subMonths(12)->unix())->with(['items.taxes','paymentitems.payment','account.country.currency'])->get()->where('due','<=',0))->count()) + @if(($x=$o->invoices()->where('invoices.created_at','>',\Carbon\Carbon::now()->subMonths(12))->with(['items.taxes','paymentitems.payment','account.country.currency'])->get()->where('due','<=',0))->count())
Subtotal:${{ number_format($o->total_sub,$o->currency()->rounding) }}${{ number_format($o->sub_total,$o->currency()->rounding) }}
 
{{ $oo->account->name }} {{ $oo->sid }}{{ $oo->date_orig->format('Y-m-d') }}{{ $oo->due_date->format('Y-m-d') }}{{ $oo->created_at->format('Y-m-d') }}{{ $oo->due_at->format('Y-m-d') }} ${{ number_format($oo->total,2) }} ${{ number_format($oo->paid,2) }} ${{ number_format($oo->due,2) }}
@@ -23,8 +23,8 @@ - - + + @@ -45,7 +45,7 @@
{{ $oo->account->name }} {{ $oo->sid }}{{ $oo->date_orig->format('Y-m-d') }}{{ $oo->due_date->format('Y-m-d') }}{{ $oo->created_at->format('Y-m-d') }}{{ $oo->due_at->format('Y-m-d') }} {{ $oo->paid_date ? $oo->paid_date->format('Y-m-d') : '' }} ${{ number_format($oo->total,2) }}