add inventory and supply logic

This commit is contained in:
root
2026-03-10 18:21:08 -04:00
parent 17d73e2f92
commit 25e7b3c67c
62 changed files with 3846 additions and 2781 deletions
@@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers\Api\Inventory;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Inventory\InventoryCategoryIndexRequest;
use App\Http\Requests\Inventory\InventoryCategoryStoreRequest;
use App\Http\Requests\Inventory\InventoryCategoryUpdateRequest;
use App\Http\Resources\Inventory\InventoryCategoryResource;
use App\Services\Inventory\InventoryCategoryService;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
class InventoryCategoryController extends BaseApiController
{
public function __construct(private InventoryCategoryService $categories)
{
parent::__construct();
}
public function index(InventoryCategoryIndexRequest $request): JsonResponse
{
$payload = $request->validated();
$rows = $this->categories->list($payload['type'] ?? null);
return $this->success([
'categories' => InventoryCategoryResource::collection($rows),
]);
}
public function store(InventoryCategoryStoreRequest $request): JsonResponse
{
$result = $this->categories->create($request->validated());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to save category.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondCreated(new InventoryCategoryResource($result['category']));
}
public function update(InventoryCategoryUpdateRequest $request, int $id): JsonResponse
{
try {
$result = $this->categories->update($id, $request->validated());
} catch (\InvalidArgumentException $e) {
return $this->error($e->getMessage(), Response::HTTP_UNPROCESSABLE_ENTITY);
}
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to update category.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success(new InventoryCategoryResource($result['category']));
}
public function destroy(int $id): JsonResponse
{
$result = $this->categories->delete($id);
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to delete category.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondDeleted();
}
}
@@ -0,0 +1,154 @@
<?php
namespace App\Http\Controllers\Api\Inventory;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Inventory\InventoryAdjustRequest;
use App\Http\Requests\Inventory\InventoryAuditRequest;
use App\Http\Requests\Inventory\InventoryItemIndexRequest;
use App\Http\Requests\Inventory\InventoryItemStoreRequest;
use App\Http\Requests\Inventory\InventoryItemUpdateRequest;
use App\Http\Requests\Inventory\InventoryTeacherDistributionRequest;
use App\Http\Requests\Inventory\InventoryTeacherDistributionStoreRequest;
use App\Http\Resources\Inventory\InventoryItemResource;
use App\Services\Inventory\InventoryItemService;
use App\Services\Inventory\InventorySummaryService;
use App\Services\Inventory\InventoryTeacherDistributionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
class InventoryController extends BaseApiController
{
public function __construct(
private InventoryItemService $items,
private InventorySummaryService $summary,
private InventoryTeacherDistributionService $distribution
) {
parent::__construct();
}
public function index(InventoryItemIndexRequest $request): JsonResponse
{
$result = $this->items->list($request->validated());
return $this->success([
'type' => $result['type'],
'items' => InventoryItemResource::collection($result['items']),
'categories' => $result['categories'],
'conditionOptions' => $result['conditionOptions'],
'schoolYears' => $result['schoolYears'],
'selectedYear' => $result['selectedYear'],
'currentYear' => $result['currentYear'],
'semester' => $result['semester'],
'userNames' => $result['userNames'],
]);
}
public function show(int $id): JsonResponse
{
$item = $this->items->find($id);
if (!$item) {
return $this->error('Item not found.', Response::HTTP_NOT_FOUND);
}
return $this->success(new InventoryItemResource($item));
}
public function store(InventoryItemStoreRequest $request): JsonResponse
{
$result = $this->items->create($request->validated(), (int) auth()->id());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to create item.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondCreated(new InventoryItemResource($result['item']));
}
public function update(InventoryItemUpdateRequest $request, int $id): JsonResponse
{
$result = $this->items->update($id, $request->validated(), (int) auth()->id());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to update item.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success(new InventoryItemResource($result['item']));
}
public function destroy(int $id): JsonResponse
{
$result = $this->items->delete($id);
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to delete item.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondDeleted();
}
public function audit(InventoryAuditRequest $request, int $id): JsonResponse
{
$result = $this->items->auditClassroom($id, $request->validated(), (int) auth()->id());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to audit item.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success(new InventoryItemResource($result['item']));
}
public function adjust(InventoryAdjustRequest $request, int $id): JsonResponse
{
$result = $this->items->adjustStock($id, $request->validated(), (int) auth()->id());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to adjust stock.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success();
}
public function summary(string $type): JsonResponse
{
$payload = $this->summary->summary($type, request()->query('school_year'));
return $this->success($payload);
}
public function summaryAll(): JsonResponse
{
$payload = $this->summary->summaryAll(
request()->query('school_year'),
request()->query('type')
);
return $this->success($payload);
}
public function teacherDistribution(InventoryTeacherDistributionRequest $request): JsonResponse
{
$payload = $request->validated();
$result = $this->distribution->formData(
(int) auth()->id(),
$payload['class_section_id'] ?? null,
$payload['item_id'] ?? null
);
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Unable to load distribution form.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success($result);
}
public function teacherDistributionStore(InventoryTeacherDistributionStoreRequest $request): JsonResponse
{
try {
$result = $this->distribution->distribute((int) auth()->id(), $request->validated());
} catch (\Throwable $e) {
Log::error('Inventory distribution failed: ' . $e->getMessage());
return $this->error('Unable to distribute inventory.', Response::HTTP_INTERNAL_SERVER_ERROR);
}
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Unable to distribute inventory.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success($result);
}
}
@@ -0,0 +1,70 @@
<?php
namespace App\Http\Controllers\Api\Inventory;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Inventory\InventoryMovementBulkDeleteRequest;
use App\Http\Requests\Inventory\InventoryMovementIndexRequest;
use App\Http\Requests\Inventory\InventoryMovementStoreRequest;
use App\Http\Requests\Inventory\InventoryMovementUpdateRequest;
use App\Http\Resources\Inventory\InventoryMovementResource;
use App\Services\Inventory\InventoryMovementService;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
class InventoryMovementController extends BaseApiController
{
public function __construct(private InventoryMovementService $movements)
{
parent::__construct();
}
public function index(InventoryMovementIndexRequest $request): JsonResponse
{
$rows = $this->movements->list($request->validated());
return $this->success([
'movements' => InventoryMovementResource::collection($rows),
]);
}
public function store(InventoryMovementStoreRequest $request): JsonResponse
{
$result = $this->movements->create($request->validated(), (int) auth()->id());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to create movement.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondCreated();
}
public function update(InventoryMovementUpdateRequest $request, int $id): JsonResponse
{
$result = $this->movements->update($id, $request->validated());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to update movement.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success();
}
public function destroy(int $id): JsonResponse
{
$result = $this->movements->delete($id);
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to delete movement.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondDeleted();
}
public function bulkDelete(InventoryMovementBulkDeleteRequest $request): JsonResponse
{
$result = $this->movements->bulkDelete($request->validated()['ids']);
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Bulk delete failed.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success($result);
}
}
@@ -0,0 +1,62 @@
<?php
namespace App\Http\Controllers\Api\Inventory;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Inventory\SupplierIndexRequest;
use App\Http\Requests\Inventory\SupplierStoreRequest;
use App\Http\Requests\Inventory\SupplierUpdateRequest;
use App\Http\Resources\Inventory\SupplierResource;
use App\Services\Inventory\SupplierService;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
class SupplierController extends BaseApiController
{
public function __construct(private SupplierService $suppliers)
{
parent::__construct();
}
public function index(SupplierIndexRequest $request): JsonResponse
{
$payload = $request->validated();
$perPage = (int) ($payload['per_page'] ?? 20);
$result = $this->suppliers->list($payload, $perPage);
return $this->success([
'suppliers' => SupplierResource::collection($result['items']),
'pagination' => $result['pagination'],
]);
}
public function store(SupplierStoreRequest $request): JsonResponse
{
$result = $this->suppliers->create($request->validated());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to save supplier.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondCreated(new SupplierResource($result['supplier']));
}
public function update(SupplierUpdateRequest $request, int $id): JsonResponse
{
$result = $this->suppliers->update($id, $request->validated());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to update supplier.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success(new SupplierResource($result['supplier']));
}
public function destroy(int $id): JsonResponse
{
$result = $this->suppliers->delete($id);
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to delete supplier.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondDeleted();
}
}
@@ -0,0 +1,58 @@
<?php
namespace App\Http\Controllers\Api\Inventory;
use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Inventory\SupplyCategoryStoreRequest;
use App\Http\Requests\Inventory\SupplyCategoryUpdateRequest;
use App\Http\Resources\Inventory\SupplyCategoryResource;
use App\Services\Inventory\SupplyCategoryService;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
class SupplyCategoryController extends BaseApiController
{
public function __construct(private SupplyCategoryService $categories)
{
parent::__construct();
}
public function index(): JsonResponse
{
$rows = $this->categories->list();
return $this->success([
'categories' => SupplyCategoryResource::collection($rows),
]);
}
public function store(SupplyCategoryStoreRequest $request): JsonResponse
{
$result = $this->categories->create($request->validated());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to save category.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondCreated(new SupplyCategoryResource($result['category']));
}
public function update(SupplyCategoryUpdateRequest $request, int $id): JsonResponse
{
$result = $this->categories->update($id, $request->validated());
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to update category.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success(new SupplyCategoryResource($result['category']));
}
public function destroy(int $id): JsonResponse
{
$result = $this->categories->delete($id);
if (!($result['ok'] ?? false)) {
return $this->error($result['message'] ?? 'Failed to delete category.', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondDeleted();
}
}