Merge Invoice and Bill into Document
This commit is contained in:
@@ -59,7 +59,7 @@ class Transaction extends Model
|
||||
|
||||
public function bill()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Purchase\Bill', 'document_id');
|
||||
return $this->belongsTo('App\Models\Document\Document', 'document_id');
|
||||
}
|
||||
|
||||
public function category()
|
||||
@@ -79,7 +79,12 @@ class Transaction extends Model
|
||||
|
||||
public function invoice()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Sale\Invoice', 'document_id');
|
||||
return $this->belongsTo('App\Models\Document\Document', 'document_id');
|
||||
}
|
||||
|
||||
public function document()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Document\Document', 'document_id');
|
||||
}
|
||||
|
||||
public function recurring()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models\Common;
|
||||
|
||||
use App\Models\Document\Document;
|
||||
use App\Traits\Contacts;
|
||||
use App\Traits\Media;
|
||||
use App\Traits\Tenants;
|
||||
@@ -47,6 +48,31 @@ class Company extends Eloquent
|
||||
});
|
||||
}
|
||||
|
||||
public function documents()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\Document');
|
||||
}
|
||||
|
||||
public function document_histories()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentHistory');
|
||||
}
|
||||
|
||||
public function document_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentItem');
|
||||
}
|
||||
|
||||
public function document_item_taxes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentItemTax');
|
||||
}
|
||||
|
||||
public function document_totals()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentTotal');
|
||||
}
|
||||
|
||||
public function accounts()
|
||||
{
|
||||
return $this->hasMany('App\Models\Banking\Account');
|
||||
@@ -54,27 +80,27 @@ class Company extends Eloquent
|
||||
|
||||
public function bills()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\Bill');
|
||||
return $this->documents()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function bill_histories()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillHistory');
|
||||
return $this->document_histories()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function bill_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillItem');
|
||||
return $this->document_items()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function bill_item_taxes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillItemTax');
|
||||
return $this->document_item_taxes()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function bill_totals()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillTotal');
|
||||
return $this->document_totals()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function categories()
|
||||
@@ -119,27 +145,27 @@ class Company extends Eloquent
|
||||
|
||||
public function invoices()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\Invoice');
|
||||
return $this->documents()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function invoice_histories()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceHistory');
|
||||
return $this->document_histories()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function invoice_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceItem');
|
||||
return $this->document_items()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function invoice_item_taxes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceItemTax');
|
||||
return $this->document_item_taxes()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function invoice_totals()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceTotal');
|
||||
return $this->document_totals()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function items()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models\Common;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Document\Document;
|
||||
use Bkwld\Cloner\Cloneable;
|
||||
use App\Traits\Contacts;
|
||||
use App\Traits\Currencies;
|
||||
@@ -40,9 +41,14 @@ class Contact extends Model
|
||||
*/
|
||||
public $sortable = ['name', 'email', 'phone', 'enabled'];
|
||||
|
||||
public function documents()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\Document');
|
||||
}
|
||||
|
||||
public function bills()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\Bill');
|
||||
return $this->documents()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function currency()
|
||||
@@ -62,7 +68,7 @@ class Contact extends Model
|
||||
|
||||
public function invoices()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\Invoice');
|
||||
return $this->documents()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function transactions()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models\Common;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Document\Document;
|
||||
use App\Traits\Currencies;
|
||||
use App\Traits\Media;
|
||||
use Bkwld\Cloner\Cloneable;
|
||||
@@ -61,14 +62,19 @@ class Item extends Model
|
||||
return $this->hasMany('App\Models\Common\ItemTax');
|
||||
}
|
||||
|
||||
public function document_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentItem');
|
||||
}
|
||||
|
||||
public function bill_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillItem');
|
||||
return $this->document_items()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function invoice_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceItem');
|
||||
return $this->document_items()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function scopeName($query, $name)
|
||||
|
||||
353
app/Models/Document/Document.php
Normal file
353
app/Models/Document/Document.php
Normal file
@@ -0,0 +1,353 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Document;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Scopes\Document as Scope;
|
||||
use App\Models\Setting\Tax;
|
||||
use App\Traits\Currencies;
|
||||
use App\Traits\DateTime;
|
||||
use App\Traits\Documents;
|
||||
use App\Traits\Media;
|
||||
use App\Traits\Recurring;
|
||||
use Bkwld\Cloner\Cloneable;
|
||||
use Database\Factories\Document as DocumentFactory;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
|
||||
class Document extends Model
|
||||
{
|
||||
use HasFactory, Documents, Cloneable, Currencies, DateTime, Media, Recurring;
|
||||
|
||||
public const INVOICE_TYPE = 'invoice';
|
||||
public const BILL_TYPE = 'bill';
|
||||
|
||||
protected $table = 'documents';
|
||||
|
||||
protected $appends = ['attachment', 'amount_without_tax', 'discount', 'paid', 'status_label'];
|
||||
|
||||
protected $dates = ['deleted_at', 'issued_at', 'due_at'];
|
||||
|
||||
protected $fillable = [
|
||||
'company_id',
|
||||
'type',
|
||||
'document_number',
|
||||
'order_number',
|
||||
'status',
|
||||
'issued_at',
|
||||
'due_at',
|
||||
'amount',
|
||||
'currency_code',
|
||||
'currency_rate',
|
||||
'contact_id',
|
||||
'contact_name',
|
||||
'contact_email',
|
||||
'contact_tax_number',
|
||||
'contact_phone',
|
||||
'contact_address',
|
||||
'notes',
|
||||
'category_id',
|
||||
'parent_id',
|
||||
'footer',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'amount' => 'double',
|
||||
'currency_rate' => 'double',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $sortable = ['document_number', 'contact_name', 'amount', 'status', 'issued_at', 'due_at'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $cloneable_relations = ['items', 'recurring', 'totals'];
|
||||
|
||||
/**
|
||||
* The "booting" method of the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::addGlobalScope(new Scope);
|
||||
}
|
||||
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Category')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function contact()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Common\Contact')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function currency()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Currency', 'currency_code', 'code');
|
||||
}
|
||||
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentItem', 'document_id');
|
||||
}
|
||||
|
||||
public function item_taxes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentItemTax', 'document_id');
|
||||
}
|
||||
|
||||
public function histories()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentHistory', 'document_id');
|
||||
}
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->transactions();
|
||||
}
|
||||
|
||||
public function recurring()
|
||||
{
|
||||
return $this->morphOne('App\Models\Common\Recurring', 'recurable');
|
||||
}
|
||||
|
||||
public function totals()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentTotal', 'document_id');
|
||||
}
|
||||
|
||||
public function transactions()
|
||||
{
|
||||
return $this->hasMany('App\Models\Banking\Transaction', 'document_id')->where('type', 'income');
|
||||
}
|
||||
|
||||
public function totals_sorted()
|
||||
{
|
||||
return $this->totals()->orderBy('sort_order');
|
||||
}
|
||||
|
||||
public function scopeLatest(Builder $query)
|
||||
{
|
||||
return $query->orderBy('issued_at', 'desc');
|
||||
}
|
||||
|
||||
public function scopeNumber(Builder $query, string $number)
|
||||
{
|
||||
return $query->where('document_number', '=', $number);
|
||||
}
|
||||
|
||||
public function scopeDue($query, $date)
|
||||
{
|
||||
return $query->whereDate('due_at', '=', $date);
|
||||
}
|
||||
|
||||
public function scopeAccrued($query)
|
||||
{
|
||||
return $query->whereNotIn('status', ['draft', 'cancelled']);
|
||||
}
|
||||
|
||||
public function scopePaid($query)
|
||||
{
|
||||
return $query->where('status', '=', 'paid');
|
||||
}
|
||||
|
||||
public function scopeNotPaid($query)
|
||||
{
|
||||
return $query->where('status', '<>', 'paid');
|
||||
}
|
||||
|
||||
public function scopeType(Builder $query, string $type)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', $type);
|
||||
}
|
||||
|
||||
public function scopeInvoice(Builder $query)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', self::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function scopeBill(Builder $query)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', self::BILL_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param Document $src
|
||||
* @param boolean $child
|
||||
*/
|
||||
public function onCloning($src, $child = null)
|
||||
{
|
||||
$this->status = 'draft';
|
||||
$this->document_number = $this->getNextDocumentNumber($src->type);
|
||||
}
|
||||
|
||||
public function getSentAtAttribute(string $value = null)
|
||||
{
|
||||
$sent = $this->histories()->where('status', 'sent')->first();
|
||||
|
||||
return $sent->created_at ?? null;
|
||||
}
|
||||
|
||||
public function getReceivedAtAttribute(string $value = null)
|
||||
{
|
||||
$received = $this->histories()->where('status', 'received')->first();
|
||||
|
||||
return $received->created_at ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current balance.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAttachmentAttribute($value = null)
|
||||
{
|
||||
if (!empty($value) && !$this->hasMedia('attachment')) {
|
||||
return $value;
|
||||
} elseif (!$this->hasMedia('attachment')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getMedia('attachment')->last();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the discount percentage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDiscountAttribute()
|
||||
{
|
||||
$percent = 0;
|
||||
|
||||
$discount = $this->totals->where('code', 'discount')->makeHidden('title')->pluck('amount')->first();
|
||||
|
||||
if ($discount) {
|
||||
$sub_total = $this->totals->where('code', 'sub_total')->makeHidden('title')->pluck('amount')->first();
|
||||
|
||||
$percent = number_format((($discount * 100) / $sub_total), 0);
|
||||
}
|
||||
|
||||
return $percent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the paid amount.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPaidAttribute()
|
||||
{
|
||||
if (empty($this->amount)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$paid = 0;
|
||||
$reconciled = $reconciled_amount = 0;
|
||||
|
||||
$code = $this->currency_code;
|
||||
$rate = config('money.' . $code . '.rate');
|
||||
$precision = config('money.' . $code . '.precision');
|
||||
|
||||
if ($this->transactions->count()) {
|
||||
foreach ($this->transactions as $item) {
|
||||
$amount = $item->amount;
|
||||
|
||||
if ($code != $item->currency_code) {
|
||||
$amount = $this->convertBetween($amount, $item->currency_code, $item->currency_rate, $code, $rate);
|
||||
}
|
||||
|
||||
$paid += $amount;
|
||||
|
||||
if ($item->reconciled) {
|
||||
$reconciled_amount = +$amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bccomp(round($this->amount, $precision), round($reconciled_amount, $precision), $precision) === 0) {
|
||||
$reconciled = 1;
|
||||
}
|
||||
|
||||
$this->setAttribute('reconciled', $reconciled);
|
||||
|
||||
return round($paid, $precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status label.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStatusLabelAttribute()
|
||||
{
|
||||
switch ($this->status) {
|
||||
case 'paid':
|
||||
$label = 'success';
|
||||
break;
|
||||
case 'partial':
|
||||
$label = 'info';
|
||||
break;
|
||||
case 'sent':
|
||||
case 'received':
|
||||
$label = 'danger';
|
||||
break;
|
||||
case 'viewed':
|
||||
$label = 'warning';
|
||||
break;
|
||||
case 'cancelled':
|
||||
$label = 'dark';
|
||||
break;
|
||||
default:
|
||||
$label = 'primary';
|
||||
break;
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount without tax.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAmountWithoutTaxAttribute()
|
||||
{
|
||||
$amount = $this->amount;
|
||||
|
||||
$this->totals->where('code', 'tax')->each(function ($total) use(&$amount) {
|
||||
$tax = Tax::name($total->name)->first();
|
||||
|
||||
if (!empty($tax) && ($tax->type == 'withholding')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$amount -= $total->amount;
|
||||
});
|
||||
|
||||
return $amount;
|
||||
}
|
||||
|
||||
protected static function newFactory(): Factory
|
||||
{
|
||||
return DocumentFactory::new();
|
||||
}
|
||||
}
|
||||
37
app/Models/Document/DocumentHistory.php
Normal file
37
app/Models/Document/DocumentHistory.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Document;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Currencies;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class DocumentHistory extends Model
|
||||
{
|
||||
use Currencies;
|
||||
|
||||
protected $table = 'document_histories';
|
||||
|
||||
protected $fillable = ['company_id', 'type', 'document_id', 'status', 'notify', 'description'];
|
||||
|
||||
public function document()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Document\Document');
|
||||
}
|
||||
|
||||
public function scopeType(Builder $query, string $type)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', $type);
|
||||
}
|
||||
|
||||
public function scopeInvoice(Builder $query)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function scopeBill(Builder $query)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', Document::BILL_TYPE);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Purchase;
|
||||
namespace App\Models\Document;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Currencies;
|
||||
use Bkwld\Cloner\Cloneable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class BillItem extends Model
|
||||
class DocumentItem extends Model
|
||||
{
|
||||
|
||||
use Cloneable, Currencies;
|
||||
|
||||
protected $table = 'bill_items';
|
||||
protected $table = 'document_items';
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['discount'];
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'company_id',
|
||||
'bill_id',
|
||||
'type',
|
||||
'document_id',
|
||||
'item_id',
|
||||
'name',
|
||||
'description',
|
||||
'quantity',
|
||||
'price',
|
||||
'total',
|
||||
@@ -39,24 +33,35 @@ class BillItem extends Model
|
||||
];
|
||||
|
||||
/**
|
||||
* Clonable relationships.
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'price' => 'double',
|
||||
'total' => 'double',
|
||||
'tax' => 'double',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $cloneable_relations = ['taxes'];
|
||||
|
||||
public static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::retrieved(function($model) {
|
||||
$model->setTaxIds();
|
||||
});
|
||||
static::retrieved(
|
||||
function ($model) {
|
||||
$model->setTaxIds();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function bill()
|
||||
public function document()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Purchase\Bill');
|
||||
return $this->belongsTo('App\Models\Document\Document');
|
||||
}
|
||||
|
||||
public function item()
|
||||
@@ -66,48 +71,26 @@ class BillItem extends Model
|
||||
|
||||
public function taxes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillItemTax', 'bill_item_id', 'id');
|
||||
return $this->hasMany('App\Models\Document\DocumentItemTax', 'document_item_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert price to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setPriceAttribute($value)
|
||||
public function scopeType(Builder $query, string $type)
|
||||
{
|
||||
$this->attributes['price'] = (double) $value;
|
||||
return $query->where($this->table . '.type', '=', $type);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert total to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setTotalAttribute($value)
|
||||
public function scopeInvoice(Builder $query)
|
||||
{
|
||||
$this->attributes['total'] = (double) $value;
|
||||
return $query->where($this->table . '.type', '=', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert tax to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setTaxAttribute($value)
|
||||
public function scopeBill(Builder $query)
|
||||
{
|
||||
$this->attributes['tax'] = (double) $value;
|
||||
return $query->where($this->table . '.type', '=', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted discount.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDiscountAttribute()
|
||||
public function getDiscountAttribute(): string
|
||||
{
|
||||
if (setting('localisation.percent_position', 'after') === 'after') {
|
||||
$text = ($this->discount_type === 'normal') ? $this->discount_rate . '%' : $this->discount_rate;
|
||||
@@ -118,12 +101,7 @@ class BillItem extends Model
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted discount.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDiscountRateAttribute($value = 0)
|
||||
public function getDiscountRateAttribute(int $value = 0)
|
||||
{
|
||||
$discount_rate = 0;
|
||||
|
||||
@@ -132,10 +110,8 @@ class BillItem extends Model
|
||||
case 'total':
|
||||
$discount_rate = 0;
|
||||
break;
|
||||
case 'item':
|
||||
$discount_rate = $value;
|
||||
break;
|
||||
case 'both':
|
||||
case 'item':
|
||||
$discount_rate = $value;
|
||||
break;
|
||||
}
|
||||
@@ -145,22 +121,20 @@ class BillItem extends Model
|
||||
|
||||
/**
|
||||
* Convert tax to Array.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setTaxIds()
|
||||
{
|
||||
$tax_ids = [];
|
||||
|
||||
foreach ($this->taxes as $tax) {
|
||||
$tax_ids[] = (string) $tax->tax_id;
|
||||
$tax_ids[] = (string)$tax->tax_id;
|
||||
}
|
||||
|
||||
$this->setAttribute('tax_id', $tax_ids);
|
||||
$this->setAttribute('tax_ids', $tax_ids);
|
||||
}
|
||||
|
||||
public function onCloning($src, $child = null)
|
||||
{
|
||||
unset($this->tax_id);
|
||||
unset($this->tax_ids);
|
||||
}
|
||||
}
|
||||
58
app/Models/Document/DocumentItemTax.php
Normal file
58
app/Models/Document/DocumentItemTax.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Document;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Currencies;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Znck\Eloquent\Relations\BelongsToThrough as BelongsToThroughRelation;
|
||||
use Znck\Eloquent\Traits\BelongsToThrough;
|
||||
|
||||
class DocumentItemTax extends Model
|
||||
{
|
||||
use Currencies, BelongsToThrough;
|
||||
|
||||
protected $table = 'document_item_taxes';
|
||||
|
||||
protected $fillable = ['company_id', 'type', 'document_id', 'document_item_id', 'tax_id', 'name', 'amount'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'amount' => 'double',
|
||||
];
|
||||
|
||||
public function document()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Document\Document');
|
||||
}
|
||||
|
||||
public function item()
|
||||
{
|
||||
return $this->belongsToThrough('App\Models\Common\Item', 'App\Models\Document\DocumentItem', 'document_item_id')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function tax()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Tax')->withDefault(['name' => trans('general.na'), 'rate' => 0]);
|
||||
}
|
||||
|
||||
public function scopeType(Builder $query, string $type)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', $type);
|
||||
}
|
||||
|
||||
public function scopeInvoice(Builder $query)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function scopeBill(Builder $query)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', Document::BILL_TYPE);
|
||||
}
|
||||
}
|
||||
93
app/Models/Document/DocumentTotal.php
Normal file
93
app/Models/Document/DocumentTotal.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Document;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Setting\Tax;
|
||||
use App\Traits\DateTime;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class DocumentTotal extends Model
|
||||
{
|
||||
use DateTime;
|
||||
|
||||
protected $table = 'document_totals';
|
||||
|
||||
protected $appends = ['title'];
|
||||
|
||||
protected $fillable = ['company_id', 'type', 'document_id', 'code', 'name', 'amount', 'sort_order'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'amount' => 'double',
|
||||
];
|
||||
|
||||
public function document()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Document\Document');
|
||||
}
|
||||
|
||||
public function getTitleAttribute()
|
||||
{
|
||||
$title = $this->name;
|
||||
|
||||
$percent = 0;
|
||||
|
||||
$tax = null;
|
||||
|
||||
switch ($this->code) {
|
||||
case 'discount':
|
||||
$title = trans($title);
|
||||
$percent = $this->document->discount;
|
||||
|
||||
break;
|
||||
case 'tax':
|
||||
$tax = Tax::where('name', $title)->first();
|
||||
|
||||
if (!empty($tax->rate)) {
|
||||
$percent = $tax->rate;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($percent)) {
|
||||
$title .= ' (';
|
||||
|
||||
if (setting('localisation.percent_position', 'after') === 'after') {
|
||||
$title .= ($this->code === 'discount') ? $percent . '%' : (($tax->type === 'fixed') ? $percent : $percent . '%');
|
||||
} else {
|
||||
$title .= ($this->code === 'discount') ? '%' . $percent : (($tax->type === 'fixed') ? $percent : '%' . $percent);
|
||||
}
|
||||
|
||||
$title .= ')';
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
public function scopeType(Builder $query, string $type)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', $type);
|
||||
}
|
||||
|
||||
public function scopeInvoice(Builder $query)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function scopeBill(Builder $query)
|
||||
{
|
||||
return $query->where($this->table . '.type', '=', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function scopeCode($query, $code)
|
||||
{
|
||||
return $query->where('code', '=', $code);
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Purchase;
|
||||
|
||||
use App\Abstracts\DocumentModel;
|
||||
use App\Traits\Purchases;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class Bill extends DocumentModel
|
||||
{
|
||||
use HasFactory, Purchases;
|
||||
|
||||
protected $table = 'bills';
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['attachment', 'amount_without_tax', 'discount', 'paid', 'status_label'];
|
||||
|
||||
protected $dates = ['deleted_at', 'billed_at', 'due_at'];
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'bill_number', 'order_number', 'status', 'billed_at', 'due_at', 'amount', 'currency_code', 'currency_rate', 'contact_id', 'contact_name', 'contact_email', 'contact_tax_number', 'contact_phone', 'contact_address', 'notes', 'category_id', 'parent_id'];
|
||||
|
||||
/**
|
||||
* Sortable columns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $sortable = ['bill_number', 'contact_name', 'amount', 'status', 'billed_at', 'due_at'];
|
||||
|
||||
/**
|
||||
* Clonable relationships.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cloneable_relations = ['items', 'recurring', 'totals'];
|
||||
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Category')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function contact()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Common\Contact')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function currency()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Currency', 'currency_code', 'code');
|
||||
}
|
||||
|
||||
public function histories()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillHistory');
|
||||
}
|
||||
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillItem');
|
||||
}
|
||||
|
||||
public function item_taxes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillItemTax');
|
||||
}
|
||||
|
||||
public function recurring()
|
||||
{
|
||||
return $this->morphOne('App\Models\Common\Recurring', 'recurable');
|
||||
}
|
||||
|
||||
public function totals()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillTotal');
|
||||
}
|
||||
|
||||
public function transactions()
|
||||
{
|
||||
return $this->hasMany('App\Models\Banking\Transaction', 'document_id')->where('type', 'expense');
|
||||
}
|
||||
|
||||
public function scopeLatest($query)
|
||||
{
|
||||
return $query->orderBy('billed_at', 'desc');
|
||||
}
|
||||
|
||||
public function scopeNumber($query, $number)
|
||||
{
|
||||
return $query->where('bill_number', '=', $number);
|
||||
}
|
||||
|
||||
public function onCloning($src, $child = null)
|
||||
{
|
||||
$this->status = 'draft';
|
||||
$this->bill_number = $this->getNextBillNumber();
|
||||
}
|
||||
|
||||
public function getReceivedAtAttribute($value)
|
||||
{
|
||||
$received = $this->histories()->where('status', 'received')->first();
|
||||
|
||||
return ($received) ? $received->created_at : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
protected static function newFactory()
|
||||
{
|
||||
return \Database\Factories\Bill::new();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Purchase;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Currencies;
|
||||
|
||||
class BillHistory extends Model
|
||||
{
|
||||
|
||||
use Currencies;
|
||||
|
||||
protected $table = 'bill_histories';
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'bill_id', 'status', 'notify', 'description'];
|
||||
|
||||
public function bill()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Purchase\Bill');
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Purchase;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Currencies;
|
||||
use Znck\Eloquent\Traits\BelongsToThrough;
|
||||
|
||||
class BillItemTax extends Model
|
||||
{
|
||||
use Currencies, BelongsToThrough;
|
||||
|
||||
protected $table = 'bill_item_taxes';
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'bill_id', 'bill_item_id', 'tax_id', 'name', 'amount'];
|
||||
|
||||
public function bill()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Purchase\Bill');
|
||||
}
|
||||
|
||||
public function item()
|
||||
{
|
||||
return $this->belongsToThrough('App\Models\Common\Item', 'App\Models\Purchase\BillItem', 'bill_item_id')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function tax()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Tax')->withDefault(['name' => trans('general.na'), 'rate' => 0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert amount to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setAmountAttribute($value)
|
||||
{
|
||||
$this->attributes['amount'] = (double) $value;
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Purchase;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Setting\Tax;
|
||||
use App\Traits\DateTime;
|
||||
|
||||
class BillTotal extends Model
|
||||
{
|
||||
use DateTime;
|
||||
|
||||
protected $table = 'bill_totals';
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['title'];
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'bill_id', 'code', 'name', 'amount', 'sort_order'];
|
||||
|
||||
public function bill()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Purchase\Bill');
|
||||
}
|
||||
|
||||
public function scopeCode($query, $code)
|
||||
{
|
||||
return $query->where('code', '=', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert amount to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setAmountAttribute($value)
|
||||
{
|
||||
$this->attributes['amount'] = (double) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleAttribute()
|
||||
{
|
||||
$title = $this->name;
|
||||
|
||||
$percent = 0;
|
||||
|
||||
$tax = null;
|
||||
|
||||
switch ($this->code) {
|
||||
case 'discount':
|
||||
$title = trans($title);
|
||||
$percent = $this->bill->discount;
|
||||
|
||||
break;
|
||||
case 'tax':
|
||||
$tax = Tax::where('name', $title)->first();
|
||||
|
||||
if (!empty($tax->rate)) {
|
||||
$percent = $tax->rate;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($percent)) {
|
||||
$title .= ' (';
|
||||
|
||||
if (setting('localisation.percent_position', 'after') == 'after') {
|
||||
$title .= ($this->code == 'discount') ? $percent. '%' : (($tax->type == 'fixed') ? $percent : $percent . '%');
|
||||
} else {
|
||||
$title .= ($this->code == 'discount') ? '%' .$percent : (($tax->type == 'fixed') ? $percent : '%' . $percent);
|
||||
}
|
||||
|
||||
$title .= ')';
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Sale;
|
||||
|
||||
use App\Abstracts\DocumentModel;
|
||||
use App\Traits\Sales;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class Invoice extends DocumentModel
|
||||
{
|
||||
use HasFactory, Sales;
|
||||
|
||||
protected $table = 'invoices';
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['attachment', 'amount_without_tax', 'discount', 'paid', 'status_label'];
|
||||
|
||||
protected $dates = ['deleted_at', 'invoiced_at', 'due_at'];
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'invoice_number', 'order_number', 'status', 'invoiced_at', 'due_at', 'amount', 'currency_code', 'currency_rate', 'contact_id', 'contact_name', 'contact_email', 'contact_tax_number', 'contact_phone', 'contact_address', 'notes', 'category_id', 'parent_id', 'footer'];
|
||||
|
||||
/**
|
||||
* Sortable columns.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $sortable = ['invoice_number', 'contact_name', 'amount', 'status' , 'invoiced_at', 'due_at'];
|
||||
|
||||
protected $reconciled_amount = [];
|
||||
|
||||
/**
|
||||
* Clonable relationships.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cloneable_relations = ['items', 'recurring', 'totals'];
|
||||
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Category')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function contact()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Common\Contact')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function currency()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Currency', 'currency_code', 'code');
|
||||
}
|
||||
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceItem');
|
||||
}
|
||||
|
||||
public function item_taxes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceItemTax');
|
||||
}
|
||||
|
||||
public function histories()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceHistory');
|
||||
}
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->transactions();
|
||||
}
|
||||
|
||||
public function recurring()
|
||||
{
|
||||
return $this->morphOne('App\Models\Common\Recurring', 'recurable');
|
||||
}
|
||||
|
||||
public function totals()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceTotal');
|
||||
}
|
||||
|
||||
public function transactions()
|
||||
{
|
||||
return $this->hasMany('App\Models\Banking\Transaction', 'document_id')->where('type', 'income');
|
||||
}
|
||||
|
||||
public function scopeLatest($query)
|
||||
{
|
||||
return $query->orderBy('invoiced_at', 'desc');
|
||||
}
|
||||
|
||||
public function scopeNumber($query, $number)
|
||||
{
|
||||
return $query->where('invoice_number', '=', $number);
|
||||
}
|
||||
|
||||
public function onCloning($src, $child = null)
|
||||
{
|
||||
$this->status = 'draft';
|
||||
$this->invoice_number = $this->getNextInvoiceNumber();
|
||||
}
|
||||
|
||||
public function getSentAtAttribute($value)
|
||||
{
|
||||
$sent = $this->histories()->where('status', 'sent')->first();
|
||||
|
||||
return ($sent) ? $sent->created_at : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
protected static function newFactory()
|
||||
{
|
||||
return \Database\Factories\Invoice::new();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Sale;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Currencies;
|
||||
|
||||
class InvoiceHistory extends Model
|
||||
{
|
||||
use Currencies;
|
||||
|
||||
protected $table = 'invoice_histories';
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'invoice_id', 'status', 'notify', 'description'];
|
||||
|
||||
public function invoice()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Sale\Invoice');
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Sale;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Currencies;
|
||||
use Bkwld\Cloner\Cloneable;
|
||||
|
||||
class InvoiceItem extends Model
|
||||
{
|
||||
use Cloneable, Currencies;
|
||||
|
||||
protected $table = 'invoice_items';
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['discount'];
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'company_id',
|
||||
'invoice_id',
|
||||
'item_id',
|
||||
'name',
|
||||
'quantity',
|
||||
'price',
|
||||
'total',
|
||||
'tax',
|
||||
'discount_rate',
|
||||
'discount_type',
|
||||
];
|
||||
|
||||
/**
|
||||
* Clonable relationships.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cloneable_relations = ['taxes'];
|
||||
|
||||
public static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::retrieved(function($model) {
|
||||
$model->setTaxIds();
|
||||
});
|
||||
}
|
||||
|
||||
public function invoice()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Sale\Invoice');
|
||||
}
|
||||
|
||||
public function item()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Common\Item')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function taxes()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceItemTax', 'invoice_item_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert price to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setPriceAttribute($value)
|
||||
{
|
||||
$this->attributes['price'] = (double) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert total to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setTotalAttribute($value)
|
||||
{
|
||||
$this->attributes['total'] = (double) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert tax to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setTaxAttribute($value)
|
||||
{
|
||||
$this->attributes['tax'] = (double) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted discount.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDiscountAttribute()
|
||||
{
|
||||
if (setting('localisation.percent_position', 'after') === 'after') {
|
||||
$text = ($this->discount_type === 'normal') ? $this->discount_rate . '%' : $this->discount_rate;
|
||||
} else {
|
||||
$text = ($this->discount_type === 'normal') ? '%' . $this->discount_rate : $this->discount_rate;
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted discount.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDiscountRateAttribute($value = 0)
|
||||
{
|
||||
$discount_rate = 0;
|
||||
|
||||
switch (setting('localisation.discount_location', 'total')) {
|
||||
case 'no':
|
||||
case 'total':
|
||||
$discount_rate = 0;
|
||||
break;
|
||||
case 'item':
|
||||
$discount_rate = $value;
|
||||
break;
|
||||
case 'both':
|
||||
$discount_rate = $value;
|
||||
break;
|
||||
}
|
||||
|
||||
return $discount_rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert tax to Array.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setTaxIds()
|
||||
{
|
||||
$tax_ids = [];
|
||||
|
||||
foreach ($this->taxes as $tax) {
|
||||
$tax_ids[] = (string) $tax->tax_id;
|
||||
}
|
||||
|
||||
$this->setAttribute('tax_id', $tax_ids);
|
||||
}
|
||||
|
||||
public function onCloning($src, $child = null)
|
||||
{
|
||||
unset($this->tax_id);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Sale;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Currencies;
|
||||
use Znck\Eloquent\Traits\BelongsToThrough;
|
||||
|
||||
class InvoiceItemTax extends Model
|
||||
{
|
||||
use Currencies, BelongsToThrough;
|
||||
|
||||
protected $table = 'invoice_item_taxes';
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'invoice_id', 'invoice_item_id', 'tax_id', 'name', 'amount'];
|
||||
|
||||
public function invoice()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Sale\Invoice');
|
||||
}
|
||||
|
||||
public function item()
|
||||
{
|
||||
return $this->belongsToThrough('App\Models\Common\Item', 'App\Models\Sale\InvoiceItem', 'invoice_item_id')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function tax()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Setting\Tax')->withDefault(['name' => trans('general.na'), 'rate' => 0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert amount to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setAmountAttribute($value)
|
||||
{
|
||||
$this->attributes['amount'] = (double) $value;
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Sale;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Setting\Tax;
|
||||
use App\Traits\DateTime;
|
||||
|
||||
class InvoiceTotal extends Model
|
||||
{
|
||||
use DateTime;
|
||||
|
||||
protected $table = 'invoice_totals';
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['title'];
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'invoice_id', 'code', 'name', 'amount', 'sort_order'];
|
||||
|
||||
public function invoice()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Sale\Invoice');
|
||||
}
|
||||
|
||||
public function scopeCode($query, $code)
|
||||
{
|
||||
return $query->where('code', '=', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert amount to double.
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setAmountAttribute($value)
|
||||
{
|
||||
$this->attributes['amount'] = (double)$value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleAttribute()
|
||||
{
|
||||
$title = $this->name;
|
||||
|
||||
$percent = 0;
|
||||
|
||||
$tax = null;
|
||||
|
||||
switch ($this->code) {
|
||||
case 'discount':
|
||||
$title = trans($title);
|
||||
$percent = $this->invoice->discount;
|
||||
|
||||
break;
|
||||
case 'tax':
|
||||
$tax = Tax::where('name', $title)->first();
|
||||
|
||||
if (!empty($tax->rate)) {
|
||||
$percent = $tax->rate;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($percent)) {
|
||||
$title .= ' (';
|
||||
|
||||
if (setting('localisation.percent_position', 'after') == 'after') {
|
||||
$title .= ($this->code == 'discount') ? $percent. '%' : (($tax->type == 'fixed') ? $percent : $percent . '%');
|
||||
} else {
|
||||
$title .= ($this->code == 'discount') ? '%' .$percent : (($tax->type == 'fixed') ? $percent : '%' . $percent);
|
||||
}
|
||||
|
||||
$title .= ')';
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models\Setting;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Document\Document;
|
||||
use App\Traits\Transactions;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
@@ -35,9 +36,14 @@ class Category extends Model
|
||||
*/
|
||||
public $sortable = ['name', 'type', 'enabled'];
|
||||
|
||||
public function documents()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\Document');
|
||||
}
|
||||
|
||||
public function bills()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\Bill');
|
||||
return $this->documents()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function expense_transactions()
|
||||
@@ -52,7 +58,7 @@ class Category extends Model
|
||||
|
||||
public function invoices()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\Invoice');
|
||||
return $this->documents()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function items()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models\Setting;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Document\Document;
|
||||
use App\Traits\Contacts;
|
||||
use App\Traits\Transactions;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
@@ -42,9 +43,14 @@ class Currency extends Model
|
||||
return $this->hasMany('App\Models\Banking\Account', 'currency_code', 'code');
|
||||
}
|
||||
|
||||
public function documents()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\Document', 'currency_code', 'code');
|
||||
}
|
||||
|
||||
public function bills()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\Bill', 'currency_code', 'code');
|
||||
return $this->documents()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function contacts()
|
||||
@@ -69,7 +75,7 @@ class Currency extends Model
|
||||
|
||||
public function invoices()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\Invoice', 'currency_code', 'code');
|
||||
return $this->documents()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function transactions()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models\Setting;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Document\Document;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class Tax extends Model
|
||||
@@ -47,14 +48,19 @@ class Tax extends Model
|
||||
return $this->hasMany('App\Models\Common\Item');
|
||||
}
|
||||
|
||||
public function document_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\DocumentItemTax');
|
||||
}
|
||||
|
||||
public function bill_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Purchase\BillItemTax');
|
||||
return $this->document_items()->where('type', Document::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function invoice_items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sale\InvoiceItemTax');
|
||||
return $this->document_items()->where('type', Document::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function scopeName($query, $name)
|
||||
|
||||
Reference in New Issue
Block a user