diff --git a/app/Console/Commands/ServiceList.php b/app/Console/Commands/ServiceList.php
index 7e0330f..90b9864 100644
--- a/app/Console/Commands/ServiceList.php
+++ b/app/Console/Commands/ServiceList.php
@@ -3,9 +3,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
-use Illuminate\Support\Facades\Config;
-use App\Models\{Service,Site};
+use App\Models\Service;
class ServiceList extends Command
{
@@ -33,7 +32,7 @@ class ServiceList extends Command
*/
public function handle()
{
- $header = '|%13s|%-14s|%-35s|%-40s|%8s|%17s|%12s|%12s|%12s|%12s|%14s|';
+ $header = '|%5s|%-9s|%-30s|%-30s|%7s|%7s|%10s|%10s|%10s|%10s|%10s|';
$this->warn(sprintf($header,
'ID',
@@ -42,41 +41,42 @@ class ServiceList extends Command
'Name',
'Active',
'Status',
- 'Next Invoice',
- 'Start Date',
- 'Stop Date',
- 'Connect Date',
- 'First Invoice'
+ 'Start',
+ 'Stop',
+ 'Connect',
+ 'First',
+ 'Next',
));
- foreach (Service::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->with(['site'])->cursor() as $o) {
- if ((! $this->option('inactive')) AND ! $o->isActive())
+ foreach (Service::cursor() as $o) {
+ if ((! $this->option('inactive')) && (! $o->isActive()))
continue;
- Config::set('site',$o->site);
-
- if ($this->option('type') AND ($o->product->getCategoryAttribute() !== $this->option('type')))
+ if ($this->option('type') && ($o->product->getCategoryAttribute() !== $this->option('type')))
continue;
- $c = $o->invoice_items->filter(function($item) {return $item->item_type === 0; })->sortby('start_at')->first();
+ $c = $o->invoiced_items
+ ->filter(fn($item)=>$item->item_type === 0)
+ ->sortby('start_at')
+ ->first();
- if ($this->option('fix') AND ! $o->start_at AND $c AND $c->start_at AND $o->type AND $o->type->connect_at AND $c->start_at->format('Y-m-d') == $o->type->connect_at->format('Y-m-d')) {
+ if ($this->option('fix') && (! $o->start_at) && $c && $c->start_at && $o->type && $o->type->connect_at && $c->start_at->format('Y-m-d') == $o->type->connect_at->format('Y-m-d')) {
$o->start_at = $o->type->connect_at;
$o->save();
}
$this->info(sprintf($header,
- $o->sid,
+ $o->lid,
$o->product->getCategoryNameAttribute(),
substr($o->product->getNameAttribute(),0,35),
substr($o->name_short,0,40),
$o->active ? 'active' : 'inactive',
$o->status,
- $o->invoice_next?->format('Y-m-d'),
$o->start_at?->format('Y-m-d'),
$o->stop_at?->format('Y-m-d'),
- ($o->type AND $o->type->connect_at) ? $o->type->connect_at->format('Y-m-d') : NULL,
- ($c && $c->date_start) ? $c->date_start->format('Y-m-d') : NULL,
+ ($o->type && $o->type->connect_at) ? $o->type->connect_at->format('Y-m-d') : NULL,
+ ($c && $c->start_at) ? $c->start_at->format('Y-m-d') : NULL,
+ $o->invoice_next?->format('Y-m-d'),
));
}
}
diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php
index b9a233c..13b06e5 100644
--- a/app/Http/Controllers/SearchController.php
+++ b/app/Http/Controllers/SearchController.php
@@ -68,9 +68,11 @@ class SearchController extends Controller
foreach (Service::Search($request->input('term'))
->whereIN('account_id',$account_ids)
->orderBy('id')
- ->limit(20)->get() as $o)
+ ->limit(20)
+ ->with(['product'])
+ ->get() as $o)
{
- $result->push(['name'=>sprintf('%s (%s) %s',$o->name,$o->lid,$o->active ? '' : 'INACT'),'value'=>'/u/service/'.$o->id,'category'=>$o->category_name]);
+ $result->push(['name'=>sprintf('%s (%s) %s',$o->name,$o->lid,$o->active ? '' : 'INACT'),'value'=>'/u/service/'.$o->id,'category'=>$o->product->category_name]);
}
// Look for an Invoice
@@ -93,7 +95,7 @@ class SearchController extends Controller
}
return $result
- ->sortBy(function($item) { return $item['category'].$item['name']; })
+ ->sortBy(fn($item)=>$item['category'].$item['name'])
->values();
}
}
\ No newline at end of file
diff --git a/app/Http/Controllers/ServiceController.php b/app/Http/Controllers/ServiceController.php
index 0e22f26..b00e19a 100644
--- a/app/Http/Controllers/ServiceController.php
+++ b/app/Http/Controllers/ServiceController.php
@@ -333,7 +333,7 @@ class ServiceController extends Controller
$start_at = Carbon::create(Arr::get($request->broadband,'start_at'));
// Get the invoiced items covering the start_at date
- foreach ($o->invoice_items->filter(function($item) use ($start_at) {
+ foreach ($o->invoiced_items->filter(function($item) use ($start_at) {
return ($item->start_at < $start_at) && ($item->stop_at > $start_at) && ($item->item_type === 0);
}) as $iio)
{
@@ -351,7 +351,7 @@ class ServiceController extends Controller
$co->stop_at = $iio->stop_at;
$co->amount = $iio->price_base;
$co->taxable = TRUE; // @todo this should be determined
- $co->quantity = -1*$start_at->diff($iio->stop_at)->days/$iio->start_at->diff($iio->stop_at)->days;
+ $co->quantity = -1*$start_at->diffInDays($iio->stop_at)/$iio->start_at->diffInDays($iio->stop_at);
$charges->push($co);
// Add the new charge
@@ -368,7 +368,7 @@ class ServiceController extends Controller
$co->stop_at = $iio->stop_at;
$co->amount = Arr::get($request->broadband,'price') ?: $po->base_charge;
$co->taxable = TRUE; // @todo this should be determined
- $co->quantity = $start_at->diff($iio->stop_at)->days/$iio->start_at->diff($iio->stop_at)->days;
+ $co->quantity = $start_at->diffInDays($iio->stop_at)/$iio->start_at->diffInDays($iio->stop_at);
$charges->push($co);
}
@@ -424,10 +424,10 @@ class ServiceController extends Controller
$request->post(),
$x=collect($o->type->validation())
->keys()
- ->transform(fn($item)=>sprintf('%s.%s',$o->category,$item))
+ ->transform(fn($item)=>sprintf('%s.%s',$o->product->category,$item))
->combine(array_values($o->type->validation()))
->transform(fn($item)=>is_string($item)
- ? preg_replace('/^exclude_without:/',sprintf('exclude_without:%s.',$o->category),$item)
+ ? preg_replace('/^exclude_without:/',sprintf('exclude_without:%s.',$o->product->category),$item)
: $item)
->merge(
[
@@ -436,7 +436,7 @@ class ServiceController extends Controller
'recur_schedule' => ['required',Rule::in(collect(Invoice::billing_periods)->keys())],
'invoice_next_at' => 'nullable|date',
'price' => 'nullable|numeric',
- $o->category => 'array|min:1',
+ $o->product->category => 'array|min:1',
]
)
->toArray()
@@ -452,13 +452,13 @@ class ServiceController extends Controller
$validated = collect($validator->validated());
// Store our service type values
- $o->type->forceFill($validated->get($o->category));
+ $o->type->forceFill($validated->get($o->product->category));
// Some special handling
- switch ($o->category) {
+ switch ($o->product->category) {
case 'broadband':
// If pppoe is not set, then we dont need username/password
- $o->type->pppoe = ($x=data_get($validated,$o->category.'.pppoe',FALSE));
+ $o->type->pppoe = ($x=data_get($validated,$o->product->category.'.pppoe',FALSE));
if (! $x) {
$o->type->service_username = NULL;
@@ -487,7 +487,7 @@ class ServiceController extends Controller
else {
// For broadband, start_at is connect_at in the type record
- switch ($o->category) {
+ switch ($o->product->category) {
case 'broadband':
$o->start_at = $o->type->connect_at;
break;
diff --git a/app/Http/Controllers/User/AccountController.php b/app/Http/Controllers/User/AccountController.php
deleted file mode 100644
index 92bc164..0000000
--- a/app/Http/Controllers/User/AccountController.php
+++ /dev/null
@@ -1,44 +0,0 @@
-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_at = $s->min(function($item) { return $item->invoice_next; });
-
- // @todo The days in advance is an application parameter
- $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_at)+1+7;
- foreach ($s as $so)
- {
- if ($so->isInvoiceDueSoon($days))
- foreach ($so->next_invoice_items() as $o)
- $io->items->push($o);
- }
-
- return view('theme.backend.adminlte.u.invoice.home')
- ->with('o',$io);
- }
-}
\ No newline at end of file
diff --git a/app/Http/Controllers/Wholesale/ReportController.php b/app/Http/Controllers/Wholesale/ReportController.php
index 20f8c50..e9d103f 100644
--- a/app/Http/Controllers/Wholesale/ReportController.php
+++ b/app/Http/Controllers/Wholesale/ReportController.php
@@ -15,9 +15,4 @@ class ReportController extends Controller
{
return view('product/report');
}
-
- public function services()
- {
- return view('service/report');
- }
}
\ No newline at end of file
diff --git a/app/Jobs/ImportCosts.php b/app/Jobs/ImportCosts.php
index e7aaa08..b7a6a4a 100644
--- a/app/Jobs/ImportCosts.php
+++ b/app/Jobs/ImportCosts.php
@@ -131,7 +131,7 @@ class ImportCosts implements ShouldQueue
if ($so) {
// r[1] = Monthly Charge or Extra Charge,r[2] = "On Plan", r[3] = Plan Info
$r = [];
- switch ($so->category) {
+ switch ($so->product->category) {
case 'broadband':
$to = Cost\Broadband::where('site_id',$this->co->site_id)
->where('cost_id',$this->co->id)
@@ -192,8 +192,8 @@ class ImportCosts implements ShouldQueue
break;
default:
- dump(['so'=>$so,'category'=>$so->category,'line'=>$line,'m'=>$m,'r'=>$r]);
- throw new \Exception(sprintf('ERROR: Service type not handled for service [%s] (%s) on line [%d]',$m[1],$so->category,$c));
+ dump(['so'=>$so,'category'=>$so->product->category,'line'=>$line,'m'=>$m,'r'=>$r]);
+ throw new \Exception(sprintf('ERROR: Service type not handled for service [%s] (%s) on line [%d]',$m[1],$so->product->category,$c));
}
} else {
diff --git a/app/Mail/OrderRequestApprove.php b/app/Mail/OrderRequestApprove.php
index b181bd1..3081701 100644
--- a/app/Mail/OrderRequestApprove.php
+++ b/app/Mail/OrderRequestApprove.php
@@ -14,7 +14,7 @@ class OrderRequestApprove extends Mailable
{
use Queueable, SerializesModels;
- public Service $service;
+ public Service $so;
public string $notes;
/**
@@ -25,7 +25,7 @@ class OrderRequestApprove extends Mailable
*/
public function __construct(Service $o,string $notes='')
{
- $this->service = $o;
+ $this->so = $o;
$this->notes = $notes;
}
@@ -36,14 +36,14 @@ class OrderRequestApprove extends Mailable
*/
public function build()
{
- Config::set('site',$this->service->site);
+ Config::set('site',$this->so->site);
// @todo This is not consistent with Cancel/Change Request
- switch ($this->service->category) {
- case 'broadband': $subject = sprintf('%s: %s',$this->service->category,$this->service->type->service_address);
+ switch ($this->so->product->category) {
+ case 'broadband': $subject = sprintf('%s: %s',$this->so->product->category,$this->so->type->service_address);
break;
- case 'phone': $subject = sprintf('%s: %s',$this->service->category,$this->service->type->service_number);
+ case 'phone': $subject = sprintf('%s: %s',$this->so->product->category,$this->so->type->service_number);
break;
default:
@@ -53,6 +53,6 @@ class OrderRequestApprove extends Mailable
return $this
->markdown('email.admin.order.approve')
->subject($subject)
- ->with(['site'=>$this->service->site]);
+ ->with(['site'=>$this->so->site]);
}
}
\ No newline at end of file
diff --git a/app/Models/Account.php b/app/Models/Account.php
index 6db2df6..63a5fa0 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -156,7 +156,7 @@ class Account extends Model implements IDs
public function services_active()
{
return $this->services()
- ->active();
+ ->ServiceActive();
}
/**
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index 323f71a..cb5a583 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -158,6 +158,148 @@ class Invoice extends Model implements IDs
return ceil(($contract_term ?: 1)/(Arr::get(self::billing_periods,$source.'.interval') ?: 1));
}
+ /**
+ * Work out the time period for a particular date and invoice period
+ *
+ * @param \Leenooks\Carbon $date
+ * @param int $interval
+ * @param bool $strict
+ * @return Collection
+ * @throws \Exception
+ */
+ public static function invoice_period(Carbon $date,int $interval,bool $strict): Collection
+ {
+ $date_start = $date->clone();
+ $date_end = $date->clone();
+
+ switch ($interval) {
+ case self::BILL_WEEKLY:
+ $result = collect([
+ 'start' => $strict
+ ? $date_start->startOfWeek()
+ : $date_start,
+ 'end'=> $strict
+ ? $date_end->endOfWeek()
+ : $date_end->addWeek()->subDay()
+ ]);
+ break;
+
+ case self::BILL_MONTHLY:
+ $result = collect([
+ 'start' => $strict
+ ? $date_start->startOfMonth()
+ : $date_start,
+ 'end' => $strict
+ ? $date_end->endOfMonth()
+ : $date_end->addMonth()->subDay()
+ ]);
+ break;
+
+ case self::BILL_QUARTERLY:
+ $result = collect([
+ 'start' => $strict// The service charges
+ ? $date_start->startOfQuarter()
+ : $date_start,
+ 'end' => $strict
+ ? $date_end->endOfQuarter()
+ : $date_end->addQuarter()->subDay()
+ ]);
+ break;
+
+ case self::BILL_SEMI_YEARLY:
+ $result = collect([
+ 'start' => $strict
+ ? $date_start->startOfHalf()
+ : $date_start,
+ 'end' => $strict
+ ? $date_end->endOfHalf()
+ : $date_end->addQuarters(2)->subDay()
+ ]);
+ break;
+
+ case self::BILL_YEARLY:
+ $result = collect([
+ 'start' => $strict
+ ? $date_start->startOfYear()
+ : $date_start,
+ 'end' => $strict
+ ? $date_end->endOfYear()
+ : $date_end->addYear()->subDay()
+ ]);
+ break;
+
+ case self::BILL_TWOYEARS:
+ if (! $strict) {
+ $result = collect([
+ 'start' => $date_start,
+ 'end' => $date_end->addYears(2)->subDay(),
+ ]);
+
+ } else {
+ $data_end = $date_end->addYears(2)->subDay()->endOfYear();
+
+ // Make sure we end on an even year
+ if ($data_end->clone()->addDay()->year%2)
+ $data_end = $data_end->subYear();
+
+ $result = collect([
+ 'start' => $data_end->clone()->subYears(2)->addDay(),
+ 'end' => $data_end,
+ ]);
+ }
+ break;
+
+ // NOTE: price_recur_strict ignored
+ case self::BILL_THREEYEARS:
+ $result = collect([
+ 'start' => $date_start,
+ 'end' => $date_end->addYears(3)->subDay(),
+ ]);
+ break;
+
+ // NOTE: price_recur_strict ignored
+ case self::BILL_FOURYEARS:
+ $result = collect([
+ 'start' => $date_start,
+ 'end' => $date_end->addYears(4)->subDay(),
+ ]);
+ break;
+
+ // NOTE: price_recur_strict ignored
+ case self::BILL_FIVEYEARS:
+ $result = collect([
+ 'start' => $date_start,
+ 'end' => $date_end->addYears(5)->subDay(),
+ ]);
+ break;
+
+ default:
+ throw new \Exception('Unknown recur_schedule: '.$interval);
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param \Leenooks\Carbon $start Start Date
+ * @param Carbon $end End Date
+ * @param int $interval Period End Date
+ * @param bool $strict
+ * @return float
+ * @throws \Exception
+ */
+ public static function invoice_quantity(Carbon $start,Carbon $end,Collection $period): float
+ {
+ if ($start->lessThan(Arr::get($period,'start')) || $end->greaterThan(Arr::get($period,'end')))
+ throw new \Exception('Billing Period differ');
+
+ $d = Arr::get($period,'start')->diffInDays(Arr::get($period,'end'));
+ if (! $d)
+ throw new \Exception('Start and End period dates cannot be the same');
+
+ return round(($d-Arr::get($period,'start')->diffInDays($start)-$end->diffInDays(Arr::get($period,'end')))/$d,2);
+ }
+
/* INTERFACES */
/**
diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php
index c1a9abb..49a726c 100644
--- a/app/Models/InvoiceItem.php
+++ b/app/Models/InvoiceItem.php
@@ -30,13 +30,16 @@ class InvoiceItem extends Model
// Array of items that can be updated with PushNew
protected $pushable = ['taxes'];
+ public const INVOICEITEM_SERVICE = 0;
+ public const INVOICEITEM_SETUP = 4;
+
// @todo Change these to CONSTS so it's easier to reference through out the code
public const type = [
- 0 => 'Service Charge',
+ self::INVOICEITEM_SERVICE => 'Service Charge',
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
+ self::INVOICEITEM_SETUP => '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
diff --git a/app/Models/Service.php b/app/Models/Service.php
index efc3b82..d285ca8 100644
--- a/app/Models/Service.php
+++ b/app/Models/Service.php
@@ -16,7 +16,7 @@ use Leenooks\Casts\LeenooksCarbon;
use App\Models\Product\Type;
use App\Interfaces\IDs;
-use App\Traits\ScopeServiceUserAuthorised;
+use App\Traits\{ScopeServiceActive,ScopeServiceUserAuthorised};
/**
* Class Service
@@ -29,10 +29,10 @@ use App\Traits\ScopeServiceUserAuthorised;
*
* Attributes for services:
* + additional_cost : Pending additional charges for this service (excluding setup) //@todo check all these are still valid
- * + billing_charge : Charge for this service each invoice period // @todo change to "charge"
+ * + billing_charge : Charge for this service each invoice period
* + billing_interval : The period that this service is billed for by default
* + billing_interval_string : The period that this service is billed for by default as a name
- * + billed_to : When this service has been billed to // @todo rename all references to invoice_to
+ * + invoiced_to : When this service has been billed to
* + category : The type of service this is, eg: broadband, phone
* + category_name : The type of service this is, eg: Broadband, Telephone (in human friendly)
* + contract_term : The term that this service must be active
@@ -54,7 +54,7 @@ use App\Traits\ScopeServiceUserAuthorised;
*/
class Service extends Model implements IDs
{
- use HasFactory,ScopeServiceUserAuthorised;
+ use HasFactory,ScopeServiceActive,ScopeServiceUserAuthorised;
protected $casts = [
'order_info' => AsCollection::class,
@@ -281,8 +281,8 @@ class Service extends Model implements IDs
public static function movements(User $uo): Collection
{
return (new self)
- ->active()
- ->serviceUserAuthorised($uo)
+ ->ServiceActive()
+ ->ServiceUserAuthorised($uo)
->where('order_status','!=','ACTIVE')
->with(['account','product'])
->get();
@@ -343,7 +343,7 @@ class Service extends Model implements IDs
public function charges_active()
{
return $this->charges()
- ->active();
+ ->ServiceActive();
}
/**
@@ -371,6 +371,7 @@ class Service extends Model implements IDs
*/
public function invoice_items($active=TRUE)
{
+ Log::alert('Call to deprecated functon '.__METHOD__);
return $this->invoiced_items_active();
}
@@ -418,6 +419,7 @@ class Service extends Model implements IDs
{
return $this->hasMany(InvoiceItem::class)
->where('item_type','=',0)
+ ->whereNotNull('start_at')
->orderBy('start_at','desc');
}
@@ -464,9 +466,11 @@ class Service extends Model implements IDs
/**
* Only query active categories
+ * @deprecated use ScopeServiceActive
*/
public function scopeActive($query)
{
+ throw new \Exception('deprecated');
return $query->where(
fn($query)=>
$query->where($this->getTable().'.active',TRUE)
@@ -479,9 +483,11 @@ class Service extends Model implements IDs
*
* @param $query
* @return mixed
+ * @deprecated use ScopeServiceInactive
*/
- public function scopeInActive($query)
+ public function scopeInactive($query)
{
+ dd('deprecated');
return $query->where(
fn($query)=>
$query->where($this->getTable().'.active',FALSE)
@@ -527,15 +533,7 @@ class Service extends Model implements IDs
*/
public function getBillingChargeAttribute(): float
{
- // If recur_schedule is null, then we only bill this item once
- if (is_null($this->recur_schedule) && $this->getInvoiceToAttribute())
- $this->price = 0;
-
- return $this->account->taxed(
- is_null($this->price)
- ? $this->product->getBaseChargeAttribute($this->recur_schedule,$this->account->group)
- : $this->price
- );
+ return $this->account->taxed($this->billing_charge());
}
/**
@@ -546,7 +544,7 @@ class Service extends Model implements IDs
*/
public function getBillingChargeNormalisedAttribute(): float
{
- return number_format($this->getBillingChargeAttribute()*Invoice::billing_change($this->recur_schedule,$this->offering->billing_interval),2);
+ return number_format($this->getBillingChargeAttribute()*Invoice::billing_change($this->getBillingIntervalAttribute(),$this->offering->billing_interval),2);
}
/**
@@ -569,39 +567,6 @@ class Service extends Model implements IDs
return Invoice::billing_name($this->getBillingIntervalAttribute());
}
- /**
- * Determine a monthly price for a service, even if it is billed at a different frequency
- *
- * @return float
- * @throws Exception
- * @deprecated use class::billing_charge_normalised()
- */
- public function getBillingMonthlyPriceAttribute(): float
- {
- Log::alert('SMO:! Deprecated function getBillingMonthlyPriceAttribute()');
- return $this->getBillingChargeNormalisedAttribute();
- }
-
- /**
- * Service Category ID
- *
- * @return string
- */
- public function getCategoryAttribute(): string
- {
- return $this->product->category;
- }
-
- /**
- * Service Category Name
- *
- * @return string
- */
- public function getCategoryNameAttribute(): string
- {
- return $this->product->category_name;
- }
-
/**
* The date the contract ends
*
@@ -652,155 +617,19 @@ class Service extends Model implements IDs
*/
public function getInvoiceNextAttribute(): Carbon
{
- $last = $this->getInvoiceToAttribute();
+ $last = $this->getInvoicedToAttribute();
return $last
? $last->addDay()
: (min($this->start_at,$this->invoice_next_at) ?: Carbon::now());
}
- /**
- * Return the end date for the next invoice
- *
- * @return Carbon
- * @throws Exception
- */
- public function getInvoiceNextEndAttribute(): Carbon
- {
- switch ($this->recur_schedule) {
- case Invoice::BILL_WEEKLY:
- $date = $this->product->price_recur_strict
- ? $this->getInvoiceNextAttribute()->endOfWeek()
- : $this->getInvoiceNextAttribute()->addWeek()->subDay();
- break;
-
- case Invoice::BILL_MONTHLY:
- $date = $this->product->price_recur_strict
- ? $this->getInvoiceNextAttribute()->endOfMonth()
- : $this->getInvoiceNextAttribute()->addMonth()->subDay();
- break;
-
- case Invoice::BILL_QUARTERLY:
- $date = $this->product->price_recur_strict
- ? $this->getInvoiceNextAttribute()->endOfQuarter()
- : $this->getInvoiceNextAttribute()->addQuarter()->subDay();
- break;
-
- case Invoice::BILL_SEMI_YEARLY:
- $date = $this->product->price_recur_strict
- ? $this->getInvoiceNextAttribute()->endOfHalf()
- : $this->getInvoiceNextAttribute()->addQuarters(2)->subDay();
- break;
-
- case Invoice::BILL_YEARLY:
- $date = $this->product->price_recur_strict
- ? $this->getInvoiceNextAttribute()->endOfYear()
- : $this->getInvoiceNextAttribute()->addYear()->subDay();
- break;
-
- case Invoice::BILL_TWOYEARS:
- if (! $this->product->price_recur_strict) {
- $date = $this->getInvoiceNextAttribute()->addYears(2)->subDay();
-
- } else {
- $date = $this->getInvoiceNextAttribute()->addYears(2)->subDay()->endOfYear();
-
- // Make sure we end on an even year
- if ($date->clone()->addDay()->year%2)
- $date = $date->subYear();
- }
- break;
-
- // NOTE: price_recur_strict ignored
- case Invoice::BILL_THREEYEARS:
- $date = $this->getInvoiceNextAttribute()->addYears(3)->subDay();
- break;
-
- // NOTE: price_recur_strict ignored
- case Invoice::BILL_FOURYEARS:
- $date = $this->getInvoiceNextAttribute()->addYears(4)->subDay();
- break;
-
- // NOTE: price_recur_strict ignored
- case Invoice::BILL_FIVEYEARS:
- $date = $this->getInvoiceNextAttribute()->addYears(5)->subDay();
- break;
-
- default:
- throw new Exception('Unknown recur_schedule');
- }
-
- // If the invoice has an end date, our invoice period shouldnt be greater than that (might be terminating).
- if ($this->stop_at && ($this->stop_at < $date))
- $date = $this->stop_at;
-
- return $date;
- }
-
- /**
- * Determine how much quantity (at the charge rate) is required for the next invoice
- *
- * @return float
- * @throws Exception
- */
- public function getInvoiceNextQuantityAttribute(): float
- {
- // If we are not rounding to the first day of the cycle, then it is always a full cycle
- if (! $this->product->price_recur_strict)
- return 1;
-
- $n = $this->invoice_next->diffInDays($this->invoice_next_end);
-
- switch ($this->recur_schedule) {
- case Invoice::BILL_WEEKLY:
- $d = $this->invoice_next_end->addWeek()->startOfWeek()->diffInDays($this->invoice_next->startOfWeek());
- break;
-
- case Invoice::BILL_MONTHLY:
- $d = $this->invoice_next_end->addMonth()->startOfMonth()->diffInDays($this->invoice_next->startOfMonth());
- break;
-
- case Invoice::BILL_QUARTERLY:
- $d = $this->invoice_next_end->startOfQuarter()->diffInDays($this->invoice_next->addQuarter()->startOfQuarter());
- break;
-
- case Invoice::BILL_SEMI_YEARLY:
- $d = $this->invoice_next_end->addQuarter(2)->startOfHalf()->diffInDays($this->invoice_next->startOfHalf());
- break;
-
- case Invoice::BILL_YEARLY:
- $d = $this->invoice_next_end->addYear()->startOfYear()->diffInDays($this->invoice_next->startOfYear());
- break;
-
- case Invoice::BILL_TWOYEARS:
- $d = $this->invoice_next_end->addYear(2)->startOfYear()->diffInDays($this->invoice_next->subyear(2))-1;
- break;
-
- case Invoice::BILL_THREEYEARS:
- $d = $this->invoice_next_end->addYear(3)->startOfYear()->diffInDays($this->invoice_next->subyear(3))-1;
- break;
-
- case Invoice::BILL_FOURYEARS:
- $d = $this->invoice_next_end->addYear(3)->startOfYear()->diffInDays($this->invoice_next->subyear(4))-1;
- break;
-
- case Invoice::BILL_FIVEYEARS:
- $d = $this->invoice_next_end->addYear(3)->startOfYear()->diffInDays($this->invoice_next->subyear(5))-1;
- break;
-
- default:
- throw new Exception('Unknown recur_schedule');
- }
-
- return round($n/$d,2);
- }
-
/**
* Get the date that the service has been invoiced to
*
* @return Carbon|null
*/
- public function getInvoiceToAttribute(): ?Carbon
+ public function getInvoicedToAttribute(): ?Carbon
{
return ($x=$this->invoiced_service_items_active_recent)->count()
? $x->first()->stop_at
@@ -826,7 +655,9 @@ class Service extends Model implements IDs
*/
public function getNameShortAttribute()
{
- return $this->type->getServiceNameAttribute() ? $this->type->getServiceNameAttribute() : 'SID:'.$this->sid;
+ return $this->type->getServiceNameAttribute()
+ ? $this->type->getServiceNameAttribute()
+ : 'SID:'.$this->sid;
}
/**
@@ -841,7 +672,9 @@ class Service extends Model implements IDs
*/
public function getNameDetailAttribute()
{
- return ($this->type->getServiceDescriptionAttribute() !== NULL) ? $this->type->getServiceDescriptionAttribute() : 'No Description';
+ return ($this->type->getServiceDescriptionAttribute() !== NULL)
+ ? $this->type->getServiceDescriptionAttribute()
+ : 'No Description';
}
/**
@@ -878,22 +711,13 @@ class Service extends Model implements IDs
->last();
return $lastpaid
- ? $this->invoiced_service_items_active->where('invoice_id',$lastpaid->id)->where('type',0)->max('stop_at')
+ ? $this->invoiced_service_items_active
+ ->where('invoice_id',$lastpaid->id)
+ ->where('type',0)
+ ->max('stop_at')
: NULL;
}
- /**
- * Return the billing recurring configuration for this service
- *
- * @param $value
- * @return int
- */
- public function xgetRecurScheduleAttribute($value): int
- {
- // If recur_schedule not set, default to quarterly
- return $value ?? Invoice::BILL_QUARTERLY;
- }
-
/**
* Return the Service Status
*
@@ -1033,6 +857,7 @@ class Service extends Model implements IDs
public function actions(): Collection
{
$next = $this->getStageParameters($this->order_status)->get('next');
+
return $next
? $next->map(function($item,$key) {
$authorized = FALSE;
@@ -1050,6 +875,22 @@ class Service extends Model implements IDs
: collect();
}
+ /**
+ * This service billing charge, pre-taxes
+ *
+ * @return float
+ */
+ public function billing_charge(): float
+ {
+ // If recur_schedule is null, then we only bill this item once
+ if (is_null($this->getBillingIntervalAttribute()) && $this->getInvoicedToAttribute())
+ $this->price = 0;
+
+ return is_null($this->price)
+ ? $this->product->getBaseChargeAttribute($this->getBillingIntervalAttribute(),$this->account->group)
+ : $this->price;
+ }
+
/**
* Get the stage parameters
*
@@ -1108,7 +949,8 @@ class Service extends Model implements IDs
*/
public function isActive(): bool
{
- return $this->attributes['active'] || ($this->order_status && (! in_array($this->order_status,self::INACTIVE_STATUS)));
+ return $this->attributes['active']
+ || ($this->order_status && (! in_array($this->order_status,self::INACTIVE_STATUS)));
}
/**
@@ -1180,17 +1022,6 @@ class Service extends Model implements IDs
return ! is_null($this->price);
}
- /**
- * Should this service be invoiced soon
- *
- * @param int $days
- * @return bool
- */
- public function isInvoiceDueSoon($days=30): bool
- {
- return $this->isBilled() AND $this->getInvoiceNextAttribute()->lessThan(now()->addDays($days));
- }
-
/**
* Identify if a service is being ordered, ie: not active yet nor cancelled
*
@@ -1206,95 +1037,88 @@ class Service extends Model implements IDs
/**
* Generate a collection of invoice_item objects that will be billed for the next invoice
*
- * @param bool $future Next item to be billed (not in the next x days)
* @param Carbon|null $billdate
* @return Collection
* @throws Exception
- * @todo This query is expensive.
*/
- public function next_invoice_items(bool $future,Carbon $billdate=NULL): Collection
+ public function next_invoice_items(Carbon $billdate=NULL): Collection
{
- if ($this->wasCancelled() OR (! $this->isBilled()) OR (! $future AND ! $this->active))
+ if ($this->wasCancelled() || (! $this->isBilled()))
return collect();
- if (is_null($billdate))
- $billdate = Carbon::now()->addDays(30);
+ $o = collect();
+ $invoiced_to = $this->getInvoiceNextAttribute();
- // If pending, add any connection charges
- // Connection charges are only charged once
- if ((! $this->invoice_items->filter(function($item) { return $item->item_type==4; })->sum('total'))
- AND ($this->isPending() OR is_null($this->invoice_to))
- AND $this->product->getSetupChargeAttribute($this->recur_schedule,$this->account->group))
+ // Connection charges are only charged once, so ignore if if we have already billed them
+ if ((! $this->invoiced_items()->where('item_type',InvoiceItem::INVOICEITEM_SETUP)->count())
+ && (InvoiceItem::distinct('invoice_id')->where('service_id',$this->id)->count() < 2)
+ && $this->product->getSetupChargeAttribute($this->getBillingIntervalAttribute(),$this->account->group))
{
- $o = new InvoiceItem;
+ $ii = new InvoiceItem;
- $o->active = TRUE;
- $o->service_id = $this->id;
- $o->product_id = $this->product_id;
- $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->start_at = $this->invoice_next;
- $o->stop_at = $this->invoice_next;
- $o->quantity = 1;
- $o->site_id = 1; // @todo
+ $ii->active = TRUE;
+ $ii->service_id = $this->id;
+ $ii->product_id = $this->product_id;
+ $ii->item_type = InvoiceItem::INVOICEITEM_SETUP;
+ $ii->price_base = $this->product->getSetupChargeAttribute($this->getBillingIntervalAttribute(),$this->account->group);
+ $ii->start_at = $this->invoice_next;
+ $ii->stop_at = $this->invoice_next;
+ $ii->quantity = 1;
+ $ii->site_id = 1; // @todo
- $o->addTaxes($this->account->country->taxes);
- $this->invoice_items->push($o);
+ $ii->addTaxes($this->account->country->taxes);
+ $o->push($ii);
}
- // If the service is active, there will be service charges
- if ((! $this->invoice_items->filter(function($item) { return $item->item_type==0 AND ! $item->exists; })->count())
- AND ($this->active OR $this->isPending())
- AND (
- (($future == TRUE) AND $this->invoice_next < $this->invoice_next_end) OR
- (($future == FALSE) AND ($this->invoice_to < ($this->stop_at ?: $billdate)))
- ))
- {
- do {
- $o = new InvoiceItem;
- $o->active = TRUE;
- $o->service_id = $this->id;
- $o->product_id = $this->product_id;
- $o->item_type = 0;
- $o->price_base = is_null($this->price)
- ? (is_null($this->price) ? $this->product->getBaseChargeAttribute($this->recur_schedule,$this->account->group) : $this->price)
- : $this->price; // @todo change to a method in this class
- $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
+ // The service charges
+ if (is_null($billdate))
+ $billdate = $invoiced_to->clone()->addDays(config('osb.invoice_days'));
- $o->addTaxes($this->account->country->taxes);
- $this->invoice_items->push($o);
- } while ($future == FALSE AND ($this->invoice_to < ($this->stop_at ?: $billdate)));
+ while ($invoiced_to < ($this->stop_at ?: $billdate)) {
+ $ii = new InvoiceItem;
+ $period = Invoice::invoice_period($invoiced_to,$this->getBillingIntervalAttribute(),$this->product->price_recur_strict);
+
+ $ii->active = TRUE;
+ $ii->service_id = $this->id;
+ $ii->product_id = $this->product_id;
+ $ii->item_type = InvoiceItem::INVOICEITEM_SERVICE;
+ $ii->price_base = $this->billing_charge();
+ $ii->recur_schedule = $this->getBillingIntervalAttribute();
+ $ii->start_at = $invoiced_to;
+ $ii->stop_at = ($this->stop_at && ($this->stop_at < Arr::get($period,'end'))) ? $this->stop_at : Arr::get($period,'end');
+ $ii->quantity = Invoice::invoice_quantity($ii->start_at,$ii->stop_at,$period);
+ $ii->site_id = 1; // @todo
+
+ $ii->addTaxes($this->account->country->taxes);
+ $o->push($ii);
+
+ $invoiced_to = $ii->stop_at
+ ->clone()
+ ->addDay()
+ ->startOfDay();
}
// Add additional charges
- if ((($future == TRUE) OR (($future == FALSE) AND ($this->invoice_to >= $billdate)))
- AND ! $this->invoice_items->filter(function($item) { return $item->module_id == 30 AND ! $item->exists; })->count())
- {
- foreach ($this->charges->filter(function($item) { return $item->unprocessed; }) as $oo) {
- $o = new InvoiceItem;
- $o->active = TRUE;
- $o->service_id = $oo->service_id;
- $o->product_id = $this->product_id;
- $o->quantity = $oo->quantity;
- $o->item_type = $oo->type;
- $o->price_base = $oo->amount;
- $o->start_at = $oo->start_at;
- $o->stop_at = $oo->stop_at;
- $o->module_id = 30; // @todo This shouldnt be hard coded
- $o->module_ref = $oo->id;
- $o->site_id = 1; // @todo
+ foreach ($this->charges->filter(function($item) { return $item->unprocessed; }) as $oo) {
+ $ii = new InvoiceItem;
- $o->addTaxes($this->account->country->taxes);
- $this->invoice_items->push($o);
- }
+ $ii->active = TRUE;
+ $ii->service_id = $oo->service_id;
+ $ii->product_id = $this->product_id;
+ $ii->quantity = $oo->quantity;
+ $ii->item_type = $oo->type;
+ $ii->price_base = $oo->amount;
+ $ii->start_at = $oo->start_at;
+ $ii->stop_at = $oo->stop_at;
+ $ii->module_id = 30; // @todo This shouldnt be hard coded
+ $ii->module_ref = $oo->id;
+ $ii->site_id = 1; // @todo
+
+ $ii->addTaxes($this->account->country->taxes);
+ $o->push($ii);
}
- return $this->invoice_items->filter(function($item) { return ! $item->exists; });
+ return $o;
}
/**
diff --git a/app/Models/Service/Broadband.php b/app/Models/Service/Broadband.php
index 3874c03..62cfa75 100644
--- a/app/Models/Service/Broadband.php
+++ b/app/Models/Service/Broadband.php
@@ -48,11 +48,13 @@ class Broadband extends Type implements ServiceUsage
* The usage information for broadband
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
+ * @todo rename to usage()
*/
public function traffic()
{
return $this->hasMany(UsageBroadband::class,'service_item_id')
- ->where('site_id',$this->site_id);
+ ->where('date','>=',Carbon::now()->startOfMonth());
+ //->where('site_id',$this->site_id);
}
/* ATTRIBUTES */
@@ -154,8 +156,6 @@ class Broadband extends Type implements ServiceUsage
if (! $maxdate)
return collect();
- Log::debug(sprintf('%s:Getting Usage data for [%d] months from [%s]',self::LOGKEY,$months,$maxdate),['m'=>__METHOD__]);
-
// Go back an extra month;
$start = $maxdate->date->subMonths($months);
@@ -166,8 +166,6 @@ class Broadband extends Type implements ServiceUsage
$start = $start->subDays($start->day-15);
}
- Log::debug(sprintf('%s:Getting Usage data from [%s]',self::LOGKEY,$start->format('Y-m-d')),['m'=>__METHOD__]);
-
$result = collect();
foreach ($this->traffic()
diff --git a/app/Models/Service/Type.php b/app/Models/Service/Type.php
index 599fa78..45b0847 100644
--- a/app/Models/Service/Type.php
+++ b/app/Models/Service/Type.php
@@ -3,6 +3,7 @@
namespace App\Models\Service;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Collection;
use Leenooks\Carbon as LeenooksCarbon;
use App\Interfaces\ServiceItem;
@@ -41,6 +42,14 @@ abstract class Type extends Model implements ServiceItem
return $this->morphOne(Service::class,'type','model','id','service_id');
}
+ public function traffic()
+ {
+ // Return a null relationship by default, if the child class doesnt track usage (and thus no usage table)
+ return $this->hasMany(Generic::class,'id')
+ ->where('id',NULL)
+ ->where('site_id',$this->site_id);
+ }
+
/* INTERFACE */
public function getContractTermAttribute(): int
@@ -97,4 +106,15 @@ abstract class Type extends Model implements ServiceItem
{
return $this->service->offering->supplied ?: new \App\Models\Supplier\Generic();
}
+
+ /**
+ * Default usage summary is empty if the underlying model doesnt capture usage
+ *
+ * @param int $months
+ * @return Collection
+ */
+ public function usage_summary(int $months=2): Collection
+ {
+ return collect();
+ }
}
\ No newline at end of file
diff --git a/app/Models/Usage/Broadband.php b/app/Models/Usage/Broadband.php
index 4f9632c..1f1e639 100644
--- a/app/Models/Usage/Broadband.php
+++ b/app/Models/Usage/Broadband.php
@@ -3,25 +3,23 @@
namespace App\Models\Usage;
use Carbon\Carbon;
-use Illuminate\Database\Eloquent\Model;
use App\Models\Service\Broadband as ServiceBroadband;
+use Illuminate\Support\Facades\Log;
-class Broadband extends Model
+class Broadband extends Type
{
- protected $casts = [
- 'date'=>'datetime:Y-m-d',
- ];
-
protected $table = 'usage_broadband';
- public $timestamps = FALSE;
private $traffic_end = 14;
/* RELATIONS */
+ /* @todo rename to service() and put in parent */
+ /* @deprecated */
public function broadband()
{
+ Log::alert('deprecated function '.__METHOD__);
return $this->belongsTo(ServiceBroadband::class);
}
diff --git a/app/Models/Usage/Type.php b/app/Models/Usage/Type.php
new file mode 100644
index 0000000..a2827a2
--- /dev/null
+++ b/app/Models/Usage/Type.php
@@ -0,0 +1,14 @@
+'datetime:Y-m-d',
+ ];
+
+ public $timestamps = FALSE;
+}
\ No newline at end of file
diff --git a/app/Traits/ScopeServiceActive.php b/app/Traits/ScopeServiceActive.php
index 35eddc3..944c910 100644
--- a/app/Traits/ScopeServiceActive.php
+++ b/app/Traits/ScopeServiceActive.php
@@ -14,12 +14,23 @@ trait ScopeServiceActive
*/
public function scopeServiceActive($query)
{
- return $query->where(function($q) {
- return $q->where('services.active',TRUE)
- ->orWhere(function($q) {
- return $q->whereNotNull('order_status')
- ->whereNotIn('services.order_status',Service::INACTIVE_STATUS);
- });
- });
+ return $query
+ ->where(fn($q)=>
+ $q->where('services.active',TRUE)
+ ->orWhere(fn($q)=>
+ $q->whereNotNull('order_status')
+ ->whereNotIn('services.order_status',Service::INACTIVE_STATUS))
+ );
+ }
+
+ public function scopeServiceInactive($query)
+ {
+ return $query
+ ->where(fn($q)=>
+ $q->where('services.active',FALSE)
+ ->orWhere(fn($q)=>
+ $q->whereNotNull('order_status')
+ ->whereIn('services.order_status',Service::INACTIVE_STATUS))
+ );
}
}
diff --git a/config/osb.php b/config/osb.php
index dc2aa7a..dcede2c 100644
--- a/config/osb.php
+++ b/config/osb.php
@@ -3,5 +3,6 @@
return [
'language_id' => 1,
'invoice_text' => 'Thank you for using our Internet Services.',
+ 'invoice_days' => 30, // Days in Advance to invoice
'admin' => env('APP_ADMIN'),
];
\ No newline at end of file
diff --git a/public/plugin/dataTables/leftSearchPanes.css b/public/plugin/dataTables/leftSearchPanes.css
index 52ae593..2b07579 100644
--- a/public/plugin/dataTables/leftSearchPanes.css
+++ b/public/plugin/dataTables/leftSearchPanes.css
@@ -4,55 +4,28 @@ table.dataTable tr.dtrg-group.dtrg-level-1 td {
}
/* RENDERING */
+/* Spacing between sp and table */
div.dtsp-verticalPanes {
- margin-right: 10px;
+ margin-right: 1em;
}
div.dtsp-panesContainer {
margin-top: 0px;
margin-bottom: 0px;
- width: 15em;
-}
-
-div.dtsp-subRow1 {
- width: 100%;
-}
-
-div.dtsp-searchCont input.dtsp-search.dtsp-disabledButton {
- background: #eaeaea;
- font-size: larger;
- border-radius: 3px;
-}
-
-div.dtsp-searchCont input.dtsp-search.dtsp-disabledButton::placeholder,
-div.dtsp-searchCont input.dtsp-search.dtsp-disabledButton:-moz-placeholder,
-div.dtsp-searchCont input.dtsp-search.dtsp-disabledButton::-moz-placeholder,
-div.dtsp-searchCont input.dtsp-search.dtsp-disabledButton::-webkit-input-placeholder {
- color: #000000;
- font-weight: bold;
+ width: 18em;
}
div.dtsp-titleRow {
- margin-top: 13px;
- padding: 5px;
+ padding: 0.5em;
}
div.dtsp-titleRow button {
- padding: 0 0 0 5px !important;
+ padding: 0 0 0 3px !important;
+ margin-bottom: 1px;
font-size: 90%;
}
-div.dtsp-titleRow div.dtsp-title {
- padding: 1px;
- margin: 0 !important;
- font-weight: bolder;
-}
-
-div.dtsp-panesContainer div.dtsp-searchPanes div.dtsp-searchPane div.dataTables_scrollBody div.dtsp-nameCont span.dtsp-pill {
- min-width: 4em;
-}
-
-div.dtsp-verticalContainer{
+div.dtsp-verticalContainer {
display: flex;
flex-direction: row;
flex-wrap: wrap;
@@ -62,42 +35,45 @@ div.dtsp-verticalContainer{
}
div.dtsp-verticalContainer div.dtsp-verticalPanes,
-div.dtsp-verticalContainer div.dtsp-dataTable{
+div.dtsp-verticalContainer div.dtsp-dataTable {
width: 50%;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 0;
}
-div.dtsp-verticalContainer div.dtsp-verticalPanes{
+div.dtsp-verticalContainer div.dtsp-verticalPanes {
background: rgba(33, 39, 45, 0.1);
border-radius: 6px;
- border: 1px solid #ccc;
+ border: 1px solid #aaa;
}
-div.dtsp-title {
- margin-right: 0px !important;
- margin-top: 13px !important;
- margin-left: 5px !important;
+/* Fix Search input */
+div.dtsp-dataTable .dt-search {
+ text-align: right;
+ padding-bottom: 0.5em;
}
-input.dtsp-search {
- min-width: 0px !important;
- padding-left: 0px !important;
- margin: 0px !important;
+/* Fix Table Result */
+div.dtsp-dataTable .dt-info {
+ float: left;
+ padding-top: 0.75em;
}
-div.dtsp-verticalContainer div.dtsp-verticalPanes div.dtsp-searchPanes{
- flex-direction: column;
- flex-basis: 0px;
+/* Fix pagination */
+div.dtsp-dataTable .dt-paging {
+ float: right;
+ padding-top: 0.5em;
}
-div.dtsp-verticalContainer div.dtsp-verticalPanes div.dtsp-searchPanes div.dtsp-searchPane{
- flex-basis: 0px;
+/* Titles */
+div.dtsp-panesContainer div.dtsp-searchPane div.dtsp-topRow input.form-control {
+ font-weight: bold;
+ padding-top: 0.5em;
+ padding-left: 0;
}
-
div.dtsp-verticalContainer div.dtsp-dataTable{
flex-grow: 1;
flex-shrink: 0;
flex-basis: auto;
-}
+}
\ No newline at end of file
diff --git a/resources/views/email/admin/order/approve.blade.php b/resources/views/email/admin/order/approve.blade.php
index 12d8137..bf59857 100644
--- a/resources/views/email/admin/order/approve.blade.php
+++ b/resources/views/email/admin/order/approve.blade.php
@@ -8,7 +8,7 @@ Please order the following...
| Account | {{ $service->account->name }} |
| Service ID | {{ $service->sid }} |
| Product | {{ $service->product->name }} |
-@switch($service->category)
+@switch($service->product->category)
@case('broadband')
| Address | {{ $service->type->service_address }} |
@break;
diff --git a/resources/views/email/admin/order/reject.blade.php b/resources/views/email/admin/order/reject.blade.php
index dbd39b3..d9abee2 100644
--- a/resources/views/email/admin/order/reject.blade.php
+++ b/resources/views/email/admin/order/reject.blade.php
@@ -9,7 +9,7 @@
| Account | {{ $service->account->name }} |
| Service ID | {{ $service->sid }} |
| Product | {{ $service->product->name }} |
-@switch($service->category)
+@switch($service->product->category)
@case('broadband')
| Address | {{ is_object($service->type) ? $service->type->service_address : 'Not Supplied' }} |
@break;
diff --git a/resources/views/email/admin/service/cancel.blade.php b/resources/views/email/admin/service/cancel.blade.php
index 7c15174..3694085 100644
--- a/resources/views/email/admin/service/cancel.blade.php
+++ b/resources/views/email/admin/service/cancel.blade.php
@@ -8,7 +8,7 @@ Please cancel the following...
| Account | {{ $service->account->name }} |
| Service ID | {{ $service->sid }} |
| Product | {{ $service->product->name }} |
-@switch($service->category)
+@switch($service->product->category)
@case('broadband')
| Address | {{ $service->type->service_address }} |
@break;
diff --git a/resources/views/email/admin/service/change.blade.php b/resources/views/email/admin/service/change.blade.php
index db38dbc..db3aaeb 100644
--- a/resources/views/email/admin/service/change.blade.php
+++ b/resources/views/email/admin/service/change.blade.php
@@ -8,7 +8,7 @@ Please change the following...
| Account | {{ $service->account->name }} |
| Service ID | {{ $service->sid }} |
| Product | {{ $service->product->name }} |
-@switch($service->category)
+@switch($service->product->category)
@case('broadband')
| Address | {{ $service->type->service_address }} |
@break;
diff --git a/resources/views/theme/backend/adminlte/account/widget/summary_boxes.blade.php b/resources/views/theme/backend/adminlte/account/widget/summary_boxes.blade.php
index 60ea198..a8f338f 100644
--- a/resources/views/theme/backend/adminlte/account/widget/summary_boxes.blade.php
+++ b/resources/views/theme/backend/adminlte/account/widget/summary_boxes.blade.php
@@ -37,7 +37,7 @@
Active Services
- {{ Service::active()->whereIn('account_id',$acts)->count() }} /{{ Service::whereIn('account_id',$acts)->count() }}
+ {{ Service::ServiceActive()->whereIn('account_id',$acts)->count() }} /{{ Service::whereIn('account_id',$acts)->count() }}
diff --git a/resources/views/theme/backend/adminlte/product/report.blade.php b/resources/views/theme/backend/adminlte/product/report.blade.php
index 89f637a..c7c5a11 100644
--- a/resources/views/theme/backend/adminlte/product/report.blade.php
+++ b/resources/views/theme/backend/adminlte/product/report.blade.php
@@ -32,7 +32,7 @@
@foreach (\App\Models\Service::active()->with(['product.translate'])->get()->groupBy('product_id') as $s)
{{ $x->id }} |
- {{ $x->category_name }} |
+ {{ $x->product->category_name }} |
{{ $x->product->pid }} |
{{ $x->product->name }} |
{{ $s->count() }} |
diff --git a/resources/views/theme/backend/adminlte/service/report.blade.php b/resources/views/theme/backend/adminlte/service/report.blade.php
index d4ebe90..6557d0c 100644
--- a/resources/views/theme/backend/adminlte/service/report.blade.php
+++ b/resources/views/theme/backend/adminlte/service/report.blade.php
@@ -1,3 +1,5 @@
+@use(App\Models\Service)
+
@extends('adminlte::layouts.app')
@section('htmlheader_title')
@@ -25,21 +27,20 @@
Product |
Monthly |
Cost |
- Traffic (GB) |
+ Usage |
Supplier |
- {{-- @todo This query is expensive still --}}
- @foreach (\App\Models\Service::active()->with(['type','product.type.supplied.supplier_detail.supplier','product.translate'])->get() as $o)
+ @foreach (Service::ServiceActive()->with(['account.taxes','type','product.type.supplied.supplier_detail.supplier','product.translate','type.traffic'])->get() as $o)
{{ $o->id }} |
{{ $o->name }} |
{{ $o->product->name }} |
- {{ number_format($o->billing_monthly_price,2) }} |
+ {{ number_format($o->billing_charge_normalised,2) }} |
{{ number_format($o->product->cost_normalized(),2) }} |
- {{ $o->category == 'broadband' ? number_format($o->type->usage_summary(0)->sum()/1000,1) : '-' }} |
+ {{ $o->product->hasUsage() ? number_format($o->type->usage_summary(0)->sum()/1000,1) : '-' }} |
{{ $o->product->supplier->name }} |
@endforeach
@@ -50,51 +51,60 @@
@endsection
+@pa(datatables,rowgroup|conditionalpaging|select|searchpanes|searchpanes-left)
+
@section('page-scripts')
- @css(datatables,bootstrap4|fixedheader|responsive|rowgroup|buttons)
- @js(datatables,bootstrap4|fixedheader|responsive|rowgroup|buttons)
-
-
-
+ $(document).ready(function() {
+ $('#table').DataTable({
+ //oSearch: { sSearch: searchString ? decodeURIComponent(searchString) : '' },
+ aLengthMenu: [
+ [25, 50, 100, 200, -1],
+ [25, 50, 100, 200, "All"]
+ ],
+ paging: true,
+ pageLength: 25,
+ conditionalPaging: true,
+ lengthChange: true,
+ searching: true,
+ ordering: true,
+ info: true,
+ autoWidth: false,
+ fixedHeader: true,
+ order: [
+ [2,'asc'],
+ [1,'asc'],
+ ],
+ rowGroup: {
+ dataSrc: [2],
+ },
+ columnDefs: [
+ {
+ targets: [2],
+ visible: false,
+ },
+ {
+ targets: [0,1,3,4,5],
+ searchPanes: {
+ show: false,
+ }
+ },
+ ],
+ language: {
+ searchPanes: {
+ title: 'Filters: %d',
+ collapse: 'Filter',
+ }
+ },
+ searchPanes: {
+ cascadePanes: true,
+ viewTotal: true,
+ layout: 'columns-1',
+ dataLength: 20,
+ controls: false,
+ },
+ dom: '<"dtsp-verticalContainer"<"dtsp-verticalPanes"P><"dtsp-dataTable"Bfrtip>>',
+ });
+ });
+
@append
\ No newline at end of file
diff --git a/resources/views/theme/backend/adminlte/service/widget/information.blade.php b/resources/views/theme/backend/adminlte/service/widget/information.blade.php
index 4a1e72a..951e00f 100644
--- a/resources/views/theme/backend/adminlte/service/widget/information.blade.php
+++ b/resources/views/theme/backend/adminlte/service/widget/information.blade.php
@@ -8,11 +8,11 @@
@endif
-