Skip to content

Commit 5879ada

Browse files
committed
fix checkout
1 parent c08e653 commit 5879ada

6 files changed

Lines changed: 560 additions & 1 deletion

File tree

app/Domain/Checkout/Models/Checkout/Checkout.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App\Domain\Checkout\Models\Checkout\States\CheckoutStatusState;
66
use App\Domain\Printing\Models\PrintJob;
77
use App\Models\Machine;
8+
use App\Models\Staff;
89
use App\Models\User;
910
use Illuminate\Database\Eloquent\Model;
1011
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -35,7 +36,7 @@ public function user(): BelongsTo
3536

3637
public function cashier(): BelongsTo
3738
{
38-
return $this->belongsTo(User::class, 'cashier_id');
39+
return $this->belongsTo(Staff::class, 'cashier_id');
3940
}
4041

4142
public function items()
Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
<?php
2+
3+
namespace App\Filament\Resources;
4+
5+
use App\Domain\Checkout\Models\Checkout\Checkout;
6+
use App\Domain\Checkout\Models\Checkout\States\Active;
7+
use App\Domain\Checkout\Models\Checkout\States\Cancelled;
8+
use App\Domain\Checkout\Models\Checkout\States\Finished;
9+
use App\Filament\Resources\CheckoutResource\Pages;
10+
use App\Filament\Resources\CheckoutResource\RelationManagers;
11+
use Filament\Forms;
12+
use Filament\Forms\Form;
13+
use Filament\Resources\Resource;
14+
use Filament\Tables;
15+
use Filament\Tables\Table;
16+
use Illuminate\Database\Eloquent\Builder;
17+
use Illuminate\Database\Eloquent\Model;
18+
use Illuminate\Support\HtmlString;
19+
20+
class CheckoutResource extends Resource
21+
{
22+
protected static ?string $model = Checkout::class;
23+
24+
protected static ?string $navigationIcon = 'heroicon-o-shopping-cart';
25+
26+
protected static ?string $navigationGroup = 'Sales';
27+
28+
protected static ?int $navigationSort = 10;
29+
30+
public static function form(Form $form): Form
31+
{
32+
return $form
33+
->schema([
34+
Forms\Components\Section::make('Checkout Information')
35+
->schema([
36+
Forms\Components\TextInput::make('remote_id')
37+
->label('Remote ID')
38+
->disabled(),
39+
40+
Forms\Components\Select::make('user_id')
41+
->label('Customer')
42+
->relationship('user', 'name')
43+
->disabled()
44+
->searchable(),
45+
46+
Forms\Components\Select::make('cashier_id')
47+
->label('Cashier')
48+
->relationship('cashier', 'name')
49+
->disabled(),
50+
51+
Forms\Components\Select::make('machine_id')
52+
->label('Machine')
53+
->relationship('machine', 'name')
54+
->disabled(),
55+
56+
Forms\Components\TextInput::make('status')
57+
->disabled(),
58+
59+
Forms\Components\TextInput::make('payment_method')
60+
->disabled(),
61+
])
62+
->columns(2),
63+
64+
Forms\Components\Section::make('Financial Details')
65+
->schema([
66+
Forms\Components\TextInput::make('subtotal')
67+
->prefix('')
68+
->numeric()
69+
->disabled(),
70+
71+
Forms\Components\TextInput::make('tax')
72+
->prefix('')
73+
->numeric()
74+
->disabled(),
75+
76+
Forms\Components\TextInput::make('total')
77+
->prefix('')
78+
->numeric()
79+
->disabled(),
80+
])
81+
->columns(3),
82+
83+
Forms\Components\Section::make('TSE Information')
84+
->schema([
85+
Forms\Components\DateTimePicker::make('tse_start_timestamp')
86+
->label('TSE Start')
87+
->disabled(),
88+
89+
Forms\Components\DateTimePicker::make('tse_end_timestamp')
90+
->label('TSE End')
91+
->disabled(),
92+
93+
Forms\Components\TextInput::make('tse_signature')
94+
->label('TSE Signature')
95+
->disabled()
96+
->columnSpanFull(),
97+
])
98+
->columns(2)
99+
->collapsed(),
100+
101+
Forms\Components\Section::make('Timestamps')
102+
->schema([
103+
Forms\Components\DateTimePicker::make('created_at')
104+
->disabled(),
105+
106+
Forms\Components\DateTimePicker::make('updated_at')
107+
->disabled(),
108+
])
109+
->columns(2)
110+
->collapsed(),
111+
]);
112+
}
113+
114+
public static function table(Table $table): Table
115+
{
116+
return $table
117+
->columns([
118+
Tables\Columns\TextColumn::make('id')
119+
->label('ID')
120+
->searchable()
121+
->sortable(),
122+
123+
Tables\Columns\TextColumn::make('user.name')
124+
->label('Customer')
125+
->searchable()
126+
->sortable()
127+
->url(fn ($record) => $record->user ? UserResource::getUrl('index') . '?tableSearch=' . urlencode($record->user->name) : null),
128+
129+
Tables\Columns\TextColumn::make('cashier.name')
130+
->label('Cashier')
131+
->searchable()
132+
->sortable()
133+
->default('-'),
134+
135+
Tables\Columns\TextColumn::make('machine.name')
136+
->label('Machine')
137+
->searchable()
138+
->sortable()
139+
->toggleable(),
140+
141+
Tables\Columns\TextColumn::make('status')
142+
->badge()
143+
->formatStateUsing(fn ($state) => class_basename($state))
144+
->color(fn ($state) => match (true) {
145+
$state instanceof Finished => 'success',
146+
$state instanceof Active => 'warning',
147+
$state instanceof Cancelled => 'danger',
148+
default => 'gray',
149+
}),
150+
151+
Tables\Columns\TextColumn::make('payment_method')
152+
->badge()
153+
->color(fn ($state) => match ($state) {
154+
'cash' => 'success',
155+
'card' => 'info',
156+
default => 'gray',
157+
}),
158+
159+
Tables\Columns\TextColumn::make('total')
160+
->money('EUR', divideBy: 100)
161+
->sortable()
162+
->summarize(Tables\Columns\Summarizers\Sum::make()
163+
->money('EUR', divideBy: 100)
164+
->label('Total')),
165+
166+
Tables\Columns\TextColumn::make('items_count')
167+
->counts('items')
168+
->label('Items'),
169+
170+
Tables\Columns\TextColumn::make('created_at')
171+
->dateTime()
172+
->sortable()
173+
->toggleable(),
174+
])
175+
->defaultSort('created_at', 'desc')
176+
->filters([
177+
Tables\Filters\SelectFilter::make('status')
178+
->options([
179+
Active::class => 'Active',
180+
Finished::class => 'Finished',
181+
Cancelled::class => 'Cancelled',
182+
])
183+
->multiple(),
184+
185+
Tables\Filters\SelectFilter::make('payment_method')
186+
->options([
187+
'cash' => 'Cash',
188+
'card' => 'Card',
189+
]),
190+
191+
Tables\Filters\SelectFilter::make('machine_id')
192+
->label('Machine')
193+
->relationship('machine', 'name'),
194+
195+
Tables\Filters\Filter::make('created_at')
196+
->form([
197+
Forms\Components\DatePicker::make('created_from'),
198+
Forms\Components\DatePicker::make('created_until'),
199+
])
200+
->query(function (Builder $query, array $data): Builder {
201+
return $query
202+
->when(
203+
$data['created_from'],
204+
fn (Builder $query, $date): Builder => $query->whereDate('created_at', '>=', $date),
205+
)
206+
->when(
207+
$data['created_until'],
208+
fn (Builder $query, $date): Builder => $query->whereDate('created_at', '<=', $date),
209+
);
210+
})
211+
])
212+
->actions([
213+
Tables\Actions\ViewAction::make(),
214+
Tables\Actions\Action::make('receipt')
215+
->label('Receipt')
216+
->icon('heroicon-o-document-text')
217+
->color('gray')
218+
->url(fn (Checkout $record): string => route('pos.checkout.receipt', $record))
219+
->openUrlInNewTab(),
220+
Tables\Actions\Action::make('print')
221+
->label('Print')
222+
->icon('heroicon-o-printer')
223+
->color('info')
224+
->action(function (Checkout $record) {
225+
// Generate receipt PDF
226+
\App\Jobs\CreateReceiptFromCheckoutJob::dispatchSync($record);
227+
228+
// Find active receipt printer
229+
$receiptPrinter = \App\Domain\Printing\Models\Printer::where('is_active', true)
230+
->where('type', 'receipt')
231+
->first();
232+
233+
if (!$receiptPrinter) {
234+
\Filament\Notifications\Notification::make()
235+
->title('No receipt printer found')
236+
->body('Please configure an active receipt printer first.')
237+
->danger()
238+
->send();
239+
return;
240+
}
241+
242+
// Create print job
243+
$record->printJobs()->create([
244+
'printer_id' => $receiptPrinter->id,
245+
'type' => 'receipt',
246+
'file' => 'checkouts/'.$record->id.'.pdf',
247+
'status' => \App\Enum\PrintJobStatusEnum::Pending,
248+
]);
249+
250+
\Filament\Notifications\Notification::make()
251+
->title('Receipt added to print queue')
252+
->body("Receipt for checkout #{$record->id} has been queued for printing.")
253+
->success()
254+
->send();
255+
})
256+
->requiresConfirmation()
257+
->modalHeading('Print Receipt')
258+
->modalDescription('This will add the receipt to the print queue.'),
259+
])
260+
->bulkActions([
261+
// No bulk actions for checkouts
262+
]);
263+
}
264+
265+
public static function getRelations(): array
266+
{
267+
return [
268+
RelationManagers\ItemsRelationManager::class,
269+
];
270+
}
271+
272+
public static function getPages(): array
273+
{
274+
return [
275+
'index' => Pages\ListCheckouts::route('/'),
276+
'view' => Pages\ViewCheckout::route('/{record}'),
277+
];
278+
}
279+
280+
public static function canCreate(): bool
281+
{
282+
return false; // Checkouts are created through POS only
283+
}
284+
285+
public static function canEdit(Model $record): bool
286+
{
287+
return false; // Checkouts should not be edited
288+
}
289+
290+
public static function canDelete(Model $record): bool
291+
{
292+
return false; // Checkouts should not be deleted
293+
}
294+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace App\Filament\Resources\CheckoutResource\Pages;
4+
5+
use App\Filament\Resources\CheckoutResource;
6+
use Filament\Actions;
7+
use Filament\Resources\Pages\ListRecords;
8+
9+
class ListCheckouts extends ListRecords
10+
{
11+
protected static string $resource = CheckoutResource::class;
12+
13+
protected function getHeaderActions(): array
14+
{
15+
return [
16+
// No create action - checkouts are created through POS only
17+
];
18+
}
19+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace App\Filament\Resources\CheckoutResource\Pages;
4+
5+
use App\Domain\Checkout\Models\Checkout\Checkout;
6+
use App\Filament\Resources\CheckoutResource;
7+
use Filament\Actions;
8+
use Filament\Resources\Pages\ViewRecord;
9+
10+
class ViewCheckout extends ViewRecord
11+
{
12+
protected static string $resource = CheckoutResource::class;
13+
14+
protected function getHeaderActions(): array
15+
{
16+
return [
17+
Actions\Action::make('receipt')
18+
->label('Download Receipt')
19+
->icon('heroicon-o-arrow-down-tray')
20+
->color('gray')
21+
->url(fn (Checkout $record): string => route('pos.checkout.receipt', $record))
22+
->openUrlInNewTab(),
23+
24+
Actions\Action::make('print')
25+
->label('Print Receipt')
26+
->icon('heroicon-o-printer')
27+
->color('info')
28+
->action(function (Checkout $record) {
29+
// Generate receipt PDF
30+
\App\Jobs\CreateReceiptFromCheckoutJob::dispatchSync($record);
31+
32+
// Find active receipt printer
33+
$receiptPrinter = \App\Domain\Printing\Models\Printer::where('is_active', true)
34+
->where('type', 'receipt')
35+
->first();
36+
37+
if (!$receiptPrinter) {
38+
\Filament\Notifications\Notification::make()
39+
->title('No receipt printer found')
40+
->body('Please configure an active receipt printer first.')
41+
->danger()
42+
->send();
43+
return;
44+
}
45+
46+
// Create print job
47+
$record->printJobs()->create([
48+
'printer_id' => $receiptPrinter->id,
49+
'type' => 'receipt',
50+
'file' => 'checkouts/'.$record->id.'.pdf',
51+
'status' => \App\Enum\PrintJobStatusEnum::Pending,
52+
]);
53+
54+
\Filament\Notifications\Notification::make()
55+
->title('Receipt added to print queue')
56+
->body("Receipt for checkout #{$record->id} has been queued for printing.")
57+
->success()
58+
->send();
59+
})
60+
->requiresConfirmation()
61+
->modalHeading('Print Receipt')
62+
->modalDescription('This will add the receipt to the print queue.'),
63+
];
64+
}
65+
}

0 commit comments

Comments
 (0)