diff --git a/src/backend/app/Http/Controllers/AgentAuthController.php b/src/backend/app/Http/Controllers/AgentAuthController.php index 1feda46dd..c9cb17aa1 100644 --- a/src/backend/app/Http/Controllers/AgentAuthController.php +++ b/src/backend/app/Http/Controllers/AgentAuthController.php @@ -81,6 +81,8 @@ public function me(): JsonResponse { $permissions = []; } + $agent = $this->agentService->getById($agent->id); + return response()->json([ /* @var Agent */ 'agent' => $agent, diff --git a/src/backend/app/Http/Controllers/AgentCustomerController.php b/src/backend/app/Http/Controllers/AgentCustomerController.php index 6b225d59e..f2cd9e306 100644 --- a/src/backend/app/Http/Controllers/AgentCustomerController.php +++ b/src/backend/app/Http/Controllers/AgentCustomerController.php @@ -2,8 +2,10 @@ namespace App\Http\Controllers; +use App\Http\Requests\AssignMeterToCustomerRequest; use App\Http\Requests\CreateAgentCustomerRequest; use App\Http\Resources\ApiResource; +use App\Models\Person\Person; use App\Services\AgentCustomerService; use App\Services\AgentService; use Illuminate\Http\JsonResponse; @@ -62,4 +64,24 @@ public function store(CreateAgentCustomerRequest $request): JsonResponse { throw $e; } } + + public function storeMeter(AssignMeterToCustomerRequest $request, int $customerId): JsonResponse { + $agent = $this->agentService->getByAuthenticatedUser(); + $customer = Person::query()->where('is_customer', 1)->findOrFail($customerId); + + try { + DB::connection('tenant')->beginTransaction(); + $meter = $this->agentCustomerService->assignMeter($agent, $customer, $request); + DB::connection('tenant')->commit(); + + return ApiResource::make($meter)->response()->setStatusCode(201); + } catch (ValidationException $e) { + DB::connection('tenant')->rollBack(); + throw $e; + } catch (\Exception $e) { + DB::connection('tenant')->rollBack(); + Log::critical('Error while an agent was assigning a meter to a customer', ['message' => $e->getMessage()]); + throw $e; + } + } } diff --git a/src/backend/app/Http/Requests/AssignMeterToCustomerRequest.php b/src/backend/app/Http/Requests/AssignMeterToCustomerRequest.php new file mode 100644 index 000000000..38c065aa3 --- /dev/null +++ b/src/backend/app/Http/Requests/AssignMeterToCustomerRequest.php @@ -0,0 +1,26 @@ + + */ + public function rules(): array { + return [ + 'serial_number' => ['required', 'string', 'unique:tenant.meters,serial_number'], + 'manufacturer_id' => ['required', 'integer', 'exists:tenant.manufacturers,id'], + 'meter_type_id' => ['required', 'integer', 'exists:tenant.meter_types,id'], + 'tariff_id' => ['required', 'integer', 'exists:tenant.tariffs,id'], + 'connection_group_id' => ['required', 'integer', 'exists:tenant.connection_groups,id'], + 'connection_type_id' => ['required', 'integer', 'exists:tenant.connection_types,id'], + 'geo_points' => ['nullable', 'string'], + ]; + } +} diff --git a/src/backend/app/Services/AgentCustomerService.php b/src/backend/app/Services/AgentCustomerService.php index cac91562b..90fc38f15 100644 --- a/src/backend/app/Services/AgentCustomerService.php +++ b/src/backend/app/Services/AgentCustomerService.php @@ -2,9 +2,12 @@ namespace App\Services; +use App\Events\AccessRatePaymentInitialize; +use App\Http\Requests\AssignMeterToCustomerRequest; use App\Http\Requests\CreateAgentCustomerRequest; use App\Models\Agent; use App\Models\City; +use App\Models\Meter\Meter; use App\Models\Person\Person; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; @@ -17,6 +20,9 @@ public function __construct( private PersonService $personService, private GeographicalInformationService $geographicalInformationService, private AddressGeographicalInformationService $addressGeographicalInformationService, + private MeterService $meterService, + private DeviceService $deviceService, + private MeterDeviceService $meterDeviceService, ) {} public function register(Agent $agent, CreateAgentCustomerRequest $request): Person { @@ -50,6 +56,45 @@ public function register(Agent $agent, CreateAgentCustomerRequest $request): Per return $person->fresh(['addresses.city', 'addresses.geo']); } + public function assignMeter(Agent $agent, Person $customer, AssignMeterToCustomerRequest $request): Meter { + $primaryAddress = $customer->addresses()->where('is_primary', 1)->with('city')->first(); + if ($primaryAddress === null || $primaryAddress->city === null || $primaryAddress->city->mini_grid_id !== $agent->mini_grid_id) { + throw ValidationException::withMessages(['customer' => ['Customer does not belong to the agent\'s mini-grid.']]); + } + + $meter = $this->meterService->create([ + 'serial_number' => $request->string('serial_number')->toString(), + 'manufacturer_id' => $request->integer('manufacturer_id'), + 'meter_type_id' => $request->integer('meter_type_id'), + 'tariff_id' => $request->integer('tariff_id'), + 'connection_group_id' => $request->integer('connection_group_id'), + 'connection_type_id' => $request->integer('connection_type_id'), + 'in_use' => 1, + ]); + + $device = $this->deviceService->make([ + 'person_id' => $customer->id, + 'device_serial' => $meter->serial_number, + ]); + $this->meterDeviceService->setAssigned($device); + $this->meterDeviceService->setAssignee($meter); + $this->meterDeviceService->assign(); + $this->deviceService->save($device); + + $geoPoints = $request->string('geo_points')->toString(); + if ($geoPoints !== '') { + $geographicalInformation = $this->geographicalInformationService->make(['points' => $geoPoints]); + $this->addressGeographicalInformationService->setAssigned($geographicalInformation); + $this->addressGeographicalInformationService->setAssignee($primaryAddress); + $this->addressGeographicalInformationService->assign(); + $this->geographicalInformationService->save($geographicalInformation); + } + + event(new AccessRatePaymentInitialize($meter)); + + return $meter->fresh(['tariff', 'device', 'meterType', 'connectionType', 'connectionGroup', 'manufacturer']); + } + /** * @return LengthAwarePaginator */ diff --git a/src/backend/app/Services/AgentTransactionService.php b/src/backend/app/Services/AgentTransactionService.php index 02f596538..fc7113fbd 100644 --- a/src/backend/app/Services/AgentTransactionService.php +++ b/src/backend/app/Services/AgentTransactionService.php @@ -38,7 +38,7 @@ public function getAll( static function ($q) use ($agentId) { $q->where('agent_id', $agentId); } - ); + )->latest()->orderByDesc('id'); return $limit ? $query->paginate($limit) : $query->get(); } @@ -63,6 +63,7 @@ public function getByCustomerId(int $agentId, ?int $customerId = null): Collecti ) ->whereHas('device', fn ($q) => $q->whereIn('device_serial', $customerDeviceSerials)) ->latest() + ->orderByDesc('id') ->paginate(); } diff --git a/src/backend/routes/resources/AgentApp.php b/src/backend/routes/resources/AgentApp.php index af3d684c0..43bf415e1 100644 --- a/src/backend/routes/resources/AgentApp.php +++ b/src/backend/routes/resources/AgentApp.php @@ -32,6 +32,8 @@ Route::group(['prefix' => 'customers'], function () { Route::get('/', [AgentCustomerController::class, 'index']); Route::post('/', [AgentCustomerController::class, 'store']); + Route::post('/{customerId}/meters', [AgentCustomerController::class, 'storeMeter']) + ->where('customerId', '[0-9]+'); Route::get('/search', [AgentCustomerController::class, 'search']); Route::get( '/{customerId}/graph/{period}/{limit?}/{order?}',