diff --git a/collections/Create Agent.bru b/collections/Create Agent.bru index a146b4766..e00c41fd8 100644 --- a/collections/Create Agent.bru +++ b/collections/Create Agent.bru @@ -16,7 +16,7 @@ body:json { "surname": "Test Agent (Created via API)", "is_customer": 0, "nationality": null, - "city_id": 3, + "village_id": 3, "email": "demo_agent_api_created@example.com", "phone": "+254 123 456789", "is_primary": 1, diff --git a/collections/Create Customer (incomplete information).bru b/collections/Create Customer (incomplete information).bru index 0aaca3ff8..db9a48633 100644 --- a/collections/Create Customer (incomplete information).bru +++ b/collections/Create Customer (incomplete information).bru @@ -17,7 +17,7 @@ body:json { "surname": null, "phone": null, "street": null, - "city_id": null, + "village_id": null, "is_primary": null, "country_code": null, "title": null, diff --git a/collections/Create Customer.bru b/collections/Create Customer.bru index a2fddefa0..f9631b909 100644 --- a/collections/Create Customer.bru +++ b/collections/Create Customer.bru @@ -17,7 +17,7 @@ body:json { "surname": "surname", "phone": "+254123456789", "street": "Some street, somewhere", - "city_id": 1, + "village_id": 1, "is_primary": true, "title": "Mr", "education": "Well educated", diff --git a/docs/usage-guide/customers.md b/docs/usage-guide/customers.md index f73f70359..e0c526f19 100644 --- a/docs/usage-guide/customers.md +++ b/docs/usage-guide/customers.md @@ -5,7 +5,7 @@ order: 8 # Customers MicroPowerManager customers are listed under `Customers` in the sidebar. -This table contains the customers' name, phone number, city, and device number. +This table contains the customers' name, phone number, village, and device number. The search function also includes all those fields. By clicking on a customer, the customer’s profile page will be loaded Data parameters included are: diff --git a/src/backend/app/Console/Commands/ReportGenerator.php b/src/backend/app/Console/Commands/ReportGenerator.php index b307d0692..c5148dcd7 100644 --- a/src/backend/app/Console/Commands/ReportGenerator.php +++ b/src/backend/app/Console/Commands/ReportGenerator.php @@ -6,8 +6,8 @@ use Carbon\Carbon; class ReportGenerator extends AbstractSharedCommand { - protected $signature = 'reports:city-revenue {type} {--start-date=} {--company-id=}'; - protected $description = 'Creates city revenue reports'; + protected $signature = 'reports:village-revenue {type} {--start-date=} {--company-id=}'; + protected $description = 'Creates village revenue reports'; public function __construct(private Reports $reports) { parent::__construct(); diff --git a/src/backend/app/DTO/ClusterDashboardData.php b/src/backend/app/DTO/ClusterDashboardData.php index c86bb3fc8..ce939d02a 100644 --- a/src/backend/app/DTO/ClusterDashboardData.php +++ b/src/backend/app/DTO/ClusterDashboardData.php @@ -17,7 +17,7 @@ public function __construct( public float $revenue = 0.0, public int $population = 0, /** @var array */ - public array $citiesRevenue = [], + public array $villagesRevenue = [], /** @var array */ public array $revenueAnalysis = [], /** @var array */ @@ -43,7 +43,7 @@ public function toArray(): array { 'meterCount' => $this->meterCount, 'revenue' => $this->revenue, 'population' => $this->population, - 'citiesRevenue' => $this->citiesRevenue, + 'villagesRevenue' => $this->villagesRevenue, 'revenueAnalysis' => $this->revenueAnalysis, 'clusterData' => $this->cluster, 'period' => $this->period, diff --git a/src/backend/app/Http/Controllers/AgentWebController.php b/src/backend/app/Http/Controllers/AgentWebController.php index 355e0d0c3..8186898a5 100644 --- a/src/backend/app/Http/Controllers/AgentWebController.php +++ b/src/backend/app/Http/Controllers/AgentWebController.php @@ -42,7 +42,7 @@ public function store(CreateAgentRequest $request): ApiResource { $agentData = [ 'password' => $request['password'], 'email' => $request['email'], - 'mini_grid_id' => $request['city_id'], + 'mini_grid_id' => $request['village_id'], 'agent_commission_id' => $request['agent_commission_id'], 'mobile_device_id' => '-', 'fire_base_token' => '-', diff --git a/src/backend/app/Http/Controllers/AppliancePersonController.php b/src/backend/app/Http/Controllers/AppliancePersonController.php index 97a537d8c..38b156ad9 100644 --- a/src/backend/app/Http/Controllers/AppliancePersonController.php +++ b/src/backend/app/Http/Controllers/AppliancePersonController.php @@ -84,7 +84,7 @@ public function store( $address = $this->addressesService->make([ 'street' => $addressData['street'], - 'city_id' => $addressData['city_id'], + 'village_id' => $addressData['village_id'], ]); // Attach the new address to the person rather than the device. diff --git a/src/backend/app/Http/Controllers/CityController.php b/src/backend/app/Http/Controllers/CityController.php deleted file mode 100644 index a58c24d90..000000000 --- a/src/backend/app/Http/Controllers/CityController.php +++ /dev/null @@ -1,53 +0,0 @@ -get('limit'); - - return ApiResource::make($this->cityService->getAll($limit)); - } - - public function show(int $cityId, Request $request): ApiResource { - $relation = $request->get('relation'); - - if ($relation) { - return ApiResource::make($this->cityService->getByIdWithRelation($cityId, ['location', 'country'])); - } - - return ApiResource::make($this->cityService->getById($cityId)); - } - - public function update(int $cityId, CityRequest $request): ApiResource { - $city = $this->cityService->getById($cityId); - $cityData = $request->only(['name', 'mini_grid_id', 'country_id']); - - return ApiResource::make($this->cityService->update($city, $cityData)); - } - - public function store(CityRequest $request): ApiResource { - $data = $request->validationData(); - $city = $this->cityService->create($data); - $geographicalInformation = $this->geographicalInformationService->make($data); - $this->cityGeographicalInformationService->setAssigned($geographicalInformation); - $this->cityGeographicalInformationService->setAssignee($city); - $this->cityGeographicalInformationService->assign(); - $this->geographicalInformationService->save($geographicalInformation); - - return ApiResource::make($city); - } -} diff --git a/src/backend/app/Http/Controllers/ClusterExportController.php b/src/backend/app/Http/Controllers/ClusterExportController.php index d73cf4290..57199a807 100644 --- a/src/backend/app/Http/Controllers/ClusterExportController.php +++ b/src/backend/app/Http/Controllers/ClusterExportController.php @@ -45,7 +45,7 @@ public function downloadCsv(Request $request): StreamedResponse { $this->clusterExportService->setClusterData($clusters); $this->clusterExportService->setExportingData(); - $headers = ['Cluster Name', 'Manager', 'Mini Grids Count', 'Cities Count', 'Created At', 'Updated At']; + $headers = ['Cluster Name', 'Manager', 'Mini Grids Count', 'Villages Count', 'Created At', 'Updated At']; $csvPath = $this->clusterExportService->saveCsv($headers); return Storage::download($csvPath, 'cluster_export_'.now()->format('Ymd_His').'.csv'); diff --git a/src/backend/app/Http/Controllers/MaintenanceUserController.php b/src/backend/app/Http/Controllers/MaintenanceUserController.php index a1c8dcbb4..20b09321e 100644 --- a/src/backend/app/Http/Controllers/MaintenanceUserController.php +++ b/src/backend/app/Http/Controllers/MaintenanceUserController.php @@ -42,7 +42,7 @@ static function ($q) use ($phone) { } else { $person = $this->personService->createMaintenancePerson($personData); } - $this->addressService->createForPerson($person->getId(), $request->getCityId(), $request->getPhone(), $request->getEmail(), $request->getStreet(), true); + $this->addressService->createForPerson($person->getId(), $request->getVillageId(), $request->getPhone(), $request->getEmail(), $request->getStreet(), true); } // Ensure the person is marked as maintenance type diff --git a/src/backend/app/Http/Controllers/MeterGeographicalInformationController.php b/src/backend/app/Http/Controllers/MeterGeographicalInformationController.php index 9d2b6144e..c981744dd 100644 --- a/src/backend/app/Http/Controllers/MeterGeographicalInformationController.php +++ b/src/backend/app/Http/Controllers/MeterGeographicalInformationController.php @@ -4,7 +4,7 @@ use App\Http\Resources\ApiResource; use App\Models\Meter\Meter; -use App\Services\CityService; +use App\Services\VillageService; use App\Services\MeterGeographicalInformationService; use App\Services\MeterService; use App\Services\PersonMeterService; @@ -14,7 +14,7 @@ class MeterGeographicalInformationController extends Controller { public function __construct( private MeterGeographicalInformationService $meterGeographicalInformationService, private PersonMeterService $personMeterService, - private CityService $cityService, + private VillageService $villageService, private MeterService $meterService, ) {} @@ -28,12 +28,12 @@ public function __construct( * @responseFile responses/meters/meters.geo.list.json */ public function index(?int $miniGridId = null): ApiResource { - $cityIds = $miniGridId ? $this->cityService->getCityIdsByMiniGridId($miniGridId) : []; - // we can get city id only by address + $villageIds = $miniGridId ? $this->villageService->getVillageIdsByMiniGridId($miniGridId) : []; + // we can get village id only by address if ($miniGridId === null) { $meters = $this->meterService->getUsedMetersGeoWithAccessRatePayments(); } else { - $meters = $this->meterService->getUsedMetersGeoWithAccessRatePaymentsInCities($cityIds); + $meters = $this->meterService->getUsedMetersGeoWithAccessRatePaymentsInVillages($villageIds); } return ApiResource::make($meters); diff --git a/src/backend/app/Http/Controllers/PersonController.php b/src/backend/app/Http/Controllers/PersonController.php index 97bc3a643..c999b69dc 100644 --- a/src/backend/app/Http/Controllers/PersonController.php +++ b/src/backend/app/Http/Controllers/PersonController.php @@ -34,7 +34,7 @@ public function __construct( * @urlParam agent_id int optional. To get a list of customers of a specific agent. * @urlParam limit int optional. The number of items per page. * @urlParam active_customer int optional. To get a list of active customers. Default: 0 - * @urlParam city_id int optional. Filter by primary address city/village id. + * @urlParam village_id int optional. Filter by primary address village id. * @urlParam total_paid_min float optional. Minimum total paid amount for the customer. * @urlParam total_paid_max float optional. Maximum total paid amount for the customer. * @urlParam latest_payment_from string optional. ISO date string for minimum latest payment date. @@ -50,7 +50,7 @@ public function index(Request $request): ApiResource { $perPage = $request->input('per_page', config('settings.paginate', 15)); $agentId = $request->input('agent_id'); $activeCustomer = $request->has('active_customer') ? (bool) $request->input('active_customer') : null; - $cityId = $request->input('city_id'); + $villageId = $request->input('village_id'); $totalPaidMin = $request->input('total_paid_min'); $totalPaidMax = $request->input('total_paid_max'); $latestPaymentFrom = $request->input('latest_payment_from'); @@ -65,7 +65,7 @@ public function index(Request $request): ApiResource { $customerType, $agentId, $activeCustomer, - $cityId, + $villageId, $totalPaidMin, $totalPaidMax, $latestPaymentFrom, diff --git a/src/backend/app/Http/Controllers/PersonExportController.php b/src/backend/app/Http/Controllers/PersonExportController.php index 06ec07dc0..6bb974a52 100644 --- a/src/backend/app/Http/Controllers/PersonExportController.php +++ b/src/backend/app/Http/Controllers/PersonExportController.php @@ -58,7 +58,7 @@ public function downloadCsv(Request $request): StreamedResponse { $this->peopleExportService->setPeopleData($people); $this->peopleExportService->setExportingData(); - $headers = ['Title', 'Name', 'Surname', 'Birth Date', 'Gender', 'Email', 'Phone', 'City', 'Device Serial', 'Agent Name']; + $headers = ['Title', 'Name', 'Surname', 'Birth Date', 'Gender', 'Email', 'Phone', 'Village', 'Device Serial', 'Agent Name']; $csvPath = $this->peopleExportService->saveCsv($headers); return Storage::download($csvPath, 'customer_export_'.now()->format('Ymd_His').'.csv'); diff --git a/src/backend/app/Http/Controllers/Reports.php b/src/backend/app/Http/Controllers/Reports.php index d05981794..03a98f590 100644 --- a/src/backend/app/Http/Controllers/Reports.php +++ b/src/backend/app/Http/Controllers/Reports.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers; use App\Exceptions\ConnectionGroupNotFoundException; -use App\Models\City; +use App\Models\Village; use App\Models\ConnectionGroup; use App\Models\ConnectionType; use App\Models\DatabaseProxy; @@ -52,7 +52,7 @@ public function __construct( private ConnectionType $connectionType, private ConnectionGroup $connectionGroup, private PaymentHistory $paymentHistory, - private City $city, + private Village $village, private Target $target, private Report $report, ) {} @@ -145,11 +145,11 @@ private function initSheet(): void { public function generateWithJob(string $startDate, string $endDate, string $reportType): void { try { - $cities = $this->city->newQuery()->get(); - foreach ($cities as $city) { + $villages = $this->village->newQuery()->get(); + foreach ($villages as $village) { $this->getCustomerGroupCountPerMonth($endDate); $this->getCustomerGroupEnergyUsagePerMonth([$startDate, $endDate]); - $this->generateReportForCity($city->id, $city->name, $startDate, $endDate, $reportType); + $this->generateReportForVillage($village->id, $village->name, $startDate, $endDate, $reportType); } } catch (\Exception $e) { Log::critical( @@ -501,9 +501,9 @@ private function excelColumnRange(string $lower, string $upper): \Generator { * @throws ConnectionGroupNotFoundException * @throws \PhpOffice\PhpSpreadsheet\Exception */ - private function generateReportForCity( - int $cityId, - string $cityName, + private function generateReportForVillage( + int $villageId, + string $villageName, string $startDate, string $endDate, string $reportType, @@ -519,8 +519,8 @@ private function generateReportForCity( ->selectRaw('id,message,SUM(amount) as amount,GROUP_CONCAT(DISTINCT id SEPARATOR \',\') AS transaction_ids') ->whereHas( 'device.person.addresses', - function ($q) use ($cityId) { - $q->where('city_id', $cityId) + function ($q) use ($villageId) { + $q->where('village_id', $villageId) ->where('is_primary', 1); } ) @@ -568,7 +568,7 @@ static function ($q) { $sheet2->setTitle('monthly'); // Add targets $this->addTargetConnectionGroups($sheet2); - $this->addStoredTargets($sheet2, $cityId, $endDate); + $this->addStoredTargets($sheet2, $villageId, $endDate); $this->addTargetsToXls($sheet2); } @@ -577,11 +577,11 @@ static function ($q) { $databaseProxy = app(DatabaseProxy::class); $companyId = $databaseProxy->findByEmail($user->email)->getCompanyId(); - $fileName = Str::slug("{$reportType}-{$cityName}-{$dateRange}").'.xlsx'; + $fileName = Str::slug("{$reportType}-{$villageName}-{$dateRange}").'.xlsx'; $path = "reports/{$companyId}/village_report_{$reportType}/{$fileName}"; // Save to a temporary local file - $tempFile = tempnam(sys_get_temp_dir(), 'city_report_').'.xlsx'; + $tempFile = tempnam(sys_get_temp_dir(), 'village_report_').'.xlsx'; $writer = new Xlsx($this->spreadsheet); $writer->save($tempFile); @@ -593,13 +593,13 @@ static function ($q) { 'path' => $path."*{$companyId}", 'type' => $reportType, 'date' => "{$startDate}---{$endDate}", - 'name' => $cityName, + 'name' => $villageName, ]); Log::info("Report generated: {$fileName}"); } catch (Exception $e) { - Log::error('Error generating report for city', [ - 'city' => $cityName, + Log::error('Error generating report for village', [ + 'village' => $villageName, 'exception' => $e->getMessage(), ]); } @@ -697,11 +697,11 @@ private function addTargetsToXls(Worksheet $sheet): void { } } - private function addStoredTargets(Worksheet $sheet, int $cityId, string $endDate): void { + private function addStoredTargets(Worksheet $sheet, int $villageId, string $endDate): void { $targetData = $this->target::with('subTargets.connectionType') ->where('target_date', '>', $endDate) ->where('owner_type', 'mini-grid') - ->where('owner_id', $cityId) + ->where('owner_id', $villageId) ->oldest('target_date')->first(); if (!$targetData) { // no target is defined for that mini-grid diff --git a/src/backend/app/Http/Controllers/RevenueController.php b/src/backend/app/Http/Controllers/RevenueController.php index 4ac634d26..d7edb0172 100644 --- a/src/backend/app/Http/Controllers/RevenueController.php +++ b/src/backend/app/Http/Controllers/RevenueController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers; use App\Http\Resources\ApiResource; -use App\Models\City; +use App\Models\Village; use App\Models\Cluster; use App\Models\ConnectionGroup; use App\Models\ConnectionType; @@ -22,7 +22,7 @@ public function __construct( private Ticket $ticket, private TicketCategory $label, private PeriodService $periodService, - private City $city, + private Village $village, private RevenueService $revenueService, private MeterRevenueService $meterRevenueService, private Target $target, @@ -71,11 +71,11 @@ public function trending(int $id, Request $request): ApiResource { $end = $request->input('endDate', date('Y-m-d')); $endDate = Carbon::parse($end)->endOfDay(); - $cities = $this->city::query()->where('mini_grid_id', $id)->get(); - $cityIds = implode(',', $cities->pluck('id')->toArray()); + $villages = $this->village::query()->where('mini_grid_id', $id)->get(); + $villageIds = implode(',', $villages->pluck('id')->toArray()); - if (count($cities) === 0) { - $response = ['data' => null, 'message' => 'There is no city for this MiniGrid']; + if (count($villages) === 0) { + $response = ['data' => null, 'message' => 'There is no village for this MiniGrid']; return ApiResource::make($response); } @@ -92,9 +92,9 @@ public function trending(int $id, Request $request): ApiResource { $initialData ); - $connections->each(function (ConnectionType $connection) use ($endDate, $startDate, $cityIds, &$response) { - $this->meterRevenueService->getConnectionTypeBasedRevenueInWeeklyPeriodForCities( - $cityIds, + $connections->each(function (ConnectionType $connection) use ($endDate, $startDate, $villageIds, &$response) { + $this->meterRevenueService->getConnectionTypeBasedRevenueInWeeklyPeriodForVillages( + $villageIds, $connection->id, $startDate, $endDate diff --git a/src/backend/app/Http/Controllers/SmsController.php b/src/backend/app/Http/Controllers/SmsController.php index af4dceb66..5fa6be100 100644 --- a/src/backend/app/Http/Controllers/SmsController.php +++ b/src/backend/app/Http/Controllers/SmsController.php @@ -93,9 +93,9 @@ public function storeBulk(Request $request): void { 'device.person.addresses', static function ($q) use ($miniGrid) { if ((int) $miniGrid === 0) { - $q->where('city_id', '>', 0); + $q->where('village_id', '>', 0); } else { - $q->where('city_id', $miniGrid); + $q->where('village_id', $miniGrid); } } )->whereHas( @@ -116,9 +116,9 @@ function ($q) use ($receivers) { 'device.person.addresses', static function ($q) use ($miniGrid) { if ((int) $miniGrid === 0) { - $q->where('city_id', '>', 0); + $q->where('village_id', '>', 0); } else { - $q->where('city_id', $miniGrid); + $q->where('village_id', $miniGrid); } } )->get(); @@ -134,9 +134,9 @@ static function ($q) use ($miniGrid) { 'device.person.addresses', static function ($q) use ($miniGrid) { if ((int) $miniGrid === 0) { - $q->where('city_id', '>', 0); + $q->where('village_id', '>', 0); } else { - $q->where('city_id', $miniGrid); + $q->where('village_id', $miniGrid); } } )->whereHas( diff --git a/src/backend/app/Http/Controllers/VillageController.php b/src/backend/app/Http/Controllers/VillageController.php new file mode 100644 index 000000000..0a564762e --- /dev/null +++ b/src/backend/app/Http/Controllers/VillageController.php @@ -0,0 +1,53 @@ +get('limit'); + + return ApiResource::make($this->villageService->getAll($limit)); + } + + public function show(int $villageId, Request $request): ApiResource { + $relation = $request->get('relation'); + + if ($relation) { + return ApiResource::make($this->villageService->getByIdWithRelation($villageId, ['location', 'country'])); + } + + return ApiResource::make($this->villageService->getById($villageId)); + } + + public function update(int $villageId, VillageRequest $request): ApiResource { + $village = $this->villageService->getById($villageId); + $villageData = $request->only(['name', 'mini_grid_id', 'country_id']); + + return ApiResource::make($this->villageService->update($village, $villageData)); + } + + public function store(VillageRequest $request): ApiResource { + $data = $request->validationData(); + $village = $this->villageService->create($data); + $geographicalInformation = $this->geographicalInformationService->make($data); + $this->villageGeographicalInformationService->setAssigned($geographicalInformation); + $this->villageGeographicalInformationService->setAssignee($village); + $this->villageGeographicalInformationService->assign(); + $this->geographicalInformationService->save($geographicalInformation); + + return ApiResource::make($village); + } +} diff --git a/src/backend/app/Http/Requests/CreateAddressRequest.php b/src/backend/app/Http/Requests/CreateAddressRequest.php index 388069c64..b759f139b 100644 --- a/src/backend/app/Http/Requests/CreateAddressRequest.php +++ b/src/backend/app/Http/Requests/CreateAddressRequest.php @@ -15,13 +15,13 @@ public function authorize(): bool { /** * Get the validation rules that apply to the request. * - * @bodyParam city_id int required + * @bodyParam village_id int required * * @return array */ public function rules(): array { return [ - 'city_id' => ['required'], + 'village_id' => ['required'], ]; } } diff --git a/src/backend/app/Http/Requests/CreateAgentRequest.php b/src/backend/app/Http/Requests/CreateAgentRequest.php index 939e2a245..3e6a2cc27 100644 --- a/src/backend/app/Http/Requests/CreateAgentRequest.php +++ b/src/backend/app/Http/Requests/CreateAgentRequest.php @@ -26,7 +26,7 @@ public function rules(): array { 'name' => ['required', 'min:3'], 'surname' => ['required', 'min:3'], 'password' => ['required', 'min:6'], - 'city_id' => ['required'], + 'village_id' => ['required'], 'agent_commission_id' => ['required'], ]; } diff --git a/src/backend/app/Http/Requests/MaintenanceRequest.php b/src/backend/app/Http/Requests/MaintenanceRequest.php index e86f813c6..e6837376a 100644 --- a/src/backend/app/Http/Requests/MaintenanceRequest.php +++ b/src/backend/app/Http/Requests/MaintenanceRequest.php @@ -25,7 +25,7 @@ public function rules(): array { 'birth_date' => ['sometimes', 'date_format:"Y-m-d"'], 'gender' => ['sometimes', 'nullable', 'string'], 'education' => ['sometimes', 'min:3'], - 'city_id' => ['sometimes', 'exists:tenant.cities,id'], + 'village_id' => ['sometimes', 'exists:tenant.villages,id'], 'street' => ['sometimes', 'string', 'min:3'], 'email' => ['sometimes', 'email'], 'phone' => ['required', 'min:11', 'regex:(^\+)'], @@ -33,8 +33,8 @@ public function rules(): array { ]; } - public function getCityId(): int { - return $this->input('city_id'); + public function getVillageId(): int { + return $this->input('village_id'); } public function getPhone(): ?string { diff --git a/src/backend/app/Http/Requests/ManufacturerRequest.php b/src/backend/app/Http/Requests/ManufacturerRequest.php index 02ad1e4e1..da2b943d8 100644 --- a/src/backend/app/Http/Requests/ManufacturerRequest.php +++ b/src/backend/app/Http/Requests/ManufacturerRequest.php @@ -24,7 +24,7 @@ public function rules(): array { 'email' => ['sometimes', 'email'], 'contact_person' => ['sometimes', 'min:3'], 'website' => ['sometimes', 'min:6'], - 'city_id' => ['sometimes', 'integer'], + 'village_id' => ['sometimes', 'integer'], 'address' => ['sometimes', 'string'], 'api_name' => ['sometimes'], ]; diff --git a/src/backend/app/Http/Requests/PersonRequest.php b/src/backend/app/Http/Requests/PersonRequest.php index 9f48f27be..0b83a206d 100644 --- a/src/backend/app/Http/Requests/PersonRequest.php +++ b/src/backend/app/Http/Requests/PersonRequest.php @@ -11,7 +11,7 @@ * @bodyParam birth_date string optional. Example: 1970-01-01 * @bodyParam gender string optional Example: male * @bodyParam education string optional. Example: University - * @bodyParam city_id int optional. Example: 1 + * @bodyParam village_id int optional. Example: 1 * @bodyParam street string optional. Example: Some Street 1/13 * @bodyParam email string optional. Example: john.doe@mail.com * @bodyParam phone string optional. Example: +1111 @@ -38,7 +38,7 @@ public function rules(): array { 'birth_date' => ['sometimes', 'nullable', 'date'], 'gender' => ['sometimes', 'nullable', 'string'], 'education' => ['sometimes', 'nullable', 'string'], - 'city_id' => ['sometimes', 'integer', 'exists:tenant.cities,id'], + 'village_id' => ['sometimes', 'integer', 'exists:tenant.villages,id'], 'street' => ['sometimes', 'nullable', 'string', 'min:5'], 'email' => ['sometimes', 'nullable', 'email'], 'phone' => ['sometimes', 'min:11'], diff --git a/src/backend/app/Http/Requests/CityRequest.php b/src/backend/app/Http/Requests/VillageRequest.php similarity index 93% rename from src/backend/app/Http/Requests/CityRequest.php rename to src/backend/app/Http/Requests/VillageRequest.php index ca8393fcc..4c03eea85 100644 --- a/src/backend/app/Http/Requests/CityRequest.php +++ b/src/backend/app/Http/Requests/VillageRequest.php @@ -4,7 +4,7 @@ use Illuminate\Foundation\Http\FormRequest; -class CityRequest extends FormRequest { +class VillageRequest extends FormRequest { /** * Determine if the user is authorized to make this request. */ diff --git a/src/backend/app/Models/Address/Address.php b/src/backend/app/Models/Address/Address.php index e9e7cbdb1..8e3dddddb 100644 --- a/src/backend/app/Models/Address/Address.php +++ b/src/backend/app/Models/Address/Address.php @@ -3,7 +3,7 @@ namespace App\Models\Address; use App\Models\Base\BaseModel; -use App\Models\City; +use App\Models\Village; use App\Models\GeographicalInformation; use Database\Factories\Address\AddressFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -22,11 +22,11 @@ * @property string|null $email * @property string|null $phone * @property string|null $street - * @property int|null $city_id + * @property int|null $village_id * @property int $is_primary * @property Carbon|null $created_at * @property Carbon|null $updated_at - * @property-read City|null $city + * @property-read Village|null $village * @property-read GeographicalInformation|null $geo * @property-read Model $owner */ @@ -39,14 +39,14 @@ class Address extends BaseModel { /** @var array */ public static $rules = [ - 'city_id' => 'required|exists:cities,id', + 'village_id' => 'required|exists:villages,id', ]; /** - * @return BelongsTo + * @return BelongsTo */ - public function city(): BelongsTo { - return $this->belongsTo(City::class); + public function village(): BelongsTo { + return $this->belongsTo(Village::class); } /** @@ -68,8 +68,8 @@ public function setOwner(int $ownerId, string $ownerType): void { $this->owner_type = $ownerType; } - public function setCityId(int $cityId): void { - $this->city_id = $cityId; + public function setVillageId(int $villageId): void { + $this->village_id = $villageId; } public function setPhone(?string $phone): void { diff --git a/src/backend/app/Models/Agent.php b/src/backend/app/Models/Agent.php index aa25e91de..85146a68d 100644 --- a/src/backend/app/Models/Agent.php +++ b/src/backend/app/Models/Agent.php @@ -149,7 +149,7 @@ public function assignedAppliance(): HasMany { * @return MorphMany */ public function addressDetails(): MorphMany { - return $this->addresses()->with('city'); + return $this->addresses()->with('village'); } /** diff --git a/src/backend/app/Models/Cluster.php b/src/backend/app/Models/Cluster.php index 909b54f8c..3fc0a435a 100644 --- a/src/backend/app/Models/Cluster.php +++ b/src/backend/app/Models/Cluster.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; +use Illuminate\Database\Eloquent\Relations\MorphOne; use Illuminate\Support\Carbon; /** @@ -21,7 +22,8 @@ * @property object $geo_json * @property Carbon|null $created_at * @property Carbon|null $updated_at - * @property-read Collection $cities + * @property-read Collection $villages + * @property-read GeographicalInformation|null $location * @property-read User|null $manager * @property-read Collection $miniGrids */ @@ -31,14 +33,20 @@ class Cluster extends BaseModel implements ITargetAssignable { public const RELATION_NAME = 'cluster'; + /** @var array */ + protected $hidden = ['location']; + + /** @var array */ + protected $appends = ['geo_json']; + /** @return BelongsTo */ public function manager(): BelongsTo { return $this->belongsTo(User::class); } - /** @return HasManyThrough */ - public function cities(): HasManyThrough { - return $this->hasManyThrough(City::class, MiniGrid::class); + /** @return HasManyThrough */ + public function villages(): HasManyThrough { + return $this->hasManyThrough(Village::class, MiniGrid::class); } /** @return HasMany */ @@ -46,6 +54,31 @@ public function miniGrids(): HasMany { return $this->hasMany(MiniGrid::class); } + /** @return MorphOne */ + public function location(): MorphOne { + return $this->morphOne(GeographicalInformation::class, 'owner'); + } + + public function getGeoJsonAttribute(): mixed { + $location = $this->relationLoaded('location') + ? $this->location + : $this->location()->first(); + + if ($location?->geo_json !== null) { + return $location->geo_json; + } + + $legacyGeoJson = $this->getRawOriginal('geo_json'); + + if ($legacyGeoJson === null || $legacyGeoJson === '') { + return null; + } + + return is_string($legacyGeoJson) + ? json_decode($legacyGeoJson) + : $legacyGeoJson; + } + protected function casts(): array { return [ 'geo_json' => 'object', diff --git a/src/backend/app/Models/CompanyDatabase.php b/src/backend/app/Models/CompanyDatabase.php index 1c32c0292..32f8eee3d 100644 --- a/src/backend/app/Models/CompanyDatabase.php +++ b/src/backend/app/Models/CompanyDatabase.php @@ -51,10 +51,18 @@ public function databaseProxies(): HasMany { } public function findByCompanyId(int $companyId): CompanyDatabase { + if (!$this->shouldUseCache()) { + return $this->newQuery() + ->where(self::COL_COMPANY_ID, '=', $companyId) + ->latest('id') + ->firstOrFail(); + } + $cacheKey = self::CACHE_KEY_PREFIX.':'.$companyId; return Cache::remember($cacheKey, self::CACHE_TTL, fn () => $this->newQuery() ->where(self::COL_COMPANY_ID, '=', $companyId) + ->latest('id') ->firstOrFail()); } @@ -74,4 +82,8 @@ private function clearCache(): void { $cacheKey = self::CACHE_KEY_PREFIX.':'.$this->company_id; Cache::forget($cacheKey); } + + private function shouldUseCache(): bool { + return !app()->environment(['development', 'testing']); + } } diff --git a/src/backend/app/Models/Country.php b/src/backend/app/Models/Country.php index 7b2bb7118..40cb02909 100644 --- a/src/backend/app/Models/Country.php +++ b/src/backend/app/Models/Country.php @@ -17,7 +17,7 @@ * @property string $country_name * @property Carbon|null $created_at * @property Carbon|null $updated_at - * @property-read Collection $cities + * @property-read Collection $villages */ class Country extends BaseModel { /** @use HasFactory */ @@ -28,9 +28,9 @@ public function getRouteKeyName(): string { } /** - * @return HasMany + * @return HasMany */ - public function cities(): HasMany { - return $this->hasMany(City::class); + public function villages(): HasMany { + return $this->hasMany(Village::class); } } diff --git a/src/backend/app/Models/DatabaseProxy.php b/src/backend/app/Models/DatabaseProxy.php index 7e9bc08ba..57b948e32 100644 --- a/src/backend/app/Models/DatabaseProxy.php +++ b/src/backend/app/Models/DatabaseProxy.php @@ -22,6 +22,7 @@ */ class DatabaseProxy extends BaseModelCentral { public const COL_DATABASE_CONNECTION = 'database_connection'; + public const COL_ID = 'id'; public const COL_COMPANY_ID = 'fk_company_id'; public const COL_EMAIL = 'email'; private const CACHE_KEY_PREFIX = 'database_proxy'; @@ -51,11 +52,18 @@ private function buildQuery(?int $companyId = null): Builder { } public function findByEmail(string $email): DatabaseProxy { + if (!$this->shouldUseCache()) { + return $this->buildQuery() + ->where(self::COL_EMAIL, '=', $email) + ->latest(self::COL_ID) + ->firstOrFail(); + } + $cacheKey = self::CACHE_KEY_PREFIX.':'.md5($email); return Cache::remember($cacheKey, self::CACHE_TTL, fn () => $this->buildQuery() - ->join(CompanyDatabase::TABLE_NAME, CompanyDatabase::COL_COMPANY_ID, '=', self::COL_COMPANY_ID) ->where(self::COL_EMAIL, '=', $email) + ->latest(self::COL_ID) ->firstOrFail()); } @@ -87,4 +95,8 @@ private function clearCache(): void { $cacheKey = self::CACHE_KEY_PREFIX.':'.md5($this->email); Cache::forget($cacheKey); } + + private function shouldUseCache(): bool { + return !app()->environment(['development', 'testing']); + } } diff --git a/src/backend/app/Models/Device.php b/src/backend/app/Models/Device.php index 33d8323cb..98752329d 100644 --- a/src/backend/app/Models/Device.php +++ b/src/backend/app/Models/Device.php @@ -77,7 +77,7 @@ public function miniGrid(): ?MiniGrid { ?->addresses() ->where('is_primary', 1) ->first() - ?->city + ?->village ?->miniGrid; } diff --git a/src/backend/app/Models/GeographicalInformation.php b/src/backend/app/Models/GeographicalInformation.php index 20be81690..d57684443 100644 --- a/src/backend/app/Models/GeographicalInformation.php +++ b/src/backend/app/Models/GeographicalInformation.php @@ -16,6 +16,7 @@ * @property int $owner_id * @property string $owner_type * @property string $points + * @property object|null $geo_json * @property Carbon|null $created_at * @property Carbon|null $updated_at * @property-read Model $owner @@ -32,4 +33,10 @@ class GeographicalInformation extends BaseModel { public function owner(): MorphTo { return $this->morphTo(); } + + protected function casts(): array { + return [ + 'geo_json' => 'object', + ]; + } } diff --git a/src/backend/app/Models/MiniGrid.php b/src/backend/app/Models/MiniGrid.php index 79c3064d6..3550e6ae0 100644 --- a/src/backend/app/Models/MiniGrid.php +++ b/src/backend/app/Models/MiniGrid.php @@ -21,7 +21,7 @@ * @property Carbon|null $created_at * @property Carbon|null $updated_at * @property-read Collection $agents - * @property-read Collection $cities + * @property-read Collection $villages * @property-read Cluster|null $cluster * @property-read GeographicalInformation|null $location */ @@ -33,10 +33,10 @@ class MiniGrid extends BaseModel implements ITargetAssignable { protected $guarded = []; /** - * @return HasMany + * @return HasMany */ - public function cities(): HasMany { - return $this->hasMany(City::class); + public function villages(): HasMany { + return $this->hasMany(Village::class); } /** diff --git a/src/backend/app/Models/Person/Person.php b/src/backend/app/Models/Person/Person.php index 24a161089..fed7b9035 100644 --- a/src/backend/app/Models/Person/Person.php +++ b/src/backend/app/Models/Person/Person.php @@ -175,14 +175,14 @@ public function livingInClusterQuery(int $clusterId): Builder { $q->where('addresses.owner_type', 'person'); $q->where('addresses.is_primary', '=', 1); }) - ->leftJoin('cities', function (JoinClause $jc) { - $jc->on('cities.id', '=', 'addresses.city_id'); + ->leftJoin('villages', function (JoinClause $jc) { + $jc->on('villages.id', '=', 'addresses.village_id'); }) ->leftJoin('clusters', function (JoinClause $jc) { - $jc->on('clusters.id', '=', 'cities.cluster_id'); + $jc->on('clusters.id', '=', 'villages.cluster_id'); })->where('clusters.id', '=', $clusterId) ->orderBy('people.id') - ->orderBy('cities.id'); + ->orderBy('villages.id'); } public function getId(): int { diff --git a/src/backend/app/Models/Target.php b/src/backend/app/Models/Target.php index 022a258cc..79636b60e 100644 --- a/src/backend/app/Models/Target.php +++ b/src/backend/app/Models/Target.php @@ -24,7 +24,7 @@ * @property int $owner_id * @property Carbon|null $created_at * @property Carbon|null $updated_at - * @property-read City|null $city + * @property-read Village|null $village * @property-read Model $owner * @property-read Collection $subTargets */ @@ -33,10 +33,10 @@ class Target extends BaseModel { use HasFactory; /** - * @return BelongsTo + * @return BelongsTo */ - public function city(): BelongsTo { - return $this->belongsTo(City::class); + public function village(): BelongsTo { + return $this->belongsTo(Village::class); } /** @@ -49,9 +49,9 @@ public function subTargets(): HasMany { /** * @return Builder */ - public function targetForMiniGrid(int|string $cityId, string $endDate): Builder { - return $this::with('subTargets.connectionType', 'city') - ->where('owner_id', $cityId) + public function targetForMiniGrid(int|string $villageId, string $endDate): Builder { + return $this::with('subTargets.connectionType', 'village') + ->where('owner_id', $villageId) ->where('owner_type', 'mini-grid') ->where('target_date', '>=', $endDate) ->oldest('target_date') @@ -66,7 +66,7 @@ public function targetForMiniGrid(int|string $cityId, string $endDate): Builder public function targetForCluster(array $miniGridIds, string $endDate): Builder { return $this::query() ->select(DB::raw('*, YEARWEEK(target_date,3) as period')) - ->with('subTargets.connectionType', 'city') + ->with('subTargets.connectionType', 'village') ->whereIn('owner_id', $miniGridIds) ->where('owner_type', 'mini-grid') ->where('target_date', '>=', $endDate) @@ -83,13 +83,13 @@ public function owner(): MorphTo { /** * @return Builder */ - public function periodTargetAlternative(int|string $cityId, string $startDate): Builder { + public function periodTargetAlternative(int|string $villageId, string $startDate): Builder { return $this::query() ->select(DB::raw('*, YEARWEEK(target_date,3) as period'))->with( 'subTargets.connectionType', - 'city' + 'village' ) - ->where('owner_id', $cityId) + ->where('owner_id', $villageId) ->where('owner_type', 'mini-grid') ->where('target_date', '<', $startDate) ->orderBy('target_date', 'desc')->limit(1); diff --git a/src/backend/app/Models/Ticket/Ticket.php b/src/backend/app/Models/Ticket/Ticket.php index 482344d3d..02ca63500 100644 --- a/src/backend/app/Models/Ticket/Ticket.php +++ b/src/backend/app/Models/Ticket/Ticket.php @@ -121,9 +121,9 @@ public function ticketsOpenedWithCategories(int $miniGridId, mixed $startDate = LEFT JOIN addresses ON addresses.owner_id = tickets.owner_id WHERE addresses.owner_type = 'person' - AND addresses.city_id IN ( + AND addresses.village_id IN ( SELECT id - FROM cities + FROM villages WHERE mini_grid_id = {$miniGridId} ){$dateFilter} GROUP BY @@ -158,9 +158,9 @@ public function ticketsClosedWithCategories(int $miniGridId, mixed $startDate = LEFT JOIN addresses ON addresses.owner_id = tickets.owner_id WHERE addresses.owner_type = 'person' - AND addresses.city_id IN ( + AND addresses.village_id IN ( SELECT id - FROM cities + FROM villages WHERE mini_grid_id = {$miniGridId} ) AND tickets.status = 1{$dateFilter} diff --git a/src/backend/app/Models/Transaction/Transaction.php b/src/backend/app/Models/Transaction/Transaction.php index 7a4d002d1..9d0ccbea5 100644 --- a/src/backend/app/Models/Transaction/Transaction.php +++ b/src/backend/app/Models/Transaction/Transaction.php @@ -110,7 +110,7 @@ public function nonPaygoAppliance(): HasOne { /** * @return array> */ - public function periodTargetAlternative(int $cityId, string $startDate, string $endDate): array { + public function periodTargetAlternative(int $villageId, string $startDate, string $endDate): array { $sql = <<getPdo()->prepare($sql); - $sth->bindValue(':city_id', $cityId, \PDO::PARAM_INT); + $sth->bindValue(':village_id', $villageId, \PDO::PARAM_INT); $sth->bindValue(':periodStartDate', $startDate, \PDO::PARAM_STR); $sth->bindValue(':periodEndDate', $endDate, \PDO::PARAM_STR); diff --git a/src/backend/app/Models/User.php b/src/backend/app/Models/User.php index e2fe1e435..53f7ecc46 100644 --- a/src/backend/app/Models/User.php +++ b/src/backend/app/Models/User.php @@ -113,7 +113,7 @@ public function address(): MorphOne { * @return MorphOne */ public function addressDetails(): MorphOne { - return $this->address()->with('city'); + return $this->address()->with('village'); } /** diff --git a/src/backend/app/Models/City.php b/src/backend/app/Models/Village.php similarity index 93% rename from src/backend/app/Models/City.php rename to src/backend/app/Models/Village.php index 60c9f9631..fb5bf199a 100644 --- a/src/backend/app/Models/City.php +++ b/src/backend/app/Models/Village.php @@ -4,7 +4,7 @@ use App\Models\Address\Address; use App\Models\Base\BaseModel; -use Database\Factories\CityFactory; +use Database\Factories\VillageFactory; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -15,7 +15,7 @@ use Znck\Eloquent\Traits\BelongsToThrough as BelongsToThroughTrait; /** - * Class City. + * Class Village. * * @property int $id * @property string $name @@ -31,12 +31,12 @@ * @property-read MiniGrid|null $miniGrid * @property-read Collection $targets */ -class City extends BaseModel { - /** @use HasFactory */ +class Village extends BaseModel { + /** @use HasFactory */ use HasFactory; use BelongsToThroughTrait; - public const RELATION_NAME = 'city'; + public const RELATION_NAME = 'village'; /** * @return HasMany diff --git a/src/backend/app/Plugins/BulkRegistration/Helpers/CsvDataProcessor.php b/src/backend/app/Plugins/BulkRegistration/Helpers/CsvDataProcessor.php index 4a07b262e..73940c35b 100644 --- a/src/backend/app/Plugins/BulkRegistration/Helpers/CsvDataProcessor.php +++ b/src/backend/app/Plugins/BulkRegistration/Helpers/CsvDataProcessor.php @@ -4,7 +4,7 @@ use App\Events\AccessRatePaymentInitialize; use App\Models\Address\Address; -use App\Models\City; +use App\Models\Village; use App\Models\Cluster; use App\Models\ConnectionType; use App\Models\Manufacturer; @@ -65,10 +65,10 @@ public function processParsedCsvData(array $csvData): array { $row['mini_grid_id'] = $miniGrid->id; $this->checkRecordWasRecentlyCreated($miniGrid, 'mini_grid'); - /** @var City */ - $city = $this->createRecordFromCsv($row, $this->reflections['CityService']); - $row['city_id'] = $city->id; - $this->checkRecordWasRecentlyCreated($city, 'village'); + /** @var Village */ + $village = $this->createRecordFromCsv($row, $this->reflections['VillageService']); + $row['village_id'] = $village->id; + $this->checkRecordWasRecentlyCreated($village, 'village'); $this->createRecordFromCsv($row, $this->reflections['AddressService']); @@ -103,7 +103,7 @@ public function processParsedCsvData(array $csvData): array { $address = new Address(); $address = $address->newQuery()->make([ - 'city_id' => $city->id, + 'village_id' => $village->id, ]); $address->owner()->associate($meter); // See: https://github.com/EnAccess/micropowermanager/issues/1004 diff --git a/src/backend/app/Plugins/BulkRegistration/Services/AddressService.php b/src/backend/app/Plugins/BulkRegistration/Services/AddressService.php index ba8453073..874205e82 100644 --- a/src/backend/app/Plugins/BulkRegistration/Services/AddressService.php +++ b/src/backend/app/Plugins/BulkRegistration/Services/AddressService.php @@ -24,7 +24,7 @@ public function resolveCsvDataFromComingRow(array $csvData): void { $firstAddressData = [ 'owner_type' => 'person', 'owner_id' => $csvData[$addressConfig['person_id']], - 'city_id' => $csvData[$addressConfig['city_id']], + 'village_id' => $csvData[$addressConfig['village_id']], 'phone' => $csvData[$addressConfig['phone']], 'is_primary' => 1, ]; @@ -33,7 +33,7 @@ public function resolveCsvDataFromComingRow(array $csvData): void { $alternativeAddress = [ 'owner_type' => 'person', 'owner_id' => $csvData[$addressConfig['person_id']], - 'city_id' => $csvData[$addressConfig['city_id']], + 'village_id' => $csvData[$addressConfig['village_id']], 'phone' => $csvData[$addressConfig['alternative_phone']], 'is_primary' => 0, ]; @@ -42,10 +42,10 @@ public function resolveCsvDataFromComingRow(array $csvData): void { $this->createRelatedDataIfDoesNotExists($returnAddresses); } - public function createForPerson(int $personId, int $cityId, ?string $phone, ?string $email, ?string $street, bool $isPrimary): Address { + public function createForPerson(int $personId, int $villageId, ?string $phone, ?string $email, ?string $street, bool $isPrimary): Address { $address = new Address(); $address->setOwner($personId, 'person'); - $address->setCityId($cityId); + $address->setVillageId($villageId); $address->setPhone($phone); $address->setEmail($email); $address->setIsPrimary($isPrimary); diff --git a/src/backend/app/Plugins/BulkRegistration/Services/CityService.php b/src/backend/app/Plugins/BulkRegistration/Services/CityService.php deleted file mode 100644 index ab88356da..000000000 --- a/src/backend/app/Plugins/BulkRegistration/Services/CityService.php +++ /dev/null @@ -1,40 +0,0 @@ - $csvData - */ - public function resolveCsvDataFromComingRow(array $csvData) { - $cityConfig = config('bulk-registration.csv_fields.city'); - - if (!$csvData[$cityConfig['name']]) { - throw new VillageNotFoundException('Village Name is required'); - } - $registeredCity = City::query()->where('name', $csvData[$cityConfig['name']])->first(); - - if (!$registeredCity) { - $message = 'There is no registered Village for '.$csvData[$cityConfig['name']]. - '. Please add the Village first.'; - - throw new VillageNotFoundException($message); - } - - $cityData = [ - 'cluster_id' => $csvData[$cityConfig['cluster_id']], - 'country_id' => 0, - 'mini_grid_id' => $csvData[$cityConfig['mini_grid_id']], - 'name' => $csvData[$cityConfig['name']], - ]; - - return $this->createRelatedDataIfDoesNotExists($cityData); - } -} diff --git a/src/backend/app/Plugins/BulkRegistration/Services/VillageService.php b/src/backend/app/Plugins/BulkRegistration/Services/VillageService.php new file mode 100644 index 000000000..ea483c6ef --- /dev/null +++ b/src/backend/app/Plugins/BulkRegistration/Services/VillageService.php @@ -0,0 +1,40 @@ + $csvData + */ + public function resolveCsvDataFromComingRow(array $csvData) { + $villageConfig = config('bulk-registration.csv_fields.village'); + + if (!$csvData[$villageConfig['name']]) { + throw new VillageNotFoundException('Village Name is required'); + } + $registeredVillage = Village::query()->where('name', $csvData[$villageConfig['name']])->first(); + + if (!$registeredVillage) { + $message = 'There is no registered Village for '.$csvData[$villageConfig['name']]. + '. Please add the Village first.'; + + throw new VillageNotFoundException($message); + } + + $villageData = [ + 'cluster_id' => $csvData[$villageConfig['cluster_id']], + 'country_id' => 0, + 'mini_grid_id' => $csvData[$villageConfig['mini_grid_id']], + 'name' => $csvData[$villageConfig['name']], + ]; + + return $this->createRelatedDataIfDoesNotExists($villageData); + } +} diff --git a/src/backend/app/Plugins/KelinMeter/Services/KelinCustomerService.php b/src/backend/app/Plugins/KelinMeter/Services/KelinCustomerService.php index ad971c1b1..44d54856b 100644 --- a/src/backend/app/Plugins/KelinMeter/Services/KelinCustomerService.php +++ b/src/backend/app/Plugins/KelinMeter/Services/KelinCustomerService.php @@ -2,7 +2,7 @@ namespace App\Plugins\KelinMeter\Services; -use App\Models\City; +use App\Models\Village; use App\Models\Person\Person; use App\Plugins\KelinMeter\Exceptions\KelinApiResponseException; use App\Plugins\KelinMeter\Helpers\ApiHelpers; @@ -188,12 +188,12 @@ public function createRelatedPerson(array $customer): Person { 'is_customer' => 1, ]); $addressService = app()->make(AddressesService::class); - $city = City::query()->first(); + $village = Village::query()->first(); $addressParams = [ 'phone' => $personData['phone'], 'street' => $personData['street1'], 'is_primary' => 1, - 'city_id' => $city ? $city->id : 1, + 'village_id' => $village ? $village->id : 1, ]; $address = $addressService->instantiate($addressParams); $addressService->assignAddressToOwner($person, $address); diff --git a/src/backend/app/Plugins/KelinMeter/Services/KelinMeterService.php b/src/backend/app/Plugins/KelinMeter/Services/KelinMeterService.php index fe4a29a8a..863f3dc1f 100644 --- a/src/backend/app/Plugins/KelinMeter/Services/KelinMeterService.php +++ b/src/backend/app/Plugins/KelinMeter/Services/KelinMeterService.php @@ -255,15 +255,15 @@ public function createRelatedMeter(array $kelinMeter): Meter { $meter->save(); $kelinCustomerAddress = $kelinCustomer ->mpmPerson - ->with('addresses.city') + ->with('addresses.village') ->whereHas('addresses', fn ($q) => $q->where('is_primary', 1)) ->first() ; - $city = $kelinCustomerAddress->addresses[0]->city()->first() ?? null; + $village = $kelinCustomerAddress->addresses[0]->village()->first() ?? null; $address = new Address(); $address = $address->newQuery()->create([ - 'city_id' => $city ? $city->id : 1, + 'village_id' => $village ? $village->id : 1, ]); $address->owner()->associate($meter->device); $address->save(); diff --git a/src/backend/app/Plugins/Prospect/Jobs/ExtractAgents.php b/src/backend/app/Plugins/Prospect/Jobs/ExtractAgents.php index b8c9688cf..fe5ebdda1 100644 --- a/src/backend/app/Plugins/Prospect/Jobs/ExtractAgents.php +++ b/src/backend/app/Plugins/Prospect/Jobs/ExtractAgents.php @@ -67,8 +67,8 @@ private function extractDataFromDatabase(): array { ->with([ 'person', 'person.addresses.geo', - 'person.addresses.city.country', - 'person.addresses.city.cluster', + 'person.addresses.village.country', + 'person.addresses.village.cluster', ]); $agents = $query->get(); diff --git a/src/backend/app/Plugins/Prospect/Jobs/ExtractCustomers.php b/src/backend/app/Plugins/Prospect/Jobs/ExtractCustomers.php index 67ef83f34..9c5dcee2b 100644 --- a/src/backend/app/Plugins/Prospect/Jobs/ExtractCustomers.php +++ b/src/backend/app/Plugins/Prospect/Jobs/ExtractCustomers.php @@ -67,7 +67,7 @@ private function extractDataFromDatabase(): array { ->where('is_customer', 1) ->with([ 'addresses.geo', - 'addresses.city.country', + 'addresses.village.country', 'citizenship', 'miniGrid', 'personDocument', diff --git a/src/backend/app/Plugins/Prospect/Jobs/ExtractInstallations.php b/src/backend/app/Plugins/Prospect/Jobs/ExtractInstallations.php index 46e566127..351368133 100644 --- a/src/backend/app/Plugins/Prospect/Jobs/ExtractInstallations.php +++ b/src/backend/app/Plugins/Prospect/Jobs/ExtractInstallations.php @@ -66,7 +66,7 @@ private function extractDataFromDatabase(): array { $query = Device::query()->with([ 'device', 'person.addresses.geo', - 'person.addresses.city.country', + 'person.addresses.village.country', 'tokens.transaction', 'appliance', 'appliancePerson', diff --git a/src/backend/app/Plugins/Prospect/Services/ProspectAgentTransformer.php b/src/backend/app/Plugins/Prospect/Services/ProspectAgentTransformer.php index 903e26b46..45a8fabf3 100644 --- a/src/backend/app/Plugins/Prospect/Services/ProspectAgentTransformer.php +++ b/src/backend/app/Plugins/Prospect/Services/ProspectAgentTransformer.php @@ -26,12 +26,12 @@ public function transform(Agent $agent): array { if ($primaryAddress?->street) { $addressParts[] = $primaryAddress->street; } - if ($primaryAddress?->city?->name) { - $addressParts[] = $primaryAddress->city->name; + if ($primaryAddress?->village?->name) { + $addressParts[] = $primaryAddress->village->name; } $addressString = empty($addressParts) ? null : implode(', ', $addressParts); - $countryCode = $primaryAddress?->city?->country->country_code ?? null; + $countryCode = $primaryAddress?->village?->country->country_code ?? null; $latitude = null; $longitude = null; @@ -53,12 +53,12 @@ public function transform(Agent $agent): array { $locationArea4 = null; $locationArea5 = null; - if ($primaryAddress?->city) { - $city = $primaryAddress->city; - if ($city->cluster) { - $locationArea1 = $city->cluster->name ?? null; + if ($primaryAddress?->village) { + $village = $primaryAddress->village; + if ($village->cluster) { + $locationArea1 = $village->cluster->name ?? null; } - $locationArea2 = $city->name ?? null; + $locationArea2 = $village->name ?? null; } $agentType = $this->determineAgentType($agent); @@ -99,7 +99,7 @@ private function getPrimaryAddress(?Agent $agent): ?Address { return $person->addresses() ->where('is_primary', true) - ->with(['city.country', 'city.cluster', 'geo']) + ->with(['village.country', 'village.cluster', 'geo']) ->first(); } diff --git a/src/backend/app/Plugins/Prospect/Services/ProspectCustomerTransformer.php b/src/backend/app/Plugins/Prospect/Services/ProspectCustomerTransformer.php index 14a8a29e8..57cac5afe 100644 --- a/src/backend/app/Plugins/Prospect/Services/ProspectCustomerTransformer.php +++ b/src/backend/app/Plugins/Prospect/Services/ProspectCustomerTransformer.php @@ -24,12 +24,12 @@ public function transform(Person $person): array { if ($primaryAddress?->street) { $addressParts[] = $primaryAddress->street; } - if ($primaryAddress?->city?->name) { - $addressParts[] = $primaryAddress->city->name; + if ($primaryAddress?->village?->name) { + $addressParts[] = $primaryAddress->village->name; } $addressString = empty($addressParts) ? null : implode(', ', $addressParts); - $countryCode = $primaryAddress?->city?->country->country_code ?? null; + $countryCode = $primaryAddress?->village?->country->country_code ?? null; $birthYear = $this->extractBirthYear($person->birth_date); @@ -61,7 +61,7 @@ private function getPrimaryAddress(?Person $person): ?Address { return $person->addresses() ->where('is_primary', true) - ->with(['city.country', 'geo']) + ->with(['village.country', 'geo']) ->first(); } @@ -77,7 +77,7 @@ private function getSecondaryAddress(?Person $person): ?Address { ->where('is_primary', false) ->whereNotNull('phone') ->where('phone', '!=', '') - ->with(['city.country', 'geo']) + ->with(['village.country', 'geo']) ->first(); } diff --git a/src/backend/app/Plugins/Prospect/Services/ProspectInstallationTransformer.php b/src/backend/app/Plugins/Prospect/Services/ProspectInstallationTransformer.php index e157fd638..f51a5dcac 100644 --- a/src/backend/app/Plugins/Prospect/Services/ProspectInstallationTransformer.php +++ b/src/backend/app/Plugins/Prospect/Services/ProspectInstallationTransformer.php @@ -81,7 +81,7 @@ public function transform(Device $device): array { 'installer_agent_external_id' => null, 'product_common_id' => $appliance?->id ? (string) $appliance->id : null, 'device_external_id' => (string) $device->id, - 'parent_customer_external_id' => (string) $primaryAddress?->city?->mini_grid_id, + 'parent_customer_external_id' => (string) $primaryAddress?->village?->mini_grid_id, 'account_external_id' => $companyId, 'battery_capacity_wh' => null, 'usage_category' => $usageCategory, @@ -117,7 +117,7 @@ public function transform(Device $device): array { 'is_test' => false, 'latitude' => $latitude, 'longitude' => $longitude, - 'country' => $primaryAddress?->city?->country?->country_code, + 'country' => $primaryAddress?->village?->country?->country_code, 'location_area_1' => null, 'location_area_2' => null, 'location_area_3' => null, diff --git a/src/backend/app/Plugins/SparkMeter/Services/CustomerService.php b/src/backend/app/Plugins/SparkMeter/Services/CustomerService.php index 1a61dbfaf..47ea0d335 100644 --- a/src/backend/app/Plugins/SparkMeter/Services/CustomerService.php +++ b/src/backend/app/Plugins/SparkMeter/Services/CustomerService.php @@ -151,19 +151,19 @@ public function createRelatedPerson(array $customer, string $site_id): int { $site = $this->smSite->newQuery()->with('mpmMiniGrid')->where('site_id', $site_id)->firstOrFail(); - $sparkCity = $site->mpmMiniGrid->cities[0]; + $sparkCity = $site->mpmMiniGrid->villages[0]; $addressService = app()->make(AddressesService::class); $address = $person->addresses()->where('is_primary', 1)->first(); if ($address === null) { $addressParams = [ - 'city_id' => request()->input('city_id', $sparkCity->id), + 'village_id' => request()->input('village_id', $sparkCity->id), 'is_primary' => 1, ]; $address = $addressService->instantiate($addressParams); $addressService->assignAddressToOwner($person, $address); } else { $address->update([ - 'city_id' => request()->input('city_id', $sparkCity->id), + 'village_id' => request()->input('village_id', $sparkCity->id), ]); } DB::connection('tenant')->commit(); @@ -204,14 +204,14 @@ public function updateRelatedPerson(array $customer, Person $person, string $sit $sparkCustomerMeterSerial = $customer['meters'][0]['serial']; $currentTariffName = $customer['meters'][0]['current_tariff_name']; $site = $this->smSite->newQuery()->with('mpmMiniGrid')->where('site_id', $site_id)->firstOrFail(); - $sparkCity = $site->mpmMiniGrid->cities[0]; + $sparkCity = $site->mpmMiniGrid->villages[0]; $addressService = app()->make(AddressesService::class); $address = $person->addresses()->where('is_primary', 1)->first(); if ($address === null) { $addressParams = [ 'phone' => $customer['phone_number'], 'street' => $customer['meters'][0]['street1'], - 'city_id' => $sparkCity->id, + 'village_id' => $sparkCity->id, 'is_primary' => 1, ]; $address = $addressService->instantiate($addressParams); @@ -220,7 +220,7 @@ public function updateRelatedPerson(array $customer, Person $person, string $sit $address->update([ 'phone' => $customer['phone_number'], 'street' => $customer['meters'][0]['street1'], - 'city_id' => $sparkCity->id, + 'village_id' => $sparkCity->id, ]); } $meter = $person->devices()->first()->device; diff --git a/src/backend/app/Plugins/SparkMeter/Services/SiteService.php b/src/backend/app/Plugins/SparkMeter/Services/SiteService.php index a2bfd8d4f..0a8be4fe8 100644 --- a/src/backend/app/Plugins/SparkMeter/Services/SiteService.php +++ b/src/backend/app/Plugins/SparkMeter/Services/SiteService.php @@ -2,7 +2,7 @@ namespace App\Plugins\SparkMeter\Services; -use App\Models\City; +use App\Models\Village; use App\Models\Cluster; use App\Models\GeographicalInformation; use App\Models\MiniGrid; @@ -29,7 +29,7 @@ public function __construct( private OrganizationService $organizationService, private Cluster $cluster, private MiniGrid $miniGrid, - private City $city, + private Village $village, private GeographicalInformation $geographicalInformation, private SmSyncSettingService $smSyncSettingService, private SmSyncActionService $smSyncActionService, @@ -68,9 +68,9 @@ public function creteRelatedMiniGrid(array $site): MiniGrid { 'cluster_id' => $cluster->id, ]); - $cityName = explode('-', $site['name'])[1].' Village'; - $this->city->newQuery()->create([ - 'name' => $cityName, + $villageName = explode('-', $site['name'])[1].' Village'; + $this->village->newQuery()->create([ + 'name' => $villageName, 'mini_grid_id' => $miniGrid->id, 'cluster_id' => $miniGrid->cluster_id, ]); diff --git a/src/backend/app/Plugins/SteamaMeter/Services/SteamaAgentService.php b/src/backend/app/Plugins/SteamaMeter/Services/SteamaAgentService.php index 32a79e334..a96e18f37 100644 --- a/src/backend/app/Plugins/SteamaMeter/Services/SteamaAgentService.php +++ b/src/backend/app/Plugins/SteamaMeter/Services/SteamaAgentService.php @@ -174,13 +174,13 @@ public function createRelatedAgent(array $stmAgent): Agent { 'surname' => $stmAgent['last_name'], 'is_customer' => 0, ]); - $site = $this->site->newQuery()->with('mpmMiniGrid.cities')->where('site_id', $stmAgent['site'])->first(); + $site = $this->site->newQuery()->with('mpmMiniGrid.villages')->where('site_id', $stmAgent['site'])->first(); - $city = $site->mpmMiniGrid->cities->first(); + $village = $site->mpmMiniGrid->villages->first(); $addressService = app()->make(AddressesService::class); $addressParams = [ - 'city_id' => $city->id, + 'village_id' => $village->id, 'email' => '', 'phone' => $stmAgent['telephone'], 'street' => $stmAgent['site_name'], @@ -216,7 +216,7 @@ public function updateRelatedAgent(array $stmAgent, Agent $agent): Agent { $site = $this->site->newQuery()->with('mpmMiniGrid')->where('site_id', $stmAgent['site'])->first(); - $city = $site->mpmMiniGrid->cities->first(); + $village = $site->mpmMiniGrid->villages->first(); $personId = $relatedPerson->id; @@ -229,7 +229,7 @@ function ($q) use ($personId) { )->first(); $address->update([ - 'city_id' => $city->id, + 'village_id' => $village->id, 'phone' => $stmAgent['telephone'], 'street' => $stmAgent['site_name'], 'is_primary' => 1, diff --git a/src/backend/app/Plugins/SteamaMeter/Services/SteamaCustomerService.php b/src/backend/app/Plugins/SteamaMeter/Services/SteamaCustomerService.php index b8d795e14..2923c9d9b 100644 --- a/src/backend/app/Plugins/SteamaMeter/Services/SteamaCustomerService.php +++ b/src/backend/app/Plugins/SteamaMeter/Services/SteamaCustomerService.php @@ -2,7 +2,7 @@ namespace App\Plugins\SteamaMeter\Services; -use App\Models\City; +use App\Models\Village; use App\Models\Person\Person; use App\Plugins\SteamaMeter\Exceptions\ModelNotFoundException; use App\Plugins\SteamaMeter\Exceptions\SteamaApiResponseException; @@ -44,7 +44,7 @@ public function __construct( private SteamaPerKwhPaymentPlan $perKwhPaymentPlan, private SteamaUserType $userType, private SteamaSite $stmSite, - private City $city, + private Village $village, private SteamaSyncSettingService $steamaSyncSettingService, private StemaSyncActionService $steamaSyncActionService, private SteamaSmsNotifiedCustomerService $steamaSmsNotifiedCustomerService, @@ -183,7 +183,7 @@ public function createRelatedPerson(array $customer): Person { 'street1' => $customer['site_name'] ?: null, ]; $customerSite = $this->stmSite->newQuery()->with('mpmMiniGrid')->where('site_id', $customer['site'])->first(); - $customerCity = $this->city->newQuery()->where('mini_grid_id', $customerSite->mpmMiniGrid->id)->first(); + $customerCity = $this->village->newQuery()->where('mini_grid_id', $customerSite->mpmMiniGrid->id)->first(); $person = $this->person->newQuery()->create([ 'name' => $personData['name'], @@ -195,7 +195,7 @@ public function createRelatedPerson(array $customer): Person { 'phone' => $personData['phone'], 'street' => $personData['street1'], 'is_primary' => 1, - 'city_id' => $customerCity->id, + 'village_id' => $customerCity->id, ]; $address = $addressService->instantiate($addressParams); $addressService->assignAddressToOwner($person, $address); @@ -212,13 +212,13 @@ public function updateRelatedPerson(array $customer, Person $person): Person { 'surname' => $customer['last_name'] ?: '', ]); $customerSite = $this->stmSite->newQuery()->with('mpmMiniGrid')->where('site_id', $customer['site'])->first(); - $customerCity = $this->city->newQuery()->where('mini_grid_id', $customerSite->mpmMiniGrid->id)->first(); + $customerCity = $this->village->newQuery()->where('mini_grid_id', $customerSite->mpmMiniGrid->id)->first(); $address = $person->addresses()->where('is_primary', 1)->first(); $address->update([ 'phone' => $customer['telephone'] ?: null, 'street' => $customer['site_name'] ?: null, - 'city_id' => $customerCity->id, + 'village_id' => $customerCity->id, ]); return $person; diff --git a/src/backend/app/Plugins/SteamaMeter/Services/SteamaMeterService.php b/src/backend/app/Plugins/SteamaMeter/Services/SteamaMeterService.php index 6508568a0..e5d2b684e 100644 --- a/src/backend/app/Plugins/SteamaMeter/Services/SteamaMeterService.php +++ b/src/backend/app/Plugins/SteamaMeter/Services/SteamaMeterService.php @@ -3,7 +3,7 @@ namespace App\Plugins\SteamaMeter\Services; use App\Models\Address\Address; -use App\Models\City; +use App\Models\Village; use App\Models\ConnectionGroup; use App\Models\GeographicalInformation; use App\Models\Manufacturer; @@ -36,7 +36,7 @@ public function __construct( private SteamaCustomer $customer, private Manufacturer $manufacturer, private ConnectionGroup $connectionGroup, - private City $city, + private Village $village, private MeterType $meterType, private SteamaMeterType $stmMeterType, private SteamaTariff $tariff, @@ -206,15 +206,15 @@ public function createRelatedMeter(array $stmMeter): Meter { $tariff = $this->tariff->newQuery()->with('mpmTariff')->first(); $meter->tariff()->associate($tariff->mpmTariff); $meter->save(); - $stmCustomerAddress = $stmCustomer->mpmPerson->newQuery()->with('addresses.city') + $stmCustomerAddress = $stmCustomer->mpmPerson->newQuery()->with('addresses.village') ->whereHas('addresses', fn ($q) => $q->where('is_primary', 1))->first(); - $cityName = $stmCustomerAddress->addresses[0]->city->name; + $villageName = $stmCustomerAddress->addresses[0]->village->name; - $steamaCity = $this->city->newQuery()->with('miniGrid')->where('name', $cityName)->first(); + $steamaVillage = $this->village->newQuery()->with('miniGrid')->where('name', $villageName)->first(); $address = new Address(); $address = $address->newQuery()->create([ - 'city_id' => request()->input('city_id', $steamaCity->id), + 'village_id' => request()->input('village_id', $steamaVillage->id), ]); $address->owner()->associate($meter->device); $address->save(); diff --git a/src/backend/app/Plugins/SteamaMeter/Services/SteamaSiteService.php b/src/backend/app/Plugins/SteamaMeter/Services/SteamaSiteService.php index 479cf5a9c..d60f1658a 100644 --- a/src/backend/app/Plugins/SteamaMeter/Services/SteamaSiteService.php +++ b/src/backend/app/Plugins/SteamaMeter/Services/SteamaSiteService.php @@ -2,7 +2,7 @@ namespace App\Plugins\SteamaMeter\Services; -use App\Models\City; +use App\Models\Village; use App\Models\Cluster; use App\Models\GeographicalInformation; use App\Models\MiniGrid; @@ -28,7 +28,7 @@ public function __construct( private MiniGrid $miniGrid, private Cluster $cluster, private GeographicalInformation $geographicalInformation, - private City $city, + private Village $village, private SteamaSyncSettingService $steamaSyncSettingService, private StemaSyncActionService $steamaSyncActionService, ) {} @@ -147,7 +147,7 @@ public function creteRelatedMiniGrid(array $site): MiniGrid { 'name' => $site['name'], 'cluster_id' => $cluster->id, ]); - $this->city->newQuery()->create([ + $this->village->newQuery()->create([ 'name' => $miniGrid->name.' Village', 'mini_grid_id' => $miniGrid->id, 'cluster_id' => $miniGrid->cluster->id, diff --git a/src/backend/app/Providers/AppServiceProvider.php b/src/backend/app/Providers/AppServiceProvider.php index 8faa4c42e..de6a07c01 100644 --- a/src/backend/app/Providers/AppServiceProvider.php +++ b/src/backend/app/Providers/AppServiceProvider.php @@ -17,7 +17,7 @@ use App\Models\AgentReceipt; use App\Models\Appliance; use App\Models\ApplianceRate; -use App\Models\City; +use App\Models\Village; use App\Models\Cluster; use App\Models\Device; use App\Models\EBike; @@ -88,7 +88,7 @@ public function boot(): void { CashTransaction::RELATION_NAME => CashTransaction::class, Meter::RELATION_NAME => Meter::class, Device::RELATION_NAME => Device::class, - City::RELATION_NAME => City::class, + Village::RELATION_NAME => Village::class, Address::RELATION_NAME => Address::class, SolarHomeSystem::RELATION_NAME => SolarHomeSystem::class, Token::RELATION_NAME => Token::class, diff --git a/src/backend/app/Services/AddressesService.php b/src/backend/app/Services/AddressesService.php index b5bd54074..b94d006fe 100644 --- a/src/backend/app/Services/AddressesService.php +++ b/src/backend/app/Services/AddressesService.php @@ -24,7 +24,7 @@ public function __construct( */ public function instantiate(array $params): Address { return $this->address->fill([ - 'city_id' => $params['city_id'] ?? null, + 'village_id' => $params['village_id'] ?? null, 'email' => $params['email'] ?? null, 'phone' => $params['phone'], 'street' => $params['street'] ?? null, @@ -37,7 +37,7 @@ public function assignAddressToOwner(HasAddressesInterface $owner, Address $addr } public function getStoredAddressWithCityRelation(int $id): Address { - return $this->address::with('city')->findOrFail($id); + return $this->address::with('village')->findOrFail($id); } /** @@ -48,7 +48,7 @@ public function createAddressDataFromRequest(Request $request): array { 'email' => $request->get('email') ?? '', 'phone' => $request->get('phone') ?? '', 'street' => $request->get('street') ?? '', - 'city_id' => $request->get('city_id') ?? '', + 'village_id' => $request->get('village_id') ?? '', 'is_primary' => $request->get('is_primary') ?? 1, ]; } @@ -96,7 +96,7 @@ public function make(array $addressData): Address { 'email' => $addressData['email'] ?? null, 'phone' => $addressData['phone'] ?? null, 'street' => $addressData['street'] ?? null, - 'city_id' => $addressData['city_id'] ?? null, + 'village_id' => $addressData['village_id'] ?? null, 'is_primary' => $addressData['is_primary'] ?? 0, ]); } diff --git a/src/backend/app/Services/AgentCustomerService.php b/src/backend/app/Services/AgentCustomerService.php index 59d52e7eb..72b02d3ec 100644 --- a/src/backend/app/Services/AgentCustomerService.php +++ b/src/backend/app/Services/AgentCustomerService.php @@ -17,12 +17,12 @@ public function list(Agent $agent): LengthAwarePaginator { return $this->person->newQuery()->with([ 'devices', - 'addresses' => fn ($q) => $q->where('is_primary', 1)->with('city'), + 'addresses' => fn ($q) => $q->where('is_primary', 1)->with('village'), ]) ->where('is_customer', 1) ->whereHas( 'addresses', - fn ($q) => $q->whereHas('city', fn ($q) => $q->where('mini_grid_id', $miniGridId)) + fn ($q) => $q->whereHas('village', fn ($q) => $q->where('mini_grid_id', $miniGridId)) ) ->paginate(config('settings.paginate')); } @@ -31,7 +31,7 @@ public function list(Agent $agent): LengthAwarePaginator { * @return LengthAwarePaginator */ public function search(string $searchTerm, int $limit, Agent $agent): LengthAwarePaginator { - return $this->person->newQuery()->with(['addresses.city', 'devices'])->whereHas( + return $this->person->newQuery()->with(['addresses.village', 'devices'])->whereHas( 'addresses', fn ($q) => $q->where('phone', 'LIKE', '%'.$searchTerm.'%') )->orWhereHas( diff --git a/src/backend/app/Services/AgentCustomersPaymentHistoryService.php b/src/backend/app/Services/AgentCustomersPaymentHistoryService.php index f8bc25d79..f38d53645 100644 --- a/src/backend/app/Services/AgentCustomersPaymentHistoryService.php +++ b/src/backend/app/Services/AgentCustomersPaymentHistoryService.php @@ -71,8 +71,8 @@ public function getPaymentFlows(string $period, int $agentId, ?int $limit, strin CONCAT_WS("/", {$period}) AS period FROM payment_histories INNER JOIN addresses ON payment_histories.payer_id = addresses.owner_id - INNER JOIN cities ON addresses.city_id = cities.id - INNER JOIN mini_grids ON cities.mini_grid_id = mini_grids.id + INNER JOIN villages ON addresses.village_id = villages.id + INNER JOIN mini_grids ON villages.mini_grid_id = mini_grids.id INNER JOIN agents ON agents.mini_grid_id = mini_grids.id WHERE payment_service LIKE '%agent%' diff --git a/src/backend/app/Services/AgentSoldApplianceService.php b/src/backend/app/Services/AgentSoldApplianceService.php index ec9e3117b..a1a71205c 100644 --- a/src/backend/app/Services/AgentSoldApplianceService.php +++ b/src/backend/app/Services/AgentSoldApplianceService.php @@ -195,7 +195,7 @@ public function processSaleFromRequest(AgentSoldAppliance $agentSoldAppliance, a $addressFromCustomer = $appliancePerson->person()->first()->addresses()->first(); $addressData = $requestData['address'] ?? [ 'street' => $addressFromCustomer->street, - 'city_id' => $addressFromCustomer->city_id, + 'village_id' => $addressFromCustomer->village_id, ]; $points = $requestData['points'] ?? $addressFromCustomer->geo()->first()->points; @@ -204,7 +204,7 @@ public function processSaleFromRequest(AgentSoldAppliance $agentSoldAppliance, a $address = $this->addressesService->make([ 'street' => $addressData['street'], - 'city_id' => $addressData['city_id'], + 'village_id' => $addressData['village_id'], ]); // Attach the new address to the buyer (person) rather than the device. diff --git a/src/backend/app/Services/CityService.php b/src/backend/app/Services/CityService.php deleted file mode 100644 index ec42f7054..000000000 --- a/src/backend/app/Services/CityService.php +++ /dev/null @@ -1,72 +0,0 @@ - - */ -class CityService implements IBaseService { - public function __construct( - private City $city, - ) {} - - /** - * @return array - */ - public function getCityIdsByMiniGridId(int $miniGridId): array { - return $this->city->newQuery()->select('id')->where('mini_grid_id', $miniGridId)->get()->pluck('id')->toArray(); - } - - /** - * @param string|array $relation - */ - public function getByIdWithRelation(int $cityId, string|array $relation): ?City { - return $this->city->newQuery()->with($relation)->find($cityId); - } - - public function getById(int $cityId): ?Model { - return $this->city->newQuery()->find($cityId); - } - - /** - * @param array $cityData - */ - public function update(Model $model, array $cityData): Model { - $model->update([ - 'name' => $cityData['name'] ?? $model->name, - 'mini_grid_id' => $cityData['mini_grid_id'] ?? $model->mini_grid_id, - 'country_id' => $cityData['country_id'] ?? $model->country_id, - ]); - $model->fresh(); - - return $model; - } - - /** - * @param array $data - */ - public function create(array $data): Model { - return $this->city->newQuery()->create($data); - } - - /** - * @return Collection|LengthAwarePaginator - */ - public function getAll(?int $limit = null): Collection|LengthAwarePaginator { - if ($limit) { - return $this->city->newQuery()->with('location')->paginate($limit); - } - - return $this->city->newQuery()->with('location')->get(); - } - - public function delete(Model $model): ?bool { - throw new \Exception('not implemented'); - } -} diff --git a/src/backend/app/Services/ClusterDeviceService.php b/src/backend/app/Services/ClusterDeviceService.php index deb32a42b..22337639d 100644 --- a/src/backend/app/Services/ClusterDeviceService.php +++ b/src/backend/app/Services/ClusterDeviceService.php @@ -14,7 +14,7 @@ public function getCountByClusterId(int $clusterId): int { ->whereHas('person', function ($q) use ($clusterId) { $q->whereHas('addresses', function ($q) use ($clusterId) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($clusterId) { + ->whereHas('village', function ($q) use ($clusterId) { $q->where('cluster_id', $clusterId); }); }); @@ -27,11 +27,11 @@ public function getCountByClusterId(int $clusterId): int { */ public function getByClusterId(int $clusterId): Collection { return $this->device->newQuery() - ->with(['device', 'person.addresses.city']) + ->with(['device', 'person.addresses.village']) ->whereHas('person', function ($q) use ($clusterId) { $q->whereHas('addresses', function ($q) use ($clusterId) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($clusterId) { + ->whereHas('village', function ($q) use ($clusterId) { $q->whereHas('cluster', function ($q) use ($clusterId) { $q->where('clusters.id', $clusterId); }); @@ -53,7 +53,7 @@ public function getMetersByClusterId(int $clusterId): Collection { ->whereHas('person', function ($q) use ($clusterId) { $q->whereHas('addresses', function ($q) use ($clusterId) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($clusterId) { + ->whereHas('village', function ($q) use ($clusterId) { $q->whereHas('cluster', function ($q) use ($clusterId) { $q->where('clusters.id', $clusterId); }); diff --git a/src/backend/app/Services/ClusterMeterService.php b/src/backend/app/Services/ClusterMeterService.php index 90e2f52ed..8f3b9ca43 100644 --- a/src/backend/app/Services/ClusterMeterService.php +++ b/src/backend/app/Services/ClusterMeterService.php @@ -8,21 +8,12 @@ class ClusterMeterService { public function __construct(private Meter $meter) {} public function getCountById(int $clusterId): int { - return $this->meter->newQuery()->whereHas( - 'device', - function ($q) use ($clusterId) { - $q->whereHas( - 'address', - function ($q) use ($clusterId) { - $q->whereHas( - 'city', - function ($q) use ($clusterId) { - $q->where('cluster_id', $clusterId); - } - ); - } - ); - } - )->count(); + return $this->meter->newQuery() + ->whereHas('device.person.addresses.village', function ($q) use ($clusterId) { + $q->whereHas('miniGrid', function ($miniGridQuery) use ($clusterId) { + $miniGridQuery->where('cluster_id', $clusterId); + }); + }) + ->count(); } } diff --git a/src/backend/app/Services/ClusterPopulationService.php b/src/backend/app/Services/ClusterPopulationService.php index 1c370ae72..8282f37dc 100644 --- a/src/backend/app/Services/ClusterPopulationService.php +++ b/src/backend/app/Services/ClusterPopulationService.php @@ -15,7 +15,7 @@ public function getById(int $clusterId, bool $onlyCustomers = true): int { 'addresses', function ($q) use ($clusterId) { $q->where('is_primary', 1)->whereHas( - 'city', + 'village', function ($q) use ($clusterId) { $q->whereHas('cluster', function ($q) use ($clusterId) { $q->where('clusters.id', $clusterId); @@ -29,7 +29,7 @@ function ($q) use ($clusterId) { 'addresses', function ($q) use ($clusterId) { $q->where('is_primary', 1)->whereHas( - 'city', + 'village', function ($q) use ($clusterId) { $q->whereHas('cluster', function ($q) use ($clusterId) { $q->where('clusters.id', $clusterId); diff --git a/src/backend/app/Services/ClusterRevenueService.php b/src/backend/app/Services/ClusterRevenueService.php index 712a06bfa..cc9469e18 100644 --- a/src/backend/app/Services/ClusterRevenueService.php +++ b/src/backend/app/Services/ClusterRevenueService.php @@ -42,7 +42,7 @@ public function getTransactionsForMonthlyPeriodById( function ($q) use ($clusterId, $connectionType, $miniGridId) { $q->whereHas('person.addresses', function ($q) use ($clusterId, $miniGridId) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($clusterId, $miniGridId) { + ->whereHas('village', function ($q) use ($clusterId, $miniGridId) { if ($miniGridId) { $q->where('mini_grid_id', $miniGridId); } else { @@ -89,7 +89,7 @@ public function getTransactionsForWeeklyPeriod(int $clusterId, array $period, ?i function ($q) use ($clusterId, $connectionType) { $q->whereHas('person.addresses', function ($q) use ($clusterId) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($clusterId) { + ->whereHas('village', function ($q) use ($clusterId) { $q->whereHas('cluster', function ($q) use ($clusterId) { $q->where('clusters.id', $clusterId); }); diff --git a/src/backend/app/Services/ClusterService.php b/src/backend/app/Services/ClusterService.php index 9e1d5766e..46184753e 100644 --- a/src/backend/app/Services/ClusterService.php +++ b/src/backend/app/Services/ClusterService.php @@ -7,6 +7,8 @@ use App\Services\Interfaces\IBaseService; use Illuminate\Database\Eloquent\Collection; use Illuminate\Pagination\LengthAwarePaginator; +use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; /** * @implements IBaseService @@ -35,15 +37,17 @@ public function getClusterWithComputedData( } public function getClusterCities(int $clusterId): ?Cluster { - return Cluster::query()->with('cities')->find($clusterId); + return Cluster::query()->with(['villages', 'location'])->find($clusterId); } public function getClusterMiniGrids(int $clusterId): ?Cluster { - return Cluster::query()->with('miniGrids')->find($clusterId); + return Cluster::query()->with(['miniGrids', 'location'])->find($clusterId); } public function getGeoLocationById(int $clusterId): mixed { - return $this->cluster->newQuery()->select('geo_json')->find($clusterId)->geo_json; + $cluster = $this->cluster->newQuery()->with('location')->findOrFail($clusterId); + + return $cluster->geo_json; } /** @@ -64,14 +68,32 @@ public function getDateRangeFromRequest(?string $startDate, ?string $endDate): a } public function getById(int $clusterId): Cluster { - return $this->cluster->newQuery()->with(['miniGrids.location', 'cities'])->find($clusterId); + return $this->cluster->newQuery()->with(['miniGrids.location', 'villages', 'location'])->find($clusterId); } /** * @param array $clusterData */ public function create(array $clusterData): Cluster { - return $this->cluster->newQuery()->create($clusterData); + return DB::connection('tenant')->transaction(function () use ($clusterData): Cluster { + $geoJson = $clusterData['geo_json'] ?? null; + + // Keep legacy write only while clusters.geo_json exists. + if (! Schema::connection('tenant')->hasColumn('clusters', 'geo_json')) { + unset($clusterData['geo_json']); + } + + $cluster = $this->cluster->newQuery()->create($clusterData); + + if ($geoJson !== null) { + $cluster->location()->create([ + 'points' => '', + 'geo_json' => $geoJson, + ]); + } + + return $cluster->fresh('location'); + }); } /** @@ -79,10 +101,10 @@ public function create(array $clusterData): Cluster { */ public function getAll(?int $limit = null): Collection|LengthAwarePaginator { if ($limit !== null) { - return $this->cluster->newQuery()->with('miniGrids')->limit($limit)->get(); + return $this->cluster->newQuery()->with(['miniGrids', 'location'])->limit($limit)->get(); } - return $this->cluster->newQuery()->with('miniGrids')->get(); + return $this->cluster->newQuery()->with(['miniGrids', 'location'])->get(); } /** @@ -102,8 +124,9 @@ public function delete($model): ?bool { public function getAllForExport(): Collection { return $this->cluster->newQuery()->with([ 'miniGrids', - 'cities', + 'villages', 'manager', + 'location', ])->get(); } } diff --git a/src/backend/app/Services/ClusterTransactionService.php b/src/backend/app/Services/ClusterTransactionService.php index c6d476bb7..3d69c1aee 100644 --- a/src/backend/app/Services/ClusterTransactionService.php +++ b/src/backend/app/Services/ClusterTransactionService.php @@ -16,7 +16,7 @@ public function getById(int $clusterId, array $range): float { return $this->transaction->newQuery()->whereHas( 'device.person.addresses', function ($q) use ($clusterId) { - $q->where('is_primary', 1)->whereHas('city', function ($q) use ($clusterId) { + $q->where('is_primary', 1)->whereHas('village', function ($q) use ($clusterId) { $q->whereHas('cluster', function ($q) use ($clusterId) { $q->where('clusters.id', $clusterId); }); diff --git a/src/backend/app/Services/ClustersDashboardCacheDataService.php b/src/backend/app/Services/ClustersDashboardCacheDataService.php index 1206024e6..24a0be6f9 100644 --- a/src/backend/app/Services/ClustersDashboardCacheDataService.php +++ b/src/backend/app/Services/ClustersDashboardCacheDataService.php @@ -53,7 +53,7 @@ public function setData(array $dateRange = []): void { $revenue = $this->clusterTransactionsService->getById($cluster->id, $dateRange); $population = $this->clusterPopulationService->getById($cluster->id); - $citiesRevenue = $this->clusterRevenueService->getMonthlyMiniGridBasedRevenueById($cluster->id); + $villagesRevenue = $this->clusterRevenueService->getMonthlyMiniGridBasedRevenueById($cluster->id); $revenueAnalysis = $this->clusterRevenueService->getMonthlyRevenueAnalysisForConnectionTypesById( $cluster->id, $connectionTypes, @@ -73,7 +73,7 @@ public function setData(array $dateRange = []): void { meterCount: $meterCount, revenue: $revenue, population: $population, - citiesRevenue: $citiesRevenue, + villagesRevenue: $villagesRevenue, revenueAnalysis: $revenueAnalysis, period: $periodicRevenue['period'], periodWeekly: $periodicRevenue['periodWeekly'], diff --git a/src/backend/app/Services/CustomerRegistrationAppService.php b/src/backend/app/Services/CustomerRegistrationAppService.php index 8e128cbfb..2e2d21c36 100644 --- a/src/backend/app/Services/CustomerRegistrationAppService.php +++ b/src/backend/app/Services/CustomerRegistrationAppService.php @@ -32,7 +32,7 @@ public function createCustomer(AndroidAppRequest $request): Person { $connectionTypeId = $request->input('connection_type_id'); $connectionGroupId = $request->input('connection_group_id'); $tariffId = $request->input('tariff_id'); - $cityId = $request->input('city_id'); + $villageId = $request->input('village_id'); $geoPoints = $request->input('geo_points'); if (!$person instanceof Person) { $request->attributes->add(['is_customer' => 1]); @@ -57,7 +57,7 @@ public function createCustomer(AndroidAppRequest $request): Person { $this->meterDeviceService->assign(); $this->deviceService->save($device); $addressData = [ - 'city_id' => $cityId ?? 1, + 'village_id' => $villageId ?? 1, ]; $address = $this->addressService->make($addressData); $this->addressService->assignAddressToOwner($person, $address); diff --git a/src/backend/app/Services/DeviceService.php b/src/backend/app/Services/DeviceService.php index ae6b26d96..b5a5bd30f 100644 --- a/src/backend/app/Services/DeviceService.php +++ b/src/backend/app/Services/DeviceService.php @@ -26,7 +26,7 @@ public function make(mixed $deviceData): Device { public function getBySerialNumber(string $serialNumber): ?Device { return $this->device->newQuery() - ->with(['geo', 'device.manufacturer', 'person.addresses.city']) + ->with(['geo', 'device.manufacturer', 'person.addresses.village']) ->where('device_serial', $serialNumber) ->first(); } @@ -79,7 +79,7 @@ public function getAllForExport(?string $miniGridName = null, ?string $villageNa $query = $this->device->newQuery()->with([ 'person', 'device.manufacturer', - 'person.addresses.city', + 'person.addresses.village', 'tokens', 'appliance.applianceType', ]); @@ -88,7 +88,7 @@ public function getAllForExport(?string $miniGridName = null, ?string $villageNa $query->whereHas('person', function ($q) use ($miniGridName) { $q->whereHas('addresses', function ($q) use ($miniGridName) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($miniGridName) { + ->whereHas('village', function ($q) use ($miniGridName) { $q->whereHas('miniGrid', function ($q) use ($miniGridName) { $q->where('name', 'LIKE', '%'.$miniGridName.'%'); }); @@ -101,7 +101,7 @@ public function getAllForExport(?string $miniGridName = null, ?string $villageNa $query->whereHas('person', function ($q) use ($villageName) { $q->whereHas('addresses', function ($q) use ($villageName) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($villageName) { + ->whereHas('village', function ($q) use ($villageName) { $q->where('name', 'LIKE', '%'.$villageName.'%'); }); }); diff --git a/src/backend/app/Services/ExportServices/ClusterExportService.php b/src/backend/app/Services/ExportServices/ClusterExportService.php index e6ac5be59..435e7676a 100644 --- a/src/backend/app/Services/ExportServices/ClusterExportService.php +++ b/src/backend/app/Services/ExportServices/ClusterExportService.php @@ -29,14 +29,14 @@ public function writeClusterData(): void { public function setExportingData(): void { $this->exportingData = $this->clusterData->map(function (Cluster $cluster): array { $miniGridCount = $cluster->miniGrids->count(); - $cityCount = $cluster->cities->count(); + $villageCount = $cluster->villages->count(); $managerName = $cluster->manager->name ?? ''; return [ $cluster->name, $managerName, $miniGridCount, - $cityCount, + $villageCount, $this->convertUtcDateToTimezone($cluster->created_at), $this->convertUtcDateToTimezone($cluster->updated_at), ]; @@ -69,14 +69,14 @@ public function exportDataToArray(): array { // transform exporting data to JSON structure for cluster export $jsonDataTransform = $this->clusterData->map(function (Cluster $cluster): array { $miniGrids = $cluster->miniGrids->pluck('name')->filter()->implode(', '); - $cities = $cluster->cities->pluck('name')->filter()->implode(', '); + $villages = $cluster->villages->pluck('name')->filter()->implode(', '); $managerName = $cluster->manager->name ?? ''; return [ 'cluster_name' => $cluster->name, 'manager' => $managerName, 'mini_grids' => $miniGrids, - 'villages' => $cities, + 'villages' => $villages, 'created_at' => $this->convertUtcDateToTimezone($cluster->created_at), 'updated_at' => $this->convertUtcDateToTimezone($cluster->updated_at), ]; diff --git a/src/backend/app/Services/ExportServices/DeviceExportService.php b/src/backend/app/Services/ExportServices/DeviceExportService.php index b6c7877d8..a00816730 100644 --- a/src/backend/app/Services/ExportServices/DeviceExportService.php +++ b/src/backend/app/Services/ExportServices/DeviceExportService.php @@ -33,7 +33,7 @@ public function setExportingData(): void { $personSurname = $device->person->surname ?? ''; $fullName = trim($personName.' '.$personSurname); $primaryAddress = $device->person?->addresses->where('is_primary', 1)->first(); - $address = $primaryAddress?->city->name ?? ''; + $address = $primaryAddress?->village->name ?? ''; return [ $device->device_serial, @@ -98,7 +98,7 @@ public function exportDataToArray(): array { $primaryAddress = $device->person?->addresses->where('is_primary', 1)->first(); if ($primaryAddress) { $address = [ - 'city' => $primaryAddress->city->name ?? '', + 'village' => $primaryAddress->village->name ?? '', 'street' => $primaryAddress->street ?? '', ]; } diff --git a/src/backend/app/Services/ExportServices/PersonExportService.php b/src/backend/app/Services/ExportServices/PersonExportService.php index e294f4f64..fd94abe5f 100644 --- a/src/backend/app/Services/ExportServices/PersonExportService.php +++ b/src/backend/app/Services/ExportServices/PersonExportService.php @@ -44,7 +44,7 @@ public function setExportingData(): void { $person->gender, $primaryAddress?->email, $primaryAddress?->phone, - $primaryAddress?->city?->name, + $primaryAddress?->village?->name, $devices, $agent->person->name ?? '', ]; @@ -88,7 +88,7 @@ public function exportDataToArray(): array { 'gender' => $person->gender, 'email' => $primaryAddress?->email, 'phone' => $primaryAddress?->phone, - 'city' => $primaryAddress?->city?->name, + 'village' => $primaryAddress?->village?->name, 'devices' => $devices, 'agent' => $agent->person->name ?? '', ]; diff --git a/src/backend/app/Services/ManufacturerService.php b/src/backend/app/Services/ManufacturerService.php index c9c4c1875..ed061f47d 100644 --- a/src/backend/app/Services/ManufacturerService.php +++ b/src/backend/app/Services/ManufacturerService.php @@ -29,7 +29,7 @@ public function createManufacturerDataFromRequest(Request $request): array { } public function getById(int $manufacturerId): Manufacturer { - return $this->manufacturer->newQuery()->with(['address.city.country'])->findOrFail($manufacturerId); + return $this->manufacturer->newQuery()->with(['address.village.country'])->findOrFail($manufacturerId); } /** diff --git a/src/backend/app/Services/MeterRevenueService.php b/src/backend/app/Services/MeterRevenueService.php index 2735de2dc..08f7a91e2 100644 --- a/src/backend/app/Services/MeterRevenueService.php +++ b/src/backend/app/Services/MeterRevenueService.php @@ -58,9 +58,9 @@ public function getConnectionGroupBasedRevenueForCluster( ->where('addresses.is_primary', '=', 1); }) ->where('meters.connection_group_id', $connectionGroupId) - ->whereIn('addresses.city_id', function ($query) use ($clusterId) { + ->whereIn('addresses.village_id', function ($query) use ($clusterId) { $query->select('id') - ->from('cities') + ->from('villages') ->where('cluster_id', $clusterId); }); }) @@ -76,15 +76,15 @@ public function getConnectionGroupBasedRevenueForCluster( /** * @return \Illuminate\Database\Eloquent\Collection */ - public function getConnectionTypeBasedRevenueInWeeklyPeriodForCities( - string $cityIds, + public function getConnectionTypeBasedRevenueInWeeklyPeriodForVillages( + string $villageIds, int $connectionId, string $startDate, string $endDate, ): Collection { return Transaction::query() ->selectRaw('SUM(transactions.amount) as total, YEARWEEK(transactions.created_at, 3) as result_date') - ->whereIn('transactions.message', function ($query) use ($connectionId, $cityIds) { + ->whereIn('transactions.message', function ($query) use ($connectionId, $villageIds) { $query->select('serial_number') ->from('meters') ->join('devices', function ($join) { @@ -98,7 +98,7 @@ public function getConnectionTypeBasedRevenueInWeeklyPeriodForCities( ->where('addresses.is_primary', '=', 1); }) ->where('meters.connection_type_id', $connectionId) - ->whereIn('addresses.city_id', explode(',', $cityIds)); + ->whereIn('addresses.village_id', explode(',', $villageIds)); }) ->whereHasMorph( 'originalTransaction', @@ -142,9 +142,9 @@ public function getConnectionGroupBasedRevenueForMiniGrid( ->where('addresses.is_primary', '=', 1); }) ->where('meters.connection_group_id', $connectionGroupId) - ->whereIn('addresses.city_id', function ($query) use ($miniGridId) { + ->whereIn('addresses.village_id', function ($query) use ($miniGridId) { $query->select('id') - ->from('cities') + ->from('villages') ->where('mini_grid_id', $miniGridId); }); }) @@ -179,9 +179,9 @@ public function getMetersByConnectionGroupForMiniGrid( }) ->where('meters.connection_group_id', $connectionGroupId) ->whereDate('meters.created_at', '<=', $endDate) - ->whereIn('addresses.city_id', function ($query) use ($miniGridId) { + ->whereIn('addresses.village_id', function ($query) use ($miniGridId) { $query->select('id') - ->from('cities') + ->from('villages') ->where('mini_grid_id', $miniGridId); }) ->get() @@ -211,9 +211,9 @@ public function getRegisteredMetersByConnectionGroupInWeeklyPeriodForMiniGrid( }) ->leftJoin('connection_groups', 'connection_groups.id', '=', 'meters.connection_group_id') ->where('meters.connection_group_id', $connectionGroupId) - ->whereIn('addresses.city_id', function ($query) use ($miniGridId) { + ->whereIn('addresses.village_id', function ($query) use ($miniGridId) { $query->select('id') - ->from('cities') + ->from('villages') ->where('mini_grid_id', $miniGridId); }) ->whereBetween(DB::raw('DATE(meters.created_at)'), [$startDate, $endDate]) @@ -245,9 +245,9 @@ public function getRegisteredMetersByConnectionGroupInWeeklyPeriodForCluster( }) ->leftJoin('connection_groups', 'connection_groups.id', '=', 'meters.connection_group_id') ->where('meters.connection_group_id', $connectionGroupId) - ->whereIn('addresses.city_id', function ($query) use ($clusterId) { + ->whereIn('addresses.village_id', function ($query) use ($clusterId) { $query->select('id') - ->from('cities') + ->from('villages') ->where('cluster_id', $clusterId); }) ->whereBetween(DB::raw('DATE(meters.created_at)'), [$startDate, $endDate]) @@ -278,9 +278,9 @@ public function getMetersByConnectionGroupForCluster( }) ->where('meters.connection_group_id', $connectionGroupId) ->whereDate('meters.created_at', '<=', $endDate) - ->whereIn('addresses.city_id', function ($query) use ($clusterId) { + ->whereIn('addresses.village_id', function ($query) use ($clusterId) { $query->select('id') - ->from('cities') + ->from('villages') ->where('cluster_id', $clusterId); }) ->get() diff --git a/src/backend/app/Services/MeterService.php b/src/backend/app/Services/MeterService.php index 15294541f..4c7ac1a08 100644 --- a/src/backend/app/Services/MeterService.php +++ b/src/backend/app/Services/MeterService.php @@ -66,18 +66,18 @@ public function getUsedMetersGeoWithAccessRatePayments(): Collection { } /** - * @param array $cities + * @param array $villages * * @return Collection */ - public function getUsedMetersGeoWithAccessRatePaymentsInCities(array $cities): Collection { + public function getUsedMetersGeoWithAccessRatePaymentsInVillages(array $villages): Collection { return $this->meter->newQuery()->with(['device.geo', 'accessRatePayment']) ->whereHas( 'device', fn ($q) => $q->whereHas( 'address', - function ($q) use ($cities) { - $q->whereIn('city_id', $cities); + function ($q) use ($villages) { + $q->whereIn('village_id', $villages); } ) ) diff --git a/src/backend/app/Services/MiniGridDashboardCacheDataService.php b/src/backend/app/Services/MiniGridDashboardCacheDataService.php index f54e61cf7..5d35a8a59 100644 --- a/src/backend/app/Services/MiniGridDashboardCacheDataService.php +++ b/src/backend/app/Services/MiniGridDashboardCacheDataService.php @@ -3,7 +3,7 @@ namespace App\Services; use App\DTO\MiniGridDashboardData; -use App\Models\City; +use App\Models\Village; use App\Models\ConnectionGroup; use App\Models\Target; use App\Models\Ticket\Ticket; @@ -20,7 +20,7 @@ public function __construct( private Target $target, private ConnectionGroup $connectionGroup, private ConnectionGroupService $connectionGroupService, - private City $city, + private Village $village, private ConnectionTypeService $connectionTypeService, private PeriodService $periodService, private Ticket $ticket, @@ -118,8 +118,8 @@ public function setData($dateRange = []): void { $connectionsData[$connectionGroup->name] = $connectionData[0]['registered_connections'] ?? 0; } - $cities = $this->city::where('mini_grid_id', $miniGridId)->get(); - $cityIds = implode(',', $cities->pluck('id')->toArray()); + $villages = $this->village::where('mini_grid_id', $miniGridId)->get(); + $villageIds = implode(',', $villages->pluck('id')->toArray()); $initialData = array_fill_keys($connectionNames, ['revenue' => 0]); $response = $this->periodService->generatePeriodicList( @@ -129,8 +129,8 @@ public function setData($dateRange = []): void { $initialData ); foreach ($connectionsTypes as $connectionType) { - $tariffRevenue = $this->meterRevenueService->getConnectionTypeBasedRevenueInWeeklyPeriodForCities( - $cityIds, + $tariffRevenue = $this->meterRevenueService->getConnectionTypeBasedRevenueInWeeklyPeriodForVillages( + $villageIds, $connectionType->id, $startDate, $endDate diff --git a/src/backend/app/Services/MiniGridDeviceService.php b/src/backend/app/Services/MiniGridDeviceService.php index 7136bcee6..019edc0b0 100644 --- a/src/backend/app/Services/MiniGridDeviceService.php +++ b/src/backend/app/Services/MiniGridDeviceService.php @@ -22,7 +22,7 @@ public function getMetersByMiniGridId(int $miniGridId) { ->whereHas('person', function ($q) use ($miniGridId) { $q->whereHas('addresses', function ($q) use ($miniGridId) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($miniGridId) { + ->whereHas('village', function ($q) use ($miniGridId) { $q->where('mini_grid_id', $miniGridId); }); }); @@ -35,7 +35,7 @@ public function getMetersByMiniGridId(int $miniGridId) { */ public function getDevicesByMiniGridId(int $miniGridId): Collection { return $this->device->newQuery() - ->with(['device', 'geo', 'person.addresses.city']) + ->with(['device', 'geo', 'person.addresses.village']) ->whereHasMorph( 'device', '*' @@ -43,7 +43,7 @@ public function getDevicesByMiniGridId(int $miniGridId): Collection { ->whereHas('person', function ($q) use ($miniGridId) { $q->whereHas('addresses', function ($q) use ($miniGridId) { $q->where('is_primary', 1) - ->whereHas('city', function ($q) use ($miniGridId) { + ->whereHas('village', function ($q) use ($miniGridId) { $q->where('mini_grid_id', $miniGridId); }); }); diff --git a/src/backend/app/Services/PersonAddressService.php b/src/backend/app/Services/PersonAddressService.php index 6d10d3095..1e8b29b41 100644 --- a/src/backend/app/Services/PersonAddressService.php +++ b/src/backend/app/Services/PersonAddressService.php @@ -20,7 +20,7 @@ public function setOldPrimaryAddressToNotPrimary(): Person { } public function getPersonAddresses(Person $person): mixed { - return $person->addresses()->with('city', 'geo')->orderBy('is_primary', 'DESC')->paginate(5); + return $person->addresses()->with('village', 'geo')->orderBy('is_primary', 'DESC')->paginate(5); } public function setAssigned($address): void { diff --git a/src/backend/app/Services/PersonService.php b/src/backend/app/Services/PersonService.php index 3fb5e1f72..fc2bd6075 100644 --- a/src/backend/app/Services/PersonService.php +++ b/src/backend/app/Services/PersonService.php @@ -45,8 +45,8 @@ public function getDetails(int $personID, bool $allRelations = false): ?Person { return $this->person->newQuery()->with( [ 'addresses' => fn ($q) => $q->orderBy('is_primary') - ->with('city', fn ($q) => $q->whereHas('location')) - ->with('city.location') + ->with('village', fn ($q) => $q->whereHas('location')) + ->with('village.location') ->with('geo') ->get(), 'citizenship', @@ -62,7 +62,7 @@ public function getDetails(int $personID, bool $allRelations = false): ?Person { * @return Builder|Collection|LengthAwarePaginator */ public function searchPerson(string $searchTerm, $paginate, int $per_page): Builder|Collection|LengthAwarePaginator { - $query = $this->person->newQuery()->with(['addresses.city', 'devices'])->whereHas( + $query = $this->person->newQuery()->with(['addresses.village', 'devices'])->whereHas( 'addresses', fn ($q) => $q->where('phone', 'LIKE', $searchTerm.'%') )->orWhereHas( @@ -108,7 +108,7 @@ public function getBulkDetails(array $peopleId): Builder { return $this->person->newQuery()->with( [ 'addresses' => fn ($q) => $q->where('is_primary', '=', 1), - 'addresses.city', + 'addresses.village', 'citizenship', 'roleOwner.definitions', 'devices.device', @@ -179,7 +179,7 @@ public function getAll( ?int $customerType = 1, ?int $agentId = null, ?bool $activeCustomer = null, - ?int $cityId = null, + ?int $villageId = null, ?float $totalPaidMin = null, ?float $totalPaidMax = null, ?string $latestPaymentFrom = null, @@ -190,7 +190,7 @@ public function getAll( ): LengthAwarePaginator { $query = $this->person->newQuery() ->with([ - 'addresses.city', + 'addresses.village', 'devices', 'agentSoldAppliance', 'latestPayment', @@ -217,9 +217,9 @@ public function getAll( } } - if ($cityId) { - $query->whereHas('addresses', function ($q) use ($cityId) { - $q->where('city_id', $cityId) + if ($villageId) { + $query->whereHas('addresses', function ($q) use ($villageId) { + $q->where('village_id', $villageId) ->where('is_primary', 1); }); } @@ -289,12 +289,12 @@ public function getAll( $query->orderByRaw('('.$subquery->toSql().') '.$direction) ->addBinding($subquery->getBindings(), 'order'); }), - AllowedSort::callback('city', function (Builder $query, bool $descending, string $property) { + AllowedSort::callback('village', function (Builder $query, bool $descending, string $property) { $direction = $descending ? 'desc' : 'asc'; $subquery = DB::table('addresses', 'addr') ->select('c.name') - ->join('cities as c', 'c.id', '=', 'addr.city_id') + ->join('villages as c', 'c.id', '=', 'addr.village_id') ->whereColumn('addr.owner_id', 'people.id') ->where('addr.owner_type', 'person') ->where('addr.is_primary', 1) @@ -326,13 +326,13 @@ public function getAll( public function getAllForExport(?string $miniGridName = null, ?string $villageName = null, ?string $deviceType = null, ?bool $isActive = null): Collection|array { $query = $this->person->newQuery()->with([ 'addresses' => fn ($q) => $q->where('is_primary', 1), - 'addresses.city', + 'addresses.village', 'devices', ])->where('is_customer', 1); if ($miniGridName) { $query->whereHas('addresses', function ($q) use ($miniGridName) { - $q->whereHas('city', function ($q) use ($miniGridName) { + $q->whereHas('village', function ($q) use ($miniGridName) { $q->whereHas('miniGrid', function ($q) use ($miniGridName) { $q->where('name', 'LIKE', '%'.$miniGridName.'%'); }); @@ -342,7 +342,7 @@ public function getAllForExport(?string $miniGridName = null, ?string $villageNa if ($villageName) { $query->whereHas('addresses', function ($q) use ($villageName) { - $q->whereHas('city', function ($q) use ($villageName) { + $q->whereHas('village', function ($q) use ($villageName) { $q->where('name', 'LIKE', '%'.$villageName.'%'); }); }); @@ -383,7 +383,7 @@ public function createFromRequest(Request $request): Person { $addressService = app()->make(AddressesService::class); $addressParams = [ - 'city_id' => $request->get('city_id') ?? 1, + 'village_id' => $request->get('village_id') ?? 1, 'email' => $request->get('email') ?? '', 'phone' => $request->get('phone') ?? '', 'street' => $request->get('street') ?? '', diff --git a/src/backend/app/Services/TargetService.php b/src/backend/app/Services/TargetService.php index 6f257c811..0ddad9e2a 100644 --- a/src/backend/app/Services/TargetService.php +++ b/src/backend/app/Services/TargetService.php @@ -14,7 +14,7 @@ class TargetService { public function __construct(private Target $target) {} public function getById(int $targetId): Target { - return $this->target->newQuery()->with(['subTargets', 'city'])->find($targetId); + return $this->target->newQuery()->with(['subTargets', 'village'])->find($targetId); } public function create(CarbonImmutable $period, string $targetForType, ITargetAssignable $targetOwner): Target { diff --git a/src/backend/app/Services/UserAddressService.php b/src/backend/app/Services/UserAddressService.php index 29b1c0ba1..842745016 100644 --- a/src/backend/app/Services/UserAddressService.php +++ b/src/backend/app/Services/UserAddressService.php @@ -16,14 +16,14 @@ public function create(User $user, array $data): Address { 'email' => $data['email'] ?? '', 'phone' => $data['phone'] ?? '', 'street' => $data['street'] ?? '', - 'city_id' => $data['city_id'] ?? '', + 'village_id' => $data['village_id'] ?? '', ]); // delete address if exists $user->address()->delete(); $address->owner()->associate($user); $address->save(); - return $address->load(['city']); + return $address->load(['village']); } /** @@ -38,7 +38,7 @@ public function update(User $user, array $data): User { 'email' => $user->email, 'phone' => $data['phone'], 'street' => $data['street'], - 'city_id' => $data['city_id'], + 'village_id' => $data['village_id'], 'is_primary' => 1, ]); $address->owner()->associate($user); @@ -50,7 +50,7 @@ public function update(User $user, array $data): User { 'email' => $user->email, 'phone' => $data['phone'], 'street' => $data['street'], - 'city_id' => $data['city_id'], + 'village_id' => $data['village_id'], 'is_primary' => $address->is_primary, ]); diff --git a/src/backend/app/Services/CityGeographicalInformationService.php b/src/backend/app/Services/VillageGeographicalInformationService.php similarity index 68% rename from src/backend/app/Services/CityGeographicalInformationService.php rename to src/backend/app/Services/VillageGeographicalInformationService.php index 32e3f3590..ef7bf1391 100644 --- a/src/backend/app/Services/CityGeographicalInformationService.php +++ b/src/backend/app/Services/VillageGeographicalInformationService.php @@ -2,27 +2,27 @@ namespace App\Services; -use App\Models\City; +use App\Models\Village; use App\Models\GeographicalInformation; use App\Services\Interfaces\IAssignationService; /** - * @implements IAssignationService + * @implements IAssignationService */ -class CityGeographicalInformationService implements IAssignationService { +class VillageGeographicalInformationService implements IAssignationService { private GeographicalInformation $geographicInformation; - private City $city; + private Village $village; public function setAssigned($assigned): void { $this->geographicInformation = $assigned; } public function setAssignee($assignee): void { - $this->city = $assignee; + $this->village = $assignee; } public function assign(): GeographicalInformation { - $this->geographicInformation->owner()->associate($this->city); + $this->geographicInformation->owner()->associate($this->village); return $this->geographicInformation; } diff --git a/src/backend/app/Services/VillageService.php b/src/backend/app/Services/VillageService.php new file mode 100644 index 000000000..bbcf160c1 --- /dev/null +++ b/src/backend/app/Services/VillageService.php @@ -0,0 +1,72 @@ + + */ +class VillageService implements IBaseService { + public function __construct( + private Village $village, + ) {} + + /** + * @return array + */ + public function getVillageIdsByMiniGridId(int $miniGridId): array { + return $this->village->newQuery()->select('id')->where('mini_grid_id', $miniGridId)->get()->pluck('id')->toArray(); + } + + /** + * @param string|array $relation + */ + public function getByIdWithRelation(int $villageId, string|array $relation): ?Village { + return $this->village->newQuery()->with($relation)->find($villageId); + } + + public function getById(int $villageId): ?Model { + return $this->village->newQuery()->find($villageId); + } + + /** + * @param array $villageData + */ + public function update(Model $model, array $villageData): Model { + $model->update([ + 'name' => $villageData['name'] ?? $model->name, + 'mini_grid_id' => $villageData['mini_grid_id'] ?? $model->mini_grid_id, + 'country_id' => $villageData['country_id'] ?? $model->country_id, + ]); + $model->fresh(); + + return $model; + } + + /** + * @param array $data + */ + public function create(array $data): Model { + return $this->village->newQuery()->create($data); + } + + /** + * @return Collection|LengthAwarePaginator + */ + public function getAll(?int $limit = null): Collection|LengthAwarePaginator { + if ($limit) { + return $this->village->newQuery()->with('location')->paginate($limit); + } + + return $this->village->newQuery()->with('location')->get(); + } + + public function delete(Model $model): ?bool { + throw new \Exception('not implemented'); + } +} diff --git a/src/backend/bootstrap/app.php b/src/backend/bootstrap/app.php index 7847c5c2f..ec30b7121 100644 --- a/src/backend/bootstrap/app.php +++ b/src/backend/bootstrap/app.php @@ -83,8 +83,8 @@ ], 422)); }) ->withSchedule(function (Schedule $schedule) { - $schedule->command('reports:city-revenue weekly')->weeklyOn(1, '3:00'); - $schedule->command('reports:city-revenue monthly')->monthlyOn(1, '3:00'); + $schedule->command('reports:village-revenue weekly')->weeklyOn(1, '3:00'); + $schedule->command('reports:village-revenue monthly')->monthlyOn(1, '3:00'); $schedule->command('reports:ticket-outsource-payout')->monthlyOn(1, '3:30'); $schedule->command('sms:resend-rejected 5')->everyMinute(); $schedule->command('update:cachedClustersDashboardData')->everyFifteenMinutes(); diff --git a/src/backend/config/bulk-registration.php b/src/backend/config/bulk-registration.php index 86a8adaa6..e27c062b6 100644 --- a/src/backend/config/bulk-registration.php +++ b/src/backend/config/bulk-registration.php @@ -2,7 +2,7 @@ use App\Plugins\BulkRegistration\Services\AddressService; use App\Plugins\BulkRegistration\Services\ApplianceTypeService; -use App\Plugins\BulkRegistration\Services\CityService; +use App\Plugins\BulkRegistration\Services\VillageService; use App\Plugins\BulkRegistration\Services\ClusterService; use App\Plugins\BulkRegistration\Services\ConnectionGroupService; use App\Plugins\BulkRegistration\Services\ConnectionTypeService; @@ -33,7 +33,7 @@ 'name' => 'Mini Grid Name', ], - 'city' => [ + 'village' => [ 'cluster_id' => 'cluster_id', 'mini_grid_id' => 'mini_grid_id', 'name' => 'Village Name', @@ -41,7 +41,7 @@ 'address' => [ 'person_id' => 'person_id', - 'city_id' => 'city_id', + 'village_id' => 'village_id', 'phone' => 'Phone number', 'alternative_phone' => 'Alternate phone number', ], @@ -133,7 +133,7 @@ 'ClusterService' => ClusterService::class, 'MiniGridService' => MiniGridService::class, 'GeographicalInformationService' => GeographicalInformationService::class, - 'CityService' => CityService::class, + 'VillageService' => VillageService::class, 'AddressService' => AddressService::class, 'TariffService' => TariffService::class, 'ConnectionTypeService' => ConnectionTypeService::class, diff --git a/src/backend/database/factories/ClusterFactory.php b/src/backend/database/factories/ClusterFactory.php index 3865d51ab..3b9f95e9c 100644 --- a/src/backend/database/factories/ClusterFactory.php +++ b/src/backend/database/factories/ClusterFactory.php @@ -4,6 +4,7 @@ use App\Models\Cluster; use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Support\Facades\Schema; /** @extends Factory */ class ClusterFactory extends Factory { @@ -14,6 +15,19 @@ public function __construct( parent::__construct(...func_get_args()); $this->faker->addProvider(new \Faker\Provider\en_NG\Address($this->faker)); } + + public function configure(): static { + return $this->afterCreating(function (Cluster $cluster): void { + if ($cluster->location()->exists()) { + return; + } + + $cluster->location()->create([ + 'points' => '', + 'geo_json' => $this->buildDefaultGeoJson($cluster->name), + ]); + }); + } /** * Define the model's default state. @@ -24,27 +38,41 @@ public function definition(): array { // @phpstan-ignore-next-line varTag.unresolvableType /** @var \Faker\Generator&\Faker\Provider\en_NG\Address */ $faker = $this->faker; + $clusterName = 'Cluster '.$faker->county(); + $geoJson = $this->buildDefaultGeoJson($clusterName); return [ - 'name' => 'Cluster '.$faker->county(), - 'geo_json' => json_decode('{ - "type": "Feature", - "properties": { - "name": "Cluster '.$faker->county().'" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [34.09735878800838, -1.0021831137920607], - [34.08104951280351, -1.0037278294879668], - [34.08001945331692, -0.9961758791705448], - [34.079332746992485, -0.9831315606570004], - [34.08036280647911, -0.9745497443261169], - [34.09890387723834, -0.9889671831741885], - [34.09735878800838, -1.0021831137920607] - ] - } - }'), + 'name' => $clusterName, + // Kept for backward compatibility until tenant data migration removes the column. + ...($this->shouldPersistLegacyGeoJsonOnCluster() ? ['geo_json' => $geoJson] : []), ]; } + + /** + * @return array + */ + private function buildDefaultGeoJson(string $clusterName): array { + return [ + 'type' => 'Feature', + 'properties' => [ + 'name' => $clusterName, + ], + 'geometry' => [ + 'type' => 'Polygon', + 'coordinates' => [[ + [34.09735878800838, -1.0021831137920607], + [34.08104951280351, -1.0037278294879668], + [34.08001945331692, -0.9961758791705448], + [34.079332746992485, -0.9831315606570004], + [34.08036280647911, -0.9745497443261169], + [34.09890387723834, -0.9889671831741885], + [34.09735878800838, -1.0021831137920607], + ]], + ], + ]; + } + + private function shouldPersistLegacyGeoJsonOnCluster(): bool { + return Schema::connection('tenant')->hasColumn('clusters', 'geo_json'); + } } diff --git a/src/backend/database/factories/CityFactory.php b/src/backend/database/factories/VillageFactory.php similarity index 72% rename from src/backend/database/factories/CityFactory.php rename to src/backend/database/factories/VillageFactory.php index ccf8eef46..83c913180 100644 --- a/src/backend/database/factories/CityFactory.php +++ b/src/backend/database/factories/VillageFactory.php @@ -2,13 +2,13 @@ namespace Database\Factories; -use App\Models\City; +use App\Models\Village; use Faker\Provider\en_NG\Address; use Illuminate\Database\Eloquent\Factories\Factory; -/** @extends Factory */ -class CityFactory extends Factory { - protected $model = City::class; +/** @extends Factory */ +class VillageFactory extends Factory { + protected $model = Village::class; public function __construct( ) { @@ -23,7 +23,7 @@ public function __construct( */ public function definition(): array { return [ - 'name' => $this->faker->city, + 'name' => $this->faker->streetName, 'country_id' => 1, ]; } diff --git a/src/backend/database/migrations/tenant/2018_05_29_071453_create_addresses_table.php b/src/backend/database/migrations/tenant/2018_05_29_071453_create_addresses_table.php index 7a017b228..0f9948a99 100644 --- a/src/backend/database/migrations/tenant/2018_05_29_071453_create_addresses_table.php +++ b/src/backend/database/migrations/tenant/2018_05_29_071453_create_addresses_table.php @@ -17,12 +17,12 @@ public function up() { $table->string('email')->nullable(); $table->string('phone')->nullable(); $table->string('street')->nullable(); - $table->integer('city_id')->nullable(); + $table->integer('village_id')->nullable(); $table->integer('geo_id')->nullable(); $table->integer('is_primary')->default(0); $table->timestamps(); - // email, phone, street, city ,province, country, geo reference + // email, phone, street, village, province, country, geo reference }); } diff --git a/src/backend/database/migrations/tenant/2018_05_31_075346_create_cities_table.php b/src/backend/database/migrations/tenant/2018_05_31_075346_create_cities_table.php index fd6c3df0e..afa1053e8 100644 --- a/src/backend/database/migrations/tenant/2018_05_31_075346_create_cities_table.php +++ b/src/backend/database/migrations/tenant/2018_05_31_075346_create_cities_table.php @@ -11,7 +11,7 @@ * @return void */ public function up() { - Schema::connection('tenant')->create('cities', function (Blueprint $table) { + Schema::connection('tenant')->create('villages', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->integer('country_id'); @@ -27,6 +27,6 @@ public function up() { * @return void */ public function down() { - Schema::connection('tenant')->dropIfExists('cities'); + Schema::connection('tenant')->dropIfExists('villages'); } }; diff --git a/src/backend/database/migrations/tenant/2026_02_23_111733_remove_cluster_id_column_from_cities.php b/src/backend/database/migrations/tenant/2026_02_23_111733_remove_cluster_id_column_from_cities.php index 374458682..8ed29ce9d 100644 --- a/src/backend/database/migrations/tenant/2026_02_23_111733_remove_cluster_id_column_from_cities.php +++ b/src/backend/database/migrations/tenant/2026_02_23_111733_remove_cluster_id_column_from_cities.php @@ -1,6 +1,6 @@ table('cities', function (Blueprint $table) { + Schema::connection('tenant')->table('villages', function (Blueprint $table) { $table->dropColumn('cluster_id'); }); } @@ -20,18 +20,18 @@ public function up(): void { * Reverse the migrations. */ public function down(): void { - Schema::connection('tenant')->table('cities', function (Blueprint $table) { + Schema::connection('tenant')->table('villages', function (Blueprint $table) { $table->integer('cluster_id')->after('country_id'); }); - // Repopulate cluster_id from city -> minigrid -> cluster - City::with('miniGrid')->chunkById(100, function ($cities) { - foreach ($cities as $city) { - if ($city->miniGrid && $city->miniGrid->cluster_id) { - DB::connection('tenant')->table('cities') - ->where('id', $city->id) + // Repopulate cluster_id from village -> minigrid -> cluster + Village::with('miniGrid')->chunkById(100, function ($villages) { + foreach ($villages as $village) { + if ($village->miniGrid && $village->miniGrid->cluster_id) { + DB::connection('tenant')->table('villages') + ->where('id', $village->id) ->update([ - 'cluster_id' => $city->miniGrid->cluster_id, + 'cluster_id' => $village->miniGrid->cluster_id, ]); } } diff --git a/src/backend/database/migrations/tenant/2026_03_13_120000_move_cluster_geo_json_to_geographical_information.php b/src/backend/database/migrations/tenant/2026_03_13_120000_move_cluster_geo_json_to_geographical_information.php new file mode 100644 index 000000000..ac804a4a9 --- /dev/null +++ b/src/backend/database/migrations/tenant/2026_03_13_120000_move_cluster_geo_json_to_geographical_information.php @@ -0,0 +1,98 @@ +hasColumn('geographical_informations', 'geo_json')) { + $schema->table('geographical_informations', function (Blueprint $table): void { + $table->json('geo_json')->nullable()->after('points'); + }); + } + + if (! $schema->hasColumn('clusters', 'geo_json')) { + return; + } + + $clusters = DB::connection('tenant') + ->table('clusters') + ->select(['id', 'geo_json']) + ->whereNotNull('geo_json') + ->get(); + + foreach ($clusters as $cluster) { + $existingGeo = DB::connection('tenant') + ->table('geographical_informations') + ->where('owner_type', 'cluster') + ->where('owner_id', $cluster->id) + ->first(); + + if ($existingGeo) { + DB::connection('tenant') + ->table('geographical_informations') + ->where('id', $existingGeo->id) + ->update([ + 'geo_json' => $cluster->geo_json, + 'updated_at' => now(), + ]); + + continue; + } + + DB::connection('tenant') + ->table('geographical_informations') + ->insert([ + 'owner_id' => $cluster->id, + 'owner_type' => 'cluster', + 'points' => '', + 'geo_json' => $cluster->geo_json, + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + + $schema->table('clusters', function (Blueprint $table): void { + $table->dropColumn('geo_json'); + }); + } + + public function down(): void { + $schema = Schema::connection('tenant'); + + if (! $schema->hasColumn('clusters', 'geo_json')) { + $schema->table('clusters', function (Blueprint $table): void { + $table->json('geo_json')->nullable()->after('manager_id'); + }); + } + + if (! $schema->hasColumn('geographical_informations', 'geo_json')) { + return; + } + + $clusterGeo = DB::connection('tenant') + ->table('geographical_informations') + ->select(['owner_id', 'geo_json']) + ->where('owner_type', 'cluster') + ->whereNotNull('geo_json') + ->get(); + + foreach ($clusterGeo as $geoInfo) { + DB::connection('tenant') + ->table('clusters') + ->where('id', $geoInfo->owner_id) + ->update([ + 'geo_json' => $geoInfo->geo_json, + 'updated_at' => now(), + ]); + } + + $schema->table('geographical_informations', function (Blueprint $table): void { + $table->dropColumn('geo_json'); + }); + } +}; diff --git a/src/backend/database/migrations/tenant/2026_03_14_000001_rename_cities_to_villages.php b/src/backend/database/migrations/tenant/2026_03_14_000001_rename_cities_to_villages.php new file mode 100644 index 000000000..f35d7c57d --- /dev/null +++ b/src/backend/database/migrations/tenant/2026_03_14_000001_rename_cities_to_villages.php @@ -0,0 +1,62 @@ +hasTable('cities') && !$schema->hasTable('villages')) { + Schema::connection('tenant')->rename('cities', 'villages'); + } + + if ($schema->hasTable('addresses') && $schema->hasColumn('addresses', 'city_id') && !$schema->hasColumn('addresses', 'village_id')) { + Schema::connection('tenant')->table('addresses', function (Blueprint $table): void { + $table->renameColumn('city_id', 'village_id'); + }); + } + + if ($schema->hasTable('targets') && $schema->hasColumn('targets', 'city_id') && !$schema->hasColumn('targets', 'village_id')) { + Schema::connection('tenant')->table('targets', function (Blueprint $table): void { + $table->renameColumn('city_id', 'village_id'); + }); + } + + if ($schema->hasTable('geographical_informations')) { + DB::connection('tenant') + ->table('geographical_informations') + ->where('owner_type', 'city') + ->update(['owner_type' => 'village']); + } + } + + public function down(): void { + $schema = Schema::connection('tenant'); + + if ($schema->hasTable('targets') && $schema->hasColumn('targets', 'village_id') && !$schema->hasColumn('targets', 'city_id')) { + Schema::connection('tenant')->table('targets', function (Blueprint $table): void { + $table->renameColumn('village_id', 'city_id'); + }); + } + + if ($schema->hasTable('addresses') && $schema->hasColumn('addresses', 'village_id') && !$schema->hasColumn('addresses', 'city_id')) { + Schema::connection('tenant')->table('addresses', function (Blueprint $table): void { + $table->renameColumn('village_id', 'city_id'); + }); + } + + if ($schema->hasTable('villages') && !$schema->hasTable('cities')) { + Schema::connection('tenant')->rename('villages', 'cities'); + } + + if ($schema->hasTable('geographical_informations')) { + DB::connection('tenant') + ->table('geographical_informations') + ->where('owner_type', 'village') + ->update(['owner_type' => 'city']); + } + } +}; diff --git a/src/backend/database/seeders/AgentSeeder.php b/src/backend/database/seeders/AgentSeeder.php index cf4cae37a..28e93132f 100644 --- a/src/backend/database/seeders/AgentSeeder.php +++ b/src/backend/database/seeders/AgentSeeder.php @@ -42,7 +42,7 @@ public function run() { // For each Mini-Grid we create one Agent foreach ($minigrids as $minigrid) { - $village = $minigrid->cities()->get()->random(); + $village = $minigrid->villages()->get()->random(); $person = Person::factory() ->isAgent($village->name) @@ -54,7 +54,7 @@ public function run() { // https://github.com/larastan/larastan/issues/2307 // @phpstan-ignore argument.type ->state(function (array $attributes, Address $address) { - return ['points' => $address->city->location->points]; + return ['points' => $address->village->location->points]; }) ->randomizePointsInVillage(), 'geo' diff --git a/src/backend/database/seeders/ClusterSeeder.php b/src/backend/database/seeders/ClusterSeeder.php index 1fa173114..52926ba57 100644 --- a/src/backend/database/seeders/ClusterSeeder.php +++ b/src/backend/database/seeders/ClusterSeeder.php @@ -2,7 +2,7 @@ namespace Database\Seeders; -use App\Models\City; +use App\Models\Village; use App\Models\Cluster; use App\Models\GeographicalInformation; use App\Models\MiniGrid; @@ -40,56 +40,54 @@ public function run() { ->sequence( [ 'name' => 'Cluster Mafia Island', - 'geo_json' => json_decode( - '{ - "type": "Feature", - "properties": { - "name": "Cluster Mafia Island" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [39.961513, -7.630225], - [39.631923, -7.652002], - [39.549526, -7.910525], - [39.631923, -8.125383], - [39.934047, -8.092754], - [39.988979, -7.869716], - [39.961513, -7.630225] - ] - ] - } - }' - ), ], [ 'name' => 'Cluster Pemba Island', - 'geo_json' => json_decode( - '{ - "type": "Feature", - "properties": {}, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [39.770765, -4.800463], - [39.520826, -4.937297], - [39.545546, -5.421455], - [39.647169, -5.582757], - [39.905348, -5.448798], - [39.95204, -5.194467], - [39.899855, -4.86341], - [39.770765, -4.800463] - ] - ] - } - }' - ), ], ) ->create(); + $clusters[0]->location()->update([ + 'geo_json' => [ + 'type' => 'Feature', + 'properties' => [ + 'name' => 'Cluster Mafia Island', + ], + 'geometry' => [ + 'type' => 'Polygon', + 'coordinates' => [[ + [39.961513, -7.630225], + [39.631923, -7.652002], + [39.549526, -7.910525], + [39.631923, -8.125383], + [39.934047, -8.092754], + [39.988979, -7.869716], + [39.961513, -7.630225], + ]], + ], + ], + ]); + + $clusters[1]->location()->update([ + 'geo_json' => [ + 'type' => 'Feature', + 'properties' => (object) [], + 'geometry' => [ + 'type' => 'Polygon', + 'coordinates' => [[ + [39.770765, -4.800463], + [39.520826, -4.937297], + [39.545546, -5.421455], + [39.647169, -5.582757], + [39.905348, -5.448798], + [39.95204, -5.194467], + [39.899855, -4.86341], + [39.770765, -4.800463], + ]], + ], + ], + ]); + // MiniGrids and Villages on Mafia Island $miniGridsMafiaIsland = MiniGrid::factory() ->count(2) @@ -106,7 +104,7 @@ public function run() { 'location' ) ->has( - City::factory() + Village::factory() ->sequence( ['name' => 'Mafia Village'], ['name' => 'Jibondo Island Village'], @@ -139,7 +137,7 @@ public function run() { 'location' ) ->has( - City::factory() + Village::factory() ->sequence( ['name' => 'Konde Village'], ['name' => 'Wette Village'], diff --git a/src/backend/database/seeders/CustomerSeeder.php b/src/backend/database/seeders/CustomerSeeder.php index 644666ec5..ef7bfad76 100644 --- a/src/backend/database/seeders/CustomerSeeder.php +++ b/src/backend/database/seeders/CustomerSeeder.php @@ -3,7 +3,7 @@ namespace Database\Seeders; use App\Models\Address\Address; -use App\Models\City; +use App\Models\Village; use App\Models\GeographicalInformation; use App\Models\Person\Person; use App\Services\DatabaseProxyManagerService; @@ -23,7 +23,7 @@ public function __construct( */ public function run() { // Get available Villages - $villages = City::all(); + $villages = Village::all(); // For each Village generate customers foreach ($villages as $village) { @@ -38,7 +38,7 @@ public function run() { // https://github.com/larastan/larastan/issues/2307 // @phpstan-ignore argument.type ->state(function (array $attributes, Address $address) { - return ['points' => $address->city->location->points]; + return ['points' => $address->village->location->points]; }) ->randomizePointsInVillage(), 'geo' diff --git a/src/backend/database/seeders/TicketSeeder.php b/src/backend/database/seeders/TicketSeeder.php index fc18b8301..9f191132f 100644 --- a/src/backend/database/seeders/TicketSeeder.php +++ b/src/backend/database/seeders/TicketSeeder.php @@ -103,7 +103,7 @@ public function run() { // For each Mini-Grid we create one Maintenance User foreach ($minigrids as $minigrid) { - $village = $minigrid->cities()->get()->random(); + $village = $minigrid->villages()->get()->random(); $person = Person::factory() ->isMaintenanceUser($village->name) @@ -115,7 +115,7 @@ public function run() { // https://github.com/larastan/larastan/issues/2307 // @phpstan-ignore argument.type ->state(function (array $attributes, Address $address) { - return ['points' => $address->city->location->points]; + return ['points' => $address->village->location->points]; }) ->randomizePointsInVillage(), 'geo' diff --git a/src/backend/database/seeders/TransactionSeeder.php b/src/backend/database/seeders/TransactionSeeder.php index 16dd867fb..683603c74 100644 --- a/src/backend/database/seeders/TransactionSeeder.php +++ b/src/backend/database/seeders/TransactionSeeder.php @@ -128,8 +128,8 @@ private function generateTransaction(): void { $deviceSerial = $randomDevice->device_serial; if ($transactionType instanceof AgentTransaction) { - $city = $randomDevice->person->addresses()->first()->city()->first(); - $miniGrid = $city->miniGrid()->first(); + $village = $randomDevice->person->addresses()->first()->village()->first(); + $miniGrid = $village->miniGrid()->first(); // get a random agent from the mini grid $agent = $miniGrid->agents()->inRandomOrder()->first(); $transaction = (new TransactionFactory())->make([ @@ -157,8 +157,8 @@ private function generateTransaction(): void { $manufacturerTransaction = $this->getManufacturerTransactionFromDeviceType($deviceModel); if ($transactionType instanceof AgentTransaction) { - $city = $randomDevice->person->addresses()->first()->city()->first(); - $miniGrid = $city->miniGrid()->first(); + $village = $randomDevice->person->addresses()->first()->village()->first(); + $miniGrid = $village->miniGrid()->first(); $agent = $miniGrid->agents()->inRandomOrder()->first(); if (!$agent) { return; diff --git a/src/backend/resources/docs/responses/meters/meters.geo.list.json b/src/backend/resources/docs/responses/meters/meters.geo.list.json index 1626ef7c5..4def01861 100644 --- a/src/backend/resources/docs/responses/meters/meters.geo.list.json +++ b/src/backend/resources/docs/responses/meters/meters.geo.list.json @@ -21,7 +21,7 @@ "email": null, "phone": null, "street": null, - "city_id": 1, + "village_id": 1, "geo_id": 1, "created_at": "2020-01-09 07:05:49", "updated_at": "2020-01-09 07:05:49", diff --git a/src/backend/resources/docs/responses/people/people.detail.json b/src/backend/resources/docs/responses/people/people.detail.json index 622717096..3665ec6ec 100644 --- a/src/backend/resources/docs/responses/people/people.detail.json +++ b/src/backend/resources/docs/responses/people/people.detail.json @@ -20,7 +20,7 @@ "email": "", "phone": "+1111111111", "street": "-", - "city_id": 1, + "village_id": 1, "geo_id": null, "created_at": "2018-06-22 11:49:57", "updated_at": "2018-11-22 09:37:07" @@ -31,7 +31,7 @@ "email": "", "phone": "+1111111112", "street": "", - "city_id": 1, + "village_id": 1, "geo_id": null, "created_at": "2018-11-15 08:57:47", "updated_at": "2020-03-21 13:47:36" diff --git a/src/backend/resources/docs/responses/people/people.search.json b/src/backend/resources/docs/responses/people/people.search.json index a46186a7e..a8bb85519 100644 --- a/src/backend/resources/docs/responses/people/people.search.json +++ b/src/backend/resources/docs/responses/people/people.search.json @@ -22,11 +22,11 @@ "email": "", "phone": "+11111", "street": "-", - "city_id": 1, + "village_id": 1, "geo_id": null, "created_at": "2018-06-22 11:49:57", "updated_at": "2020-03-24 13:02:02", - "city": { + "village": { "id": 1, "name": "Some Village", "country_id": 215, @@ -42,11 +42,11 @@ "email": "", "phone": "+11111111", "street": "", - "city_id": 1, + "village_id": 1, "geo_id": null, "created_at": "2018-11-15 08:57:47", "updated_at": "2020-03-24 13:01:57", - "city": { + "village": { "id": 1, "name": "Some Village", "country_id": 215, diff --git a/src/backend/resources/docs/responses/people/person.addresses.list.json b/src/backend/resources/docs/responses/people/person.addresses.list.json index 765012d9f..30894fde8 100644 --- a/src/backend/resources/docs/responses/people/person.addresses.list.json +++ b/src/backend/resources/docs/responses/people/person.addresses.list.json @@ -7,11 +7,11 @@ "email": "", "phone": "+111111", "street": "-", - "city_id": 1, + "village_id": 1, "geo_id": null, "created_at": "2018-06-22 11:49:57", "updated_at": "2020-03-24 13:02:02", - "city": { + "village": { "id": 1, "name": "Some Village", "country_id": 1, @@ -28,11 +28,11 @@ "email": "", "phone": "+11111111111", "street": "", - "city_id": 1, + "village_id": 1, "geo_id": null, "created_at": "2018-11-15 08:57:47", "updated_at": "2020-03-24 13:01:57", - "city": { + "village": { "id": 1, "name": "Some Village", "country_id": 1, diff --git a/src/backend/routes/api.php b/src/backend/routes/api.php index 16cf8c688..af76efc0a 100644 --- a/src/backend/routes/api.php +++ b/src/backend/routes/api.php @@ -67,8 +67,8 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; -// Routes for City resource -require __DIR__.'/resources/Cities.php'; +// Routes for Village resource +require __DIR__.'/resources/Villages.php'; // Routes for Country resource require __DIR__.'/resources/Countries.php'; // Routes for meter resource @@ -151,7 +151,7 @@ Route::get('/revenue', [ClusterRevenueController::class, 'index']); Route::get('/{clusterId}/revenue', [ClusterRevenueController::class, 'show']); Route::get('/{clusterId}/revenue/analysis', [ClusterRevenueAnalysisController::class, 'show']); - Route::get('/{clusterId}/cities-revenue', [ClusterMiniGridRevenueController::class, 'show']); + Route::get('/{clusterId}/villages-revenue', [ClusterMiniGridRevenueController::class, 'show']); }); // Dashboard data from cache Route::group(['prefix' => '/dashboard', 'middleware' => 'jwt.verify'], static function () { diff --git a/src/backend/routes/resources/Cities.php b/src/backend/routes/resources/Cities.php deleted file mode 100644 index f9c9f5b7b..000000000 --- a/src/backend/routes/resources/Cities.php +++ /dev/null @@ -1,14 +0,0 @@ -prefix('cities') - ->group(function () { - Route::get('/', [CityController::class, 'index']); - Route::get('/{cityId}', [CityController::class, 'show'])->where('id', '[0-9]+'); - Route::post('/', [CityController::class, 'store'])->middleware('permission:settings'); - Route::put('/{cityId}', [CityController::class, 'update'])->middleware('permission:settings'); - }); diff --git a/src/backend/routes/resources/CustomerRegistrationApp.php b/src/backend/routes/resources/CustomerRegistrationApp.php index b782205bc..ebb4a0972 100644 --- a/src/backend/routes/resources/CustomerRegistrationApp.php +++ b/src/backend/routes/resources/CustomerRegistrationApp.php @@ -1,6 +1,6 @@ prefix('villages') + ->group(function () { + Route::get('/', [VillageController::class, 'index']); + Route::get('/{villageId}', [VillageController::class, 'show'])->where('villageId', '[0-9]+'); + Route::post('/', [VillageController::class, 'store'])->middleware('permission:settings'); + Route::put('/{villageId}', [VillageController::class, 'update'])->middleware('permission:settings'); + }); diff --git a/src/backend/tests/CreateEnvironments.php b/src/backend/tests/CreateEnvironments.php index 213d2a471..f15effe53 100644 --- a/src/backend/tests/CreateEnvironments.php +++ b/src/backend/tests/CreateEnvironments.php @@ -16,7 +16,7 @@ use Database\Factories\ApplianceFactory; use Database\Factories\AppliancePersonFactory; use Database\Factories\ApplianceTypeFactory; -use Database\Factories\CityFactory; +use Database\Factories\VillageFactory; use Database\Factories\ClusterFactory; use Database\Factories\ConnectionGroupFactory; use Database\Factories\ConnectionTypeFactory; @@ -44,7 +44,7 @@ trait CreateEnvironments { use WithFaker; private $user; - private $city; + private $village; private $cluster; private $miniGrid; private $connectionType; @@ -86,7 +86,7 @@ trait CreateEnvironments { private $subConnectionTypes = []; private $meterTypes = []; private $manufacturers = []; - private $cities = []; + private $villages = []; private $meterTariffs = []; private $targets = []; private $subTargets = []; @@ -142,19 +142,19 @@ protected function createMiniGrid($miniGridCount = 1) { } } - protected function createCity($cityCount = 1) { - while ($cityCount > 0) { - $city = CityFactory::new()->create([ - 'name' => $this->faker->citySuffix.$this->faker->randomAscii(), + protected function createVillage($villageCount = 1) { + while ($villageCount > 0) { + $village = VillageFactory::new()->create([ + 'name' => $this->faker->streetName.$this->faker->randomAscii(), 'country_id' => 1, 'mini_grid_id' => $this->getRandomIdFromList($this->miniGrids), ]); - $this->cities[] = $city; - --$cityCount; + $this->villages[] = $village; + --$villageCount; } - if (count($this->cities) > 0) { - $this->city = $this->cities[0]; + if (count($this->villages) > 0) { + $this->village = $this->villages[0]; } } @@ -182,7 +182,7 @@ protected function createMeterWithGeo(): void { $geographicalInformation = GeographicalInformation::query()->make(['points' => '111,222']); $this->person = PersonFactory::new()->create(); $addressData = [ - 'city_id' => $this->city->id, + 'village_id' => $this->village->id, 'geo_id' => $geographicalInformation->id, ]; @@ -190,7 +190,7 @@ protected function createMeterWithGeo(): void { 'email' => isset($addressData['email']) ?: null, 'phone' => isset($addressData['phone']) ?: null, 'street' => isset($addressData['street']) ?: null, - 'city_id' => isset($addressData['city_id']) ?: null, + 'village_id' => isset($addressData['village_id']) ?: null, 'geo_id' => isset($addressData['geo_id']) ?: null, 'is_primary' => isset($addressData['is_primary']) ?: 0, ]); @@ -254,7 +254,7 @@ protected function createMeterManufacturer($manufacturerCount = 1): void { 'email' => $this->faker->email, 'phone' => $this->faker->phoneNumber, 'street' => $this->faker->streetAddress, - 'city_id' => 1, + 'village_id' => 1, ]); $address->owner()->associate($manufacturer); $address->save(); @@ -352,7 +352,7 @@ protected function createMeter($meterCount = 1): void { $geographicalInformation = GeographicalInformation::query()->make(['points' => '111,222']); $person = PersonFactory::new()->create(); $addressData = [ - 'city_id' => $this->getRandomIdFromList($this->cities), + 'village_id' => $this->getRandomIdFromList($this->villages), 'geo_id' => $geographicalInformation->id, ]; @@ -360,7 +360,7 @@ protected function createMeter($meterCount = 1): void { 'email' => $addressData['email'] ?? null, 'phone' => $addressData['phone'] ?? null, 'street' => $addressData['street'] ?? null, - 'city_id' => $addressData['city_id'] ?? null, + 'village_id' => $addressData['village_id'] ?? null, 'geo_id' => $addressData['geo_id'] ?? null, 'is_primary' => $addressData['is_primary'] ?? 0, ]); @@ -404,7 +404,7 @@ protected function createPerson($personCount = 1, $isCustomer = 1) { 'email' => $this->faker->email, 'phone' => $this->faker->phoneNumber, 'street' => '', - 'city_id' => collect($this->cities)->random()['id'], + 'village_id' => collect($this->villages)->random()['id'], 'is_primary' => 1, ]); $address->owner()->associate($person)->save(); diff --git a/src/backend/tests/Feature/AddressTest.php b/src/backend/tests/Feature/AddressTest.php index 0c3bf70ee..79adceb1c 100644 --- a/src/backend/tests/Feature/AddressTest.php +++ b/src/backend/tests/Feature/AddressTest.php @@ -22,13 +22,13 @@ public function testUserDefinesAnAddressToCustomerForOwnCompany(): void { $person = PersonFactory::new()->create(); $this->createCluster(1); $this->createMiniGrid(1); - $this->createCity(1); + $this->createVillage(1); $response = $this->actingAs($user)->post(sprintf('/api/people/%s/addresses', $person->id), [ 'email' => $this->faker->email(), 'phone' => $this->faker->phoneNumber(), 'street' => $this->faker->streetAddress(), - 'city_id' => $this->city->id, + 'village_id' => $this->village->id, 'country_id' => 1, 'cluster_id' => $this->cluster->id, 'mini_grid_id' => $this->miniGrid->id, @@ -36,7 +36,7 @@ public function testUserDefinesAnAddressToCustomerForOwnCompany(): void { ]); $response->assertStatus(200); $this->assertEquals(1, $person->addresses()->count()); - $this->assertEquals($this->city->id, $person->addresses()->first()->city_id); + $this->assertEquals($this->village->id, $person->addresses()->first()->village_id); $this->assertEquals(1, $person->addresses()->first()->is_primary); } @@ -47,7 +47,7 @@ public function testUserUpdatesAndAddressOfCustomerForOwnCompany(): void { $person = PersonFactory::new()->create(); $this->createCluster(1); $this->createMiniGrid(1); - $this->createCity(1); + $this->createVillage(1); $address = AddressFactory::new()->make(); $address->owner()->associate($person); @@ -61,7 +61,7 @@ public function testUserUpdatesAndAddressOfCustomerForOwnCompany(): void { 'country_id' => 1, 'cluster_id' => $this->cluster->id, 'mini_grid_id' => $this->miniGrid->id, - 'city_id' => $this->city->id, + 'village_id' => $this->village->id, 'primary' => 0, ]); diff --git a/src/backend/tests/Feature/AgentAppTest.php b/src/backend/tests/Feature/AgentAppTest.php index 1115de6f3..520bee3a4 100644 --- a/src/backend/tests/Feature/AgentAppTest.php +++ b/src/backend/tests/Feature/AgentAppTest.php @@ -14,7 +14,7 @@ public function testAgentLogsIn(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $agent = $this->agent; @@ -33,7 +33,7 @@ public function testAgentGetsOwnData(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $agent = $this->agent; @@ -48,7 +48,7 @@ public function testAgentLogsOut(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $response = $this->actingAs($this->agent)->post('/api/app/logout'); @@ -60,7 +60,7 @@ public function testAgentRefreshesAuthToken(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $response = $this->actingAs($this->agent)->post('/api/app/refresh'); @@ -71,7 +71,7 @@ public function testAgentSetsFirebaseToken(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $postData = [ @@ -86,7 +86,7 @@ public function testAgentGetsBalance(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $agent = $this->agent; @@ -99,7 +99,7 @@ public function testAgentGetsCustomers(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createMeterType(); $this->createMeterTariff(); $this->createAgentCommission(); @@ -115,7 +115,7 @@ public function testAgentSearchesInCustomers(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createMeterType(); $this->createMeterTariff(); $this->createAgentCommission(); @@ -133,7 +133,7 @@ public function testAgentGetsCustomersPaymentFlow(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createPerson(); $this->createMeterType(); $this->createMeterTariff(); @@ -156,7 +156,7 @@ public function testAgentGetsCustomerPaymentFlowByCustomerId(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createPerson(); $this->createMeterType(); $this->createMeterTariff(); @@ -181,7 +181,7 @@ public function testAgentGetsCustomersTransactions(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createPerson(); $this->createMeterType(); $this->createMeterTariff(); @@ -204,7 +204,7 @@ public function testAgentGetsCustomerTransactionsByCustomerId(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createPerson(); $this->createMeterType(); $this->createMeterTariff(); @@ -227,7 +227,7 @@ public function testAgentGetsSoldAppliances(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->createAssignedAppliances(); @@ -242,7 +242,7 @@ public function testAgentGetsCustomerSoldAppliancesByCustomerId(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->createAssignedAppliances(); @@ -257,7 +257,7 @@ public function testAgentSalesAppliances(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->createAssignedAppliances(); @@ -277,7 +277,7 @@ public function testAgentGetsAssignedAppliances(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $assignedApplianceCount = 2; @@ -292,7 +292,7 @@ public function testAgentGetsApplicationDashboardBoxes(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createPerson(); $this->createMeterType(); $this->createMeterTariff(); @@ -319,7 +319,7 @@ public function testAgentGetsApplicationDashboardGraphValues(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createPerson(); $this->createMeterType(); $this->createMeterTariff(); @@ -341,7 +341,7 @@ public function testAgentGetsApplicationDashboardWeeklyRevenues(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createPerson(); $this->createMeterType(); $this->createMeterTariff(); diff --git a/src/backend/tests/Feature/AgentAppTicketsTest.php b/src/backend/tests/Feature/AgentAppTicketsTest.php index c4ae6cd03..81b5f4109 100644 --- a/src/backend/tests/Feature/AgentAppTicketsTest.php +++ b/src/backend/tests/Feature/AgentAppTicketsTest.php @@ -12,7 +12,7 @@ public function testAgentGetsTicketList(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->createTicketCategory(); @@ -28,7 +28,7 @@ public function testAgentGetsTicketById(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->createTicketCategory(); @@ -46,7 +46,7 @@ public function testAgentGetsTicketCustomerId(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->createTicketCategory(); @@ -66,7 +66,7 @@ public function testAgentCreatesATicket(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->createPerson(); diff --git a/src/backend/tests/Feature/AgentAssignedApplianceWebTest.php b/src/backend/tests/Feature/AgentAssignedApplianceWebTest.php index 713a6b19b..3326a503f 100644 --- a/src/backend/tests/Feature/AgentAssignedApplianceWebTest.php +++ b/src/backend/tests/Feature/AgentAssignedApplianceWebTest.php @@ -13,7 +13,7 @@ public function testUserGetsAgentsAssignedApplianceList(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $agentCount = 1; $this->createAgentCommission(); $this->createAgent($agentCount); @@ -28,7 +28,7 @@ public function testUserAssignsAnAssignedApplianceToAgent(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $agentCount = 1; $this->createAgentCommission(); $this->createAgent($agentCount); diff --git a/src/backend/tests/Feature/AgentBalanceHistoryWebTest.php b/src/backend/tests/Feature/AgentBalanceHistoryWebTest.php index 95fe39e4d..4ff5080be 100644 --- a/src/backend/tests/Feature/AgentBalanceHistoryWebTest.php +++ b/src/backend/tests/Feature/AgentBalanceHistoryWebTest.php @@ -12,7 +12,7 @@ public function testUserGetsAgentsBalanceHistories(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createPerson(); $this->createMeterType(); $this->createMeterTariff(); diff --git a/src/backend/tests/Feature/AgentChargeTest.php b/src/backend/tests/Feature/AgentChargeTest.php index b7c1df02d..d7a276218 100644 --- a/src/backend/tests/Feature/AgentChargeTest.php +++ b/src/backend/tests/Feature/AgentChargeTest.php @@ -13,7 +13,7 @@ public function testUserCreatesNewBalanceForAgent(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $agentBalance = $this->agents[0]->balance; diff --git a/src/backend/tests/Feature/AgentCommissionTest.php b/src/backend/tests/Feature/AgentCommissionTest.php index b7868f915..b8d13a001 100644 --- a/src/backend/tests/Feature/AgentCommissionTest.php +++ b/src/backend/tests/Feature/AgentCommissionTest.php @@ -22,7 +22,7 @@ public function testUserCreatesAgentCommission(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $postData = [ 'name' => 'test commission', diff --git a/src/backend/tests/Feature/AgentReceiptTest.php b/src/backend/tests/Feature/AgentReceiptTest.php index 4419106f3..ba42e57e6 100644 --- a/src/backend/tests/Feature/AgentReceiptTest.php +++ b/src/backend/tests/Feature/AgentReceiptTest.php @@ -13,7 +13,7 @@ public function testUserGetsAgentsReceipts(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createMeterType(); $this->createMeterTariff(); $this->createMeterManufacturer(); @@ -36,7 +36,7 @@ public function testUserGetsAllReceipts(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createMeterType(); $this->createMeterTariff(); $this->createMeterManufacturer(); @@ -56,7 +56,7 @@ public function testUserCreatesNewReceipt(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createMeterType(); $this->createMeterTariff(); $this->createMeterManufacturer(); diff --git a/src/backend/tests/Feature/AgentSoldApplianceWebTest.php b/src/backend/tests/Feature/AgentSoldApplianceWebTest.php index beceeba9d..6b26994ee 100644 --- a/src/backend/tests/Feature/AgentSoldApplianceWebTest.php +++ b/src/backend/tests/Feature/AgentSoldApplianceWebTest.php @@ -12,7 +12,7 @@ public function testUserGetsAgentsSoldApplianceList(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->createAssignedAppliances(); diff --git a/src/backend/tests/Feature/AgentTest.php b/src/backend/tests/Feature/AgentTest.php index 92018f11c..e3cfc7eb3 100644 --- a/src/backend/tests/Feature/AgentTest.php +++ b/src/backend/tests/Feature/AgentTest.php @@ -13,7 +13,7 @@ public function testUserGetsAgentList(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $agentCount = 4; $this->createAgent($agentCount); @@ -26,7 +26,7 @@ public function testUserGetsAgentById(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(4); $response = $this->actingAs($this->user)->get(sprintf('/api/agents/%s', $this->agents[0]->id)); @@ -38,7 +38,7 @@ public function testUserCreatesNewAgent(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $postData = [ 'name' => $this->faker->name(), @@ -49,7 +49,7 @@ public function testUserCreatesNewAgent(): void { 'mini_grid_id' => $this->miniGrid->id, 'phone' => $this->faker->phoneNumber(), 'agent_commission_id' => $this->agentCommissions[0]->id, - 'city_id' => $this->city->id, + 'village_id' => $this->village->id, ]; $response = $this->actingAs($this->user)->post('/api/agents', $postData); $response->assertStatus(201); @@ -63,7 +63,7 @@ public function testUserCanUpdateAnAgent(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); @@ -88,7 +88,7 @@ public function testUserCanResetsAgentsPassword(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); @@ -104,7 +104,7 @@ public function testUserCanSearchAnAgentByName(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); @@ -118,7 +118,7 @@ public function testUserCanDeleteAnAgent(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createAgentCommission(); $this->createAgent(); $this->actingAs($this->user)->delete(sprintf('/api/agents/%s', $this->agents[0]->id)); diff --git a/src/backend/tests/Feature/AgentTransactionWebTest.php b/src/backend/tests/Feature/AgentTransactionWebTest.php index 693a2eec6..4e6177338 100644 --- a/src/backend/tests/Feature/AgentTransactionWebTest.php +++ b/src/backend/tests/Feature/AgentTransactionWebTest.php @@ -12,7 +12,7 @@ public function testUserGetsAgentsTransactions(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createMeterType(); $this->createMeterTariff(); $this->createMeterManufacturer(); diff --git a/src/backend/tests/Feature/CityTest.php b/src/backend/tests/Feature/CityTest.php deleted file mode 100644 index 8a949722e..000000000 --- a/src/backend/tests/Feature/CityTest.php +++ /dev/null @@ -1,118 +0,0 @@ -createTestData($clusterCount, $miniGridCount); - $response = $this->actingAs($this->user)->get('/api/cities'); - $response->assertStatus(200); - $this->assertEquals(count($response['data']), count($this->cityIds)); - } - - public function testUserGetsCityById(): void { - $clusterCount = 1; - $miniGridCount = 1; - $cityCount = 1; - $this->createTestData($clusterCount, $miniGridCount, $cityCount); - $response = $this->actingAs($this->user)->get(sprintf('/api/cities/%s', $this->cityIds[0])); - $response->assertStatus(200); - $this->assertEquals($response['data']['id'], $this->cityIds[0]); - } - - public function testUserCreatesNewCity(): void { - $clusterCount = 1; - $miniGridCount = 1; - $cityCount = 1; - $this->createTestData($clusterCount, $miniGridCount, $cityCount); - $cityData = [ - 'mini_grid_id' => $this->miniGridIds[0], - 'country_id' => 1, - 'points' => '-7.873645,39.754433', - 'name' => $this->faker->city(), - ]; - $response = $this->actingAs($this->user)->post('/api/cities', $cityData); - $response->assertStatus(201); - $this->assertEquals($response['data']['name'], $cityData['name']); - } - - public function testUserUpdatesACity(): void { - $clusterCount = 2; - $miniGridCount = 2; - $this->createTestData($clusterCount, $miniGridCount); - $city = City::query()->first(); - $cityData = [ - 'name' => 'updatedName', - 'mini_grid_id' => $this->miniGridIds[1], - 'country_id' => 1, - 'points' => '-7.873645,39.754433', - ]; - $response = $this->actingAs($this->user)->put(sprintf('/api/cities/%s', $city->id), $cityData); - $response->assertStatus(200); - $this->assertEquals($response['data']['name'], $cityData['name']); - } - - protected function createTestData($clusterCount = 1, $miniGridCount = 1, $cityCount = 1) { - $this->user = UserFactory::new()->create(); - $this->assignRole($this->user, 'admin'); - - while ($clusterCount > 0) { - $cluster = ClusterFactory::new()->create([ - 'name' => $this->faker->unique()->companySuffix(), - 'manager_id' => $this->user->id, - ]); - $this->clusterIds[] = $cluster->id; - - while ($miniGridCount > 0) { - $geographicalInformation = GeographicalInformation::query()->make(['points' => '111,222']); - $miniGrid = MiniGridFactory::new()->create([ - 'cluster_id' => $cluster->id, - 'name' => $this->faker->unique()->companySuffix(), - ]); - - while ($cityCount > 0) { - $city = CityFactory::new()->create([ - 'name' => $this->faker->unique()->citySuffix(), - 'country_id' => 1, - 'mini_grid_id' => $miniGrid->id, - ]); - $this->cityIds[] = $city->id; - --$cityCount; - } - - $geographicalInformation->owner()->associate($miniGrid); - $geographicalInformation->save(); - $this->miniGridIds[] = $miniGrid->id; - --$miniGridCount; - } - - --$clusterCount; - } - } - - protected function generateUniqueNumber(): int { - return $this->faker->unique()->randomNumber() + $this->faker->unique()->randomNumber() + - $this->faker->unique()->randomNumber(); - } -} diff --git a/src/backend/tests/Feature/ManufacturerTest.php b/src/backend/tests/Feature/ManufacturerTest.php index 16d6797a9..5e9f1978d 100644 --- a/src/backend/tests/Feature/ManufacturerTest.php +++ b/src/backend/tests/Feature/ManufacturerTest.php @@ -29,13 +29,13 @@ public function testUserCreatesNewManufacturer(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $manufacturerData = [ 'name' => 'test meters company', 'website' => $this->faker->url(), 'api_name' => $this->faker->name(), 'email' => 'test@test.com', - 'city_id' => $this->cities[0]->id, + 'village_id' => $this->villages[0]->id, 'phone' => $this->faker->phoneNumber(), ]; $response = $this->actingAs($this->user)->post('/api/manufacturers', $manufacturerData); diff --git a/src/backend/tests/Feature/MeterTariffTest.php b/src/backend/tests/Feature/MeterTariffTest.php index fff147bdc..1b6b0607b 100644 --- a/src/backend/tests/Feature/MeterTariffTest.php +++ b/src/backend/tests/Feature/MeterTariffTest.php @@ -186,7 +186,7 @@ public function testUserGetsMeterListForATariff(): void { $this->createConnectionGroup(1); $this->createCluster(2); $this->createMiniGrid(2); - $this->createCity(2); + $this->createVillage(2); $meterCount = 5; $this->createMeter($meterCount); $response = $this->actingAs($this->user)->get(sprintf( diff --git a/src/backend/tests/Feature/MeterTest.php b/src/backend/tests/Feature/MeterTest.php index 99bd5e5da..bd4ef572a 100644 --- a/src/backend/tests/Feature/MeterTest.php +++ b/src/backend/tests/Feature/MeterTest.php @@ -168,7 +168,7 @@ protected function createTestData() { $this->user->syncRoles('admin'); $this->createCluster(1); $this->createMiniGrid(1); - $this->createCity(1); + $this->createVillage(1); $this->manufacturer = ManufacturerFactory::new()->create(); $this->meterType = MeterTypeFactory::new()->create(); $this->meterTariff = TariffFactory::new()->create(); @@ -204,7 +204,7 @@ protected function createMeterWithGeo(): void { $geographicalInformation = GeographicalInformation::query()->make(['points' => '111,222']); $person = PersonFactory::new()->create(); $addressData = [ - 'city_id' => $this->city->id, + 'village_id' => $this->village->id, 'geo_id' => $geographicalInformation->id, ]; @@ -212,7 +212,7 @@ protected function createMeterWithGeo(): void { 'email' => isset($addressData['email']) ?: null, 'phone' => isset($addressData['phone']) ?: null, 'street' => isset($addressData['street']) ?: null, - 'city_id' => isset($addressData['city_id']) ?: null, + 'village_id' => isset($addressData['village_id']) ?: null, 'geo_id' => isset($addressData['geo_id']) ?: null, 'is_primary' => isset($addressData['is_primary']) ?: 0, ]); diff --git a/src/backend/tests/Feature/MeterTypeTest.php b/src/backend/tests/Feature/MeterTypeTest.php index 78e369336..f444db390 100644 --- a/src/backend/tests/Feature/MeterTypeTest.php +++ b/src/backend/tests/Feature/MeterTypeTest.php @@ -80,7 +80,7 @@ public function testUserGetsMeterTypesWithMeterRelationByMeterTypeId(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createMeterTariff(); $this->createConnectionGroup(); $this->createConnectionType($connectionTypeCount); diff --git a/src/backend/tests/Feature/MiniGridTest.php b/src/backend/tests/Feature/MiniGridTest.php index cb32743b5..0c0afb186 100644 --- a/src/backend/tests/Feature/MiniGridTest.php +++ b/src/backend/tests/Feature/MiniGridTest.php @@ -4,7 +4,7 @@ use App\Models\GeographicalInformation; use App\Models\MiniGrid; -use Database\Factories\CityFactory; +use Database\Factories\VillageFactory; use Database\Factories\ClusterFactory; use Database\Factories\MiniGridFactory; use Database\Factories\UserFactory; @@ -25,7 +25,12 @@ public function testUserGetsMiniGridList(): void { $this->createTestData($clusterCount, $miniGridCount); $response = $this->actingAs($this->user)->get('/api/mini-grids'); $response->assertStatus(200); - $this->assertEquals(count($response['data']), count($this->miniGridIds)); + $miniGridList = $this->getResponseCollection($response); + $returnedMiniGridIds = array_values(array_filter(array_column($miniGridList, 'id'), 'is_int')); + + foreach ($this->miniGridIds as $miniGridId) { + $this->assertContains($miniGridId, $returnedMiniGridIds); + } } public function testUserGetsMiniGridById(): void { @@ -34,7 +39,8 @@ public function testUserGetsMiniGridById(): void { $this->createTestData($clusterCount, $miniGridCount); $response = $this->actingAs($this->user)->get(sprintf('/api/mini-grids/%s', $this->miniGridIds[0])); $response->assertStatus(200); - $this->assertEquals($response['data']['id'], $this->miniGridIds[0]); + $miniGridPayload = $this->getResponsePayload($response); + $this->assertEquals($this->miniGridIds[0], $miniGridPayload['id']); } public function testUserGetsMiniGridByIdWithGeographicalInformation(): void { @@ -43,7 +49,8 @@ public function testUserGetsMiniGridByIdWithGeographicalInformation(): void { $this->createTestData($clusterCount, $miniGridCount); $response = $this->actingAs($this->user)->get(sprintf('/api/mini-grids/%s?relation=1', $this->miniGridIds[0])); $response->assertStatus(200); - $this->assertEquals(array_key_exists('location', $response['data']), true); + $miniGridPayload = $this->getResponsePayload($response); + $this->assertEquals(array_key_exists('location', $miniGridPayload), true); } public function testUserCreatesNewMiniGrid(): void { @@ -56,9 +63,60 @@ public function testUserCreatesNewMiniGrid(): void { 'geo_data' => $this->faker->latitude().','.$this->faker->longitude(), ]; $response = $this->actingAs($this->user)->post('/api/mini-grids', $miGridData); - $response->assertStatus(201); - $this->assertEquals($response['data']['name'], $miGridData['name']); - $this->assertEquals(count(MiniGrid::query()->get()), 1); + $this->assertContains($response->status(), [200, 201]); + $miniGridPayload = $this->getResponsePayload($response); + $this->assertEquals($miGridData['name'], $miniGridPayload['name']); + $this->assertTrue( + MiniGrid::query()->where('name', $miGridData['name'])->where('cluster_id', $this->clusterIds[0])->exists() + ); + } + + /** + * @return array> + */ + private function getResponseCollection(mixed $response): array { + /** @var mixed $json */ + $json = $response->json(); + + if (!is_array($json)) { + return []; + } + + if (array_key_exists('data', $json) && is_array($json['data']) && array_is_list($json['data'])) { + /** @var array> $data */ + $data = $json['data']; + + return $data; + } + + if (array_is_list($json)) { + /** @var array> $json */ + return $json; + } + + return []; + } + + /** + * @return array + */ + private function getResponsePayload(mixed $response): array { + /** @var mixed $json */ + $json = $response->json(); + + if (!is_array($json)) { + return []; + } + + if (array_key_exists('data', $json) && is_array($json['data']) && !array_is_list($json['data'])) { + /** @var array $data */ + $data = $json['data']; + + return $data; + } + + /** @var array $json */ + return $json; } protected function createTestData($clusterCount = 1, $miniGridCount = 1) { @@ -80,8 +138,8 @@ protected function createTestData($clusterCount = 1, $miniGridCount = 1) { ]); $geographicalInformation->owner()->associate($miniGrid); $geographicalInformation->save(); - CityFactory::new()->create([ - 'name' => $this->faker->citySuffix().$this->faker->randomAscii(), + VillageFactory::new()->create([ + 'name' => $this->faker->streetName().$this->faker->randomAscii(), 'country_id' => 1, 'mini_grid_id' => $miniGrid->id, ]); diff --git a/src/backend/tests/Feature/TargetTest.php b/src/backend/tests/Feature/TargetTest.php index ecb4ea33f..f92653d92 100644 --- a/src/backend/tests/Feature/TargetTest.php +++ b/src/backend/tests/Feature/TargetTest.php @@ -12,7 +12,7 @@ public function testUserGetsTargetList(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createConnectionGroup(); $targetCount = 2; $this->createTarget($targetCount); @@ -25,7 +25,7 @@ public function testUserGetsTargetById(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createConnectionGroup(); $targetCount = 2; $this->createTarget($targetCount); @@ -39,7 +39,7 @@ public function testUserCreatesNewTarget(): void { $this->createTestData(); $this->createCluster(); $this->createMiniGrid(); - $this->createCity(); + $this->createVillage(); $this->createConnectionGroup(); $targetData = [ 'data' => [ diff --git a/src/backend/tests/Feature/TicketTest.php b/src/backend/tests/Feature/TicketTest.php index 5d5c1c357..7e1a5a9a7 100644 --- a/src/backend/tests/Feature/TicketTest.php +++ b/src/backend/tests/Feature/TicketTest.php @@ -21,7 +21,7 @@ public function testUserCreatesATicket(): void { $this->createTestData(); $this->createCluster(1); $this->createMiniGrid(1); - $this->createCity(1); + $this->createVillage(1); $this->createPerson(); $this->createTicketCategory(); $this->createTicketUser($this->user->id); @@ -43,7 +43,7 @@ public function testUserGetsTicketList(): void { $this->createTestData(); $this->createCluster(1); $this->createMiniGrid(1); - $this->createCity(1); + $this->createVillage(1); $this->createPerson(); $this->createTicketCategory(); $this->createTicketUser($this->user->id); @@ -57,7 +57,7 @@ public function testUserClosesATicket(): void { $this->createTestData(); $this->createCluster(1); $this->createMiniGrid(1); - $this->createCity(1); + $this->createVillage(1); $this->createPerson(); $this->createTicketCategory(); $this->createTicketUser($this->user->id); @@ -71,7 +71,7 @@ public function testUserGetsAgentsTicketList(): void { $this->createTestData(); $this->createCluster(1); $this->createMiniGrid(1); - $this->createCity(1); + $this->createVillage(1); $this->createPerson(); $this->createAgentCommission(); $this->createAgent(); @@ -111,7 +111,7 @@ public function testUserGetsTicketListForACustomer(): void { $this->createTestData(); $this->createCluster(1); $this->createMiniGrid(1); - $this->createCity(1); + $this->createVillage(1); $this->createPerson(); $this->createAgentCommission(); $this->createAgent(); diff --git a/src/backend/tests/Feature/VillageTest.php b/src/backend/tests/Feature/VillageTest.php new file mode 100644 index 000000000..0daa7b4b0 --- /dev/null +++ b/src/backend/tests/Feature/VillageTest.php @@ -0,0 +1,174 @@ +createTestData($clusterCount, $miniGridCount); + $response = $this->actingAs($this->user)->get('/api/villages'); + $response->assertStatus(200); + $villageList = $this->getResponseCollection($response); + $returnedVillageIds = array_values(array_filter(array_column($villageList, 'id'), 'is_int')); + + foreach ($this->villageIds as $villageId) { + $this->assertContains($villageId, $returnedVillageIds); + } + } + + public function testUserGetsVillageById(): void { + $clusterCount = 1; + $miniGridCount = 1; + $villageCount = 1; + $this->createTestData($clusterCount, $miniGridCount, $villageCount); + $response = $this->actingAs($this->user)->get(sprintf('/api/villages/%s', $this->villageIds[0])); + $response->assertStatus(200); + $villagePayload = $this->getResponsePayload($response); + $this->assertEquals($this->villageIds[0], $villagePayload['id']); + } + + public function testUserCreatesNewVillage(): void { + $clusterCount = 1; + $miniGridCount = 1; + $villageCount = 1; + $this->createTestData($clusterCount, $miniGridCount, $villageCount); + $villageData = [ + 'mini_grid_id' => $this->miniGridIds[0], + 'country_id' => 1, + 'points' => '-7.873645,39.754433', + 'name' => $this->faker->streetName(), + ]; + $response = $this->actingAs($this->user)->post('/api/villages', $villageData); + $this->assertContains($response->status(), [200, 201]); + $villagePayload = $this->getResponsePayload($response); + $this->assertEquals($villageData['name'], $villagePayload['name']); + } + + public function testUserUpdatesAVillage(): void { + $clusterCount = 2; + $miniGridCount = 2; + $this->createTestData($clusterCount, $miniGridCount); + $village = Village::query()->first(); + $villageData = [ + 'name' => 'updatedName', + 'mini_grid_id' => $this->miniGridIds[1], + 'country_id' => 1, + 'points' => '-7.873645,39.754433', + ]; + $response = $this->actingAs($this->user)->put(sprintf('/api/villages/%s', $village->id), $villageData); + $response->assertStatus(200); + $villagePayload = $this->getResponsePayload($response); + $this->assertEquals($villageData['name'], $villagePayload['name']); + } + + /** + * @return array> + */ + private function getResponseCollection(mixed $response): array { + /** @var mixed $json */ + $json = $response->json(); + + if (!is_array($json)) { + return []; + } + + if (array_key_exists('data', $json) && is_array($json['data']) && array_is_list($json['data'])) { + /** @var array> $data */ + $data = $json['data']; + + return $data; + } + + if (array_is_list($json)) { + /** @var array> $json */ + return $json; + } + + return []; + } + + /** + * @return array + */ + private function getResponsePayload(mixed $response): array { + /** @var mixed $json */ + $json = $response->json(); + + if (!is_array($json)) { + return []; + } + + if (array_key_exists('data', $json) && is_array($json['data']) && !array_is_list($json['data'])) { + /** @var array $data */ + $data = $json['data']; + + return $data; + } + + /** @var array $json */ + return $json; + } + + protected function createTestData($clusterCount = 1, $miniGridCount = 1, $villageCount = 1) { + $this->user = UserFactory::new()->create(); + $this->assignRole($this->user, 'admin'); + + while ($clusterCount > 0) { + $cluster = ClusterFactory::new()->create([ + 'name' => $this->faker->unique()->companySuffix(), + 'manager_id' => $this->user->id, + ]); + $this->clusterIds[] = $cluster->id; + + while ($miniGridCount > 0) { + $geographicalInformation = GeographicalInformation::query()->make(['points' => '111,222']); + $miniGrid = MiniGridFactory::new()->create([ + 'cluster_id' => $cluster->id, + 'name' => $this->faker->unique()->companySuffix(), + ]); + + while ($villageCount > 0) { + $village = VillageFactory::new()->create([ + 'name' => $this->faker->unique()->streetName(), + 'country_id' => 1, + 'mini_grid_id' => $miniGrid->id, + ]); + $this->villageIds[] = $village->id; + --$villageCount; + } + + $geographicalInformation->owner()->associate($miniGrid); + $geographicalInformation->save(); + $this->miniGridIds[] = $miniGrid->id; + --$miniGridCount; + } + + --$clusterCount; + } + } + + protected function generateUniqueNumber(): int { + return $this->faker->unique()->randomNumber() + $this->faker->unique()->randomNumber() + + $this->faker->unique()->randomNumber(); + } +} diff --git a/src/backend/tests/TestCase.php b/src/backend/tests/TestCase.php index 768a1ab72..5b9efec07 100644 --- a/src/backend/tests/TestCase.php +++ b/src/backend/tests/TestCase.php @@ -38,7 +38,7 @@ public function actingAs(Authenticatable $user, $guard = null) { $token = JWTAuth::fromUser($user); $this->withHeader('Authorization', "Bearer {$token}"); - $guard = $driver ?? ($user instanceof Agent ? 'agent_api' : 'api'); + $guard = $guard ?? ($user instanceof Agent ? 'agent_api' : 'api'); parent::actingAs($user, $guard); diff --git a/src/backend/tests/Unit/AgentSellApplianceTest.php b/src/backend/tests/Unit/AgentSellApplianceTest.php index 96e1de90a..67e0c6fde 100644 --- a/src/backend/tests/Unit/AgentSellApplianceTest.php +++ b/src/backend/tests/Unit/AgentSellApplianceTest.php @@ -13,6 +13,7 @@ use Database\Factories\Person\PersonFactory; use Database\Factories\UserFactory; use Illuminate\Foundation\Testing\WithFaker; +use Illuminate\Support\Facades\Schema; use Tests\RefreshMultipleDatabases; use Tests\TestCase; @@ -46,26 +47,40 @@ public function initData(): array { $user = UserFactory::new()->create(['company_id' => $this->companyId]); $this->actingAs($user); $person = PersonFactory::new()->create(); - $cluster = Cluster::query()->create([ - 'name' => 'Test Cluster', - 'manager_id' => 1, - 'geo_json' => json_encode([ - 'type' => 'Feature', - 'properties' => [ - 'name' => 'Test Cluster', - ], - 'geometry' => [ - 'type' => 'Polygon', - 'coordinates' => [ - [ - [37.937924389032375, -3.204747603780925], - [37.93779565098191, -3.4220930701917984], - [38.24208948955007, -3.2492230959644415], - [37.937924389032375, -3.204747603780925], - ], + $clusterGeoJson = [ + 'type' => 'Feature', + 'properties' => [ + 'name' => 'Test Cluster', + ], + 'geometry' => [ + 'type' => 'Polygon', + 'coordinates' => [ + [ + [37.937924389032375, -3.204747603780925], + [37.93779565098191, -3.4220930701917984], + [38.24208948955007, -3.2492230959644415], + [37.937924389032375, -3.204747603780925], ], ], - ]), + ], + ]; + + $clusterCreateData = [ + 'name' => 'Test Cluster', + 'manager_id' => 1, + ]; + + if (Schema::connection('tenant')->hasColumn('clusters', 'geo_json')) { + $clusterCreateData['geo_json'] = $clusterGeoJson; + } + + $cluster = Cluster::query()->create([ + ...$clusterCreateData, + ]); + + $cluster->location()->create([ + 'points' => '', + 'geo_json' => $clusterGeoJson, ]); $miniGrid = MiniGrid::query()->create([ diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 7576c0f7b..5ae1ad0ba 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -2916,6 +2916,27 @@ "@parcel/watcher-win32-x64": "2.5.1" } }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher-darwin-arm64": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", @@ -2937,6 +2958,237 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", diff --git a/src/frontend/package.json b/src/frontend/package.json index a29394381..d15e6f4b6 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -70,6 +70,9 @@ "setupFiles": [ "/setupTests.js" ], + "moduleNameMapper": { + "^@/(.*)$": "/src/$1" + }, "transform": { "^.+\\.jsx?$": "babel-jest" } diff --git a/src/frontend/setupTests.js b/src/frontend/setupTests.js new file mode 100644 index 000000000..f70cefe5d --- /dev/null +++ b/src/frontend/setupTests.js @@ -0,0 +1,2 @@ +// Jest setup placeholder for frontend unit tests. +// Keep this file even when empty because package.json references it. diff --git a/src/frontend/src/__tests__/CityService.test.js b/src/frontend/src/__tests__/CityService.test.js deleted file mode 100644 index c4e250548..000000000 --- a/src/frontend/src/__tests__/CityService.test.js +++ /dev/null @@ -1,46 +0,0 @@ -jest.mock("../repositories/CityRepository.js") -import { CityService } from "../services/CityService.js" -const cityService = new CityService() -const cityServiceProperties = [ - "id", - "name", - "country_id", - "created_at", - "updated_at", - "cluster_id", - "mini_grid_id", -] - -describe("CityService #getCities", () => { - it("should get cities data", async () => { - const data = await cityService.getCities() - expect(Object.keys(data[0]).length).toEqual(7) - }) - it("should list cities data with these properties", async () => { - const data = await cityService.getCities() - Object.keys(data[0]).forEach(function (item, index) { - expect(item).toEqual(cityServiceProperties[index]) - }) - }) - it("should not have null data", async () => { - const data = await cityService.getCities() - Object.keys(data).forEach(function (item) { - expect(data[item]).not.toBeNull() - expect(data[item]).not.toEqual("") - }) - }) -}) -describe("CityService #createCity", () => { - it("should create new City successfully", async () => { - const testData = require("./TestData/cityCreate.json") - const data = await cityService.createCity( - testData.name, - testData.cluster_id, - testData.mini_grid_id, - testData.geo_data, - ) - expect(data).toHaveProperty("id") - expect(data.id).not.toBeNull() - expect(data.id).not.toBeUndefined() - }) -}) diff --git a/src/frontend/src/__tests__/ClusterService.test.js b/src/frontend/src/__tests__/ClusterService.test.js index ae9f5cdcd..909c38fea 100644 --- a/src/frontend/src/__tests__/ClusterService.test.js +++ b/src/frontend/src/__tests__/ClusterService.test.js @@ -45,9 +45,9 @@ describe("ClusterService #getAllRevenues", () => { expect(Object.keys(data[0]).length).not.toEqual(0) }) }) -describe("ClusterService #getClusterCitiesRevenue", () => { - it("should get cluster cities revenue data for chart", async () => { - const financialData = await clusterService.getClusterCitiesRevenue( +describe("ClusterService #getClusterVillagesRevenue", () => { + it("should get cluster villages revenue data for chart", async () => { + const financialData = await clusterService.getClusterVillagesRevenue( 12, "monthly", ) @@ -71,7 +71,7 @@ describe("ClusterService #lineChartData", () => { } }) it("should get formatted Line chart data for Cluster Mini Grids", async () => { - const financialData = await clusterService.getClusterCitiesRevenue( + const financialData = await clusterService.getClusterVillagesRevenue( 12, "monthly", ) @@ -102,7 +102,7 @@ describe("ClusterService #columnChartData", () => { } }) it("should get formatted Column chart data for MiniGrids", async () => { - const financialData = await clusterService.getClusterCitiesRevenue( + const financialData = await clusterService.getClusterVillagesRevenue( 12, "monthly", ) diff --git a/src/frontend/src/__tests__/TestData/maintenanceTicketCreate.json b/src/frontend/src/__tests__/TestData/maintenanceTicketCreate.json index a0400290d..17f8926f9 100644 --- a/src/frontend/src/__tests__/TestData/maintenanceTicketCreate.json +++ b/src/frontend/src/__tests__/TestData/maintenanceTicketCreate.json @@ -3,7 +3,7 @@ "name": null, "surname": null, "phone": null, - "city_id": null, + "village_id": null, "mini_grid_id": null, "gender": "male", "creator": 22, diff --git a/src/frontend/src/__tests__/TestData/cityCreate.json b/src/frontend/src/__tests__/TestData/villageCreate.json similarity index 100% rename from src/frontend/src/__tests__/TestData/cityCreate.json rename to src/frontend/src/__tests__/TestData/villageCreate.json diff --git a/src/frontend/src/__tests__/VillageService.test.js b/src/frontend/src/__tests__/VillageService.test.js new file mode 100644 index 000000000..c47e50e96 --- /dev/null +++ b/src/frontend/src/__tests__/VillageService.test.js @@ -0,0 +1,46 @@ +jest.mock("../repositories/VillageRepository.js") +import { VillageService } from "../services/VillageService.js" +const villageService = new VillageService() +const villageServiceProperties = [ + "id", + "name", + "country_id", + "created_at", + "updated_at", + "cluster_id", + "mini_grid_id", +] + +describe("VillageService #getVillages", () => { + it("should get villages data", async () => { + const data = await villageService.getVillages() + expect(Object.keys(data[0]).length).toEqual(7) + }) + it("should list villages data with these properties", async () => { + const data = await villageService.getVillages() + Object.keys(data[0]).forEach(function (item, index) { + expect(item).toEqual(villageServiceProperties[index]) + }) + }) + it("should not have null data", async () => { + const data = await villageService.getVillages() + Object.keys(data).forEach(function (item) { + expect(data[item]).not.toBeNull() + expect(data[item]).not.toEqual("") + }) + }) +}) +describe("VillageService #createVillage", () => { + it("should create new Village successfully", async () => { + const testData = require("./TestData/villageCreate.json") + const data = await villageService.createVillage( + testData.name, + testData.cluster_id, + testData.mini_grid_id, + testData.geo_data, + ) + expect(data).toHaveProperty("id") + expect(data.id).not.toBeNull() + expect(data.id).not.toBeUndefined() + }) +}) diff --git a/src/frontend/src/assets/locales/ar.json b/src/frontend/src/assets/locales/ar.json index 3897e791f..2fb6a1d5a 100644 --- a/src/frontend/src/assets/locales/ar.json +++ b/src/frontend/src/assets/locales/ar.json @@ -498,7 +498,7 @@ "callback": "كولباك", "cancel": "ملغى | إلغاء", "category": "فئات | فئة", - "city": "مدن | مدينة", + "village": "مدن | مدينة", "clear": "واضح", "close": "مغلق | إغلاق", "cluster": "مجموعات | مجموعة", diff --git a/src/frontend/src/assets/locales/bu.json b/src/frontend/src/assets/locales/bu.json index e7167e71a..c9c5392e8 100644 --- a/src/frontend/src/assets/locales/bu.json +++ b/src/frontend/src/assets/locales/bu.json @@ -498,7 +498,7 @@ "callback": "ြပနေ်ခgပါ", "cancel": "ဖျက်သိမ်းသည် | ဖျက်သိမ်းလိကု ်Nပီး", "category": "အမျ+ိးအစား | အမျ+ိးအစားများ", - "city": "Nမိm | Nမိmများ", + "village": "Nမိm | Nမိmများ", "clear": "ရှင်းလင်း", "close": " ပိတ်သိမ်းသည် | ပိတ်သိမ်းလိကု ်Nပီး", "cluster": "အစုအဖဲF | အစုအဖဲFများ", diff --git a/src/frontend/src/assets/locales/en.json b/src/frontend/src/assets/locales/en.json index 4920e897e..3fcb61923 100644 --- a/src/frontend/src/assets/locales/en.json +++ b/src/frontend/src/assets/locales/en.json @@ -498,7 +498,7 @@ "callback": "Callback", "cancel": "Cancel | Cancelled", "category": "Category | Categories", - "city": "City | Cities", + "village": "Village | Villages", "clear": "Clear", "close": "Close | Closed", "cluster": "Cluster | Clusters", diff --git a/src/frontend/src/assets/locales/fr.json b/src/frontend/src/assets/locales/fr.json index db9b9dfec..3c66b45ce 100644 --- a/src/frontend/src/assets/locales/fr.json +++ b/src/frontend/src/assets/locales/fr.json @@ -498,7 +498,7 @@ "callback": "Callback", "cancel": "Cancel | Cancelled", "category": "Category | Categories", - "city": "City | Cities", + "village": "Village | Villages", "clear": "Effacer", "close": "Close | Closed", "cluster": "Cluster | Clusters", diff --git a/src/frontend/src/modules/Client/AddClientModal.vue b/src/frontend/src/modules/Client/AddClientModal.vue index c822100f0..5a1db1fd4 100644 --- a/src/frontend/src/modules/Client/AddClientModal.vue +++ b/src/frontend/src/modules/Client/AddClientModal.vue @@ -209,28 +209,28 @@
-
@@ -281,7 +281,7 @@ import moment from "moment" import { notify } from "@/mixins/notify.js" -import { CityService } from "@/services/CityService.js" +import { VillageService } from "@/services/VillageService.js" import { PersonService } from "@/services/PersonService.js" import Loader from "@/shared/Loader.vue" @@ -298,9 +298,9 @@ export default { data() { return { personService: new PersonService(), - cityService: new CityService(), + villageService: new VillageService(), loading: false, - selectedCityId: null, + selectedVillageId: null, phone: { valid: true, }, @@ -308,7 +308,7 @@ export default { } }, beforeMount() { - this.cityService.getCities() + this.villageService.getVillages() }, methods: { async save() { @@ -324,7 +324,7 @@ export default { surname: this.personService.person.surname, phone: this.personService.person.address.phone, street: this.personService.person.address.street, - cityId: this.personService.person.address.cityId, + villageId: this.personService.person.address.villageId, isPrimary: true, country_code: this.phone.countryCode, title: this.personService.person.title, @@ -360,8 +360,8 @@ export default { }, }, watch: { - selectedCityId: function (val) { - this.personService.person.address.cityId = val + selectedVillageId: function (val) { + this.personService.person.address.villageId = val }, }, } diff --git a/src/frontend/src/modules/Client/Addresses.vue b/src/frontend/src/modules/Client/Addresses.vue index 4a361d299..b6d2c9583 100644 --- a/src/frontend/src/modules/Client/Addresses.vue +++ b/src/frontend/src/modules/Client/Addresses.vue @@ -24,8 +24,8 @@ {{ item.street }} - - {{ item.city }} + + {{ item.village }} {{ item.phone }} @@ -54,22 +54,22 @@
- - - + + + - {{ $tc("words.city") }} + {{ $tc("words.village") }} - {{ city.name }} + {{ village.name }} @@ -154,7 +154,7 @@ diff --git a/src/frontend/src/modules/Maintenance/NewUser.vue b/src/frontend/src/modules/Maintenance/NewUser.vue index 642ceac68..f0221c213 100644 --- a/src/frontend/src/modules/Maintenance/NewUser.vue +++ b/src/frontend/src/modules/Maintenance/NewUser.vue @@ -122,7 +122,7 @@
-- @@ -141,15 +141,15 @@ -- - {{ city.name }} + {{ village.name }} - {{ errors.first($tc("words.city")) }} + {{ errors.first($tc("words.village")) }}
@@ -184,7 +184,7 @@ import RedirectionModal from "../../shared/RedirectionModal.vue" import { notify } from "@/mixins/notify.js" -import { CityService } from "@/services/CityService.js" +import { VillageService } from "@/services/VillageService.js" import { MaintenanceService } from "@/services/MaintenanceService.js" import { MiniGridService } from "@/services/MiniGridService.js" import { EventBus } from "@/shared/eventbus.js" @@ -204,9 +204,9 @@ export default { data() { return { miniGrids: [], - cities: [], + villages: [], miniGridService: new MiniGridService(), - cityService: new CityService(), + villageService: new VillageService(), maintenanceService: new MaintenanceService(), loading: false, imperativeItem: "Mini-Grid", @@ -221,7 +221,7 @@ export default { mounted() { EventBus.$on("getLists", () => { this.getMiniGrids() - this.getCities() + this.getVillages() }) }, methods: { @@ -235,9 +235,9 @@ export default { this.alertNotify("error", e.message) } }, - async getCities() { + async getVillages() { try { - this.cities = await this.cityService.getCities() + this.villages = await this.villageService.getVillages() } catch (e) { this.alertNotify("error", e.message) } diff --git a/src/frontend/src/modules/MiniGrid/RevenueTrends.vue b/src/frontend/src/modules/MiniGrid/RevenueTrends.vue index 2aa1c5e88..c6cc3ba61 100644 --- a/src/frontend/src/modules/MiniGrid/RevenueTrends.vue +++ b/src/frontend/src/modules/MiniGrid/RevenueTrends.vue @@ -107,7 +107,7 @@ export default { return { loading: false, redirectionUrl: "/locations/add-village", - imperativeItem: "City", + imperativeItem: "Village", redirectDialogActive: false, } }, diff --git a/src/frontend/src/modules/Profile/Profile.vue b/src/frontend/src/modules/Profile/Profile.vue index 4565c4a5c..0b4999e97 100644 --- a/src/frontend/src/modules/Profile/Profile.vue +++ b/src/frontend/src/modules/Profile/Profile.vue @@ -77,21 +77,21 @@
-
@@ -193,7 +193,7 @@