File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -81,3 +81,5 @@ PAYMONGO_SUCCESS_URL="${APP_URL}/checkout/success"
8181PAYMONGO_FAILED_URL = " ${ APP_URL } /checkout/failed"
8282
8383GEMINI_API_KEY =
84+
85+ RFID_API_SECRET =
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ namespace App \Http \Controllers \Api ;
4+
5+ use App \Http \Controllers \Controller ;
6+ use App \Http \Requests \Rfid \RfidScanRequest ;
7+ use App \Services \ItemService ;
8+ use Illuminate \Http \JsonResponse ;
9+ use Illuminate \Http \Request ;
10+
11+ class RfidController extends Controller
12+ {
13+ /**
14+ * Inject Item Service
15+ *
16+ * @param ItemService $itemService
17+ */
18+ public function __construct (
19+ protected ItemService $ itemService
20+ ) {}
21+
22+ /**
23+ * Handle RFID scan and adjust item quantity.
24+ */
25+ public function scan (RfidScanRequest $ request ): JsonResponse
26+ {
27+ $ result = $ this ->itemService ->adjustQuantityByCode (
28+ $ request ->validated ()['item_code ' ],
29+ $ request ->validated ()['action ' ],
30+ $ request ->validated ()['quantity ' ]
31+ );
32+
33+ if (! $ result ['success ' ]) {
34+ return response ()->json ([
35+ 'status ' => 'error ' ,
36+ 'message ' => $ result ['message ' ]
37+ ], 422 );
38+ }
39+
40+ return response ()->json ([
41+ 'status ' => 'success ' ,
42+ 'message ' => $ result ['message ' ],
43+ 'data ' => $ result ['item ' ],
44+ ], 200 );
45+ }
46+ }
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ namespace App \Http \Middleware ;
4+
5+ use Closure ;
6+ use Illuminate \Http \Request ;
7+ use Symfony \Component \HttpFoundation \Response ;
8+
9+ class ApiSecretMiddleware
10+ {
11+ /**
12+ * Handle an incoming request.
13+ *
14+ * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
15+ */
16+ public function handle (Request $ request , Closure $ next ): Response
17+ {
18+ $ secret = config ('app.rfid_api_secret ' );
19+
20+ if (! $ secret || $ request ->header ('X-API-Secret ' ) !== $ secret ) {
21+ return response ()->json ([
22+ 'status ' => 'error ' ,
23+ 'message ' => 'Unauthorized '
24+ ], 401 );
25+ }
26+
27+ return $ next ($ request );
28+ }
29+ }
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ namespace App \Http \Requests \Rfid ;
4+
5+ use Illuminate \Foundation \Http \FormRequest ;
6+
7+ class RfidScanRequest extends FormRequest
8+ {
9+ /**
10+ * Determine if the user is authorized to make this request.
11+ */
12+ public function authorize (): bool
13+ {
14+ return true ; // Middleware handles authorization
15+ }
16+
17+ /**
18+ * Get the validation rules that apply to the request.
19+ *
20+ * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
21+ */
22+ public function rules (): array
23+ {
24+ return [
25+ 'item_code ' => 'required|string ' ,
26+ 'action ' => 'required|string|in:add,deduct ' ,
27+ 'quantity ' => 'required|integer|min:1 '
28+ ];
29+ }
30+ }
Original file line number Diff line number Diff line change @@ -9,4 +9,5 @@ interface ItemRepositoryInterface extends BaseRepositoryInterface
99{
1010 public function latestByCategory (string $ category ): ?Item ;
1111 public function getLowStockItems (): Collection ;
12+ public function findByCode (string $ itemCode ): ?Item ;
1213}
Original file line number Diff line number Diff line change @@ -42,4 +42,17 @@ public function getLowStockItems(): Collection
4242 ->orderBy ('quantity ' , 'asc ' )
4343 ->get ();
4444 }
45+
46+ /**
47+ * Find an item by its item_code
48+ *
49+ * @param string $itemCode
50+ * @return Item|null
51+ */
52+ public function findByCode (string $ itemCode ): ?Item
53+ {
54+ return $ this ->query ()
55+ ->where ('item_code ' , $ itemCode )
56+ ->first ();
57+ }
4558}
Original file line number Diff line number Diff line change @@ -220,4 +220,44 @@ protected function deleteImages(Item $item)
220220 }
221221 }
222222 }
223+
224+ /**
225+ * Adjust item quantity via RFID scan.
226+ * Use action 'add' to increase and 'deduct' to decrease.
227+ *
228+ * @param string $itemCode
229+ * @param string $action 'add' | 'deduct'
230+ * @param int $quantity
231+ * @return array{success: bool, message: string, item?: Item}
232+ */
233+ public function adjustQuantityByCode (string $ itemCode , string $ action , int $ quantity ): array
234+ {
235+ $ item = $ this ->itemRepo ->findByCode ($ itemCode );
236+
237+ if (! $ item ) {
238+ return ['success ' => false , 'message ' => 'Item not found ' ];
239+ }
240+
241+ if ($ action === 'deduct ' ) {
242+ if ($ item ->quantity < $ quantity ) {
243+ return ['success ' => false , 'message ' => 'Insufficient stock ' ];
244+ }
245+ $ newQuantity = $ item ->quantity - $ quantity ;
246+ } elseif ($ action === 'add ' ) {
247+ $ newQuantity = $ item ->quantity + $ quantity ;
248+ } else {
249+ return ['success ' => false , 'message ' => 'Invalid action. Use "add" or "deduct" ' ];
250+ }
251+
252+ $ this ->itemRepo ->update ($ item ->id , ['quantity ' => $ newQuantity ]);
253+
254+ // Re-fetch for fresh data
255+ $ item ->refresh ();
256+
257+ return [
258+ 'success ' => true ,
259+ 'message ' => 'Quantity updated successfully ' ,
260+ 'item ' => $ item
261+ ];
262+ }
223263}
Original file line number Diff line number Diff line change 11<?php
22
3+ use App \Http \Middleware \ApiSecretMiddleware ;
34use App \Http \Middleware \HandleAppearance ;
45use App \Http \Middleware \HandleInertiaRequests ;
56use App \Http \Middleware \RoleMiddleware ;
1112return Application::configure (basePath: dirname (__DIR__ ))
1213 ->withRouting (
1314 web: __DIR__ .'/../routes/web.php ' ,
15+ api: __DIR__ .'/../routes/api.php ' ,
1416 commands: __DIR__ .'/../routes/console.php ' ,
1517 channels: __DIR__ .'/../routes/channels.php ' ,
1618 health: '/up ' ,
2628
2729 $ middleware ->alias ([
2830 'role ' => RoleMiddleware::class,
31+ 'api.secret ' => ApiSecretMiddleware::class
2932 ]);
3033 })
3134 ->withExceptions (function (Exceptions $ exceptions ): void {
Original file line number Diff line number Diff line change 123123 'store ' => env ('APP_MAINTENANCE_STORE ' , 'database ' ),
124124 ],
125125
126+ /*
127+ |--------------------------------------------------------------------------
128+ | RFID API Secret
129+ |--------------------------------------------------------------------------
130+ |
131+ | This secret key is used to authenticate requests from the Python RFID
132+ | scanner. It must match the X-API-Secret header sent by the scanner.
133+ |
134+ */
135+ 'rfid_api_secret ' => env ('RFID_API_SECRET ' ),
126136];
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ use Illuminate \Support \Facades \Route ;
4+
5+ Route::get ('/health ' , function () {
6+ return response ()->json ([
7+ 'status ' => 'ok ' ,
8+ 'message ' => 'API is running ' ,
9+ ]);
10+ });
11+
12+ require __DIR__ . '/groups/rfid.php ' ;
You can’t perform that action at this time.
0 commit comments