Work on invoices

orders
Nisse Lommerde 3 weeks ago
parent d950955371
commit a12e0b29d3

@ -3,7 +3,15 @@
namespace App\Filament\Resources; namespace App\Filament\Resources;
use App\Filament\Resources\InvoiceResource\Pages; use App\Filament\Resources\InvoiceResource\Pages;
use App\Models\Customer;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Order;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Split;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables; use Filament\Tables;
@ -23,19 +31,78 @@ class InvoiceResource extends Resource
{ {
return $form return $form
->schema([ ->schema([
// Section::make([
]); Grid::make(2)
->schema([
Select::make('customer_id')
->required()
->label('Customer')
->options(Customer::all()->pluck('company_name', 'id'))
->reactive()
->searchable()
->columnSpan(2),
Select::make('orders')
->options(fn ($get): array => Order::where('customer_id', $get('customer_id') ?? null)
->get()
->pluck('customer_po', 'id')
->toArray())
->multiple()
->searchable()
->columnSpan(2),
Split::make([
DatePicker::make('date')
->required()
->default(today()),
DatePicker::make('due_date'),
])
->columnSpan(2),
])->columnSpan(2),
Grid::make(1)
->schema([
ToggleButtons::make('gst')
->boolean()
->default(true)
->inline()
->colors([
'true' => 'info',
'false' => 'info',
]),
ToggleButtons::make('pst')
->boolean()
->default(false)
->inline()
->colors([
'true' => 'info',
'false' => 'info',
]),
])->columnSpan(1),
])
->columns(3)
->columnSpan(3),
])->columns(3);
} }
public static function table(Table $table): Table public static function table(Table $table): Table
{ {
return $table return $table
->columns([ ->columns([
// Tables\Columns\TextColumn::make('internal_id')
->label('ID')
->color('primary'),
Tables\Columns\TextColumn::make('created_at')
->date(),
Tables\Columns\TextColumn::make('order.total_service_price')
->label('Price')
->prefix('$'),
]) ])
->filters([ ->filters([
// //
]) ])
->defaultSort('created_at', 'desc')
->actions([ ->actions([
Tables\Actions\EditAction::make(), Tables\Actions\EditAction::make(),
]) ])
@ -49,7 +116,7 @@ class InvoiceResource extends Resource
public static function getRelations(): array public static function getRelations(): array
{ {
return [ return [
// // OrdersRelationManager::class,
]; ];
} }

@ -3,13 +3,36 @@
namespace App\Filament\Resources\InvoiceResource\Pages; namespace App\Filament\Resources\InvoiceResource\Pages;
use App\Filament\Resources\InvoiceResource; use App\Filament\Resources\InvoiceResource;
use App\Models\Invoice;
use App\Models\Order;
use Filament\Actions; use Filament\Actions;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
use Illuminate\Database\Eloquent\Model;
class EditInvoice extends EditRecord class EditInvoice extends EditRecord
{ {
protected static string $resource = InvoiceResource::class; protected static string $resource = InvoiceResource::class;
protected function mutateFormDataBeforeFill(array $data): array
{
$invoice = Invoice::findOrFail($data['id']);
foreach ($invoice->orders as $order) {
$data['orders'][] = $order->id;
}
return $data;
}
protected function handleRecordUpdate(Model $record, array $data): Model
{
$record->orders()->delete();
$record->orders()->saveMany(Order::findMany($data['orders']));
return $record;
}
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
return [ return [

@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\InvoiceResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class OrdersRelationManager extends RelationManager
{
protected static string $relationship = 'orders';
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('customer_po')
->required()
->maxLength(255),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('customer_po')
->columns([
Tables\Columns\TextColumn::make('customer_po'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
}

@ -255,6 +255,13 @@ class OrderResource extends Resource
->searchable() ->searchable()
->sortable(), ->sortable(),
]) ])
->recordClasses(function (Order $order) {
if ($order->rush) {
return 'bg-green-100';
}
return '';
})
->defaultSort('order_date', 'desc') ->defaultSort('order_date', 'desc')
->groups([ ->groups([
'status', 'status',

@ -6,6 +6,7 @@ use App\Filament\Resources\QuoteResource\Pages;
use App\Models\Customer; use App\Models\Customer;
use App\Models\Order; use App\Models\Order;
use App\Models\Quote; use App\Models\Quote;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Components\Split; use Filament\Forms\Components\Split;
use Filament\Forms\Components\Textarea; use Filament\Forms\Components\Textarea;
@ -28,25 +29,28 @@ class QuoteResource extends Resource
{ {
return $form return $form
->schema([ ->schema([
Split::make([ Section::make([
Select::make('customer_id') Split::make([
->required() Select::make('customer_id')
->label('Customer') ->required()
->options(Customer::all()->pluck('company_name', 'id')) ->label('Customer')
->reactive() ->options(Customer::all()->pluck('company_name', 'id'))
->searchable(), ->reactive()
->searchable(),
Select::make('order_id') Select::make('order_id')
->label('Order') ->label('Order')
->options(fn ($get): array => Order::where('customer_id', $get('customer_id') ?? null) ->options(fn ($get): array => Order::where('customer_id', $get('customer_id') ?? null)
->get() ->get()
->pluck('customer_po', 'id') ->pluck('customer_po', 'id')
->toArray()) ->toArray())
->searchable(), ->searchable(),
])->columnSpan(2),
Textarea::make('body') ])->columnSpan(2),
->columnSpan(2) Textarea::make('body')
->rows(8), ->columnSpan(2)
->rows(8),
]),
])->columns(3); ])->columns(3);
} }

@ -52,4 +52,9 @@ class Customer extends Model
{ {
return $this->hasMany(Order::class); return $this->hasMany(Order::class);
} }
public function invoices(): HasMany
{
return $this->hasMany(invoice::class);
}
} }

@ -4,8 +4,41 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Invoice extends Model class Invoice extends Model
{ {
use HasFactory; use HasFactory;
protected $fillable = [
'customer_id',
'subtotal',
'total',
'gst',
'pst',
'date',
];
protected $appends = [
'internal_id',
];
public function getInternalIdAttribute(): string
{
$po = str_pad(strval($this->id), 4, '0', STR_PAD_LEFT);
$year = date('y');
return 'TN-IN-'.$year.'-'.$po;
}
public function orders(): HasMany
{
return $this->HasMany(Order::class);
}
public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class);
}
} }

@ -42,9 +42,12 @@ class Order extends Model
'pre_production', 'pre_production',
]; ];
protected $appends = [
'total_service_price',
];
protected $casts = [ protected $casts = [
'status' => OrderStatus::class, 'status' => OrderStatus::class,
// 'order_attributes' => 'array',
]; ];
public static function boot(): void public static function boot(): void
@ -86,7 +89,7 @@ class Order extends Model
return $total; return $total;
} }
public function totalServicePrice(): string public function getTotalServicePriceAttribute(): string
{ {
$total = 0; $total = 0;
@ -200,6 +203,11 @@ class Order extends Model
return $this->hasOne(Quote::class); return $this->hasOne(Quote::class);
} }
public function invoice(): BelongsTo
{
return $this->belongsTo(Invoice::class);
}
protected function serializeDate(DateTimeInterface $date): string protected function serializeDate(DateTimeInterface $date): string
{ {
return $date->format('Y-m-d'); return $date->format('Y-m-d');

@ -18,7 +18,7 @@ class ProductServiceFactory extends Factory
'service_type' => $this->faker->randomElement(['emb', 'scp', 'dtg', 'vinyl']), 'service_type' => $this->faker->randomElement(['emb', 'scp', 'dtg', 'vinyl']),
'placement' => $this->faker->randomElement(['l/c', 'c/f', 'f/b', 'r/c']), 'placement' => $this->faker->randomElement(['l/c', 'c/f', 'f/b', 'r/c']),
'amount' => $this->faker->randomNumber(1), 'amount' => $this->faker->randomNumber(1),
'amount_price' => 0, 'amount_price' => random_int(1, 15),
'notes' => $this->faker->randomElement(['1) 1149 2) grey 3) white', '1) white', '1) black 2) white']), 'notes' => $this->faker->randomElement(['1) 1149 2) grey 3) white', '1) white', '1) black 2) white']),
]; ];
} }

