mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-27 11:41:09 -04:00
add overdue
This commit is contained in:
@ -41,11 +41,12 @@ class CheckInvoiceStatus extends Command
|
|||||||
{
|
{
|
||||||
$date = Carbon::now();
|
$date = Carbon::now();
|
||||||
$invoices = Invoice::whereNotIn('status', [Invoice::STATUS_COMPLETED, Invoice::STATUS_DRAFT])
|
$invoices = Invoice::whereNotIn('status', [Invoice::STATUS_COMPLETED, Invoice::STATUS_DRAFT])
|
||||||
|
->where('overdue', false)
|
||||||
->whereDate('due_date', '<', $date)
|
->whereDate('due_date', '<', $date)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
foreach ($invoices as $invoice) {
|
foreach ($invoices as $invoice) {
|
||||||
$invoice->status = Invoice::STATUS_OVERDUE;
|
$invoice->overdue = true;
|
||||||
printf("Invoice %s is OVERDUE \n", $invoice->invoice_number);
|
printf("Invoice %s is OVERDUE \n", $invoice->invoice_number);
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ class InvoiceResource extends JsonResource
|
|||||||
'formatted_invoice_date' => $this->formattedInvoiceDate,
|
'formatted_invoice_date' => $this->formattedInvoiceDate,
|
||||||
'formatted_due_date' => $this->formattedDueDate,
|
'formatted_due_date' => $this->formattedDueDate,
|
||||||
'payment_module_enabled' => $this->payment_module_enabled,
|
'payment_module_enabled' => $this->payment_module_enabled,
|
||||||
|
'overdue' => $this->overdue,
|
||||||
'items' => $this->when($this->items()->exists(), function () {
|
'items' => $this->when($this->items()->exists(), function () {
|
||||||
return InvoiceItemResource::collection($this->items);
|
return InvoiceItemResource::collection($this->items);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -55,6 +55,7 @@ class InvoiceResource extends JsonResource
|
|||||||
'payment_module_enabled' => $this->payment_module_enabled,
|
'payment_module_enabled' => $this->payment_module_enabled,
|
||||||
'sales_tax_type' => $this->sales_tax_type,
|
'sales_tax_type' => $this->sales_tax_type,
|
||||||
'sales_tax_address_type' => $this->sales_tax_address_type,
|
'sales_tax_address_type' => $this->sales_tax_address_type,
|
||||||
|
'overdue' => $this->overdue,
|
||||||
'items' => $this->when($this->items()->exists(), function () {
|
'items' => $this->when($this->items()->exists(), function () {
|
||||||
return InvoiceItemResource::collection($this->items);
|
return InvoiceItemResource::collection($this->items);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -28,10 +28,8 @@ class Invoice extends Model implements HasMedia
|
|||||||
public const STATUS_DRAFT = 'DRAFT';
|
public const STATUS_DRAFT = 'DRAFT';
|
||||||
public const STATUS_SENT = 'SENT';
|
public const STATUS_SENT = 'SENT';
|
||||||
public const STATUS_VIEWED = 'VIEWED';
|
public const STATUS_VIEWED = 'VIEWED';
|
||||||
public const STATUS_OVERDUE = 'OVERDUE';
|
|
||||||
public const STATUS_COMPLETED = 'COMPLETED';
|
public const STATUS_COMPLETED = 'COMPLETED';
|
||||||
|
|
||||||
public const STATUS_DUE = 'DUE';
|
|
||||||
public const STATUS_UNPAID = 'UNPAID';
|
public const STATUS_UNPAID = 'UNPAID';
|
||||||
public const STATUS_PARTIALLY_PAID = 'PARTIALLY_PAID';
|
public const STATUS_PARTIALLY_PAID = 'PARTIALLY_PAID';
|
||||||
public const STATUS_PAID = 'PAID';
|
public const STATUS_PAID = 'PAID';
|
||||||
@ -138,7 +136,6 @@ class Invoice extends Model implements HasMedia
|
|||||||
self::STATUS_DRAFT,
|
self::STATUS_DRAFT,
|
||||||
self::STATUS_SENT,
|
self::STATUS_SENT,
|
||||||
self::STATUS_VIEWED,
|
self::STATUS_VIEWED,
|
||||||
self::STATUS_OVERDUE,
|
|
||||||
self::STATUS_COMPLETED,
|
self::STATUS_COMPLETED,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -155,9 +152,7 @@ class Invoice extends Model implements HasMedia
|
|||||||
|
|
||||||
public function getPreviousStatus()
|
public function getPreviousStatus()
|
||||||
{
|
{
|
||||||
if ($this->due_date < Carbon::now()) {
|
if ($this->viewed) {
|
||||||
return self::STATUS_OVERDUE;
|
|
||||||
} elseif ($this->viewed) {
|
|
||||||
return self::STATUS_VIEWED;
|
return self::STATUS_VIEWED;
|
||||||
} elseif ($this->sent) {
|
} elseif ($this->sent) {
|
||||||
return self::STATUS_SENT;
|
return self::STATUS_SENT;
|
||||||
@ -254,7 +249,7 @@ class Invoice extends Model implements HasMedia
|
|||||||
$filters->get('status') == self::STATUS_PAID
|
$filters->get('status') == self::STATUS_PAID
|
||||||
) {
|
) {
|
||||||
$query->wherePaidStatus($filters->get('status'));
|
$query->wherePaidStatus($filters->get('status'));
|
||||||
} elseif ($filters->get('status') == self::STATUS_DUE) {
|
} elseif ($filters->get('status') == 'DUE') {
|
||||||
$query->whereDueStatus($filters->get('status'));
|
$query->whereDueStatus($filters->get('status'));
|
||||||
} else {
|
} else {
|
||||||
$query->whereStatus($filters->get('status'));
|
$query->whereStatus($filters->get('status'));
|
||||||
@ -692,6 +687,7 @@ class Invoice extends Model implements HasMedia
|
|||||||
if ($amount == 0) {
|
if ($amount == 0) {
|
||||||
$this->status = Invoice::STATUS_COMPLETED;
|
$this->status = Invoice::STATUS_COMPLETED;
|
||||||
$this->paid_status = Invoice::STATUS_PAID;
|
$this->paid_status = Invoice::STATUS_PAID;
|
||||||
|
$this->overdue = false;
|
||||||
} elseif ($amount == $this->total) {
|
} elseif ($amount == $this->total) {
|
||||||
$this->status = $this->getPreviousStatus();
|
$this->status = $this->getPreviousStatus();
|
||||||
$this->paid_status = Invoice::STATUS_UNPAID;
|
$this->paid_status = Invoice::STATUS_UNPAID;
|
||||||
|
|||||||
@ -37,15 +37,6 @@ class InvoiceFactory extends Factory
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function overdue()
|
|
||||||
{
|
|
||||||
return $this->state(function (array $attributes) {
|
|
||||||
return [
|
|
||||||
'status' => Invoice::STATUS_OVERDUE,
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function completed()
|
public function completed()
|
||||||
{
|
{
|
||||||
return $this->state(function (array $attributes) {
|
return $this->state(function (array $attributes) {
|
||||||
@ -55,15 +46,6 @@ class InvoiceFactory extends Factory
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function due()
|
|
||||||
{
|
|
||||||
return $this->state(function (array $attributes) {
|
|
||||||
return [
|
|
||||||
'status' => Invoice::STATUS_DUE,
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function unpaid()
|
public function unpaid()
|
||||||
{
|
{
|
||||||
return $this->state(function (array $attributes) {
|
return $this->state(function (array $attributes) {
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddOverdueToInvoicesTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('invoices', function (Blueprint $table) {
|
||||||
|
$table->boolean('overdue')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('invoices', function (Blueprint $table) {
|
||||||
|
$table->dropForeign(['overdue']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -237,6 +237,14 @@
|
|||||||
:currency="row.data.currency"
|
:currency="row.data.currency"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<BasePaidStatusBadge
|
||||||
|
v-if="row.data.overdue"
|
||||||
|
status="OVERDUE"
|
||||||
|
class="px-1 py-0.5 ml-2"
|
||||||
|
>
|
||||||
|
{{ $t('invoices.overdue') }}
|
||||||
|
</BasePaidStatusBadge>
|
||||||
|
|
||||||
<BasePaidStatusBadge
|
<BasePaidStatusBadge
|
||||||
:status="row.data.paid_status"
|
:status="row.data.paid_status"
|
||||||
class="px-1 py-0.5 ml-2"
|
class="px-1 py-0.5 ml-2"
|
||||||
@ -284,7 +292,7 @@ const showFilters = ref(false)
|
|||||||
const status = ref([
|
const status = ref([
|
||||||
{
|
{
|
||||||
label: 'Status',
|
label: 'Status',
|
||||||
options: ['DRAFT', 'DUE', 'SENT', 'VIEWED', 'OVERDUE', 'COMPLETED'],
|
options: ['DRAFT', 'DUE', 'SENT', 'VIEWED', 'COMPLETED'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Paid Status',
|
label: 'Paid Status',
|
||||||
@ -527,10 +535,6 @@ function setActiveTab(val) {
|
|||||||
activeTab.value = t('invoices.viewed')
|
activeTab.value = t('invoices.viewed')
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'OVERDUE':
|
|
||||||
activeTab.value = t('invoices.overdue')
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
activeTab.value = t('general.all')
|
activeTab.value = t('general.all')
|
||||||
break
|
break
|
||||||
|
|||||||
@ -267,9 +267,7 @@ onSearched = debounce(onSearched, 500)
|
|||||||
>
|
>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
v-if="
|
v-if="
|
||||||
invoiceData.status === 'SENT' ||
|
invoiceData.status === 'SENT' || invoiceData.status === 'VIEWED'
|
||||||
invoiceData.status === 'OVERDUE' ||
|
|
||||||
invoiceData.status === 'VIEWED'
|
|
||||||
"
|
"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -29,6 +29,8 @@ export default {
|
|||||||
return ' bg-yellow-500 bg-opacity-25 text-yellow-900 uppercase font-normal text-center '
|
return ' bg-yellow-500 bg-opacity-25 text-yellow-900 uppercase font-normal text-center '
|
||||||
case 'PARTIALLY_PAID':
|
case 'PARTIALLY_PAID':
|
||||||
return 'bg-blue-400 bg-opacity-25 text-blue-900 uppercase font-normal text-center'
|
return 'bg-blue-400 bg-opacity-25 text-blue-900 uppercase font-normal text-center'
|
||||||
|
case 'OVERDUE':
|
||||||
|
return 'bg-red-300 bg-opacity-50 px-2 py-1 text-sm text-red-900 uppercase font-normal text-center'
|
||||||
default:
|
default:
|
||||||
return 'bg-gray-500 bg-opacity-25 text-gray-900 uppercase font-normal text-center'
|
return 'bg-gray-500 bg-opacity-25 text-gray-900 uppercase font-normal text-center'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -160,7 +160,7 @@ const route = useRoute()
|
|||||||
const table = ref(null)
|
const table = ref(null)
|
||||||
let isFetchingInitialData = ref(true)
|
let isFetchingInitialData = ref(true)
|
||||||
let showFilters = ref(false)
|
let showFilters = ref(false)
|
||||||
const status = ref(['DRAFT', 'DUE', 'SENT', 'VIEWED', 'OVERDUE', 'COMPLETED'])
|
const status = ref(['DRAFT', 'DUE', 'SENT', 'VIEWED', 'COMPLETED'])
|
||||||
const filters = reactive({
|
const filters = reactive({
|
||||||
status: '',
|
status: '',
|
||||||
from_date: '',
|
from_date: '',
|
||||||
|
|||||||
@ -209,11 +209,6 @@ export default {
|
|||||||
bgColor: '#C9E3EC',
|
bgColor: '#C9E3EC',
|
||||||
color: '#2c5282',
|
color: '#2c5282',
|
||||||
}
|
}
|
||||||
case 'OVERDUE':
|
|
||||||
return {
|
|
||||||
bgColor: '#FED7D7',
|
|
||||||
color: '#c53030',
|
|
||||||
}
|
|
||||||
case 'COMPLETED':
|
case 'COMPLETED':
|
||||||
return {
|
return {
|
||||||
bgColor: '#D5EED0',
|
bgColor: '#D5EED0',
|
||||||
@ -256,8 +251,6 @@ export default {
|
|||||||
return global.t('estimates.expired')
|
return global.t('estimates.expired')
|
||||||
case 'PARTIALLY PAID':
|
case 'PARTIALLY PAID':
|
||||||
return global.t('estimates.partially_paid')
|
return global.t('estimates.partially_paid')
|
||||||
case 'OVERDUE':
|
|
||||||
return global.t('invoices.overdue')
|
|
||||||
case 'COMPLETED':
|
case 'COMPLETED':
|
||||||
return global.t('invoices.completed')
|
return global.t('invoices.completed')
|
||||||
case 'DUE':
|
case 'DUE':
|
||||||
|
|||||||
Reference in New Issue
Block a user