More Tax Rates
This commit is contained in:
parent
9efde6fa34
commit
efe78bb49f
25
app/Enums/IconEnum.php
Normal file
25
app/Enums/IconEnum.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum IconEnum: string
|
||||
{
|
||||
case DEFAULT = 'heroicon-o-rectangle-stack';
|
||||
case INVOICE = 'lucide-receipt-text';
|
||||
case ORDER = 'lucide-shopping-cart';
|
||||
case QUOTE = 'lucide-quote';
|
||||
case CUSTOMER = 'lucide-building';
|
||||
case PACKING_SLIP = 'lucide-package';
|
||||
case SHIPPING_ENTRY = 'lucide-truck';
|
||||
case USER = 'lucide-users';
|
||||
case TAX_RATE = 'lucide-circle-dollar-sign';
|
||||
|
||||
// case PRODUCT_SERVICE = 'heroicon-o-rectangle-stack';
|
||||
// case CUSTOMER_SALES = 'heroicon-o-rectangle-stack';
|
||||
// case INVOICE_REPORT = 'heroicon-o-rectangle-stack';
|
||||
|
||||
case TAB_ALL = 'lucide-layout-grid';
|
||||
case TAB_OVERDUE = 'lucide-calendar-clock';
|
||||
case TAB_UNPRINTED = ' lucide-printer';
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum IconName: string
|
||||
{
|
||||
case INVOICE = 'lucide-receipt-text';
|
||||
case ORDER = 'lucide-shopping-cart';
|
||||
case QUOTE = 'lucide-quote';
|
||||
case CUSTOMER = 'lucide-building';
|
||||
case PACKING_SLIP = 'lucide-package';
|
||||
case SHIPPING_ENTRY = 'lucide-truck';
|
||||
case USER = 'lucide-users';
|
||||
case TAX_RATE = 'lucide-circle-dollar-sign';
|
||||
case PRODUCT_SERVICE = 'heroicon-o-rectangle-stack';
|
||||
case CUSTOMER_SALES = 'heroicon-o-rectangle-stack';
|
||||
case INVOICE_REPORT = 'heroicon-o-rectangle-stack';
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Invoice;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
@ -20,7 +20,7 @@ class CustomerReportResource extends Resource
|
||||
|
||||
protected static ?string $navigationGroup = 'Reports';
|
||||
|
||||
protected static ?string $navigationIcon = IconName::CUSTOMER_SALES->value;
|
||||
protected static ?string $navigationIcon = IconEnum::DEFAULT->value;
|
||||
|
||||
protected static ?string $navigationLabel = 'Customer Sales';
|
||||
|
||||
@ -46,14 +46,14 @@ public static function table(Table $table): Table
|
||||
|
||||
Tables\Columns\TextColumn::make('subtotal')
|
||||
->money()
|
||||
->summarize(Summarizer::make()->using(function ($query, Table $table) {
|
||||
$createdAt = $table->getfilter('created_at')->getstate()['created_at'] ?? '1900-01-01';
|
||||
$createdUntil = $table->getfilter('created_until')->getstate()['created_until'] ?? '2100-01-01';
|
||||
|
||||
$invoiceSum = invoice::wherebetween('date', [$createdAt, $createdUntil])->sum('subtotal');
|
||||
|
||||
return '$'.number_format(round($invoiceSum, 2), 2, '.', ',');
|
||||
}))
|
||||
// ->summarize(Summarizer::make()->using(function ($query, Table $table) {
|
||||
// $createdAt = $table->getfilter('created_at')->getstate()['created_at'] ?? '1900-01-01';
|
||||
// $createdUntil = $table->getfilter('created_until')->getstate()['created_until'] ?? '2100-01-01';
|
||||
//
|
||||
// $invoiceSum = invoice::wherebetween('date', [$createdAt, $createdUntil])->sum('subtotal');
|
||||
//
|
||||
// return '$'.number_format(round($invoiceSum, 2), 2, '.', ',');
|
||||
// }))
|
||||
->alignRight()
|
||||
->getStateUsing(function (Table $table, Model $record) {
|
||||
return $record->getSubtotalAttribute(
|
||||
@ -78,23 +78,22 @@ public static function table(Table $table): Table
|
||||
->money()
|
||||
->alignRight()
|
||||
->getStateUsing(function (Table $table, Customer $record) {
|
||||
// return $record->invoices()->;
|
||||
// return $record->getPstAttribute(
|
||||
// $table->getFilter('created_at')->getState()['created_at'],
|
||||
// $table->getFilter('created_until')->getState()['created_until']
|
||||
// );
|
||||
return $record->getPstAttribute(
|
||||
$table->getFilter('created_at')->getState()['created_at'],
|
||||
$table->getFilter('created_until')->getState()['created_until']
|
||||
);
|
||||
}),
|
||||
|
||||
Tables\Columns\TextColumn::make('total')
|
||||
->money()
|
||||
->summarize(summarizer::make()->using(function ($query, table $table) {
|
||||
$createdAt = $table->getfilter('created_at')->getstate()['created_at'] ?? '1900-01-01';
|
||||
$createdUntil = $table->getfilter('created_until')->getstate()['created_until'] ?? '2100-01-01';
|
||||
|
||||
$invoiceSum = invoice::wherebetween('date', [$createdAt, $createdUntil])->sum('total');
|
||||
|
||||
return '$'.number_format(round($invoiceSum, 2), 2, '.', ',');
|
||||
}))
|
||||
// ->summarize(summarizer::make()->using(function ($query, table $table) {
|
||||
// $createdAt = $table->getfilter('created_at')->getstate()['created_at'] ?? '1900-01-01';
|
||||
// $createdUntil = $table->getfilter('created_until')->getstate()['created_until'] ?? '2100-01-01';
|
||||
//
|
||||
// $invoiceSum = invoice::wherebetween('date', [$createdAt, $createdUntil])->sum('total');
|
||||
//
|
||||
// return '$'.number_format(round($invoiceSum, 2), 2, '.', ',');
|
||||
// }))
|
||||
->weight(FontWeight::Bold)
|
||||
->alignRight()
|
||||
->getStateUsing(function (Table $table, Model $record) {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Filament\Admin\Resources\CustomerResource\RelationManagers\ContactsRelationManager;
|
||||
use App\Filament\Admin\Resources\CustomerResource\RelationManagers\ShippingEntriesRelationManager;
|
||||
use App\Models\Customer;
|
||||
@ -18,7 +18,7 @@ class CustomerResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Customer::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::CUSTOMER->value;
|
||||
protected static ?string $navigationIcon = IconEnum::CUSTOMER->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Management';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Filament\Admin\Resources\InvoiceReportResource\RelationManagers\InvoicesRelationManager;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Section;
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
class InvoiceReportResource extends Resource
|
||||
{
|
||||
protected static ?string $navigationIcon = IconName::INVOICE_REPORT->value;
|
||||
protected static ?string $navigationIcon = IconEnum::DEFAULT->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Reports';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Filament\Admin\Resources\InvoiceResource\RelationManagers\OrdersRelationManager;
|
||||
use App\Filament\Admin\Resources\InvoiceResource\RelationManagers\ProductServicesRelationManager;
|
||||
@ -29,7 +29,7 @@ class InvoiceResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Invoice::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::INVOICE->value;
|
||||
protected static ?string $navigationIcon = IconEnum::INVOICE->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Production';
|
||||
|
||||
|
@ -3,19 +3,9 @@
|
||||
namespace App\Filament\Admin\Resources\InvoiceResource\Pages;
|
||||
|
||||
use App\Filament\Admin\Resources\InvoiceResource;
|
||||
use App\Models\Invoice;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class CreateInvoice extends CreateRecord
|
||||
{
|
||||
protected static string $resource = InvoiceResource::class;
|
||||
|
||||
protected function handleRecordCreation(array $data): Model
|
||||
{
|
||||
$invoice = Invoice::create($data);
|
||||
$invoice->calculateTotals();
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,45 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources\InvoiceResource\Pages;
|
||||
|
||||
use App\Enums\IconEnum;
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Filament\Admin\Resources\InvoiceResource;
|
||||
use App\Models\Invoice;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Components\Tab;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListInvoices extends ListRecords
|
||||
{
|
||||
protected static string $resource = InvoiceResource::class;
|
||||
|
||||
public function getTabs(): array
|
||||
{
|
||||
return [
|
||||
'all' => Tab::make('All')
|
||||
->icon(IconEnum::TAB_ALL->value),
|
||||
|
||||
'unpaid' => Tab::make('Unpaid')
|
||||
->query(fn ($query) => $query->where('status', InvoiceStatus::UNPAID))
|
||||
->badge(function () {
|
||||
$count = Invoice::where('status', InvoiceStatus::UNPAID)->count();
|
||||
|
||||
return $count > 0 ? $count : null;
|
||||
})
|
||||
->badgeColor(InvoiceStatus::UNPAID->getColor())
|
||||
->icon(InvoiceStatus::UNPAID->getIcon()),
|
||||
|
||||
'paid' => Tab::make('Paid')
|
||||
->query(fn ($query) => $query->where('status', InvoiceStatus::PAID))
|
||||
->icon(InvoiceStatus::PAID->getIcon()),
|
||||
|
||||
'void' => Tab::make('Void')
|
||||
->query(fn ($query) => $query->where('status', InvoiceStatus::VOID))
|
||||
->icon(InvoiceStatus::VOID->getIcon()),
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Enums\OrderAttributes;
|
||||
use App\Enums\OrderStatus;
|
||||
use App\Enums\OrderType;
|
||||
@ -40,7 +40,7 @@ class OrderResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Order::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::ORDER->value;
|
||||
protected static ?string $navigationIcon = IconEnum::ORDER->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Production';
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources\OrderResource\Pages;
|
||||
|
||||
use App\Enums\IconEnum;
|
||||
use App\Enums\OrderAttributes;
|
||||
use App\Enums\OrderStatus;
|
||||
use App\Filament\Admin\Resources\OrderResource;
|
||||
@ -41,7 +42,7 @@ public function getTabs(): array
|
||||
->query(function ($query) {
|
||||
return $query->where('printed', false);
|
||||
})
|
||||
->icon('lucide-printer')
|
||||
->icon(IconEnum::TAB_UNPRINTED->value)
|
||||
->badge(function () {
|
||||
$count = Order::where('printed', false)->count();
|
||||
|
||||
@ -55,7 +56,7 @@ public function getTabs(): array
|
||||
->whereNot('status', OrderStatus::INVOICED)
|
||||
->whereNot('status', ORderStatus::SHIPPED);
|
||||
})
|
||||
->icon('lucide-calendar-clock')
|
||||
->icon(IconEnum::TAB_OVERDUE->value)
|
||||
->badge(function () {
|
||||
$count = Order::whereDate('due_date', '<=', today())
|
||||
->whereNot('status', OrderStatus::INVOICED)
|
||||
@ -84,7 +85,7 @@ public function getTabs(): array
|
||||
->badgeColor('warning'),
|
||||
|
||||
'all' => Tab::make('All')
|
||||
->icon('lucide-layout-grid'),
|
||||
->icon(IconEnum::TAB_ALL->value),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Order;
|
||||
use App\Models\PackingSlip;
|
||||
@ -21,7 +21,7 @@ class PackingSlipResource extends Resource
|
||||
{
|
||||
protected static ?string $model = PackingSlip::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::PACKING_SLIP->value;
|
||||
protected static ?string $navigationIcon = IconEnum::PACKING_SLIP->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Management';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Order;
|
||||
use App\Models\Quote;
|
||||
@ -19,7 +19,7 @@ class QuoteResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Quote::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::QUOTE->value;
|
||||
protected static ?string $navigationIcon = IconEnum::QUOTE->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Production';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Filament\Admin\Resources\ServiceTypeResource\Widgets\ServiceTypeOverview;
|
||||
use App\Models\ServiceType;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
@ -16,7 +16,7 @@ class ServiceTypeResource extends Resource
|
||||
{
|
||||
protected static ?string $model = ServiceType::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::PRODUCT_SERVICE->value;
|
||||
protected static ?string $navigationIcon = IconEnum::DEFAULT->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Reports';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Enums\ShippingType;
|
||||
use App\Models\ShippingEntry;
|
||||
use Filament\Forms\Components\Fieldset;
|
||||
@ -25,7 +25,7 @@ class ShippingEntryResource extends Resource
|
||||
{
|
||||
protected static ?string $model = ShippingEntry::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::SHIPPING_ENTRY->value;
|
||||
protected static ?string $navigationIcon = IconEnum::SHIPPING_ENTRY->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Management';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Filament\Admin\Resources\TaxRateResource\Pages;
|
||||
use App\Models\TaxRate;
|
||||
use Filament\Forms\Components\Placeholder;
|
||||
@ -19,7 +19,7 @@ class TaxRateResource extends Resource
|
||||
{
|
||||
protected static ?string $model = TaxRate::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::TAX_RATE->value;
|
||||
protected static ?string $navigationIcon = IconEnum::TAX_RATE->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Settings';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Models\User;
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
use Filament\Forms\Components\Section;
|
||||
@ -19,7 +19,7 @@ class UserResource extends Resource
|
||||
|
||||
protected static ?string $model = User::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::USER->value;
|
||||
protected static ?string $navigationIcon = IconEnum::USER->value;
|
||||
|
||||
protected static ?string $navigationGroup = 'Settings';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Filament\Customer\Resources;
|
||||
|
||||
use App\Enums\IconName;
|
||||
use App\Enums\IconEnum;
|
||||
use App\Filament\Customer\Resources\OrderResource\Pages;
|
||||
use App\Models\Order;
|
||||
use Filament\Forms\Form;
|
||||
@ -15,7 +15,7 @@ class OrderResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Order::class;
|
||||
|
||||
protected static ?string $navigationIcon = IconName::ORDER->value;
|
||||
protected static ?string $navigationIcon = IconEnum::ORDER->value;
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
|
@ -26,9 +26,9 @@ public function index(Request $request)
|
||||
return redirect()->route('dashboard', ['tab' => 'active_orders']);
|
||||
}
|
||||
|
||||
return view('dashboard', [
|
||||
'today' => Carbon::today(),
|
||||
'tab' => $request->get('tab'),
|
||||
]);
|
||||
// return view('dashboard', [
|
||||
// 'today' => Carbon::today(),
|
||||
// 'tab' => $request->get('tab'),
|
||||
// ]);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ public function getGstAttribute($created_at = null, $created_until = null): floa
|
||||
return $this->invoices()
|
||||
->when($created_at, fn ($query) => $query->whereDate('created_at', '>=', $created_at))
|
||||
->when($created_until, fn ($query) => $query->whereDate('created_at', '<=', $created_until))
|
||||
->sum('total') * 0.05;
|
||||
->where('has_gst', true)
|
||||
->sum('gst_amount');
|
||||
}
|
||||
|
||||
public function getPstAttribute($created_at = null, $created_until = null): float
|
||||
@ -51,8 +52,8 @@ public function getPstAttribute($created_at = null, $created_until = null): floa
|
||||
return $this->invoices()
|
||||
->when($created_at, fn ($query) => $query->whereDate('created_at', '>=', $created_at))
|
||||
->when($created_until, fn ($query) => $query->whereDate('created_at', '<=', $created_until))
|
||||
->where('pst', true)
|
||||
->sum('total') * 0.07;
|
||||
->where('has_pst', true)
|
||||
->sum('pst_amount');
|
||||
}
|
||||
|
||||
public function getTotalAttribute($created_at = null, $created_until = null): float
|
||||
|
@ -3,6 +3,8 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Observers\InvoiceObserver;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
@ -11,10 +13,15 @@
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
#[ObservedBy(InvoiceObserver::class)]
|
||||
|
||||
class Invoice extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
/**
|
||||
* @var float|int|mixed
|
||||
*/
|
||||
protected $fillable = [
|
||||
'internal_id',
|
||||
'customer_id',
|
||||
@ -32,55 +39,43 @@ class Invoice extends Model
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'has_gst' => 'boolean',
|
||||
'has_pst' => 'boolean',
|
||||
'date' => 'datetime',
|
||||
'total' => 'decimal:2',
|
||||
'subtotal' => 'decimal:2',
|
||||
'status' => InvoiceStatus::class,
|
||||
];
|
||||
|
||||
public static function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::created(function ($model) {
|
||||
$model->attributes['internal_id'] = 'TN4'.str_pad($model->id, 4, '0', STR_PAD_LEFT);
|
||||
$model->attributes['pst_rate'] = TaxRate::where('name', 'PST')->value('value');
|
||||
$model->attributes['gst_rate'] = TaxRate::where('name', 'GST')->value('value');
|
||||
$model->save();
|
||||
});
|
||||
}
|
||||
|
||||
public function setHasPstAttribute(bool $value): void
|
||||
{
|
||||
$this->attributes['has_pst'] = $value;
|
||||
$this->save();
|
||||
|
||||
$this->calculateTotals();
|
||||
}
|
||||
|
||||
public function setHasGstAttribute(bool $value): void
|
||||
{
|
||||
$this->attributes['has_gst'] = $value;
|
||||
$this->save();
|
||||
|
||||
$this->calculateTotals();
|
||||
}
|
||||
|
||||
public function calculateTotals(): void
|
||||
{
|
||||
$subtotal = 0;
|
||||
$this->loadMissing('orders');
|
||||
|
||||
// $gst_amount = ($this->gst_rate / 100) * $this->gst ?? 0;
|
||||
// $pst_amount = ($this->pst_rate / 100) * $this->pst ?? 0;
|
||||
if ($this->orders->isEmpty()) {
|
||||
$this->subtotal = 0;
|
||||
$this->gst_amount = 0;
|
||||
$this->pst_amount = 0;
|
||||
$this->total = 0;
|
||||
|
||||
foreach ($this->orders as $order) {
|
||||
$subtotal += $order->total_service_price;
|
||||
return;
|
||||
}
|
||||
|
||||
$subtotal = $this->orders->sum(fn (Order $order) => $order->total_service_price);
|
||||
$this->subtotal = $subtotal;
|
||||
// $this->total = $subtotal + $gst_amount + $pst_amount;
|
||||
|
||||
$this->save();
|
||||
$gstAmount = $this->calculateTaxAmount($subtotal, $this->gst_rate, $this->has_gst);
|
||||
$pstAmount = $this->calculateTaxAmount($subtotal, $this->pst_rate, $this->has_pst);
|
||||
|
||||
$this->gst_amount = $gstAmount;
|
||||
$this->pst_amount = $pstAmount;
|
||||
$this->total = $subtotal + $gstAmount + $pstAmount;
|
||||
|
||||
$this->saveQuietly();
|
||||
}
|
||||
|
||||
private function calculateTaxAmount(float $amount, float $rate, ?bool $apply): float
|
||||
{
|
||||
return $apply ? $amount * ($rate / 100) : 0;
|
||||
}
|
||||
|
||||
public function setStatus(InvoiceStatus $status): void
|
||||
@ -91,27 +86,9 @@ public function setStatus(InvoiceStatus $status): void
|
||||
}
|
||||
}
|
||||
|
||||
// public function getGstAmountAttribute(): float
|
||||
// {
|
||||
// if ($this->gst) {
|
||||
// return round($this->subtotal * ($this->gst_rate / 100), 2);
|
||||
// }
|
||||
//
|
||||
// return 0.00;
|
||||
// }
|
||||
//
|
||||
// public function getPstAmountAttribute(): float
|
||||
// {
|
||||
// if ($this->pst) {
|
||||
// return round($this->subtotal * ($this->pst_rate / 100), 2);
|
||||
// }
|
||||
//
|
||||
// return 0.00;
|
||||
// }
|
||||
|
||||
public function orders(): HasMany
|
||||
{
|
||||
return $this->HasMany(Order::class);
|
||||
return $this->hasMany(Order::class);
|
||||
}
|
||||
|
||||
public function customer(): BelongsTo
|
||||
|
@ -3,16 +3,28 @@
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\TaxRate;
|
||||
|
||||
class InvoiceObserver
|
||||
{
|
||||
/**
|
||||
* Handle the Invoice "creating" event.
|
||||
*/
|
||||
public function creating(Invoice $invoice): void
|
||||
{
|
||||
$invoice->pst_rate = TaxRate::where('name', 'PST')->value('value') ?? 0;
|
||||
$invoice->gst_rate = TaxRate::where('name', 'GST')->value('value') ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Invoice "created" event.
|
||||
*/
|
||||
public function created(Invoice $invoice): void
|
||||
{
|
||||
Log::debug('Invoice created');
|
||||
$invoice->internal_id = 'INV4'.str_pad($invoice->id, 5, '0', STR_PAD_LEFT);
|
||||
$invoice->saveQuietly();
|
||||
|
||||
$invoice->calculateTotals();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -20,30 +32,6 @@ public function created(Invoice $invoice): void
|
||||
*/
|
||||
public function updated(Invoice $invoice): void
|
||||
{
|
||||
\Log::debug('Invoice updated!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Invoice "deleted" event.
|
||||
*/
|
||||
public function deleted(Invoice $invoice): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Invoice "restored" event.
|
||||
*/
|
||||
public function restored(Invoice $invoice): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Invoice "force deleted" event.
|
||||
*/
|
||||
public function forceDeleted(Invoice $invoice): void
|
||||
{
|
||||
//
|
||||
$invoice->calculateTotals();
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ public function definition(): array
|
||||
'created_at' => Carbon::now()->subDays(rand(1, 30)),
|
||||
'pst_rate' => TaxRate::where('name', 'PST')->value('value'),
|
||||
'gst_rate' => TaxRate::where('name', 'GST')->value('value'),
|
||||
// 'gst' => true,
|
||||
// 'pst' => $this->faker->boolean(40),
|
||||
'has_gst' => true,
|
||||
'has_pst' => $this->faker->boolean(40),
|
||||
'date' => Carbon::now()->subDays(rand(1, 60)),
|
||||
'status' => $this->faker->randomElement(InvoiceStatus::cases())->value,
|
||||
'customer_id' => $customer->id,
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,59 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('header')
|
||||
<div class="container-fluid bg-light pt-3">
|
||||
|
||||
<!-- Customer company name row -->
|
||||
<div class="row justify-content-center pb-2">
|
||||
<div class="col-3"></div>
|
||||
<div class="col">
|
||||
{{-- <h2>Overview</h2>--}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabs row -->
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-3 border-bottom"></div>
|
||||
<div class="col-6 p-0">
|
||||
|
||||
<ul class="nav nav-fill nav-tabs" id="home-tabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link link-dark {{$tab == 'active_orders' ? 'active' : ''}}" id="active_orders-tab"
|
||||
href="{{route('dashboard', ['tab' => 'active_orders'])}}" type="button" role="tab"
|
||||
aria-controls="active_orders"
|
||||
aria-selected="{{$tab == 'active_orders' ? 'true' : 'false'}}">
|
||||
<x-bi-arrow-clockwise/>
|
||||
Active Orders
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link link-dark {{$tab == 'packing_slips' ? 'active' : ''}}" id="packing-tab"
|
||||
href="{{route('dashboard', ['tab' => 'packing_slips'])}}" type="button" role="tab"
|
||||
aria-controls="packing_slips"
|
||||
aria-selected="{{$tab == 'packing_slips' ? 'true' : 'false'}}">
|
||||
<x-bi-list-ul/>
|
||||
Packing Slips
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col border-bottom"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center my-3">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane {{$tab == 'active_orders' ? 'active' : ''}}" id="active_orders" role="tabpanel"
|
||||
aria-labelledby="active_orders-tab">
|
||||
|
||||
<livewire:orders-table :order-type="'active'" :show-customer-column="true" title="Active Orders"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@ -113,8 +113,8 @@
|
||||
|
||||
<div class="fw-bold text-end">
|
||||
<div>Subtotal</div>
|
||||
<div>GST @ 5%</div>
|
||||
<div>PST (BC) @ 7%</div>
|
||||
<div>GST @ {{$invoice->gst_rate}}%</div>
|
||||
<div>PST (BC) @ {{$invoice->pst_rate}}%</div>
|
||||
<div>TOTAL</div>
|
||||
<br>
|
||||
<div>BALANCE DUE</div>
|
||||
|
File diff suppressed because one or more lines are too long
50
tests/Feature/InvoiceTest.php
Normal file
50
tests/Feature/InvoiceTest.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Filament\Admin\Resources\InvoiceResource\Pages\CreateInvoice;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('can create an invoice', function () {
|
||||
$customer = Customer::factory()->create(); // Generates a customer
|
||||
$user = User::factory(['is_admin' => true])->create();
|
||||
$pst_rate = TaxRate::where('name', 'PST')->value('value') ?? 0;
|
||||
$gst_rate = TaxRate::where('name', 'GST')->value('value') ?? 0;
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$formData = [
|
||||
'customer_id' => $customer->id,
|
||||
'date' => now()->toDateString(),
|
||||
'due_date' => now()->addDays(7)->toDateString(),
|
||||
'status' => InvoiceStatus::UNPAID->value,
|
||||
'has_gst' => true,
|
||||
'has_pst' => true,
|
||||
];
|
||||
|
||||
// Step 3: Submit the form and create an invoice
|
||||
$this->livewire(CreateInvoice::class)
|
||||
->fillForm($formData) // Simulates filling the form
|
||||
->call('create') // Submits the form
|
||||
->assertHasNoErrors(); // Verifies no validation errors occurred
|
||||
|
||||
// Step 4: Assert the invoice was successfully created in the database
|
||||
$this->assertDatabaseHas('invoices', [
|
||||
'internal_id' => 'INV400001',
|
||||
'customer_id' => $formData['customer_id'],
|
||||
'status' => $formData['status'],
|
||||
'has_gst' => $formData['has_gst'],
|
||||
'has_pst' => $formData['has_pst'],
|
||||
'gst_rate' => $gst_rate,
|
||||
'pst_rate' => $pst_rate,
|
||||
]);
|
||||
});
|
||||
|
||||
// it can add orders
|
||||
|
||||
// it correctly calculates tax
|
@ -35,7 +35,7 @@
|
||||
$formData = [
|
||||
'order_type' => $type->value,
|
||||
'customer_id' => $customer->id,
|
||||
'contact_id' => $contact->id,
|
||||
// 'contact_id' => $contact->id,
|
||||
'customer_po' => 'Customer PO name here',
|
||||
'order_date' => $orderDate,
|
||||
'due_date' => $dueDate,
|
||||
@ -113,7 +113,7 @@
|
||||
[
|
||||
$order->id,
|
||||
$order->customer_id,
|
||||
$order->contact_id,
|
||||
// $order->contact_id,
|
||||
$order->internal_po,
|
||||
$order->customer_po,
|
||||
$order->invoice_id,
|
||||
@ -135,8 +135,8 @@
|
||||
[
|
||||
1,
|
||||
$customer->id,
|
||||
$contact->id,
|
||||
'TN24-0001',
|
||||
// $contact->id,
|
||||
'TN25-0001',
|
||||
'Customer PO name here',
|
||||
null,
|
||||
$orderDate->format('Y-m-d'),
|
Loading…
x
Reference in New Issue
Block a user