Skip to content
This repository has been archived by the owner on Oct 14, 2024. It is now read-only.

[CI-1250]: Feature: Credit Invoices #15

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public function __invoke(Request $request, Customer $customer)
)
->whereCompany()
->whereCustomer($customer->id)
->whereCredit(false)
->sum('total');
$totalReceipts = Payment::whereBetween(
'payment_date',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public function __invoke(Request $request)
[$start->format('Y-m-d'), $end->format('Y-m-d')]
)
->whereCompany()
->whereCredit(false)
->sum('base_total')
);
array_push(
Expand Down Expand Up @@ -105,6 +106,7 @@ public function __invoke(Request $request)
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
)
->whereCompany()
->whereCredit(false)
->sum('base_total');

$total_receipts = Payment::whereBetween(
Expand Down Expand Up @@ -136,6 +138,7 @@ public function __invoke(Request $request)
->count();
$total_estimate_count = Estimate::whereCompany()->count();
$total_amount_due = Invoice::whereCompany()
->whereCredit(false)
->sum('base_due_amount');

$recent_due_invoices = Invoice::with('customer')
Expand Down
1 change: 1 addition & 0 deletions app/Http/Resources/Customer/InvoiceResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function toArray($request)
'formatted_due_date' => $this->formattedDueDate,
'payment_module_enabled' => $this->payment_module_enabled,
'overdue' => $this->overdue,
'credit' => $this->credit,
'items' => $this->when($this->items()->exists(), function () {
return InvoiceItemResource::collection($this->items);
}),
Expand Down
1 change: 1 addition & 0 deletions app/Http/Resources/InvoiceResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public function toArray($request)
'sales_tax_type' => $this->sales_tax_type,
'sales_tax_address_type' => $this->sales_tax_address_type,
'overdue' => $this->overdue,
'credit' => $this->credit,
'items' => $this->when($this->items()->exists(), function () {
return InvoiceItemResource::collection($this->items);
}),
Expand Down
96 changes: 93 additions & 3 deletions app/Models/Invoice.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Invoice extends Model implements HasMedia
public const STATUS_SENT = 'SENT';
public const STATUS_VIEWED = 'VIEWED';
public const STATUS_COMPLETED = 'COMPLETED';
public const STATUS_CREDIT = 'CREDIT';

public const STATUS_UNPAID = 'UNPAID';
public const STATUS_PARTIALLY_PAID = 'PARTIALLY_PAID';
Expand Down Expand Up @@ -187,6 +188,46 @@ public function getFormattedInvoiceDateAttribute($value)
return Carbon::parse($this->invoice_date)->format($dateFormat);
}

public function getTotalAttribute($value)
{
return $this->credit ? 0 - $value : $value;
}

public function getSubTotalAttribute($value)
{
return $this->credit ? 0 - $value : $value;
}

public function getTaxAttribute($value)
{
return $this->credit ? 0 - $value : $value;
}

public function getBaseTotalAttribute($value)
{
return $this->credit ? 0 - $value : $value;
}

public function getBaseSubTotalAttribute($value)
{
return $this->credit ? 0 - $value : $value;
}

public function getBaseTaxAttribute($value)
{
return $this->credit ? 0 - $value : $value;
}

public function getBaseDueAmountAttribute($value)
{
return $this->credit ? 0 - $value : $value;
}

public function getDueAmountAttribute($value)
{
return $this->credit ? 0 - $value : $value;
}

public function scopeWhereStatus($query, $status)
{
return $query->where('invoices.status', $status);
Expand Down Expand Up @@ -224,7 +265,8 @@ public function scopeWhereSearch($query, $search)
$query->whereHas('customer', function ($query) use ($term) {
$query->where('name', 'LIKE', '%'.$term.'%')
->orWhere('contact_name', 'LIKE', '%'.$term.'%')
->orWhere('company_name', 'LIKE', '%'.$term.'%');
->orWhere('company_name', 'LIKE', '%'.$term.'%')
->orWhere('invoice_number', 'LIKE', '%'.$term.'%');
});
}
}
Expand All @@ -249,6 +291,8 @@ public function scopeApplyFilters($query, array $filters)
$filters->get('status') == self::STATUS_PAID
) {
$query->wherePaidStatus($filters->get('status'));
} elseif ($filters->get('status') == self::STATUS_CREDIT) {
$query->whereCredit(true);
} elseif ($filters->get('status') == 'DUE') {
$query->whereDueStatus($filters->get('status'));
} else {
Expand Down Expand Up @@ -314,6 +358,11 @@ public function scopePaginateData($query, $limit)
return $query->paginate($limit);
}

