Skip to content

Commit 69c9542

Browse files
feat: add order manangment
1 parent 7ce6310 commit 69c9542

56 files changed

Lines changed: 3168 additions & 103 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Orders;
4+
5+
use App\Http\Concerns\ExtractsFilters;
6+
use App\Http\Controllers\Controller;
7+
use App\Http\Requests\Orders\StoreOrderRequest;
8+
use App\Http\Requests\Orders\UpdateOrderRequest;
9+
use App\Models\Order;
10+
use App\Services\AccessControlService;
11+
use App\Services\OrderService;
12+
use Illuminate\Http\JsonResponse;
13+
use Illuminate\Http\RedirectResponse;
14+
use Illuminate\Http\Request;
15+
use Inertia\Inertia;
16+
use Inertia\Response;
17+
18+
class OrderController extends Controller
19+
{
20+
use ExtractsFilters;
21+
22+
public function __construct(
23+
private OrderService $orderService,
24+
private AccessControlService $accessControl,
25+
) {}
26+
27+
public function index(Request $request): Response
28+
{
29+
$filters = $this->extractFilters($request, [
30+
'search',
31+
'outlet_id',
32+
'status',
33+
'order_type',
34+
'reservation_id',
35+
'customer_id',
36+
'date_from',
37+
'date_to',
38+
'per_page',
39+
]);
40+
41+
$scope = $this->accessControl->resolveSessionScope($request);
42+
43+
return Inertia::render('orders/index',
44+
$this->orderService->getIndexData($filters, $scope));
45+
}
46+
47+
public function create(Request $request): Response
48+
{
49+
$scope = $this->accessControl->resolveSessionScope($request);
50+
51+
return Inertia::render('orders/create',
52+
$this->orderService->getCreateData($scope));
53+
}
54+
55+
public function store(StoreOrderRequest $request): RedirectResponse
56+
{
57+
$order = $this->orderService->createOrder($request->validated());
58+
59+
return redirect($request->input('_redirect', route('orders.show', $order)))
60+
->with('success', 'Order created successfully.');
61+
}
62+
63+
public function show(Order $order): Response
64+
{
65+
return Inertia::render('orders/show',
66+
$this->orderService->getShowData($order));
67+
}
68+
69+
public function edit(Order $order): Response
70+
{
71+
return Inertia::render('orders/edit',
72+
$this->orderService->getEditData($order));
73+
}
74+
75+
public function destroy(Order $order): RedirectResponse
76+
{
77+
abort_if(
78+
in_array($order->status, ['confirmed', 'preparing', 'ready', 'served']),
79+
422,
80+
'Cannot delete an active order. Cancel it first.'
81+
);
82+
83+
$this->orderService->deleteOrder($order);
84+
85+
return redirect()->route('orders.index')
86+
->with('success', 'Order deleted.');
87+
}
88+
89+
public function availableTables(Request $request): JsonResponse
90+
{
91+
$request->validate([
92+
'outlet_id' => ['required', 'exists:outlets,id'],
93+
]);
94+
95+
$tables = $this->orderService->getAvailableDiningTables((int) $request->input('outlet_id'));
96+
97+
return response()->json(['tables' => $tables]);
98+
}
99+
100+
public function update(UpdateOrderRequest $request, Order $order): RedirectResponse
101+
{
102+
abort_if(
103+
in_array($order->status, ['completed', 'cancelled']),
104+
422,
105+
'Cannot update a completed or cancelled order.'
106+
);
107+
108+
$this->orderService->updateOrder($order, $request->validated());
109+
110+
return redirect($request->input('_redirect', route('orders.show', $order)))
111+
->with('success', 'Order updated successfully.');
112+
}
113+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Orders;
4+
5+
use App\Http\Controllers\Controller;
6+
use App\Http\Requests\Orders\CancelOrderItemRequest;
7+
use App\Http\Requests\Orders\StoreOrderItemRequest;
8+
use App\Http\Requests\Orders\UpdateOrderItemRequest;
9+
use App\Models\Order;
10+
use App\Models\OrderItem;
11+
use App\Services\OrderService;
12+
use Illuminate\Http\RedirectResponse;
13+
14+
class OrderItemController extends Controller
15+
{
16+
public function __construct(
17+
private OrderService $orderService,
18+
) {}
19+
20+
public function store(StoreOrderItemRequest $request, Order $order): RedirectResponse
21+
{
22+
abort_if(
23+
in_array($order->status, ['completed', 'cancelled']),
24+
422,
25+
'Cannot add items to a completed or cancelled order.'
26+
);
27+
28+
$this->orderService->addItem($order, $request->validated());
29+
30+
return back()->with('success', 'Item added to order.');
31+
}
32+
33+
public function update(UpdateOrderItemRequest $request, Order $order, OrderItem $orderItem): RedirectResponse
34+
{
35+
abort_if(
36+
in_array($order->status, ['completed', 'cancelled']),
37+
422,
38+
'Cannot update items on a completed or cancelled order.'
39+
);
40+
41+
abort_if(
42+
$orderItem->status === 'cancelled',
43+
422,
44+
'Cannot update a cancelled item.'
45+
);
46+
47+
abort_if(
48+
$orderItem->order_id !== $order->id,
49+
404,
50+
'Item does not belong to this order.'
51+
);
52+
53+
$this->orderService->updateItem($orderItem, $request->validated());
54+
55+
return back()->with('success', 'Item updated.');
56+
}
57+
58+
public function cancel(CancelOrderItemRequest $request, Order $order, OrderItem $orderItem): RedirectResponse
59+
{
60+
abort_if(
61+
$orderItem->status === 'cancelled',
62+
422,
63+
'Item is already cancelled.'
64+
);
65+
66+
abort_if(
67+
$orderItem->order_id !== $order->id,
68+
404,
69+
'Item does not belong to this order.'
70+
);
71+
72+
$this->orderService->cancelItem($orderItem, $request->input('cancel_reason'));
73+
74+
return back()->with('success', 'Item cancelled.');
75+
}
76+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Orders;
4+
5+
use App\Http\Controllers\Controller;
6+
use App\Http\Requests\Orders\UpdateOrderStatusRequest;
7+
use App\Models\Order;
8+
use App\Services\OrderService;
9+
use Illuminate\Http\RedirectResponse;
10+
11+
class OrderStatusController extends Controller
12+
{
13+
public function __construct(
14+
private OrderService $orderService,
15+
) {}
16+
17+
public function update(UpdateOrderStatusRequest $request, Order $order): RedirectResponse
18+
{
19+
$this->orderService->changeStatus(
20+
$order,
21+
$request->input('status'),
22+
$request->input('note')
23+
);
24+
25+
return back()->with('success', 'Order status updated.');
26+
}
27+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Orders;
4+
5+
use App\Http\Controllers\Controller;
6+
use App\Http\Requests\Orders\StoreOrderTableRequest;
7+
use App\Models\Order;
8+
use App\Models\OrderTable;
9+
use App\Services\OrderService;
10+
use Illuminate\Http\RedirectResponse;
11+
12+
class OrderTableController extends Controller
13+
{
14+
public function __construct(
15+
private OrderService $orderService,
16+
) {}
17+
18+
public function store(StoreOrderTableRequest $request, Order $order): RedirectResponse
19+
{
20+
abort_if(
21+
in_array($order->status, ['completed', 'cancelled']),
22+
422,
23+
'Cannot add tables to a completed or cancelled order.'
24+
);
25+
26+
$this->orderService->addTable(
27+
$order,
28+
(int) $request->input('dining_table_id'),
29+
$request->input('assignment_type')
30+
);
31+
32+
return back()->with('success', 'Table added to order.');
33+
}
34+
35+
public function destroy(Order $order, OrderTable $orderTable): RedirectResponse
36+
{
37+
abort_if(
38+
$orderTable->order_id !== $order->id,
39+
404,
40+
'Table does not belong to this order.'
41+
);
42+
43+
$this->orderService->removeTable($order, $orderTable);
44+
45+
return back()->with('success', 'Table removed from order.');
46+
}
47+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace App\Http\Requests\Orders;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
7+
class CancelOrderItemRequest extends FormRequest
8+
{
9+
public function authorize(): bool
10+
{
11+
return true;
12+
}
13+
14+
public function rules(): array
15+
{
16+
return [
17+
'cancel_reason' => ['required', 'string', 'max:500'],
18+
];
19+
}
20+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace App\Http\Requests\Orders;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
7+
class StoreOrderItemRequest extends FormRequest
8+
{
9+
public function authorize(): bool
10+
{
11+
return true;
12+
}
13+
14+
public function rules(): array
15+
{
16+
return [
17+
'food_id' => ['required', 'exists:foods,id'],
18+
'food_variant_id' => ['nullable', 'exists:food_variants,id'],
19+
'quantity' => ['required', 'numeric', 'min:0.01'],
20+
'note' => ['nullable', 'string'],
21+
'addons' => ['nullable', 'array'],
22+
'addons.*.addon_id' => ['required', 'exists:addons,id'],
23+
'addons.*.quantity' => ['nullable', 'numeric', 'min:0.01'],
24+
];
25+
}
26+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace App\Http\Requests\Orders;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
use Illuminate\Validation\Rule;
7+
8+
class StoreOrderRequest extends FormRequest
9+
{
10+
public function authorize(): bool
11+
{
12+
return true;
13+
}
14+
15+
public function rules(): array
16+
{
17+
$orderType = $this->input('order_type', 'dine_in');
18+
$isDineIn = $orderType === 'dine_in';
19+
20+
return [
21+
'outlet_id' => ['required_without:reservation_id', 'nullable', 'exists:outlets,id'],
22+
'reservation_id' => ['nullable', 'exists:reservations,id'],
23+
'customer_id' => ['nullable', 'exists:customers,id'],
24+
'order_type' => ['required', Rule::in(['dine_in', 'takeaway', 'delivery'])],
25+
'source' => ['required', Rule::in(['walk_in', 'phone', 'online', 'staff', 'other'])],
26+
'note' => ['nullable', 'string'],
27+
'dining_table_ids' => [$isDineIn ? 'required' : 'nullable', 'array'],
28+
'dining_table_ids.*' => ['integer', 'exists:dining_tables,id'],
29+
];
30+
}
31+
32+
public function messages(): array
33+
{
34+
return [
35+
'dining_table_ids.required' => 'Please select at least one dining table for a dine-in order.',
36+
];
37+
}
38+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace App\Http\Requests\Orders;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
use Illuminate\Validation\Rule;
7+
8+
class StoreOrderTableRequest extends FormRequest
9+
{
10+
public function authorize(): bool
11+
{
12+
return true;
13+
}
14+
15+
public function rules(): array
16+
{
17+
return [
18+
'dining_table_id' => ['required', 'exists:dining_tables,id'],
19+
'assignment_type' => ['required', Rule::in(['added_on_arrival', 'changed_by_staff'])],
20+
];
21+
}
22+
}

0 commit comments

Comments
 (0)