WIP Work on Payments
This commit is contained in:
parent
f937302159
commit
cadc096227
@ -5,7 +5,7 @@
|
|||||||
enum IconEnum: string
|
enum IconEnum: string
|
||||||
{
|
{
|
||||||
case DEFAULT = 'heroicon-o-rectangle-stack';
|
case DEFAULT = 'heroicon-o-rectangle-stack';
|
||||||
case INVOICE = 'lucide-receipt-text';
|
case INVOICE = 'lucide-file-text';
|
||||||
case ORDER = 'lucide-shopping-cart';
|
case ORDER = 'lucide-shopping-cart';
|
||||||
case QUOTE = 'lucide-quote';
|
case QUOTE = 'lucide-quote';
|
||||||
case CUSTOMER = 'lucide-building';
|
case CUSTOMER = 'lucide-building';
|
||||||
@ -15,8 +15,8 @@ enum IconEnum: string
|
|||||||
case TAX_RATE = 'lucide-circle-dollar-sign';
|
case TAX_RATE = 'lucide-circle-dollar-sign';
|
||||||
|
|
||||||
// case PRODUCT_SERVICE = 'heroicon-o-rectangle-stack';
|
// case PRODUCT_SERVICE = 'heroicon-o-rectangle-stack';
|
||||||
// case CUSTOMER_SALES = 'heroicon-o-rectangle-stack';
|
case CUSTOMER_SALES = 'lucide-book-user';
|
||||||
// case INVOICE_REPORT = 'heroicon-o-rectangle-stack';
|
case INVOICE_REPORT = 'lucide-files';
|
||||||
|
|
||||||
case TAB_ALL = 'lucide-layout-grid';
|
case TAB_ALL = 'lucide-layout-grid';
|
||||||
case TAB_OVERDUE = 'lucide-calendar-clock';
|
case TAB_OVERDUE = 'lucide-calendar-clock';
|
||||||
|
@ -18,13 +18,13 @@ class CustomerReportResource extends Resource
|
|||||||
{
|
{
|
||||||
protected static ?string $model = Customer::class;
|
protected static ?string $model = Customer::class;
|
||||||
|
|
||||||
|
protected static ?string $navigationIcon = IconEnum::CUSTOMER_SALES->value;
|
||||||
|
|
||||||
protected static ?string $navigationGroup = 'Reports';
|
protected static ?string $navigationGroup = 'Reports';
|
||||||
|
|
||||||
protected static ?string $navigationIcon = IconEnum::DEFAULT->value;
|
protected static ?string $navigationLabel = 'Customer Reports';
|
||||||
|
|
||||||
protected static ?string $navigationLabel = 'Customer Sales';
|
protected static ?int $navigationSort = 4;
|
||||||
|
|
||||||
protected static ?int $navigationSort = 2;
|
|
||||||
|
|
||||||
public static function form(Form $form): Form
|
public static function form(Form $form): Form
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
class InvoiceReportResource extends Resource
|
class InvoiceReportResource extends Resource
|
||||||
{
|
{
|
||||||
protected static ?string $navigationIcon = IconEnum::DEFAULT->value;
|
protected static ?string $navigationIcon = IconEnum::INVOICE_REPORT->value;
|
||||||
|
|
||||||
protected static ?string $navigationGroup = 'Reports';
|
protected static ?string $navigationGroup = 'Reports';
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@ class InvoiceResource extends Resource
|
|||||||
|
|
||||||
protected static ?string $navigationIcon = IconEnum::INVOICE->value;
|
protected static ?string $navigationIcon = IconEnum::INVOICE->value;
|
||||||
|
|
||||||
protected static ?string $navigationGroup = 'Production';
|
protected static ?string $navigationGroup = 'Financial';
|
||||||
|
|
||||||
protected static ?int $navigationSort = 2;
|
protected static ?int $navigationSort = 1;
|
||||||
|
|
||||||
public static function form(Form $form): Form
|
public static function form(Form $form): Form
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ class PackingSlipResource extends Resource
|
|||||||
|
|
||||||
protected static ?string $navigationIcon = IconEnum::PACKING_SLIP->value;
|
protected static ?string $navigationIcon = IconEnum::PACKING_SLIP->value;
|
||||||
|
|
||||||
protected static ?string $navigationGroup = 'Management';
|
protected static ?string $navigationGroup = 'Production';
|
||||||
|
|
||||||
protected static ?int $navigationSort = 2;
|
protected static ?int $navigationSort = 2;
|
||||||
|
|
||||||
|
74
app/Filament/Admin/Resources/PaymentResource.php
Normal file
74
app/Filament/Admin/Resources/PaymentResource.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use Filament\Forms\Components\Section;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
|
use Filament\Forms\Form;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Tables;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class PaymentResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = Payment::class;
|
||||||
|
|
||||||
|
protected static ?string $navigationIcon = 'lucide-hand-coins';
|
||||||
|
|
||||||
|
protected static ?string $navigationGroup = 'Financial';
|
||||||
|
|
||||||
|
protected static ?int $navigationSort = 2;
|
||||||
|
|
||||||
|
public static function form(Form $form): Form
|
||||||
|
{
|
||||||
|
return $form
|
||||||
|
->schema([
|
||||||
|
Section::make([
|
||||||
|
Select::make('customer_id')
|
||||||
|
->relationship('customer', 'company_name'),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
//
|
||||||
|
])
|
||||||
|
->filters([
|
||||||
|
//
|
||||||
|
])
|
||||||
|
->actions([
|
||||||
|
Tables\Actions\EditAction::make(),
|
||||||
|
])
|
||||||
|
->bulkActions([
|
||||||
|
Tables\Actions\BulkActionGroup::make([
|
||||||
|
Tables\Actions\DeleteBulkAction::make(),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function canAccess(): bool
|
||||||
|
{
|
||||||
|
return auth()->user()->is_admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRelations(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => Pages\ListPayments::route('/'),
|
||||||
|
'create' => Pages\CreatePayment::route('/create'),
|
||||||
|
'edit' => Pages\EditPayment::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\PaymentResource;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreatePayment extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = PaymentResource::class;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\PaymentResource;
|
||||||
|
use Filament\Actions;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditPayment extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = PaymentResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Actions\DeleteAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\PaymentResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\PaymentResource;
|
||||||
|
use Filament\Actions;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListPayments extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = PaymentResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Actions\CreateAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,8 @@ class ServiceTypeResource extends Resource
|
|||||||
|
|
||||||
protected static ?string $label = 'Product Services';
|
protected static ?string $label = 'Product Services';
|
||||||
|
|
||||||
|
protected static ?int $navigationSort = 2;
|
||||||
|
|
||||||
public static function getWidgets(): array
|
public static function getWidgets(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
@ -54,6 +54,13 @@ class Invoice extends Model
|
|||||||
'total' => 'float',
|
'total' => 'float',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function remainingBalance(): float
|
||||||
|
{
|
||||||
|
$applied = $this->payments()->sum('pivot.applied_amount');
|
||||||
|
|
||||||
|
return max(0, $this->total - $applied);
|
||||||
|
}
|
||||||
|
|
||||||
public function calculateTotals(): void
|
public function calculateTotals(): void
|
||||||
{
|
{
|
||||||
$this->refresh();
|
$this->refresh();
|
||||||
@ -120,4 +127,11 @@ public function invoiceReports(): BelongsToMany
|
|||||||
{
|
{
|
||||||
return $this->belongsToMany(InvoiceReport::class);
|
return $this->belongsToMany(InvoiceReport::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function payments(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Payment::class)
|
||||||
|
->withPivot('applied_amount')
|
||||||
|
->withTimestamps();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
64
app/Models/Payment.php
Normal file
64
app/Models/Payment.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\InvoiceStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
|
||||||
|
class Payment extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'customer_id',
|
||||||
|
'amount',
|
||||||
|
'unapplied_amount',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function applyToInvoices()
|
||||||
|
{
|
||||||
|
$remaning = $this->unapplied_amount ?? $this->amount;
|
||||||
|
|
||||||
|
$invoices = Invoice::where('customer_id', $this->customer_id)
|
||||||
|
->where('status', '==', 'UNPAID')
|
||||||
|
->orderBy('date')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($invoices as $invoice) {
|
||||||
|
$balance = $invoice->remainingBalance();
|
||||||
|
|
||||||
|
if ($remaning <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$applied = min($remaining, $balance);
|
||||||
|
$invoice->payments()->attach($this->id, ['applied_amount' => $applied]);
|
||||||
|
|
||||||
|
$remaining -= $applied;
|
||||||
|
|
||||||
|
if ($invoice->remainingBalance() == 0) {
|
||||||
|
$invoice->setStatus(InvoiceStatus::PAID);
|
||||||
|
} elseif ($applied > 0) {
|
||||||
|
$invoice->setStatus(InvoiceStatus::UNPAID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->unapplied_amount = $remaining;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customer(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Customer::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoices(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Invoice::class)
|
||||||
|
->withPivot('applied_amount')
|
||||||
|
->withTimestamps();
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
use Filament\Http\Middleware\Authenticate;
|
use Filament\Http\Middleware\Authenticate;
|
||||||
use Filament\Http\Middleware\DisableBladeIconComponents;
|
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||||
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||||
|
use Filament\Navigation\NavigationGroup;
|
||||||
use Filament\Pages;
|
use Filament\Pages;
|
||||||
use Filament\Panel;
|
use Filament\Panel;
|
||||||
use Filament\PanelProvider;
|
use Filament\PanelProvider;
|
||||||
@ -53,6 +54,13 @@ public function panel(Panel $panel): Panel
|
|||||||
->authMiddleware([
|
->authMiddleware([
|
||||||
Authenticate::class,
|
Authenticate::class,
|
||||||
])
|
])
|
||||||
->sidebarWidth('13rem');
|
->sidebarWidth('13rem')
|
||||||
|
->navigationGroups([
|
||||||
|
NavigationGroup::make('Production'),
|
||||||
|
NavigationGroup::make('Management'),
|
||||||
|
NavigationGroup::make('Financial'),
|
||||||
|
NavigationGroup::make('Reports'),
|
||||||
|
NavigationGroup::make('Settings'),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1491
composer.lock
generated
1491
composer.lock
generated
File diff suppressed because it is too large
Load Diff
32
database/migrations/018_create_payments_table.php
Normal file
32
database/migrations/018_create_payments_table.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('payments', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('customer_id')->constrained();
|
||||||
|
$table->decimal('amount', 8, 2);
|
||||||
|
$table->decimal('unapplied_amount', 8, 2)->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('payments');
|
||||||
|
}
|
||||||
|
};
|
31
database/migrations/019_create_invoice_payment_table.php
Normal file
31
database/migrations/019_create_invoice_payment_table.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('invoice_payment', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('invoice_id')->constrained();
|
||||||
|
$table->foreignId('payment_id')->constrained();
|
||||||
|
$table->decimal('applied_amount', 8, 2);
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('invoice_payment');
|
||||||
|
}
|
||||||
|
};
|
1473
package-lock.json
generated
1473
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user