public function scopeWhereCredit($query, bool $isCredit)
{
$query->where('invoices.credit', $isCredit);
}

public static function createInvoice($request)
{
$data = $request->getInvoicePayload();
Expand All @@ -322,8 +371,11 @@ public static function createInvoice($request)
$data['status'] = Invoice::STATUS_SENT;
}

$invoice = Invoice::create($data);
if ($data['credit']) {
$data = self::getAbsoluteValues($data);
}

$invoice = Invoice::create($data);
$serial = (new SerialNumberFormatter())
->setModel($invoice)
->setCompany($invoice->company_id)
Expand Down Expand Up @@ -382,7 +434,9 @@ public function updateInvoice($request)
}

if ($request->total < $total_paid_amount) {
return 'total_invoice_amount_must_be_more_than_paid_amount';
if (! $request->credit) {
return 'total_invoice_amount_must_be_more_than_paid_amount';
}
}

if ($oldTotal != $request->total) {
Expand All @@ -397,6 +451,10 @@ public function updateInvoice($request)

$this->changeInvoiceStatus($data['due_amount']);

if ($request->credit) {
$data = self::getAbsoluteValues($data);
}

$this->update($data);

$company_currency = CompanySetting::getSetting('currency', $request->header('company'));
Expand Down Expand Up @@ -462,6 +520,12 @@ public function preview($data)

public function send($data)
{
if ($this->status == Invoice::STATUS_DRAFT) {
$this->invoice_date = Carbon::now();
$this->due_date = Carbon::now()->addDays(14);
$this->save();
}

$data = $this->sendInvoiceData($data);

\Mail::to($data['to'])->send(new SendInvoiceMail($data));
Expand Down Expand Up @@ -722,4 +786,30 @@ public static function deleteInvoices($ids)

return true;
}

private static function getAbsoluteValues($data)
{
foreach ($data as $field => &$value) {
if (in_array($field, [
'tax',
'sub_total',
'total',
'due_amount',
'base_total',
'base_sub_total',
'base_tax',
'base_due_amount'
])) {
$value = abs($value);
}
}

$data['sent'] = 1;
$data['status'] = Invoice::STATUS_SENT;
$data['paid_status'] = Invoice::STATUS_PAID;
$data['due_amount'] = 0;
$data['base_due_amount'] = 0;

return $data;
}
}
2 changes: 1 addition & 1 deletion config/dompdf.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
/**
* Whether to enable font subsetting or not.
*/
"enable_font_subsetting" => false,
"enable_font_subsetting" => true,

