Enabled console invoice generation

This commit is contained in:
Deon George
2020-04-01 23:35:06 +11:00
parent fb9ccd927d
commit 23dc668c65
11 changed files with 273 additions and 166 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use App\Traits\NextKey;
@@ -61,7 +62,7 @@ class Account extends Model
{
$query = $this->hasMany(Service::class);
return $active ? $query->where('active','=',TRUE) : $query;
return $active ? $query->active() : $query;
}
public function user()
@@ -71,6 +72,14 @@ class Account extends Model
/** SCOPES */
/**
* Only query active categories
*/
public function scopeActive($query)
{
return $query->where('active',TRUE);
}
/**
* Search for a record
*

View File

@@ -2,12 +2,24 @@
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use App\Traits\NextKey;
use App\Traits\PushNew;
class Invoice extends Model
{
use NextKey,PushNew;
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 $appends = [
'date_due',
@@ -183,4 +195,23 @@ class Invoice extends Model
return $item->product_id == $po->id AND $item->service_id == $so->id;
})->filter()->sortBy('item_type');
}
/**
* Automatically set our due_date 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');
// @todo This 7 days should be sysetm configurable
if (($x=Carbon::now()->addDay(7)) > $this->due_date)
$this->due_date = $x;
}
return parent::save($options);
}
}

View File

@@ -6,14 +6,22 @@ use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use App\Traits\NextKey;
use App\Traits\PushNew;
use Leenooks\Carbon;
class InvoiceItem extends Model
{
protected $dates = ['date_start','date_stop'];
public $dateFormat = 'U';
use NextKey,PushNew;
const RECORD_ID = 'invoice_item';
public $incrementing = FALSE;
protected $table = 'ab_invoice_item';
const CREATED_AT = 'date_orig';
const UPDATED_AT = 'date_last';
protected $dates = ['date_start','date_stop'];
public $dateFormat = 'U';
private $_tax = 0;
@@ -115,6 +123,7 @@ class InvoiceItem extends Model
{
return $this->quantity * $this->price_base;
}
public function getTaxAttribute()
{
if (! $this->_tax)
@@ -149,6 +158,7 @@ class InvoiceItem extends Model
$iit = new InvoiceItemTax;
$iit->tax_id = $to->id;
$iit->amount = round($this->quantity*$this->price_base*$to->rate,3);
$iit->site_id = 1;
$this->taxes->push($iit);
}
}

View File

@@ -4,9 +4,20 @@ 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;
protected $table = 'ab_invoice_item_tax';
const CREATED_AT = 'date_orig';
const UPDATED_AT = NULL;
public $dateFormat = 'U';
public function invoice_item()
{

View File

@@ -468,7 +468,15 @@ class Service extends Model
*/
public function getInvoiceToAttribute()
{
return ($x=$this->invoice_items->filter(function($item) { return $item->item_type === 0;}))->count() ? $x->last()->date_stop : NULL;
$result = ($x=$this->invoice_items->filter(function($item) { return $item->item_type === 0;}))->count()
? $x->last()->date_stop
: NULL;
// For SSL Certificates, the invoice_to date is the expiry date of the Cert
if (is_null($result) AND $this->type->type == 'ssl' AND $this->type->valid_to)
return $this->type->valid_to;
return $result;
}
public function getNameAttribute(): string
@@ -480,13 +488,12 @@ class Service extends Model
* Return the short name for the service.
*
* EG:
* For ADSL, this would be the phone number,
* For Hosting, this would be the domain name, etc
* @deprecated
* + For ADSL, this would be the phone number,
* + For Hosting, this would be the domain name, etc
*/
public function getNameShortAttribute()
{
return $this->model ? $this->type->name : 'NAME UNKNOWN';
return $this->type->service_name;
}
/**
@@ -599,10 +606,10 @@ class Service extends Model
/**
* Return the service description.
* For:
* + Broadband, this is the service address
* + Domains, blank
* + Hosting, blank
* + SSL, blank
* + Broadband, this is the service address
* + Domains, blank
* + Hosting, blank
* + SSL, blank
*
* @return string
*/
@@ -616,10 +623,10 @@ class Service extends Model
/**
* Return the service name.
* For:
* + Broadband, this is the service number
* + Domains, this is the full domain name
* + Hosting, this is the full domain name
* + SSL, this is the DN
* + Broadband, this is the service number
* + Domains, this is the full domain name
* + Hosting, this is the full domain name
* + SSL, this is the DN
*
* @return string
*/
@@ -789,30 +796,33 @@ class Service extends Model
/**
* 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)
* @return Collection
* @throws Exception
*/
public function next_invoice_items(bool $future): Collection
{
if ($this->wasCancelled())
if ($this->wasCancelled() OR $this->suspend_billing OR ! $this->active)
return collect();
// 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->isPending() OR is_null($this->invoice_to))
AND $this->product->price($this->recur_schedule,'price_setup'))
{
$o = 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->price ?: $this->product->price($this->recur_schedule,'price_setup'); // @todo change to a method in this class
$o->item_type = 4; // @todo change to const or something
$o->price_base = $this->product->price($this->recur_schedule,'price_setup'); // @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;
$o->quantity = 1;
$o->site_id = 1; // @todo
$o->addTaxes($this->account->country->taxes);
$this->invoice_items->push($o);
@@ -820,7 +830,8 @@ class Service extends Model
// 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 ($this->active OR $this->isPending())
AND ($future == FALSE AND ($this->invoice_to < Carbon::now()->addDays(30))))
{
do {
$o = new InvoiceItem;
@@ -828,35 +839,39 @@ class Service extends Model
$o->service_id = $this->id;
$o->product_id = $this->product_id;
$o->item_type = 0;
$o->price_base = $this->price ?: $this->product->price($this->recur_schedule); // @todo change to a method in this class
$o->price_base = is_null($this->price)
? (is_null($this->price_override) ? $this->product->price($this->recur_schedule) : $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->quantity = $this->invoice_next_quantity;
$o->site_id = 1; // @todo
$o->addTaxes($this->account->country->taxes);
$this->invoice_items->push($o);
} while ($future == FALSE AND ($this->invoice_to < Carbon::now()->addDays(30)));
}
// Add additional charges
if (! $this->invoice_items->filter(function($item) { return $item->module_id == 30 AND ! $item->exists; })->count())
foreach ($this->charges->filter(function($item) { return ! $item->processed; }) 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->date_start = $oo->date_charge;
$o->date_stop = $oo->date_charge;
$o->module_id = 30; // @todo This shouldnt be hard coded
$o->module_ref = $oo->id;
// Add additional charges
if (! $this->invoice_items->filter(function($item) { return $item->module_id == 30 AND ! $item->exists; })->count())
foreach ($this->charges->filter(function($item) { return ! $item->processed; }) 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->date_start = $oo->date_charge;
$o->date_stop = $oo->date_charge;
$o->module_id = 30; // @todo This shouldnt be hard coded
$o->module_ref = $oo->id;
$o->site_id = 1; // @todo
$o->addTaxes($this->account->country->taxes);
$this->invoice_items->push($o);
}
$o->addTaxes($this->account->country->taxes);
$this->invoice_items->push($o);
}
return $this->invoice_items->filter(function($item) { return ! $item->exists; });
}

