Skip to content

Commit de0bd75

Browse files
committed
feat(phase-9): add API controllers for 16 modules (batch 1)
Modules covered: Finance (bills/contacts), Accounting (journal entries/accounts), Purchase (vendors/RFQs/POs with confirm/receive actions), PM (projects/tasks), Subscriptions (plans/subscribe/renew/cancel), Repairs, Maintenance (orders/equipment/plans), Fleet (vehicles/assignments/fuel), Appointments (types/slots/bookings/cancel), Rental, QualityControl, Marketing (campaigns/lists/subscribers), Ecommerce, LiveChat, Lunch (suppliers/products/orders), Planning, Sign, SocialMarketing, KnowledgeBase. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a4c1ef4 commit de0bd75

27 files changed

Lines changed: 2391 additions & 0 deletions
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Api\V1;
4+
5+
use App\Modules\Appointments\Models\Appointment;
6+
use App\Modules\Appointments\Models\AppointmentSlot;
7+
use App\Modules\Appointments\Models\AppointmentType;
8+
use Illuminate\Http\JsonResponse;
9+
use Illuminate\Http\Request;
10+
11+
class AppointmentsApiController extends ApiController
12+
{
13+
/**
14+
* GET /api/v1/appointments/types
15+
*/
16+
public function types(Request $request): JsonResponse
17+
{
18+
$query = AppointmentType::query();
19+
20+
if ($request->boolean('active')) {
21+
$query->where('is_active', true);
22+
}
23+
24+
$paginator = $query->latest()->paginate(20);
25+
26+
return $this->paginated($paginator);
27+
}
28+
29+
/**
30+
* GET /api/v1/appointments/slots
31+
*/
32+
public function slots(Request $request): JsonResponse
33+
{
34+
$query = AppointmentSlot::with(['type:id,name']);
35+
36+
if ($typeId = $request->query('appointment_type_id')) {
37+
$query->where('appointment_type_id', $typeId);
38+
}
39+
40+
if ($date = $request->query('date')) {
41+
$query->whereDate('start_at', $date);
42+
}
43+
44+
$paginator = $query->orderBy('start_at')->paginate(20);
45+
46+
return $this->paginated($paginator);
47+
}
48+
49+
/**
50+
* GET /api/v1/appointments
51+
*/
52+
public function appointments(Request $request): JsonResponse
53+
{
54+
$query = Appointment::with(['type:id,name']);
55+
56+
if ($status = $request->query('status')) {
57+
$query->where('status', $status);
58+
}
59+
60+
$paginator = $query->latest()->paginate(20);
61+
62+
return $this->paginated($paginator);
63+
}
64+
65+
/**
66+
* GET /api/v1/appointments/{id}
67+
*/
68+
public function showAppointment(int $id): JsonResponse
69+
{
70+
$appointment = Appointment::with('type')->findOrFail($id);
71+
72+
return $this->success($appointment);
73+
}
74+
75+
/**
76+
* POST /api/v1/appointments
77+
*/
78+
public function storeAppointment(Request $request): JsonResponse
79+
{
80+
$validated = $request->validate([
81+
'appointment_slot_id' => 'required|integer',
82+
'appointment_type_id' => 'required|integer',
83+
'customer_name' => 'required|string|max:255',
84+
'customer_email' => 'nullable|email|max:255',
85+
'customer_phone' => 'nullable|string|max:50',
86+
'notes' => 'nullable|string',
87+
'status' => 'nullable|string|max:50',
88+
]);
89+
90+
$tenantId = app()->has('tenant') ? app('tenant')->id : $request->user()->tenant_id;
91+
92+
$appointment = Appointment::create(array_merge($validated, [
93+
'tenant_id' => $tenantId,
94+
'status' => $validated['status'] ?? 'pending',
95+
]));
96+
97+
return $this->success($appointment->load('type'), 201);
98+
}
99+
100+
/**
101+
* POST /api/v1/appointments/{id}/cancel
102+
*/
103+
public function cancelAppointment(int $id): JsonResponse
104+
{
105+
$appointment = Appointment::findOrFail($id);
106+
107+
$appointment->update([
108+
'status' => 'cancelled',
109+
'cancelled_at' => now(),
110+
]);
111+
112+
return $this->success($appointment->fresh());
113+
}
114+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Api\V1;
4+
5+
use App\Modules\Ecommerce\Models\StoreCategory;
6+
use App\Modules\Ecommerce\Models\StoreOrder;
7+
use App\Modules\Ecommerce\Models\StoreProduct;
8+
use Illuminate\Http\JsonResponse;
9+
use Illuminate\Http\Request;
10+
11+
class EcommerceApiController extends ApiController
12+
{
13+
public function storeProducts(Request $request): JsonResponse
14+
{
15+
$tenantId = app()->has('tenant') ? app('tenant')->id : $request->user()->tenant_id;
16+
17+
$query = StoreProduct::where('tenant_id', $tenantId);
18+
19+
if ($request->filled('category_id')) {
20+
$query->where('category_id', $request->category_id);
21+
}
22+
23+
if ($request->has('is_active')) {
24+
$query->where('is_visible', filter_var($request->is_active, FILTER_VALIDATE_BOOLEAN));
25+
}
26+
27+
return $this->paginated($query->latest()->paginate(15));
28+
}
29+
30+
public function showStoreProduct(int $id): JsonResponse
31+
{
32+
$product = StoreProduct::with('category')->findOrFail($id);
33+
34+
return $this->success($product);
35+
}
36+
37+
public function storeOrders(Request $request): JsonResponse
38+
{
39+
$tenantId = app()->has('tenant') ? app('tenant')->id : $request->user()->tenant_id;
40+
41+
$query = StoreOrder::where('tenant_id', $tenantId);
42+
43+
if ($request->filled('status')) {
44+
$query->where('status', $request->status);
45+
}
46+
47+
return $this->paginated($query->latest()->paginate(15));
48+
}
49+
50+
public function showStoreOrder(int $id): JsonResponse
51+
{
52+
$order = StoreOrder::with('items')->findOrFail($id);
53+
54+
return $this->success($order);
55+
}
56+
57+
public function categories(Request $request): JsonResponse
58+
{
59+
$tenantId = app()->has('tenant') ? app('tenant')->id : $request->user()->tenant_id;
60+
61+
$categories = StoreCategory::where('tenant_id', $tenantId)
62+
->orderBy('sort_order')
63+
->get();
64+
65+
return $this->success($categories);
66+
}
67+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Api\V1;
4+
5+
use App\Modules\FieldService\Models\ServiceOrder;
6+
use Illuminate\Http\JsonResponse;
7+
use Illuminate\Http\Request;
8+
9+
class FieldServiceApiController extends ApiController
10+
{
11+
public function tasks(Request $request): JsonResponse
12+
{
13+
$tenantId = app()->has('tenant') ? app('tenant')->id : $request->user()->tenant_id;
14+
15+
$query = ServiceOrder::where('tenant_id', $tenantId);
16+
17+
if ($request->filled('status')) {
18+
$query->where('status', $request->status);
19+
}
20+
21+
return $this->paginated($query->latest()->paginate(15));
22+
}
23+
24+
public function showTask(int $id): JsonResponse
25+
{
26+
$task = ServiceOrder::with(['technician', 'creator', 'items'])->findOrFail($id);
27+
28+
return $this->success($task);
29+
}
30+
31+
public function storeTask(Request $request): JsonResponse
32+
{
33+
$tenantId = app()->has('tenant') ? app('tenant')->id : $request->user()->tenant_id;
34+
35+
$validated = $request->validate([
36+
'title' => 'required|string|max:255',
37+
'description' => 'nullable|string',
38+
'type' => 'nullable|string|max:100',
39+
'priority' => 'nullable|string|max:50',
40+
'status' => 'nullable|string|max:50',
41+
'customer_name' => 'nullable|string|max:255',
42+
'customer_email' => 'nullable|email|max:255',
43+
'customer_phone' => 'nullable|string|max:50',
44+
'address' => 'nullable|string',
45+
'scheduled_at' => 'nullable|date',
46+
'estimated_duration' => 'nullable|integer',
47+
'assigned_to' => 'nullable|integer|exists:users,id',
48+
'notes' => 'nullable|string',
49+
]);
50+
51+
$validated['tenant_id'] = $tenantId;
52+
$validated['created_by'] = $request->user()->id;
53+
54+
$task = ServiceOrder::create($validated);
55+
56+
return $this->success($task, 201);
57+
}
58+
59+
public function updateTask(Request $request, int $id): JsonResponse
60+
{
61+
$task = ServiceOrder::findOrFail($id);
62+
63+
$validated = $request->validate([
64+
'title' => 'sometimes|required|string|max:255',
65+
'description' => 'nullable|string',
66+
'type' => 'nullable|string|max:100',
67+
'priority' => 'nullable|string|max:50',
68+
'status' => 'nullable|string|max:50',
69+
'customer_name' => 'nullable|string|max:255',
70+
'customer_email' => 'nullable|email|max:255',
71+
'customer_phone' => 'nullable|string|max:50',
72+
'address' => 'nullable|string',
73+
'scheduled_at' => 'nullable|date',
74+
'started_at' => 'nullable|date',
75+
'completed_at' => 'nullable|date',
76+
'estimated_duration' => 'nullable|integer',
77+
'actual_duration' => 'nullable|integer',
78+
'assigned_to' => 'nullable|integer|exists:users,id',
79+
'notes' => 'nullable|string',
80+
]);
81+
82+
$task->update($validated);
83+
84+
return $this->success($task->fresh(['technician', 'creator', 'items']));
85+
}
86+
}

0 commit comments

Comments
 (0)