diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php
index 0ccdf39..93ddc86 100644
--- a/app/Http/Controllers/SearchController.php
+++ b/app/Http/Controllers/SearchController.php
@@ -27,7 +27,7 @@ class SearchController extends Controller
$accounts = ($x=Auth::user()->all_accounts())->pluck('id');
$users = $x->transform(function($item) { return $item->user;});
- # Look for Account
+ # Look for User
foreach (User::Search($request->input('term'))
->whereIN('id',$users->pluck('id'))
->orderBy('lastname')
@@ -37,6 +37,15 @@ class SearchController extends Controller
$result->push(['label'=>sprintf('US:%s %s',$o->aid,$o->name),'value'=>'/u/home/'.$o->id]);
}
+ # Look for Account
+ foreach (Account::Search($request->input('term'))
+ ->whereIN('user_id',$users->pluck('id'))
+ ->orderBy('company')
+ ->limit(10)->get() as $o)
+ {
+ $result->push(['label'=>sprintf('AC:%s %s',$o->aid,$o->company),'value'=>'/u/home/'.$o->user_id]);
+ }
+
# Look for a Service
foreach (Service::Search($request->input('term'))
->whereIN('account_id',$accounts)
diff --git a/app/Http/Controllers/UserHomeController.php b/app/Http/Controllers/UserHomeController.php
index 9676863..88d9604 100644
--- a/app/Http/Controllers/UserHomeController.php
+++ b/app/Http/Controllers/UserHomeController.php
@@ -24,8 +24,11 @@ class UserHomeController extends Controller
*/
public function home(User $o=NULL): View
{
- if (is_null($o))
- $o = Auth::user();
+ if ($o)
+ return View('u.home',['o'=>$o]);
+
+ // If User was null, then test and see what type of logged on user we have
+ $o = Auth::user();
switch (Auth::user()->role()) {
case 'customer':
diff --git a/app/Models/Account.php b/app/Models/Account.php
index 6973f3c..05f9a26 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -2,7 +2,6 @@
namespace App\Models;
-use App\User;
use Illuminate\Database\Eloquent\Model;
use App\Traits\NextKey;
@@ -10,9 +9,7 @@ use App\Traits\NextKey;
class Account extends Model
{
use NextKey;
-
const RECORD_ID = 'account';
-
public $incrementing = FALSE;
protected $table = 'ab_account';
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index 6d2a460..f9dddf2 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -8,7 +8,7 @@ class Invoice extends Model
{
protected $table = 'ab_invoice';
protected $dates = ['date_orig','due_date'];
- protected $with = ['account.country.currency','items','paymentitems'];
+ protected $with = ['account.country.currency','items.taxes','paymentitems'];
protected $appends = [
'date_due',
diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php
index 6d34d16..d589c1a 100644
--- a/app/Models/InvoiceItem.php
+++ b/app/Models/InvoiceItem.php
@@ -2,8 +2,10 @@
namespace App\Models;
+use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
+
use Leenooks\Carbon;
class InvoiceItem extends Model
@@ -11,7 +13,6 @@ class InvoiceItem extends Model
protected $dates = ['date_start','date_stop'];
public $dateFormat = 'U';
protected $table = 'ab_invoice_item';
- protected $with = ['taxes'];
private $_tax = 0;
@@ -20,6 +21,11 @@ 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);
@@ -131,13 +137,13 @@ class InvoiceItem extends Model
/**
* Add taxes to this record
*/
- public function addTaxes()
+ public function addTaxes(Collection $taxes)
{
// Refuse to change an existing record
if ($this->exists)
throw new \Exception('Refusing to add Taxes to existing record');
- foreach($this->service->account->country->taxes as $to)
+ foreach($taxes as $to)
{
$iit = new InvoiceItemTax;
$iit->tax_id = $to->id;
diff --git a/app/Models/Service.php b/app/Models/Service.php
index 7eef306..9640f54 100644
--- a/app/Models/Service.php
+++ b/app/Models/Service.php
@@ -191,9 +191,6 @@ class Service extends Model
*/
public function type()
{
- if (! $this->model)
- abort(500,'Missing Model in',['service'=>$this]);
-
return $this->morphTo(null,'model','id','service_id');
}
@@ -772,7 +769,7 @@ class Service extends Model
$o->date_stop = $this->invoice_next_end;
$o->quantity = $this->invoice_next_quantity;
- $o->addTaxes();
+ $o->addTaxes($this->account->country->taxes);
$result->push($o);
}
@@ -789,7 +786,7 @@ class Service extends Model
$o->date_stop = $this->invoice_next;
$o->quantity = 1;
- $o->addTaxes();
+ $o->addTaxes($this->account->country->taxes);
$result->push($o);
}
@@ -807,7 +804,7 @@ class Service extends Model
$o->module_id = 30; // @todo This shouldnt be hard coded
$o->module_ref = $oo->id;
- $o->addTaxes();
+ $o->addTaxes($this->account->country->taxes);
$result->push($o);
}
diff --git a/app/Models/Service/Adsl.php b/app/Models/Service/Adsl.php
index dca9b77..f0b9118 100644
--- a/app/Models/Service/Adsl.php
+++ b/app/Models/Service/Adsl.php
@@ -68,7 +68,7 @@ class Adsl extends ServiceType implements ServiceItem
*/
public function getServiceDescriptionAttribute(): string
{
- return $this->service_address ?: 'NO Service Address';
+ return strtoupper($this->service_address) ?: 'NO Service Address';
}
/**
diff --git a/app/Models/Service/Voip.php b/app/Models/Service/Voip.php
index 12c697e..4dd7e6d 100644
--- a/app/Models/Service/Voip.php
+++ b/app/Models/Service/Voip.php
@@ -2,24 +2,33 @@
namespace App\Models\Service;
+use App\Interfaces\ServiceItem;
+use App\Models\Base\ServiceType;
use App\Traits\NextKey;
-class Voip extends \App\Models\Base\ServiceType
+class Voip extends ServiceType implements ServiceItem
{
use NextKey;
-
const RECORD_ID = 'service__adsl';
protected $table = 'ab_service__voip';
- public function getFullNameAttribute()
+ /**
+ * Return the service address
+ *
+ * @return string
+ */
+ public function getServiceDescriptionAttribute(): string
{
- return ($this->service_number AND $this->service_address)
- ? sprintf('%s: %s',$this->service_number, $this->service_address)
- : $this->name;
+ return $this->service_address ?: 'VOIP';
}
- public function getNameAttribute()
+ /**
+ * Return the service number
+ *
+ * @return string
+ */
+ public function getServiceNameAttribute(): string
{
return $this->service_number;
}
diff --git a/app/User.php b/app/User.php
index 970849e..35a017f 100644
--- a/app/User.php
+++ b/app/User.php
@@ -2,7 +2,6 @@
namespace App;
-use App\Models\Site;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Collection;
@@ -12,32 +11,38 @@ use Laravel\Passport\HasApiTokens;
use Leenooks\Carbon;
use Leenooks\Traits\UserSwitch;
use App\Notifications\ResetPassword as ResetPasswordNotification;
+use App\Models\Site;
use App\Models\Service;
use Spinen\QuickBooks\HasQuickBooksToken;
class User extends Authenticatable
{
- use HasApiTokens,Notifiable,UserSwitch,HasQuickBooksToken;
+ use HasApiTokens,Notifiable,UserSwitch,HasQuickBooksToken;
- protected $dates = ['created_at','updated_at','last_access'];
+ protected $dates = [
+ 'created_at',
+ 'updated_at',
+ 'last_access'
+ ];
- /**
- * The attributes that are mass assignable.
- *
- * @var array
- */
- protected $fillable = [
- 'name', 'email', 'password',
- ];
+ /**
+ * The attributes that are mass assignable.
+ *
+ * @var array
+ */
+ protected $fillable = [
+ 'name', 'email', 'password',
+ ];
- /**
- * The attributes that should be hidden for arrays.
- *
- * @var array
- */
- protected $hidden = [
- 'password', 'remember_token',
- ];
+ /**
+ * The attributes that should be hidden for arrays.
+ *
+ * @var array
+ */
+ protected $hidden = [
+ 'password',
+ 'remember_token',
+ ];
protected $appends = [
'active_display',
@@ -57,49 +62,92 @@ class User extends Authenticatable
'user_id_url',
];
+ /**
+ * The accounts that this user manages
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
public function accounts()
- {
+ {
return $this->hasMany(Models\Account::class);
- }
+ }
+ /**
+ * The agents that this users manages
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
public function agents() {
return $this->hasMany(static::class,'parent_id','id')->with('agents');
}
+ /**
+ * The clients that this user has
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
public function clients() {
- return $this->hasMany(static::class,'parent_id','id')->with('clients');
+ return $this
+ ->hasMany(static::class,'parent_id','id')
+ ->with('clients');
}
+ /**
+ * This users language configuration
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
+ */
public function language()
{
return $this->belongsTo(Models\Language::class);
}
+ /**b
+ * This users invoices
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
+ */
public function invoices()
{
return $this->hasManyThrough(Models\Invoice::class,Models\Account::class);
}
+ /**
+ * The payments this user has made
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
+ */
public function payments()
{
return $this->hasManyThrough(Models\Payment::class,Models\Account::class);
}
- public function site()
- {
- return $this->belongsTo(Site::class);
- }
-
+ /**
+ * THe services this user has
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
+ */
public function services()
{
- return $this->hasManyThrough(Models\Service::class,Models\Account::class);
+ return $this->hasManyThrough(Models\Service::class,Models\Account::class)
+ ->with(['account','product','invoices.items.tax','type']);
}
+ /**
+ * This users supplier/reseller
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
+ */
protected function supplier()
{
return $this->belongsTo(static::class,'parent_id','id');
}
+ /**
+ * Who this user supplies to
+ *
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
+ */
protected function suppliers() {
return $this->hasMany(static::class,'parent_id','id');
}
@@ -116,11 +164,16 @@ class User extends Authenticatable
*
* @return string
*/
- public function getFullNameAttribute()
+ public function getFullNameAttribute(): string
{
return sprintf('%s %s',$this->firstname,$this->lastname);
}
+ /**
+ * A list of all invoices currently unpaid
+ *
+ * @return mixed
+ */
public function getInvoicesDueAttribute()
{
return $this->invoices
@@ -131,9 +184,17 @@ class User extends Authenticatable
->filter();
}
+ /**
+ * Get the users language
+ *
+ * For non logged in users we need to populate with a default language
+ * @param $value
+ * @return mixed
+ * @todo This doesnt appear to be used?
+ */
public function getLanguageAttribute($value)
{
- if (is_null($this->language_id))
+ if (is_null($value))
return config('SITE_SETUP')->language;
}
@@ -141,7 +202,8 @@ class User extends Authenticatable
* Return a Carbon Date if it has a value.
*
* @param $value
- * @return \Leenooks\Carbon
+ * @return Carbon
+ * @throws \Exception
* @todo This attribute is not in the schema
*/
public function getLastAccessAttribute($value)
@@ -159,6 +221,12 @@ class User extends Authenticatable
return $this->full_name;
}
+ /**
+ * Return a list of the payments that the user has made
+ *
+ * @return mixed
+ * @todo Merge this with payments()
+ */
public function getPaymentHistoryAttribute()
{
return $this->payments
@@ -166,11 +234,18 @@ class User extends Authenticatable
->reverse();
}
+ /**
+ * The users active services
+ *
+ * @return mixed
+ */
public function getServicesActiveAttribute()
{
- return $this->services->filter(function($item) {
- return $item->isActive();
- });
+ return $this->services
+ ->filter(function($item)
+ {
+ return $item->isActive();
+ });
}
public function getServicesCountHtmlAttribute()
@@ -198,6 +273,11 @@ class User extends Authenticatable
return sprintf('%s',$this->id,$this->user_id);
}
+ /**
+ * Users password reset email notification
+ *
+ * @param string $token
+ */
public function sendPasswordResetNotification($token)
{
$this->notify((new ResetPasswordNotification($token))->onQueue('high'));
@@ -213,7 +293,7 @@ class User extends Authenticatable
/**
* Search for a record
*
- * @param $query
+ * @param $query
* @param string $term
* @return
*/
@@ -253,12 +333,12 @@ class User extends Authenticatable
* @param $id
* @return bool
*/
- public function isAdmin($id)
+ public function isAdmin($id): bool
{
return $id AND $this->isReseller() AND in_array($id,$this->all_accounts()->pluck('id')->toArray());
}
- /** Functions */
+ /** FUNCTIONS */
/**
* Get a list of accounts for the clients of this user
@@ -337,13 +417,17 @@ class User extends Authenticatable
});
}
- // List all the agents, including agents of agents
+ /**
+ * List of all this users agents, recursively
+ *
+ * @param int $level
+ * @return Collection
+ */
public function all_agents($level=0)
{
$result = collect();
- foreach ($this->agents as $o)
- {
+ foreach ($this->agents as $o) {
if (! $o->active OR ! $o->agents->count())
continue;
@@ -363,16 +447,56 @@ class User extends Authenticatable
*
* @return bool
*/
- public function isReseller()
+ public function isReseller(): bool
{
return in_array($this->role(),['wholesaler','reseller']);
}
- public function isWholesaler()
+ /**
+ * Determine if the logged in user is a wholesaler
+ *
+ * @return bool
+ */
+ public function isWholesaler(): bool
{
return in_array($this->role(),['wholesaler']);
}
+ /**
+ * Get all the items for the next invoice
+ *
+ * @return Collection
+ */
+ public function next_invoice_items(bool $future=FALSE): DatabaseCollection
+ {
+ $result = new DatabaseCollection;
+ $this->load([
+ 'services.charges',
+ 'services.invoice_items'
+ ]);
+
+ foreach ($this->services as $o) {
+ if ($future) {
+ if ($o->invoice_next->subDays(config('app.invoice_inadvance'))->isPast())
+ continue;
+
+ } else {
+ if ($o->invoice_next->subDays(config('app.invoice_inadvance'))->isFuture())
+ continue;
+ }
+
+ foreach ($o->next_invoice_items() as $oo)
+ $result->push($oo);
+ }
+
+ $result->load([
+ 'product.descriptions',
+ 'service.type',
+ ]);
+
+ return $result;
+ }
+
public function role()
{
// If I have agents and no parent, I am the wholesaler
diff --git a/composer.lock b/composer.lock
index aa79149..7bd0e2e 100644
--- a/composer.lock
+++ b/composer.lock
@@ -2336,11 +2336,11 @@
},
{
"name": "leenooks/laravel",
- "version": "6.0.14",
+ "version": "6.0.15",
"source": {
"type": "git",
"url": "https://dev.leenooks.net/leenooks/laravel",
- "reference": "176f680ff740d41b6e66723557e2e64721e0d51f"
+ "reference": "96a6830e61a612dbff396a041bc0263f2308a324"
},
"require": {
"creativeorange/gravatar": "^1.0",
@@ -2377,7 +2377,7 @@
"laravel",
"leenooks"
],
- "time": "2020-01-22T09:48:42+00:00"
+ "time": "2020-02-08T06:52:13+00:00"
},
{
"name": "monolog/monolog",
diff --git a/config/app.php b/config/app.php
index 56d93ed..de385cd 100644
--- a/config/app.php
+++ b/config/app.php
@@ -242,4 +242,5 @@ return [
],
+ 'invoice_inadvance'=>30,
];
diff --git a/resources/theme/backend/adminlte/common/invoice/widget/list.blade.php b/resources/theme/backend/adminlte/common/invoice/widget/list.blade.php
index 2c0d5a5..ad2f0c3 100644
--- a/resources/theme/backend/adminlte/common/invoice/widget/list.blade.php
+++ b/resources/theme/backend/adminlte/common/invoice/widget/list.blade.php
@@ -9,6 +9,7 @@
Outstanding |
+
@foreach ($o->invoices as $io)
@@ -32,15 +33,15 @@
@js('/plugin/dataTables/dataTables.bootstrap4.js','dt-bootstrap4-js','jq-dt-js')
@append
\ No newline at end of file
diff --git a/resources/theme/backend/adminlte/r/account/widget/list.blade.php b/resources/theme/backend/adminlte/r/account/widget/list.blade.php
index 1acb0ae..1897641 100644
--- a/resources/theme/backend/adminlte/r/account/widget/list.blade.php
+++ b/resources/theme/backend/adminlte/r/account/widget/list.blade.php
@@ -33,8 +33,8 @@
@section('page-scripts')
- @css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
- @js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
+ @css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery')
+ @js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery')
@css('//cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
@js('//cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
@css('/plugin/dataTables/dataTables.bootstrap4.css','dt-bootstrap4-css','jq-dt-css')
diff --git a/resources/theme/backend/adminlte/r/home.blade.php b/resources/theme/backend/adminlte/r/home.blade.php
index 898028a..818dc4e 100644
--- a/resources/theme/backend/adminlte/r/home.blade.php
+++ b/resources/theme/backend/adminlte/r/home.blade.php
@@ -22,7 +22,6 @@
diff --git a/resources/theme/backend/adminlte/r/service/widget/movement.blade.php b/resources/theme/backend/adminlte/r/service/widget/movement.blade.php
index 6bb6584..f7768d7 100644
--- a/resources/theme/backend/adminlte/r/service/widget/movement.blade.php
+++ b/resources/theme/backend/adminlte/r/service/widget/movement.blade.php
@@ -34,8 +34,8 @@
@section('page-scripts')
- @css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery');
- @js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery');
+ @css('//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css','jq-dt-css','jquery')
+ @js('//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js','jq-dt-js','jquery')
@css('//cdn.datatables.net/responsive/2.2.1/css/responsive.dataTables.min.css','dt-responsive-css','jq-dt-css')
@js('//cdn.datatables.net/responsive/2.2.1/js/dataTables.responsive.min.js','dt-responsive-js','jq-dt-js')
@css('//cdn.datatables.net/rowgroup/1.0.2/css/rowGroup.dataTables.min.css','dt-rowgroup-css','jq-dt-css')
diff --git a/resources/theme/backend/adminlte/u/home.blade.php b/resources/theme/backend/adminlte/u/home.blade.php
index 3de3c0d..f3d37e9 100644
--- a/resources/theme/backend/adminlte/u/home.blade.php
+++ b/resources/theme/backend/adminlte/u/home.blade.php
@@ -15,19 +15,53 @@
@endsection
@section('main-content')
-
-
- @include('common.account.widget.summary')
-
+
+ @include('common.account.widget.summary')
+
-
-
- @include('common.service.widget.active')
-
+
+
+
+
-
- @include('common.invoice.widget.due')
- @include('common.payment.widget.history')
+
+
+
+
+
+ @include('common.service.widget.active')
+
+
+
+ @include('common.invoice.widget.due')
+ @include('common.payment.widget.history')
+
+
+
+
+
+
+
+ @include('r.invoice.widget.next',['future'=>FALSE])
+
+
+
+
+
+
+
+ @include('r.invoice.widget.next',['future'=>TRUE])
+
+
+
+
+
diff --git a/resources/theme/backend/adminlte/u/service/widgets/broadband/details.blade.php b/resources/theme/backend/adminlte/u/service/widgets/broadband/details.blade.php
index ed9141c..d077559 100644
--- a/resources/theme/backend/adminlte/u/service/widgets/broadband/details.blade.php
+++ b/resources/theme/backend/adminlte/u/service/widgets/broadband/details.blade.php
@@ -15,7 +15,7 @@
Address |
- {{ $o->service_description }} |
+ {{ $o->service_description }} |
Service Number |
diff --git a/resources/theme/backend/adminlte/u/service/widgets/information.blade.php b/resources/theme/backend/adminlte/u/service/widgets/information.blade.php
index 91940c6..db20cdb 100644
--- a/resources/theme/backend/adminlte/u/service/widgets/information.blade.php
+++ b/resources/theme/backend/adminlte/u/service/widgets/information.blade.php
@@ -18,7 +18,7 @@
Billed |
{{ $o->billing_period }} |
- @if($o->active)
+ @if($o->active AND $o->invoice_to)
Invoiced To |
{{ $o->invoice_to->format('Y-m-d') }} |