View File

@@ -2,6 +2,9 @@
namespace App\Models\Service;
use Illuminate\Support\Arr;
use Carbon\Carbon;
use App\Interfaces\ServiceItem;
use App\Models\Base\ServiceType;
use App\Traits\NextKey;
@@ -13,32 +16,53 @@ class SSL extends ServiceType implements ServiceItem
protected $table = 'ab_service__ssl';
protected $_o = NULL;
protected $crt_parse = NULL;
protected $public_key = NULL;
public function getSSLAttribute()
public static function boot()
{
if (is_null($this->_o)) {
$this->_o = new \App\Classes\SSL;
parent::boot();
if ($this->cert)
$this->_o->crt($this->cert);
if ($this->csr)
$this->_o->csr($this->csr);
if ($this->pk)
$this->_o->key($this->pk);
}
static::retrieved(function($model) {
if ($model->cert);
$model->crt_parse = collect(openssl_x509_parse($model->cert));
return $this->_o;
if ($model->csr) {
$model->public_key = collect(openssl_pkey_get_details(openssl_csr_get_public_key($model->csr)));
}
});
}
public function getValidToAttribute()
{
return $this->cert ? Carbon::createFromTimestamp($this->crt_parse->get('validTo_time_t')) : NULL;
}
public function getServiceDescriptionAttribute(): string
{
return $this->ssl->dn;
if ($this->cert)
return Arr::get($this->crt_parse,'name');
else {
$dn = '';
$dna = openssl_csr_get_subject($this->csr);
foreach ($dna as $k=>$v) {
if ($dn)
$dn .= ',';
$dn .= sprintf('%s=%s',$k,$v);
}
return $dn;
}
}
public function getServiceNameAttribute(): string
{
return $this->ssl->cn;
return $this->cert
? Arr::get($this->crt_parse,'subject.CN')
: Arr::get(openssl_csr_get_subject($this->csr),'CN');
}
public function inContract(): bool