@ -11,10 +11,17 @@ return new class extends Migration
Schema::create('invoices', function (Blueprint $table) { Schema::create('invoices', function (Blueprint $table) {
$table->id(); $table->id();
$table->foreignId('order_id')->nullable(); $table->foreignId('customer_id')->constrained()->nullable();
$table->float('subtotal')->default(0.00);
$table->float('total')->default(0.00);
$table->boolean('gst')->default(0); $table->boolean('gst')->default(0);
$table->boolean('pst')->default(0); $table->boolean('pst')->default(0);
$table->date('date')->default(today());
$table->date('due_date')->nullable();
$table->timestamps(); $table->timestamps();
}); });
} }

@ -10,8 +10,11 @@ return new class extends Migration
{ {
Schema::create('orders', function (Blueprint $table) { Schema::create('orders', function (Blueprint $table) {
$table->id(); $table->id();
$table->foreignId('customer_id')->constrained(); $table->foreignId('customer_id')->constrained();
$table->foreignId('contact_id')->nullable()->constrained(); $table->foreignId('contact_id')->nullable()->constrained();
$table->foreignId('invoice_id')->nullable()->constrained();
$table->string('internal_po')->nullable(); $table->string('internal_po')->nullable();
$table->string('customer_po'); $table->string('customer_po');
$table->string('order_type'); $table->string('order_type');

@ -2,9 +2,6 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Enums\OrderStatus;
use App\Models\Invoice;
use App\Models\Order;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
class InvoiceSeeder extends Seeder class InvoiceSeeder extends Seeder
@ -14,8 +11,8 @@ class InvoiceSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
foreach (Order::where('status', OrderStatus::INVOICED) as $order) { // foreach (Order::where('status', OrderStatus::INVOICED->value)->get() as $order) {
Invoice::factory()->for($order)->create(); // Invoice::factory()->for($order)->create();
} // }
} }
} }

@ -2,7 +2,8 @@
export default { export default {
content: [ content: [
"./resources/**/*.blade.php", "./resources/**/*.blade.php",
"./app/Filament/**/*.blade.php" "./app/Filament/**/*.php",
"./vendor/filament/**/*.php"
], ],
theme: { theme: {
extend: {}, extend: {},

Loading…
Cancel
Save