/**
* The PDF rendering backend to use
Expand Down
32 changes: 32 additions & 0 deletions database/migrations/2022_08_09_195557_add_column_to_invoices.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddColumnToInvoices extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('invoices', function (Blueprint $table) {
$table->boolean('credit')->default(false);
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('invoices', function (Blueprint $table) {
$table->dropForeign(['credit']);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
v-if="userStore.hasAbilities(abilities.EDIT_INVOICE)"
:to="`/admin/invoices/${row.id}/edit`"
>
<BaseDropdownItem v-show="row.allow_edit">
<BaseDropdownItem v-show="(row.credit != 1 && row.allow_edit)">
<BaseIcon
name="PencilIcon"
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
Expand Down Expand Up @@ -57,7 +57,7 @@
</BaseDropdownItem>

<!-- Resend Invoice -->
<BaseDropdownItem v-if="canReSendInvoice(row)" @click="sendInvoice(row)">
<BaseDropdownItem v-if="canReSendInvoice(row)" @click="sendInvoice(row, 'resend')">
<BaseIcon
name="PaperAirplaneIcon"
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
Expand Down Expand Up @@ -238,13 +238,14 @@ async function onMarkAsSent(id) {
})
}

async function sendInvoice(invoice) {
async function sendInvoice(invoice, type = null) {
modalStore.openModal({
title: t('invoices.send_invoice'),
componentName: 'SendInvoiceModal',
id: invoice.id,
data: invoice,
variant: 'sm',
type: type,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
v-else-if="store[storeProp].tax_per_item === 'YES'"
class="flex items-center justify-center m-0 text-lg text-black uppercase "
>
<BaseFormatMoney :amount="tax.amount" :currency="defaultCurrency" />
<BaseFormatMoney :amount="!!store[storeProp].credit ? 0 - tax.amount : tax.amount" :currency="defaultCurrency" />
</label>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
v-model="invoiceMailForm.from"
type="text"
:invalid="v$.from.$error"
:disabled="true"
@input="v$.from.$touch()"
/>
</BaseInputGroup>
Expand Down
12 changes: 8 additions & 4 deletions resources/scripts/admin/stores/invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ export const useInvoiceStore = (useWindow = false) => {
},

getSubTotal() {
return this.newInvoice.items.reduce(function (a, b) {
let isCredit = !!this.newInvoice.credit;
let calc = this.newInvoice.items.reduce(function (a, b) {
return a + b['total']
}, 0)
}, 0);
return isCredit ? (0 - calc) : calc;
},

getTotalSimpleTax() {
Expand All @@ -69,14 +71,15 @@ export const useInvoiceStore = (useWindow = false) => {
},

getTotalTax() {
let isCredit = !!this.newInvoice.credit;
if (
this.newInvoice.tax_per_item === 'NO' ||
this.newInvoice.tax_per_item === null
) {
return this.getTotalSimpleTax + this.getTotalCompoundTax
return isCredit ? 0 - (this.getTotalSimpleTax + this.getTotalCompoundTax) : (this.getTotalSimpleTax + this.getTotalCompoundTax)
}
return _.sumBy(this.newInvoice.items, function (tax) {
return tax.tax
return isCredit ? 0 - tax.tax : tax.tax
})
},

Expand Down Expand Up @@ -119,6 +122,7 @@ export const useInvoiceStore = (useWindow = false) => {
.then((response) => {
this.invoices = response.data.data
this.invoiceTotalCount = response.data.meta.invoice_total_count

resolve(response)
})
.catch((err) => {
Expand Down
1 change: 1 addition & 0 deletions resources/scripts/admin/stub/invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ export default function () {
fields: [],
selectedNote: null,
selectedCurrency: '',
credit: Boolean(0),
}
}
4 changes: 2 additions & 2 deletions resources/scripts/admin/views/invoices/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@

<!-- Invoice status -->
<template #cell-status="{ row }">
<BaseInvoiceStatusBadge :status="row.data.status" class="px-3 py-1">
{{ row.data.status }}
<BaseInvoiceStatusBadge :status="row.data.credit != 0 ? 'CREDIT' : row.data.status" class="px-3 py-1">
{{ Boolean(row.data.credit) ? 'CREDIT' : (t('general.'+(row.data.status).toLowerCase()) === 'general.'+(row.data.status).toLowerCase() ? row.data.status : t('general.'+(row.data.status).toLowerCase())) }}
</BaseInvoiceStatusBadge>
</template>

Expand Down
4 changes: 2 additions & 2 deletions resources/scripts/admin/views/invoices/View.vue
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,10 @@ onSearched = debounce(onSearched, 500)
{{ invoice.invoice_number }}
</div>
<BaseEstimateStatusBadge
:status="invoice.status"
:status="invoice.credit != 0 ? 'CREDIT' : invoice.status"
class="px-1 text-xs"
>
{{ invoice.status }}
{{ invoice.credit != 0 ? 'CREDIT' : invoice.status }}
</BaseEstimateStatusBadge>
</div>

Expand Down
Loading