diff --git a/app/Http/Controllers/UserHomeController.php b/app/Http/Controllers/UserHomeController.php index 86929a2..97772b7 100644 --- a/app/Http/Controllers/UserHomeController.php +++ b/app/Http/Controllers/UserHomeController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use Illuminate\Support\Facades\Auth; + use App\Models\{Invoice,Service}; use App\User; use PDF; diff --git a/app/Models/Base/ProductType.php b/app/Models/Base/ProductType.php new file mode 100644 index 0000000..d66057c --- /dev/null +++ b/app/Models/Base/ProductType.php @@ -0,0 +1,14 @@ +hasMany(ProductTranslate::class); @@ -21,6 +33,16 @@ class Product extends Model return $this->hasMany(Service::class); } + /** + * Return a child model with details of the service + * + * @return \Illuminate\Database\Eloquent\Relations\MorphTo + */ + public function type() + { + return $this->morphTo(null,'model','prod_plugin_data'); + } + /** * Get the service category (from the product) * @@ -91,6 +113,14 @@ class Product extends Model return $this->descriptions->where('language_id',$lo->id)->first()->description_short; } + public function getNameShortAttribute(Language $lo=NULL) + { + if (is_null($lo)) + $lo = $this->getDefaultLanguage(); + + return $this->descriptions->where('language_id',$lo->id)->first()->name; + } + public function getProductTypeAttribute() { return $this->plugin()->product->name; @@ -149,6 +179,11 @@ class Product extends Model } } + public function price(int $period) + { + return Arr::get($this->price_array,sprintf('%s.1.price_base',$period)); + } + public function PricePeriods() { return [ diff --git a/app/Models/Product/Adsl.php b/app/Models/Product/Adsl.php new file mode 100644 index 0000000..ce7fb99 --- /dev/null +++ b/app/Models/Product/Adsl.php @@ -0,0 +1,36 @@ +hasOne(AdslSupplierPlan::class,'id','adsl_supplier_plan_id'); + } + + public function __get($key) + { + switch($key) + { + case 'base_down_peak': + return $this->attributes['base_down_peak']/$this->attributes['metric']; + case 'base_down_peak': + return $this->attributes['base_down_offpeak']/$this->attributes['metric']; + case 'speed': + return $this->product->speed; + } + + // If we dont have a specific key, we'll resolve it normally + return parent::__get($key); + } +} \ No newline at end of file diff --git a/app/Models/Product/Domain.php b/app/Models/Product/Domain.php new file mode 100644 index 0000000..8f432ef --- /dev/null +++ b/app/Models/Product/Domain.php @@ -0,0 +1,12 @@ +'array', @@ -97,9 +96,23 @@ class Service extends Model return $this->belongsTo(Account::class); } + /** + * Return Charges associated with this Service + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function charges() + { + return $this->hasMany(Charge::class) + ->where('active','=',TRUE) + ->orderBy('date_orig'); + } + + // @todo changed to invoiced_items public function invoice_items($active=TRUE) { $query = $this->hasMany(InvoiceItem::class) + ->where('item_type','=',0) ->orderBy('date_orig'); if ($active) @@ -131,6 +144,7 @@ class Service extends Model /** * Account that ordered the service * + * @todo changed to orderedby * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function orderby() @@ -215,11 +229,7 @@ class Service extends Model public function getBillingPriceAttribute(): float { - if ($this->price) - return $this->addtax($this->price); - - dd($this->product->price_group,$this); - return $this->cost; + return $this->addTax($this->price ?: $this->product->price($this->recur_schedule)); } /** @@ -248,11 +258,36 @@ class Service extends Model * @todo This function negates the need for date_next_invoice * @return null */ - public function getInvoiceNextAttribute(): Carbon + public function getInvoiceNextAttribute() { $last = $this->getInvoiceToAttribute(); + $date = $last ? $last->addDay() : now(); - return $last ? $last->addDay() : now(); + return request()->wantsJson() ? $date->format('Y-m-d') : $date; + } + + public function getInvoiceNextEndAttribute() + { + switch ($this->recur_schedule) + { + // Weekly + case 0: $date = $this->getInvoiceNextAttribute()->addWeek(); break; + // Monthly + case 1: $date = $this->getInvoiceNextAttribute()->addMonth(); break; + // Quarterly + case 2: $date = $this->getInvoiceNextAttribute()->addQuarter(); break; + // Half Yearly + case 3: $date = $this->getInvoiceNextAttribute()->addQuarter(2); break; + // Yearly + case 4: $date = $this->getInvoiceNextAttribute()->addYear(); break; + // Two Yearly + case 5: $date = $this->getInvoiceNextAttribute()->addYear(2); break; + // Three Yearly + case 6: $date = $this->getInvoiceNextAttribute()->addYear(3); break; + default: throw new \Exception('Unknown recur_schedule'); + } + + return $date->subDay(); } /** @@ -263,6 +298,11 @@ class Service extends Model return $this->invoice_items->count() ? $this->invoice_items->last()->date_stop : NULL; } + public function getNameAttribute(): string + { + return $this->product->name_short.': '.$this->getNameShortAttribute(); + } + /** * Return the short name for the service. * @@ -448,6 +488,8 @@ class Service extends Model public function invoices_due(): Collection { + $this->load('invoice_items.invoice'); + return $this->invoice_items->filter(function($item) { return $item->invoice->due > 0; }); @@ -464,6 +506,28 @@ class Service extends Model return $this->active OR ($this->order_status AND ! in_array($this->order_status,$this->inactive_status)); } + public function next_invoice_items() + { + $result = collect(); + + $result->push([ + 'item'=>0, + 'desc'=>sprintf('Product/Service [%s->%s]', + $this->invoice_next->format('Y-m-d'), + $this->invoice_next_end->format('Y-m-d')), + 'amt'=>$this->getBillingPriceAttribute()]); + + foreach ($this->charges->filter(function($item) { return ! $item->processed; }) as $o) + { + $result->push([ + 'item'=>5, // @tod Charges + 'desc'=>sprintf('%d@%3.2f - %s',$o->quantity,$this->addTax($o->amount),$o->name), + 'amt'=>$this->addTax($o->amount*$o->quantity)]); + } + + return $result; + } + /** * @todo * @param string $status diff --git a/app/User.php b/app/User.php index cb8a5ab..a60f6c7 100644 --- a/app/User.php +++ b/app/User.php @@ -17,7 +17,6 @@ class User extends Authenticatable use HasApiTokens,Notifiable,UserSwitch,HasQuickBooksToken; protected $dates = ['created_at','updated_at','last_access']; - protected $with = ['accounts.services']; /** * The attributes that are mass assignable. diff --git a/database/migrations/2019_06_29_101655_add_model_to_product.php b/database/migrations/2019_06_29_101655_add_model_to_product.php new file mode 100644 index 0000000..79c60b7 --- /dev/null +++ b/database/migrations/2019_06_29_101655_add_model_to_product.php @@ -0,0 +1,57 @@ +string('model')->nullable(); + }); + + // Go through our services and add the relation + foreach (\App\Models\Product\Adsl::all() as $o) + $this->update($o,'ADSL'); + /* + foreach (\App\Models\Product\Domain::all() as $o) + $this->update($o); + foreach (\App\Models\Product\Host::all() as $o) + $this->update($o); + */ + foreach (\App\Models\Product\SSL::all() as $o) + $this->update($o,'SSL'); + /* + foreach (\App\Models\Product\Voip::all() as $o) + $this->update($o); + */ + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('ab_product', function (Blueprint $table) { + $table->dropColumn('model'); + }); + } + + function update(\Illuminate\Database\Eloquent\Model $o,$file) + { + foreach (\App\Models\Product::where('prod_plugin_file',$file)->where('prod_plugin_data',$o->id)->get() as $oo) + { + $oo->model = get_class($o); + $oo->save(); + } + } +} diff --git a/resources/theme/backend/adminlte/common/service/widget/invoice.blade.php b/resources/theme/backend/adminlte/common/service/widget/invoice.blade.php new file mode 100644 index 0000000..6e84b47 --- /dev/null +++ b/resources/theme/backend/adminlte/common/service/widget/invoice.blade.php @@ -0,0 +1,18 @@ +
+
+ Next Invoice Details +
+ +
+ + + + + @foreach ($o->next_invoice_items() as $oo) + + + + @endforeach +
{{ $o->name }}{{ number_format($o->next_invoice_items()->sum('amt'),2) }}
 {{ $oo['desc'] }}{{ number_format($oo['amt'],2) }}
+
+
\ No newline at end of file diff --git a/resources/theme/backend/adminlte/u/service/adsl/ACTIVE.blade.php b/resources/theme/backend/adminlte/u/service/adsl/ACTIVE.blade.php index b2a74f2..3f7e3c2 100644 --- a/resources/theme/backend/adminlte/u/service/adsl/ACTIVE.blade.php +++ b/resources/theme/backend/adminlte/u/service/adsl/ACTIVE.blade.php @@ -84,12 +84,20 @@ - + + @if ($o->product->type->base_down_peak) - + + @endif + @if ($o->product->type->base_down_offpeak) + + + + + @endif @@ -111,7 +119,22 @@
- @include('common.invoice.widget.list') +
+
+ @include('common.service.widget.invoice') + + {{-- @todo show list of outstanding invoices --}} +
+ + {{-- Workaround since col-offset-x is not in our CSS? --}} +
+   +
+ +
+ @include('common.invoice.widget.list') +
+
SpeedTBA{{ $o->product->type->speed }}
Peak Included DownloadsTBA{{ number_format($o->product->type->base_down_peak,0) }}GB
Peak Included Downloads{{ number_format($o->product->type->base_down_offpeak,0) }}MB
Traffic Last Month TBA