validate([ 'status' => ['nullable', 'in:pending_kyc,active,suspended'], 'q' => ['nullable', 'string', 'max:100'], 'per_page' => ['nullable', 'integer', 'min:1', 'max:500'], ]); $perPage = (int) $request->input('per_page', 25); $stores = PartnerStore::query() ->with(['owner', 'barangay', 'inventory']) ->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status'))) ->when($request->filled('q'), fn ($q) => $q->where('business_name', 'like', '%'.$request->string('q').'%')) ->orderBy('business_name') ->paginate($perPage); return $this->ok( PartnerStoreResource::collection($stores), null, [ 'page' => $stores->currentPage(), 'per_page' => $stores->perPage(), 'total' => $stores->total(), 'last_page' => $stores->lastPage(), ], ); } public function store(Request $request): JsonResponse { $data = $request->validate([ 'owner_user_id' => ['required', 'integer', 'exists:users,id'], 'business_name' => ['required', 'string', 'max:191'], 'business_permit_number' => ['nullable', 'string', 'max:64'], 'address_line' => ['nullable', 'string', 'max:255'], 'barangay_id' => ['nullable', 'integer', 'exists:barangays,id'], 'lat' => ['nullable', 'numeric', 'between:-90,90'], 'lng' => ['nullable', 'numeric', 'between:-180,180'], 'commission_rate_percent' => ['nullable', 'integer', 'min:0', 'max:50'], 'status' => ['nullable', Rule::in(['pending_kyc', 'active', 'suspended'])], ]); $payload = collect($data)->except(['lat', 'lng'])->all(); if (isset($data['lat'], $data['lng'])) { $payload['coordinates'] = new Point((float) $data['lat'], (float) $data['lng'], 4326); } $store = PartnerStore::create($payload); return $this->created( new PartnerStoreResource($store->load(['owner', 'barangay'])), 'Store created', ); } public function show(PartnerStore $store): JsonResponse { $store->load(['owner', 'barangay', 'inventory']); return $this->ok(new PartnerStoreResource($store)); } public function update(Request $request, PartnerStore $store): JsonResponse { $data = $request->validate([ 'business_name' => ['sometimes', 'required', 'string', 'max:191'], 'business_permit_number' => ['sometimes', 'nullable', 'string', 'max:64'], 'commission_rate_percent' => ['sometimes', 'integer', 'min:0', 'max:50'], 'status' => ['sometimes', Rule::in(['pending_kyc', 'active', 'suspended'])], 'address_line' => ['sometimes', 'nullable', 'string', 'max:255'], 'barangay_id' => ['sometimes', 'nullable', 'integer', 'exists:barangays,id'], 'lat' => ['sometimes', 'nullable', 'numeric', 'between:-90,90'], 'lng' => ['sometimes', 'nullable', 'numeric', 'between:-180,180'], ]); $payload = collect($data)->except(['lat', 'lng'])->all(); if (isset($data['lat'], $data['lng'])) { $payload['coordinates'] = new Point((float) $data['lat'], (float) $data['lng'], 4326); } $store->update($payload); return $this->ok(new PartnerStoreResource($store->fresh()->load(['owner', 'barangay', 'inventory'])), 'Store updated'); } public function issueInventory(Request $request, PartnerStore $store): JsonResponse { $data = $request->validate([ 'quantity' => ['required', 'integer', 'min:1', 'max:50000'], 'wholesale_price_centavos' => ['required', 'integer', 'min:0'], ]); if ($store->status !== PartnerStore::STATUS_ACTIVE) { return $this->fail('Store must be active to receive inventory', null, 422); } $purchase = $this->ops->issueWholesale( $store, (int) $data['quantity'], (int) $data['wholesale_price_centavos'], ); return $this->created([ 'purchase_id' => $purchase->id, 'batch_number' => $purchase->batch->batch_number, 'quantity' => $purchase->quantity, 'inventory_balance' => $store->fresh()->load('inventory')->inventory?->current_code_balance ?? 0, ], 'Inventory issued'); } public function recordSale(Request $request, PartnerStore $store): JsonResponse { $data = $request->validate([ 'household_id' => ['required', 'integer', 'exists:households,id'], 'quantity' => ['required', 'integer', 'min:1', 'max:1000'], 'retail_price_per_code_centavos' => ['required', 'integer', 'min:0'], ]); try { $household = Household::findOrFail($data['household_id']); $sale = $this->ops->sellToHousehold( $store, $household, (int) $data['quantity'], (int) $data['retail_price_per_code_centavos'], ); } catch (\DomainException $e) { return $this->fail($e->getMessage(), null, 422); } return $this->created([ 'sale_id' => $sale->id, 'quantity' => $sale->quantity, 'retail_price_centavos' => $sale->retail_price_centavos, 'commission_centavos' => $sale->commission_centavos, ], 'Sale recorded'); } }