$documents * @property-read \App\Models\PaymentType|null $payment_type * @property-read \App\Models\Project|null $project * @property-read \App\Models\PurchaseOrder|null $purchase_order * @property-read \App\Models\User $user * @property-read \App\Models\Vendor|null $vendor * @property-read \App\Models\Currency|null $invoice_currency * @method static \Illuminate\Database\Eloquent\Builder|BaseModel company() * @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude($columns) * @method static \Database\Factories\ExpenseFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|Expense filter(\App\Filters\QueryFilters $filters) * @method static \Illuminate\Database\Eloquent\Builder|Expense newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Expense newQuery() * @method static \Illuminate\Database\Eloquent\Builder|Expense onlyTrashed() * @method static \Illuminate\Database\Eloquent\Builder|Expense query() * @method static \Illuminate\Database\Eloquent\Builder|BaseModel scope() * @method static \Illuminate\Database\Eloquent\Builder|Expense withTrashed() * @method static \Illuminate\Database\Eloquent\Builder|Expense withoutTrashed() * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \App\Models\Invoice|null $invoice * @property-read \App\Models\BankTransaction|null $transaction * @mixin \Eloquent */ class Expense extends BaseModel { use SoftDeletes; use Filterable; use Searchable; /** * Get the index name for the model. * * @return string */ public function searchableAs(): string { return 'expenses_v2'; } protected $fillable = [ 'client_id', 'assigned_user_id', 'vendor_id', 'invoice_id', 'currency_id', 'date', 'invoice_currency_id', 'amount', 'foreign_amount', 'exchange_rate', 'private_notes', 'public_notes', 'bank_id', 'transaction_id', 'category_id', 'tax_rate1', 'tax_name1', 'tax_rate2', 'tax_name2', 'tax_rate3', 'tax_name3', 'payment_date', 'payment_type_id', 'project_id', 'transaction_reference', 'invoice_documents', 'should_be_invoiced', 'custom_value1', 'custom_value2', 'custom_value3', 'custom_value4', 'number', 'tax_amount1', 'tax_amount2', 'tax_amount3', 'uses_inclusive_taxes', 'calculate_tax_by_amount', 'purchase_order_id', ]; protected $casts = [ 'is_deleted' => 'boolean', 'updated_at' => 'timestamp', 'created_at' => 'timestamp', 'deleted_at' => 'timestamp', 'e_invoice' => 'object', ]; public static array $bulk_update_columns = [ 'tax1', 'tax2', 'tax3', 'custom_value1', 'custom_value2', 'custom_value3', 'custom_value4', 'should_be_invoiced', 'uses_inclusive_taxes', 'private_notes', 'public_notes', ]; protected $touches = []; public function toSearchableArray() { $locale = $this->company->locale(); App::setLocale($locale); return [ 'id' => $this->company->db.":".$this->id, 'name' => ctrans('texts.expense') . " " . ($this->number ?? '') . ' | ' . Number::formatMoney($this->amount, $this->company) . ' | ' . $this->translateDate($this->date, $this->company->date_format(), $locale), 'hashed_id' => $this->hashed_id, 'number' => $this->number, 'is_deleted' => $this->is_deleted, 'amount' => (float) $this->amount, 'date' => $this->date ?? null, 'custom_value1' => (string)$this->custom_value1, 'custom_value2' => (string)$this->custom_value2, 'custom_value3' => (string)$this->custom_value3, 'custom_value4' => (string)$this->custom_value4, 'company_key' => $this->company->company_key, ]; } public function getScoutKey() { return $this->company->db.":".$this->id; } public function getEntityType() { return self::class; } public function documents(): \Illuminate\Database\Eloquent\Relations\MorphMany { return $this->morphMany(Document::class, 'documentable'); } public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(User::class)->withTrashed(); } public function assigned_user(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed(); } public function company() { return $this->belongsTo(Company::class); } public function invoice(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Invoice::class); } public function vendor(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Vendor::class); } public function client(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Client::class); } public function purchase_order() { return $this->hasOne(PurchaseOrder::class)->withTrashed(); } public function translate_entity() { return ctrans('texts.expense'); } public function currency(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Currency::class); } public function invoice_currency(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Currency::class); } public function category(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(ExpenseCategory::class)->withTrashed(); } public function payment_type(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(PaymentType::class); } public function project(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Project::class); } public function transaction(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(BankTransaction::class)->withTrashed(); } public function stringStatus() { if ($this->is_deleted) { return ctrans('texts.deleted'); } elseif ($this->payment_date) { return ctrans('texts.paid'); } elseif ($this->invoice_id) { return ctrans('texts.invoiced'); } elseif ($this->should_be_invoiced) { return ctrans('texts.pending'); } elseif ($this->trashed()) { return ctrans('texts.archived'); } return ctrans('texts.logged'); } public function calculatedTaxRate($tax_amount, $tax_rate): float { if ($this->calculate_tax_by_amount) { if ($this->uses_inclusive_taxes) { return round((($tax_amount / $this->amount) * 100 * 1000) / 10) / 100; } return round((($tax_amount / $this->amount) * 1000) / 10) / 1; } return $tax_rate; } public function getNetAmount() { $precision = $this->currency->precision ?? 2; if ($this->calculate_tax_by_amount) { $total_tax_amount = round($this->tax_amount1 + $this->tax_amount2 + $this->tax_amount3, $precision); if ($this->uses_inclusive_taxes) { return round($this->amount, $precision) - $total_tax_amount; } else { return round($this->amount, $precision); } } else { if ($this->uses_inclusive_taxes) { $total_tax_amount = ($this->calcInclusiveLineTax($this->tax_rate1 ?? 0, $this->amount, $precision)) + ($this->calcInclusiveLineTax($this->tax_rate2 ?? 0, $this->amount, $precision)) + ($this->calcInclusiveLineTax($this->tax_rate3 ?? 0, $this->amount, $precision)); return round(($this->amount - round($total_tax_amount, $precision)), $precision); } else { $total_tax_amount = ($this->amount * (($this->tax_rate1 ?? 0) / 100)) + ($this->amount * (($this->tax_rate2 ?? 0) / 100)) + ($this->amount * (($this->tax_rate3 ?? 0) / 100)); return round(($this->amount + round($total_tax_amount, $precision)), $precision); } } } /** * getTaxAmount * * @return float */ public function getTaxAmount(): float { $precision = $this->currency->precision ?? 2; if ($this->calculate_tax_by_amount) { return round($this->tax_amount1 + $this->tax_amount2 + $this->tax_amount3, $precision); } else { if ($this->uses_inclusive_taxes) { return ($this->calcInclusiveLineTax($this->tax_rate1 ?? 0, $this->amount, $precision)) + ($this->calcInclusiveLineTax($this->tax_rate2 ?? 0, $this->amount, $precision)) + ($this->calcInclusiveLineTax($this->tax_rate3 ?? 0, $this->amount, $precision)); } else { return ($this->amount * (($this->tax_rate1 ?? 0) / 100)) + ($this->amount * (($this->tax_rate2 ?? 0) / 100)) + ($this->amount * (($this->tax_rate3 ?? 0) / 100)); } } } /** * calcInclusiveLineTax * * @param mixed $tax_rate * @param mixed $amount * @param mixed $precision * @return float */ private function calcInclusiveLineTax($tax_rate, $amount, $precision): float { return round($amount - ($amount / (1 + ($tax_rate / 100))), $precision); } }