From 61070799671f4d05f84c984194a4de9598c8cac3 Mon Sep 17 00:00:00 2001 From: Roberto Stomeo Date: Tue, 1 Jul 2025 16:42:34 +0200 Subject: [PATCH] Initial commit edera-api --- edera-api/.gitignore | 40 + edera-api/README.md | 6 + edera-api/api/pom.xml | 107 + .../main/java/applica/app/Application.java | 39 + .../ApplicationConfiguration.java | 52 + .../configuration/AuditLogConfiguration.java | 17 + .../configuration/GeoAutoConfiguration.java | 32 + .../app/configuration/MLConfiguration.java | 15 + .../NotificationsConfiguration.java | 76 + .../configuration/SecurityConfiguration.java | 61 + .../java/applica/app/domain/Category.java | 20 + .../main/java/applica/app/domain/Device.java | 25 + .../applica/app/domain/DeviceDataLayer.java | 82 + .../main/java/applica/app/domain/Gallery.java | 24 + .../java/applica/app/domain/I18nMessage.java | 119 + .../app/domain/I18nMessageRepository.java | 6 + .../java/applica/app/domain/Notification.java | 76 + .../app/domain/NotificationDataLayer.java | 59 + .../java/applica/app/domain/SubCategory.java | 37 + .../main/java/applica/app/domain/User.java | 43 + .../applica/app/domain/UsersDataLayer.java | 180 + .../applica/app/domain/audit/AuditLog.java | 94 + .../app/domain/audit/AuditLogMessage.java | 15 + .../domain/audit/AuditLogMessageBuilder.java | 14 + .../audit/AuditLogMessageBuilderFactory.java | 21 + .../builders/CrudAuditLogMessageBuilder.java | 41 + .../CrudCreateAuditLogMessageBuilder.java | 41 + .../CrudDeleteAuditLogMessageBuilder.java | 35 + .../CrudEditAuditLogMessageBuilder.java | 43 + .../CrudFindAuditLogMessageBuilder.java | 23 + .../CrudViewAuditLogMessageBuilder.java | 29 + .../applica/app/domain/customer/Area.java | 62 + .../app/domain/customer/AreaRepository.java | 9 + .../applica/app/domain/customer/Customer.java | 46 + .../domain/customer/CustomerRepository.java | 6 + .../applica/app/domain/customer/Office.java | 82 + .../applica/app/domain/customer/Referent.java | 60 + .../applica/app/domain/docx/DocxBuilder.java | 180 + .../app/domain/docx/DocxDataSource.java | 28 + .../app/domain/docx/DocxDataSourceRow.java | 38 + .../app/domain/docx/DocxDescriptor.java | 60 + .../app/domain/docx/DocxException.java | 8 + .../applica/app/domain/docx/DocxFactory.java | 48 + .../applica/app/domain/docx/DocxField.java | 10 + .../applica/app/domain/docx/DocxTemplate.java | 38 + .../applica/app/domain/docx/DocxTypeDef.java | 26 + .../docx/typedef/MaintenanceDocxTypeDef.java | 151 + .../app/domain/dto/ActivityDetailsDTO.java | 10 + .../app/domain/dto/SupplyDetailsDTO.java | 10 + .../app/domain/equipment/Equipment.java | 58 + .../domain/equipment/EquipmentAttachment.java | 50 + .../domain/equipment/EquipmentRepository.java | 6 + .../app/domain/equipment/EquipmentType.java | 68 + .../equipment/EquipmentTypeAttachment.java | 49 + .../equipment/EquipmentTypeRepository.java | 6 + .../java/applica/app/domain/geo/City.java | 43 + .../java/applica/app/domain/geo/Nation.java | 31 + .../java/applica/app/domain/geo/Province.java | 1 + .../java/applica/app/domain/geo/Region.java | 39 + .../app/domain/maintenance/Activity.java | 84 + .../maintenance/ActivityRepository.java | 9 + .../domain/maintenance/ActivityStatus.java | 6 + .../app/domain/maintenance/ActivityType.java | 50 + .../maintenance/ActivityTypeRepository.java | 6 + .../app/domain/maintenance/Intervention.java | 18 + .../app/domain/maintenance/Maintenance.java | 79 + .../maintenance/MaintenanceRepository.java | 6 + .../java/applica/app/domain/package-info.java | 1 + .../applica/app/domain/pricing/PriceList.java | 57 + .../app/domain/pricing/PriceListItem.java | 56 + .../applica/app/domain/protocol/Protocol.java | 71 + .../domain/protocol/ProtocolAttachment.java | 50 + .../domain/protocol/ProtocolRepository.java | 7 + .../app/domain/protocol/ProtocolService.java | 25 + .../app/domain/reporting/DataPoint.java | 73 + .../app/domain/reporting/DataPointSet.java | 62 + .../applica/app/domain/reporting/Filter.java | 32 + .../app/domain/reporting/FilterSet.java | 7 + .../applica/app/domain/reporting/GroupBy.java | 19 + .../app/domain/reporting/TemporalFilter.java | 190 + .../applica/app/domain/rfid/RFIDDevice.java | 54 + .../app/domain/rfid/RFIDDeviceRepository.java | 9 + .../app/domain/rfid/RFIDDeviceTrack.java | 61 + .../rfid/RFIDDeviceTrackRepository.java | 6 + .../rfid/RFIDDeviceTrackStatsRepository.java | 10 + .../RFIDDeviceTrackStatsRepositoryImpl.java | 104 + .../app/domain/rfid/RFIDDeviceType.java | 6 + .../applica/app/domain/supplier/Referent.java | 66 + .../applica/app/domain/supplier/Supplier.java | 61 + .../domain/supplier/SupplierRepository.java | 6 + .../applica/app/domain/supply/Supply.java | 137 + .../app/domain/supply/SupplyRepository.java | 12 + .../domain/supply/SupplyStatsRepository.java | 25 + .../supply/SupplyStatsRepositoryImpl.java | 279 + .../java/applica/app/domain/supply/Usage.java | 68 + .../supply/UsageOverlapUtilsRepository.java | 7 + .../UsageOverlapUtilsRepositoryImpl.java | 30 + .../app/domain/supply/UsageRepository.java | 9 + .../app/domain/supply/UsageStatus.java | 6 + .../main/java/applica/app/mapping/Mapper.java | 42 + .../main/java/applica/app/ml/MLClient.java | 52 + .../main/java/applica/app/ml/MLRequest.java | 85 + .../main/java/applica/app/ml/MLResponse.java | 24 + .../java/applica/app/ml/PredictionItem.java | 17 + .../applica/app/services/EderaService.java | 245 + .../services/GeoInitializationService.java | 209 + .../app/services/InitializationService.java | 154 + .../app/services/reporting/Report.java | 12 + .../app/services/reporting/ReportData.java | 13 + .../app/services/reporting/ReportFactory.java | 18 + .../services/reporting/impl/SupplyReport.java | 141 + .../reporting/impl/SupplyTracksReport.java | 53 + .../app/tasks/ProtocolServiceNotifyTask.java | 178 + .../java/applica/app/utils/SecurityUtils.java | 36 + .../web/annotations/CustomerFilterable.java | 18 + .../app/web/controllers/DocxController.java | 108 + .../app/web/controllers/I18nController.java | 48 + .../app/web/controllers/IAMController.java | 206 + .../controllers/MaintenanceController.java | 33 + .../web/controllers/ProfileController.java | 53 + .../controllers/ProtectedRestController.java | 26 + .../RFIDDeviceTrackController.java | 39 + .../app/web/controllers/ReportController.java | 31 + .../app/web/controllers/SupplyController.java | 33 + .../app/web/controllers/ValuesController.java | 55 + .../app/web/crud/ActivityDataLayer.java | 87 + .../app/web/crud/AuditLogDataLayer.java | 92 + .../app/web/crud/DefaultDataLayer.java | 34 + .../app/web/crud/EquipmentDataLayer.java | 127 + .../app/web/crud/EquipmentTypeDataLayer.java | 84 + .../app/web/crud/MaintenanceDataLayer.java | 93 + .../app/web/crud/PriceListItemDataLayer.java | 88 + .../app/web/crud/ProtocolDataLayer.java | 86 + .../web/crud/RFIDDeviceTrackDataLayer.java | 113 + .../applica/app/web/crud/SupplyDataLayer.java | 124 + .../app/web/filters/AuditLogTraceFilter.java | 96 + .../web/filters/JwtAuthenticationFilter.java | 60 + .../operations/EquipmentTypeGetOperation.java | 60 + .../I18nMessageDeleteOperation.java | 41 + .../operations/I18nMessageSaveOperation.java | 41 + .../operations/NotificationFindOperation.java | 38 + .../PriceListItemSaveOperation.java | 43 + .../operations/PriceListSaveOperation.java | 38 + .../CustomerFilterableFindDecorator.java | 25 + .../web/requests/GetReportDataRequest.java | 6 + .../app/web/requests/PatchProfileRequest.java | 12 + .../web/responses/ActivityInfoResponse.java | 23 + .../app/web/responses/CrudLoginResponse.java | 30 + .../web/responses/GetReportDataResponse.java | 21 + .../app/web/responses/SupplyInfoResponse.java | 23 + .../security/JwtAuthenticationEntryPoint.java | 18 + .../resources/application-production.yaml | 13 + .../src/main/resources/application-test.yaml | 11 + .../api/src/main/resources/application.yaml | 96 + .../credentials/service-account.json | 13 + .../api/src/main/resources/csv/cities.csv | 7905 +++++++++++++++++ .../api/src/main/resources/csv/nations.csv | 233 + .../api/src/main/resources/csv/provinces.csv | 112 + .../api/src/main/resources/csv/regions.csv | 21 + .../api/src/main/resources/docx/helper.docx | Bin 0 -> 5227 bytes edera-api/api/src/main/resources/i18n.json | 3136 +++++++ .../applica/app/test/TestApplication.java | 14 + .../applica/app/test/TestDataFactory.java | 36 + .../test/configuration/TestConfiguration.java | 14 + .../app/test/domain/docx/DocxBuilderTest.java | 66 + .../app/test/endtoend/IAMControllerTest.java | 245 + .../RFIDDeviceTrackControllerTest.java | 102 + .../applica/app/test/fixture/AreaFixture.java | 39 + .../applica/app/test/fixture/Fixture.java | 59 + .../app/test/fixture/RFIDDeviceFixture.java | 39 + .../app/test/fixture/SupplyFixture.java | 63 + edera-api/api/src/test/resources/i18n.json | 1721 ++++ .../resources/sample-google-workspace.docx | Bin 0 -> 5913 bytes .../resources/sample-ms-office-open-xml.docx | Bin 0 -> 12298 bytes .../src/test/resources/sample-ms-office.docx | Bin 0 -> 14152 bytes .../test/resources/sample-open-office.docx | Bin 0 -> 1987329 bytes edera-api/bitbucket-pipelines.yml | 101 + edera-api/mvnw | 316 + edera-api/mvnw.cmd | 188 + edera-api/notifications/pom.xml | 57 + .../application/NotificationService.java | 5 + .../UserActivatedEventHandler.java | 44 + .../UserPasswordChangedEventHandler.java | 45 + .../UserPasswordRecoveredEventHandler.java | 49 + .../UserRegisteredEventHandler.java | 50 + .../DefaultMailMessageService.java | 55 + .../integration/FreemarkerHelper.java | 19 + .../integration/MailMessage.java | 23 + .../integration/MailMessageService.java | 6 + .../main/resources/templates/activation.ftlh | 3 + .../resources/templates/passwordChanged.ftlh | 3 + .../src/main/resources/templates/recover.ftlh | 3 + .../resources/templates/registration.ftlh | 7 + edera-api/pom.xml | 113 + edera-api/scripts/create-infrastructure.sh | 4 + edera-api/scripts/docker/Dockerfile | 16 + edera-api/scripts/init-gcloud.sh | 7 + edera-api/scripts/init-k8s.sh | 8 + edera-api/scripts/kube/api.yml | 53 + edera-api/scripts/kube/ingress.yml | 28 + edera-api/scripts/set-env.sh | 4 + edera-api/scripts/tf/main.tf | 75 + edera-api/scripts/tf/mongo-atlas.tf | 60 + edera-api/scripts/tf/provider.tf | 5 + .../scripts/tf/service-account.json.base64 | 42 + edera-api/scripts/tf/terraform.tfstate | 238 + edera-api/scripts/tf/variables.tf | 22 + 207 files changed, 23578 insertions(+) create mode 100644 edera-api/.gitignore create mode 100644 edera-api/README.md create mode 100644 edera-api/api/pom.xml create mode 100644 edera-api/api/src/main/java/applica/app/Application.java create mode 100644 edera-api/api/src/main/java/applica/app/configuration/ApplicationConfiguration.java create mode 100644 edera-api/api/src/main/java/applica/app/configuration/AuditLogConfiguration.java create mode 100644 edera-api/api/src/main/java/applica/app/configuration/GeoAutoConfiguration.java create mode 100644 edera-api/api/src/main/java/applica/app/configuration/MLConfiguration.java create mode 100644 edera-api/api/src/main/java/applica/app/configuration/NotificationsConfiguration.java create mode 100644 edera-api/api/src/main/java/applica/app/configuration/SecurityConfiguration.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/Category.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/Device.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/DeviceDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/Gallery.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/I18nMessage.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/I18nMessageRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/Notification.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/NotificationDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/SubCategory.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/User.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/UsersDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/AuditLog.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessage.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessageBuilder.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessageBuilderFactory.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudAuditLogMessageBuilder.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudCreateAuditLogMessageBuilder.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudDeleteAuditLogMessageBuilder.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudEditAuditLogMessageBuilder.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudFindAuditLogMessageBuilder.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudViewAuditLogMessageBuilder.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/customer/Area.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/customer/AreaRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/customer/Customer.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/customer/CustomerRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/customer/Office.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/customer/Referent.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxBuilder.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxDataSource.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxDataSourceRow.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxDescriptor.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxException.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxFactory.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxField.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxTemplate.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/DocxTypeDef.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/docx/typedef/MaintenanceDocxTypeDef.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/dto/ActivityDetailsDTO.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/dto/SupplyDetailsDTO.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/equipment/Equipment.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentAttachment.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentType.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentTypeAttachment.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentTypeRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/geo/City.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/geo/Nation.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/geo/Province.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/geo/Region.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/maintenance/Activity.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityStatus.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityType.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityTypeRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/maintenance/Intervention.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/maintenance/Maintenance.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/maintenance/MaintenanceRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/package-info.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/pricing/PriceList.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/pricing/PriceListItem.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/protocol/Protocol.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolAttachment.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolService.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/reporting/DataPoint.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/reporting/DataPointSet.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/reporting/Filter.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/reporting/FilterSet.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/reporting/GroupBy.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/reporting/TemporalFilter.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDevice.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrack.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackStatsRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackStatsRepositoryImpl.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceType.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supplier/Referent.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supplier/Supplier.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supplier/SupplierRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/Supply.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/SupplyRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/SupplyStatsRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/SupplyStatsRepositoryImpl.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/Usage.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/UsageOverlapUtilsRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/UsageOverlapUtilsRepositoryImpl.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/UsageRepository.java create mode 100644 edera-api/api/src/main/java/applica/app/domain/supply/UsageStatus.java create mode 100644 edera-api/api/src/main/java/applica/app/mapping/Mapper.java create mode 100644 edera-api/api/src/main/java/applica/app/ml/MLClient.java create mode 100644 edera-api/api/src/main/java/applica/app/ml/MLRequest.java create mode 100644 edera-api/api/src/main/java/applica/app/ml/MLResponse.java create mode 100644 edera-api/api/src/main/java/applica/app/ml/PredictionItem.java create mode 100644 edera-api/api/src/main/java/applica/app/services/EderaService.java create mode 100644 edera-api/api/src/main/java/applica/app/services/GeoInitializationService.java create mode 100644 edera-api/api/src/main/java/applica/app/services/InitializationService.java create mode 100644 edera-api/api/src/main/java/applica/app/services/reporting/Report.java create mode 100644 edera-api/api/src/main/java/applica/app/services/reporting/ReportData.java create mode 100644 edera-api/api/src/main/java/applica/app/services/reporting/ReportFactory.java create mode 100644 edera-api/api/src/main/java/applica/app/services/reporting/impl/SupplyReport.java create mode 100644 edera-api/api/src/main/java/applica/app/services/reporting/impl/SupplyTracksReport.java create mode 100644 edera-api/api/src/main/java/applica/app/tasks/ProtocolServiceNotifyTask.java create mode 100644 edera-api/api/src/main/java/applica/app/utils/SecurityUtils.java create mode 100644 edera-api/api/src/main/java/applica/app/web/annotations/CustomerFilterable.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/DocxController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/I18nController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/IAMController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/MaintenanceController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/ProfileController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/ProtectedRestController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/RFIDDeviceTrackController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/ReportController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/SupplyController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/controllers/ValuesController.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/ActivityDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/AuditLogDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/DefaultDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/EquipmentDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/EquipmentTypeDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/MaintenanceDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/PriceListItemDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/ProtocolDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/RFIDDeviceTrackDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/crud/SupplyDataLayer.java create mode 100644 edera-api/api/src/main/java/applica/app/web/filters/AuditLogTraceFilter.java create mode 100644 edera-api/api/src/main/java/applica/app/web/filters/JwtAuthenticationFilter.java create mode 100644 edera-api/api/src/main/java/applica/app/web/operations/EquipmentTypeGetOperation.java create mode 100644 edera-api/api/src/main/java/applica/app/web/operations/I18nMessageDeleteOperation.java create mode 100644 edera-api/api/src/main/java/applica/app/web/operations/I18nMessageSaveOperation.java create mode 100644 edera-api/api/src/main/java/applica/app/web/operations/NotificationFindOperation.java create mode 100644 edera-api/api/src/main/java/applica/app/web/operations/PriceListItemSaveOperation.java create mode 100644 edera-api/api/src/main/java/applica/app/web/operations/PriceListSaveOperation.java create mode 100644 edera-api/api/src/main/java/applica/app/web/operations/decorators/CustomerFilterableFindDecorator.java create mode 100644 edera-api/api/src/main/java/applica/app/web/requests/GetReportDataRequest.java create mode 100644 edera-api/api/src/main/java/applica/app/web/requests/PatchProfileRequest.java create mode 100644 edera-api/api/src/main/java/applica/app/web/responses/ActivityInfoResponse.java create mode 100644 edera-api/api/src/main/java/applica/app/web/responses/CrudLoginResponse.java create mode 100644 edera-api/api/src/main/java/applica/app/web/responses/GetReportDataResponse.java create mode 100644 edera-api/api/src/main/java/applica/app/web/responses/SupplyInfoResponse.java create mode 100644 edera-api/api/src/main/java/applica/app/web/security/JwtAuthenticationEntryPoint.java create mode 100644 edera-api/api/src/main/resources/application-production.yaml create mode 100644 edera-api/api/src/main/resources/application-test.yaml create mode 100644 edera-api/api/src/main/resources/application.yaml create mode 100644 edera-api/api/src/main/resources/credentials/service-account.json create mode 100644 edera-api/api/src/main/resources/csv/cities.csv create mode 100644 edera-api/api/src/main/resources/csv/nations.csv create mode 100644 edera-api/api/src/main/resources/csv/provinces.csv create mode 100644 edera-api/api/src/main/resources/csv/regions.csv create mode 100644 edera-api/api/src/main/resources/docx/helper.docx create mode 100644 edera-api/api/src/main/resources/i18n.json create mode 100644 edera-api/api/src/test/java/applica/app/test/TestApplication.java create mode 100644 edera-api/api/src/test/java/applica/app/test/TestDataFactory.java create mode 100644 edera-api/api/src/test/java/applica/app/test/configuration/TestConfiguration.java create mode 100644 edera-api/api/src/test/java/applica/app/test/domain/docx/DocxBuilderTest.java create mode 100644 edera-api/api/src/test/java/applica/app/test/endtoend/IAMControllerTest.java create mode 100644 edera-api/api/src/test/java/applica/app/test/endtoend/RFIDDeviceTrackControllerTest.java create mode 100644 edera-api/api/src/test/java/applica/app/test/fixture/AreaFixture.java create mode 100644 edera-api/api/src/test/java/applica/app/test/fixture/Fixture.java create mode 100644 edera-api/api/src/test/java/applica/app/test/fixture/RFIDDeviceFixture.java create mode 100644 edera-api/api/src/test/java/applica/app/test/fixture/SupplyFixture.java create mode 100644 edera-api/api/src/test/resources/i18n.json create mode 100644 edera-api/api/src/test/resources/sample-google-workspace.docx create mode 100644 edera-api/api/src/test/resources/sample-ms-office-open-xml.docx create mode 100644 edera-api/api/src/test/resources/sample-ms-office.docx create mode 100644 edera-api/api/src/test/resources/sample-open-office.docx create mode 100644 edera-api/bitbucket-pipelines.yml create mode 100644 edera-api/mvnw create mode 100644 edera-api/mvnw.cmd create mode 100644 edera-api/notifications/pom.xml create mode 100644 edera-api/notifications/src/main/java/applica/notifications/application/NotificationService.java create mode 100644 edera-api/notifications/src/main/java/applica/notifications/application/UserActivatedEventHandler.java create mode 100644 edera-api/notifications/src/main/java/applica/notifications/application/UserPasswordChangedEventHandler.java create mode 100644 edera-api/notifications/src/main/java/applica/notifications/application/UserPasswordRecoveredEventHandler.java create mode 100644 edera-api/notifications/src/main/java/applica/notifications/application/UserRegisteredEventHandler.java create mode 100644 edera-api/notifications/src/main/java/applica/notifications/integration/DefaultMailMessageService.java create mode 100644 edera-api/notifications/src/main/java/applica/notifications/integration/FreemarkerHelper.java create mode 100644 edera-api/notifications/src/main/java/applica/notifications/integration/MailMessage.java create mode 100644 edera-api/notifications/src/main/java/applica/notifications/integration/MailMessageService.java create mode 100644 edera-api/notifications/src/main/resources/templates/activation.ftlh create mode 100644 edera-api/notifications/src/main/resources/templates/passwordChanged.ftlh create mode 100644 edera-api/notifications/src/main/resources/templates/recover.ftlh create mode 100644 edera-api/notifications/src/main/resources/templates/registration.ftlh create mode 100644 edera-api/pom.xml create mode 100644 edera-api/scripts/create-infrastructure.sh create mode 100644 edera-api/scripts/docker/Dockerfile create mode 100644 edera-api/scripts/init-gcloud.sh create mode 100644 edera-api/scripts/init-k8s.sh create mode 100644 edera-api/scripts/kube/api.yml create mode 100644 edera-api/scripts/kube/ingress.yml create mode 100644 edera-api/scripts/set-env.sh create mode 100644 edera-api/scripts/tf/main.tf create mode 100644 edera-api/scripts/tf/mongo-atlas.tf create mode 100644 edera-api/scripts/tf/provider.tf create mode 100644 edera-api/scripts/tf/service-account.json.base64 create mode 100644 edera-api/scripts/tf/terraform.tfstate create mode 100644 edera-api/scripts/tf/variables.tf diff --git a/edera-api/.gitignore b/edera-api/.gitignore new file mode 100644 index 0000000..a95772d --- /dev/null +++ b/edera-api/.gitignore @@ -0,0 +1,40 @@ +api/HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Idea and Custom ### +.flattened-pom.xml +i18n-test.json +.DS_Store + +/api/src/test/resources/out-*.docx \ No newline at end of file diff --git a/edera-api/README.md b/edera-api/README.md new file mode 100644 index 0000000..c68414b --- /dev/null +++ b/edera-api/README.md @@ -0,0 +1,6 @@ +# Leggimi + +Il seguente archetipo è disponibile in due varianti disponibili su branch separati +- `master`: espone un archetipo base con configurazione **MongoDB** +- `feature/jpa`: espone un archetipo con configurazione **JPA** + diff --git a/edera-api/api/pom.xml b/edera-api/api/pom.xml new file mode 100644 index 0000000..4473207 --- /dev/null +++ b/edera-api/api/pom.xml @@ -0,0 +1,107 @@ + + + 4.0.0 + + applica.app + root + ${revision}${sha1}${changelist} + + + api + ${revision}${sha1}${changelist} + app + + + ${project.build.directory}/generated-snippets + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + 1.4.200 + + + org.springframework.boot + spring-boot-starter-web + + + applica.modules + iam + ${applica-iam.version} + + + applica.modules + crud-mongodb + ${applica-crud.version} + + + applica.modules + fs-gcp + ${applica-fs.version} + + + applica.app + notifications + ${revision}${sha1}${changelist} + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.restdocs + spring-restdocs-mockmvc + test + + + org.springframework.security + spring-security-test + test + + + org.apache.poi + poi + 5.2.2 + + + org.apache.poi + poi-ooxml + 5.2.2 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + applica.app.Application + + + + + build-info + + + + + + + + diff --git a/edera-api/api/src/main/java/applica/app/Application.java b/edera-api/api/src/main/java/applica/app/Application.java new file mode 100644 index 0000000..a99054c --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/Application.java @@ -0,0 +1,39 @@ +package applica.app; + +import applica.crud.configuration.EnableCrud; +import applica.fs.gcp.configuration.EnableGcpFs; +import applica.iam.configuration.EnableIAM; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.mongodb.config.EnableMongoAuditing; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +@SpringBootApplication +@ComponentScan({ + "applica.app.web", + "applica.app.services", + "applica.app.configuration", + "applica.app.domain", + "applica.app.tasks" +}) +@EnableWebMvc +@EnableWebSecurity +@EnableCrud(packages = { + "applica.app.domain" +}) +@EnableGcpFs +@EnableIAM +@EnableMongoAuditing +@EnableMongoRepositories(basePackages = "applica.app.domain") +@EnableScheduling +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/configuration/ApplicationConfiguration.java b/edera-api/api/src/main/java/applica/app/configuration/ApplicationConfiguration.java new file mode 100644 index 0000000..f383c02 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/configuration/ApplicationConfiguration.java @@ -0,0 +1,52 @@ +package applica.app.configuration; + +import applica.app.web.crud.DefaultDataLayer; +import applica.app.web.operations.decorators.CustomerFilterableFindDecorator; +import applica.crud.operations.decorators.user.LoggedUserIdSaveDecorator; +import applica.crud.query.CrudQueryConverter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Scope; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class ApplicationConfiguration { + @Bean + public WebMvcConfigurer corsConfigurer(@Value("${cors.allowed-origins}") String[] allowedOrigins) { + return new WebMvcConfigurer() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry + .addMapping("/**") + .allowedMethods("POST", "PUT", "GET", "DELETE", "OPTIONS", "PATCH") + .allowedOrigins(allowedOrigins) + ; + } + }; + } + + @Bean + @Scope("prototype") + public LoggedUserIdSaveDecorator loggedUserIdSaveDecorator() { + return new LoggedUserIdSaveDecorator(); + } + + @Bean + @Scope("prototype") + public CustomerFilterableFindDecorator customerFilterableFindDecorator() { + return new CustomerFilterableFindDecorator(); + } + + @Bean + @Scope("prototype") + @Primary + public DefaultDataLayer dataLayer(MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + return new DefaultDataLayer<>(mongoTemplate, queryConverter); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/configuration/AuditLogConfiguration.java b/edera-api/api/src/main/java/applica/app/configuration/AuditLogConfiguration.java new file mode 100644 index 0000000..7fbca21 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/configuration/AuditLogConfiguration.java @@ -0,0 +1,17 @@ +package applica.app.configuration; + +import applica.app.domain.audit.AuditLogMessageBuilder; +import applica.app.domain.audit.AuditLogMessageBuilderFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Configuration +@SuppressWarnings("unused") +public class AuditLogConfiguration { + @Bean + public AuditLogMessageBuilderFactory logExplainerFactory(List explainers) { + return new AuditLogMessageBuilderFactory(explainers); + } +} diff --git a/edera-api/api/src/main/java/applica/app/configuration/GeoAutoConfiguration.java b/edera-api/api/src/main/java/applica/app/configuration/GeoAutoConfiguration.java new file mode 100644 index 0000000..c797e08 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/configuration/GeoAutoConfiguration.java @@ -0,0 +1,32 @@ +package applica.app.configuration; + +import applica.app.services.GeoInitializationService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.mongodb.core.MongoTemplate; + +@ComponentScan({ + "applica.app.services" +}) +public class GeoAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public GeoInitializationService geoInitializationService( + @Value("${geo.csv.nation}") String nationCsvPath, + @Value("${geo.csv.region}") String regionCsvPath, + @Value("${geo.csv.province}") String provinceCsvPath, + @Value("${geo.csv.city}") String cityCsvPath, + MongoTemplate mongoTemplate + ) { + return new GeoInitializationService( + nationCsvPath, + regionCsvPath, + provinceCsvPath, + cityCsvPath, + mongoTemplate + ); + } +} diff --git a/edera-api/api/src/main/java/applica/app/configuration/MLConfiguration.java b/edera-api/api/src/main/java/applica/app/configuration/MLConfiguration.java new file mode 100644 index 0000000..df30aea --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/configuration/MLConfiguration.java @@ -0,0 +1,15 @@ +package applica.app.configuration; + +import applica.app.ml.MLClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@SuppressWarnings("unused") +public class MLConfiguration { + @Bean + public MLClient mlClient(@Value("${ml.endpoint}") String endpoint) { + return new MLClient(endpoint); + } +} diff --git a/edera-api/api/src/main/java/applica/app/configuration/NotificationsConfiguration.java b/edera-api/api/src/main/java/applica/app/configuration/NotificationsConfiguration.java new file mode 100644 index 0000000..168c46e --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/configuration/NotificationsConfiguration.java @@ -0,0 +1,76 @@ +package applica.app.configuration; + +import applica.iam.sdk.IAMService; +import applica.integration.events.ApplicationDomainEventsHandler; +import applica.integration.events.DomainEventsHandler; +import applica.notifications.application.UserActivatedEventHandler; +import applica.notifications.application.UserPasswordChangedEventHandler; +import applica.notifications.application.UserPasswordRecoveredEventHandler; +import applica.notifications.application.UserRegisteredEventHandler; +import applica.notifications.integration.DefaultMailMessageService; +import applica.notifications.integration.FreemarkerHelper; +import applica.notifications.integration.MailMessageService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@SuppressWarnings("unused") +@Configuration +public class NotificationsConfiguration { + + @Bean + public FreemarkerHelper freemarkerHelper(@Value("${mail.templates.path}") String templatesPath) { + return new FreemarkerHelper(templatesPath); + } + + @Bean + public MailMessageService mailMessageService() { + return new DefaultMailMessageService(); + } + @Bean + public UserRegisteredEventHandler profileCreatedEventHandler( + MailMessageService mailMessageService, + IAMService iamService + ) { + return new UserRegisteredEventHandler(mailMessageService, iamService); + } + + @Bean + public UserPasswordChangedEventHandler userPasswordChangedEventHandler( + MailMessageService mailMessageService, + IAMService iamService + ) { + return new UserPasswordChangedEventHandler(mailMessageService, iamService); + } + + @Bean + public UserPasswordRecoveredEventHandler userPasswordRecoveredEventHandler( + MailMessageService mailMessageService, + IAMService iamService + ) { + return new UserPasswordRecoveredEventHandler(mailMessageService, iamService); + } + + @Bean + public UserActivatedEventHandler userActivatedEventHandler( + MailMessageService mailMessageService, + IAMService iamService + ) { + return new UserActivatedEventHandler(mailMessageService, iamService); + } + + @Bean + public DomainEventsHandler domainEventsHandler( + UserRegisteredEventHandler userRegisteredEventHandler, + UserPasswordChangedEventHandler userPasswordChangedEventHandler, + UserPasswordRecoveredEventHandler userPasswordRecoveredEventHandler, + UserActivatedEventHandler userActivatedEventHandler + ) { + ApplicationDomainEventsHandler domainEventsListener = new ApplicationDomainEventsHandler(); + domainEventsListener.registerHandler(userRegisteredEventHandler); + domainEventsListener.registerHandler(userPasswordChangedEventHandler); + domainEventsListener.registerHandler(userPasswordRecoveredEventHandler); + domainEventsListener.registerHandler(userActivatedEventHandler); + return domainEventsListener; + } +} diff --git a/edera-api/api/src/main/java/applica/app/configuration/SecurityConfiguration.java b/edera-api/api/src/main/java/applica/app/configuration/SecurityConfiguration.java new file mode 100644 index 0000000..94c86af --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/configuration/SecurityConfiguration.java @@ -0,0 +1,61 @@ +package applica.app.configuration; + +import applica.app.web.filters.JwtAuthenticationFilter; +import applica.iam.sdk.IAMService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@SuppressWarnings("unused") +@EnableWebSecurity +@EnableMethodSecurity +@Configuration +public class SecurityConfiguration { + @Bean + public SecurityFilterChain filterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception { + http + .cors() + .and() + + .csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + + .authorizeHttpRequests() + .requestMatchers( + "/actuator/**", + "/attachments/**", + "/iam/**", + "/i18n/**", + "/track", + "/docx/helper/**", + "/docx/generate/**" + ).permitAll() + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .requestMatchers("/**").authenticated() + .and() + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) + + .headers() + .contentSecurityPolicy("script-src 'self'") + .and() + .frameOptions() + .sameOrigin() + .httpStrictTransportSecurity() + .includeSubDomains(true); + + return http.build(); + } + + @Bean + public JwtAuthenticationFilter jwtAuthenticationFilter(IAMService iamService) { + return new JwtAuthenticationFilter(iamService); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/Category.java b/edera-api/api/src/main/java/applica/app/domain/Category.java new file mode 100644 index 0000000..bdf3cb7 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/Category.java @@ -0,0 +1,20 @@ +package applica.app.domain; + +import applica.crud.annotations.CrudEntity; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +@CrudEntity("category") +public class Category { + @EqualsAndHashCode.Include + String id; + @NotEmpty + String description; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/Device.java b/edera-api/api/src/main/java/applica/app/domain/Device.java new file mode 100644 index 0000000..8bf08ea --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/Device.java @@ -0,0 +1,25 @@ +package applica.app.domain; + +import applica.crud.annotations.CrudEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author Roberto Conte Rosito + * + * Identifica un singolo dispositivo riconosciuto. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@CrudEntity("device") +public class Device { + String id; + String code; + String secret; + Date registrationDate; +} + diff --git a/edera-api/api/src/main/java/applica/app/domain/DeviceDataLayer.java b/edera-api/api/src/main/java/applica/app/domain/DeviceDataLayer.java new file mode 100644 index 0000000..fb11860 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/DeviceDataLayer.java @@ -0,0 +1,82 @@ +package applica.app.domain; + +import applica.crud.datalayer.DataLayer; +import applica.crud.model.Result; +import applica.crud.query.CrudQuery; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.requests.*; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.Optional; + +import static applica.app.mapping.Mapper.deviceViewToDevice; + +@Component +public class DeviceDataLayer implements DataLayer { + private IAMService iamService; + + public DeviceDataLayer(IAMService iamService) { + this.iamService = iamService; + } + + @Override + public Optional get(Object id) { + var getDeviceRequest = new GetDeviceByIdRequest(id.toString()); + var device = iamService.getDeviceById(getDeviceRequest); + return Optional.ofNullable(deviceViewToDevice(device.getDevice())); + } + + @Override + public Result find(CrudQuery query) { + var keyword = query.getKeyword(); + var searchRequest = new SearchDevicesRequest(); + if (StringUtils.hasLength(keyword)) { + searchRequest.setKeyword(keyword); + } + var pageable = query.getPageable(); + if (pageable != null) { + searchRequest.setPageable(pageable); + } + + var devices = iamService.searchDevices(searchRequest); + return new Result<>( + devices.getDevices().stream().map(deviceView -> deviceViewToDevice(deviceView)).toList(), + devices.getDevices().getTotalElements(), + devices.getDevices().getPageable().getPageNumber(), + devices.getDevices().getPageable().getPageSize() + ); + } + + @Override + public void save(Device entity) { + if (StringUtils.hasLength(entity.getId())) { + var getDeviceByIdRequest = new GetDeviceByCodeRequest(entity.getId().toString()); + var getDeviceByIdResponse = iamService.getDeviceByCode(getDeviceByIdRequest); + if (getDeviceByIdResponse.getDevice() != null) { + var updateDeviceRequest = new UpdateDeviceRequest( + entity.getId(), + entity.getCode(), + entity.getSecret() + ); + iamService.updateDevice(updateDeviceRequest); + } + } else { + var registerDeviceRequest = new RegisterDeviceRequest(entity.getCode()); + var registerDeviceResponse = iamService.registerDevice(registerDeviceRequest); + entity.setId(registerDeviceResponse.getDevice().getId()); + entity.setSecret(registerDeviceResponse.getDevice().getSecret()); + } + } + + @Override + public void delete(Object id) { + var deleteRequest = new DeleteDeviceRequest(id.toString()); + iamService.deleteDevice(deleteRequest); + } + + @Override + public Class getEntityType() { + return Device.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/Gallery.java b/edera-api/api/src/main/java/applica/app/domain/Gallery.java new file mode 100644 index 0000000..98453e7 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/Gallery.java @@ -0,0 +1,24 @@ +package applica.app.domain; + +import applica.crud.annotations.CrudEntity; +import applica.crud.attachments.Attachment; +import lombok.*; +import lombok.experimental.FieldDefaults; + +import java.util.List; + +@CrudEntity("gallery") +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class Gallery { + + String id; + String description; + List images; + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/I18nMessage.java b/edera-api/api/src/main/java/applica/app/domain/I18nMessage.java new file mode 100644 index 0000000..6e79605 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/I18nMessage.java @@ -0,0 +1,119 @@ +package applica.app.domain; + +import applica.crud.annotations.CrudEntity; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.io.File; +import java.io.InputStream; +import java.util.List; + +/** + * @author Roberto Conte Rosito + */ +@Data +@NoArgsConstructor +@CrudEntity(value = "i18n-message", listPermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }) +@ToString +@Document +public class I18nMessage { + private static Log log = LogFactory.getLog(I18nMessage.class); + + @Id + @MongoId(targetType = FieldType.STRING) + @Keyword + String id; + @Keyword + String code; + @Keyword + String lang; + @Keyword + String text; + + public I18nMessage(String lang, String code, String text) { + this.lang = lang; + this.code = code; + this.text = text; + this.id = String.format("%s.%s", lang, code); + } + + @JsonIgnore + public boolean isValid() { + return lang != null && code != null && text != null; + } + + @JsonIgnore + public boolean isEmpty() { + var isNull = lang == null && code == null && text == null; + return isNull || text.equals(code); + } + + public static I18nMessage create(String lang, String code, String text) { + return new I18nMessage(lang, code, text); + } + + private static void writeJson(List messages, String csvPath) { + var objectMapper = new ObjectMapper(); + objectMapper.getFactory().configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, false); + objectMapper.getFactory().configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true); + objectMapper.getFactory().configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); + objectMapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, false); + objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true); + var jsonFile = new File(csvPath); + + try { + messages.forEach(m -> m.setId(String.format("%s.%s", m.getLang(), m.getCode()))); + messages.sort((m1, m2) -> { + var langCompare = m1.getLang().compareTo(m2.getLang()); + if (langCompare == 0) { + return m1.getCode().compareTo(m2.getCode()); + } + return langCompare; + }); + objectMapper.writerWithDefaultPrettyPrinter().writeValue(jsonFile, messages); + } catch (Exception e) { + log.error(e); + } + } + + private static List readJson(InputStream jsonStream) { + var objectMapper = new ObjectMapper(); + try { + var messages = objectMapper.readValue(jsonStream, I18nMessage[].class); + + return List.of(messages); + } catch (Exception e) { + log.error(e); + return null; + } + } + + public static void persistAsResource(List messages) { + persistAsResource(messages, "i18n.json"); + } + + public static void persistAsResource(List messages, String filename) { + var jarPath = I18nMessage.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + var cleanPath = jarPath.replace("/target/classes/", ""); + var resourcePath = String.format("%s/src/main/resources/%s", cleanPath, filename); + writeJson(messages, resourcePath); + } + + public static List loadFromResource() { + var stream = I18nMessage.class.getResourceAsStream("/i18n.json"); + return readJson(stream); + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/I18nMessageRepository.java b/edera-api/api/src/main/java/applica/app/domain/I18nMessageRepository.java new file mode 100644 index 0000000..d2cd6ac --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/I18nMessageRepository.java @@ -0,0 +1,6 @@ +package applica.app.domain; + +import org.springframework.data.repository.CrudRepository; + +public interface I18nMessageRepository extends CrudRepository { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/Notification.java b/edera-api/api/src/main/java/applica/app/domain/Notification.java new file mode 100644 index 0000000..42821a1 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/Notification.java @@ -0,0 +1,76 @@ +package applica.app.domain; + +import applica.crud.annotations.CrudEntity; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.data.domain.AbstractAggregateRoot; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; +import org.springframework.util.StringUtils; + +import java.util.Date; +import java.util.UUID; + +/** + * @author Roberto Conte Rosito + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@CrudEntity(value = "notification", completePermissionsRoles = {"ROLE_ADMIN", "ROLE_USER", "ROLE_MAINTAINER", "ROLE_OPERATOR", "ROLE_CUSTOMER"}) +@Entity +public class Notification extends AbstractAggregateRoot { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + String userId; + + String title; + + String content; + + String resource; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + Date created; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + Date readed; + + public boolean isNew() { + return !StringUtils.hasLength(id); + } + + public Notification merge(Notification notification) { + if (notification == null) { + return this; + } + + this.setTitle(notification.getTitle()); + this.setContent(notification.getContent()); + this.setResource(notification.getResource()); + this.setUserId(notification.getUserId()); + this.setCreated(notification.getCreated()); + + return this; + } + + public static Notification create(String userId, String title, String content, String resource) { + return new Notification( + UUID.randomUUID().toString(), + userId, + title, + content, + resource, + new Date(), + null); + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/NotificationDataLayer.java b/edera-api/api/src/main/java/applica/app/domain/NotificationDataLayer.java new file mode 100644 index 0000000..7fe51c3 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/NotificationDataLayer.java @@ -0,0 +1,59 @@ +package applica.app.domain; + +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.query.CrudQuery; +import applica.crud.query.builders.CrudQueryBuilder; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class NotificationDataLayer implements DataLayer { + final DataLayer dataLayer; + + public NotificationDataLayer(CrudFactory crudFactory) { + dataLayer = crudFactory.createDataLayer(Notification.class); + } + @Override + public Optional get(Object id) { + return dataLayer.get(id); + } + + @Override + public Result find(CrudQuery query) { + var queryBuilder = CrudQueryBuilder.build(query); + var readed = queryBuilder.popFilter("readed").orElse(null); + if (readed != null) { + queryBuilder.setNullCheck(false); + if (readed.getValue().equals(true)) { + queryBuilder.ne("readAt", null); + } else { + queryBuilder.eq("readAt", null); + } + } + return dataLayer.find(queryBuilder.get()); + } + + @Override + public void save(Notification entity) { + if (!entity.isNew()) { + var old = dataLayer.get(entity.getId()).orElse(null); + if (old != null) { + entity = entity.merge(old); + } + } + dataLayer.save(entity); + } + + @Override + public void delete(Object id) { + dataLayer.delete(id); + } + + @Override + public Class getEntityType() { + return Notification.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/SubCategory.java b/edera-api/api/src/main/java/applica/app/domain/SubCategory.java new file mode 100644 index 0000000..43b9ac1 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/SubCategory.java @@ -0,0 +1,37 @@ +package applica.app.domain; + +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.query.Keyword; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +@CrudEntity("subCategory") +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@Entity +public class SubCategory { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + @NotNull + @JsonMaterialize(entityType = Category.class, destination = "category") + String categoryId; + + @NotEmpty + @Keyword + String description; + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/User.java b/edera-api/api/src/main/java/applica/app/domain/User.java new file mode 100644 index 0000000..cac8fc1 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/User.java @@ -0,0 +1,43 @@ +package applica.app.domain; + +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.Image; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.Date; +import java.util.List; + +@CrudEntity(value = "user", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN" }) +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class User { + + String id; + + @NotEmpty + String email; + + @NotEmpty + String name; + + @Image(nodeProperty = "_image", directory = "users") + String image; + + boolean active; + + Date registrationDate; + + @NotEmpty + List roles; + String password; + + String pinCode; + + String customerId; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/UsersDataLayer.java b/edera-api/api/src/main/java/applica/app/domain/UsersDataLayer.java new file mode 100644 index 0000000..5171e44 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/UsersDataLayer.java @@ -0,0 +1,180 @@ +package applica.app.domain; + +import applica.crud.datalayer.DataLayer; +import applica.crud.model.Result; +import applica.crud.operations.OperationException; +import applica.crud.query.CrudQuery; +import applica.crud.query.Filter; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.ResponseCodes; +import applica.iam.sdk.requests.*; +import org.springframework.data.domain.Range; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.util.*; + +import static applica.app.mapping.Mapper.userViewToUser; +import static applica.crud.model.ErrorCodes.OK; + +@Component +public class UsersDataLayer implements DataLayer { + + final IAMService iamService; + + public UsersDataLayer(IAMService iamService) { + this.iamService = iamService; + } + + @Override + public Optional get(Object id) { + var response = iamService.getUserById(new GetUserByIdRequest(id.toString())); + return Optional.ofNullable(userViewToUser(response.getUser())); + } + + @Override + public Result find(CrudQuery query) throws OperationException { + var registrationDateFilter = (Long) query.getFilterValue("registrationDate"); + Date registrationDateFrom = null; + Date registrationDateTo = null; + if (registrationDateFilter != null) { + var calendar = GregorianCalendar.getInstance(); + if (Objects.equals(Filter.GTE, query.getFilterType("registrationDate"))) { + registrationDateFrom = new Date(registrationDateFilter); + calendar.setTime(registrationDateFrom); + calendar.add(Calendar.YEAR, 1000); + registrationDateTo = calendar.getTime(); + } else { + registrationDateTo = new Date(registrationDateFilter); + calendar.setTime(registrationDateTo); + calendar.add(Calendar.YEAR, -1000); + registrationDateFrom = calendar.getTime(); + } + } + + Boolean active = (Boolean) query.getFilterValue("active"); + String keyword = query.getKeyword(); + String[] possibleKeywords = new String[]{"q", "keyword"}; + for (String possibleKeyword : possibleKeywords) { + String value = (String) query.getFilterValue(possibleKeyword); + if (StringUtils.hasLength(value)) { + keyword = value; + break; + } + } + + Map profile = null; + var customerId = query.popFilter("customerId"); + if (customerId.isPresent()) { + profile = Map.of("customerId", customerId.get().getValue()); + } + + var response = iamService.searchUsers(new SearchUsersRequest( + keyword, + (String) query.getFilterValue("mail"), + registrationDateFrom != null ? Range.closed(registrationDateFrom, registrationDateTo) : null, + active, + (String) query.getFilterValue("role"), + profile, + query.getPageable() + )); + + if (!OK.equals(response.getResponseCode())) { + throw new OperationException(response.getResponseCode()); + } + + return new Result<>( + response.getUsers().stream().map(u -> (Object) userViewToUser(u)).toList(), + response.getUsers().getTotalElements(), + response.getUsers().getPageable().getPageNumber(), + response.getUsers().getPageable().getPageSize() + ); + } + + @Override + @Transactional + public void save(Object entity) throws OperationException { + var user = (User) entity; + + var profile = new HashMap(); + profile.put("name", user.getName()); + profile.put("image", StringUtils.hasLength(user.getImage()) ? user.getImage() : ""); + profile.put("customerId", user.getCustomerId()); + + if (user.getId() == null) { + register(user, profile); + } else { + update(user, profile); + } + } + + private void update(User user, HashMap profile) throws OperationException { + iamService.updateProfile(new UpdateProfileRequest(user.getId(), profile)); + var response = iamService.getUserById(new GetUserByIdRequest(user.getId())); + if (!OK.equals(response.getResponseCode())) { + throw new OperationException(response.getResponseCode()); + } + if (!user.getRoles().equals(response.getUser().getRoles())) { + var updateRolesResponse = iamService.updateRoles(new UpdateRolesRequest(user.getId(), user.getRoles())); + if (!OK.equals(updateRolesResponse.getResponseCode())) { + throw new OperationException(updateRolesResponse.getResponseCode()); + } + } + if (user.getPassword() != null && !user.getPassword().isEmpty()) { + var resetPasswordResponse = iamService.resetPassword(new ResetPasswordRequest(user.getId(), user.getPassword())); + if (!OK.equals(resetPasswordResponse.getResponseCode())) { + throw new OperationException(resetPasswordResponse.getResponseCode()); + } + } + if (user.getPinCode() != null) { + var resetPinCodeResponse = iamService.resetPin(new ResetPinRequest(user.getId(), user.getPinCode())); + if (!OK.equals(resetPinCodeResponse.getResponseCode())) { + throw new OperationException(resetPinCodeResponse.getResponseCode()); + } + } + + if (user.isActive() == response.getUser().isActive()) { + return; + } + + if (user.isActive()) { + var enableUserResponse = iamService.enableUser(new EnableUserRequest(user.getId())); + if (!OK.equals(enableUserResponse.getResponseCode())) { + throw new OperationException(enableUserResponse.getResponseCode()); + } + } else { + var disableUserResponse = iamService.disableUser(new DisableUserRequest(user.getId())); + if (!OK.equals(disableUserResponse.getResponseCode())) { + throw new OperationException(disableUserResponse.getResponseCode()); + } + } + } + + private void register(User user, HashMap profile) throws OperationException { + var response = iamService.register(new RegistrationRequest( + user.getEmail(), + null, + user.getRoles(), + user.isActive(), + profile) + ); + if (!ResponseCodes.OK.equals(response.getResponseCode())) { + throw new OperationException(response.getResponseCode()); + } + user.setId(response.getUserId()); + if (StringUtils.hasLength(user.getPinCode())) { + iamService.resetPin(new ResetPinRequest(user.getId(), user.getPinCode())); + } + } + + @Override + public void delete(Object id) { + iamService.deleteUser(new DeleteUserRequest(id.toString())); + } + + @Override + public Class getEntityType() { + return User.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/AuditLog.java b/edera-api/api/src/main/java/applica/app/domain/audit/AuditLog.java new file mode 100644 index 0000000..7a8ff54 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/AuditLog.java @@ -0,0 +1,94 @@ +package applica.app.domain.audit; + +import applica.crud.annotations.CrudEntity; +import applica.crud.query.Keyword; +import applica.iam.sdk.readmodel.UserView; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.google.gson.Gson; +import jakarta.servlet.http.HttpServletRequest; +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Data +@CrudEntity(value = "audit-log", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN" }) +public class AuditLog { + final static String[] skipList = new String[] { + "/api/actuator/health", + "/api/entities/audit-log", + "/api/entities/notification/find", + "/api/entities/user/find", + "/api/entities/i18n-message", + "/api/entities/city", + "/api/entities/nation", + "/api/entities/province", + "/api/entities/region", + "/api/iam/login", + "/api/iam/impersonate", + "/api/iam/token-login", + "/api/iam/fresh-token", + "/api/profile/", + "/api/i18n/messages", + }; + final static Gson gson = new com.google.gson.Gson(); + + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + String userId; + @Keyword + String method; + @Keyword + String url; + String requestBody; + String responseBody; + @Keyword + String userAgent; + @Keyword + String ip; + AuditLogMessage message; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime created; + + public static AuditLog create( + HttpServletRequest request, + String requestBody, + String responseBody, + Optional loggedUser, + AuditLogMessageBuilderFactory auditLogMessageBuilderFactory) { + var auditLog = new AuditLog(); + auditLog.setIp(request.getRemoteAddr()); + auditLog.setUrl(request.getRequestURI()); + auditLog.setMethod(request.getMethod()); + auditLog.setUserAgent(request.getHeader("user-agent")); + auditLog.setCreated(LocalDateTime.now()); + auditLog.setRequestBody(requestBody); + auditLog.setResponseBody(responseBody); + auditLog.setMessage(auditLogMessageBuilderFactory.build(auditLog)); + if (loggedUser.isPresent()) { + auditLog.setUserId(loggedUser.get().getId()); + } + return auditLog; + } + + + public static boolean skip(HttpServletRequest request) { + var url = request.getRequestURI(); + for (String urlToSkip : skipList) { + if (url.startsWith(urlToSkip)) { + return true; + } + } + + return false; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessage.java b/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessage.java new file mode 100644 index 0000000..6f95219 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessage.java @@ -0,0 +1,15 @@ +package applica.app.domain.audit; + +import lombok.Data; + +import java.util.HashMap; + +@Data +public class AuditLogMessage { + String message; + HashMap args = new HashMap<>(); + + public void setArg(String key, Object value) { + args.put(key, value); + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessageBuilder.java b/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessageBuilder.java new file mode 100644 index 0000000..d8f2865 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessageBuilder.java @@ -0,0 +1,14 @@ +package applica.app.domain.audit; + +/** + * Definisce una interfaccia da implementare qualora si voglia provare a interpretare + * un log di audit secondo specifiche regole di parsing. + */ +public interface AuditLogMessageBuilder { + /** + * Restituisce la spiegazione del log di audit o NULL se non è possibile spiegarlo. + * @param auditLog il log di audit da spiegare + * @return la spiegazione del log di audit o NULL se non è possibile spiegarlo + */ + AuditLogMessage build(AuditLog auditLog); +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessageBuilderFactory.java b/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessageBuilderFactory.java new file mode 100644 index 0000000..5416f86 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/AuditLogMessageBuilderFactory.java @@ -0,0 +1,21 @@ +package applica.app.domain.audit; + +import java.util.List; + +public class AuditLogMessageBuilderFactory { + private List auditLogMessageBuilders; + + public AuditLogMessageBuilderFactory(List auditLogMessageBuilders) { + this.auditLogMessageBuilders = auditLogMessageBuilders; + } + + public AuditLogMessage build(AuditLog auditLog) { + for (var explainer : auditLogMessageBuilders) { + var explanation = explainer.build(auditLog); + if (explanation != null) { + return explanation; + } + } + return null; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudAuditLogMessageBuilder.java b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudAuditLogMessageBuilder.java new file mode 100644 index 0000000..b11bb0e --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudAuditLogMessageBuilder.java @@ -0,0 +1,41 @@ +package applica.app.domain.audit.builders; + +import applica.app.domain.audit.AuditLog; +import applica.app.domain.audit.AuditLogMessage; +import applica.app.domain.audit.AuditLogMessageBuilder; + +/** + * Definisce una classe base da poter utilizzare per la predisposizione di un builder che lavora con entità CRUD. + * Internamente espone già una serie di metodi utili a lavorare in questo contesto. + */ +public abstract class CrudAuditLogMessageBuilder implements AuditLogMessageBuilder { + public boolean isCrudEntity(AuditLog auditLog) { + return auditLog.getUrl().matches("/api/entities/[^/]+.*"); + } + + public String getI18nEntityName(AuditLog auditLog) { + var url = auditLog.getUrl(); + var entityName = url.split("/")[3]; + var i18nEntityName = String.format("resources.entities/%s.name", entityName); + + return i18nEntityName; + } + + /** + * L'unico metodo che devi implementare per gestire un messaggio relativo alla CRUD. + * Questo metodo sarà chiamato solo se il log di audit è relativo a una entità CRUD. + * @param auditLog il log di audit da spiegare + * @return la spiegazione del log di audit o NULL se non è possibile spiegarlo + */ + public abstract AuditLogMessage buildInternal(AuditLog auditLog); + + @Override + public AuditLogMessage build(AuditLog auditLog) { + if (isCrudEntity(auditLog)) { + return buildInternal(auditLog); + } + else { + return null; + } + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudCreateAuditLogMessageBuilder.java b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudCreateAuditLogMessageBuilder.java new file mode 100644 index 0000000..2c58557 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudCreateAuditLogMessageBuilder.java @@ -0,0 +1,41 @@ +package applica.app.domain.audit.builders; + +import applica.app.domain.audit.AuditLog; +import applica.app.domain.audit.AuditLogMessage; +import com.google.gson.Gson; +import com.google.gson.internal.LinkedTreeMap; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.HashMap; + +@Component +@SuppressWarnings("unused") +public class CrudCreateAuditLogMessageBuilder extends CrudAuditLogMessageBuilder { + private Gson gson = new Gson(); + @Override + public AuditLogMessage buildInternal(AuditLog auditLog) { + var requestBody = auditLog.getRequestBody(); + if (!StringUtils.hasLength(requestBody)) { + return null; + } + + var jsonData = gson.fromJson(requestBody, HashMap.class); + var entity = (LinkedTreeMap)jsonData.get("entity"); + if (entity == null) { + return null; + } + var id = (String)entity.get("id"); + if (StringUtils.hasLength(id)) { + return null; + } + + var method = auditLog.getMethod(); + var i18nEntityName = getI18nEntityName(auditLog); + var message = new AuditLogMessage(); + message.setMessage("ra.audit-log.entities/create"); + message.setArg("entity", i18nEntityName); + + return message; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudDeleteAuditLogMessageBuilder.java b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudDeleteAuditLogMessageBuilder.java new file mode 100644 index 0000000..50225f1 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudDeleteAuditLogMessageBuilder.java @@ -0,0 +1,35 @@ +package applica.app.domain.audit.builders; + +import applica.app.domain.audit.AuditLog; +import applica.app.domain.audit.AuditLogMessage; +import com.google.gson.Gson; +import org.springframework.stereotype.Component; + +import java.util.HashMap; + +@Component +@SuppressWarnings("unused") +public class CrudDeleteAuditLogMessageBuilder extends CrudAuditLogMessageBuilder { + private Gson gson = new Gson(); + + @Override + public AuditLogMessage buildInternal(AuditLog auditLog) { + var url = auditLog.getUrl(); + var isDelete = url.endsWith("/delete"); + if (!isDelete) { + return null; + } + + var method = auditLog.getMethod(); + var requestBody = auditLog.getRequestBody(); + var i18nEntityName = getI18nEntityName(auditLog); + var message = new AuditLogMessage(); + var jsonData = gson.fromJson(requestBody, HashMap.class); + var ids = (String)jsonData.get("ids"); + message.setMessage(String.format("ra.audit-log.entities/%s", method.toLowerCase())); + message.setArg("entity", i18nEntityName); + message.setArg("ids", ids); + + return message; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudEditAuditLogMessageBuilder.java b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudEditAuditLogMessageBuilder.java new file mode 100644 index 0000000..63b2c4f --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudEditAuditLogMessageBuilder.java @@ -0,0 +1,43 @@ +package applica.app.domain.audit.builders; + +import applica.app.domain.audit.AuditLog; +import applica.app.domain.audit.AuditLogMessage; +import com.google.gson.Gson; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +@Component +@SuppressWarnings("unused") +public class CrudEditAuditLogMessageBuilder extends CrudAuditLogMessageBuilder { + private Gson gson = new Gson(); + @Override + public AuditLogMessage buildInternal(AuditLog auditLog) { + var requestBody = auditLog.getRequestBody(); + if (!StringUtils.hasLength(requestBody)) { + return null; + } + + var jsonData = gson.fromJson(requestBody, HashMap.class); + var entity = (Map)jsonData.get("entity"); + + if (entity == null) { + return null; + } + var id = (String)entity.get("id"); + if (!StringUtils.hasLength(id)) { + return null; + } + + var method = auditLog.getMethod(); + var i18nEntityName = getI18nEntityName(auditLog); + var message = new AuditLogMessage(); + message.setMessage("ra.audit-log.entities/edit"); + message.setArg("entity", i18nEntityName); + message.setArg("id", id); + + return message; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudFindAuditLogMessageBuilder.java b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudFindAuditLogMessageBuilder.java new file mode 100644 index 0000000..99328a7 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudFindAuditLogMessageBuilder.java @@ -0,0 +1,23 @@ +package applica.app.domain.audit.builders; + +import applica.app.domain.audit.AuditLog; +import applica.app.domain.audit.AuditLogMessage; +import org.springframework.stereotype.Component; + +@Component +@SuppressWarnings("unused") +public class CrudFindAuditLogMessageBuilder extends CrudAuditLogMessageBuilder { + @Override + public AuditLogMessage buildInternal(AuditLog auditLog) { + var url = auditLog.getUrl(); + if (!url.endsWith("/find")) { + return null; + } + + var i18nEntityName = getI18nEntityName(auditLog); + var message = new AuditLogMessage(); + message.setMessage("ra.audit-log.entities/find"); + message.setArg("entity", i18nEntityName); + return message; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudViewAuditLogMessageBuilder.java b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudViewAuditLogMessageBuilder.java new file mode 100644 index 0000000..db2f0ff --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/audit/builders/CrudViewAuditLogMessageBuilder.java @@ -0,0 +1,29 @@ +package applica.app.domain.audit.builders; + +import applica.app.domain.audit.AuditLog; +import applica.app.domain.audit.AuditLogMessage; +import org.springframework.stereotype.Component; + +@Component +@SuppressWarnings("unused") +public class CrudViewAuditLogMessageBuilder extends CrudAuditLogMessageBuilder { + @Override + public AuditLogMessage buildInternal(AuditLog auditLog) { + var url = auditLog.getUrl(); + var method = auditLog.getMethod(); + + var isView = method.equals("GET") && url.split("/").length == 5; + if (!isView) { + return null; + } + + var id = url.split("/")[4]; + var i18nEntityName = getI18nEntityName(auditLog); + var message = new AuditLogMessage(); + message.setMessage("ra.audit-log.entities/" + method.toLowerCase()); + message.setArg("entity", i18nEntityName); + message.setArg("id", id); + + return message; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/customer/Area.java b/edera-api/api/src/main/java/applica/app/domain/customer/Area.java new file mode 100644 index 0000000..44df50d --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/customer/Area.java @@ -0,0 +1,62 @@ +package applica.app.domain.customer; + +import applica.app.domain.rfid.RFIDDevice; +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@CrudEntity(value = "customer-area", completePermissionsRoles = { "ROLE_ADMIN", "ROLE_OPERATOR" }, listPermissionsRoles = {"ROLE_MAINTAINER", "ROLE_CUSTOMER", "ROLE_USER"}) +@Document +public class Area { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Customer.class) + String customerId; + + @Indexed + @ForeignKey(primaryType = Office.class) + @JsonMaterialize(entityType = Office.class, destination = "office") + String officeId; + + @Indexed + @ForeignKey(primaryType = RFIDDevice.class) + String rfidDeviceId; + + @NotBlank + @Keyword + String name; + + @NotBlank + @Keyword + String description; + + @CreatedDate + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime created; + + @LastModifiedDate + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/customer/AreaRepository.java b/edera-api/api/src/main/java/applica/app/domain/customer/AreaRepository.java new file mode 100644 index 0000000..6b19830 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/customer/AreaRepository.java @@ -0,0 +1,9 @@ +package applica.app.domain.customer; + +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; + +public interface AreaRepository extends CrudRepository { + Optional findFirstByRfidDeviceId(String rfidDeviceId); +} diff --git a/edera-api/api/src/main/java/applica/app/domain/customer/Customer.java b/edera-api/api/src/main/java/applica/app/domain/customer/Customer.java new file mode 100644 index 0000000..962185d --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/customer/Customer.java @@ -0,0 +1,46 @@ +package applica.app.domain.customer; + +import applica.crud.annotations.CrudEntity; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@Data +@CrudEntity(value = "customer", completePermissionsRoles = { "ROLE_ADMIN", "ROLE_OPERATOR" }, listPermissionsRoles = "ROLE_MAINTAINER") +@NoArgsConstructor +@AllArgsConstructor +@Document +public class Customer { + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @NotBlank + @Keyword + String name; + + @NotBlank + @Keyword + String vatCode; + + boolean active; + + @CreatedDate + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime created; + + @LastModifiedDate + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/customer/CustomerRepository.java b/edera-api/api/src/main/java/applica/app/domain/customer/CustomerRepository.java new file mode 100644 index 0000000..e7e5fdd --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/customer/CustomerRepository.java @@ -0,0 +1,6 @@ +package applica.app.domain.customer; + +import org.springframework.data.repository.CrudRepository; + +public interface CustomerRepository extends CrudRepository { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/customer/Office.java b/edera-api/api/src/main/java/applica/app/domain/customer/Office.java new file mode 100644 index 0000000..a1cba2d --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/customer/Office.java @@ -0,0 +1,82 @@ +package applica.app.domain.customer; + + +import applica.app.domain.geo.City; +import applica.app.domain.geo.Nation; +import applica.app.domain.geo.Province; +import applica.app.domain.geo.Region; +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@Data +@CrudEntity(value = "customer-office", completePermissionsRoles = { "ROLE_ADMIN", "ROLE_OPERATOR" }) +@NoArgsConstructor +@AllArgsConstructor +public class Office { + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Customer.class) + String customerId; + + @Indexed + @ForeignKey(primaryType = City.class) + @JsonMaterialize(entityType = City.class, destination = "city") + String cityId; + + @Indexed + @ForeignKey(primaryType = Province.class) + @JsonMaterialize(entityType = Province.class, destination = "province") + String provinceId; + + @Indexed + @ForeignKey(primaryType = Region.class) + @JsonMaterialize(entityType = Region.class, destination = "region") + String regionId; + + @Indexed + @ForeignKey(primaryType = Nation.class) + @JsonMaterialize(entityType = Nation.class, destination = "nation") + String nationId; + + /* + Il nome è stato inserito nel caso serva in futuro + */ + @Keyword + String name; + + @NotBlank + @Keyword + String address; + + boolean headquarter; + + @NotBlank + @Keyword + String email; + + @CreatedDate + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime created; + + @LastModifiedDate + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/customer/Referent.java b/edera-api/api/src/main/java/applica/app/domain/customer/Referent.java new file mode 100644 index 0000000..c553e23 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/customer/Referent.java @@ -0,0 +1,60 @@ +package applica.app.domain.customer; + +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@CrudEntity(value = "customer-referent", completePermissionsRoles = { "ROLE_ADMIN", "ROLE_OPERATOR" }) +public class Referent { + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Customer.class) + String customerId; + + @Indexed + @ForeignKey(primaryType = Office.class) + @JsonMaterialize(entityType = Office.class, destination = "office") + String officeId; + + @NotBlank + @Keyword + String name; + @NotBlank + @Keyword + String surname; + + @Keyword + String email; + @Keyword + String mobile; + @Keyword + String unit; + + @CreatedDate + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime created; + + @LastModifiedDate + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxBuilder.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxBuilder.java new file mode 100644 index 0000000..ed11825 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxBuilder.java @@ -0,0 +1,180 @@ +package applica.app.domain.docx; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.xwpf.usermodel.*; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; + +import java.io.*; +import java.util.stream.Stream; + +public class DocxBuilder { + private final Log logger = LogFactory.getLog(getClass()); + + /** + * @see stackoverflow answer + * This method is responsible for generating a document as a ByteArrayInputStream, using an exisiting word template at templatePath. + * It replaces any keyTags in the document by the corresponding value in the JSONObject dataSource, + * it assumes the keyTags come preceeded by the separator "{#" and proceeded by "#}", in the following form: {#keyTag#} + * + * @param templatePath path to the template file + * @param dataSource JSONObject containing the keyTags and their corresponding values + * @return ByteArrayInputStream containing the generated document + */ + public ByteArrayInputStream generate(String templatePath, DocxDataSource dataSource) throws DocxException { + try { + var doc = new XWPFDocument(OPCPackage.open(templatePath)); + + for(XWPFParagraph p : doc.getParagraphs()){ + processParagraph(p, dataSource.get(0)); + } + + for(var table : doc.getTables()){ + processTable(table, dataSource); + } + + var out = new ByteArrayOutputStream(); + doc.write(out); + + return new ByteArrayInputStream(out.toByteArray()); + } catch (IOException | InvalidFormatException e) { + logger.error(e.getMessage(), e); + throw new DocxException(e.getMessage()); + } + } + + public ByteArrayInputStream generate(InputStream template, DocxDataSource dataSource) throws DocxException { + try { + var doc = new XWPFDocument(OPCPackage.open(template)); + for(XWPFParagraph p : doc.getParagraphs()){ + processParagraph(p, dataSource.get(0)); + } + + for(var table : doc.getTables()){ + processTable(table, dataSource); + } + + var out = new ByteArrayOutputStream(); + doc.write(out); + + return new ByteArrayInputStream(out.toByteArray()); + } + catch (IOException | InvalidFormatException e) { + logger.error(e.getMessage(), e); + throw new DocxException(e.getMessage()); + } + } + + /** + * This method is responsible for replacing any occurrences in the paragraph of the keyTags present + * in the JSONObject dataSourceRow by the corresponding value. + * + * @param paragraph paragraph to replace the keyTags + * @param dataSourceRow JSONObject containing the keyTags and their corresponding values + */ + public void processParagraph(XWPFParagraph paragraph, DocxDataSourceRow dataSourceRow){ + var text = paragraph.getText(); + if (!text.contains("{#")) { + return; + } + + for (var column : dataSourceRow.getColumns()){ + var bindValue = String.format("{#%s#}", column); + if( text.contains(bindValue)) { + mergeRunsWithSplittedKeyTags(paragraph); + for (var run : paragraph.getRuns()) { + checkAndReplaceFieldRun(run, bindValue, String.valueOf(dataSourceRow.get(column))); + } + } + } + } + + /** + * This method is responsible for replacing any occurrences in the table of the keyTags + * present in the JSONObject dataSource by the corresponding value + * + * @param table table to replace the keyTags + * @param dataSource JSONObject containing the keyTags and their corresponding values + */ + public void processTable(XWPFTable table, DocxDataSource dataSource){ + var hasHeader = table.getNumberOfRows() > 1; + var template = hasHeader + ? table.getRow(1) + : table.getRow(0); + for (var dataSourceRow : dataSource) { + var row = new XWPFTableRow((CTRow) template.getCtRow().copy(), table); + for( var cell : row.getTableCells()){ + if( cell.getParagraphs() != null && !cell.getParagraphs().isEmpty()){ + for(XWPFParagraph paragraph : cell.getParagraphs()){ + processParagraph(paragraph, dataSourceRow); + } + } + } + table.addRow(row); + } + + table.removeRow(hasHeader ? 1 : 0); + } + + public void checkAndReplaceFieldRun(XWPFRun run, String findStr, String value){ + String runText = run.getText(0); + if( runText!= null && runText.contains(findStr)){ + runText = runText.replace(findStr, value); + run.setText(runText, 0); + } + } + + /** + * A run is a part of the paragraph that has the same formatting. + * Word separates the text in paragraphs by different runs in an almost 'random' way, + * sometimes the tag we are looking for is splitted across multiple runs. + * This method merges the runs that have a keyTag or part of one, so that the keyTag starting with + * "{#" and ending with "#}" is in the same run + * + * @param paragraph paragraph to merge the runs + */ + public void mergeRunsWithSplittedKeyTags(XWPFParagraph paragraph){ + String runText; + XWPFRun run, nextRun; + var runs = paragraph.getRuns(); + + for( int i=0 ; i0) { + return completeOpenTagCount == completeCloseTagCount; + } else { + return incompleteOpenTagCount <= 0; + } + } + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxDataSource.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxDataSource.java new file mode 100644 index 0000000..a8b0214 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxDataSource.java @@ -0,0 +1,28 @@ +package applica.app.domain.docx; + +import java.util.ArrayList; +import java.util.List; + +/** + * Rappresenta un insieme di righe di dati da utilizzare per popolare un documento RTF. + */ +public class DocxDataSource extends ArrayList { + /** + * Restituisce l'elenco delle colonne presenti all'interno di ogni singola riga del DataSource. + * @return Elenco delle colonne presenti all'interno di ogni singola riga del DataSource. + */ + public List getColumns() { + if (!isEmpty()) { + var firstRow = get(0); + return new ArrayList<>(firstRow.keySet()); + } + + return new ArrayList<>(); + } + + public DocxDataSourceRow createRow() { + var row = new DocxDataSourceRow(); + add(row); + return row; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxDataSourceRow.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxDataSourceRow.java new file mode 100644 index 0000000..5bfbb8a --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxDataSourceRow.java @@ -0,0 +1,38 @@ +package applica.app.domain.docx; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; + +public class DocxDataSourceRow extends HashMap { + private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); + + @Override + public Object put(String key, Object value) { + return super.put(key, value); + } + + public void put(String key, LocalDateTime date) { + put(key, date.format(dateTimeFormatter)); + } + + public void put(String key, LocalDate date) { + put(key, date.format(dateFormatter)); + } + + public Object get(String key) { + var v = super.get(key); + if (v == null) { + return ""; + } + + return v; + } + + public ArrayList getColumns() { + return new ArrayList<>(keySet()); + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxDescriptor.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxDescriptor.java new file mode 100644 index 0000000..6994fbe --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxDescriptor.java @@ -0,0 +1,60 @@ +package applica.app.domain.docx; + +import java.util.ArrayList; + +public class DocxDescriptor extends ArrayList { + public static DocxDescriptor build() { + return new DocxDescriptor(); + } + + /** + * Un campo 'header' è un campo che non varia per ogni eventuale riga di dati. + * + * @param name Nome del campo. + * @param description Descrizione del campo. + * @return Riferimento all'istanza corrente. + */ + public DocxDescriptor header(String name, String description) { + var field = new DocxField(); + field.setName(name); + field.setDescription(description); + field.setBody(false); + + add(field); + return this; + } + + /** + * Un campo 'footer' è identico a un campo 'header' poiché non varia per ogni eventuale riga di dati. + * Questo metodo è stato aggiunto come 'convenzione' per rendere più leggibile il codice. + * + * @param name Nome del campo. + * @param description Descrizione del campo. + * @return Riferimento all'istanza corrente. + */ + public DocxDescriptor footer(String name, String description) { + return header(name, description); + } + + /** + * Un campo 'body' è differente da un campo 'header' poiché varia per ogni eventuale riga di dati. + * + * @param name Nome del campo. + * @param description Descrizione del campo. + * @return Riferimento all'istanza corrente. + */ + public DocxDescriptor body(String name, String description) { + var field = new DocxField(); + field.setName(name); + field.setDescription(description); + field.setBody(true); + + add(field); + return this; + } + + public DocxDescriptor get() { + return this; + } + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxException.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxException.java new file mode 100644 index 0000000..ab6f6bb --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxException.java @@ -0,0 +1,8 @@ +package applica.app.domain.docx; + +public class DocxException extends Exception { + public DocxException(String message) { + super(message); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxFactory.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxFactory.java new file mode 100644 index 0000000..02cdbeb --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxFactory.java @@ -0,0 +1,48 @@ +package applica.app.domain.docx; + +import applica.fs.FilesService; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.List; + +@Component +public class DocxFactory { + private final List types; + private final DocxBuilder builder; + private final FilesService filesService; + + public DocxFactory(List types, FilesService filesService) { + this.types = types; + this.builder = new DocxBuilder(); + this.filesService = filesService; + } + + public DocxTypeDef get(String type) { + return types.stream().filter(t -> t.getType().equals(type)).findFirst().orElse(null); + } + + public List getTypesNames() { + return types.stream().map(DocxTypeDef::getType).toList(); + } + + public ByteArrayInputStream generate(DocxTemplate template, String id) throws DocxException, FileNotFoundException { + var typeDef = get(template.getType()); + if (typeDef == null) { + throw new DocxException(String.format("Invalid type %s", template.getType())); + } + + var dataSource = typeDef.createDataSource(id); + if (dataSource.isEmpty()) { + throw new FileNotFoundException(String.format("Data source not found for type %s and id %s", template.getType(), id)); + } + var templateFile = filesService.get(template.getAttachment().getPath()); + return builder.generate(templateFile, dataSource); + } + + public ByteArrayInputStream generate(InputStream template, DocxDataSource dataSource) throws DocxException { + return builder.generate(template, dataSource); + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxField.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxField.java new file mode 100644 index 0000000..d99c26e --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxField.java @@ -0,0 +1,10 @@ +package applica.app.domain.docx; + +import lombok.Data; + +@Data +public class DocxField { + String name; + String description; + boolean body; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxTemplate.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxTemplate.java new file mode 100644 index 0000000..8ba5342 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxTemplate.java @@ -0,0 +1,38 @@ +package applica.app.domain.docx; + +import applica.crud.annotations.CrudEntity; +import applica.crud.attachments.Attachment; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.Id; +import lombok.Data; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@Document +@CrudEntity(value = "docx-template", + completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN"}, + listPermissionsRoles = {"ROLE_CUSTOMER", "ROLE_MAINTAINER", "ROLE_USER"}) +@Data +public class DocxTemplate { + @Id + @MongoId(targetType = FieldType.STRING) + String id; + String type; + @Keyword + String name; + Attachment attachment; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/DocxTypeDef.java b/edera-api/api/src/main/java/applica/app/domain/docx/DocxTypeDef.java new file mode 100644 index 0000000..9438209 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/DocxTypeDef.java @@ -0,0 +1,26 @@ +package applica.app.domain.docx; + +public abstract class DocxTypeDef { + + /** + * Definisce il tipo mappato e utilizzabile all'interno del template. + * Il tipo, in formato codice, deve essere localizzato nell'interfaccia. + */ + public abstract String getType(); + + /** + * Restituisce il descrittore associato al tipo. + * @return Descrittore associato al tipo. + */ + public abstract DocxDescriptor getDescriptor(); + + /** + * Consente, a partire da un ID specificato in input, di caricare il data source associato al tipo con i relativi dati. + * + * @param id ID del datasource da caricare. + * @return Data source associato al tipo con i relativi dati. + * @throws DocxException Eccezione generata in caso di errore durante il caricamento del datasource. + */ + public abstract DocxDataSource createDataSource(String id) throws DocxException; + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/docx/typedef/MaintenanceDocxTypeDef.java b/edera-api/api/src/main/java/applica/app/domain/docx/typedef/MaintenanceDocxTypeDef.java new file mode 100644 index 0000000..bd1df4c --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/docx/typedef/MaintenanceDocxTypeDef.java @@ -0,0 +1,151 @@ +package applica.app.domain.docx.typedef; + +import applica.app.domain.docx.DocxDataSource; +import applica.app.domain.docx.DocxDescriptor; +import applica.app.domain.docx.DocxTypeDef; +import applica.app.domain.equipment.EquipmentRepository; +import applica.app.domain.equipment.EquipmentTypeRepository; +import applica.app.domain.maintenance.*; +import applica.app.domain.protocol.ProtocolRepository; +import applica.app.domain.supplier.SupplierRepository; +import applica.app.domain.supply.SupplyRepository; +import org.apache.commons.lang3.StringUtils; +import org.springframework.format.datetime.DateFormatter; +import org.springframework.stereotype.Component; + +import java.time.format.DateTimeFormatterBuilder; +import java.util.List; + +@Component +@SuppressWarnings("unused") +public class MaintenanceDocxTypeDef extends DocxTypeDef { + public static final String TYPE = "maintenance"; + + private final ActivityRepository activityRepository; + private final ActivityTypeRepository activityTypeRepository; + private final MaintenanceRepository maintenanceRepository; + private final SupplyRepository supplyRepository; + private final ProtocolRepository protocolRepository; + private final EquipmentRepository equipmentRepository; + private final EquipmentTypeRepository equipmentTypeRepository; + + public MaintenanceDocxTypeDef( + ActivityRepository activityRepository, + ActivityTypeRepository activityTypeRepository, + MaintenanceRepository maintenanceRepository, + SupplyRepository supplyRepository, + ProtocolRepository protocolRepository, + EquipmentRepository equipmentRepository, + EquipmentTypeRepository equipmentTypeRepository, + SupplierRepository supplierRepository) { + this.activityRepository = activityRepository; + this.activityTypeRepository = activityTypeRepository; + this.maintenanceRepository = maintenanceRepository; + this.supplyRepository = supplyRepository; + this.protocolRepository = protocolRepository; + this.equipmentRepository = equipmentRepository; + this.equipmentTypeRepository = equipmentTypeRepository; + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public DocxDescriptor getDescriptor() { + return DocxDescriptor.build() + .header("ID", "Identificativo univoco alfanumerico della manutenzione") + .header("TITLE", "Titolo della manutenzione") + .header("DESCRIPTION", "Descrizione della manutenzione") + .header("INTERVENTION_NUMBER", "Numero intervento") + .header("DATE", "Data intervento") + .header("ACTIVITY_ID", "Identificativo univoco alfanumerico dell'attività correlata") + .header("ACTIVITY_TITLE", "Titolo dell'attività correlata") + .header("ACTIVITY_DESCR", "Descrizione dell'attività correlata") + .header("ACTIVITY_DATE", "Data dell'attività correlata") + .header("ACTIVITY_TYPE_ID", "Identificativo univoco alfanumerico del tipo di attività correlata") + .header("ACTIVITY_TYPE_DESCR", "Nome del tipo di attività correlata") + .header("SUPPLY_ID", "Identificativo univoco alfanumerico dell'approvvigionamento") + .header("SUPPLY_QUANTITY", "Quantità dell'approvvigionamento") + .header("SUPPLY_BREAKPOINT_IN_HOURS", "Punto di rottura in ore dell'approvvigionamento") + .header("SUPPLY_ACCUMULATED_HOURS", "Ore accumulate dall'apparecchiatura") + .header("SUPPLY_ORDER_DATE", "Data dell'ordine dell'approvvigionamento") + .header("SUPPLY_DELIVERY_DATE", "Data di consegna dell'approvvigionamento") + .header("SUPPLY_SERIAL_NUMBER", "Numero seriale dell'approvvigionamento") + .header("SUPPLY_DTT_NUMBER", "Numero DTT dell'approvvigionamento") + .header("EQUIPMENT_TYPE", "Tipo di approvvigionamento") + .header("PROTOCOL_ID", "Identificativo univoco alfanumerico del protocollo") + .header("PROTOCOL_TITLE", "Titolo del protocollo") + .header("PROTOCOL_DESCR", "Descrizione del protocollo") + .header("PROTOCOL_DATE", "Data del protocollo") + .body("INTERVENTION_ITEM_EQUIPMENT_TYPE_NAME", "Nome del tipo di apparecchiatura") + .body("INTERVENTION_ITEM_DESCRIPTION", "Descrizione dell'intervento") + .body("INTERVENTION_ITEM_SUBSTITUTION", "Sostituzione") + .get(); + } + + @Override + public DocxDataSource createDataSource(String id) { + var ds = new DocxDataSource(); + var maintenance = maintenanceRepository.findById(id).orElseThrow(); + var activity = activityRepository.findById(maintenance.getActivityId()).orElseThrow(); + var activityType = activityTypeRepository.findById(activity.getActivityTypeId()).orElseThrow(); + var supply = supplyRepository.findById(activity.getSupplyId()).orElseThrow(); + var protocol = protocolRepository.findById(supply.getProtocolId()).orElseThrow(); + var equipment = equipmentRepository.findById(supply.getEquipmentId()).orElseThrow(); + var equipmentType = equipmentTypeRepository.findById(equipment.getEquipmentTypeId()).orElseThrow(); + var dateFormatter = new DateFormatter(); + var localDateTimeFormatter = new DateTimeFormatterBuilder() + .toFormatter(); + + var bodyItems = createBody(maintenance); + for (var item : bodyItems) { + var row = ds.createRow(); + row.put("ID", maintenance.getId()); + row.put("TITLE", maintenance.getTitle()); + row.put("DESCRIPTION", maintenance.getDescription()); + row.put("INTERVENTION_NUMBER", maintenance.getInterventionNumber()); + row.put("DATE", maintenance.getDate()); + + if (!StringUtils.isEmpty(item.getEquipmentTypeId())) { + var itemEquipmentType = equipmentTypeRepository.findById(item.getEquipmentTypeId()).orElseThrow(); + row.put("INTERVENTION_ITEM_EQUIPMENT_TYPE_NAME", itemEquipmentType.getName()); + row.put("INTERVENTION_ITEM_DESCRIPTION", item.getDescription()); + row.put("INTERVENTION_ITEM_SUBSTITUTION", item.isSubstitution() ? "Sì" : "No"); + row.put("INTERVENTION_ITEM_REORDER", item.isReorder() ? "Sì" : "No"); + } + + row.put("ACTIVITY_ID", activity.getId()); + row.put("ACTIVITY_TITLE", activity.getTitle()); + row.put("ACTIVITY_DESCR", activity.getDescription()); + row.put("ACTIVITY_DATE", activity.getDate()); + row.put("ACTIVITY_TYPE_ID", activityType.getId()); + row.put("ACTIVITY_TYPE_DESCR", activityType.getDescription()); + row.put("SUPPLY_ID", supply.getId()); + row.put("SUPPLY_QUANTITY", supply.getQuantity()); + row.put("SUPPLY_BREAKPOINT_IN_HOURS", supply.getBreakpointInHours()); + row.put("SUPPLY_ACCUMULATED_HOURS", supply.getAccumulatedHours()); + row.put("SUPPLY_ORDER_DATE", supply.getOrderDate()); + row.put("SUPPLY_DELIVERY_DATE", supply.getDeliveryDate()); + row.put("SUPPLY_SERIAL_NUMBER", supply.getSerialNumber()); + row.put("SUPPLY_DTT_NUMBER", supply.getDdtNumber()); + row.put("EQUIPMENT_TYPE", equipmentType.getName()); + row.put("PROTOCOL_ID", protocol.getId()); + row.put("PROTOCOL_TITLE", protocol.getTitle()); + row.put("PROTOCOL_DESCR", protocol.getDescription()); + row.put("PROTOCOL_DATE", protocol.getProtocolDate()); + } + + return ds; + } + + private List createBody(Maintenance maintenance) { + var interventions = maintenance.getInterventions(); + if (interventions == null || interventions.isEmpty()) { + return List.of(new Intervention()); + } + + return interventions; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/dto/ActivityDetailsDTO.java b/edera-api/api/src/main/java/applica/app/domain/dto/ActivityDetailsDTO.java new file mode 100644 index 0000000..e48c403 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/dto/ActivityDetailsDTO.java @@ -0,0 +1,10 @@ +package applica.app.domain.dto; + +import lombok.Data; + +@Data +public class ActivityDetailsDTO { + String equipmentName; + String supplierName; + String locationName; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/dto/SupplyDetailsDTO.java b/edera-api/api/src/main/java/applica/app/domain/dto/SupplyDetailsDTO.java new file mode 100644 index 0000000..827e421 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/dto/SupplyDetailsDTO.java @@ -0,0 +1,10 @@ +package applica.app.domain.dto; + +import lombok.Data; + +@Data +public class SupplyDetailsDTO { + String supplierName; + String equipmentName; + String protocolName; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/equipment/Equipment.java b/edera-api/api/src/main/java/applica/app/domain/equipment/Equipment.java new file mode 100644 index 0000000..066a39c --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/equipment/Equipment.java @@ -0,0 +1,58 @@ +package applica.app.domain.equipment; + +import applica.app.domain.supplier.Supplier; +import applica.app.web.annotations.CustomerFilterable; +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "equipment", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }, listPermissionsRoles = {"ROLE_CUSTOMER","ROLE_MAINTAINER"}, savePermissionsRoles = {"ROLE_CUSTOMER","ROLE_MAINTAINER"}) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@CustomerFilterable +@Document +public class Equipment { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @Keyword + @ForeignKey(primaryType = EquipmentType.class) + String equipmentTypeId; + + @Indexed + @ForeignKey(primaryType = Supplier.class) + @JsonMaterialize(entityType = Supplier.class, destination = "supplier") + String supplierId; + + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; + + transient EquipmentType equipmentType; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentAttachment.java b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentAttachment.java new file mode 100644 index 0000000..dffd629 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentAttachment.java @@ -0,0 +1,50 @@ +package applica.app.domain.equipment; + +import applica.crud.annotations.CrudEntity; +import applica.crud.attachments.Attachment; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "equipment-attachment", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }, + listPermissionsRoles = {"ROLE_CUSTOMER","ROLE_MAINTAINER" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class EquipmentAttachment { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Equipment.class) + String equipmentId; + + @Keyword + String description; + + Attachment attachment; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentRepository.java b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentRepository.java new file mode 100644 index 0000000..81910b7 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentRepository.java @@ -0,0 +1,6 @@ +package applica.app.domain.equipment; + +import org.springframework.data.repository.CrudRepository; + +public interface EquipmentRepository extends CrudRepository { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentType.java b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentType.java new file mode 100644 index 0000000..19ec0be --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentType.java @@ -0,0 +1,68 @@ +package applica.app.domain.equipment; + +import applica.crud.annotations.Code; +import applica.crud.annotations.CrudEntity; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "equipment-type", + completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR", "ROLE_MAINTAINER", "ROLE_CUSTOMER" }, + listPermissionsRoles = {"ROLE_USER"} +) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@Document +public class EquipmentType { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + /** + * Il progressivo della tipologia di equipment ci servirà, in futuro, per l'addestramento del modello + * di machine learning per la predizione dei guasti. + */ + @Code + Long progressive; + + @Indexed + @ForeignKey(primaryType = EquipmentType.class) + String parentId; + + @Keyword + @NotBlank + String name; + + boolean accessory; + + /** + * Numero di ore di funzionamento dopo le quali l'attrezzatura deve essere sottoposta a manutenzione per probabile guasto. + */ + int breakpointInHours; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentTypeAttachment.java b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentTypeAttachment.java new file mode 100644 index 0000000..fd86342 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentTypeAttachment.java @@ -0,0 +1,49 @@ +package applica.app.domain.equipment; + +import applica.crud.annotations.CrudEntity; +import applica.crud.attachments.Attachment; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "equipment-type-attachment", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class EquipmentTypeAttachment { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Keyword + String description; + + Attachment attachment; + + @Indexed + @ForeignKey(primaryType = EquipmentType.class) + String typeId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentTypeRepository.java b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentTypeRepository.java new file mode 100644 index 0000000..b1f3740 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/equipment/EquipmentTypeRepository.java @@ -0,0 +1,6 @@ +package applica.app.domain.equipment; + +import org.springframework.data.repository.CrudRepository; + +public interface EquipmentTypeRepository extends CrudRepository { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/geo/City.java b/edera-api/api/src/main/java/applica/app/domain/geo/City.java new file mode 100644 index 0000000..8dbadb8 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/geo/City.java @@ -0,0 +1,43 @@ +package applica.app.domain.geo; + + +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +@CrudEntity(value = "city", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR", "ROLE_CUSTOMER", "ROLE_MAINTAINER" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class City { + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Province.class) + @JsonMaterialize(destination = "province", entityType = Province.class) + String provinceId; + + @Keyword + String name; + + @Keyword + String postalCode; + + @Keyword + String istatCode; + + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/geo/Nation.java b/edera-api/api/src/main/java/applica/app/domain/geo/Nation.java new file mode 100644 index 0000000..ee7c5eb --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/geo/Nation.java @@ -0,0 +1,31 @@ +package applica.app.domain.geo; + + +import applica.crud.annotations.CrudEntity; +import applica.crud.query.Keyword; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +@CrudEntity(value = "nation", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR", "ROLE_CUSTOMER", "ROLE_MAINTAINER" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class Nation { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Keyword + String code; + + @Keyword + String name; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/geo/Province.java b/edera-api/api/src/main/java/applica/app/domain/geo/Province.java new file mode 100644 index 0000000..ea7cee5 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/geo/Province.java @@ -0,0 +1 @@ +package applica.app.domain.geo; import applica.crud.annotations.CrudEntity; import applica.crud.annotations.JsonMaterialize; import applica.crud.constraints.ForeignKey; import applica.crud.query.Keyword; import lombok.*; import lombok.experimental.FieldDefaults; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.FieldType; import org.springframework.data.mongodb.core.mapping.MongoId; @CrudEntity(value = "province", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR", "ROLE_CUSTOMER", "ROLE_MAINTAINER" }) @AllArgsConstructor @Getter @Setter @NoArgsConstructor @ToString @EqualsAndHashCode @FieldDefaults(level = AccessLevel.PRIVATE) public class Province { @Id @MongoId(targetType = FieldType.STRING) String id; @Indexed @ForeignKey(primaryType = Region.class) @JsonMaterialize(destination = "region", entityType = Region.class) String regionId; @Keyword String name; @Keyword String code; } \ No newline at end of file diff --git a/edera-api/api/src/main/java/applica/app/domain/geo/Region.java b/edera-api/api/src/main/java/applica/app/domain/geo/Region.java new file mode 100644 index 0000000..a8d99a0 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/geo/Region.java @@ -0,0 +1,39 @@ +package applica.app.domain.geo; + +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +@CrudEntity(value = "region", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR", "ROLE_CUSTOMER", "ROLE_MAINTAINER" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class Region { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Nation.class) + @JsonMaterialize(destination = "nation", entityType = Nation.class) + String nationId; + + @Keyword + String code; + + @Keyword + String name; + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/maintenance/Activity.java b/edera-api/api/src/main/java/applica/app/domain/maintenance/Activity.java new file mode 100644 index 0000000..daf852f --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/maintenance/Activity.java @@ -0,0 +1,84 @@ +package applica.app.domain.maintenance; + +import applica.app.domain.User; +import applica.app.domain.customer.Customer; +import applica.app.domain.protocol.Protocol; +import applica.app.domain.supply.Supply; +import applica.app.web.annotations.CustomerFilterable; +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.annotations.LoggedUserId; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@CrudEntity(value = "activity", + completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN","ROLE_USER", "ROLE_CUSTOMER" }, + listPermissionsRoles = {"ROLE_MAINTAINER"}, + savePermissionsRoles = {"ROLE_MAINTAINER"}) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@CustomerFilterable +@Document +public class Activity { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Supply.class) + String supplyId; + + @Indexed + @ForeignKey(primaryType = ActivityType.class) + @JsonMaterialize(destination = "activityType", entityType = ActivityType.class) + String activityTypeId; + + @JsonMaterialize(destination = "user", entityType = User.class) + @LoggedUserId + String userId; + + @Keyword + @NotBlank + String title; + + @Keyword + String description; + + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate date; + + ActivityStatus status; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; + + transient Protocol protocol; + transient Supply supply; + transient Customer customer; + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityRepository.java b/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityRepository.java new file mode 100644 index 0000000..dff4ab8 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityRepository.java @@ -0,0 +1,9 @@ +package applica.app.domain.maintenance; + +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; + +public interface ActivityRepository extends CrudRepository { + Optional findFirstBySupplyIdAndActivityTypeIdOrderByCreatedDesc(String supplyId, String activityTypeId); +} diff --git a/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityStatus.java b/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityStatus.java new file mode 100644 index 0000000..45dac05 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityStatus.java @@ -0,0 +1,6 @@ +package applica.app.domain.maintenance; + +public enum ActivityStatus { + OPEN, + CLOSED +} diff --git a/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityType.java b/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityType.java new file mode 100644 index 0000000..453a894 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityType.java @@ -0,0 +1,50 @@ +package applica.app.domain.maintenance; + +import applica.crud.annotations.CrudEntity; +import applica.crud.attachments.Attachment; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "activity-type", + completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN" }, + listPermissionsRoles = { "ROLE_CUSTOMER", "ROLE_MAINTAINER", "ROLE_USER" } +) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@Document +public class ActivityType { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @NotBlank + @Keyword + String description; + + Attachment attachment; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityTypeRepository.java b/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityTypeRepository.java new file mode 100644 index 0000000..53cd99a --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/maintenance/ActivityTypeRepository.java @@ -0,0 +1,6 @@ +package applica.app.domain.maintenance; + +import org.springframework.data.repository.CrudRepository; + +public interface ActivityTypeRepository extends CrudRepository { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/maintenance/Intervention.java b/edera-api/api/src/main/java/applica/app/domain/maintenance/Intervention.java new file mode 100644 index 0000000..a68659a --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/maintenance/Intervention.java @@ -0,0 +1,18 @@ +package applica.app.domain.maintenance; + +import applica.app.domain.equipment.EquipmentType; +import applica.crud.annotations.JsonMaterialize; +import lombok.Data; +import org.springframework.data.mongodb.core.index.Indexed; + +@Data +public class Intervention { + @Indexed + @JsonMaterialize(destination = "equipmentType", entityType = EquipmentType.class) + String equipmentTypeId; + + String description; + + boolean substitution; + boolean reorder; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/maintenance/Maintenance.java b/edera-api/api/src/main/java/applica/app/domain/maintenance/Maintenance.java new file mode 100644 index 0000000..23d7957 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/maintenance/Maintenance.java @@ -0,0 +1,79 @@ +package applica.app.domain.maintenance; + +import applica.app.domain.User; +import applica.app.domain.protocol.Protocol; +import applica.app.web.annotations.CustomerFilterable; +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.annotations.LoggedUserId; +import applica.crud.attachments.Attachment; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@CrudEntity(value = "maintenance", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_CUSTOMER", "ROLE_USER" }, listPermissionsRoles = {"ROLE_MAINTAINER"}, savePermissionsRoles = {"ROLE_MAINTAINER"}, creationPermissionsRoles = {"ROLE_MAINTAINER"}) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@CustomerFilterable +@Document +public class Maintenance { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Activity.class) + String activityId; + + @LoggedUserId + @JsonMaterialize(entityType = User.class, destination = "user") + String userId; + + @Keyword + @NotBlank + String title; + + String description; + + @NotBlank + String interventionNumber; + + Attachment attachment; + + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate date; + + List interventions; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; + + transient Protocol protocol; + transient Activity activity; + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/maintenance/MaintenanceRepository.java b/edera-api/api/src/main/java/applica/app/domain/maintenance/MaintenanceRepository.java new file mode 100644 index 0000000..e5a59e9 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/maintenance/MaintenanceRepository.java @@ -0,0 +1,6 @@ +package applica.app.domain.maintenance; + +import org.springframework.data.repository.CrudRepository; + +public interface MaintenanceRepository extends CrudRepository { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/package-info.java b/edera-api/api/src/main/java/applica/app/domain/package-info.java new file mode 100644 index 0000000..888c375 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/package-info.java @@ -0,0 +1 @@ +package applica.app.domain; \ No newline at end of file diff --git a/edera-api/api/src/main/java/applica/app/domain/pricing/PriceList.java b/edera-api/api/src/main/java/applica/app/domain/pricing/PriceList.java new file mode 100644 index 0000000..f7d2bee --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/pricing/PriceList.java @@ -0,0 +1,57 @@ +package applica.app.domain.pricing; + +import applica.app.domain.supplier.Supplier; +import applica.crud.annotations.CrudEntity; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@CrudEntity(value = "price-list", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class PriceList { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @Keyword + @ForeignKey(primaryType = Supplier.class) + String supplierId; + + @Keyword + @NotBlank + String name; + + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate start; + + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate end; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/pricing/PriceListItem.java b/edera-api/api/src/main/java/applica/app/domain/pricing/PriceListItem.java new file mode 100644 index 0000000..59b6f00 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/pricing/PriceListItem.java @@ -0,0 +1,56 @@ +package applica.app.domain.pricing; + +import applica.app.domain.equipment.Equipment; +import applica.app.domain.equipment.EquipmentType; +import applica.app.domain.supplier.Supplier; +import applica.crud.annotations.CrudEntity; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "price-list-item", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class PriceListItem { + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @Keyword + @ForeignKey(primaryType = PriceList.class) + String priceListId; + + @Indexed + @Keyword + @ForeignKey(primaryType = Equipment.class) + String equipmentId; + + float price; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; + + transient Supplier supplier; + transient EquipmentType equipmentType; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/protocol/Protocol.java b/edera-api/api/src/main/java/applica/app/domain/protocol/Protocol.java new file mode 100644 index 0000000..fdd9d8d --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/protocol/Protocol.java @@ -0,0 +1,71 @@ +package applica.app.domain.protocol; + +import applica.app.domain.customer.Customer; +import applica.app.web.annotations.CustomerFilterable; +import applica.crud.annotations.CrudEntity; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@CrudEntity(value = "protocol", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }, listPermissionsRoles = {"ROLE_CUSTOMER", "ROLE_MAINTAINER"}, savePermissionsRoles = {"ROLE_CUSTOMER", "ROLE_MAINTAINER"}) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@CustomerFilterable +@Document +public class Protocol { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @Keyword + @ForeignKey(primaryType = Customer.class) + String customerId; + + @Keyword + @NotBlank + String title; + + @Keyword + String description; + + @Keyword + @NotBlank + String protocolNumber; + + List services; + + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate protocolDate; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; + + transient Customer customer; + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolAttachment.java b/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolAttachment.java new file mode 100644 index 0000000..f0f9c71 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolAttachment.java @@ -0,0 +1,50 @@ +package applica.app.domain.protocol; + +import applica.crud.annotations.CrudEntity; +import applica.crud.attachments.Attachment; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "protocol-attachment", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }, listPermissionsRoles = {"ROLE_CUSTOMER","ROLE_MAINTAINER"}) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ProtocolAttachment { + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Protocol.class) + String protocolId; + + @Keyword + @NotBlank + String description; + + Attachment attachment; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolRepository.java b/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolRepository.java new file mode 100644 index 0000000..824bda0 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolRepository.java @@ -0,0 +1,7 @@ +package applica.app.domain.protocol; + +import org.springframework.data.repository.CrudRepository; + +public interface ProtocolRepository extends CrudRepository{ + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolService.java b/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolService.java new file mode 100644 index 0000000..2997b60 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/protocol/ProtocolService.java @@ -0,0 +1,25 @@ +package applica.app.domain.protocol; + +import applica.app.domain.maintenance.ActivityType; +import applica.crud.constraints.ForeignKey; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.data.mongodb.core.index.Indexed; + +import java.time.LocalDate; + +@Data +public class ProtocolService { + @Indexed + @ForeignKey(primaryType = ActivityType.class) + String fromActivityTypeId; + + @Indexed + @ForeignKey(primaryType = ActivityType.class) + String toActivityTypeId; + + long frequency; + + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate end; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/reporting/DataPoint.java b/edera-api/api/src/main/java/applica/app/domain/reporting/DataPoint.java new file mode 100644 index 0000000..c7f91d7 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/reporting/DataPoint.java @@ -0,0 +1,73 @@ +package applica.app.domain.reporting; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.HashMap; + +@Data +@EqualsAndHashCode(callSuper = true) +public class DataPoint extends HashMap { + @Override + @JsonIgnore + public Object get(Object key) { + return super.get(key); + } + + public double getDouble(String key) { + var v = get(key); + if (v instanceof Double) { + return (double) v; + } else if (v instanceof Integer) { + return (int) v; + } else { + return 0; + } + } + + public int getInt(String key) { + var v = get(key); + if (v instanceof Integer) { + return (int) v; + } else if (v instanceof Double) { + return (int) (double) v; + } else { + return 0; + } + } + + public double getTrend(DataPoint other, String property) { + var thisAverage = getDouble(property); + var otherAverage = other.getDouble(property); + + if (thisAverage == 0 || otherAverage == 0) { + return 0; + } + + var v = ((thisAverage - otherAverage) / otherAverage) * 100; + return Math.round(v * 100.0) / 100.0; + } + + public DataPoint set(String key, Object value) { + put(key, value); + return this; + } + + public static DataPoint create() { + return new DataPoint(); + } + + public DataPoint rename(String key, String newKey) { + var value = get(key); + remove(key); + put(newKey, value); + return this; + } + + public DataPoint clone() { + DataPoint clone = (DataPoint) super.clone(); + clone.putAll(this); + return clone; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/reporting/DataPointSet.java b/edera-api/api/src/main/java/applica/app/domain/reporting/DataPointSet.java new file mode 100644 index 0000000..fa95818 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/reporting/DataPointSet.java @@ -0,0 +1,62 @@ +package applica.app.domain.reporting; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class DataPointSet { + List points; + + public DataPointSet() { + points = new ArrayList<>(); + } + + public DataPointSet(List points) { + this.points = new ArrayList<>(points); + } + + public double getTrend(DataPointSet other, String property) { + var thisAverage = getAverage(property); + var otherAverage = other.getAverage(property); + + if (thisAverage == 0 || otherAverage == 0) { + return 0; + } + + var v = ((thisAverage - otherAverage) / otherAverage) * 100; + return Math.round(v * 100.0) / 100.0; + } + + public double getSum(String property) { + return points.stream().mapToDouble(p -> p.getDouble(property)).sum(); + } + + public double getAverage(String property) { + return points.stream().mapToDouble(p -> p.getDouble(property)).average().orElse(0); + } + + public double getMin(String property) { + return points.stream().mapToDouble(p -> p.getDouble(property)).min().orElse(0); + } + + public double getMax(String property) { + return points.stream().mapToDouble(p -> p.getDouble(property)).max().orElse(0); + } + + public int getCount() { + return points.size(); + } + + public void add(DataPoint point) { + points.add(point); + } + + @JsonIgnore + public DataPoint getLast() { + return points.get(points.size() - 1); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/reporting/Filter.java b/edera-api/api/src/main/java/applica/app/domain/reporting/Filter.java new file mode 100644 index 0000000..988f989 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/reporting/Filter.java @@ -0,0 +1,32 @@ +package applica.app.domain.reporting; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Optional; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Filter implements Cloneable{ + Optional groupBy = Optional.empty(); + Optional supplyId = Optional.empty(); + Optional tagId = Optional.empty(); + Optional gatewayId = Optional.empty(); + Optional officeId = Optional.empty(); + + @Override + public Filter clone() { + try { + var filter = (Filter)super.clone(); + filter.setSupplyId(supplyId); + filter.setGatewayId(gatewayId); + filter.setTagId(tagId); + filter.setOfficeId(officeId); + return filter; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/reporting/FilterSet.java b/edera-api/api/src/main/java/applica/app/domain/reporting/FilterSet.java new file mode 100644 index 0000000..0736dc1 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/reporting/FilterSet.java @@ -0,0 +1,7 @@ +package applica.app.domain.reporting; + +import lombok.Data; + +@Data +public class FilterSet extends TemporalFilter { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/reporting/GroupBy.java b/edera-api/api/src/main/java/applica/app/domain/reporting/GroupBy.java new file mode 100644 index 0000000..d54e60e --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/reporting/GroupBy.java @@ -0,0 +1,19 @@ +package applica.app.domain.reporting; + +public enum GroupBy { + YEAR("year"), + MONTH("month"), + DAY("day"), + HOUR("hour"), + MINUTE("minute"); + + private final String alias; + + GroupBy(String alias) { + this.alias = alias; + } + + public String getAlias() { + return alias; + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/reporting/TemporalFilter.java b/edera-api/api/src/main/java/applica/app/domain/reporting/TemporalFilter.java new file mode 100644 index 0000000..b617209 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/reporting/TemporalFilter.java @@ -0,0 +1,190 @@ +package applica.app.domain.reporting; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.aggregation.*; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TemporalFilter extends Filter implements Cloneable { + LocalDateTime from; + LocalDateTime to; + + + public GroupBy getSuggestedGroupBy() { + if (groupBy.isPresent()) { + return groupBy.get(); + } + if (from == null || to == null) { + return GroupBy.YEAR; + } + + if (from.getYear() != to.getYear()) { + return GroupBy.YEAR; + } + + if (from.getMonth() != to.getMonth()) { + return GroupBy.MONTH; + } + + if (from.getDayOfMonth() != to.getDayOfMonth()) { + return GroupBy.DAY; + } + + if (from.getHour() != to.getHour()) { + return GroupBy.HOUR; + } + + if (from.getMinute() != to.getMinute()) { + return GroupBy.MINUTE; + } + + return GroupBy.YEAR; + } + + public ProjectionOperation project(String field) { + var groupBy = getSuggestedGroupBy(); + var dateOperators = List.of( + DateOperators.Year.yearOf(field), + DateOperators.Month.monthOf(field), + DateOperators.DayOfMonth.dayOfMonth(field), + DateOperators.Hour.hourOf(field), + DateOperators.Minute.minuteOf(field) + ); + var projectOperation = Aggregation.project(); + for (int i = 0; i <= groupBy.ordinal(); i++) { + projectOperation = projectOperation.and(dateOperators.get(i)).as(GroupBy.values()[i].getAlias()); + } + return projectOperation; + } + + public GroupOperation group(String... additionalFields) { + var groupBy = getSuggestedGroupBy(); + var fields = new String[groupBy.ordinal() + 1 + additionalFields.length]; + for (int i = 0; i <= groupBy.ordinal(); i++) { + fields[i] = GroupBy.values()[i].getAlias(); + } + for (int i = 0; i < additionalFields.length; i++) { + fields[groupBy.ordinal() + 1 + i] = additionalFields[i]; + } + + return Aggregation.group(fields); + } + + public SortOperation sort() { + var groupBy = getSuggestedGroupBy(); + var sortOperation = Aggregation.sort(Sort.Direction.ASC, GroupBy.values()[0].getAlias()); + for (int i = 1; i <= groupBy.ordinal(); i++) { + sortOperation = sortOperation.and(Sort.Direction.ASC, GroupBy.values()[i].getAlias()); + } + return sortOperation; + } + + public ProjectionOperation projectionAs() { + var projectionOperation = Aggregation.project(); + var groupBy = getSuggestedGroupBy(); + for (var i = 0; i <= groupBy.ordinal(); i++) { + var alias = GroupBy.values()[i].getAlias(); + projectionOperation = projectionOperation.and(alias).as(alias); + } + return projectionOperation; + } + + public MatchOperation between(String field) { + var criteria = new Criteria(); + criteria = criteria.and(field).gte(from).lte(to); + return Aggregation.match(criteria); + } + + + public TemporalFilter forTrend() { + var trendFilter = (TemporalFilter) clone(); + var groupBy = getSuggestedGroupBy(); + switch (groupBy) { + case YEAR: + trendFilter.setFrom(from.minusYears(1)); + trendFilter.setTo(to.minusYears(1)); + break; + case MONTH: + trendFilter.setFrom(from.minusMonths(1)); + trendFilter.setTo(to.minusMonths(1)); + break; + case DAY: + trendFilter.setFrom(from.minusDays(1)); + trendFilter.setTo(to.minusDays(1)); + break; + case HOUR: + trendFilter.setFrom(from.minusHours(1)); + trendFilter.setTo(to.minusHours(1)); + break; + case MINUTE: + trendFilter.setFrom(from.minusMinutes(1)); + trendFilter.setTo(to.minusMinutes(1)); + break; + } + return trendFilter; + } + + public TemporalFilter groupBy(GroupBy groupBy) { + this.setGroupBy(Optional.of(groupBy)); + return this; + } + + public TemporalFilter clone() { + var filter = (TemporalFilter) super.clone(); + filter.setFrom(from); + filter.setTo(to); + return filter; + } + + public static TemporalFilter between(LocalDateTime from, LocalDateTime to) { + var filter = new TemporalFilter(); + filter.setFrom(from); + filter.setTo(to); + return filter; + } + + public TemporalFilter currentMonth() { + var start = LocalDateTime.now().withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0); + var end = LocalDateTime.now().withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).plusMonths(1); + + var filter = (TemporalFilter) clone(); + filter.setFrom(start); + filter.setTo(end); + filter.setSupplyId(supplyId); + return filter; + } + + public TemporalFilter currentYear() { + var start = LocalDateTime.now().withDayOfYear(1).withHour(0).withMinute(0).withSecond(0); + var end = LocalDateTime.now().withDayOfYear(1).withHour(0).withMinute(0).withSecond(0).plusYears(1); + + var filter = (TemporalFilter) clone(); + filter.setFrom(start); + filter.setTo(end); + filter.setSupplyId(supplyId); + return filter; + } + + public TemporalFilter lastXDays(int days) { + var start = LocalDateTime.now().minusDays(days); + var end = LocalDateTime.now(); + + var filter = (TemporalFilter) clone(); + filter.setFrom(start); + filter.setTo(end); + return filter; + } + + public int getDays() { + return (int) (to.toLocalDate().toEpochDay() - from.toLocalDate().toEpochDay()); + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDevice.java b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDevice.java new file mode 100644 index 0000000..7c3c87a --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDevice.java @@ -0,0 +1,54 @@ +package applica.app.domain.rfid; + +import applica.crud.annotations.CrudEntity; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "rfid-device", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN" }, + listPermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_MAINTAINER", "ROLE_CUSTOMER", "ROLE_OPERATOR" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@Document +public class RFIDDevice { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @NotBlank + @Keyword + String name; + + @NotBlank + @Keyword + String code; + + @NotNull + RFIDDeviceType type; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceRepository.java b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceRepository.java new file mode 100644 index 0000000..beb4881 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceRepository.java @@ -0,0 +1,9 @@ +package applica.app.domain.rfid; + +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; + +public interface RFIDDeviceRepository extends CrudRepository { + Optional findFirstByCodeAndType(String code, RFIDDeviceType type); +} diff --git a/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrack.java b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrack.java new file mode 100644 index 0000000..3c5dbed --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrack.java @@ -0,0 +1,61 @@ +package applica.app.domain.rfid; + +import applica.app.domain.customer.Area; +import applica.app.domain.supply.Supply; +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "rfid-device-track", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_MAINTAINER", "ROLE_CUSTOMER", "ROLE_OPERATOR" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@Document +public class RFIDDeviceTrack { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = RFIDDevice.class) + @JsonMaterialize(destination = "tag", entityType = RFIDDevice.class) + String tagId; + + @Indexed + @ForeignKey(primaryType = Supply.class) + String supplyId; + + @Indexed + @ForeignKey(primaryType = RFIDDevice.class) + @JsonMaterialize(destination = "gateway", entityType = RFIDDevice.class) + String gatewayId; + + @Indexed + @ForeignKey(primaryType = Area.class) + String areaId; + + String additionalData; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime ts; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackRepository.java b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackRepository.java new file mode 100644 index 0000000..83e27f7 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackRepository.java @@ -0,0 +1,6 @@ +package applica.app.domain.rfid; + +import org.springframework.data.repository.CrudRepository; + +public interface RFIDDeviceTrackRepository extends CrudRepository, RFIDDeviceTrackStatsRepository { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackStatsRepository.java b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackStatsRepository.java new file mode 100644 index 0000000..439a832 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackStatsRepository.java @@ -0,0 +1,10 @@ +package applica.app.domain.rfid; + +import applica.app.domain.reporting.DataPointSet; +import applica.app.domain.reporting.TemporalFilter; + +public interface RFIDDeviceTrackStatsRepository { + DataPointSet getTotalTrackedRFID(TemporalFilter temporalFilter); + DataPointSet getMonthlyTotalTrackedRFID(TemporalFilter temporalFilter); + DataPointSet getTagsAndGatewaysNames(TemporalFilter temporalFilter); +} diff --git a/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackStatsRepositoryImpl.java b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackStatsRepositoryImpl.java new file mode 100644 index 0000000..76b5405 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceTrackStatsRepositoryImpl.java @@ -0,0 +1,104 @@ +package applica.app.domain.rfid; + +import applica.app.domain.reporting.DataPoint; +import applica.app.domain.reporting.DataPointSet; +import applica.app.domain.reporting.TemporalFilter; +import applica.app.domain.supply.Supply; +import com.mongodb.BasicDBObject; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.data.mongodb.core.aggregation.ArithmeticOperators; + +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; + +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@SuppressWarnings("unused") +public class RFIDDeviceTrackStatsRepositoryImpl implements RFIDDeviceTrackStatsRepository{ + + private final MongoTemplate mongoTemplate; + public RFIDDeviceTrackStatsRepositoryImpl(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + @Override + public DataPointSet getTotalTrackedRFID(TemporalFilter temporalFilter) { + var pipeline = new ArrayList() {{ + add(match(where("ts").gte(temporalFilter.getFrom()).lte(temporalFilter.getTo()))); + add(lookup("area", "areaId", "_id", "areas")); + add(unwind("areas")); + add(lookup("office", "areas.officeId", "_id", "office")); + add(unwind("office")); + temporalFilter.getOfficeId().ifPresent(officeId -> add(match(where("office._id").is(officeId)))); + + add(count().as("totalTrackedRFID")); + + add(project().andInclude("totalTrackedRFID") + .andExclude("_id")); + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var dataPoints = mongoTemplate.aggregate(aggregation, RFIDDeviceTrack.class, DataPoint.class); + return new DataPointSet(dataPoints.getMappedResults()); + } + + @Override + public DataPointSet getMonthlyTotalTrackedRFID(TemporalFilter temporalFilter) { + var pipeline = new ArrayList() {{ + add(match(where("ts").gte(temporalFilter.getFrom()).lte(temporalFilter.getTo()))); + add(lookup("area", "areaId", "_id", "areas")); + add(unwind("areas")); + add(lookup("office", "areas.officeId", "_id", "office")); + add(unwind("office")); + temporalFilter.getOfficeId().ifPresent(officeId -> add(match(where("office._id").is(officeId)))); + + add(group("supplyId")); + + add(count().as("totalUniqueSupplyId")); + + add(project().andInclude("totalUniqueSupplyId").andExclude("_id")); + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var dataPoints = mongoTemplate.aggregate(aggregation, RFIDDeviceTrack.class, DataPoint.class); + return new DataPointSet(dataPoints.getMappedResults()); + + } + + @Override + public DataPointSet getTagsAndGatewaysNames(TemporalFilter temporalFilter) { + var pipeline = new ArrayList() {{ + add(lookup("area", "areaId", "_id", "areas")); + add(unwind("areas", true)); + add(lookup("office", "areas.officeId", "_id", "office")); + add(unwind("office", true)); + temporalFilter.getOfficeId().ifPresent(officeId -> add(match(where("office._id").is(officeId)))); + + add(lookup("rFIDDevice", "tagId", "_id", "tag")); + add(lookup("rFIDDevice", "gatewayId", "_id", "gateway")); + + add(group("tagId", "gatewayId") + .first("tagId").as("tagId") + .first("tag.name").as("tagName") + .first("gatewayId").as("gatewayId") + .first("gateway.name").as("gatewayName")); + + add(group() + .addToSet(new BasicDBObject("tagId", "$tagId") + .append("tagName", "$tagName")).as("tags") + .addToSet(new BasicDBObject("gatewayId", "$gatewayId") + .append("gatewayName", "$gatewayName")).as("gateways")); + + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var dataPoints = mongoTemplate.aggregate(aggregation, RFIDDeviceTrack.class, DataPoint.class); + return new DataPointSet(dataPoints.getMappedResults()); + + } + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceType.java b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceType.java new file mode 100644 index 0000000..755d621 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/rfid/RFIDDeviceType.java @@ -0,0 +1,6 @@ +package applica.app.domain.rfid; + +public enum RFIDDeviceType { + TAG, + GATEWAY +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supplier/Referent.java b/edera-api/api/src/main/java/applica/app/domain/supplier/Referent.java new file mode 100644 index 0000000..5194ee2 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supplier/Referent.java @@ -0,0 +1,66 @@ +package applica.app.domain.supplier; + + +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "supplier-referent", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +public class Referent { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Supplier.class) + @JsonMaterialize(entityType = Supplier.class, destination = "supplier") + String supplierId; + + @NotBlank + @Keyword + String name; + + @NotBlank + @Keyword + String surname; + + @NotBlank + @Keyword + String email; + + @Keyword + String phone; + + @NotBlank + @Keyword + String department; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supplier/Supplier.java b/edera-api/api/src/main/java/applica/app/domain/supplier/Supplier.java new file mode 100644 index 0000000..b32c47f --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supplier/Supplier.java @@ -0,0 +1,61 @@ +package applica.app.domain.supplier; + +import applica.app.domain.geo.City; +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.query.Keyword; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "supplier", completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }, listPermissionsRoles = {"ROLE_MAINTAINER"}) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@Document +public class Supplier { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = City.class) + @Keyword + @JsonMaterialize(entityType = City.class, destination = "city") + String cityId; + + @NotBlank + @Keyword + String businessName; + + @NotBlank + @Keyword + String vatNumber; + + @Keyword + String address; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supplier/SupplierRepository.java b/edera-api/api/src/main/java/applica/app/domain/supplier/SupplierRepository.java new file mode 100644 index 0000000..0e32a1d --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supplier/SupplierRepository.java @@ -0,0 +1,6 @@ +package applica.app.domain.supplier; + +import org.springframework.data.repository.CrudRepository; + +public interface SupplierRepository extends CrudRepository { +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/Supply.java b/edera-api/api/src/main/java/applica/app/domain/supply/Supply.java new file mode 100644 index 0000000..e74e772 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/Supply.java @@ -0,0 +1,137 @@ +package applica.app.domain.supply; + +import applica.app.domain.customer.Area; +import applica.app.domain.customer.Customer; +import applica.app.domain.equipment.Equipment; +import applica.app.domain.equipment.EquipmentType; +import applica.app.domain.protocol.Protocol; +import applica.app.domain.rfid.RFIDDevice; +import applica.app.domain.rfid.RFIDDeviceTrack; +import applica.app.domain.supplier.Supplier; +import applica.app.web.annotations.CustomerFilterable; +import applica.crud.annotations.CrudEntity; +import applica.crud.annotations.JsonMaterialize; +import applica.crud.constraints.ForeignKey; +import applica.crud.operations.OperationException; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@CrudEntity(value = "supply", + completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR" }, + listPermissionsRoles = {"ROLE_MAINTAINER", "ROLE_CUSTOMER", "ROLE_USER"}, + savePermissionsRoles = {"ROLE_MAINTAINER", "ROLE_CUSTOMER"} +) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@CustomerFilterable +@Document +public class Supply { + + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + @ForeignKey(primaryType = Supplier.class) + @JsonMaterialize(destination = "supplier", entityType = Supplier.class) + String supplierId; + + @Indexed + @ForeignKey(primaryType = Equipment.class) + String equipmentId; + + @Indexed + @ForeignKey(primaryType = Protocol.class) + String protocolId; + + @Indexed + @ForeignKey(primaryType = RFIDDevice.class) + @JsonMaterialize(destination = "rfidDevice", entityType = RFIDDevice.class) + String rfidDeviceId; + + @Indexed + @ForeignKey(primaryType = Area.class) + @JsonMaterialize(destination = "area", entityType = Area.class) + String areaId; + + @Indexed + String usageId; + + @NotNull + int quantity; + /** + * Numero di ore di funzionamento dopo le quali l'attrezzatura deve essere sottoposta a manutenzione per probabile guasto. + * Questo campo, se valorizzato, prevale sullo stesso campo di EquipmentType. + */ + int breakpointInHours; + /** + * Numero di ore di funzionamento accumulate dall'attrezzatura. + */ + double accumulatedHours; + + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate orderDate; + + @JsonFormat(pattern = "yyyy-MM-dd") + LocalDate deliveryDate; + + String serialNumber; + + String ddtNumber; + + UsageStatus usageStatus; + + RFIDDeviceTrack latestRfidTrack; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; + + transient Protocol protocol; + transient EquipmentType equipmentType; + transient Equipment equipment; + transient Customer customer; + transient Supplier supplier; + transient List usages; + transient Area area; + transient Area latestArea; + + public void setUsage(Usage usage) { + this.usageId = usage.getId(); + this.usageStatus = UsageStatus.RUNNING; + } + + public void stopUsage(Usage usage) { + if (this.usageId != null) { + this.usageId = null; + this.usageStatus = UsageStatus.STOPPED; + this.accumulatedHours += usage.getDurationInHours(); + } + else { + throw new OperationException("ra.error.supply-not-in-use"); + } + } + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/SupplyRepository.java b/edera-api/api/src/main/java/applica/app/domain/supply/SupplyRepository.java new file mode 100644 index 0000000..444ed35 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/SupplyRepository.java @@ -0,0 +1,12 @@ +package applica.app.domain.supply; + + +import org.springframework.data.repository.CrudRepository; + +import java.util.List; +import java.util.Optional; + +public interface SupplyRepository extends CrudRepository, SupplyStatsRepository { + List findByProtocolId(String protocolId); + Optional findFirstByRfidDeviceId (String rfidDeviceId); +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/SupplyStatsRepository.java b/edera-api/api/src/main/java/applica/app/domain/supply/SupplyStatsRepository.java new file mode 100644 index 0000000..118836b --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/SupplyStatsRepository.java @@ -0,0 +1,25 @@ +package applica.app.domain.supply; + +import applica.app.domain.reporting.DataPoint; +import applica.app.domain.reporting.DataPointSet; +import applica.app.domain.reporting.TemporalFilter; +import applica.app.domain.rfid.RFIDDeviceTrack; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; + +import java.util.ArrayList; + +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +public interface SupplyStatsRepository { + + DataPointSet getCustomUsage(TemporalFilter temporalFilter); + DataPointSet getTotalUsage(TemporalFilter temporalFilter); + DataPointSet getAverageUsage(TemporalFilter temporalFilter); + DataPointSet getMonthlyUtilizationPercentage(TemporalFilter temporalFilter); + DataPointSet getLatestTrackedSupplies(TemporalFilter temporalFilter); + DataPointSet getMonthlyTrackingPercentage(TemporalFilter temporalFilter); + +} + diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/SupplyStatsRepositoryImpl.java b/edera-api/api/src/main/java/applica/app/domain/supply/SupplyStatsRepositoryImpl.java new file mode 100644 index 0000000..eabd0b0 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/SupplyStatsRepositoryImpl.java @@ -0,0 +1,279 @@ +package applica.app.domain.supply; + +import applica.app.domain.reporting.DataPoint; +import applica.app.domain.reporting.DataPointSet; +import applica.app.domain.reporting.GroupBy; +import applica.app.domain.reporting.TemporalFilter; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.*; + +import java.time.Month; +import java.time.Year; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@SuppressWarnings("unused") +public class SupplyStatsRepositoryImpl implements SupplyStatsRepository { + + private final MongoTemplate mongoTemplate; + + public SupplyStatsRepositoryImpl(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + @Override + public DataPointSet getCustomUsage(TemporalFilter temporalFilter) { + var pipeline = new ArrayList() {{ + temporalFilter.getSupplyId().ifPresent(supplyId -> add(match(where("_id").is(supplyId)))); + add(lookup("usage", "_id", "supplyId", "usages")); + add(unwind("usages")); + + + var suggestedGroupBy = temporalFilter.getSuggestedGroupBy(); + var divideBy = suggestedGroupBy == GroupBy.HOUR ? 3600000 : 86400000; + + add(temporalFilter.between("usages.start")); + add(temporalFilter + .project("usages.start") + .and(ArithmeticOperators.Divide.valueOf( + ArithmeticOperators.Subtract.valueOf("usages.stop").subtract("usages.start") + ).divideBy(divideBy)).as("total") + ); + add(temporalFilter.group().sum("total").as("total")); + add(temporalFilter.projectionAs().andInclude("total")); + + add(temporalFilter.sort()); + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var rawResults = mongoTemplate.aggregate(aggregation, Supply.class, DataPoint.class).getMappedResults(); + + + List transformedResults = new ArrayList<>(); + for (DataPoint rawResult : rawResults) { + double totalUsageHours; + if (rawResult.get("hours") != null) { + totalUsageHours = (double) rawResult.get("hours"); + } else { + return new DataPointSet(rawResults); + } + if (totalUsageHours > 24) + { + int fullDays = (int) (totalUsageHours / 24); + double remainingHours = totalUsageHours % 24; + + for (int i = 0; i < fullDays; i++) { + DataPoint transformedResult = new DataPoint(); + int year = (int) rawResult.get("year"); + int month = (int) rawResult.get("month"); + int day = (int) rawResult.get("day") + i; + + if (day > Month.of(month).length(Year.isLeap(year))) { + day = 1; + month++; + if (month > 12) { + month = 1; + year++; + } + } + + transformedResult.put("year", year); + transformedResult.put("month", month); + transformedResult.put("day", day); + transformedResult.put("totalUsageHours", 24); + transformedResults.add(transformedResult); + } + if (remainingHours > 0) { + DataPoint transformedResult = new DataPoint(); + int year = (int) rawResult.get("year"); + int month = (int) rawResult.get("month"); + int day = (int) rawResult.get("day") + fullDays; + + if (day > Month.of(month).length(Year.isLeap(year))) { + day = 1; + month++; + if (month > 12) { + month = 1; + year++; + } + } + + transformedResult.put("year", year); + transformedResult.put("month", month); + transformedResult.put("day", day); + transformedResult.put("totalUsageHours", remainingHours); + transformedResults.add(transformedResult); + } + } + else { + transformedResults.add(rawResult); + } + } + + return new DataPointSet(transformedResults); + } + + @Override + public DataPointSet getTotalUsage(TemporalFilter temporalFilter) { + var pipeline = new ArrayList() {{ + temporalFilter.getSupplyId().ifPresent(supplyId -> add(match(where("_id").is(supplyId)))); + add(lookup("usage", "_id", "supplyId", "usages")); + add(unwind("usages")); + add(match(where("usages.start").gte(temporalFilter.getFrom()).lte(temporalFilter.getTo()))); + + long daysBetween = ChronoUnit.DAYS.between(temporalFilter.getFrom(), temporalFilter.getTo()); + boolean useHours = daysBetween <= 60; + + if (useHours) { + add(project() + .and(ArithmeticOperators.Divide.valueOf( + ArithmeticOperators.Subtract.valueOf("usages.stop").subtract("usages.start") + ).divideBy(3600000)).as("usageDurationInHours") + ); + add(group().sum("usageDurationInHours").as("totalUsageHours")); + add(project() + .andInclude("totalUsageHours") + ); + } else { + add(project() + .and(ArithmeticOperators.Divide.valueOf( + ArithmeticOperators.Subtract.valueOf("usages.stop").subtract("usages.start") + ).divideBy(86400000)).as("usageDurationInDays") + ); + add(group().sum("usageDurationInDays").as("totalUsageDays")); + add(project() + .andInclude("totalUsageDays") + ); + } + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var dataPoints = mongoTemplate.aggregate(aggregation, Supply.class, DataPoint.class); + return new DataPointSet(dataPoints.getMappedResults()); + } + + + @Override + public DataPointSet getAverageUsage(TemporalFilter temporalFilter) { + + var pipeline = new ArrayList() {{ + temporalFilter.getSupplyId().ifPresent(supplyId -> add(match(where("_id").is(supplyId)))); + add(lookup("usage", "_id", "supplyId", "usages")); + add(unwind("usages")); + add(match(where("usages.start").gte(temporalFilter.getFrom()).lte(temporalFilter.getTo()))); + add(group().sum("usage.start").as("totalUsages").count().as("count")); + add(project() + .andInclude("count") + ); + + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var dataPoints = mongoTemplate.aggregate(aggregation, Supply.class, DataPoint.class); + return new DataPointSet(dataPoints.getMappedResults()); + } + + @Override + public DataPointSet getMonthlyUtilizationPercentage(TemporalFilter temporalFilter) { + var pipeline = new ArrayList() {{ + temporalFilter.getSupplyId().ifPresent(supplyId -> add(match(where("_id").is(supplyId)))); + add(lookup("usage", "_id", "supplyId", "usages")); + add(unwind("usages")); + add(match(where("usages.start").gte(temporalFilter.getFrom()).lte(temporalFilter.getTo()))); + add(temporalFilter.projectionAs() + .and(ArithmeticOperators.Multiply.valueOf( + ArithmeticOperators.Divide.valueOf("totalUsageDuration") + .divideBy(ChronoUnit.HOURS.between( + temporalFilter.getFrom(), temporalFilter.getTo()) + ) + ) + .multiplyBy(100)).as("utilizationPercentage") + ); + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var dataPoints = mongoTemplate.aggregate(aggregation, Supply.class, DataPoint.class); + return new DataPointSet(dataPoints.getMappedResults()); + } + + @Override + public DataPointSet getLatestTrackedSupplies(TemporalFilter temporalFilter) { + var pipeline = new ArrayList() {{ + add(lookup("area", "latestRfidTrack.areaId", "_id", "areas")); + add(unwind("areas", true)); + add(lookup("office", "areas.officeId", "_id", "office")); + add(unwind("office", true)); + temporalFilter.getOfficeId().ifPresent(officeId -> add(match(where("office._id").is(officeId)))); + temporalFilter.getGatewayId().ifPresent(gatewayId -> add( + match(where("latestRfidTrack.gatewayId").is(gatewayId)) + )); + temporalFilter.getTagId().ifPresent(tagId -> add(match(where("latestRfidTrack.tagId").is(tagId)))); + + if (temporalFilter.getTo() != null && temporalFilter.getFrom() != null) { + add(match(where("latestRfidTrack.ts").gte(temporalFilter.getFrom()).lte(temporalFilter.getTo()))); + } + + add(match(where("latestRfidTrack").exists(true))); + + add(lookup("equipment", "equipmentId", "_id", "equipment")); + add(unwind("equipment")); + add(lookup("equipmentType", "equipment.equipmentTypeId", "_id", "equipmentType")); + add(unwind("equipmentType")); + add(lookup("rFIDDevice", "latestRfidTrack.gatewayId", "_id", "gateway")); + add(unwind("gateway")); + add(lookup("rFIDDevice", "latestRfidTrack.tagId", "_id", "tag")); + add(unwind("tag")); + + add(project().andInclude("latestRfidTrack") + .and("equipmentType.name").as("equipmentTypeName") + .and("area.description").as("areaDescription") + .and("tag.code").as("tagCode") + .and("gateway.code").as("gatewayCode") + .andExclude("_id")); + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var dataPoints = mongoTemplate.aggregate(aggregation, Supply.class, DataPoint.class); + return new DataPointSet(dataPoints.getMappedResults()); + } + + @Override + public DataPointSet getMonthlyTrackingPercentage(TemporalFilter temporalFilter) { + + var pipeline = new ArrayList() {{ + add(lookup("area", "latestRfidTrack.areaId", "_id", "areas")); + add(unwind("areas", true)); + add(lookup("office", "areas.officeId", "_id", "office")); + add(unwind("office", true)); + temporalFilter.getOfficeId().ifPresent(officeId -> add(match(where("office._id").is(officeId)))); + + add(match(where("latestRfidTrack").exists(true))); + add(match(where("latestRfidTrack.ts").gte(temporalFilter.getFrom()).lte(temporalFilter.getTo()))); + + add(group().count().as("uniqueSupplyCount") + .addToSet("$_id").as("uniqueSupplies")); + + add(group().sum("uniqueSupplyCount").as("totalSupplies") + .first("uniqueSupplies").as("uniqueSuppliesList")); + + add(project() + .and(ArithmeticOperators.Multiply.valueOf( + ArithmeticOperators.Divide.valueOf("totalSupplies") + .divideBy(ArrayOperators.Size.lengthOfArray("uniqueSuppliesList")) + ) + .multiplyBy(100)).as("trackingPercentage") + ); + }}; + + var aggregation = Aggregation.newAggregation(pipeline); + var dataPoints = mongoTemplate.aggregate(aggregation, Supply.class, DataPoint.class); + return new DataPointSet(dataPoints.getMappedResults()); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/Usage.java b/edera-api/api/src/main/java/applica/app/domain/supply/Usage.java new file mode 100644 index 0000000..a8a5383 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/Usage.java @@ -0,0 +1,68 @@ +package applica.app.domain.supply; + +import applica.app.web.annotations.CustomerFilterable; +import applica.crud.annotations.CrudEntity; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldType; +import org.springframework.data.mongodb.core.mapping.MongoId; + +import java.time.LocalDateTime; + +@CrudEntity(value = "usage", + completePermissionsRoles = { "ROLE_SUPERUSER", "ROLE_ADMIN", "ROLE_OPERATOR", "ROLE_MAINTAINER", "ROLE_CUSTOMER" } +) +@AllArgsConstructor +@Getter +@Setter +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@FieldDefaults(level = AccessLevel.PRIVATE) +@CustomerFilterable +@Document +public class Usage { + @Id + @MongoId(targetType = FieldType.STRING) + String id; + + @Indexed + String supplyId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime start; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime stop; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @CreatedDate + LocalDateTime created; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + LocalDateTime updated; + + public static Usage start(String supplyId) { + Usage usage = new Usage(); + usage.setSupplyId(supplyId); + usage.setStart(LocalDateTime.now()); + return usage; + } + + public void stop() { + this.setStop(LocalDateTime.now()); + } + + @JsonIgnore + public int getDurationInHours() { + return (int) Math.ceil((double) (stop.getSecond() - start.getSecond()) / 3600); + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/UsageOverlapUtilsRepository.java b/edera-api/api/src/main/java/applica/app/domain/supply/UsageOverlapUtilsRepository.java new file mode 100644 index 0000000..696ffbb --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/UsageOverlapUtilsRepository.java @@ -0,0 +1,7 @@ +package applica.app.domain.supply; + +import java.time.LocalDateTime; + +public interface UsageOverlapUtilsRepository { + int countOverlappingUsages(String supplyId, LocalDateTime start, LocalDateTime end); +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/UsageOverlapUtilsRepositoryImpl.java b/edera-api/api/src/main/java/applica/app/domain/supply/UsageOverlapUtilsRepositoryImpl.java new file mode 100644 index 0000000..b8e42e3 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/UsageOverlapUtilsRepositoryImpl.java @@ -0,0 +1,30 @@ +package applica.app.domain.supply; + +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; + +import java.time.LocalDateTime; + +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@SuppressWarnings("unused") +public class UsageOverlapUtilsRepositoryImpl implements UsageOverlapUtilsRepository { + private final MongoTemplate mongoTemplate; + + public UsageOverlapUtilsRepositoryImpl(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + @Override + public int countOverlappingUsages(String supplyId, LocalDateTime start, LocalDateTime end) { + var query = new Query(); + query.addCriteria( + where("supplyId").is(supplyId) + .andOperator( + where("start").lte(end), + where("end").gte(start) + ) + ); + return (int) mongoTemplate.count(query, Usage.class); + } +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/UsageRepository.java b/edera-api/api/src/main/java/applica/app/domain/supply/UsageRepository.java new file mode 100644 index 0000000..427f8a8 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/UsageRepository.java @@ -0,0 +1,9 @@ +package applica.app.domain.supply; + +import org.springframework.data.repository.CrudRepository; + +import java.util.List; + +public interface UsageRepository extends CrudRepository, UsageOverlapUtilsRepository { + List findBySupplyId(String supplyId); +} diff --git a/edera-api/api/src/main/java/applica/app/domain/supply/UsageStatus.java b/edera-api/api/src/main/java/applica/app/domain/supply/UsageStatus.java new file mode 100644 index 0000000..a7e5c63 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/domain/supply/UsageStatus.java @@ -0,0 +1,6 @@ +package applica.app.domain.supply; + +public enum UsageStatus { + RUNNING, + STOPPED +} diff --git a/edera-api/api/src/main/java/applica/app/mapping/Mapper.java b/edera-api/api/src/main/java/applica/app/mapping/Mapper.java new file mode 100644 index 0000000..3a70cbd --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/mapping/Mapper.java @@ -0,0 +1,42 @@ +package applica.app.mapping; + +import applica.app.domain.Device; +import applica.app.domain.User; +import applica.iam.sdk.readmodel.DeviceView; +import applica.iam.sdk.readmodel.UserView; +import org.apache.commons.beanutils.PropertyUtils; + +import static applica.crud.utils.LangUtils.unchecked; + +public class Mapper { + + public static User userViewToUser(UserView userView) { + if (userView == null) { + return null; + } + var user = new User(); + unchecked(() -> PropertyUtils.copyProperties(user, userView)); + user.setId(userView.getId()); + user.setName(userView.getProfile().getOrDefault("name", null)); + user.setImage(userView.getProfile().getOrDefault("image", null)); + user.setCustomerId(userView.getProfile().getOrDefault("customerId", null)); + user.setRegistrationDate(userView.getRegistrationDate()); + + return user; + } + + public static Device deviceViewToDevice(DeviceView deviceView) { + if (deviceView == null) { + return null; + } + var device = new Device(); + unchecked(() -> PropertyUtils.copyProperties(device, deviceView)); + + device.setCode(deviceView.getCode()); + device.setSecret(deviceView.getSecret()); + device.setRegistrationDate(deviceView.getRegistrationDate()); + + return device; + } + +} diff --git a/edera-api/api/src/main/java/applica/app/ml/MLClient.java b/edera-api/api/src/main/java/applica/app/ml/MLClient.java new file mode 100644 index 0000000..6ddf2fe --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/ml/MLClient.java @@ -0,0 +1,52 @@ +package applica.app.ml; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import org.apache.commons.logging.Log; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; + +/** + * Machine Learning client used to communicate with python server. + */ +public class MLClient { + private final Log logger = org.apache.commons.logging.LogFactory.getLog(MLClient.class); + private final ObjectMapper mapper = new ObjectMapper(); + + @Getter + String endpoint; + HttpClient client = null; + + public MLClient(String endpoint) { + this.endpoint = endpoint; + this.client = HttpClient.newHttpClient(); + } + + /** + * Send a prediction request to the machine learning server. + * @param request Prediction request. + * @return Prediction response. + */ + public MLResponse predict(MLRequest request) { + var requestBuilder = HttpRequest.newBuilder(URI.create(endpoint + "/predict")); + + try { + var json = mapper.writeValueAsString(request); + var body = java.net.http.HttpRequest.BodyPublishers.ofString(json); + var requestWithBody = requestBuilder.POST(body) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .build(); + var response = client.send(requestWithBody, java.net.http.HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() != 200) { + throw new Exception(String.format("Error %d: %s", response.statusCode(), response.body())); + } + return mapper.readValue(response.body(), MLResponse.class); + } catch (Exception e) { + logger.error(e.getMessage()); + return MLResponse.failed(e); + } + } +} diff --git a/edera-api/api/src/main/java/applica/app/ml/MLRequest.java b/edera-api/api/src/main/java/applica/app/ml/MLRequest.java new file mode 100644 index 0000000..eb1658b --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/ml/MLRequest.java @@ -0,0 +1,85 @@ +package applica.app.ml; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; + +/** + * Machine Learning request. + */ +@Getter +@Setter +public class MLRequest { + /** + * Type of machine for which you are requesting the prediction. + */ + int machine; + /** + * Day of week from which you are requesting the prediction. + */ + int day; + /** + * Number of next days for which you are requesting the prediction. + */ + @JsonProperty("max_days") + Integer maxDays; + /** + * Max number of hours for which you are requesting the prediction. + * For example you can ask to predict usage based on working hours (8) or 24 hours. + */ + @JsonProperty("max_hours") + Integer maxHours; + /** + * Accumulated hours until now. + */ + @JsonProperty("accumulated_hours") + int accumulatedHours; + /** + * Number of total hours after which the machine will be considered as broken. + */ + @JsonProperty("breakpoint_hours") + int breakpointHours; + /** + * Machine Learning model threshold. + */ + float threshold; + + public MLRequest(int machine, int day) { + this.machine = machine; + this.day = day; + } + + public MLRequest withAccumulatedHours(int accumulatedHours) { + this.accumulatedHours = accumulatedHours; + return this; + } + + public MLRequest withBreakpointHours(int breakpointHours) { + this.breakpointHours = breakpointHours; + return this; + } + + public MLRequest withMaxDays(int maxDays) { + this.maxDays = maxDays; + return this; + } + + public MLRequest withMaxHours(int maxHours) { + this.maxHours = maxHours; + return this; + } + + public MLRequest withThreshold(float threshold) { + this.threshold = threshold; + return this; + } + + public MLRequest build() { + return this; + } + + public static MLRequest of(int machine, int day) { + return new MLRequest(machine, day); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/ml/MLResponse.java b/edera-api/api/src/main/java/applica/app/ml/MLResponse.java new file mode 100644 index 0000000..b7818f6 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/ml/MLResponse.java @@ -0,0 +1,24 @@ +package applica.app.ml; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; + +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MLResponse extends ArrayList { + String error; + boolean failed; + + public static MLResponse failed(Exception e) { + var response = new MLResponse(); + response.setFailed(true); + response.setError(e.getMessage()); + return response; + } +} diff --git a/edera-api/api/src/main/java/applica/app/ml/PredictionItem.java b/edera-api/api/src/main/java/applica/app/ml/PredictionItem.java new file mode 100644 index 0000000..86c53d4 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/ml/PredictionItem.java @@ -0,0 +1,17 @@ +package applica.app.ml; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PredictionItem { + int day; + int hours; + @JsonProperty("accumulated_hours") + int accumulatedHours; + boolean broken; +} diff --git a/edera-api/api/src/main/java/applica/app/services/EderaService.java b/edera-api/api/src/main/java/applica/app/services/EderaService.java new file mode 100644 index 0000000..7b9a262 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/services/EderaService.java @@ -0,0 +1,245 @@ +package applica.app.services; + +import applica.app.domain.customer.Area; +import applica.app.domain.customer.AreaRepository; +import applica.app.domain.dto.ActivityDetailsDTO; +import applica.app.domain.dto.SupplyDetailsDTO; +import applica.app.domain.equipment.Equipment; +import applica.app.domain.equipment.EquipmentType; +import applica.app.domain.maintenance.Activity; +import applica.app.domain.protocol.Protocol; +import applica.app.domain.rfid.*; +import applica.app.domain.supplier.Supplier; +import applica.app.domain.supply.Supply; +import applica.app.domain.supply.SupplyRepository; +import applica.app.domain.supply.Usage; +import applica.app.services.reporting.ReportFactory; +import applica.app.services.reporting.impl.SupplyReport; +import applica.app.services.reporting.impl.SupplyTracksReport; +import applica.app.web.requests.GetReportDataRequest; +import applica.app.web.responses.GetReportDataResponse; +import applica.crud.datalayer.DataLayerAwareAdapter; +import applica.crud.operations.OperationException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Map; + +@Component +public class EderaService extends DataLayerAwareAdapter { + + private final SupplyRepository supplyRepository; + private final RFIDDeviceRepository rfidDeviceRepository; + private final RFIDDeviceTrackRepository rfidDeviceTrackRepository; + private final AreaRepository areaRepository; + private final Log log = LogFactory.getLog(getClass()); + private final ObjectMapper objectMapper; + private final ReportFactory reportFactory; + + public EderaService(SupplyReport supplyReport, + SupplyTracksReport rfidDeviceTrackingReport, + SupplyRepository supplyRepository, + RFIDDeviceRepository rfidDeviceRepository, + RFIDDeviceTrackRepository rfidDeviceTrackRepository, + AreaRepository areaRepository, + ObjectMapper objectMapper, + ReportFactory reportFactory) { + this.supplyRepository = supplyRepository; + this.rfidDeviceRepository = rfidDeviceRepository; + this.rfidDeviceTrackRepository = rfidDeviceTrackRepository; + this.areaRepository = areaRepository; + this.objectMapper = objectMapper; + this.reportFactory = reportFactory; + } + + public ActivityDetailsDTO getActivityDetails(String activityId) { + var activity = dal(Activity.class).get(activityId); + if (activity.isEmpty()) { + throw new OperationException("ra.error.activity-not-found"); + } + var supply = dal(Supply.class).get(activity.get().getSupplyId()); + if (supply.isEmpty()) { + throw new OperationException("ra.error.supply-not-found"); + } + var equipment = dal(Equipment.class).get(supply.get().getEquipmentId()); + if (equipment.isEmpty()) { + throw new OperationException("ra.error.equipment-not-found"); + } + var supplier = dal(Supplier.class).get(supply.get().getSupplierId()); + if (supplier.isEmpty()) { + throw new OperationException("ra.error.supplier-not-found"); + } + var locationName = ""; + if (StringUtils.hasLength(supply.get().getRfidDeviceId())) { + var rfid = dal(RFIDDevice.class).get(supply.get().getRfidDeviceId()); + if (rfid.isEmpty()) { + throw new OperationException("ra.error.rfid-not-found"); + } + locationName = rfid.get().getName(); + } + else if (StringUtils.hasLength(supply.get().getAreaId())) { + var area = dal(Area.class).get(supply.get().getAreaId()); + if (area.isEmpty()) { + throw new OperationException("ra.error.area-not-found"); + } + locationName = area.get().getName(); + } + var equipmentType = dal(EquipmentType.class).get(equipment.get().getEquipmentTypeId()); + if (equipmentType.isEmpty()) { + throw new OperationException("ra.error.equipment-type-not-found"); + } + + ActivityDetailsDTO activityDetailsDTO = new ActivityDetailsDTO(); + activityDetailsDTO.setEquipmentName(equipmentType.get().getName()); + activityDetailsDTO.setSupplierName(supplier.get().getBusinessName()); + activityDetailsDTO.setLocationName(locationName); + return activityDetailsDTO; + } + + public SupplyDetailsDTO getSupplyDetails(String supplyId) { + var supply = dal(Supply.class).get(supplyId); + if (supply.isEmpty()) { + throw new OperationException("ra.error.supply-not-found"); + } + var equipment = dal(Equipment.class).get(supply.get().getEquipmentId()); + if (equipment.isEmpty()) { + throw new OperationException("ra.error.equipment-not-found"); + } + var supplier = dal(Supplier.class).get(supply.get().getSupplierId()); + if (supplier.isEmpty()) { + throw new OperationException("ra.error.supplier-not-found"); + } + var protocol = dal(Protocol.class).get(supply.get().getProtocolId()); + if (protocol.isEmpty()) { + throw new OperationException("ra.error.protocol-not-found"); + } + var equipmentType = dal(EquipmentType.class).get(equipment.get().getEquipmentTypeId()); + if (equipmentType.isEmpty()) { + throw new OperationException("ra.error.equipment-type-not-found"); + } + + SupplyDetailsDTO supplyDetailsDTO = new SupplyDetailsDTO(); + supplyDetailsDTO.setEquipmentName(equipmentType.get().getName()); + supplyDetailsDTO.setSupplierName(supplier.get().getBusinessName()); + supplyDetailsDTO.setProtocolName(protocol.get().getTitle()); + return supplyDetailsDTO; + + } + + public void startUsage(String supplyId){ + Usage usage = Usage.start(supplyId); + var supply = dal(Supply.class).get(supplyId); + if (supply.isPresent()) { + if (supply.get().getUsageId() == null) { + dal(Usage.class).save(usage); + supply.get().setUsage(usage); + dal(Supply.class).save(supply.get()); + }else { + throw new OperationException("ra.error.supply-already-in-use"); + } + } else { + throw new OperationException("ra.error.supply-not-found"); + } + + } + + public void stopUsage(String supplyId) { + var supply = dal(Supply.class).get(supplyId); + + if (supply.isPresent()) { + var usage = dal(Usage.class).get(supply.get().getUsageId()); + if (usage.isPresent()) { + usage.get().stop(); + supply.get().stopUsage(usage.get()); + dal(Supply.class).save(supply.get()); + dal(Usage.class).save(usage.get()); + } else { + throw new OperationException("ra.error.usage-not-found"); + } + }else { + throw new OperationException("ra.error.supply-not-found"); + } + } + + public GetReportDataResponse getReportData(String code, GetReportDataRequest request) throws RuntimeException { + var report = reportFactory.get(code); + if (report == null) { + throw new RuntimeException("Report not found"); + } + var data = report.execute(request); + return new GetReportDataResponse(data); + } + + public void save(String gatewayId, String tagId, Long ts, Map allParams) throws Exception { + + allParams.remove("tag"); + allParams.remove("timestamp"); + allParams.remove("gate"); + + if (gatewayId == null || gatewayId.isEmpty()) { + log.error("Invalid gateway"); + throw new Exception("Invalid gateway"); + } + + if (tagId == null || tagId.isEmpty()) { + log.error("Invalid tag"); + throw new Exception("Invalid tag"); + } + + if (ts == null) { + ts = System.currentTimeMillis(); + } + + String additionalDataJson; + try { + additionalDataJson = objectMapper.writeValueAsString(allParams); + } catch (Exception e) { + log.error("Error converting additional params to JSON", e); + throw new Exception("Error processing additional data"); + } + + var tag = rfidDeviceRepository.findFirstByCodeAndType(tagId, RFIDDeviceType.TAG).orElse(null); + + if (tag == null) { + log.error("Tag not found"); + throw new Exception("Tag not found"); + } + var gateway = rfidDeviceRepository.findFirstByCodeAndType(gatewayId, RFIDDeviceType.GATEWAY).orElse(null); + if (gateway == null) { + log.error("Gateway not found"); + throw new Exception("Gateway not found"); + } + var supply = supplyRepository.findFirstByRfidDeviceId(tag.getId()).orElse(null); + if (supply == null) { + log.error("Supply not found"); + throw new Exception("Supply not found"); + } + var area = areaRepository.findFirstByRfidDeviceId(gateway.getId()).orElse(null); + if (area == null) { + log.error("Area not found"); + throw new Exception("Area not found"); + } + + RFIDDeviceTrack track = new RFIDDeviceTrack( + null, + tag.getId(), + supply.getId(), + gateway.getId(), + area.getId(), + additionalDataJson, + Instant.ofEpochMilli(ts).atZone(ZoneId.systemDefault()).toLocalDateTime(), + LocalDateTime.now() + ); + + rfidDeviceTrackRepository.save(track); + supply.setLatestRfidTrack(track); + supplyRepository.save(supply); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/services/GeoInitializationService.java b/edera-api/api/src/main/java/applica/app/services/GeoInitializationService.java new file mode 100644 index 0000000..ac073f2 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/services/GeoInitializationService.java @@ -0,0 +1,209 @@ +package applica.app.services; + +import applica.app.domain.geo.City; +import applica.app.domain.geo.Nation; +import applica.app.domain.geo.Province; +import applica.app.domain.geo.Region; +import applica.crud.datalayer.DataLayerAwareAdapter; +import applica.crud.query.builders.CrudQueryBuilder; +import lombok.SneakyThrows; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.UUID; + +@Service +public class GeoInitializationService extends DataLayerAwareAdapter implements InitializingBean { + + private final Log logger = LogFactory.getLog(getClass()); + + private final String nationCsvPath; + private final String regionCsvPath; + private final String provinceCsvPath; + private final String cityCsvPath; + + private final MongoTemplate mongoTemplate; + + public GeoInitializationService( + @Value("${geo.csv.nation}") String nationCsvPath, + @Value("${geo.csv.region}") String regionCsvPath, + @Value("${geo.csv.province}") String provinceCsvPath, + @Value("${geo.csv.city}") String cityCsvPath, + MongoTemplate mongoTemplate) { + this.nationCsvPath = nationCsvPath; + this.regionCsvPath = regionCsvPath; + this.provinceCsvPath = provinceCsvPath; + this.cityCsvPath = cityCsvPath; + this.mongoTemplate = mongoTemplate; + } + + @Override + @ConditionalOnProperty(name = "app.test", havingValue = "false") + public void afterPropertiesSet() { + importNations(); + importRegions(); + importProvinces(); + importCities(); + } + + private String[] loadCsvResourceFile(String resourceName) { + var file = GeoInitializationService.class.getResourceAsStream(resourceName); + assert file != null; + var streamReader = new InputStreamReader(file); + var reader = new BufferedReader(streamReader); + return reader.lines().skip(1).toArray(String[]::new); + } + + + @Transactional + @SneakyThrows + public void importNations() { + logger.info("Importing nations"); + var lines = loadCsvResourceFile(nationCsvPath); + var query = new Query(); + var count = mongoTemplate.count(query, Nation.class); + if (lines.length == count) { + logger.info("%s nations already loaded".formatted(count)); + return; + } + for(var line : lines) { + String[] values = line.split(";"); + String code = values[0]; + String description = values[1]; + + Nation existingNation = dal(Nation.class) + .find(CrudQueryBuilder.build().eq("code", code).get()) + .findFirst().orElse(null); + + if (existingNation == null) { + Nation nation = new Nation(UUID.randomUUID().toString(), code, description); + dal(Nation.class).save(nation); + } + } + + logger.info("%s nations created".formatted(lines.length)); + } + + + + @Transactional + @SneakyThrows + public void importRegions() { + logger.info("Importing regions"); + var lines = loadCsvResourceFile(regionCsvPath); + var query = new Query(); + var count = mongoTemplate.count(query, Region.class); + if (lines.length == count) { + logger.info("%s regions already loaded".formatted(count)); + return; + } + + var created = 0; + for (var line : lines) { + String[] values = line.split(";"); + String code = values[0]; + String name = values[1]; + String nationCode = values[2]; + + Region existingRegion = dal(Region.class).find(CrudQueryBuilder.build().eq("name", name).get()) + .findFirst().orElse(null); + + if (existingRegion == null) { + Nation nation = dal(Nation.class).find(CrudQueryBuilder.build().eq("code", nationCode).get()) + .findFirst().orElseThrow(() -> new Exception("Nation not found")); + Region region = new Region(UUID.randomUUID().toString(), nation.getId(), code, name); + dal(Region.class).save(region); + created++; + } + } + + logger.info("%s regions created".formatted(created)); + } + + + @Transactional + @SneakyThrows + public void importProvinces() { + logger.info("Importing provinces"); + var lines = loadCsvResourceFile(provinceCsvPath); + var query = new Query(); + var count = mongoTemplate.count(query, Province.class); + if (lines.length == count) { + logger.info("%s provinces already loaded".formatted(count)); + return; + } + var created = 0; + for (var line : lines) { + String[] values = line.split(";"); + String name = values[0]; + String regionName = values[1]; + String code = values[2]; + + Province existingProvince = dal(Province.class).find(CrudQueryBuilder.build().eq("name", name).get()) + .findFirst().orElse(null); + + if (existingProvince == null) { + Region region = dal(Region.class).find(CrudQueryBuilder.build().eq("name", regionName).get()) + .findFirst().orElseThrow(() -> new Exception("Region not found")); + Province province = new Province(UUID.randomUUID().toString(), region.getId(), name, code); + dal(Province.class).save(province); + created++; + } + } + + logger.info("%s provinces created".formatted(created)); + } + + + @Transactional + @SneakyThrows + public void importCities() { + logger.info("Importing cities"); + var lines = loadCsvResourceFile(cityCsvPath); + var query = new Query(); + var count = mongoTemplate.count(query, City.class); + if (lines.length == count) { + logger.info("%s cities already loaded".formatted(count)); + return; + } + + var created = 0; + for (var line : lines) { + String[] values = line.split(","); + String name = values[0]; + String istatCode = values[1]; + String provinceName = values[2]; + String provinceCode = values[3]; + String postalCode = values[6]; + + City existingCity = dal(City.class).find(CrudQueryBuilder.build() + .eq("postalCode", postalCode) + .eq("name", name).get()) + .findFirst() + .orElse(null); + + if (existingCity == null) { + Province province = dal(Province.class).find(CrudQueryBuilder.build().eq("name", provinceName).get()) + .findFirst() + .orElse( + dal(Province.class) + .find(CrudQueryBuilder.build().eq("code", provinceCode).get()) + .findFirst().orElseThrow(() -> new Exception("Province not found"))); + City city = new City(UUID.randomUUID().toString(), province.getId(), name, postalCode, istatCode); + dal(City.class).save(city); + created++; + } + } + logger.info("%s cities created".formatted(created)); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/services/InitializationService.java b/edera-api/api/src/main/java/applica/app/services/InitializationService.java new file mode 100644 index 0000000..abc57a3 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/services/InitializationService.java @@ -0,0 +1,154 @@ +package applica.app.services; + +import applica.app.domain.I18nMessage; +import applica.app.domain.I18nMessageRepository; +import applica.app.domain.Notification; +import applica.crud.acl.CrudPermission; +import applica.crud.acl.CrudSecurityConfigurer; +import applica.crud.annotations.CrudEntity; +import applica.crud.factory.CrudFactory; +import applica.crud.model.CrudEntitiesRegistry; +import applica.crud.query.builders.CrudQueryBuilder; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.requests.SearchUsersRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.format.DateTimeFormatter; +import java.util.*; + +@SuppressWarnings("unused") +@Service +public class InitializationService implements InitializingBean { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final IAMService iamService; + private final CrudFactory crudFactory; + private final I18nMessageRepository i18nMessageRepository; + private final boolean test; + private static final Random RANDOM = new Random(); + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + + public InitializationService(IAMService iam, CrudFactory crudFactory, I18nMessageRepository i18nMessageRepository, @Value("${app.test}") boolean test) { + this.iamService = iam; + this.crudFactory = crudFactory; + this.i18nMessageRepository = i18nMessageRepository; + this.test = test; + } + + @Override + @ConditionalOnProperty(name = "app.test", havingValue = "false") + public void afterPropertiesSet() throws InterruptedException { + if (!test) { + initializeI18nMessages(); + initializeWelcomeNotification(); + } + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + + tryInitializeWebEntitiesSecurity(); + } + + private void tryInitializeWebEntitiesSecurity() throws InterruptedException { + int retries = 0; + while (retries < 10) { + try { + var response = iamService.initializeAdmin(); + if (response == null) { + return; + } + initializeWebEntitiesSecurity(); + break; + } catch (Exception e) { + retries++; + logger.warn("Error initializing IAM, retrying: {}", e.getMessage()); + int randomSeconds = (int) (Math.random() * 3) + 3; + logger.warn("Waiting {} seconds to allow IAM to initialize", randomSeconds); + Thread.sleep(randomSeconds * 1000L); + } + } + } + + private void initializeWebEntitiesSecurity() { + var adminRole = iamService.getIamOptions().getAdminRole(); + var roles = iamService.getIamOptions().getRoles(); + roles.forEach(role -> { + if (role.equals(adminRole)){ + CrudEntitiesRegistry.instance().getDefinitions().forEach(d -> { + CrudSecurityConfigurer.instance().configure(d.getId(), adminRole, CrudPermission.values()); + }); + } else { + CrudEntitiesRegistry.instance().getDefinitions().forEach(d -> { + CrudEntity annotation = d.getType().getAnnotation(CrudEntity.class); + List _permissions = new ArrayList<>(); + + if (Arrays.asList(annotation.completePermissionsRoles()).contains(role)){ + _permissions.addAll(Arrays.stream(CrudPermission.values()).toList()); + } else { + if (Arrays.asList(annotation.creationPermissionsRoles()).contains(role)){ + _permissions.add(CrudPermission.NEW); + } + if (Arrays.asList(annotation.deletePermissionsRoles()).contains(role)){ + _permissions.add(CrudPermission.DELETE); + } + if (Arrays.asList(annotation.savePermissionsRoles()).contains(role)){ + _permissions.add(CrudPermission.EDIT); + _permissions.add(CrudPermission.SAVE); + } + if (Arrays.asList(annotation.listPermissionsRoles()).contains(role)){ + _permissions.add(CrudPermission.LIST); + } + } + + CrudPermission[] permissions = new CrudPermission[_permissions.size()]; + _permissions.toArray(permissions); + CrudSecurityConfigurer.instance().configure(d.getId(), role, permissions); + }); + } + }); + + logger.info("Web entities security initialized"); + } + + @Transactional + private void initializeI18nMessages() { + var messages = I18nMessage.loadFromResource(); + i18nMessageRepository.deleteAll(); + i18nMessageRepository.saveAll(messages); + logger.info("%s i18n messages loaded".formatted(messages.size())); + } + + private void initializeWelcomeNotification() { + var searchUsersRequest = new SearchUsersRequest(); + searchUsersRequest.setPageable(Pageable.ofSize(100)); + searchUsersRequest.setRole("ROLE_ADMIN"); + + var searchUsersResponse = iamService.searchUsers(searchUsersRequest); + var users = searchUsersResponse.getUsers(); + var dal = crudFactory.createDataLayer(Notification.class); + for (var user : users) { + var query = CrudQueryBuilder + .build() + .eq("userId", user.getId()) + .eq("title", "Welcome to Applica") + .get(); + var notification = dal.find(query).findFirst().orElse(null); + if (notification != null) { + continue; + } + notification = Notification.create( + user.getId(), + "Welcome to Applica", + "This is a welcome notification", + "#/profile"); + + dal.save(notification); + } + } + +} diff --git a/edera-api/api/src/main/java/applica/app/services/reporting/Report.java b/edera-api/api/src/main/java/applica/app/services/reporting/Report.java new file mode 100644 index 0000000..c425c06 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/services/reporting/Report.java @@ -0,0 +1,12 @@ +package applica.app.services.reporting; + +import applica.app.domain.reporting.FilterSet; +import lombok.Data; + +@Data +public abstract class Report { + + public abstract String getCode(); + + public abstract ReportData execute(FilterSet filter); +} diff --git a/edera-api/api/src/main/java/applica/app/services/reporting/ReportData.java b/edera-api/api/src/main/java/applica/app/services/reporting/ReportData.java new file mode 100644 index 0000000..86ab820 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/services/reporting/ReportData.java @@ -0,0 +1,13 @@ +package applica.app.services.reporting; + +import java.util.HashMap; +import java.util.Map; + +public class ReportData extends HashMap { + public ReportData() { + } + + public ReportData(Map map) { + super(map); + } +} diff --git a/edera-api/api/src/main/java/applica/app/services/reporting/ReportFactory.java b/edera-api/api/src/main/java/applica/app/services/reporting/ReportFactory.java new file mode 100644 index 0000000..d8ef2d1 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/services/reporting/ReportFactory.java @@ -0,0 +1,18 @@ +package applica.app.services.reporting; + +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class ReportFactory { + private final List reports; + + public ReportFactory(List reports) { + this.reports = reports; + } + + public Report get(String code) { + return reports.stream().filter(r -> r.getCode().equals(code)).findFirst().orElse(null); + } +} diff --git a/edera-api/api/src/main/java/applica/app/services/reporting/impl/SupplyReport.java b/edera-api/api/src/main/java/applica/app/services/reporting/impl/SupplyReport.java new file mode 100644 index 0000000..b0ee40a --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/services/reporting/impl/SupplyReport.java @@ -0,0 +1,141 @@ +package applica.app.services.reporting.impl; + +import applica.app.domain.equipment.EquipmentRepository; +import applica.app.domain.equipment.EquipmentType; +import applica.app.domain.equipment.EquipmentTypeRepository; +import applica.app.domain.reporting.*; +import applica.app.domain.supply.Supply; +import applica.app.domain.supply.SupplyRepository; +import applica.app.ml.MLClient; +import applica.app.ml.MLRequest; +import applica.app.services.reporting.Report; +import applica.app.services.reporting.ReportData; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; + +@Component +public class SupplyReport extends Report { + + public static final String CODE = "supply"; + private static final int DAYS = 30; + private final SupplyRepository supplyRepository; + private final EquipmentRepository equipmentRepository; + private final EquipmentTypeRepository equipmentTypeRepository; + private final MLClient mlClient; + + public SupplyReport(SupplyRepository supplyRepository, + EquipmentRepository equipmentRepository, + EquipmentTypeRepository equipmentTypeRepository, + MLClient mlClient) { + this.supplyRepository = supplyRepository; + this.equipmentRepository = equipmentRepository; + this.equipmentTypeRepository = equipmentTypeRepository; + this.mlClient = mlClient; + } + + @Override + public String getCode() { + return CODE; + } + + @Override + public ReportData execute(FilterSet filter) { + var reportData = new ReportData(); + + var supplyId = filter.getSupplyId().orElseThrow(); + var supply = supplyRepository.findById(supplyId).orElseThrow(); + var equipment = equipmentRepository.findById(supply.getEquipmentId()).orElseThrow(); + var equipmentType = equipmentTypeRepository.findById(equipment.getEquipmentTypeId()).orElseThrow(); + if (filter.getDays() <= 60) { + filter.setGroupBy(Optional.of(GroupBy.HOUR)); + } + + var currentMonth = filter.currentMonth(); + var currentYear = filter.currentYear(); + + var customUsage = supplyRepository.getCustomUsage(filter); + var monthUsage = supplyRepository.getTotalUsage(currentMonth); + var yearUsage = supplyRepository.getTotalUsage(currentYear); + var averageMonthUsage = supplyRepository.getAverageUsage(currentMonth); + var averageYearUsage = supplyRepository.getAverageUsage(currentYear); + var monthlyUtilizationPercentage = supplyRepository.getMonthlyUtilizationPercentage(currentMonth); + var history = supplyRepository.getCustomUsage(filter.lastXDays(DAYS)); + + reportData.put("customUsage", customUsage); + reportData.put("monthUsage", monthUsage); + reportData.put("yearUsage", yearUsage); + reportData.put("averageMonthUsage", averageMonthUsage); + reportData.put("averageYearUsage", averageYearUsage); + reportData.put("monthlyUtilizationPercentage", monthlyUtilizationPercentage); + reportData.put("predictions", createPredictions(history, supply, equipmentType, filter)); + reportData.put("breakpointInHours", supply.getBreakpointInHours() > 0 + ? supply.getBreakpointInHours() + : equipmentType.getBreakpointInHours()); + + return reportData; + } + + + + private DataPointSet createPredictions(DataPointSet history, Supply supply, EquipmentType equipmentType, TemporalFilter filter) { + var breakpointInHours = supply.getBreakpointInHours() > 0 + ? supply.getBreakpointInHours() + : equipmentType.getBreakpointInHours(); + + var predictions = new DataPointSet(history + .getPoints() + .stream() + .peek(dataPoint -> dataPoint + .set("broken", 0) + .set("prediction", 0) + ) + .toList()); + + var decremented = supply.getAccumulatedHours(); + for (var i = predictions.getPoints().size() - 1; i >= 0; i--) { + var point = predictions.getPoints().get(i); + decremented -= point.getInt("total"); + point.set("accumulated", decremented); + } + + var points = predictions.getPoints(); + var lastDay = !points.isEmpty() ? points.get(points.size() - 1) : DataPoint.create(); + var cursor = !points.isEmpty() ? LocalDateTime.of( + lastDay.getInt("year"), + lastDay.getInt("month"), + lastDay.getInt("day"), + 0, 0, 0) + .plusDays(1) : filter.getFrom(); + + var mlRequest = MLRequest.of(equipmentType.getProgressive().intValue(), cursor.getDayOfYear()) + .withAccumulatedHours((int)supply.getAccumulatedHours()) + .withBreakpointHours(breakpointInHours) + .withThreshold(0.51f) + .withMaxDays(DAYS) + .withMaxHours(24); + + var mlPredictions = mlClient.predict(mlRequest); + var accumulatedHours = supply.getAccumulatedHours(); + + for (var mlPrediction : mlPredictions) { + accumulatedHours += mlPrediction.getHours(); + var dataPoint = DataPoint.create() + .set("year", cursor.getYear()) + .set("month", cursor.getMonthValue()) + .set("day", cursor.getDayOfMonth()) + .set("total", mlPrediction.getHours()) + .set("accumulated", accumulatedHours) + .set("prediction", 1) + .set("broken", mlPrediction.isBroken() ? 1 : 0); + + cursor = cursor.plusDays(1); + predictions.add(dataPoint); + } + + return predictions; + } +} + diff --git a/edera-api/api/src/main/java/applica/app/services/reporting/impl/SupplyTracksReport.java b/edera-api/api/src/main/java/applica/app/services/reporting/impl/SupplyTracksReport.java new file mode 100644 index 0000000..2c6ad7f --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/services/reporting/impl/SupplyTracksReport.java @@ -0,0 +1,53 @@ +package applica.app.services.reporting.impl; + +import applica.app.domain.reporting.FilterSet; +import applica.app.domain.reporting.TemporalFilter; +import applica.app.domain.rfid.RFIDDeviceTrackRepository; +import applica.app.domain.supply.SupplyRepository; +import applica.app.services.reporting.Report; +import applica.app.services.reporting.ReportData; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +@Component +public class SupplyTracksReport extends Report { + + public static final String CODE = "supply-tracks"; + private final RFIDDeviceTrackRepository rfidDeviceTrackRepository; + private final SupplyRepository supplyRepository; + + public SupplyTracksReport(RFIDDeviceTrackRepository rfidDeviceTrackRepository, SupplyRepository supplyRepository) { + this.rfidDeviceTrackRepository = rfidDeviceTrackRepository; + this.supplyRepository = supplyRepository; + } + + @Override + public String getCode() { + return CODE; + } + + @Override + public ReportData execute(FilterSet filter) { + var reportData = new ReportData(); + var currentMonth = filter.currentMonth(); + var currentYear = filter.currentYear(); + + var latestTrackedSupplies = supplyRepository.getLatestTrackedSupplies(filter); + var monthMovementTracking = rfidDeviceTrackRepository.getTotalTrackedRFID(currentMonth); + var yearMovementTracking = rfidDeviceTrackRepository.getTotalTrackedRFID(currentYear); + var monthlyTotalTrackedRFID = rfidDeviceTrackRepository.getMonthlyTotalTrackedRFID(currentMonth); + var monthlyTotalTrackedRFIDPercentage = supplyRepository.getMonthlyTrackingPercentage(currentMonth); + var tagsAndGatewaysNames = rfidDeviceTrackRepository.getTagsAndGatewaysNames(filter); + + reportData.put("latestTrackedSupplies", latestTrackedSupplies); + reportData.put("monthMovementTracking", monthMovementTracking); + reportData.put("yearMovementTracking", yearMovementTracking); + reportData.put("monthlyTotalTrackedRFID", monthlyTotalTrackedRFID); + reportData.put("monthlyTotalTrackedRFIDPercentage", monthlyTotalTrackedRFIDPercentage); + reportData.put("tagsAndGatewaysNames", tagsAndGatewaysNames); + + + return reportData; + } +} diff --git a/edera-api/api/src/main/java/applica/app/tasks/ProtocolServiceNotifyTask.java b/edera-api/api/src/main/java/applica/app/tasks/ProtocolServiceNotifyTask.java new file mode 100644 index 0000000..dbcb42b --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/tasks/ProtocolServiceNotifyTask.java @@ -0,0 +1,178 @@ +package applica.app.tasks; + +import applica.app.domain.I18nMessageRepository; +import applica.app.domain.Notification; +import applica.app.domain.customer.CustomerRepository; +import applica.app.domain.equipment.EquipmentRepository; +import applica.app.domain.equipment.EquipmentTypeRepository; +import applica.app.domain.maintenance.Activity; +import applica.app.domain.maintenance.ActivityRepository; +import applica.app.domain.maintenance.ActivityTypeRepository; +import applica.app.domain.protocol.Protocol; +import applica.app.domain.protocol.ProtocolRepository; +import applica.app.domain.protocol.ProtocolService; +import applica.app.domain.supplier.SupplierRepository; +import applica.app.domain.supply.Supply; +import applica.app.domain.supply.SupplyRepository; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.requests.SearchUsersRequest; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.Arrays; +import java.util.Objects; + +@Component +@SuppressWarnings("unused") +public class ProtocolServiceNotifyTask { + + private final CrudFactory crudFactory; + private final ProtocolRepository protocolRepository; + private final ActivityRepository activityRepository; + private final SupplyRepository supplyRepository; + private final ActivityTypeRepository activityTypeRepository; + private final CustomerRepository customerRepository; + private final EquipmentRepository equipmentRepository; + private final EquipmentTypeRepository equipmentTypeRepository; + private final SupplierRepository supplierRepository; + private final Log log = LogFactory.getLog(getClass()); + private final IAMService iamService; + private static final String DEFAULT_LOCALE = "it"; + private final I18nMessageRepository i18nMessageRepository; + + public ProtocolServiceNotifyTask(ProtocolRepository protocolRepository, + IAMService iamService, + CrudFactory crudFactory, + ActivityRepository activityRepository, + SupplyRepository supplyRepository, + ActivityTypeRepository activityTypeRepository, + CustomerRepository customerRepository, + I18nMessageRepository i18nMessageRepository, + EquipmentRepository equipmentRepository, + EquipmentTypeRepository equipmentTypeRepository, + SupplierRepository supplierRepository) { + this.protocolRepository = protocolRepository; + this.iamService = iamService; + this.crudFactory = crudFactory; + this.activityRepository = activityRepository; + this.supplyRepository = supplyRepository; + this.activityTypeRepository = activityTypeRepository; + this.customerRepository = customerRepository; + this.i18nMessageRepository = i18nMessageRepository; + this.equipmentRepository = equipmentRepository; + this.equipmentTypeRepository = equipmentTypeRepository; + this.supplierRepository = supplierRepository; + + log.info("Protocol service checker configured successfully"); + } + + @Scheduled(cron = "0 0 0 * * ?") + public void execute() { + var today = LocalDate.now(); + var notificationDal = crudFactory.createDataLayer(Notification.class); + var protocols = protocolRepository.findAll(); + for (var protocol : protocols) { + if (protocol.getServices() != null) { + for (var service : protocol.getServices()) { + var endDate = service.getEnd(); + long frequency = service.getFrequency(); + + if (today.isAfter(endDate)) continue; + + var supplies = supplyRepository.findByProtocolId(protocol.getId()); + if (supplies.isEmpty()) continue; + for (var supply : supplies) { + var supplyActivities = activityRepository.findFirstBySupplyIdAndActivityTypeIdOrderByCreatedDesc( + supply.getId(), + service.getFromActivityTypeId()); + if (supplyActivities.isPresent()) { + var mostRecentActivity = supplyActivities.get(); + var activityDate = mostRecentActivity.getDate(); + long daysSinceActivity = ChronoUnit.DAYS.between(activityDate, today); + if (daysSinceActivity == frequency) { + sendNotifications(mostRecentActivity, notificationDal, service, supply, protocol); + } + } + } + } + } + } + } + + private void sendNotifications(Activity activity, DataLayer dal, ProtocolService service, Supply supply, Protocol protocol) { + var roles = Arrays.asList("ROLE_ADMIN", "ROLE_OPERATOR", "ROLE_USER"); + var title = i18nMessageRepository.findById(String.format("%s.%s", DEFAULT_LOCALE, "ra.activity.schedule.title")); + var description = i18nMessageRepository.findById(String.format("%s.%s", DEFAULT_LOCALE, "ra.activity.schedule.description")); + if (title.isEmpty() || description.isEmpty()) { + log.error(String.format("Missing i18n message for key %s or %s", "ra.activity.schedule.title", "ra.activity.schedule.description")); + return; + } + + var fromActivityType = activityTypeRepository.findById(service.getFromActivityTypeId()).orElse(null); + var toActivityType = service.getToActivityTypeId() == null + ? null + : activityTypeRepository.findById(service.getToActivityTypeId()).orElse(null); + if (fromActivityType == null) { + log.error(String.format("Activity type %s not found", service.getFromActivityTypeId())); + return; + } + + var customer = customerRepository.findById(protocol.getCustomerId()).orElse(null); + if (customer == null) { + log.error(String.format("Customer %s not found", protocol.getCustomerId())); + return; + } + var equipment = equipmentRepository.findById(supply.getEquipmentId()).orElse(null); + if (equipment == null) { + log.error(String.format("Equipment %s not found", supply.getEquipmentId())); + return; + } + var equipmentType = equipmentTypeRepository.findById(equipment.getEquipmentTypeId()).orElse(null); + if (equipmentType == null) { + log.error(String.format("Equipment type %s not found", equipment.getEquipmentTypeId())); + return; + } + var supplier = supplierRepository.findById(supply.getSupplierId()).orElse(null); + if (supplier == null) { + log.error(String.format("Supplier %s not found", supply.getSupplierId())); + return; + } + + for (String role : roles) { + var searchUsersRequest = new SearchUsersRequest(); + searchUsersRequest.setPageable(Pageable.ofSize(100)); + searchUsersRequest.setRole(role); + + var searchUsersResponse = iamService.searchUsers(searchUsersRequest); + var users = searchUsersResponse.getUsers(); + + for (var user : users) { + var notification = Notification.create( + user.getId(), + title.get().getText(), + String.format(description.get().getText(), + service.getToActivityTypeId() == null + ? fromActivityType.getDescription() + : Objects.requireNonNull(toActivityType).getDescription(), + customer.getName(), + equipmentType.getName(), + supplier.getBusinessName(), + protocol.getProtocolNumber()), + String.format("#/entities/activity/create?activity-id=%s&activity-type-id=%s", + activity.getId(), + toActivityType == null ? fromActivityType.getId() : toActivityType.getId()) + ); + + dal.save(notification); + } + } + } + +} diff --git a/edera-api/api/src/main/java/applica/app/utils/SecurityUtils.java b/edera-api/api/src/main/java/applica/app/utils/SecurityUtils.java new file mode 100644 index 0000000..3195fe9 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/utils/SecurityUtils.java @@ -0,0 +1,36 @@ +package applica.app.utils; + +import applica.iam.sdk.readmodel.UserView; +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.Optional; + + +public class SecurityUtils { + public static String tokenFromAuthorizationHeader(String authorization) { + if (StringUtils.isNotEmpty(authorization) && authorization.toLowerCase().startsWith("bearer")) { + return authorization.substring("bearer ".length()); + } + + return null; + } + + public static boolean isLogged() { + return SecurityContextHolder.getContext().getAuthentication() != null && + SecurityContextHolder.getContext().getAuthentication().isAuthenticated(); + } + + public static boolean isAnonymous() { + return !isLogged() || SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser"); + } + + public static Optional getLoggedUser() { + if (!isLogged() || isAnonymous()) { + return Optional.empty(); + } + + var user = ((UserView) SecurityContextHolder.getContext().getAuthentication().getPrincipal()); + return Optional.ofNullable(user); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/annotations/CustomerFilterable.java b/edera-api/api/src/main/java/applica/app/web/annotations/CustomerFilterable.java new file mode 100644 index 0000000..c28e5cc --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/annotations/CustomerFilterable.java @@ -0,0 +1,18 @@ +package applica.app.web.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Puoi applicare questa annotazione a una qualsiasi entità. + * In tal caso, se passi dal Crud Controller di Applica, il sistema provvederà + * automaticamente ad applicare un filtro per customerId se l'utente corrente non è admin + * ed ha un customerId valido. + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CustomerFilterable { +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/DocxController.java b/edera-api/api/src/main/java/applica/app/web/controllers/DocxController.java new file mode 100644 index 0000000..10c7e3c --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/DocxController.java @@ -0,0 +1,108 @@ +package applica.app.web.controllers; + +import applica.app.domain.docx.DocxDataSource; +import applica.app.domain.docx.DocxFactory; +import applica.app.domain.docx.DocxTemplate; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.query.builders.CrudQueryBuilder; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.ResponseCodes; +import applica.iam.sdk.requests.ValidateTokenRequest; +import jakarta.servlet.ServletRequest; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/docx") +@SuppressWarnings("unused") +public class DocxController { + private final DocxFactory docxFactory; + private final DataLayer docxTemplateDataLayer; + private final Log logger = LogFactory.getLog(DocxController.class); + private final IAMService IAMService; + + public DocxController(DocxFactory docxFactory, CrudFactory crudFactory, IAMService IAMService) { + this.docxFactory = docxFactory; + this.docxTemplateDataLayer = crudFactory.createDataLayer(DocxTemplate.class); + this.IAMService = IAMService; + } + + @GetMapping("/generate/{type}/{templateId}/{id}.docx") + public ResponseEntity generate(@PathVariable String type, @PathVariable String templateId, @PathVariable String id, ServletRequest request) { + var token = request.getParameter("_token"); + if (StringUtils.isEmpty(token)) { + return ResponseEntity.badRequest().build(); + } + + var result = IAMService.validateToken(new ValidateTokenRequest(token)); + if (!result.getResponseCode().equals(ResponseCodes.OK)) { + return ResponseEntity.badRequest().build(); + } + + var template = docxTemplateDataLayer.get(templateId); + if (template.isEmpty()) { + return ResponseEntity.notFound().build(); + } + + try { + var docx = docxFactory.generate(template.get(), id); + return ResponseEntity.ok() + .header("Content-Disposition", String.format("attachment; filename=\"%s.docx\"", template.get().getName())) + .header("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document") + .body(new InputStreamResource(docx)); + } catch (Exception e) { + logger.error("Error generating docx", e); + return ResponseEntity.badRequest().build(); + } + } + + @GetMapping("/helper/{type}.docx") + public ResponseEntity helper(@PathVariable String type) { + try { + var typeDef = docxFactory.get(type); + if (typeDef == null) { + return ResponseEntity.notFound().build(); + } + + var descriptor = typeDef.getDescriptor(); + var dataSource = new DocxDataSource(); + for (var field : descriptor) { + var row = dataSource.createRow(); + row.put("TYPE", typeDef.getType()); + row.put("NAME", String.format("{#%s#}", field.getName())); + row.put("DESCRIPTION", field.getDescription()); + row.put("COLUMN_TYPE", field.isBody() ? "BODY" : "HEADER"); + } + var template = getClass().getClassLoader().getResourceAsStream("docx/helper.docx"); + var docx = docxFactory.generate(template, dataSource); + var filename = String.format("%s.docx", type); + + return ResponseEntity.ok() + .header("Content-Disposition", String.format("attachment; filename=\"%s\"", filename)) + .header("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document") + .body(new InputStreamResource(docx)); + } catch (Exception e) { + logger.error("Error generating docx", e); + return ResponseEntity.badRequest().build(); + } + } + + @GetMapping("/templates/{type}") + public List getTemplates(@PathVariable String type) { + var query = CrudQueryBuilder + .build() + .eq("type", type) + .rowsPerPage(1000); + return docxTemplateDataLayer.find(query).getRows(); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/I18nController.java b/edera-api/api/src/main/java/applica/app/web/controllers/I18nController.java new file mode 100644 index 0000000..f70e930 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/I18nController.java @@ -0,0 +1,48 @@ +package applica.app.web.controllers; + +import applica.app.domain.I18nMessage; +import applica.crud.factory.CrudFactory; +import applica.crud.query.builders.CrudQueryBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/i18n") +public class I18nController { + @Autowired + CrudFactory crudFactory; + + @PutMapping("/message") + public ResponseEntity putMessage(@RequestBody Map payload) { + String lang = (String) payload.get("lang"); + String code = (String) payload.get("code"); + String text = (String) payload.get("text"); + if (lang == null || code == null || text == null) { + return ResponseEntity.badRequest().build(); + } + var dal = crudFactory.createDataLayer(I18nMessage.class); + var query = CrudQueryBuilder.build().eq("lang", lang).eq("code", code); + var message = dal.find(query).findFirst().orElse(null); + if (message == null) { + message = I18nMessage.create(lang, code, text); + dal.save(message); + } + + return ResponseEntity.ok(message); + } + + @GetMapping("/messages") + public @ResponseBody List getMessages() { + var dal = crudFactory.createDataLayer(I18nMessage.class); + var query = CrudQueryBuilder.build(); + var rows = dal.find(query) + .getRows() + .stream() + .filter(m -> m.isValid()).toList(); + return rows; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/IAMController.java b/edera-api/api/src/main/java/applica/app/web/controllers/IAMController.java new file mode 100644 index 0000000..8902f1f --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/IAMController.java @@ -0,0 +1,206 @@ +package applica.app.web.controllers; + +import applica.app.utils.SecurityUtils; +import applica.app.web.requests.PatchProfileRequest; +import applica.app.web.responses.CrudLoginResponse; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.ResponseCodes; +import applica.iam.sdk.requests.*; +import applica.iam.sdk.responses.*; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +import static applica.iam.sdk.ResponseCodes.OK; +import static applica.iam.sdk.ResponseCodes.TOKEN_EXPIRED; +import static org.springframework.http.ResponseEntity.*; + +@SuppressWarnings("unused") +@RestController +@RequestMapping("/iam") +public class IAMController { + + final IAMService iamService; + + public IAMController(IAMService iamService) { + this.iamService = iamService; + } + + @PostMapping("/login") + public ResponseEntity login(HttpServletRequest request, String mail, String password) { + var response = iamService.login(new LoginRequest(mail, password)); + + if (response.getResponseCode().equals(OK)) { + var authentication = new UsernamePasswordAuthenticationToken( + response.getUser(), + null, + response.getUser().getRoles().stream().map(SimpleGrantedAuthority::new).toList() + ); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + + var crudResponse = new CrudLoginResponse( + response.getResponseCode(), + response.getUser(), + response.getToken() + ); + + return ok(crudResponse); + } + + return status(HttpStatus.UNAUTHORIZED).build(); + } + + @PostMapping("/impersonate") + @PreAuthorize("hasRole('ROLE_ADMIN')") + public ResponseEntity login(HttpServletRequest request, String id) { + var response = iamService.impersonate(new ImpersonateRequest(id)); + if (response.getResponseCode().equals(OK)) { + var authentication = new UsernamePasswordAuthenticationToken( + response.getUser(), + null, + response.getUser().getRoles().stream().map(SimpleGrantedAuthority::new).toList() + ); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + + var crudResponse = new CrudLoginResponse( + response.getResponseCode(), + response.getUser(), + response.getToken() + ); + + return ok(crudResponse); + } + + return status(HttpStatus.UNAUTHORIZED).build(); + } + + + @PostMapping("/token-login") + public ResponseEntity tokenLogin(String token) { + ValidateTokenResponse validateTokenResponse = iamService.validateToken(new ValidateTokenRequest(token)); + if (!validateTokenResponse.getResponseCode().equals(ResponseCodes.OK)) { + return status(HttpStatus.UNAUTHORIZED).body(new CrudLoginResponse(TOKEN_EXPIRED, null, null)); + } + + FreshTokenResponse freshTokenResponse = iamService.freshToken(new FreshTokenRequest(token)); + if (!validateTokenResponse.getResponseCode().equals(ResponseCodes.OK)) { + return status(HttpStatus.UNAUTHORIZED).body(new CrudLoginResponse(TOKEN_EXPIRED, null, null)); + } + + return ok().body(new CrudLoginResponse(OK, validateTokenResponse.getUser(), freshTokenResponse.getToken())); + } + + @GetMapping("/fresh-token") + public ResponseEntity freshToken(HttpServletRequest request) { + var authorization = request.getHeader("Authorization"); + var currentToken = SecurityUtils.tokenFromAuthorizationHeader(authorization); + if (StringUtils.isEmpty(currentToken)) { + return status(HttpStatus.BAD_REQUEST).build(); + } + var response = iamService.freshToken(new FreshTokenRequest(currentToken)); + if (response.getResponseCode().equals(OK)) { + return ok().body(response); + } + + return internalServerError().body(response); + } + + @PostMapping("/reset-pin") + @PreAuthorize("hasRole('ROLE_ADMIN')") + public ResponseEntity resetPin(String userId, String pinCode) { + var resetPinRequest = new ResetPinRequest(userId, pinCode); + var resetPinResponse = iamService.resetPin(resetPinRequest); + return ok().body(resetPinResponse); + } + + @PostMapping("/register") + public ResponseEntity register(String name, String email, String password) { + var request = new RegistrationRequest(email, password, null, true, Map.of("name", name)) {{ + setActiveByDefault(true); + }}; + var response = iamService.register(request); + if (response.getResponseCode().equals(OK)) { + return ok().body(response); + } + + return badRequest().body(response); + } + + @PostMapping("/activate") + public ResponseEntity activate(String activationCode) { + var response = iamService.activate(new ActivationRequest(activationCode)); + if (response.getResponseCode().equals(OK)) { + return ok().body(response); + } + + return badRequest().body(response); + } + + @PostMapping("/recover") + public ResponseEntity recover(String email) { + var response = iamService.recoverPassword(new RecoverPasswordRequest(email)); + if (response.getResponseCode().equals(OK)) { + return ok().body(response); + } + + return badRequest().body(response); + } + + @PostMapping("/change-password") + public ResponseEntity changePassword(String currentPassword, String password) { + var loggedUser = SecurityUtils.getLoggedUser().orElse(null); + if (loggedUser == null) { + return status(HttpStatus.UNAUTHORIZED).build(); + } + + var response = iamService.changePassword(new ChangePasswordRequest(loggedUser.getId(), currentPassword, password)); + if (response.getResponseCode().equals(OK)) { + return ok().body(response); + } + + return status(HttpStatus.UNAUTHORIZED).build(); + } + + @PostMapping("/register-device") + @ResponseBody public ResponseEntity registerDevice(@RequestBody RegisterDeviceRequest request) { + var getDeviceByCodeRequest = new GetDeviceByCodeRequest(request.getCode()); + var getDeviceByCodeResponse = iamService.getDeviceByCode(getDeviceByCodeRequest); + if (!getDeviceByCodeResponse.getResponseCode().equals(OK)) { + var registerDeviceResponse = iamService.registerDevice(request); + return ok().body(registerDeviceResponse); + } + + return ok().body(new RegisterDeviceResponse(OK, getDeviceByCodeResponse.getDevice())); + } + + @PostMapping("/pin-login") + @ResponseBody public ResponseEntity pinLogin(@RequestBody PinLoginRequest request) { + var response = iamService.pinLogin(request); + return ok().body(response); + } + + @PostMapping("/update-profile") + @ResponseBody public ResponseEntity updateProfile(@RequestBody PatchProfileRequest request) { + var user = SecurityUtils.getLoggedUser().orElse(null); + + if (user == null) { + return status(HttpStatus.UNAUTHORIZED).build(); + } + + var updateProfileRequest = new UpdateProfileRequest(user.getId(), new HashMap<>(Map.of("name", request.getName()))); + var response = iamService.updateProfile(updateProfileRequest); + return ok().body(response); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/MaintenanceController.java b/edera-api/api/src/main/java/applica/app/web/controllers/MaintenanceController.java new file mode 100644 index 0000000..7a4e119 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/MaintenanceController.java @@ -0,0 +1,33 @@ +package applica.app.web.controllers; + +import applica.app.services.EderaService; +import applica.app.web.responses.ActivityInfoResponse; +import applica.app.web.responses.SupplyInfoResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/maintenance") +public class MaintenanceController { + + final EderaService ederaService; + + public MaintenanceController(EderaService ederaService) { + this.ederaService = ederaService; + } + + + @GetMapping("/activity-info/{activityId}") + public ActivityInfoResponse allActivityInfo(@PathVariable String activityId) { + var response = new ActivityInfoResponse(ederaService.getActivityDetails(activityId)); + return response; + } + + @GetMapping("/supply-info/{supplyId}") + public SupplyInfoResponse allSupplyInfo(@PathVariable String supplyId) { + var response = new SupplyInfoResponse(ederaService.getSupplyDetails(supplyId)); + return response; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/ProfileController.java b/edera-api/api/src/main/java/applica/app/web/controllers/ProfileController.java new file mode 100644 index 0000000..cab6def --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/ProfileController.java @@ -0,0 +1,53 @@ +package applica.app.web.controllers; + +import applica.app.utils.SecurityUtils; +import applica.fs.FsClient; +import applica.fs.MimeUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; + +import static org.springframework.http.ResponseEntity.*; + +@RestController +@RequestMapping("/profile") +public class ProfileController { + + final FsClient fsClient; + + public ProfileController(FsClient fsClient) { + this.fsClient = fsClient; + } + + @GetMapping("/me/image") + public ResponseEntity image() { + try { + var user = SecurityUtils + .getLoggedUser() + .orElseThrow(() -> new AuthenticationCredentialsNotFoundException(null)); + + var image = user.getProfile().getOrDefault("image", null); + if (!StringUtils.hasLength(image)) { + return notFound().build(); + } + + return ok() + .header("Content-Type", MimeUtils.getMimeType(FilenameUtils.getExtension(image))) + .header("Content-Disposition", "attachment; filename=" + "profile." + FilenameUtils.getExtension(image)) + .body(IOUtils.toByteArray(fsClient.getImage(image, "100x100"))); + } catch (AuthenticationCredentialsNotFoundException e) { + return status(HttpStatus.UNAUTHORIZED).build(); + } catch (IOException e) { + return internalServerError().build(); + } + } + +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/ProtectedRestController.java b/edera-api/api/src/main/java/applica/app/web/controllers/ProtectedRestController.java new file mode 100644 index 0000000..8d5c424 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/ProtectedRestController.java @@ -0,0 +1,26 @@ +package applica.app.web.controllers; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import static org.springframework.http.ResponseEntity.ok; + +@RestController +public class ProtectedRestController { + + @GetMapping("/tests/protected/user") + @PreAuthorize("hasRole('USER')") + public ResponseEntity protectedUserMethod() { + return ok().build(); + } + + @GetMapping("/tests/protected/admin") + @PreAuthorize("hasRole('ADMIN')") + public ResponseEntity protectedAdminMethod(HttpServletRequest request) { + request.isUserInRole("ADMIN"); + return ok().build(); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/RFIDDeviceTrackController.java b/edera-api/api/src/main/java/applica/app/web/controllers/RFIDDeviceTrackController.java new file mode 100644 index 0000000..29ae861 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/RFIDDeviceTrackController.java @@ -0,0 +1,39 @@ +package applica.app.web.controllers; + +import applica.app.services.EderaService; +import applica.crud.responses.Response; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +public class RFIDDeviceTrackController { + + private final EderaService ederaService; + private final Log log = LogFactory.getLog(getClass()); + + public RFIDDeviceTrackController(EderaService ederaService) { + this.ederaService = ederaService; + } + + @GetMapping("/track") + public Response acquire( + @RequestParam("tag") String tagId, + @RequestParam("gate") String gatewayId, + @RequestParam(value = "timestamp", required = false) Long ts, + @RequestParam Map allParams) { + + try { + ederaService.save(gatewayId, tagId, ts, allParams); + } catch (Exception e) { + log.error("Error while saving tracking data", e); + return Response.error(e.getMessage()); + } + return Response.ok(); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/ReportController.java b/edera-api/api/src/main/java/applica/app/web/controllers/ReportController.java new file mode 100644 index 0000000..19438e5 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/ReportController.java @@ -0,0 +1,31 @@ +package applica.app.web.controllers; + +import applica.app.services.EderaService; +import applica.app.web.requests.GetReportDataRequest; +import applica.app.web.responses.GetReportDataResponse; +import applica.crud.responses.Response; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/report") +@SuppressWarnings("unused") +public class ReportController { + private final EderaService ederaService; + private final Log logger = LogFactory.getLog(getClass()); + + public ReportController(EderaService ederaService) { + this.ederaService = ederaService; + } + + @PostMapping("/{code}/execute") + public GetReportDataResponse execute(@PathVariable String code, @RequestBody GetReportDataRequest request) { + try { + return ederaService.getReportData(code, request); + } catch (RuntimeException e) { + logger.error("Error executing report", e); + return new GetReportDataResponse(Response.ERROR); + } + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/SupplyController.java b/edera-api/api/src/main/java/applica/app/web/controllers/SupplyController.java new file mode 100644 index 0000000..c3fa337 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/SupplyController.java @@ -0,0 +1,33 @@ +package applica.app.web.controllers; + +import applica.app.services.EderaService; +import applica.crud.responses.Response; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/supply") +@SuppressWarnings("unused") +public class SupplyController{ + + final EderaService ederaService; + + public SupplyController(EderaService ederaService) { + this.ederaService = ederaService; + } + + + @GetMapping("/supply-start/{supplyId}") + public Response startUsage(@PathVariable String supplyId) { + ederaService.startUsage(supplyId); + return Response.ok(); + } + + @GetMapping("/supply-stop/{supplyId}") + public Response stopUsage(@PathVariable String supplyId) { + ederaService.stopUsage(supplyId); + return Response.ok(); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/controllers/ValuesController.java b/edera-api/api/src/main/java/applica/app/web/controllers/ValuesController.java new file mode 100644 index 0000000..a63a6d3 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/controllers/ValuesController.java @@ -0,0 +1,55 @@ +package applica.app.web.controllers; + +import applica.app.domain.docx.DocxFactory; +import applica.app.domain.maintenance.ActivityStatus; +import applica.app.domain.rfid.RFIDDeviceType; +import applica.app.domain.supply.UsageStatus; +import applica.crud.model.SimpleItem; +import applica.crud.responses.Response; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.List; + +import static org.springframework.http.ResponseEntity.ok; + +@RestController +@RequestMapping("/values") +@SuppressWarnings("unused") +public class ValuesController { + + private final List roles = List.of("ROLE_ADMIN", "ROLE_USER"); + private final DocxFactory docxFactory; + + public ValuesController(DocxFactory docxFactory) { + this.docxFactory = docxFactory; + } + + @GetMapping("/roles") + public ResponseEntity allRoles() { + return ok().body(Response.value(roles.stream().map(SimpleItem::new).toList())); + } + + @GetMapping("/rfid-device-types") + public ResponseEntity allRfidDeviceTypes() { + return ok().body(Response.value(Arrays.stream(RFIDDeviceType.values()).map(t -> new SimpleItem(t.name(), t.name())).toList())); + } + + @GetMapping("/activity-status") + public ResponseEntity allActivityStatus() { + return ok().body(Response.value(Arrays.stream(ActivityStatus.values()).map(t -> new SimpleItem(t.name(), t.name())).toList())); + } + + @GetMapping("/supply-status") + public ResponseEntity allSupplyStatus() { + return ok().body(Response.value(Arrays.stream(UsageStatus.values()).map(t -> new SimpleItem(t.name(), t.name())).toList())); + } + + @GetMapping("/docx-types") + public ResponseEntity allDocxTypes() { + return ok().body(Response.value(docxFactory.getTypesNames().stream().map(SimpleItem::new).toList())); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/ActivityDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/ActivityDataLayer.java new file mode 100644 index 0000000..ecde39f --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/ActivityDataLayer.java @@ -0,0 +1,87 @@ +package applica.app.web.crud; + +import applica.app.domain.maintenance.Activity; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Component +@SuppressWarnings("unused") +public class ActivityDataLayer implements DataLayer { + private final DataLayer dal; + private final MongoTemplate mongoTemplate; + private final CrudQueryConverter queryConverter; + + public ActivityDataLayer(CrudFactory crudFactory, MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + this.dal = crudFactory.createDataLayer(Activity.class); + this.mongoTemplate = mongoTemplate; + this.queryConverter = queryConverter; + } + + @Override + public Optional get(Object id) { + var query = CrudQuery.build().eq("_id", id).get(); + return find(query) + .getRows() + .stream() + .findFirst(); + } + + @Override + public Result find(CrudQuery query) { + var customerIdFilter = query.popFilter("customerId"); + var pipeline = new ArrayList() {{ + addAll(queryConverter.convert(query)); + add(lookup("supply", "supplyId", "_id", "supply")); + add(unwind("supply")); + add(lookup("protocol", "supply.protocolId", "_id", "protocol")); + add(unwind("protocol")); + add(lookup("customer", "protocol.customerId", "_id", "customer")); + add(unwind("customer")); + + customerIdFilter.ifPresent(filter -> add(match(where("customer._id").is(filter.getValue())))); + }}; + + var totalRows = getTotalRows(mongoTemplate, pipeline, Activity.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + + + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var aggregation = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(aggregation, Activity.class, Activity.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(Activity entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return Activity.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/AuditLogDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/AuditLogDataLayer.java new file mode 100644 index 0000000..ed2f71e --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/AuditLogDataLayer.java @@ -0,0 +1,92 @@ +package applica.app.web.crud; + +import applica.app.domain.audit.AuditLog; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Component +@SuppressWarnings("unused") +public class AuditLogDataLayer implements DataLayer { + private final DataLayer dal; + private final MongoTemplate mongoTemplate; + private final CrudQueryConverter queryConverter; + + public AuditLogDataLayer(CrudFactory crudFactory, MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + this.dal = crudFactory.createDataLayer(AuditLog.class); + this.mongoTemplate = mongoTemplate; + this.queryConverter = queryConverter; + } + + + @Override + public Optional get(Object id) { + return dal.get(id); + } + + @Override + public Result find(CrudQuery query) { + var pipeline = new ArrayList() {{ + var from = query.popFilter("from"); + var to = query.popFilter("to"); + + if (from.isPresent() && to.isPresent()) { + var fromDate = LocalDateTime.parse(String.valueOf(from.get().getValue())); + var toDate = LocalDateTime.parse(String.valueOf(to.get().getValue())); + add(match(where("created").gte(fromDate).lte(toDate))); + } else if (from.isPresent()) { + var fromDate = LocalDateTime.parse(String.valueOf(from.get().getValue())); + add(match(where("created").gte(fromDate))); + } else if (to.isPresent()) { + var toDate = LocalDateTime.parse(String.valueOf(to.get().getValue())); + add(match(where("created").lte(toDate))); + } + + addAll(queryConverter.convert(query)); + }}; + + var totalRows = getTotalRows(mongoTemplate, pipeline, AuditLog.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + var sort = pageable.getSort(); + + pipeline.add(sort(sort)); + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var aggregation = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(aggregation, AuditLog.class, AuditLog.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(AuditLog entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return AuditLog.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/DefaultDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/DefaultDataLayer.java new file mode 100644 index 0000000..29d0604 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/DefaultDataLayer.java @@ -0,0 +1,34 @@ +package applica.app.web.crud; + +import applica.crud.mongodb.MongoDataLayer; +import applica.crud.query.CrudQueryConverter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public class DefaultDataLayer extends MongoDataLayer { + public DefaultDataLayer(MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + super(mongoTemplate, queryConverter); + } + + @Override + public void save(Object entity) { + Class clazz = entity.getClass(); + while (clazz != null) { + for (Field field : clazz.getDeclaredFields()) { + if (Modifier.isTransient(field.getModifiers())) { + field.setAccessible(true); + try { + field.set(entity, null); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + clazz = clazz.getSuperclass(); + } + super.save(entity); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/EquipmentDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/EquipmentDataLayer.java new file mode 100644 index 0000000..7ec6171 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/EquipmentDataLayer.java @@ -0,0 +1,127 @@ +package applica.app.web.crud; + +import applica.app.domain.equipment.Equipment; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import org.bson.Document; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Component +@SuppressWarnings("unused") +public class EquipmentDataLayer implements DataLayer { + private final DataLayer dal; + private final MongoTemplate mongoTemplate; + private final CrudQueryConverter queryConverter; + + public EquipmentDataLayer(CrudFactory crudFactory, MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + this.dal = crudFactory.createDataLayer(Equipment.class); + this.mongoTemplate = mongoTemplate; + this.queryConverter = queryConverter; + } + + @Override + public Optional get(Object id) { + var query = CrudQuery.build().eq("_id", id).get(); + var item = find(query) + .getRows() + .stream() + .findFirst(); + + return item; + } + + @Override + public Result find(CrudQuery query) { + var customerIdFilter = query.popFilter("customerId"); + var priceListIdFilter = query.popFilter("priceListId"); + var supplierIdFilter = query.popFilter("supplierId"); + var pipeline = new ArrayList() {{ + addAll(queryConverter.convert(query)); + add(lookup("supply", "_id", "equipmentId", "supply")); + add(lookup("protocol", "supply.protocolId", "_id", "protocol")); + add(lookup("customer", "protocol.customerId", "_id", "customer")); + add(lookup("equipmentType", "equipmentTypeId", "_id", "equipmentType")); + add(unwind("equipmentType")); + + if (customerIdFilter.isPresent()) { + add(match(where("customer._id").is(customerIdFilter.get().getValue()))); + } + + if (priceListIdFilter.isPresent()) { + var priceListIdValue = priceListIdFilter.get().getValue(); + add(lookup("supplier", "supplierId", "_id", "supplier")); + add(unwind("supplier")); + add(ctx -> new Document("$lookup", new Document() + .append("from", "priceList") + .append("localField", "supplier._id") + .append("foreignField", "supplierId") + .append("pipeline", new ArrayList() {{ + add(new Document("$match", new Document("_id", priceListIdValue))); + }}) + .append("as", "priceList") + )); + add(unwind("priceList")); + add(ctx -> new Document("$lookup", new Document() + .append("from", "priceListItem") + .append("localField", "_id") + .append("foreignField", "equipmentId") + .append("pipeline", new ArrayList() {{ + add(new Document("$match", new Document("priceListId", priceListIdValue))); + }}) + .append("as", "priceListItem") + )); + add(unwind("priceListItem", true)); + add(match(Criteria.where("priceListItem.equipmentId").is(null))); + } + + if (supplierIdFilter.isPresent()) { + add(lookup("supplier", "supplierId", "_id", "supplier")); + add(unwind("supplier")); + add(match(where("supplier._id").is(supplierIdFilter.get().getValue()))); + } + }}; + + var totalRows = getTotalRows(mongoTemplate, pipeline, Equipment.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + + + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var aggregation = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(aggregation, Equipment.class, Equipment.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(Equipment entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return Equipment.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/EquipmentTypeDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/EquipmentTypeDataLayer.java new file mode 100644 index 0000000..6a7bdb7 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/EquipmentTypeDataLayer.java @@ -0,0 +1,84 @@ +package applica.app.web.crud; + +import applica.app.domain.equipment.EquipmentType; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +@Component +@SuppressWarnings("unused") +public class EquipmentTypeDataLayer implements DataLayer { + private final DataLayer dal; + private final MongoTemplate mongoTemplate; + private final CrudQueryConverter queryConverter; + + public EquipmentTypeDataLayer(CrudFactory crudFactory, MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + this.dal = crudFactory.createDataLayer(EquipmentType.class); + this.mongoTemplate = mongoTemplate; + this.queryConverter = queryConverter; + } + + @Override + public Optional get(Object id) { + var query = CrudQuery.build().eq("_id", id).get(); + var item = find(query) + .getRows() + .stream() + .findFirst(); + + return item; + } + + @Override + public Result find(CrudQuery query) { + var supplierId = query.popFilter("supplierId"); + var pipeline = new ArrayList() {{ + addAll(queryConverter.convert(query)); + if (supplierId.isPresent()) { + add(lookup("equipment", "_id", "equipmentTypeId", "usedEquipments")); + add(match(Criteria.where("usedEquipments.supplierId").ne(supplierId.get().getValue()))); + } + }}; + + var totalRows = getTotalRows(mongoTemplate, pipeline, EquipmentType.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + + + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var aggregation = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(aggregation, EquipmentType.class, EquipmentType.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(EquipmentType entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return EquipmentType.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/MaintenanceDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/MaintenanceDataLayer.java new file mode 100644 index 0000000..afed2db --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/MaintenanceDataLayer.java @@ -0,0 +1,93 @@ +package applica.app.web.crud; + +import applica.app.domain.maintenance.Maintenance; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Component +@SuppressWarnings("unused") +public class MaintenanceDataLayer implements DataLayer { + private final DataLayer dal; + private final MongoTemplate mongoTemplate; + private final CrudQueryConverter queryConverter; + + public MaintenanceDataLayer(CrudFactory crudFactory, MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + this.dal = crudFactory.createDataLayer(Maintenance.class); + this.mongoTemplate = mongoTemplate; + this.queryConverter = queryConverter; + } + + @Override + public Optional get(Object id) { + var query = CrudQuery.build().eq("_id", id).get(); + var item = find(query) + .getRows() + .stream() + .findFirst(); + + return item; + } + + @Override + public Result find(CrudQuery query) { + var customerIdFilter = query.popFilter("customerId"); + var pipeline = new ArrayList() {{ + addAll(queryConverter.convert(query)); + add(lookup("activity", "activityId", "_id", "activity")); + add(unwind("activity")); + add(lookup("supply", "activity.supplyId", "_id", "supply")); + add(unwind("supply")); + add(lookup("protocol", "supply.protocolId", "_id", "protocol")); + add(unwind("protocol")); + add(lookup("customer", "protocol.customerId", "_id", "customer")); + add(unwind("customer")); + + if (customerIdFilter.isPresent()) { + add(match(where("customer._id").is(customerIdFilter.get().getValue()))); + } + }}; + + var totalRows = getTotalRows(mongoTemplate, pipeline, Maintenance.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + + + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var aggregation = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(aggregation, Maintenance.class, Maintenance.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(Maintenance entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return Maintenance.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/PriceListItemDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/PriceListItemDataLayer.java new file mode 100644 index 0000000..ae83dbf --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/PriceListItemDataLayer.java @@ -0,0 +1,88 @@ +package applica.app.web.crud; + +import applica.app.domain.pricing.PriceListItem; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Component +@SuppressWarnings("unused") +public class PriceListItemDataLayer implements DataLayer { + private final DataLayer dal; + private final MongoTemplate mongoTemplate; + private final CrudQueryConverter queryConverter; + + public PriceListItemDataLayer(CrudFactory crudFactory, MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + this.dal = crudFactory.createDataLayer(PriceListItem.class); + this.mongoTemplate = mongoTemplate; + this.queryConverter = queryConverter; + } + + @Override + public Optional get(Object id) { + var query = CrudQuery.build().eq("_id", id).get(); + var item = find(query) + .getRows() + .stream() + .findFirst(); + + return item; + } + + @Override + public Result find(CrudQuery query) { + var priceListIdFilter = query.popFilter("priceListId"); + var pipeline = new ArrayList() {{ + addAll(queryConverter.convert(query)); + add(lookup("priceList", "priceListId", "_id", "priceList")); + add(unwind("priceList")); + add(lookup("equipment", "equipmentId", "_id", "equipment")); + add(lookup("equipmentType", "equipment.equipmentTypeId", "_id", "equipmentType")); + add(unwind("equipmentType")); + if (priceListIdFilter.isPresent()) { + add(match(where("priceList._id").is(priceListIdFilter.get().getValue()))); + } + }}; + + var totalRows = getTotalRows(mongoTemplate, pipeline, PriceListItem.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var aggregation = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(aggregation, PriceListItem.class, PriceListItem.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(PriceListItem entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return PriceListItem.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/ProtocolDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/ProtocolDataLayer.java new file mode 100644 index 0000000..c5699ca --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/ProtocolDataLayer.java @@ -0,0 +1,86 @@ +package applica.app.web.crud; + +import applica.app.domain.protocol.Protocol; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Component +@SuppressWarnings("unused") +public class ProtocolDataLayer implements DataLayer { + private final DataLayer dal; + private final MongoTemplate mongoTemplate; + private final CrudQueryConverter queryConverter; + + public ProtocolDataLayer(CrudFactory crudFactory, MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + this.dal = crudFactory.createDataLayer(Protocol.class); + this.mongoTemplate = mongoTemplate; + this.queryConverter = queryConverter; + } + + @Override + public Optional get(Object id) { + var query = CrudQuery.build().eq("_id", id).get(); + var item = find(query) + .getRows() + .stream() + .findFirst(); + + return item; + } + + @Override + public Result find(CrudQuery query) { + var customerIdFilter = query.popFilter("customerId"); + var pipeline = new ArrayList() {{ + addAll(queryConverter.convert(query)); + add(lookup("customer", "customerId", "_id", "customer")); + add(unwind("customer")); + + if (customerIdFilter.isPresent()) { + add(match(where("customer._id").is(customerIdFilter.get().getValue()))); + } + }}; + + var totalRows = getTotalRows(mongoTemplate, pipeline, Protocol.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var aggregation = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(aggregation, Protocol.class, Protocol.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(Protocol entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return Protocol.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/RFIDDeviceTrackDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/RFIDDeviceTrackDataLayer.java new file mode 100644 index 0000000..423dad1 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/RFIDDeviceTrackDataLayer.java @@ -0,0 +1,113 @@ +package applica.app.web.crud; + +import applica.app.domain.rfid.RFIDDeviceTrack; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import applica.crud.query.builders.CrudQueryBuilder; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Component +@SuppressWarnings("unused") +public class RFIDDeviceTrackDataLayer implements DataLayer { + private final DataLayer dal; + private final CrudQueryConverter queryConverter; + private final MongoTemplate mongoTemplate; + + public RFIDDeviceTrackDataLayer(CrudFactory crudFactory, CrudQueryConverter queryConverter, MongoTemplate mongoTemplate) { + this.dal = crudFactory.createDataLayer(RFIDDeviceTrack.class); + this.queryConverter = queryConverter; + this.mongoTemplate = mongoTemplate; + } + + @Override + public Optional get(Object id) { + return dal.get(id); + } + + @Override + public Result find(CrudQuery query) { + var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + var pipeline = new ArrayList() {{ + var from = query.popFilter("from"); + var to = query.popFilter("to"); + if (from.isPresent() && to.isPresent()) { + var fromValue = from.get().getValue(); + var toValue = to.get().getValue(); + if (fromValue instanceof String && toValue instanceof String) { + var fromDateTime = LocalDateTime.parse((String) fromValue, formatter); + var toDateTime = LocalDateTime.parse((String) toValue, formatter); + add(match(where("ts").gte(fromDateTime).lte(toDateTime))); + } + } + else if (from.isPresent()) { + var fromValue = from.get().getValue(); + if (fromValue instanceof String) { + var fromDateTime = LocalDateTime.parse((String) fromValue, formatter); + add(match(where("ts").gte(fromDateTime))); + } + } + else if (to.isPresent()) { + var toValue = to.get().getValue(); + if (toValue instanceof String) { + var toDateTime = LocalDateTime.parse((String) toValue, formatter); + add(match(where("ts").lte(toDateTime))); + } + } + }}; + + pipeline.addAll(queryConverter.convert(query)); + + var sorts = query.getSorts(); + if (!sorts.isEmpty()) { + for (var sort : sorts) { + var sortField = sort.getProperty(); + var sortDirection = sort.isDescending() ? Sort.Direction.DESC: Sort.Direction.ASC; + pipeline.add(sort(sortDirection, sortField)); + } + } + + var totalRows = getTotalRows(mongoTemplate, pipeline, RFIDDeviceTrack.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var resultsAggregate = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(resultsAggregate, RFIDDeviceTrack.class, RFIDDeviceTrack.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(RFIDDeviceTrack entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return RFIDDeviceTrack.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/crud/SupplyDataLayer.java b/edera-api/api/src/main/java/applica/app/web/crud/SupplyDataLayer.java new file mode 100644 index 0000000..cbb5478 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/crud/SupplyDataLayer.java @@ -0,0 +1,124 @@ +package applica.app.web.crud; + +import applica.app.domain.supply.Supply; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.model.Result; +import applica.crud.mongodb.MongoAggregateQuery; +import applica.crud.query.CrudQuery; +import applica.crud.query.CrudQueryConverter; +import com.mongodb.BasicDBObject; +import org.bson.Document; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.aggregation.AggregationOperation; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Optional; + +import static applica.crud.mongodb.MongoAggregationUtils.getTotalRows; +import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; +import static org.springframework.data.mongodb.core.query.Criteria.where; + +@Component +@SuppressWarnings("unused") +public class SupplyDataLayer implements DataLayer { + private final DataLayer dal; + private final MongoTemplate mongoTemplate; + private final CrudQueryConverter queryConverter; + + public SupplyDataLayer(CrudFactory crudFactory, MongoTemplate mongoTemplate, CrudQueryConverter queryConverter) { + this.dal = crudFactory.createDataLayer(Supply.class); + this.mongoTemplate = mongoTemplate; + this.queryConverter = queryConverter; + } + + @Override + public Optional get(Object id) { + var query = CrudQuery.build().eq("_id", id).get(); + var item = find(query) + .getRows() + .stream() + .findFirst(); + + return item; + } + + @Override + public Result find(CrudQuery query) { + var customerIdFilter = query.popFilter("customerId"); + var keyword = query.getKeyword(); + + final Criteria criteria; + + if ( keyword != null ) { + BasicDBObject regexObject = new BasicDBObject("$regex", keyword).append("$options", "i"); + + criteria = new Criteria().orOperator( + Criteria.where("supplier.businessName").is(regexObject), + Criteria.where("equipmentType.name").is(regexObject), + Criteria.where("protocol.title").is(regexObject), + Criteria.where("protocol.protocolNumber").is(regexObject), + Criteria.where("ddtNumber").is(regexObject) + ); + } else { + criteria = new Criteria(); + } + + + var pipeline = new ArrayList() {{ + addAll(queryConverter.convert(query)); + add(lookup("protocol", "protocolId", "_id", "protocol")); + add(unwind("protocol")); + add(lookup("customer", "protocol.customerId", "_id", "customer")); + add(unwind("customer")); + + if (customerIdFilter.isPresent()) { + add(match(where("customer._id").is(customerIdFilter.get().getValue()))); + } + + add(lookup("equipment", "equipmentId", "_id", "equipment")); + add(unwind("equipment")); + add(lookup("equipmentType", "equipment.equipmentTypeId", "_id", "equipmentType")); + add(unwind("equipmentType")); + add(lookup("supplier", "equipment.supplierId", "_id", "supplier")); + add(unwind("supplier")); + add(lookup("usage", "_id", "supplyId", "usages")); + add(lookup("area", "latestRfidTrack.areaId", "_id", "latestArea")); + add(unwind("latestArea", true)); + + if (keyword != null) { + add(match(criteria)); + } + }}; + + var totalRows = getTotalRows(mongoTemplate, pipeline, Supply.class); + var pageable = query.getPageable(); + var pageSize = pageable.getPageSize(); + var page = pageable.getPageNumber(); + + pipeline.add(skip((long) (page) * pageSize)); + pipeline.add(limit(pageSize)); + + var aggregation = Aggregation.newAggregation(pipeline); + var results = mongoTemplate.aggregate(aggregation, Supply.class, Supply.class); + return new Result<>(results.getMappedResults(), totalRows, page, pageSize); + } + + @Override + public void save(Supply entity) { + dal.save(entity); + } + + @Override + public void delete(Object id) { + dal.delete(id); + } + + @Override + public Class getEntityType() { + return Supply.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/filters/AuditLogTraceFilter.java b/edera-api/api/src/main/java/applica/app/web/filters/AuditLogTraceFilter.java new file mode 100644 index 0000000..1cfd302 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/filters/AuditLogTraceFilter.java @@ -0,0 +1,96 @@ +package applica.app.web.filters; + +import applica.app.domain.audit.AuditLog; +import applica.app.domain.audit.AuditLogMessageBuilderFactory; +import applica.app.utils.SecurityUtils; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import com.google.gson.Gson; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.web.util.ContentCachingRequestWrapper; +import org.springframework.web.util.ContentCachingResponseWrapper; + +import java.io.IOException; +import java.util.HashMap; + +@Component +@SuppressWarnings("unused") +public class AuditLogTraceFilter extends OncePerRequestFilter { + public static final String BODY_PARAM = "body"; + + private final Gson gson = new Gson(); + + private Log logger = LogFactory.getLog(getClass()); + private final DataLayer auditLogDataLayer; + private final AuditLogMessageBuilderFactory auditLogMessageBuilderFactory; + + public AuditLogTraceFilter(CrudFactory crudFactory, AuditLogMessageBuilderFactory auditLogMessageBuilderFactory) { + this.auditLogDataLayer = crudFactory.createDataLayer(AuditLog.class); + this.auditLogMessageBuilderFactory = auditLogMessageBuilderFactory; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + var requestWrapper = new ContentCachingRequestWrapper(request); + var responseWrapper = new ContentCachingResponseWrapper(response); + var requestData = new HashMap(); + var skip = AuditLog.skip(request); + try { + if (!skip) { + trace(request, requestData); + } + filterChain.doFilter(requestWrapper, responseWrapper); + } + finally { + responseWrapper.copyBodyToResponse(); + if (skip) { + return; + } + var body = new String(requestWrapper.getContentAsByteArray()); + + try { + var jsonBody = gson.fromJson(body, HashMap.class); + requestData.put(BODY_PARAM, jsonBody); + } + catch(Exception e) { + requestData.put(BODY_PARAM, body); + } + var auditLog = AuditLog.create( + requestWrapper, + gson.toJson(requestData), + new String(responseWrapper.getContentAsByteArray()), + SecurityUtils.getLoggedUser(), + auditLogMessageBuilderFactory); + + auditLogDataLayer.save(auditLog); + } + } + + + + private void trace(HttpServletRequest request, HashMap requestBody) throws ServletException, IOException { + if (isMultiPart(request)) { + var requestParts = request.getParts(); + for (var requestPart : requestParts) { + if (requestPart.getContentType().equals("application/json")) { + var partBody = new String(requestPart.getInputStream().readAllBytes()); + var json = gson.fromJson(partBody, HashMap.class); + requestBody.put(requestPart.getName(), json); + } + } + } + } + + private boolean isMultiPart(HttpServletRequest request) { + return request.getContentType() != null && ( + request.getContentType().startsWith("multipart/form-data") + || request.getContentType().startsWith("multipart/mixed")); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/filters/JwtAuthenticationFilter.java b/edera-api/api/src/main/java/applica/app/web/filters/JwtAuthenticationFilter.java new file mode 100644 index 0000000..bcd9b91 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/filters/JwtAuthenticationFilter.java @@ -0,0 +1,60 @@ +package applica.app.web.filters; + +import applica.app.utils.SecurityUtils; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.ResponseCodes; +import applica.iam.sdk.requests.ValidateTokenRequest; +import io.micrometer.common.util.StringUtils; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.annotation.Order; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Order(1) +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + final IAMService IAMService; + + public JwtAuthenticationFilter(IAMService IAMService) { + this.IAMService = IAMService; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + var authorization = request.getHeader("Authorization"); + var token = SecurityUtils.tokenFromAuthorizationHeader(authorization); + if (StringUtils.isEmpty(token)) { + chain.doFilter(request, response); + return; + } + + var result = IAMService.validateToken(new ValidateTokenRequest(token)); + if (!result.getResponseCode().equals(ResponseCodes.OK)) { + chain.doFilter(request, response); + return; + } + + var authentication = UsernamePasswordAuthenticationToken.authenticated( + result.getUser(), + null, + result.getUser() + .getRoles() + .stream() + .map(SimpleGrantedAuthority::new) + .toList() + ); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + + chain.doFilter(request, response); + } + +} diff --git a/edera-api/api/src/main/java/applica/app/web/operations/EquipmentTypeGetOperation.java b/edera-api/api/src/main/java/applica/app/web/operations/EquipmentTypeGetOperation.java new file mode 100644 index 0000000..5677042 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/operations/EquipmentTypeGetOperation.java @@ -0,0 +1,60 @@ +package applica.app.web.operations; + +import applica.app.domain.equipment.EquipmentType; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.mapping.EntityMapper; +import applica.crud.operations.BaseGetOperation; +import applica.crud.operations.OperationException; +import applica.crud.operations.OperationsRouter; +import applica.crud.operations.decorators.GetDecorator; +import applica.crud.query.builders.CrudQueryBuilder; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +public class EquipmentTypeGetOperation extends BaseGetOperation { + + final CrudFactory crudFactory; + public EquipmentTypeGetOperation(EntityMapper entityMapper, Optional router, CrudFactory crudFactory, GetDecorator[] decorators) { + super(entityMapper, router, crudFactory, decorators); + this.crudFactory = crudFactory; + } + + @Override + protected void finishNode(Object entity, ObjectNode node) throws OperationException { + super.finishNode(entity, node); + + List> parents = loadParents((EquipmentType) entity, new ArrayList<>(), crudFactory.createDataLayer(EquipmentType.class)); + ArrayNode parentArray = node.putArray("parents"); + + for (Map parent : parents) { + ObjectNode parentObj = parentArray.addObject(); + parentObj.put("id", parent.get("id")); + parentObj.put("name", parent.get("name")); + } + } + + private List> loadParents(EquipmentType equipmentType, List> parents, DataLayer dal) { + if (equipmentType.getParentId() != null) { + var parent = dal.find(CrudQueryBuilder.build().eq("id", equipmentType.getParentId())).getRows().get(0); + + Map parentData = new HashMap<>(); + parentData.put("id", parent.getId()); + parentData.put("name", parent.getName()); + parents.add(parentData); + + loadParents(parent, parents, dal); + } + return parents; + } + + + @Override + public Class getEntityType() { + return EquipmentType.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/operations/I18nMessageDeleteOperation.java b/edera-api/api/src/main/java/applica/app/web/operations/I18nMessageDeleteOperation.java new file mode 100644 index 0000000..4e137c8 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/operations/I18nMessageDeleteOperation.java @@ -0,0 +1,41 @@ +package applica.app.web.operations; + +import applica.app.domain.I18nMessage; +import applica.crud.attachments.AttachmentsResolver; +import applica.crud.constraints.ConstraintsChecker; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.operations.BaseDeleteOperation; +import applica.crud.operations.OperationException; +import applica.crud.operations.OperationsRouter; +import applica.crud.operations.decorators.DeleteDecorator; +import applica.crud.query.CrudQuery; +import applica.fs.FsClient; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +@Component +@SuppressWarnings("unused") +public class I18nMessageDeleteOperation extends BaseDeleteOperation { + final DataLayer dataLayer; + + public I18nMessageDeleteOperation(FsClient fileServer, CrudFactory crudFactory, Optional constraintsChecker, AttachmentsResolver attachmentsResolver, Optional router, DeleteDecorator[] decorators) { + super(fileServer, crudFactory, constraintsChecker, attachmentsResolver, router, decorators); + + this.dataLayer = crudFactory.createDataLayer(I18nMessage.class); + } + + @Override + public void delete(List ids) throws OperationException { + super.delete(ids); + + I18nMessage.persistAsResource(dataLayer.find(CrudQuery.build()).getRows()); + } + + @Override + public Class getEntityType() { + return I18nMessage.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/operations/I18nMessageSaveOperation.java b/edera-api/api/src/main/java/applica/app/web/operations/I18nMessageSaveOperation.java new file mode 100644 index 0000000..d267d15 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/operations/I18nMessageSaveOperation.java @@ -0,0 +1,41 @@ +package applica.app.web.operations; + +import applica.app.domain.I18nMessage; +import applica.crud.attachments.AttachmentsResolver; +import applica.crud.datalayer.DataLayer; +import applica.crud.factory.CrudFactory; +import applica.crud.mapping.EntityMapper; +import applica.crud.operations.BaseSaveOperation; +import applica.crud.operations.OperationException; +import applica.crud.operations.OperationsRouter; +import applica.crud.operations.decorators.SaveDecorator; +import applica.crud.query.CrudQuery; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.validation.Validator; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +@SuppressWarnings("unused") +public class I18nMessageSaveOperation extends BaseSaveOperation { + final DataLayer dataLayer; + + public I18nMessageSaveOperation(EntityMapper entityMapper, Optional router, Validator validator, CrudFactory crudFactory, SaveDecorator[] decorators, AttachmentsResolver attachmentsResolver) { + super(entityMapper, router, validator, crudFactory, decorators, attachmentsResolver); + + this.dataLayer = crudFactory.createDataLayer(I18nMessage.class); + } + + @Override + protected void afterSave(ObjectNode node, Object entity) throws OperationException { + super.afterSave(node, entity); + + I18nMessage.persistAsResource(dataLayer.find(CrudQuery.build()).getRows()); + } + + @Override + public Class getEntityType() { + return I18nMessage.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/operations/NotificationFindOperation.java b/edera-api/api/src/main/java/applica/app/web/operations/NotificationFindOperation.java new file mode 100644 index 0000000..c6647c4 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/operations/NotificationFindOperation.java @@ -0,0 +1,38 @@ +package applica.app.web.operations; + +import applica.app.domain.Notification; +import applica.app.utils.SecurityUtils; +import applica.crud.factory.CrudFactory; +import applica.crud.mapping.EntityMapper; +import applica.crud.operations.BaseFindOperation; +import applica.crud.operations.OperationException; +import applica.crud.operations.OperationsRouter; +import applica.crud.operations.decorators.FindDecorator; +import applica.crud.query.CrudQuery; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +@SuppressWarnings("unused") +public class NotificationFindOperation extends BaseFindOperation { + public NotificationFindOperation(Optional router, CrudFactory factory, EntityMapper entityMapper, FindDecorator[] decorators) { + super(router, factory, entityMapper, decorators); + } + + @Override + public ObjectNode find(CrudQuery query) throws OperationException { + var loggedUser = SecurityUtils.getLoggedUser(); + if (loggedUser.isPresent()) { + var builder = CrudQuery.build(query); + builder.eq("userId", loggedUser.get().getId()); + } + return super.find(query); + } + + @Override + public Class getEntityType() { + return Notification.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/operations/PriceListItemSaveOperation.java b/edera-api/api/src/main/java/applica/app/web/operations/PriceListItemSaveOperation.java new file mode 100644 index 0000000..024ae4c --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/operations/PriceListItemSaveOperation.java @@ -0,0 +1,43 @@ +package applica.app.web.operations; + +import applica.app.domain.pricing.PriceListItem; +import applica.crud.attachments.AttachmentsResolver; +import applica.crud.factory.CrudFactory; +import applica.crud.mapping.EntityMapper; +import applica.crud.operations.BaseSaveOperation; +import applica.crud.operations.OperationException; +import applica.crud.operations.OperationsRouter; +import applica.crud.operations.decorators.SaveDecorator; +import applica.crud.query.builders.CrudQueryBuilder; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.validation.Validator; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class PriceListItemSaveOperation extends BaseSaveOperation { + + final CrudFactory crudFactory; + public PriceListItemSaveOperation(EntityMapper entityMapper, Optional router, Validator validator, CrudFactory crudFactory, SaveDecorator[] decorators, AttachmentsResolver attachmentsResolver) { + super(entityMapper, router, validator, crudFactory, decorators, attachmentsResolver); + this.crudFactory = crudFactory; + } + + @Override + protected void beforeSave(ObjectNode data, Object entity) throws OperationException { + super.beforeSave(data, entity); + PriceListItem priceListItem = (PriceListItem) entity; + + if (priceListItem.getId() == null) { + if (crudFactory.createDataLayer(PriceListItem.class).find(CrudQueryBuilder.build().eq("equipmentId", priceListItem.getEquipmentId()).eq("priceListId", priceListItem.getPriceListId())).getRows().size() > 0) { + throw new OperationException("ra.error.price-list-item.save.equipmentId-already-exists"); + } + } + } + + @Override + public Class getEntityType() { + return PriceListItem.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/operations/PriceListSaveOperation.java b/edera-api/api/src/main/java/applica/app/web/operations/PriceListSaveOperation.java new file mode 100644 index 0000000..a41ae00 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/operations/PriceListSaveOperation.java @@ -0,0 +1,38 @@ +package applica.app.web.operations; + +import applica.app.domain.pricing.PriceList; +import applica.crud.attachments.AttachmentsResolver; +import applica.crud.factory.CrudFactory; +import applica.crud.mapping.EntityMapper; +import applica.crud.operations.BaseSaveOperation; +import applica.crud.operations.OperationException; +import applica.crud.operations.OperationsRouter; +import applica.crud.operations.decorators.SaveDecorator; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.validation.Validator; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class PriceListSaveOperation extends BaseSaveOperation { + + final CrudFactory crudFactory; + public PriceListSaveOperation(EntityMapper entityMapper, Optional router, Validator validator, CrudFactory crudFactory, SaveDecorator[] decorators, AttachmentsResolver attachmentsResolver) { + super(entityMapper, router, validator, crudFactory, decorators, attachmentsResolver); + this.crudFactory = crudFactory; + } + + @Override + protected void beforeSave(ObjectNode data, Object entity) throws OperationException { + PriceList priceList = (PriceList) entity; + if (priceList.getStart().isAfter(priceList.getEnd())) { + throw new OperationException("ra.error.price-list.save.start-after-end"); + } + } + + @Override + public Class getEntityType() { + return PriceList.class; + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/operations/decorators/CustomerFilterableFindDecorator.java b/edera-api/api/src/main/java/applica/app/web/operations/decorators/CustomerFilterableFindDecorator.java new file mode 100644 index 0000000..1170252 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/operations/decorators/CustomerFilterableFindDecorator.java @@ -0,0 +1,25 @@ +package applica.app.web.operations.decorators; + +import applica.app.utils.SecurityUtils; +import applica.app.web.annotations.CustomerFilterable; +import applica.crud.operations.OperationException; +import applica.crud.operations.decorators.FindDecoratorAdapter; +import applica.crud.query.CrudQuery; +import org.springframework.util.StringUtils; + +public class CustomerFilterableFindDecorator extends FindDecoratorAdapter { + @Override + public void onBeforeFind(Class entityType, CrudQuery query) throws OperationException { + if (entityType.isAnnotationPresent(CustomerFilterable.class)) { + var loggedUser = SecurityUtils.getLoggedUser(); + if (loggedUser.isPresent()) { + var customerId = loggedUser.get().getProfile().get("customerId"); + if (StringUtils.hasLength(customerId)){ + var builder = CrudQuery.build(query); + builder.eq("customerId", customerId); + } + } + } + super.onBeforeFind(entityType, query); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/requests/GetReportDataRequest.java b/edera-api/api/src/main/java/applica/app/web/requests/GetReportDataRequest.java new file mode 100644 index 0000000..36836fd --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/requests/GetReportDataRequest.java @@ -0,0 +1,6 @@ +package applica.app.web.requests; + +import applica.app.domain.reporting.FilterSet; + +public class GetReportDataRequest extends FilterSet { +} diff --git a/edera-api/api/src/main/java/applica/app/web/requests/PatchProfileRequest.java b/edera-api/api/src/main/java/applica/app/web/requests/PatchProfileRequest.java new file mode 100644 index 0000000..0d0668d --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/requests/PatchProfileRequest.java @@ -0,0 +1,12 @@ +package applica.app.web.requests; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PatchProfileRequest { + String name; +} diff --git a/edera-api/api/src/main/java/applica/app/web/responses/ActivityInfoResponse.java b/edera-api/api/src/main/java/applica/app/web/responses/ActivityInfoResponse.java new file mode 100644 index 0000000..c5407cc --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/responses/ActivityInfoResponse.java @@ -0,0 +1,23 @@ +package applica.app.web.responses; + +import applica.app.domain.dto.ActivityDetailsDTO; +import applica.crud.responses.Response; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper=false) +public class ActivityInfoResponse extends Response { + private ActivityDetailsDTO activityDetailsDTO; + + public ActivityInfoResponse(ActivityDetailsDTO activityDetailsDTO) { + super(Response.OK); + this.activityDetailsDTO = activityDetailsDTO; + } + + public ActivityInfoResponse(String responseCode) { + super(responseCode); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/responses/CrudLoginResponse.java b/edera-api/api/src/main/java/applica/app/web/responses/CrudLoginResponse.java new file mode 100644 index 0000000..0ae05d3 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/responses/CrudLoginResponse.java @@ -0,0 +1,30 @@ +package applica.app.web.responses; + +import applica.crud.acl.CrudSecurityConfigurer; +import applica.iam.sdk.readmodel.UserView; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +import java.util.List; + +@Getter +@ToString +@EqualsAndHashCode +public class CrudLoginResponse { + public CrudLoginResponse(String responseCode, UserView user, String token) { + this.responseCode = responseCode; + this.user = user; + this.token = token; + + if (user != null) { + crudPermissions = CrudSecurityConfigurer.instance().getCrudPermissionsByRoles(user.getRoles()); + } + } + + String responseCode; + UserView user; + String token; + List crudPermissions; + +} diff --git a/edera-api/api/src/main/java/applica/app/web/responses/GetReportDataResponse.java b/edera-api/api/src/main/java/applica/app/web/responses/GetReportDataResponse.java new file mode 100644 index 0000000..c7e521a --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/responses/GetReportDataResponse.java @@ -0,0 +1,21 @@ +package applica.app.web.responses; + +import applica.crud.responses.Response; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public class GetReportDataResponse extends Response { + Map data = new HashMap<>(); + + public GetReportDataResponse(Map map) { + super(Response.OK); + this.data = map; + } + + public GetReportDataResponse(String responseCode) { + super(responseCode); + } +} diff --git a/edera-api/api/src/main/java/applica/app/web/responses/SupplyInfoResponse.java b/edera-api/api/src/main/java/applica/app/web/responses/SupplyInfoResponse.java new file mode 100644 index 0000000..31b7e92 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/responses/SupplyInfoResponse.java @@ -0,0 +1,23 @@ +package applica.app.web.responses; + +import applica.app.domain.dto.SupplyDetailsDTO; +import applica.crud.responses.Response; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper=false) +public class SupplyInfoResponse extends Response { + private SupplyDetailsDTO supplyDetailsDTO; + + public SupplyInfoResponse(SupplyDetailsDTO supplyDetailsDTO) { + super(Response.OK); + this.supplyDetailsDTO = supplyDetailsDTO; + } + + public SupplyInfoResponse(String responseCode) { + super(responseCode); + } +} \ No newline at end of file diff --git a/edera-api/api/src/main/java/applica/app/web/security/JwtAuthenticationEntryPoint.java b/edera-api/api/src/main/java/applica/app/web/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..41ab871 --- /dev/null +++ b/edera-api/api/src/main/java/applica/app/web/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,18 @@ +package applica.app.web.security; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + } +} diff --git a/edera-api/api/src/main/resources/application-production.yaml b/edera-api/api/src/main/resources/application-production.yaml new file mode 100644 index 0000000..b01a5fb --- /dev/null +++ b/edera-api/api/src/main/resources/application-production.yaml @@ -0,0 +1,13 @@ +spring: + data: + mongodb: + uri: mongodb+srv://edera:pS9GGYdSRDm94Pdr@edera.a8nnng4.mongodb.net + database: production + +ml: + endpoint: http://ml:5000 + +app: + mode: production + test: false + diff --git a/edera-api/api/src/main/resources/application-test.yaml b/edera-api/api/src/main/resources/application-test.yaml new file mode 100644 index 0000000..b4a4856 --- /dev/null +++ b/edera-api/api/src/main/resources/application-test.yaml @@ -0,0 +1,11 @@ +spring: + data: + mongodb: + uri: mongodb+srv://edera:pS9GGYdSRDm94Pdr@edera.a8nnng4.mongodb.net + database: test + # uri: mongodb://localhost:27017 + # database: edera-test + auto-index-creation: true +app: + mode: test + test: true \ No newline at end of file diff --git a/edera-api/api/src/main/resources/application.yaml b/edera-api/api/src/main/resources/application.yaml new file mode 100644 index 0000000..a4003b3 --- /dev/null +++ b/edera-api/api/src/main/resources/application.yaml @@ -0,0 +1,96 @@ +server: + port: 8080 + servlet: + context-path: /api + +spring: + servlet: + multipart: + max-file-size: 8MB + data: + mongodb: + uri: mongodb://localhost:27017 + database: edera + auto-index-creation: true + rest: + basePath: /crud + mail: + host: smtp-relay.sendinblue.com + port: 587 + username: bruno.fortunato@applica.guru + password: pAbxCmgwLRFWHcJB + smtp: + auth: true + starttls: + enable: true +jwt: + token: + secret: applica + expire-seconds: 3000 + +mail: + from: "noreply@applica.guru" + templates: + path: "templates" + +fs: + local: + base-path: "/tmp" + images: + max-size: "2532x2532" + gcp: + credentials: "classpath:/credentials/service-account.json" + project-id: "edera" + bucket-name: "edera-bucket" + +cors: + allowed-origins: "*" + +iam: + max-login-attempts: 3 + default-role: ROLE_USER # Utilizzatore + setup: + roles: + - ROLE_ADMIN # Administrator + - ROLE_OPERATOR # Operatore + - ROLE_USER # Utilizzatore + - ROLE_MAINTAINER # Manutentore + - ROLE_CUSTOMER # Cliente + admin: + email: admin@applica.guru + password: YXBwbGljYQ== #base64 + role: ROLE_ADMIN + http: + url: "http://localhost:8082/iam" + +management: + endpoints: + web: + cors: + allowed-origins: "*" + allowed-methods: "OPTIONS,GET,POST" + exposure: + include: "info,health,httptrace" + endpoint: + health: + probes: + enabled: true + health: + livenessState: + enabled: true + readinessState: + enabled: true + +app: + test: false + mode: development + +geo: + csv: + nation: "/csv/nations.csv" + region: "/csv/regions.csv" + province: "/csv/provinces.csv" + city: "/csv/cities.csv" + +ml: + endpoint: http://localhost:5000 \ No newline at end of file diff --git a/edera-api/api/src/main/resources/credentials/service-account.json b/edera-api/api/src/main/resources/credentials/service-account.json new file mode 100644 index 0000000..5ed0315 --- /dev/null +++ b/edera-api/api/src/main/resources/credentials/service-account.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "applica-general", + "private_key_id": "497c6f5597f45275f7e9fe4031c4b829e2687121", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCt4kcPwQRzmD7o\npyUAPeNpgKMSXlS3nBbemIAeri7vnFxrH0UxFRgvdMU9sE2z/HyYsS0cgGTwcMEw\nBUUaQwQjT0UqvPk7prciNYDRMuMAv51nXZJQgDXz+LHmyVWahMUE9Ls38c2qyAij\nU0cjHjNll2jwKby9bU5ETqiSxKqtMEEYpIAsWi/XmbzLz6UmJyZvnzd+dDSQA57h\ncCl8ASvPiA7HyusoYsUbvKlQKKfrwmWsARYDV7QsKzlJlGEbXMlZZ3w0uT+3VLW9\nMc2KQhHjoijhMorF7Uv5V22kMi2/exFB7/q+nYBz59+S1QveFjBwq9/H0A4rMzTk\nmfCc8c1fAgMBAAECggEANGWlvTkQItcjSc8oJrD/iKizOxNC2wtFlvEEVnpteVW4\nQa1sF7TAE3jQAN1SJOT2FLr7GYYVJKENje9gmd/M7OjzskO8pL2BnOTbeu6nGfAj\nueSn9OsVlv1/ekh8K7JLfklS6zJJo+dgNvseyhXNLhVYkVo6XiiEd6/uOz/ZIJOU\nLYG7XOTq15hJrfZ3kkt0AFWIscJIuElPeQ2Nh5VcuRyRpQT0hP45IQQ6EtIAYzx9\nRtFQaawkiYQjgDdzQNBmmPsveg8cbdAyVeYqr+ZVAb6MiZ2v7MQGHrxAArxRytLf\n2gvUIt+zovbAzj7Cxtb5/KrCtu00/ZY7074qLLgGSQKBgQDv5td6lVmH9qywM8Ss\n6p94NeMQkmOo0N5J0TR+1LaHNpdv0ZcptlBCKIBMz+U0AsJtpmuvZFLgGrjzSq6p\nTYFR+42W562F2J1ZiJfggX7nmjwNhT77kue0n5VlMbLpT7B3j0zWqmsHjgOeehCn\nxB09zJqrDboz2EwPeoFHCV0ytwKBgQC5jVjIwmEwMOSh9PqwC2yIPXy/5RJFLn2/\n5lsRhQnI+NLSeBcZtHWPb9g25QzHUUudQ4hbajGh35GkyHkHr2y0ecu1TwjUN+F0\no7az4szI8ky3FOlEJous8zqMAk+bxEGXkQCdZab/ImKK/GWQ+mQqyCWDmRAoGsUq\nLBMuHJ9ymQKBgF+FrADcXOTdXI9gXYx4c3zbAAmGMHZ0jD4aNevWaMNYAl58ttLe\nDAD7vXJYSSw3eRFN9YzFxpYDLed5sigpezeYkR0oLJih0q1mzQqQpWY0rHq5toVX\nTjlGXacIbfOmTl6cyXykKK++ZUSB2AXk+bu0r1UyxxSDqG11WupdGSXrAoGBAJ6a\nroB0foSl1liFwd7G9Q+Dl2Wj1bki40QsED3qfRG3duWG1yAWu8JOtP8/TGv3Fm4n\nsp+JJ0GZi7HR1np2PbIKxdCF7SMRXPrJkbszqx481sxL6JRjalL8WVgiBZA88mAv\nBtqDcHp3Fsp8sgh5rzNOf5p8NG5Da7L/l6l7t+NJAoGBAOgz0s5Xa+G6KNiU7B2H\nsIv2dM36o6VwkmOOqct+dU/2pmvdc8hZClVFapPyfxv1jVscH5+dnEhRHi13awHS\nW772t9YGA5jFoggjEOENPmTvAL1wMM/A1D+fjuZYP+8EChE4BafmSwYfFW2QBlDx\nfXh8sfOAg28n0G5AcFqvUHRM\n-----END PRIVATE KEY-----\n", + "client_email": "bitbucket-pipelines@applica-general.iam.gserviceaccount.com", + "client_id": "108394815677481426260", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/bitbucket-pipelines%40applica-general.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +} diff --git a/edera-api/api/src/main/resources/csv/cities.csv b/edera-api/api/src/main/resources/csv/cities.csv new file mode 100644 index 0000000..f9f113a --- /dev/null +++ b/edera-api/api/src/main/resources/csv/cities.csv @@ -0,0 +1,7905 @@ +comune,pro_com_t,den_prov,sigla,den_reg,cod_reg,cap +Agliè,1001,Torino,TO,Piemonte,1,10011 +Airasca,1002,Torino,TO,Piemonte,1,10060 +Ala di Stura,1003,Torino,TO,Piemonte,1,10070 +Albiano d'Ivrea,1004,Torino,TO,Piemonte,1,10010 +Almese,1006,Torino,TO,Piemonte,1,10040 +Alpette,1007,Torino,TO,Piemonte,1,10080 +Alpignano,1008,Torino,TO,Piemonte,1,10091 +Andezeno,1009,Torino,TO,Piemonte,1,10020 +Andrate,1010,Torino,TO,Piemonte,1,10010 +Angrogna,1011,Torino,TO,Piemonte,1,10060 +Arignano,1012,Torino,TO,Piemonte,1,10020 +Avigliana,1013,Torino,TO,Piemonte,1,10051 +Azeglio,1014,Torino,TO,Piemonte,1,10010 +Bairo,1015,Torino,TO,Piemonte,1,10010 +Balangero,1016,Torino,TO,Piemonte,1,10070 +Baldissero Canavese,1017,Torino,TO,Piemonte,1,10080 +Baldissero Torinese,1018,Torino,TO,Piemonte,1,10020 +Balme,1019,Torino,TO,Piemonte,1,10070 +Banchette,1020,Torino,TO,Piemonte,1,10010 +Barbania,1021,Torino,TO,Piemonte,1,10070 +Bardonecchia,1022,Torino,TO,Piemonte,1,10052 +Barone Canavese,1023,Torino,TO,Piemonte,1,10010 +Beinasco,1024,Torino,TO,Piemonte,1,10092 +Bibiana,1025,Torino,TO,Piemonte,1,10060 +Bobbio Pellice,1026,Torino,TO,Piemonte,1,10060 +Bollengo,1027,Torino,TO,Piemonte,1,10012 +Borgaro Torinese,1028,Torino,TO,Piemonte,1,10071 +Borgiallo,1029,Torino,TO,Piemonte,1,10080 +Borgofranco d'Ivrea,1030,Torino,TO,Piemonte,1,10013 +Borgomasino,1031,Torino,TO,Piemonte,1,10031 +Borgone Susa,1032,Torino,TO,Piemonte,1,10050 +Bosconero,1033,Torino,TO,Piemonte,1,10080 +Brandizzo,1034,Torino,TO,Piemonte,1,10032 +Bricherasio,1035,Torino,TO,Piemonte,1,10060 +Brosso,1036,Torino,TO,Piemonte,1,10080 +Brozolo,1037,Torino,TO,Piemonte,1,10020 +Bruino,1038,Torino,TO,Piemonte,1,10090 +Brusasco,1039,Torino,TO,Piemonte,1,10020 +Bruzolo,1040,Torino,TO,Piemonte,1,10050 +Buriasco,1041,Torino,TO,Piemonte,1,10060 +Burolo,1042,Torino,TO,Piemonte,1,10010 +Busano,1043,Torino,TO,Piemonte,1,10080 +Bussoleno,1044,Torino,TO,Piemonte,1,10053 +Buttigliera Alta,1045,Torino,TO,Piemonte,1,10090 +Cafasse,1046,Torino,TO,Piemonte,1,10070 +Caluso,1047,Torino,TO,Piemonte,1,10014 +Cambiano,1048,Torino,TO,Piemonte,1,10020 +Campiglione Fenile,1049,Torino,TO,Piemonte,1,10060 +Candia Canavese,1050,Torino,TO,Piemonte,1,10010 +Candiolo,1051,Torino,TO,Piemonte,1,10060 +Canischio,1052,Torino,TO,Piemonte,1,10080 +Cantalupa,1053,Torino,TO,Piemonte,1,10060 +Cantoira,1054,Torino,TO,Piemonte,1,10070 +Caprie,1055,Torino,TO,Piemonte,1,10040 +Caravino,1056,Torino,TO,Piemonte,1,10010 +Carema,1057,Torino,TO,Piemonte,1,10010 +Carignano,1058,Torino,TO,Piemonte,1,10041 +Carmagnola,1059,Torino,TO,Piemonte,1,10022 +Casalborgone,1060,Torino,TO,Piemonte,1,10020 +Cascinette d'Ivrea,1061,Torino,TO,Piemonte,1,10010 +Caselette,1062,Torino,TO,Piemonte,1,10040 +Caselle Torinese,1063,Torino,TO,Piemonte,1,10072 +Castagneto Po,1064,Torino,TO,Piemonte,1,10090 +Castagnole Piemonte,1065,Torino,TO,Piemonte,1,10060 +Castellamonte,1066,Torino,TO,Piemonte,1,10081 +Castelnuovo Nigra,1067,Torino,TO,Piemonte,1,10080 +Castiglione Torinese,1068,Torino,TO,Piemonte,1,10090 +Cavagnolo,1069,Torino,TO,Piemonte,1,10020 +Cavour,1070,Torino,TO,Piemonte,1,10061 +Cercenasco,1071,Torino,TO,Piemonte,1,10060 +Ceres,1072,Torino,TO,Piemonte,1,10070 +Ceresole Reale,1073,Torino,TO,Piemonte,1,10080 +Cesana Torinese,1074,Torino,TO,Piemonte,1,10054 +Chialamberto,1075,Torino,TO,Piemonte,1,10070 +Chianocco,1076,Torino,TO,Piemonte,1,10050 +Chiaverano,1077,Torino,TO,Piemonte,1,10010 +Chieri,1078,Torino,TO,Piemonte,1,10023 +Chiesanuova,1079,Torino,TO,Piemonte,1,10080 +Chiomonte,1080,Torino,TO,Piemonte,1,10050 +Chiusa di San Michele,1081,Torino,TO,Piemonte,1,10050 +Chivasso,1082,Torino,TO,Piemonte,1,10034 +Ciconio,1083,Torino,TO,Piemonte,1,10080 +Cintano,1084,Torino,TO,Piemonte,1,10080 +Cinzano,1085,Torino,TO,Piemonte,1,10090 +Ciriè,1086,Torino,TO,Piemonte,1,10073 +Claviere,1087,Torino,TO,Piemonte,1,10050 +Coassolo Torinese,1088,Torino,TO,Piemonte,1,10070 +Coazze,1089,Torino,TO,Piemonte,1,10050 +Collegno,1090,Torino,TO,Piemonte,1,10093 +Colleretto Castelnuovo,1091,Torino,TO,Piemonte,1,10080 +Colleretto Giacosa,1092,Torino,TO,Piemonte,1,10010 +Condove,1093,Torino,TO,Piemonte,1,10055 +Corio,1094,Torino,TO,Piemonte,1,10070 +Cossano Canavese,1095,Torino,TO,Piemonte,1,10010 +Cuceglio,1096,Torino,TO,Piemonte,1,10090 +Cumiana,1097,Torino,TO,Piemonte,1,10040 +Cuorgnè,1098,Torino,TO,Piemonte,1,10082 +Druento,1099,Torino,TO,Piemonte,1,10040 +Exilles,1100,Torino,TO,Piemonte,1,10050 +Favria,1101,Torino,TO,Piemonte,1,10083 +Feletto,1102,Torino,TO,Piemonte,1,10080 +Fenestrelle,1103,Torino,TO,Piemonte,1,10060 +Fiano,1104,Torino,TO,Piemonte,1,10070 +Fiorano Canavese,1105,Torino,TO,Piemonte,1,10010 +Foglizzo,1106,Torino,TO,Piemonte,1,10090 +Forno Canavese,1107,Torino,TO,Piemonte,1,10084 +Frassinetto,1108,Torino,TO,Piemonte,1,10080 +Front,1109,Torino,TO,Piemonte,1,10070 +Frossasco,1110,Torino,TO,Piemonte,1,10060 +Garzigliana,1111,Torino,TO,Piemonte,1,10060 +Gassino Torinese,1112,Torino,TO,Piemonte,1,10090 +Germagnano,1113,Torino,TO,Piemonte,1,10070 +Giaglione,1114,Torino,TO,Piemonte,1,10050 +Giaveno,1115,Torino,TO,Piemonte,1,10094 +Givoletto,1116,Torino,TO,Piemonte,1,10040 +Gravere,1117,Torino,TO,Piemonte,1,10050 +Groscavallo,1118,Torino,TO,Piemonte,1,10070 +Grosso,1119,Torino,TO,Piemonte,1,10070 +Grugliasco,1120,Torino,TO,Piemonte,1,10095 +Ingria,1121,Torino,TO,Piemonte,1,10080 +Inverso Pinasca,1122,Torino,TO,Piemonte,1,10060 +Isolabella,1123,Torino,TO,Piemonte,1,10046 +Issiglio,1124,Torino,TO,Piemonte,1,10080 +Ivrea,1125,Torino,TO,Piemonte,1,10015 +La Cassa,1126,Torino,TO,Piemonte,1,10040 +La Loggia,1127,Torino,TO,Piemonte,1,10040 +Lanzo Torinese,1128,Torino,TO,Piemonte,1,10074 +Lauriano,1129,Torino,TO,Piemonte,1,10020 +Leini,1130,Torino,TO,Piemonte,1,10040 +Lemie,1131,Torino,TO,Piemonte,1,10070 +Lessolo,1132,Torino,TO,Piemonte,1,10010 +Levone,1133,Torino,TO,Piemonte,1,10070 +Locana,1134,Torino,TO,Piemonte,1,10080 +Lombardore,1135,Torino,TO,Piemonte,1,10040 +Lombriasco,1136,Torino,TO,Piemonte,1,10040 +Loranzè,1137,Torino,TO,Piemonte,1,10010 +Luserna San Giovanni,1139,Torino,TO,Piemonte,1,10062 +Lusernetta,1140,Torino,TO,Piemonte,1,10060 +Lusigliè,1141,Torino,TO,Piemonte,1,10080 +Macello,1142,Torino,TO,Piemonte,1,10060 +Maglione,1143,Torino,TO,Piemonte,1,10030 +Marentino,1144,Torino,TO,Piemonte,1,10020 +Massello,1145,Torino,TO,Piemonte,1,10060 +Mathi,1146,Torino,TO,Piemonte,1,10075 +Mattie,1147,Torino,TO,Piemonte,1,10050 +Mazzè,1148,Torino,TO,Piemonte,1,10035 +Meana di Susa,1149,Torino,TO,Piemonte,1,10050 +Mercenasco,1150,Torino,TO,Piemonte,1,10010 +Mezzenile,1152,Torino,TO,Piemonte,1,10070 +Mombello di Torino,1153,Torino,TO,Piemonte,1,10020 +Mompantero,1154,Torino,TO,Piemonte,1,10059 +Monastero di Lanzo,1155,Torino,TO,Piemonte,1,10070 +Moncalieri,1156,Torino,TO,Piemonte,1,10024 +Moncenisio,1157,Torino,TO,Piemonte,1,10050 +Montaldo Torinese,1158,Torino,TO,Piemonte,1,10020 +Montalenghe,1159,Torino,TO,Piemonte,1,10090 +Montalto Dora,1160,Torino,TO,Piemonte,1,10016 +Montanaro,1161,Torino,TO,Piemonte,1,10017 +Monteu da Po,1162,Torino,TO,Piemonte,1,10020 +Moriondo Torinese,1163,Torino,TO,Piemonte,1,10020 +Nichelino,1164,Torino,TO,Piemonte,1,10042 +Noasca,1165,Torino,TO,Piemonte,1,10080 +Nole,1166,Torino,TO,Piemonte,1,10076 +Nomaglio,1167,Torino,TO,Piemonte,1,10010 +None,1168,Torino,TO,Piemonte,1,10060 +Novalesa,1169,Torino,TO,Piemonte,1,10050 +Oglianico,1170,Torino,TO,Piemonte,1,10080 +Orbassano,1171,Torino,TO,Piemonte,1,10043 +Orio Canavese,1172,Torino,TO,Piemonte,1,10010 +Osasco,1173,Torino,TO,Piemonte,1,10060 +Osasio,1174,Torino,TO,Piemonte,1,10040 +Oulx,1175,Torino,TO,Piemonte,1,10056 +Ozegna,1176,Torino,TO,Piemonte,1,10080 +Palazzo Canavese,1177,Torino,TO,Piemonte,1,10010 +Pancalieri,1178,Torino,TO,Piemonte,1,10060 +Parella,1179,Torino,TO,Piemonte,1,10010 +Pavarolo,1180,Torino,TO,Piemonte,1,10020 +Pavone Canavese,1181,Torino,TO,Piemonte,1,10018 +Pecetto Torinese,1183,Torino,TO,Piemonte,1,10020 +Perosa Argentina,1184,Torino,TO,Piemonte,1,10063 +Perosa Canavese,1185,Torino,TO,Piemonte,1,10010 +Perrero,1186,Torino,TO,Piemonte,1,10060 +Pertusio,1187,Torino,TO,Piemonte,1,10080 +Pessinetto,1188,Torino,TO,Piemonte,1,10070 +Pianezza,1189,Torino,TO,Piemonte,1,10044 +Pinasca,1190,Torino,TO,Piemonte,1,10060 +Pinerolo,1191,Torino,TO,Piemonte,1,10064 +Pino Torinese,1192,Torino,TO,Piemonte,1,10025 +Piobesi Torinese,1193,Torino,TO,Piemonte,1,10040 +Piossasco,1194,Torino,TO,Piemonte,1,10045 +Piscina,1195,Torino,TO,Piemonte,1,10060 +Piverone,1196,Torino,TO,Piemonte,1,10010 +Poirino,1197,Torino,TO,Piemonte,1,10046 +Pomaretto,1198,Torino,TO,Piemonte,1,10063 +Pont Canavese,1199,Torino,TO,Piemonte,1,10085 +Porte,1200,Torino,TO,Piemonte,1,10060 +Pragelato,1201,Torino,TO,Piemonte,1,10060 +Prali,1202,Torino,TO,Piemonte,1,10060 +Pralormo,1203,Torino,TO,Piemonte,1,10040 +Pramollo,1204,Torino,TO,Piemonte,1,10065 +Prarostino,1205,Torino,TO,Piemonte,1,10060 +Prascorsano,1206,Torino,TO,Piemonte,1,10080 +Pratiglione,1207,Torino,TO,Piemonte,1,10080 +Quagliuzzo,1208,Torino,TO,Piemonte,1,10010 +Quassolo,1209,Torino,TO,Piemonte,1,10010 +Quincinetto,1210,Torino,TO,Piemonte,1,10010 +Reano,1211,Torino,TO,Piemonte,1,10090 +Ribordone,1212,Torino,TO,Piemonte,1,10080 +Rivalba,1213,Torino,TO,Piemonte,1,10090 +Rivalta di Torino,1214,Torino,TO,Piemonte,1,10040 +Riva presso Chieri,1215,Torino,TO,Piemonte,1,10020 +Rivara,1216,Torino,TO,Piemonte,1,10080 +Rivarolo Canavese,1217,Torino,TO,Piemonte,1,10086 +Rivarossa,1218,Torino,TO,Piemonte,1,10040 +Rivoli,1219,Torino,TO,Piemonte,1,10098 +Robassomero,1220,Torino,TO,Piemonte,1,10070 +Rocca Canavese,1221,Torino,TO,Piemonte,1,10070 +Roletto,1222,Torino,TO,Piemonte,1,10060 +Romano Canavese,1223,Torino,TO,Piemonte,1,10090 +Ronco Canavese,1224,Torino,TO,Piemonte,1,10080 +Rondissone,1225,Torino,TO,Piemonte,1,10030 +Rorà,1226,Torino,TO,Piemonte,1,10060 +Roure,1227,Torino,TO,Piemonte,1,10060 +Rosta,1228,Torino,TO,Piemonte,1,10090 +Rubiana,1229,Torino,TO,Piemonte,1,10040 +Rueglio,1230,Torino,TO,Piemonte,1,10010 +Salassa,1231,Torino,TO,Piemonte,1,10080 +Salbertrand,1232,Torino,TO,Piemonte,1,10050 +Salerano Canavese,1233,Torino,TO,Piemonte,1,10010 +Salza di Pinerolo,1234,Torino,TO,Piemonte,1,10060 +Samone,1235,Torino,TO,Piemonte,1,10010 +San Benigno Canavese,1236,Torino,TO,Piemonte,1,10080 +San Carlo Canavese,1237,Torino,TO,Piemonte,1,10070 +San Colombano Belmonte,1238,Torino,TO,Piemonte,1,10080 +San Didero,1239,Torino,TO,Piemonte,1,10050 +San Francesco al Campo,1240,Torino,TO,Piemonte,1,10070 +Sangano,1241,Torino,TO,Piemonte,1,10090 +San Germano Chisone,1242,Torino,TO,Piemonte,1,10065 +San Gillio,1243,Torino,TO,Piemonte,1,10040 +San Giorgio Canavese,1244,Torino,TO,Piemonte,1,10090 +San Giorio di Susa,1245,Torino,TO,Piemonte,1,10050 +San Giusto Canavese,1246,Torino,TO,Piemonte,1,10090 +San Martino Canavese,1247,Torino,TO,Piemonte,1,10010 +San Maurizio Canavese,1248,Torino,TO,Piemonte,1,10077 +San Mauro Torinese,1249,Torino,TO,Piemonte,1,10099 +San Pietro Val Lemina,1250,Torino,TO,Piemonte,1,10060 +San Ponso,1251,Torino,TO,Piemonte,1,10080 +San Raffaele Cimena,1252,Torino,TO,Piemonte,1,10090 +San Sebastiano da Po,1253,Torino,TO,Piemonte,1,10020 +San Secondo di Pinerolo,1254,Torino,TO,Piemonte,1,10060 +Sant'Ambrogio di Torino,1255,Torino,TO,Piemonte,1,10057 +Sant'Antonino di Susa,1256,Torino,TO,Piemonte,1,10050 +Santena,1257,Torino,TO,Piemonte,1,10026 +Sauze di Cesana,1258,Torino,TO,Piemonte,1,10054 +Sauze d'Oulx,1259,Torino,TO,Piemonte,1,10050 +Scalenghe,1260,Torino,TO,Piemonte,1,10060 +Scarmagno,1261,Torino,TO,Piemonte,1,10010 +Sciolze,1262,Torino,TO,Piemonte,1,10090 +Sestriere,1263,Torino,TO,Piemonte,1,10058 +Settimo Rottaro,1264,Torino,TO,Piemonte,1,10010 +Settimo Torinese,1265,Torino,TO,Piemonte,1,10036 +Settimo Vittone,1266,Torino,TO,Piemonte,1,10010 +Sparone,1267,Torino,TO,Piemonte,1,10080 +Strambinello,1268,Torino,TO,Piemonte,1,10010 +Strambino,1269,Torino,TO,Piemonte,1,10019 +Susa,1270,Torino,TO,Piemonte,1,10059 +Tavagnasco,1271,Torino,TO,Piemonte,1,10010 +Torino,1272,Torino,TO,Piemonte,1,10138 +Torrazza Piemonte,1273,Torino,TO,Piemonte,1,10037 +Torre Canavese,1274,Torino,TO,Piemonte,1,10010 +Torre Pellice,1275,Torino,TO,Piemonte,1,10066 +Trana,1276,Torino,TO,Piemonte,1,10090 +Traversella,1278,Torino,TO,Piemonte,1,10080 +Traves,1279,Torino,TO,Piemonte,1,10070 +Trofarello,1280,Torino,TO,Piemonte,1,10028 +Usseaux,1281,Torino,TO,Piemonte,1,10060 +Usseglio,1282,Torino,TO,Piemonte,1,10070 +Vaie,1283,Torino,TO,Piemonte,1,10050 +Val della Torre,1284,Torino,TO,Piemonte,1,10040 +Valgioie,1285,Torino,TO,Piemonte,1,10094 +Vallo Torinese,1286,Torino,TO,Piemonte,1,10070 +Valperga,1287,Torino,TO,Piemonte,1,10087 +Valprato Soana,1288,Torino,TO,Piemonte,1,10080 +Varisella,1289,Torino,TO,Piemonte,1,10070 +Vauda Canavese,1290,Torino,TO,Piemonte,1,10070 +Venaus,1291,Torino,TO,Piemonte,1,10050 +Venaria Reale,1292,Torino,TO,Piemonte,1,10078 +Verolengo,1293,Torino,TO,Piemonte,1,10038 +Verrua Savoia,1294,Torino,TO,Piemonte,1,10020 +Vestignè,1295,Torino,TO,Piemonte,1,10030 +Vialfrè,1296,Torino,TO,Piemonte,1,10090 +Vidracco,1298,Torino,TO,Piemonte,1,10080 +Vigone,1299,Torino,TO,Piemonte,1,10067 +Villafranca Piemonte,1300,Torino,TO,Piemonte,1,10068 +Villanova Canavese,1301,Torino,TO,Piemonte,1,10070 +Villarbasse,1302,Torino,TO,Piemonte,1,10090 +Villar Dora,1303,Torino,TO,Piemonte,1,10040 +Villareggia,1304,Torino,TO,Piemonte,1,10030 +Villar Focchiardo,1305,Torino,TO,Piemonte,1,10050 +Villar Pellice,1306,Torino,TO,Piemonte,1,10060 +Villar Perosa,1307,Torino,TO,Piemonte,1,10069 +Villastellone,1308,Torino,TO,Piemonte,1,10029 +Vinovo,1309,Torino,TO,Piemonte,1,10048 +Virle Piemonte,1310,Torino,TO,Piemonte,1,10060 +Vische,1311,Torino,TO,Piemonte,1,10030 +Vistrorio,1312,Torino,TO,Piemonte,1,10080 +Viù,1313,Torino,TO,Piemonte,1,10070 +Volpiano,1314,Torino,TO,Piemonte,1,10088 +Volvera,1315,Torino,TO,Piemonte,1,10040 +Mappano,1316,Torino,TO,Piemonte,1,10072 +Val di Chy,1317,Torino,TO,Piemonte,1,10010 +Valchiusa,1318,Torino,TO,Piemonte,1,10080 +Alagna Valsesia,2002,Vercelli,VC,Piemonte,1,13021 +Albano Vercellese,2003,Vercelli,VC,Piemonte,1,13030 +Alice Castello,2004,Vercelli,VC,Piemonte,1,13040 +Arborio,2006,Vercelli,VC,Piemonte,1,13031 +Asigliano Vercellese,2007,Vercelli,VC,Piemonte,1,13032 +Balmuccia,2008,Vercelli,VC,Piemonte,1,13020 +Balocco,2009,Vercelli,VC,Piemonte,1,13040 +Bianzè,2011,Vercelli,VC,Piemonte,1,13041 +Boccioleto,2014,Vercelli,VC,Piemonte,1,13022 +Borgo d'Ale,2015,Vercelli,VC,Piemonte,1,13040 +Borgosesia,2016,Vercelli,VC,Piemonte,1,13011 +Borgo Vercelli,2017,Vercelli,VC,Piemonte,1,13012 +Buronzo,2021,Vercelli,VC,Piemonte,1,13040 +Campertogno,2025,Vercelli,VC,Piemonte,1,13023 +Carcoforo,2029,Vercelli,VC,Piemonte,1,13026 +Caresana,2030,Vercelli,VC,Piemonte,1,13010 +Caresanablot,2031,Vercelli,VC,Piemonte,1,13030 +Carisio,2032,Vercelli,VC,Piemonte,1,13040 +Casanova Elvo,2033,Vercelli,VC,Piemonte,1,13030 +San Giacomo Vercellese,2035,Vercelli,VC,Piemonte,1,13030 +Cervatto,2041,Vercelli,VC,Piemonte,1,13025 +Cigliano,2042,Vercelli,VC,Piemonte,1,13043 +Civiasco,2043,Vercelli,VC,Piemonte,1,13010 +Collobiano,2045,Vercelli,VC,Piemonte,1,13030 +Costanzana,2047,Vercelli,VC,Piemonte,1,13033 +Cravagliana,2048,Vercelli,VC,Piemonte,1,13020 +Crescentino,2049,Vercelli,VC,Piemonte,1,13044 +Crova,2052,Vercelli,VC,Piemonte,1,13040 +Desana,2054,Vercelli,VC,Piemonte,1,13034 +Fobello,2057,Vercelli,VC,Piemonte,1,13025 +Fontanetto Po,2058,Vercelli,VC,Piemonte,1,13040 +Formigliana,2059,Vercelli,VC,Piemonte,1,13030 +Gattinara,2061,Vercelli,VC,Piemonte,1,13045 +Ghislarengo,2062,Vercelli,VC,Piemonte,1,13030 +Greggio,2065,Vercelli,VC,Piemonte,1,13030 +Guardabosone,2066,Vercelli,VC,Piemonte,1,13010 +Lamporo,2067,Vercelli,VC,Piemonte,1,13046 +Lenta,2068,Vercelli,VC,Piemonte,1,13035 +Lignana,2070,Vercelli,VC,Piemonte,1,13034 +Livorno Ferraris,2071,Vercelli,VC,Piemonte,1,13046 +Lozzolo,2072,Vercelli,VC,Piemonte,1,13045 +Mollia,2078,Vercelli,VC,Piemonte,1,13020 +Moncrivello,2079,Vercelli,VC,Piemonte,1,13040 +Motta de' Conti,2082,Vercelli,VC,Piemonte,1,13010 +Olcenengo,2088,Vercelli,VC,Piemonte,1,13047 +Oldenico,2089,Vercelli,VC,Piemonte,1,13030 +Palazzolo Vercellese,2090,Vercelli,VC,Piemonte,1,13040 +Pertengo,2091,Vercelli,VC,Piemonte,1,13030 +Pezzana,2093,Vercelli,VC,Piemonte,1,13010 +Pila,2096,Vercelli,VC,Piemonte,1,13020 +Piode,2097,Vercelli,VC,Piemonte,1,13020 +Postua,2102,Vercelli,VC,Piemonte,1,13010 +Prarolo,2104,Vercelli,VC,Piemonte,1,13012 +Quarona,2107,Vercelli,VC,Piemonte,1,13017 +Quinto Vercellese,2108,Vercelli,VC,Piemonte,1,13030 +Rassa,2110,Vercelli,VC,Piemonte,1,13020 +Rimella,2113,Vercelli,VC,Piemonte,1,13020 +Rive,2115,Vercelli,VC,Piemonte,1,13030 +Roasio,2116,Vercelli,VC,Piemonte,1,13060 +Ronsecco,2118,Vercelli,VC,Piemonte,1,13036 +Rossa,2121,Vercelli,VC,Piemonte,1,13020 +Rovasenda,2122,Vercelli,VC,Piemonte,1,13040 +Salasco,2126,Vercelli,VC,Piemonte,1,13040 +Sali Vercellese,2127,Vercelli,VC,Piemonte,1,13040 +Saluggia,2128,Vercelli,VC,Piemonte,1,13040 +San Germano Vercellese,2131,Vercelli,VC,Piemonte,1,13047 +Santhià,2133,Vercelli,VC,Piemonte,1,13048 +Scopa,2134,Vercelli,VC,Piemonte,1,13027 +Scopello,2135,Vercelli,VC,Piemonte,1,13028 +Serravalle Sesia,2137,Vercelli,VC,Piemonte,1,13037 +Stroppiana,2142,Vercelli,VC,Piemonte,1,13010 +Tricerro,2147,Vercelli,VC,Piemonte,1,13038 +Trino,2148,Vercelli,VC,Piemonte,1,13039 +Tronzano Vercellese,2150,Vercelli,VC,Piemonte,1,13049 +Valduggia,2152,Vercelli,VC,Piemonte,1,13018 +Varallo,2156,Vercelli,VC,Piemonte,1,13019 +Vercelli,2158,Vercelli,VC,Piemonte,1,13100 +Villarboit,2163,Vercelli,VC,Piemonte,1,13030 +Villata,2164,Vercelli,VC,Piemonte,1,13010 +Vocca,2166,Vercelli,VC,Piemonte,1,13020 +Alto Sermenza,2170,Vercelli,VC,Piemonte,1,13026 +Cellio con Breia,2171,Vercelli,VC,Piemonte,1,13024 +Agrate Conturbia,3001,Novara,NO,Piemonte,1,28010 +Ameno,3002,Novara,NO,Piemonte,1,28010 +Armeno,3006,Novara,NO,Piemonte,1,28011 +Arona,3008,Novara,NO,Piemonte,1,28041 +Barengo,3012,Novara,NO,Piemonte,1,28010 +Bellinzago Novarese,3016,Novara,NO,Piemonte,1,28043 +Biandrate,3018,Novara,NO,Piemonte,1,28061 +Boca,3019,Novara,NO,Piemonte,1,28010 +Bogogno,3021,Novara,NO,Piemonte,1,28010 +Bolzano Novarese,3022,Novara,NO,Piemonte,1,28010 +Borgolavezzaro,3023,Novara,NO,Piemonte,1,28071 +Borgomanero,3024,Novara,NO,Piemonte,1,28021 +Borgo Ticino,3025,Novara,NO,Piemonte,1,28040 +Briga Novarese,3026,Novara,NO,Piemonte,1,28010 +Briona,3027,Novara,NO,Piemonte,1,28072 +Caltignaga,3030,Novara,NO,Piemonte,1,28010 +Cameri,3032,Novara,NO,Piemonte,1,28062 +Carpignano Sesia,3036,Novara,NO,Piemonte,1,28064 +Casalbeltrame,3037,Novara,NO,Piemonte,1,28060 +Casaleggio Novara,3039,Novara,NO,Piemonte,1,28060 +Casalino,3040,Novara,NO,Piemonte,1,28060 +Casalvolone,3041,Novara,NO,Piemonte,1,28060 +Castellazzo Novarese,3042,Novara,NO,Piemonte,1,28060 +Castelletto sopra Ticino,3043,Novara,NO,Piemonte,1,28053 +Cavaglietto,3044,Novara,NO,Piemonte,1,28010 +Cavaglio d'Agogna,3045,Novara,NO,Piemonte,1,28010 +Cavallirio,3047,Novara,NO,Piemonte,1,28010 +Cerano,3049,Novara,NO,Piemonte,1,28065 +Colazza,3051,Novara,NO,Piemonte,1,28010 +Comignago,3052,Novara,NO,Piemonte,1,28060 +Cressa,3055,Novara,NO,Piemonte,1,28012 +Cureggio,3058,Novara,NO,Piemonte,1,28060 +Divignano,3060,Novara,NO,Piemonte,1,28010 +Dormelletto,3062,Novara,NO,Piemonte,1,28040 +Fara Novarese,3065,Novara,NO,Piemonte,1,28073 +Fontaneto d'Agogna,3066,Novara,NO,Piemonte,1,28010 +Galliate,3068,Novara,NO,Piemonte,1,28066 +Garbagna Novarese,3069,Novara,NO,Piemonte,1,28070 +Gargallo,3070,Novara,NO,Piemonte,1,28010 +Ghemme,3073,Novara,NO,Piemonte,1,28074 +Gozzano,3076,Novara,NO,Piemonte,1,28024 +Granozzo con Monticello,3077,Novara,NO,Piemonte,1,28060 +Grignasco,3079,Novara,NO,Piemonte,1,28075 +Invorio,3082,Novara,NO,Piemonte,1,28045 +Landiona,3083,Novara,NO,Piemonte,1,28064 +Lesa,3084,Novara,NO,Piemonte,1,28040 +Maggiora,3088,Novara,NO,Piemonte,1,28014 +Mandello Vitta,3090,Novara,NO,Piemonte,1,28060 +Marano Ticino,3091,Novara,NO,Piemonte,1,28040 +Massino Visconti,3093,Novara,NO,Piemonte,1,28040 +Meina,3095,Novara,NO,Piemonte,1,28046 +Mezzomerico,3097,Novara,NO,Piemonte,1,28040 +Miasino,3098,Novara,NO,Piemonte,1,28010 +Momo,3100,Novara,NO,Piemonte,1,28015 +Nebbiuno,3103,Novara,NO,Piemonte,1,28010 +Nibbiola,3104,Novara,NO,Piemonte,1,28070 +Novara,3106,Novara,NO,Piemonte,1,28100 +Oleggio,3108,Novara,NO,Piemonte,1,28047 +Oleggio Castello,3109,Novara,NO,Piemonte,1,28040 +Orta San Giulio,3112,Novara,NO,Piemonte,1,28016 +Paruzzaro,3114,Novara,NO,Piemonte,1,28040 +Pella,3115,Novara,NO,Piemonte,1,28010 +Pettenasco,3116,Novara,NO,Piemonte,1,28028 +Pisano,3119,Novara,NO,Piemonte,1,28010 +Pogno,3120,Novara,NO,Piemonte,1,28076 +Pombia,3121,Novara,NO,Piemonte,1,28050 +Prato Sesia,3122,Novara,NO,Piemonte,1,28077 +Recetto,3129,Novara,NO,Piemonte,1,28060 +Romagnano Sesia,3130,Novara,NO,Piemonte,1,28078 +Romentino,3131,Novara,NO,Piemonte,1,28068 +San Maurizio d'Opaglio,3133,Novara,NO,Piemonte,1,28017 +San Nazzaro Sesia,3134,Novara,NO,Piemonte,1,28060 +San Pietro Mosezzo,3135,Novara,NO,Piemonte,1,28060 +Sillavengo,3138,Novara,NO,Piemonte,1,28064 +Sizzano,3139,Novara,NO,Piemonte,1,28070 +Soriso,3140,Novara,NO,Piemonte,1,28010 +Sozzago,3141,Novara,NO,Piemonte,1,28060 +Suno,3143,Novara,NO,Piemonte,1,28019 +Terdobbiate,3144,Novara,NO,Piemonte,1,28070 +Tornaco,3146,Novara,NO,Piemonte,1,28070 +Trecate,3149,Novara,NO,Piemonte,1,28069 +Vaprio d'Agogna,3153,Novara,NO,Piemonte,1,28010 +Varallo Pombia,3154,Novara,NO,Piemonte,1,28040 +Vespolate,3158,Novara,NO,Piemonte,1,28079 +Vicolungo,3159,Novara,NO,Piemonte,1,28060 +Vinzaglio,3164,Novara,NO,Piemonte,1,28060 +Gattico-Veruno,3166,Novara,NO,Piemonte,1,28013 +Acceglio,4001,Cuneo,CN,Piemonte,1,12021 +Aisone,4002,Cuneo,CN,Piemonte,1,12010 +Alba,4003,Cuneo,CN,Piemonte,1,12051 +Albaretto della Torre,4004,Cuneo,CN,Piemonte,1,12050 +Alto,4005,Cuneo,CN,Piemonte,1,12070 +Argentera,4006,Cuneo,CN,Piemonte,1,12010 +Arguello,4007,Cuneo,CN,Piemonte,1,12050 +Bagnasco,4008,Cuneo,CN,Piemonte,1,12071 +Bagnolo Piemonte,4009,Cuneo,CN,Piemonte,1,12031 +Baldissero d'Alba,4010,Cuneo,CN,Piemonte,1,12040 +Barbaresco,4011,Cuneo,CN,Piemonte,1,12050 +Barge,4012,Cuneo,CN,Piemonte,1,12032 +Barolo,4013,Cuneo,CN,Piemonte,1,12060 +Bastia Mondovì,4014,Cuneo,CN,Piemonte,1,12060 +Battifollo,4015,Cuneo,CN,Piemonte,1,12070 +Beinette,4016,Cuneo,CN,Piemonte,1,12081 +Bellino,4017,Cuneo,CN,Piemonte,1,12020 +Belvedere Langhe,4018,Cuneo,CN,Piemonte,1,12060 +Bene Vagienna,4019,Cuneo,CN,Piemonte,1,12041 +Benevello,4020,Cuneo,CN,Piemonte,1,12050 +Bergolo,4021,Cuneo,CN,Piemonte,1,12074 +Bernezzo,4022,Cuneo,CN,Piemonte,1,12010 +Bonvicino,4023,Cuneo,CN,Piemonte,1,12060 +Borgomale,4024,Cuneo,CN,Piemonte,1,12050 +Borgo San Dalmazzo,4025,Cuneo,CN,Piemonte,1,12011 +Bosia,4026,Cuneo,CN,Piemonte,1,12050 +Bossolasco,4027,Cuneo,CN,Piemonte,1,12060 +Boves,4028,Cuneo,CN,Piemonte,1,12012 +Bra,4029,Cuneo,CN,Piemonte,1,12042 +Briaglia,4030,Cuneo,CN,Piemonte,1,12080 +Briga Alta,4031,Cuneo,CN,Piemonte,1,18025 +Brondello,4032,Cuneo,CN,Piemonte,1,12030 +Brossasco,4033,Cuneo,CN,Piemonte,1,12020 +Busca,4034,Cuneo,CN,Piemonte,1,12022 +Camerana,4035,Cuneo,CN,Piemonte,1,12072 +Canale,4037,Cuneo,CN,Piemonte,1,12043 +Canosio,4038,Cuneo,CN,Piemonte,1,12020 +Caprauna,4039,Cuneo,CN,Piemonte,1,12070 +Caraglio,4040,Cuneo,CN,Piemonte,1,12023 +Caramagna Piemonte,4041,Cuneo,CN,Piemonte,1,12030 +Cardè,4042,Cuneo,CN,Piemonte,1,12030 +Carrù,4043,Cuneo,CN,Piemonte,1,12061 +Cartignano,4044,Cuneo,CN,Piemonte,1,12020 +Casalgrasso,4045,Cuneo,CN,Piemonte,1,12030 +Castagnito,4046,Cuneo,CN,Piemonte,1,12050 +Casteldelfino,4047,Cuneo,CN,Piemonte,1,12020 +Castelletto Stura,4049,Cuneo,CN,Piemonte,1,12040 +Castelletto Uzzone,4050,Cuneo,CN,Piemonte,1,12070 +Castellinaldo d'Alba,4051,Cuneo,CN,Piemonte,1,12050 +Castellino Tanaro,4052,Cuneo,CN,Piemonte,1,12060 +Castelmagno,4053,Cuneo,CN,Piemonte,1,12020 +Castelnuovo di Ceva,4054,Cuneo,CN,Piemonte,1,12070 +Castiglione Falletto,4055,Cuneo,CN,Piemonte,1,12060 +Castiglione Tinella,4056,Cuneo,CN,Piemonte,1,12053 +Castino,4057,Cuneo,CN,Piemonte,1,12050 +Cavallerleone,4058,Cuneo,CN,Piemonte,1,12030 +Cavallermaggiore,4059,Cuneo,CN,Piemonte,1,12030 +Celle di Macra,4060,Cuneo,CN,Piemonte,1,12020 +Centallo,4061,Cuneo,CN,Piemonte,1,12044 +Ceresole Alba,4062,Cuneo,CN,Piemonte,1,12040 +Cerretto Langhe,4063,Cuneo,CN,Piemonte,1,12050 +Cervasca,4064,Cuneo,CN,Piemonte,1,12010 +Cervere,4065,Cuneo,CN,Piemonte,1,12040 +Ceva,4066,Cuneo,CN,Piemonte,1,12073 +Cherasco,4067,Cuneo,CN,Piemonte,1,12062 +Chiusa di Pesio,4068,Cuneo,CN,Piemonte,1,12013 +Cigliè,4069,Cuneo,CN,Piemonte,1,12060 +Cissone,4070,Cuneo,CN,Piemonte,1,12050 +Clavesana,4071,Cuneo,CN,Piemonte,1,12060 +Corneliano d'Alba,4072,Cuneo,CN,Piemonte,1,12040 +Cortemilia,4073,Cuneo,CN,Piemonte,1,12074 +Cossano Belbo,4074,Cuneo,CN,Piemonte,1,12054 +Costigliole Saluzzo,4075,Cuneo,CN,Piemonte,1,12024 +Cravanzana,4076,Cuneo,CN,Piemonte,1,12050 +Crissolo,4077,Cuneo,CN,Piemonte,1,12030 +Cuneo,4078,Cuneo,CN,Piemonte,1,12100 +Demonte,4079,Cuneo,CN,Piemonte,1,12014 +Diano d'Alba,4080,Cuneo,CN,Piemonte,1,12055 +Dogliani,4081,Cuneo,CN,Piemonte,1,12063 +Dronero,4082,Cuneo,CN,Piemonte,1,12025 +Elva,4083,Cuneo,CN,Piemonte,1,12020 +Entracque,4084,Cuneo,CN,Piemonte,1,12010 +Envie,4085,Cuneo,CN,Piemonte,1,12030 +Farigliano,4086,Cuneo,CN,Piemonte,1,12060 +Faule,4087,Cuneo,CN,Piemonte,1,12030 +Feisoglio,4088,Cuneo,CN,Piemonte,1,12050 +Fossano,4089,Cuneo,CN,Piemonte,1,12045 +Frabosa Soprana,4090,Cuneo,CN,Piemonte,1,12082 +Frabosa Sottana,4091,Cuneo,CN,Piemonte,1,12083 +Frassino,4092,Cuneo,CN,Piemonte,1,12020 +Gaiola,4093,Cuneo,CN,Piemonte,1,12010 +Gambasca,4094,Cuneo,CN,Piemonte,1,12030 +Garessio,4095,Cuneo,CN,Piemonte,1,12075 +Genola,4096,Cuneo,CN,Piemonte,1,12040 +Gorzegno,4097,Cuneo,CN,Piemonte,1,12070 +Gottasecca,4098,Cuneo,CN,Piemonte,1,12070 +Govone,4099,Cuneo,CN,Piemonte,1,12040 +Grinzane Cavour,4100,Cuneo,CN,Piemonte,1,12060 +Guarene,4101,Cuneo,CN,Piemonte,1,12050 +Igliano,4102,Cuneo,CN,Piemonte,1,12060 +Isasca,4103,Cuneo,CN,Piemonte,1,12020 +Lagnasco,4104,Cuneo,CN,Piemonte,1,12030 +La Morra,4105,Cuneo,CN,Piemonte,1,12064 +Lequio Berria,4106,Cuneo,CN,Piemonte,1,12050 +Lequio Tanaro,4107,Cuneo,CN,Piemonte,1,12060 +Lesegno,4108,Cuneo,CN,Piemonte,1,12076 +Levice,4109,Cuneo,CN,Piemonte,1,12070 +Limone Piemonte,4110,Cuneo,CN,Piemonte,1,12015 +Lisio,4111,Cuneo,CN,Piemonte,1,12070 +Macra,4112,Cuneo,CN,Piemonte,1,12020 +Magliano Alfieri,4113,Cuneo,CN,Piemonte,1,12050 +Magliano Alpi,4114,Cuneo,CN,Piemonte,1,12060 +Mango,4115,Cuneo,CN,Piemonte,1,12056 +Manta,4116,Cuneo,CN,Piemonte,1,12030 +Marene,4117,Cuneo,CN,Piemonte,1,12030 +Margarita,4118,Cuneo,CN,Piemonte,1,12040 +Marmora,4119,Cuneo,CN,Piemonte,1,12020 +Marsaglia,4120,Cuneo,CN,Piemonte,1,12060 +Martiniana Po,4121,Cuneo,CN,Piemonte,1,12030 +Melle,4122,Cuneo,CN,Piemonte,1,12020 +Moiola,4123,Cuneo,CN,Piemonte,1,12010 +Mombarcaro,4124,Cuneo,CN,Piemonte,1,12070 +Mombasiglio,4125,Cuneo,CN,Piemonte,1,12070 +Monastero di Vasco,4126,Cuneo,CN,Piemonte,1,12080 +Monasterolo Casotto,4127,Cuneo,CN,Piemonte,1,12080 +Monasterolo di Savigliano,4128,Cuneo,CN,Piemonte,1,12030 +Monchiero,4129,Cuneo,CN,Piemonte,1,12060 +Mondovì,4130,Cuneo,CN,Piemonte,1,12084 +Monesiglio,4131,Cuneo,CN,Piemonte,1,12077 +Monforte d'Alba,4132,Cuneo,CN,Piemonte,1,12065 +Montà,4133,Cuneo,CN,Piemonte,1,12046 +Montaldo di Mondovì,4134,Cuneo,CN,Piemonte,1,12080 +Montaldo Roero,4135,Cuneo,CN,Piemonte,1,12040 +Montanera,4136,Cuneo,CN,Piemonte,1,12040 +Montelupo Albese,4137,Cuneo,CN,Piemonte,1,12050 +Montemale di Cuneo,4138,Cuneo,CN,Piemonte,1,12025 +Monterosso Grana,4139,Cuneo,CN,Piemonte,1,12020 +Monteu Roero,4140,Cuneo,CN,Piemonte,1,12040 +Montezemolo,4141,Cuneo,CN,Piemonte,1,12070 +Monticello d'Alba,4142,Cuneo,CN,Piemonte,1,12066 +Moretta,4143,Cuneo,CN,Piemonte,1,12033 +Morozzo,4144,Cuneo,CN,Piemonte,1,12040 +Murazzano,4145,Cuneo,CN,Piemonte,1,12060 +Murello,4146,Cuneo,CN,Piemonte,1,12030 +Narzole,4147,Cuneo,CN,Piemonte,1,12068 +Neive,4148,Cuneo,CN,Piemonte,1,12052 +Neviglie,4149,Cuneo,CN,Piemonte,1,12050 +Niella Belbo,4150,Cuneo,CN,Piemonte,1,12050 +Niella Tanaro,4151,Cuneo,CN,Piemonte,1,12060 +Novello,4152,Cuneo,CN,Piemonte,1,12060 +Nucetto,4153,Cuneo,CN,Piemonte,1,12070 +Oncino,4154,Cuneo,CN,Piemonte,1,12030 +Ormea,4155,Cuneo,CN,Piemonte,1,12078 +Ostana,4156,Cuneo,CN,Piemonte,1,12030 +Paesana,4157,Cuneo,CN,Piemonte,1,12034 +Pagno,4158,Cuneo,CN,Piemonte,1,12030 +Pamparato,4159,Cuneo,CN,Piemonte,1,12087 +Paroldo,4160,Cuneo,CN,Piemonte,1,12070 +Perletto,4161,Cuneo,CN,Piemonte,1,12070 +Perlo,4162,Cuneo,CN,Piemonte,1,12070 +Peveragno,4163,Cuneo,CN,Piemonte,1,12016 +Pezzolo Valle Uzzone,4164,Cuneo,CN,Piemonte,1,12070 +Pianfei,4165,Cuneo,CN,Piemonte,1,12080 +Piasco,4166,Cuneo,CN,Piemonte,1,12026 +Pietraporzio,4167,Cuneo,CN,Piemonte,1,12010 +Piobesi d'Alba,4168,Cuneo,CN,Piemonte,1,12040 +Piozzo,4169,Cuneo,CN,Piemonte,1,12060 +Pocapaglia,4170,Cuneo,CN,Piemonte,1,12060 +Polonghera,4171,Cuneo,CN,Piemonte,1,12030 +Pontechianale,4172,Cuneo,CN,Piemonte,1,12020 +Pradleves,4173,Cuneo,CN,Piemonte,1,12027 +Prazzo,4174,Cuneo,CN,Piemonte,1,12028 +Priero,4175,Cuneo,CN,Piemonte,1,12070 +Priocca,4176,Cuneo,CN,Piemonte,1,12040 +Priola,4177,Cuneo,CN,Piemonte,1,12070 +Prunetto,4178,Cuneo,CN,Piemonte,1,12077 +Racconigi,4179,Cuneo,CN,Piemonte,1,12035 +Revello,4180,Cuneo,CN,Piemonte,1,12036 +Rifreddo,4181,Cuneo,CN,Piemonte,1,12030 +Rittana,4182,Cuneo,CN,Piemonte,1,12010 +Roaschia,4183,Cuneo,CN,Piemonte,1,12010 +Roascio,4184,Cuneo,CN,Piemonte,1,12073 +Robilante,4185,Cuneo,CN,Piemonte,1,12017 +Roburent,4186,Cuneo,CN,Piemonte,1,12080 +Roccabruna,4187,Cuneo,CN,Piemonte,1,12020 +Rocca Cigliè,4188,Cuneo,CN,Piemonte,1,12060 +Rocca de' Baldi,4189,Cuneo,CN,Piemonte,1,12047 +Roccaforte Mondovì,4190,Cuneo,CN,Piemonte,1,12088 +Roccasparvera,4191,Cuneo,CN,Piemonte,1,12010 +Roccavione,4192,Cuneo,CN,Piemonte,1,12018 +Rocchetta Belbo,4193,Cuneo,CN,Piemonte,1,12050 +Roddi,4194,Cuneo,CN,Piemonte,1,12060 +Roddino,4195,Cuneo,CN,Piemonte,1,12050 +Rodello,4196,Cuneo,CN,Piemonte,1,12050 +Rossana,4197,Cuneo,CN,Piemonte,1,12020 +Ruffia,4198,Cuneo,CN,Piemonte,1,12030 +Sale delle Langhe,4199,Cuneo,CN,Piemonte,1,12070 +Sale San Giovanni,4200,Cuneo,CN,Piemonte,1,12070 +Saliceto,4201,Cuneo,CN,Piemonte,1,12079 +Salmour,4202,Cuneo,CN,Piemonte,1,12040 +Saluzzo,4203,Cuneo,CN,Piemonte,1,12037 +Sambuco,4204,Cuneo,CN,Piemonte,1,12010 +Sampeyre,4205,Cuneo,CN,Piemonte,1,12020 +San Benedetto Belbo,4206,Cuneo,CN,Piemonte,1,12050 +San Damiano Macra,4207,Cuneo,CN,Piemonte,1,12029 +Sanfrè,4208,Cuneo,CN,Piemonte,1,12040 +Sanfront,4209,Cuneo,CN,Piemonte,1,12030 +San Michele Mondovì,4210,Cuneo,CN,Piemonte,1,12080 +Sant'Albano Stura,4211,Cuneo,CN,Piemonte,1,12040 +Santa Vittoria d'Alba,4212,Cuneo,CN,Piemonte,1,12069 +Santo Stefano Belbo,4213,Cuneo,CN,Piemonte,1,12058 +Santo Stefano Roero,4214,Cuneo,CN,Piemonte,1,12040 +Savigliano,4215,Cuneo,CN,Piemonte,1,12038 +Scagnello,4216,Cuneo,CN,Piemonte,1,12070 +Scarnafigi,4217,Cuneo,CN,Piemonte,1,12030 +Serralunga d'Alba,4218,Cuneo,CN,Piemonte,1,12050 +Serravalle Langhe,4219,Cuneo,CN,Piemonte,1,12050 +Sinio,4220,Cuneo,CN,Piemonte,1,12050 +Somano,4221,Cuneo,CN,Piemonte,1,12060 +Sommariva del Bosco,4222,Cuneo,CN,Piemonte,1,12048 +Sommariva Perno,4223,Cuneo,CN,Piemonte,1,12040 +Stroppo,4224,Cuneo,CN,Piemonte,1,12020 +Tarantasca,4225,Cuneo,CN,Piemonte,1,12020 +Torre Bormida,4226,Cuneo,CN,Piemonte,1,12050 +Torre Mondovì,4227,Cuneo,CN,Piemonte,1,12080 +Torre San Giorgio,4228,Cuneo,CN,Piemonte,1,12030 +Torresina,4229,Cuneo,CN,Piemonte,1,12070 +Treiso,4230,Cuneo,CN,Piemonte,1,12050 +Trezzo Tinella,4231,Cuneo,CN,Piemonte,1,12050 +Trinità,4232,Cuneo,CN,Piemonte,1,12049 +Valdieri,4233,Cuneo,CN,Piemonte,1,12010 +Valgrana,4234,Cuneo,CN,Piemonte,1,12020 +Valloriate,4235,Cuneo,CN,Piemonte,1,12010 +Venasca,4237,Cuneo,CN,Piemonte,1,12020 +Verduno,4238,Cuneo,CN,Piemonte,1,12060 +Vernante,4239,Cuneo,CN,Piemonte,1,12019 +Verzuolo,4240,Cuneo,CN,Piemonte,1,12039 +Vezza d'Alba,4241,Cuneo,CN,Piemonte,1,12040 +Vicoforte,4242,Cuneo,CN,Piemonte,1,12080 +Vignolo,4243,Cuneo,CN,Piemonte,1,12010 +Villafalletto,4244,Cuneo,CN,Piemonte,1,12020 +Villanova Mondovì,4245,Cuneo,CN,Piemonte,1,12089 +Villanova Solaro,4246,Cuneo,CN,Piemonte,1,12030 +Villar San Costanzo,4247,Cuneo,CN,Piemonte,1,12020 +Vinadio,4248,Cuneo,CN,Piemonte,1,12010 +Viola,4249,Cuneo,CN,Piemonte,1,12070 +Vottignasco,4250,Cuneo,CN,Piemonte,1,12020 +Agliano Terme,5001,Asti,AT,Piemonte,1,14041 +Albugnano,5002,Asti,AT,Piemonte,1,14022 +Antignano,5003,Asti,AT,Piemonte,1,14010 +Aramengo,5004,Asti,AT,Piemonte,1,14020 +Asti,5005,Asti,AT,Piemonte,1,14100 +Azzano d'Asti,5006,Asti,AT,Piemonte,1,14030 +Baldichieri d'Asti,5007,Asti,AT,Piemonte,1,14011 +Belveglio,5008,Asti,AT,Piemonte,1,14040 +Berzano di San Pietro,5009,Asti,AT,Piemonte,1,14020 +Bruno,5010,Asti,AT,Piemonte,1,14046 +Bubbio,5011,Asti,AT,Piemonte,1,14051 +Buttigliera d'Asti,5012,Asti,AT,Piemonte,1,14021 +Calamandrana,5013,Asti,AT,Piemonte,1,14042 +Calliano,5014,Asti,AT,Piemonte,1,14031 +Calosso,5015,Asti,AT,Piemonte,1,14052 +Camerano Casasco,5016,Asti,AT,Piemonte,1,14020 +Canelli,5017,Asti,AT,Piemonte,1,14053 +Cantarana,5018,Asti,AT,Piemonte,1,14010 +Capriglio,5019,Asti,AT,Piemonte,1,14014 +Casorzo,5020,Asti,AT,Piemonte,1,14032 +Cassinasco,5021,Asti,AT,Piemonte,1,14050 +Castagnole delle Lanze,5022,Asti,AT,Piemonte,1,14054 +Castagnole Monferrato,5023,Asti,AT,Piemonte,1,14030 +Castel Boglione,5024,Asti,AT,Piemonte,1,14040 +Castell'Alfero,5025,Asti,AT,Piemonte,1,14033 +Castellero,5026,Asti,AT,Piemonte,1,14013 +Castelletto Molina,5027,Asti,AT,Piemonte,1,14040 +Castello di Annone,5028,Asti,AT,Piemonte,1,14034 +Castelnuovo Belbo,5029,Asti,AT,Piemonte,1,14043 +Castelnuovo Calcea,5030,Asti,AT,Piemonte,1,14040 +Castelnuovo Don Bosco,5031,Asti,AT,Piemonte,1,14022 +Castel Rocchero,5032,Asti,AT,Piemonte,1,14044 +Cellarengo,5033,Asti,AT,Piemonte,1,14010 +Celle Enomondo,5034,Asti,AT,Piemonte,1,14010 +Cerreto d'Asti,5035,Asti,AT,Piemonte,1,14020 +Cerro Tanaro,5036,Asti,AT,Piemonte,1,14030 +Cessole,5037,Asti,AT,Piemonte,1,14050 +Chiusano d'Asti,5038,Asti,AT,Piemonte,1,14025 +Cinaglio,5039,Asti,AT,Piemonte,1,14020 +Cisterna d'Asti,5040,Asti,AT,Piemonte,1,14010 +Coazzolo,5041,Asti,AT,Piemonte,1,14054 +Cocconato,5042,Asti,AT,Piemonte,1,14023 +Corsione,5044,Asti,AT,Piemonte,1,14020 +Cortandone,5045,Asti,AT,Piemonte,1,14013 +Cortanze,5046,Asti,AT,Piemonte,1,14020 +Cortazzone,5047,Asti,AT,Piemonte,1,14010 +Cortiglione,5048,Asti,AT,Piemonte,1,14040 +Cossombrato,5049,Asti,AT,Piemonte,1,14020 +Costigliole d'Asti,5050,Asti,AT,Piemonte,1,14055 +Cunico,5051,Asti,AT,Piemonte,1,14026 +Dusino San Michele,5052,Asti,AT,Piemonte,1,14010 +Ferrere,5053,Asti,AT,Piemonte,1,14012 +Fontanile,5054,Asti,AT,Piemonte,1,14044 +Frinco,5055,Asti,AT,Piemonte,1,14030 +Grana Monferrato,5056,Asti,AT,Piemonte,1,14031 +Grazzano Badoglio,5057,Asti,AT,Piemonte,1,14035 +Incisa Scapaccino,5058,Asti,AT,Piemonte,1,14045 +Isola d'Asti,5059,Asti,AT,Piemonte,1,14057 +Loazzolo,5060,Asti,AT,Piemonte,1,14051 +Maranzana,5061,Asti,AT,Piemonte,1,14040 +Maretto,5062,Asti,AT,Piemonte,1,14018 +Moasca,5063,Asti,AT,Piemonte,1,14050 +Mombaldone,5064,Asti,AT,Piemonte,1,14050 +Mombaruzzo,5065,Asti,AT,Piemonte,1,14046 +Mombercelli,5066,Asti,AT,Piemonte,1,14047 +Monale,5067,Asti,AT,Piemonte,1,14013 +Monastero Bormida,5068,Asti,AT,Piemonte,1,14058 +Moncalvo,5069,Asti,AT,Piemonte,1,14036 +Moncucco Torinese,5070,Asti,AT,Piemonte,1,14024 +Mongardino,5071,Asti,AT,Piemonte,1,14040 +Montabone,5072,Asti,AT,Piemonte,1,14040 +Montafia,5073,Asti,AT,Piemonte,1,14014 +Montaldo Scarampi,5074,Asti,AT,Piemonte,1,14048 +Montechiaro d'Asti,5075,Asti,AT,Piemonte,1,14025 +Montegrosso d'Asti,5076,Asti,AT,Piemonte,1,14048 +Montemagno,5077,Asti,AT,Piemonte,1,14030 +Moransengo,5079,Asti,AT,Piemonte,1,14023 +Nizza Monferrato,5080,Asti,AT,Piemonte,1,14049 +Olmo Gentile,5081,Asti,AT,Piemonte,1,14050 +Passerano Marmorito,5082,Asti,AT,Piemonte,1,14020 +Penango,5083,Asti,AT,Piemonte,1,14030 +Piea,5084,Asti,AT,Piemonte,1,14020 +Pino d'Asti,5085,Asti,AT,Piemonte,1,14020 +Piovà Massaia,5086,Asti,AT,Piemonte,1,14026 +Portacomaro,5087,Asti,AT,Piemonte,1,14037 +Quaranti,5088,Asti,AT,Piemonte,1,14040 +Refrancore,5089,Asti,AT,Piemonte,1,14030 +Revigliasco d'Asti,5090,Asti,AT,Piemonte,1,14010 +Roatto,5091,Asti,AT,Piemonte,1,14018 +Robella,5092,Asti,AT,Piemonte,1,14020 +Rocca d'Arazzo,5093,Asti,AT,Piemonte,1,14030 +Roccaverano,5094,Asti,AT,Piemonte,1,14050 +Rocchetta Palafea,5095,Asti,AT,Piemonte,1,14042 +Rocchetta Tanaro,5096,Asti,AT,Piemonte,1,14030 +San Damiano d'Asti,5097,Asti,AT,Piemonte,1,14015 +San Giorgio Scarampi,5098,Asti,AT,Piemonte,1,14059 +San Martino Alfieri,5099,Asti,AT,Piemonte,1,14010 +San Marzano Oliveto,5100,Asti,AT,Piemonte,1,14050 +San Paolo Solbrito,5101,Asti,AT,Piemonte,1,14010 +Scurzolengo,5103,Asti,AT,Piemonte,1,14030 +Serole,5104,Asti,AT,Piemonte,1,14050 +Sessame,5105,Asti,AT,Piemonte,1,14058 +Settime,5106,Asti,AT,Piemonte,1,14020 +Soglio,5107,Asti,AT,Piemonte,1,14020 +Tigliole,5108,Asti,AT,Piemonte,1,14016 +Tonco,5109,Asti,AT,Piemonte,1,14039 +Tonengo,5110,Asti,AT,Piemonte,1,14023 +Vaglio Serra,5111,Asti,AT,Piemonte,1,14049 +Valfenera,5112,Asti,AT,Piemonte,1,14017 +Vesime,5113,Asti,AT,Piemonte,1,14059 +Viale,5114,Asti,AT,Piemonte,1,14010 +Viarigi,5115,Asti,AT,Piemonte,1,14030 +Vigliano d'Asti,5116,Asti,AT,Piemonte,1,14040 +Villafranca d'Asti,5117,Asti,AT,Piemonte,1,14018 +Villanova d'Asti,5118,Asti,AT,Piemonte,1,14019 +Villa San Secondo,5119,Asti,AT,Piemonte,1,14020 +Vinchio,5120,Asti,AT,Piemonte,1,14040 +Montiglio Monferrato,5121,Asti,AT,Piemonte,1,14026 +Acqui Terme,6001,Alessandria,AL,Piemonte,1,15011 +Albera Ligure,6002,Alessandria,AL,Piemonte,1,15060 +Alessandria,6003,Alessandria,AL,Piemonte,1,15121 +Alfiano Natta,6004,Alessandria,AL,Piemonte,1,15021 +Alice Bel Colle,6005,Alessandria,AL,Piemonte,1,15010 +Altavilla Monferrato,6007,Alessandria,AL,Piemonte,1,15041 +Alzano Scrivia,6008,Alessandria,AL,Piemonte,1,15050 +Arquata Scrivia,6009,Alessandria,AL,Piemonte,1,15061 +Avolasca,6010,Alessandria,AL,Piemonte,1,15050 +Balzola,6011,Alessandria,AL,Piemonte,1,15031 +Basaluzzo,6012,Alessandria,AL,Piemonte,1,15060 +Bassignana,6013,Alessandria,AL,Piemonte,1,15042 +Belforte Monferrato,6014,Alessandria,AL,Piemonte,1,15070 +Bergamasco,6015,Alessandria,AL,Piemonte,1,15022 +Berzano di Tortona,6016,Alessandria,AL,Piemonte,1,15050 +Bistagno,6017,Alessandria,AL,Piemonte,1,15012 +Borghetto di Borbera,6018,Alessandria,AL,Piemonte,1,15060 +Borgoratto Alessandrino,6019,Alessandria,AL,Piemonte,1,15013 +Borgo San Martino,6020,Alessandria,AL,Piemonte,1,15032 +Bosco Marengo,6021,Alessandria,AL,Piemonte,1,15062 +Bosio,6022,Alessandria,AL,Piemonte,1,15060 +Bozzole,6023,Alessandria,AL,Piemonte,1,15040 +Brignano-Frascata,6024,Alessandria,AL,Piemonte,1,15050 +Cabella Ligure,6025,Alessandria,AL,Piemonte,1,15060 +Camagna Monferrato,6026,Alessandria,AL,Piemonte,1,15030 +Camino,6027,Alessandria,AL,Piemonte,1,15020 +Cantalupo Ligure,6028,Alessandria,AL,Piemonte,1,15060 +Capriata d'Orba,6029,Alessandria,AL,Piemonte,1,15060 +Carbonara Scrivia,6030,Alessandria,AL,Piemonte,1,15050 +Carentino,6031,Alessandria,AL,Piemonte,1,15026 +Carezzano,6032,Alessandria,AL,Piemonte,1,15051 +Carpeneto,6033,Alessandria,AL,Piemonte,1,15071 +Carrega Ligure,6034,Alessandria,AL,Piemonte,1,15060 +Carrosio,6035,Alessandria,AL,Piemonte,1,15060 +Cartosio,6036,Alessandria,AL,Piemonte,1,15015 +Casal Cermelli,6037,Alessandria,AL,Piemonte,1,15072 +Casaleggio Boiro,6038,Alessandria,AL,Piemonte,1,15070 +Casale Monferrato,6039,Alessandria,AL,Piemonte,1,15033 +Casalnoceto,6040,Alessandria,AL,Piemonte,1,15052 +Casasco,6041,Alessandria,AL,Piemonte,1,15050 +Cassine,6043,Alessandria,AL,Piemonte,1,15016 +Cassinelle,6044,Alessandria,AL,Piemonte,1,15070 +Castellania Coppi,6045,Alessandria,AL,Piemonte,1,15051 +Castellar Guidobono,6046,Alessandria,AL,Piemonte,1,15050 +Castellazzo Bormida,6047,Alessandria,AL,Piemonte,1,15073 +Castelletto d'Erro,6048,Alessandria,AL,Piemonte,1,15010 +Castelletto d'Orba,6049,Alessandria,AL,Piemonte,1,15060 +Castelletto Merli,6050,Alessandria,AL,Piemonte,1,15020 +Castelletto Monferrato,6051,Alessandria,AL,Piemonte,1,15040 +Castelnuovo Bormida,6052,Alessandria,AL,Piemonte,1,15017 +Castelnuovo Scrivia,6053,Alessandria,AL,Piemonte,1,15053 +Castelspina,6054,Alessandria,AL,Piemonte,1,15070 +Cavatore,6055,Alessandria,AL,Piemonte,1,15010 +Cella Monte,6056,Alessandria,AL,Piemonte,1,15034 +Cereseto,6057,Alessandria,AL,Piemonte,1,15020 +Cerreto Grue,6058,Alessandria,AL,Piemonte,1,15050 +Cerrina Monferrato,6059,Alessandria,AL,Piemonte,1,15020 +Coniolo,6060,Alessandria,AL,Piemonte,1,15030 +Conzano,6061,Alessandria,AL,Piemonte,1,15030 +Costa Vescovato,6062,Alessandria,AL,Piemonte,1,15050 +Cremolino,6063,Alessandria,AL,Piemonte,1,15010 +Denice,6065,Alessandria,AL,Piemonte,1,15010 +Dernice,6066,Alessandria,AL,Piemonte,1,15056 +Fabbrica Curone,6067,Alessandria,AL,Piemonte,1,15054 +Felizzano,6068,Alessandria,AL,Piemonte,1,15023 +Fraconalto,6069,Alessandria,AL,Piemonte,1,15060 +Francavilla Bisio,6070,Alessandria,AL,Piemonte,1,15060 +Frascaro,6071,Alessandria,AL,Piemonte,1,15010 +Frassinello Monferrato,6072,Alessandria,AL,Piemonte,1,15035 +Frassineto Po,6073,Alessandria,AL,Piemonte,1,15040 +Fresonara,6074,Alessandria,AL,Piemonte,1,15064 +Frugarolo,6075,Alessandria,AL,Piemonte,1,15065 +Fubine Monferrato,6076,Alessandria,AL,Piemonte,1,15043 +Gabiano,6077,Alessandria,AL,Piemonte,1,15020 +Gamalero,6078,Alessandria,AL,Piemonte,1,15010 +Garbagna,6079,Alessandria,AL,Piemonte,1,15050 +Gavi,6081,Alessandria,AL,Piemonte,1,15066 +Giarole,6082,Alessandria,AL,Piemonte,1,15036 +Gremiasco,6083,Alessandria,AL,Piemonte,1,15056 +Grognardo,6084,Alessandria,AL,Piemonte,1,15010 +Grondona,6085,Alessandria,AL,Piemonte,1,15060 +Guazzora,6086,Alessandria,AL,Piemonte,1,15050 +Isola Sant'Antonio,6087,Alessandria,AL,Piemonte,1,15050 +Lerma,6088,Alessandria,AL,Piemonte,1,15070 +Malvicino,6090,Alessandria,AL,Piemonte,1,15015 +Masio,6091,Alessandria,AL,Piemonte,1,15024 +Melazzo,6092,Alessandria,AL,Piemonte,1,15010 +Merana,6093,Alessandria,AL,Piemonte,1,15010 +Mirabello Monferrato,6094,Alessandria,AL,Piemonte,1,15040 +Molare,6095,Alessandria,AL,Piemonte,1,15074 +Molino dei Torti,6096,Alessandria,AL,Piemonte,1,15050 +Mombello Monferrato,6097,Alessandria,AL,Piemonte,1,15020 +Momperone,6098,Alessandria,AL,Piemonte,1,15050 +Moncestino,6099,Alessandria,AL,Piemonte,1,15020 +Mongiardino Ligure,6100,Alessandria,AL,Piemonte,1,15060 +Monleale,6101,Alessandria,AL,Piemonte,1,15059 +Montacuto,6102,Alessandria,AL,Piemonte,1,15050 +Montaldeo,6103,Alessandria,AL,Piemonte,1,15060 +Montaldo Bormida,6104,Alessandria,AL,Piemonte,1,15010 +Montecastello,6105,Alessandria,AL,Piemonte,1,15040 +Montechiaro d'Acqui,6106,Alessandria,AL,Piemonte,1,15010 +Montegioco,6107,Alessandria,AL,Piemonte,1,15050 +Montemarzino,6108,Alessandria,AL,Piemonte,1,15050 +Morano sul Po,6109,Alessandria,AL,Piemonte,1,15025 +Morbello,6110,Alessandria,AL,Piemonte,1,15010 +Mornese,6111,Alessandria,AL,Piemonte,1,15075 +Morsasco,6112,Alessandria,AL,Piemonte,1,15010 +Murisengo,6113,Alessandria,AL,Piemonte,1,15020 +Novi Ligure,6114,Alessandria,AL,Piemonte,1,15067 +Occimiano,6115,Alessandria,AL,Piemonte,1,15040 +Odalengo Grande,6116,Alessandria,AL,Piemonte,1,15020 +Odalengo Piccolo,6117,Alessandria,AL,Piemonte,1,15020 +Olivola,6118,Alessandria,AL,Piemonte,1,15030 +Orsara Bormida,6119,Alessandria,AL,Piemonte,1,15010 +Ottiglio,6120,Alessandria,AL,Piemonte,1,15038 +Ovada,6121,Alessandria,AL,Piemonte,1,15076 +Oviglio,6122,Alessandria,AL,Piemonte,1,15026 +Ozzano Monferrato,6123,Alessandria,AL,Piemonte,1,15039 +Paderna,6124,Alessandria,AL,Piemonte,1,15050 +Pareto,6125,Alessandria,AL,Piemonte,1,15010 +Parodi Ligure,6126,Alessandria,AL,Piemonte,1,15060 +Pasturana,6127,Alessandria,AL,Piemonte,1,15060 +Pecetto di Valenza,6128,Alessandria,AL,Piemonte,1,15040 +Pietra Marazzi,6129,Alessandria,AL,Piemonte,1,15040 +Pomaro Monferrato,6131,Alessandria,AL,Piemonte,1,15040 +Pontecurone,6132,Alessandria,AL,Piemonte,1,15055 +Pontestura,6133,Alessandria,AL,Piemonte,1,15027 +Ponti,6134,Alessandria,AL,Piemonte,1,15010 +Ponzano Monferrato,6135,Alessandria,AL,Piemonte,1,15020 +Ponzone,6136,Alessandria,AL,Piemonte,1,15010 +Pozzol Groppo,6137,Alessandria,AL,Piemonte,1,15050 +Pozzolo Formigaro,6138,Alessandria,AL,Piemonte,1,15068 +Prasco,6139,Alessandria,AL,Piemonte,1,15010 +Predosa,6140,Alessandria,AL,Piemonte,1,15077 +Quargnento,6141,Alessandria,AL,Piemonte,1,15044 +Quattordio,6142,Alessandria,AL,Piemonte,1,15028 +Ricaldone,6143,Alessandria,AL,Piemonte,1,15010 +Rivalta Bormida,6144,Alessandria,AL,Piemonte,1,15010 +Rivarone,6145,Alessandria,AL,Piemonte,1,15040 +Roccaforte Ligure,6146,Alessandria,AL,Piemonte,1,15060 +Rocca Grimalda,6147,Alessandria,AL,Piemonte,1,15078 +Rocchetta Ligure,6148,Alessandria,AL,Piemonte,1,15060 +Rosignano Monferrato,6149,Alessandria,AL,Piemonte,1,15030 +Sala Monferrato,6150,Alessandria,AL,Piemonte,1,15030 +Sale,6151,Alessandria,AL,Piemonte,1,15045 +San Cristoforo,6152,Alessandria,AL,Piemonte,1,15060 +San Giorgio Monferrato,6153,Alessandria,AL,Piemonte,1,15020 +San Salvatore Monferrato,6154,Alessandria,AL,Piemonte,1,15046 +San Sebastiano Curone,6155,Alessandria,AL,Piemonte,1,15056 +Sant'Agata Fossili,6156,Alessandria,AL,Piemonte,1,15050 +Sardigliano,6157,Alessandria,AL,Piemonte,1,15060 +Sarezzano,6158,Alessandria,AL,Piemonte,1,15050 +Serralunga di Crea,6159,Alessandria,AL,Piemonte,1,15020 +Serravalle Scrivia,6160,Alessandria,AL,Piemonte,1,15069 +Sezzadio,6161,Alessandria,AL,Piemonte,1,15079 +Silvano d'Orba,6162,Alessandria,AL,Piemonte,1,15060 +Solero,6163,Alessandria,AL,Piemonte,1,15029 +Solonghello,6164,Alessandria,AL,Piemonte,1,15020 +Spigno Monferrato,6165,Alessandria,AL,Piemonte,1,15018 +Spineto Scrivia,6166,Alessandria,AL,Piemonte,1,15050 +Stazzano,6167,Alessandria,AL,Piemonte,1,15060 +Strevi,6168,Alessandria,AL,Piemonte,1,15019 +Tagliolo Monferrato,6169,Alessandria,AL,Piemonte,1,15070 +Tassarolo,6170,Alessandria,AL,Piemonte,1,15060 +Terruggia,6171,Alessandria,AL,Piemonte,1,15030 +Terzo,6172,Alessandria,AL,Piemonte,1,15010 +Ticineto,6173,Alessandria,AL,Piemonte,1,15040 +Tortona,6174,Alessandria,AL,Piemonte,1,15057 +Treville,6175,Alessandria,AL,Piemonte,1,15030 +Trisobbio,6176,Alessandria,AL,Piemonte,1,15070 +Valenza,6177,Alessandria,AL,Piemonte,1,15048 +Valmacca,6178,Alessandria,AL,Piemonte,1,15040 +Vignale Monferrato,6179,Alessandria,AL,Piemonte,1,15049 +Vignole Borbera,6180,Alessandria,AL,Piemonte,1,15060 +Viguzzolo,6181,Alessandria,AL,Piemonte,1,15058 +Villadeati,6182,Alessandria,AL,Piemonte,1,15020 +Villalvernia,6183,Alessandria,AL,Piemonte,1,15050 +Villamiroglio,6184,Alessandria,AL,Piemonte,1,15020 +Villanova Monferrato,6185,Alessandria,AL,Piemonte,1,15030 +Villaromagnano,6186,Alessandria,AL,Piemonte,1,15050 +Visone,6187,Alessandria,AL,Piemonte,1,15010 +Volpedo,6188,Alessandria,AL,Piemonte,1,15059 +Volpeglino,6189,Alessandria,AL,Piemonte,1,15050 +Voltaggio,6190,Alessandria,AL,Piemonte,1,15060 +Cassano Spinola,6191,Alessandria,AL,Piemonte,1,15063 +Alluvioni Piovera,6192,Alessandria,AL,Piemonte,1,15047 +Lu e Cuccaro Monferrato,6193,Alessandria,AL,Piemonte,1,15040 +Ailoche,96001,Biella,BI,Piemonte,1,13861 +Andorno Micca,96002,Biella,BI,Piemonte,1,13811 +Benna,96003,Biella,BI,Piemonte,1,13871 +Biella,96004,Biella,BI,Piemonte,1,13900 +Bioglio,96005,Biella,BI,Piemonte,1,13841 +Borriana,96006,Biella,BI,Piemonte,1,13872 +Brusnengo,96007,Biella,BI,Piemonte,1,13862 +Callabiana,96008,Biella,BI,Piemonte,1,13821 +Camandona,96009,Biella,BI,Piemonte,1,13821 +Camburzano,96010,Biella,BI,Piemonte,1,13891 +Candelo,96012,Biella,BI,Piemonte,1,13878 +Caprile,96013,Biella,BI,Piemonte,1,13864 +Casapinta,96014,Biella,BI,Piemonte,1,13866 +Castelletto Cervo,96015,Biella,BI,Piemonte,1,13851 +Cavaglià,96016,Biella,BI,Piemonte,1,13881 +Cerrione,96018,Biella,BI,Piemonte,1,13882 +Coggiola,96019,Biella,BI,Piemonte,1,13863 +Cossato,96020,Biella,BI,Piemonte,1,13836 +Crevacuore,96021,Biella,BI,Piemonte,1,13864 +Curino,96023,Biella,BI,Piemonte,1,13865 +Donato,96024,Biella,BI,Piemonte,1,13893 +Dorzano,96025,Biella,BI,Piemonte,1,13881 +Gaglianico,96026,Biella,BI,Piemonte,1,13894 +Gifflenga,96027,Biella,BI,Piemonte,1,13874 +Graglia,96028,Biella,BI,Piemonte,1,13895 +Magnano,96030,Biella,BI,Piemonte,1,13887 +Massazza,96031,Biella,BI,Piemonte,1,13873 +Masserano,96032,Biella,BI,Piemonte,1,13866 +Mezzana Mortigliengo,96033,Biella,BI,Piemonte,1,13831 +Miagliano,96034,Biella,BI,Piemonte,1,13816 +Mongrando,96035,Biella,BI,Piemonte,1,13888 +Mottalciata,96037,Biella,BI,Piemonte,1,13874 +Muzzano,96038,Biella,BI,Piemonte,1,13895 +Netro,96039,Biella,BI,Piemonte,1,13896 +Occhieppo Inferiore,96040,Biella,BI,Piemonte,1,13897 +Occhieppo Superiore,96041,Biella,BI,Piemonte,1,13898 +Pettinengo,96042,Biella,BI,Piemonte,1,13843 +Piatto,96043,Biella,BI,Piemonte,1,13844 +Piedicavallo,96044,Biella,BI,Piemonte,1,13812 +Pollone,96046,Biella,BI,Piemonte,1,13814 +Ponderano,96047,Biella,BI,Piemonte,1,13875 +Portula,96048,Biella,BI,Piemonte,1,13833 +Pralungo,96049,Biella,BI,Piemonte,1,13899 +Pray,96050,Biella,BI,Piemonte,1,13867 +Ronco Biellese,96053,Biella,BI,Piemonte,1,13845 +Roppolo,96054,Biella,BI,Piemonte,1,13883 +Rosazza,96055,Biella,BI,Piemonte,1,13815 +Sagliano Micca,96056,Biella,BI,Piemonte,1,13816 +Sala Biellese,96057,Biella,BI,Piemonte,1,13884 +Salussola,96058,Biella,BI,Piemonte,1,13885 +Sandigliano,96059,Biella,BI,Piemonte,1,13876 +Sordevolo,96063,Biella,BI,Piemonte,1,13817 +Sostegno,96064,Biella,BI,Piemonte,1,13868 +Strona,96065,Biella,BI,Piemonte,1,13823 +Tavigliano,96066,Biella,BI,Piemonte,1,13811 +Ternengo,96067,Biella,BI,Piemonte,1,13844 +Tollegno,96068,Biella,BI,Piemonte,1,13818 +Torrazzo,96069,Biella,BI,Piemonte,1,13884 +Valdengo,96071,Biella,BI,Piemonte,1,13855 +Vallanzengo,96072,Biella,BI,Piemonte,1,13847 +Valle San Nicolao,96074,Biella,BI,Piemonte,1,13847 +Veglio,96075,Biella,BI,Piemonte,1,13824 +Verrone,96076,Biella,BI,Piemonte,1,13871 +Vigliano Biellese,96077,Biella,BI,Piemonte,1,13856 +Villa del Bosco,96078,Biella,BI,Piemonte,1,13868 +Villanova Biellese,96079,Biella,BI,Piemonte,1,13877 +Viverone,96080,Biella,BI,Piemonte,1,13886 +Zimone,96081,Biella,BI,Piemonte,1,13887 +Zubiena,96082,Biella,BI,Piemonte,1,13888 +Zumaglia,96083,Biella,BI,Piemonte,1,13848 +Lessona,96085,Biella,BI,Piemonte,1,13853 +Campiglia Cervo,96086,Biella,BI,Piemonte,1,13812 +Quaregna Cerreto,96087,Biella,BI,Piemonte,1,13854 +Valdilana,96088,Biella,BI,Piemonte,1,13835 +Antrona Schieranco,103001,Verbano-Cusio-Ossola,VB,Piemonte,1,28841 +Anzola d'Ossola,103002,Verbano-Cusio-Ossola,VB,Piemonte,1,28877 +Arizzano,103003,Verbano-Cusio-Ossola,VB,Piemonte,1,28811 +Arola,103004,Verbano-Cusio-Ossola,VB,Piemonte,1,28899 +Aurano,103005,Verbano-Cusio-Ossola,VB,Piemonte,1,28812 +Baceno,103006,Verbano-Cusio-Ossola,VB,Piemonte,1,28861 +Bannio Anzino,103007,Verbano-Cusio-Ossola,VB,Piemonte,1,28871 +Baveno,103008,Verbano-Cusio-Ossola,VB,Piemonte,1,28831 +Bee,103009,Verbano-Cusio-Ossola,VB,Piemonte,1,28813 +Belgirate,103010,Verbano-Cusio-Ossola,VB,Piemonte,1,28832 +Beura-Cardezza,103011,Verbano-Cusio-Ossola,VB,Piemonte,1,28851 +Bognanco,103012,Verbano-Cusio-Ossola,VB,Piemonte,1,28842 +Brovello-Carpugnino,103013,Verbano-Cusio-Ossola,VB,Piemonte,1,28833 +Calasca-Castiglione,103014,Verbano-Cusio-Ossola,VB,Piemonte,1,28873 +Cambiasca,103015,Verbano-Cusio-Ossola,VB,Piemonte,1,28814 +Cannero Riviera,103016,Verbano-Cusio-Ossola,VB,Piemonte,1,28821 +Cannobio,103017,Verbano-Cusio-Ossola,VB,Piemonte,1,28822 +Caprezzo,103018,Verbano-Cusio-Ossola,VB,Piemonte,1,28815 +Casale Corte Cerro,103019,Verbano-Cusio-Ossola,VB,Piemonte,1,28881 +Ceppo Morelli,103021,Verbano-Cusio-Ossola,VB,Piemonte,1,28875 +Cesara,103022,Verbano-Cusio-Ossola,VB,Piemonte,1,28891 +Cossogno,103023,Verbano-Cusio-Ossola,VB,Piemonte,1,28801 +Craveggia,103024,Verbano-Cusio-Ossola,VB,Piemonte,1,28852 +Crevoladossola,103025,Verbano-Cusio-Ossola,VB,Piemonte,1,28865 +Crodo,103026,Verbano-Cusio-Ossola,VB,Piemonte,1,28862 +Domodossola,103028,Verbano-Cusio-Ossola,VB,Piemonte,1,28845 +Druogno,103029,Verbano-Cusio-Ossola,VB,Piemonte,1,28853 +Formazza,103031,Verbano-Cusio-Ossola,VB,Piemonte,1,28863 +Germagno,103032,Verbano-Cusio-Ossola,VB,Piemonte,1,28887 +Ghiffa,103033,Verbano-Cusio-Ossola,VB,Piemonte,1,28823 +Gignese,103034,Verbano-Cusio-Ossola,VB,Piemonte,1,28836 +Gravellona Toce,103035,Verbano-Cusio-Ossola,VB,Piemonte,1,28883 +Gurro,103036,Verbano-Cusio-Ossola,VB,Piemonte,1,28828 +Intragna,103037,Verbano-Cusio-Ossola,VB,Piemonte,1,28816 +Loreglia,103038,Verbano-Cusio-Ossola,VB,Piemonte,1,28893 +Macugnaga,103039,Verbano-Cusio-Ossola,VB,Piemonte,1,28876 +Madonna del Sasso,103040,Verbano-Cusio-Ossola,VB,Piemonte,1,28894 +Malesco,103041,Verbano-Cusio-Ossola,VB,Piemonte,1,28854 +Masera,103042,Verbano-Cusio-Ossola,VB,Piemonte,1,28855 +Massiola,103043,Verbano-Cusio-Ossola,VB,Piemonte,1,28895 +Mergozzo,103044,Verbano-Cusio-Ossola,VB,Piemonte,1,28802 +Miazzina,103045,Verbano-Cusio-Ossola,VB,Piemonte,1,28817 +Montecrestese,103046,Verbano-Cusio-Ossola,VB,Piemonte,1,28864 +Montescheno,103047,Verbano-Cusio-Ossola,VB,Piemonte,1,28843 +Nonio,103048,Verbano-Cusio-Ossola,VB,Piemonte,1,28891 +Oggebbio,103049,Verbano-Cusio-Ossola,VB,Piemonte,1,28824 +Omegna,103050,Verbano-Cusio-Ossola,VB,Piemonte,1,28887 +Ornavasso,103051,Verbano-Cusio-Ossola,VB,Piemonte,1,28877 +Pallanzeno,103052,Verbano-Cusio-Ossola,VB,Piemonte,1,28884 +Piedimulera,103053,Verbano-Cusio-Ossola,VB,Piemonte,1,28885 +Pieve Vergonte,103054,Verbano-Cusio-Ossola,VB,Piemonte,1,28886 +Premeno,103055,Verbano-Cusio-Ossola,VB,Piemonte,1,28818 +Premia,103056,Verbano-Cusio-Ossola,VB,Piemonte,1,28866 +Premosello-Chiovenda,103057,Verbano-Cusio-Ossola,VB,Piemonte,1,28803 +Quarna Sopra,103058,Verbano-Cusio-Ossola,VB,Piemonte,1,28898 +Quarna Sotto,103059,Verbano-Cusio-Ossola,VB,Piemonte,1,28896 +Re,103060,Verbano-Cusio-Ossola,VB,Piemonte,1,28856 +San Bernardino Verbano,103061,Verbano-Cusio-Ossola,VB,Piemonte,1,28804 +Santa Maria Maggiore,103062,Verbano-Cusio-Ossola,VB,Piemonte,1,28857 +Stresa,103064,Verbano-Cusio-Ossola,VB,Piemonte,1,28838 +Toceno,103065,Verbano-Cusio-Ossola,VB,Piemonte,1,28858 +Trarego Viggiona,103066,Verbano-Cusio-Ossola,VB,Piemonte,1,28826 +Trasquera,103067,Verbano-Cusio-Ossola,VB,Piemonte,1,28868 +Trontano,103068,Verbano-Cusio-Ossola,VB,Piemonte,1,28859 +Valstrona,103069,Verbano-Cusio-Ossola,VB,Piemonte,1,28897 +Vanzone con San Carlo,103070,Verbano-Cusio-Ossola,VB,Piemonte,1,28879 +Varzo,103071,Verbano-Cusio-Ossola,VB,Piemonte,1,28868 +Verbania,103072,Verbano-Cusio-Ossola,VB,Piemonte,1,28922 +Vignone,103074,Verbano-Cusio-Ossola,VB,Piemonte,1,28819 +Villadossola,103075,Verbano-Cusio-Ossola,VB,Piemonte,1,28844 +Villette,103076,Verbano-Cusio-Ossola,VB,Piemonte,1,28856 +Vogogna,103077,Verbano-Cusio-Ossola,VB,Piemonte,1,28805 +Borgomezzavalle,103078,Verbano-Cusio-Ossola,VB,Piemonte,1,28841 +Valle Cannobina,103079,Verbano-Cusio-Ossola,VB,Piemonte,1,28825 +Allein,7001,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Antey-Saint-André,7002,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Aosta,7003,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11100 +Arnad,7004,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Arvier,7005,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11011 +Avise,7006,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Ayas,7007,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Aymavilles,7008,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Bard,7009,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Bionaz,7010,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Brissogne,7011,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Brusson,7012,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11022 +Challand-Saint-Anselme,7013,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Challand-Saint-Victor,7014,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Chambave,7015,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11023 +Chamois,7016,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Champdepraz,7017,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Champorcher,7018,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Charvensod,7019,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Châtillon,7020,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11024 +Cogne,7021,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11012 +Courmayeur,7022,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11013 +Donnas,7023,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Doues,7024,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Emarèse,7025,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Etroubles,7026,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11014 +Fénis,7027,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Fontainemore,7028,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Gaby,7029,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Gignod,7030,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Gressan,7031,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Gressoney-La-Trinité,7032,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Gressoney-Saint-Jean,7033,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11025 +Hône,7034,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Introd,7035,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Issime,7036,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Issogne,7037,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Jovençan,7038,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +La Magdeleine,7039,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +La Salle,7040,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11015 +La Thuile,7041,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11016 +Lillianes,7042,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Montjovet,7043,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Morgex,7044,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11017 +Nus,7045,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Ollomont,7046,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Oyace,7047,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Perloz,7048,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Pollein,7049,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Pontboset,7050,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Pontey,7051,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11024 +Pont-Saint-Martin,7052,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11026 +Pré-Saint-Didier,7053,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Quart,7054,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Rhêmes-Notre-Dame,7055,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Rhêmes-Saint-Georges,7056,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Roisan,7057,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Saint-Christophe,7058,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Saint-Denis,7059,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11023 +Saint-Marcel,7060,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Saint-Nicolas,7061,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Saint-Oyen,7062,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11014 +Saint-Pierre,7063,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Saint-Rhémy-en-Bosses,7064,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Saint-Vincent,7065,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11027 +Sarre,7066,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Torgnon,7067,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Valgrisenche,7068,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Valpelline,7069,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Valsavarenche,7070,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11010 +Valtournenche,7071,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11028 +Verrayes,7072,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11020 +Verrès,7073,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11029 +Villeneuve,7074,Valle d'Aosta/Vallée d'Aoste,AO,Valle d'Aosta/Vallée d'Aoste,2,11018 +Agra,12001,Varese,VA,Lombardia,3,21010 +Albizzate,12002,Varese,VA,Lombardia,3,21041 +Angera,12003,Varese,VA,Lombardia,3,21021 +Arcisate,12004,Varese,VA,Lombardia,3,21051 +Arsago Seprio,12005,Varese,VA,Lombardia,3,21010 +Azzate,12006,Varese,VA,Lombardia,3,21022 +Azzio,12007,Varese,VA,Lombardia,3,21030 +Barasso,12008,Varese,VA,Lombardia,3,21020 +Bardello,12009,Varese,VA,Lombardia,3,21020 +Bedero Valcuvia,12010,Varese,VA,Lombardia,3,21039 +Besano,12011,Varese,VA,Lombardia,3,21050 +Besnate,12012,Varese,VA,Lombardia,3,21010 +Besozzo,12013,Varese,VA,Lombardia,3,21023 +Biandronno,12014,Varese,VA,Lombardia,3,21024 +Bisuschio,12015,Varese,VA,Lombardia,3,21050 +Bodio Lomnago,12016,Varese,VA,Lombardia,3,21020 +Brebbia,12017,Varese,VA,Lombardia,3,21020 +Bregano,12018,Varese,VA,Lombardia,3,21020 +Brenta,12019,Varese,VA,Lombardia,3,21030 +Brezzo di Bedero,12020,Varese,VA,Lombardia,3,21010 +Brinzio,12021,Varese,VA,Lombardia,3,21030 +Brissago-Valtravaglia,12022,Varese,VA,Lombardia,3,21030 +Brunello,12023,Varese,VA,Lombardia,3,21020 +Brusimpiano,12024,Varese,VA,Lombardia,3,21050 +Buguggiate,12025,Varese,VA,Lombardia,3,21020 +Busto Arsizio,12026,Varese,VA,Lombardia,3,21052 +Cadegliano-Viconago,12027,Varese,VA,Lombardia,3,21031 +Cairate,12029,Varese,VA,Lombardia,3,21050 +Cantello,12030,Varese,VA,Lombardia,3,21050 +Caravate,12031,Varese,VA,Lombardia,3,21032 +Cardano al Campo,12032,Varese,VA,Lombardia,3,21010 +Carnago,12033,Varese,VA,Lombardia,3,21040 +Caronno Pertusella,12034,Varese,VA,Lombardia,3,21042 +Caronno Varesino,12035,Varese,VA,Lombardia,3,21040 +Casale Litta,12036,Varese,VA,Lombardia,3,21020 +Casalzuigno,12037,Varese,VA,Lombardia,3,21030 +Casciago,12038,Varese,VA,Lombardia,3,21020 +Casorate Sempione,12039,Varese,VA,Lombardia,3,21011 +Cassano Magnago,12040,Varese,VA,Lombardia,3,21012 +Cassano Valcuvia,12041,Varese,VA,Lombardia,3,21030 +Castellanza,12042,Varese,VA,Lombardia,3,21053 +Castello Cabiaglio,12043,Varese,VA,Lombardia,3,21030 +Castelseprio,12044,Varese,VA,Lombardia,3,21050 +Castelveccana,12045,Varese,VA,Lombardia,3,21010 +Castiglione Olona,12046,Varese,VA,Lombardia,3,21043 +Castronno,12047,Varese,VA,Lombardia,3,21040 +Cavaria con Premezzo,12048,Varese,VA,Lombardia,3,21044 +Cazzago Brabbia,12049,Varese,VA,Lombardia,3,21020 +Cislago,12050,Varese,VA,Lombardia,3,21040 +Cittiglio,12051,Varese,VA,Lombardia,3,21033 +Clivio,12052,Varese,VA,Lombardia,3,21050 +Cocquio-Trevisago,12053,Varese,VA,Lombardia,3,21034 +Comabbio,12054,Varese,VA,Lombardia,3,21020 +Comerio,12055,Varese,VA,Lombardia,3,21025 +Cremenaga,12056,Varese,VA,Lombardia,3,21030 +Crosio della Valle,12057,Varese,VA,Lombardia,3,21020 +Cuasso al Monte,12058,Varese,VA,Lombardia,3,21050 +Cugliate-Fabiasco,12059,Varese,VA,Lombardia,3,21030 +Cunardo,12060,Varese,VA,Lombardia,3,21035 +Curiglia con Monteviasco,12061,Varese,VA,Lombardia,3,21010 +Cuveglio,12062,Varese,VA,Lombardia,3,21030 +Cuvio,12063,Varese,VA,Lombardia,3,21030 +Daverio,12064,Varese,VA,Lombardia,3,21020 +Dumenza,12065,Varese,VA,Lombardia,3,21010 +Duno,12066,Varese,VA,Lombardia,3,21030 +Fagnano Olona,12067,Varese,VA,Lombardia,3,21054 +Ferno,12068,Varese,VA,Lombardia,3,21010 +Ferrera di Varese,12069,Varese,VA,Lombardia,3,21030 +Gallarate,12070,Varese,VA,Lombardia,3,21013 +Galliate Lombardo,12071,Varese,VA,Lombardia,3,21020 +Gavirate,12072,Varese,VA,Lombardia,3,21026 +Gazzada Schianno,12073,Varese,VA,Lombardia,3,21045 +Gemonio,12074,Varese,VA,Lombardia,3,21036 +Gerenzano,12075,Varese,VA,Lombardia,3,21040 +Germignaga,12076,Varese,VA,Lombardia,3,21010 +Golasecca,12077,Varese,VA,Lombardia,3,21010 +Gorla Maggiore,12078,Varese,VA,Lombardia,3,21050 +Gorla Minore,12079,Varese,VA,Lombardia,3,21055 +Gornate Olona,12080,Varese,VA,Lombardia,3,21040 +Grantola,12081,Varese,VA,Lombardia,3,21030 +Inarzo,12082,Varese,VA,Lombardia,3,21020 +Induno Olona,12083,Varese,VA,Lombardia,3,21056 +Ispra,12084,Varese,VA,Lombardia,3,21027 +Jerago con Orago,12085,Varese,VA,Lombardia,3,21040 +Lavena Ponte Tresa,12086,Varese,VA,Lombardia,3,21037 +Laveno-Mombello,12087,Varese,VA,Lombardia,3,21014 +Leggiuno,12088,Varese,VA,Lombardia,3,21038 +Lonate Ceppino,12089,Varese,VA,Lombardia,3,21050 +Lonate Pozzolo,12090,Varese,VA,Lombardia,3,21015 +Lozza,12091,Varese,VA,Lombardia,3,21040 +Luino,12092,Varese,VA,Lombardia,3,21016 +Luvinate,12093,Varese,VA,Lombardia,3,21020 +Malgesso,12095,Varese,VA,Lombardia,3,21020 +Malnate,12096,Varese,VA,Lombardia,3,21046 +Marchirolo,12097,Varese,VA,Lombardia,3,21030 +Marnate,12098,Varese,VA,Lombardia,3,21050 +Marzio,12099,Varese,VA,Lombardia,3,21030 +Masciago Primo,12100,Varese,VA,Lombardia,3,21030 +Mercallo,12101,Varese,VA,Lombardia,3,21020 +Mesenzana,12102,Varese,VA,Lombardia,3,21030 +Montegrino Valtravaglia,12103,Varese,VA,Lombardia,3,21010 +Monvalle,12104,Varese,VA,Lombardia,3,21020 +Morazzone,12105,Varese,VA,Lombardia,3,21040 +Mornago,12106,Varese,VA,Lombardia,3,21020 +Oggiona con Santo Stefano,12107,Varese,VA,Lombardia,3,21040 +Olgiate Olona,12108,Varese,VA,Lombardia,3,21057 +Origgio,12109,Varese,VA,Lombardia,3,21040 +Orino,12110,Varese,VA,Lombardia,3,21030 +Porto Ceresio,12113,Varese,VA,Lombardia,3,21050 +Porto Valtravaglia,12114,Varese,VA,Lombardia,3,21010 +Rancio Valcuvia,12115,Varese,VA,Lombardia,3,21030 +Ranco,12116,Varese,VA,Lombardia,3,21020 +Saltrio,12117,Varese,VA,Lombardia,3,21050 +Samarate,12118,Varese,VA,Lombardia,3,21017 +Saronno,12119,Varese,VA,Lombardia,3,21047 +Sesto Calende,12120,Varese,VA,Lombardia,3,21018 +Solbiate Arno,12121,Varese,VA,Lombardia,3,21048 +Solbiate Olona,12122,Varese,VA,Lombardia,3,21058 +Somma Lombardo,12123,Varese,VA,Lombardia,3,21019 +Sumirago,12124,Varese,VA,Lombardia,3,21040 +Taino,12125,Varese,VA,Lombardia,3,21020 +Ternate,12126,Varese,VA,Lombardia,3,21020 +Tradate,12127,Varese,VA,Lombardia,3,21049 +Travedona-Monate,12128,Varese,VA,Lombardia,3,21028 +Tronzano Lago Maggiore,12129,Varese,VA,Lombardia,3,21010 +Uboldo,12130,Varese,VA,Lombardia,3,21040 +Valganna,12131,Varese,VA,Lombardia,3,21039 +Varano Borghi,12132,Varese,VA,Lombardia,3,21020 +Varese,12133,Varese,VA,Lombardia,3,21100 +Vedano Olona,12134,Varese,VA,Lombardia,3,21040 +Venegono Inferiore,12136,Varese,VA,Lombardia,3,21040 +Venegono Superiore,12137,Varese,VA,Lombardia,3,21040 +Vergiate,12138,Varese,VA,Lombardia,3,21029 +Viggiù,12139,Varese,VA,Lombardia,3,21059 +Vizzola Ticino,12140,Varese,VA,Lombardia,3,21010 +Sangiano,12141,Varese,VA,Lombardia,3,21038 +Maccagno con Pino e Veddasca,12142,Varese,VA,Lombardia,3,21061 +Cadrezzate con Osmate,12143,Varese,VA,Lombardia,3,21062 +Albavilla,13003,Como,CO,Lombardia,3,22031 +Albese con Cassano,13004,Como,CO,Lombardia,3,22032 +Albiolo,13005,Como,CO,Lombardia,3,22070 +Alserio,13006,Como,CO,Lombardia,3,22040 +Alzate Brianza,13007,Como,CO,Lombardia,3,22040 +Anzano del Parco,13009,Como,CO,Lombardia,3,22040 +Appiano Gentile,13010,Como,CO,Lombardia,3,22070 +Argegno,13011,Como,CO,Lombardia,3,22010 +Arosio,13012,Como,CO,Lombardia,3,22060 +Asso,13013,Como,CO,Lombardia,3,22033 +Barni,13015,Como,CO,Lombardia,3,22030 +Bene Lario,13021,Como,CO,Lombardia,3,22010 +Beregazzo con Figliaro,13022,Como,CO,Lombardia,3,22070 +Binago,13023,Como,CO,Lombardia,3,22070 +Bizzarone,13024,Como,CO,Lombardia,3,22020 +Blessagno,13025,Como,CO,Lombardia,3,22028 +Blevio,13026,Como,CO,Lombardia,3,22020 +Bregnano,13028,Como,CO,Lombardia,3,22070 +Brenna,13029,Como,CO,Lombardia,3,22040 +Brienno,13030,Como,CO,Lombardia,3,22010 +Brunate,13032,Como,CO,Lombardia,3,22034 +Bulgarograsso,13034,Como,CO,Lombardia,3,22070 +Cabiate,13035,Como,CO,Lombardia,3,22060 +Cadorago,13036,Como,CO,Lombardia,3,22071 +Caglio,13037,Como,CO,Lombardia,3,22030 +Campione d'Italia,13040,Como,CO,Lombardia,3,22060 +Cantù,13041,Como,CO,Lombardia,3,22063 +Canzo,13042,Como,CO,Lombardia,3,22035 +Capiago Intimiano,13043,Como,CO,Lombardia,3,22070 +Carate Urio,13044,Como,CO,Lombardia,3,22010 +Carbonate,13045,Como,CO,Lombardia,3,22070 +Carimate,13046,Como,CO,Lombardia,3,22060 +Carlazzo,13047,Como,CO,Lombardia,3,22010 +Carugo,13048,Como,CO,Lombardia,3,22060 +Caslino d'Erba,13052,Como,CO,Lombardia,3,22030 +Casnate con Bernate,13053,Como,CO,Lombardia,3,22070 +Cassina Rizzardi,13055,Como,CO,Lombardia,3,22070 +Castelmarte,13058,Como,CO,Lombardia,3,22030 +Castelnuovo Bozzente,13059,Como,CO,Lombardia,3,22070 +Cavargna,13062,Como,CO,Lombardia,3,22010 +Cerano d'Intelvi,13063,Como,CO,Lombardia,3,22020 +Cermenate,13064,Como,CO,Lombardia,3,22072 +Cernobbio,13065,Como,CO,Lombardia,3,22012 +Cirimido,13068,Como,CO,Lombardia,3,22070 +Claino con Osteno,13071,Como,CO,Lombardia,3,22010 +Colonno,13074,Como,CO,Lombardia,3,22010 +Como,13075,Como,CO,Lombardia,3,22100 +Corrido,13077,Como,CO,Lombardia,3,22010 +Cremia,13083,Como,CO,Lombardia,3,22010 +Cucciago,13084,Como,CO,Lombardia,3,22060 +Cusino,13085,Como,CO,Lombardia,3,22010 +Dizzasco,13087,Como,CO,Lombardia,3,22020 +Domaso,13089,Como,CO,Lombardia,3,22013 +Dongo,13090,Como,CO,Lombardia,3,22014 +Dosso del Liro,13092,Como,CO,Lombardia,3,22010 +Erba,13095,Como,CO,Lombardia,3,22036 +Eupilio,13097,Como,CO,Lombardia,3,22030 +Faggeto Lario,13098,Como,CO,Lombardia,3,22020 +Faloppio,13099,Como,CO,Lombardia,3,22020 +Fenegrò,13100,Como,CO,Lombardia,3,22070 +Figino Serenza,13101,Como,CO,Lombardia,3,22060 +Fino Mornasco,13102,Como,CO,Lombardia,3,22073 +Garzeno,13106,Como,CO,Lombardia,3,22010 +Gera Lario,13107,Como,CO,Lombardia,3,22010 +Grandate,13110,Como,CO,Lombardia,3,22070 +Grandola ed Uniti,13111,Como,CO,Lombardia,3,22010 +Griante,13113,Como,CO,Lombardia,3,22011 +Guanzate,13114,Como,CO,Lombardia,3,22070 +Inverigo,13118,Como,CO,Lombardia,3,22044 +Laglio,13119,Como,CO,Lombardia,3,22010 +Laino,13120,Como,CO,Lombardia,3,22020 +Lambrugo,13121,Como,CO,Lombardia,3,22045 +Lasnigo,13123,Como,CO,Lombardia,3,22030 +Lezzeno,13126,Como,CO,Lombardia,3,22025 +Limido Comasco,13128,Como,CO,Lombardia,3,22070 +Lipomo,13129,Como,CO,Lombardia,3,22030 +Livo,13130,Como,CO,Lombardia,3,22010 +Locate Varesino,13131,Como,CO,Lombardia,3,22070 +Lomazzo,13133,Como,CO,Lombardia,3,22074 +Longone al Segrino,13134,Como,CO,Lombardia,3,22030 +Luisago,13135,Como,CO,Lombardia,3,22070 +Lurago d'Erba,13136,Como,CO,Lombardia,3,22040 +Lurago Marinone,13137,Como,CO,Lombardia,3,22070 +Lurate Caccivio,13138,Como,CO,Lombardia,3,22075 +Magreglio,13139,Como,CO,Lombardia,3,22030 +Mariano Comense,13143,Como,CO,Lombardia,3,22066 +Maslianico,13144,Como,CO,Lombardia,3,22026 +Menaggio,13145,Como,CO,Lombardia,3,22017 +Merone,13147,Como,CO,Lombardia,3,22046 +Moltrasio,13152,Como,CO,Lombardia,3,22010 +Monguzzo,13153,Como,CO,Lombardia,3,22040 +Montano Lucino,13154,Como,CO,Lombardia,3,22070 +Montemezzo,13155,Como,CO,Lombardia,3,22010 +Montorfano,13157,Como,CO,Lombardia,3,22030 +Mozzate,13159,Como,CO,Lombardia,3,22076 +Musso,13160,Como,CO,Lombardia,3,22010 +Nesso,13161,Como,CO,Lombardia,3,22020 +Novedrate,13163,Como,CO,Lombardia,3,22060 +Olgiate Comasco,13165,Como,CO,Lombardia,3,22077 +Oltrona di San Mamette,13169,Como,CO,Lombardia,3,22070 +Orsenigo,13170,Como,CO,Lombardia,3,22030 +Peglio,13178,Como,CO,Lombardia,3,22010 +Pianello del Lario,13183,Como,CO,Lombardia,3,22010 +Pigra,13184,Como,CO,Lombardia,3,22020 +Plesio,13185,Como,CO,Lombardia,3,22010 +Pognana Lario,13186,Como,CO,Lombardia,3,22020 +Ponna,13187,Como,CO,Lombardia,3,22020 +Ponte Lambro,13188,Como,CO,Lombardia,3,22037 +Porlezza,13189,Como,CO,Lombardia,3,22018 +Proserpio,13192,Como,CO,Lombardia,3,22030 +Pusiano,13193,Como,CO,Lombardia,3,22030 +Rezzago,13195,Como,CO,Lombardia,3,22030 +Rodero,13197,Como,CO,Lombardia,3,22070 +Ronago,13199,Como,CO,Lombardia,3,22027 +Rovellasca,13201,Como,CO,Lombardia,3,22069 +Rovello Porro,13202,Como,CO,Lombardia,3,22070 +Sala Comacina,13203,Como,CO,Lombardia,3,22010 +San Bartolomeo Val Cavargna,13204,Como,CO,Lombardia,3,22010 +San Fermo della Battaglia,13206,Como,CO,Lombardia,3,22020 +San Nazzaro Val Cavargna,13207,Como,CO,Lombardia,3,22010 +Schignano,13211,Como,CO,Lombardia,3,22020 +Senna Comasco,13212,Como,CO,Lombardia,3,22070 +Sorico,13216,Como,CO,Lombardia,3,22010 +Sormano,13217,Como,CO,Lombardia,3,22030 +Stazzona,13218,Como,CO,Lombardia,3,22010 +Tavernerio,13222,Como,CO,Lombardia,3,22038 +Torno,13223,Como,CO,Lombardia,3,22020 +Trezzone,13226,Como,CO,Lombardia,3,22010 +Turate,13227,Como,CO,Lombardia,3,22078 +Uggiate-Trevano,13228,Como,CO,Lombardia,3,22029 +Valbrona,13229,Como,CO,Lombardia,3,22039 +Valmorea,13232,Como,CO,Lombardia,3,22070 +Val Rezzo,13233,Como,CO,Lombardia,3,22010 +Valsolda,13234,Como,CO,Lombardia,3,22010 +Veleso,13236,Como,CO,Lombardia,3,22020 +Veniano,13238,Como,CO,Lombardia,3,22070 +Vercana,13239,Como,CO,Lombardia,3,22013 +Vertemate con Minoprio,13242,Como,CO,Lombardia,3,22070 +Villa Guardia,13245,Como,CO,Lombardia,3,22079 +Zelbio,13246,Como,CO,Lombardia,3,22020 +San Siro,13248,Como,CO,Lombardia,3,22010 +Gravedona ed Uniti,13249,Como,CO,Lombardia,3,22015 +Bellagio,13250,Como,CO,Lombardia,3,22021 +Colverde,13251,Como,CO,Lombardia,3,22041 +Tremezzina,13252,Como,CO,Lombardia,3,22016 +Alta Valle Intelvi,13253,Como,CO,Lombardia,3,22014 +Centro Valle Intelvi,13254,Como,CO,Lombardia,3,22028 +Solbiate con Cagno,13255,Como,CO,Lombardia,3,22070 +Albaredo per San Marco,14001,Sondrio,SO,Lombardia,3,23010 +Albosaggia,14002,Sondrio,SO,Lombardia,3,23010 +Andalo Valtellino,14003,Sondrio,SO,Lombardia,3,23014 +Aprica,14004,Sondrio,SO,Lombardia,3,23031 +Ardenno,14005,Sondrio,SO,Lombardia,3,23011 +Bema,14006,Sondrio,SO,Lombardia,3,23010 +Berbenno di Valtellina,14007,Sondrio,SO,Lombardia,3,23010 +Bianzone,14008,Sondrio,SO,Lombardia,3,23030 +Bormio,14009,Sondrio,SO,Lombardia,3,23032 +Buglio in Monte,14010,Sondrio,SO,Lombardia,3,23010 +Caiolo,14011,Sondrio,SO,Lombardia,3,23010 +Campodolcino,14012,Sondrio,SO,Lombardia,3,23021 +Caspoggio,14013,Sondrio,SO,Lombardia,3,23020 +Castello dell'Acqua,14014,Sondrio,SO,Lombardia,3,23030 +Castione Andevenno,14015,Sondrio,SO,Lombardia,3,23012 +Cedrasco,14016,Sondrio,SO,Lombardia,3,23010 +Cercino,14017,Sondrio,SO,Lombardia,3,23016 +Chiavenna,14018,Sondrio,SO,Lombardia,3,23022 +Chiesa in Valmalenco,14019,Sondrio,SO,Lombardia,3,23023 +Chiuro,14020,Sondrio,SO,Lombardia,3,23030 +Cino,14021,Sondrio,SO,Lombardia,3,23010 +Civo,14022,Sondrio,SO,Lombardia,3,23010 +Colorina,14023,Sondrio,SO,Lombardia,3,23010 +Cosio Valtellino,14024,Sondrio,SO,Lombardia,3,23013 +Dazio,14025,Sondrio,SO,Lombardia,3,23010 +Delebio,14026,Sondrio,SO,Lombardia,3,23014 +Dubino,14027,Sondrio,SO,Lombardia,3,23015 +Faedo Valtellino,14028,Sondrio,SO,Lombardia,3,23020 +Forcola,14029,Sondrio,SO,Lombardia,3,23010 +Fusine,14030,Sondrio,SO,Lombardia,3,23010 +Gerola Alta,14031,Sondrio,SO,Lombardia,3,23010 +Gordona,14032,Sondrio,SO,Lombardia,3,23020 +Grosio,14033,Sondrio,SO,Lombardia,3,23033 +Grosotto,14034,Sondrio,SO,Lombardia,3,23034 +Madesimo,14035,Sondrio,SO,Lombardia,3,23024 +Lanzada,14036,Sondrio,SO,Lombardia,3,23020 +Livigno,14037,Sondrio,SO,Lombardia,3,23041 +Lovero,14038,Sondrio,SO,Lombardia,3,23030 +Mantello,14039,Sondrio,SO,Lombardia,3,23016 +Mazzo di Valtellina,14040,Sondrio,SO,Lombardia,3,23030 +Mello,14041,Sondrio,SO,Lombardia,3,23010 +Mese,14043,Sondrio,SO,Lombardia,3,23020 +Montagna in Valtellina,14044,Sondrio,SO,Lombardia,3,23020 +Morbegno,14045,Sondrio,SO,Lombardia,3,23017 +Novate Mezzola,14046,Sondrio,SO,Lombardia,3,23025 +Pedesina,14047,Sondrio,SO,Lombardia,3,23010 +Piantedo,14048,Sondrio,SO,Lombardia,3,23010 +Piateda,14049,Sondrio,SO,Lombardia,3,23020 +Piuro,14050,Sondrio,SO,Lombardia,3,23020 +Poggiridenti,14051,Sondrio,SO,Lombardia,3,23020 +Ponte in Valtellina,14052,Sondrio,SO,Lombardia,3,23026 +Postalesio,14053,Sondrio,SO,Lombardia,3,23010 +Prata Camportaccio,14054,Sondrio,SO,Lombardia,3,23020 +Rasura,14055,Sondrio,SO,Lombardia,3,23010 +Rogolo,14056,Sondrio,SO,Lombardia,3,23010 +Samolaco,14057,Sondrio,SO,Lombardia,3,23027 +San Giacomo Filippo,14058,Sondrio,SO,Lombardia,3,23020 +Sernio,14059,Sondrio,SO,Lombardia,3,23030 +Sondalo,14060,Sondrio,SO,Lombardia,3,23035 +Sondrio,14061,Sondrio,SO,Lombardia,3,23100 +Spriana,14062,Sondrio,SO,Lombardia,3,23020 +Talamona,14063,Sondrio,SO,Lombardia,3,23018 +Tartano,14064,Sondrio,SO,Lombardia,3,23010 +Teglio,14065,Sondrio,SO,Lombardia,3,23036 +Tirano,14066,Sondrio,SO,Lombardia,3,23037 +Torre di Santa Maria,14067,Sondrio,SO,Lombardia,3,23020 +Tovo di Sant'Agata,14068,Sondrio,SO,Lombardia,3,23030 +Traona,14069,Sondrio,SO,Lombardia,3,23019 +Tresivio,14070,Sondrio,SO,Lombardia,3,23020 +Valdidentro,14071,Sondrio,SO,Lombardia,3,23038 +Valdisotto,14072,Sondrio,SO,Lombardia,3,23030 +Valfurva,14073,Sondrio,SO,Lombardia,3,23030 +Val Masino,14074,Sondrio,SO,Lombardia,3,23010 +Verceia,14075,Sondrio,SO,Lombardia,3,23020 +Vervio,14076,Sondrio,SO,Lombardia,3,23030 +Villa di Chiavenna,14077,Sondrio,SO,Lombardia,3,23029 +Villa di Tirano,14078,Sondrio,SO,Lombardia,3,23030 +Abbiategrasso,15002,Milano,MI,Lombardia,3,20081 +Albairate,15005,Milano,MI,Lombardia,3,20080 +Arconate,15007,Milano,MI,Lombardia,3,20020 +Arese,15009,Milano,MI,Lombardia,3,20020 +Arluno,15010,Milano,MI,Lombardia,3,20010 +Assago,15011,Milano,MI,Lombardia,3,20090 +Bareggio,15012,Milano,MI,Lombardia,3,20010 +Basiano,15014,Milano,MI,Lombardia,3,20060 +Basiglio,15015,Milano,MI,Lombardia,3,20080 +Bellinzago Lombardo,15016,Milano,MI,Lombardia,3,20060 +Bernate Ticino,15019,Milano,MI,Lombardia,3,20010 +Besate,15022,Milano,MI,Lombardia,3,20080 +Binasco,15024,Milano,MI,Lombardia,3,20082 +Boffalora sopra Ticino,15026,Milano,MI,Lombardia,3,20010 +Bollate,15027,Milano,MI,Lombardia,3,20021 +Bresso,15032,Milano,MI,Lombardia,3,20091 +Bubbiano,15035,Milano,MI,Lombardia,3,20080 +Buccinasco,15036,Milano,MI,Lombardia,3,20090 +Buscate,15038,Milano,MI,Lombardia,3,20010 +Bussero,15040,Milano,MI,Lombardia,3,20060 +Busto Garolfo,15041,Milano,MI,Lombardia,3,20020 +Calvignasco,15042,Milano,MI,Lombardia,3,20080 +Cambiago,15044,Milano,MI,Lombardia,3,20040 +Canegrate,15046,Milano,MI,Lombardia,3,20010 +Carpiano,15050,Milano,MI,Lombardia,3,20080 +Carugate,15051,Milano,MI,Lombardia,3,20061 +Casarile,15055,Milano,MI,Lombardia,3,20080 +Casorezzo,15058,Milano,MI,Lombardia,3,20010 +Cassano d'Adda,15059,Milano,MI,Lombardia,3,20062 +Cassina de' Pecchi,15060,Milano,MI,Lombardia,3,20060 +Cassinetta di Lugagnano,15061,Milano,MI,Lombardia,3,20081 +Castano Primo,15062,Milano,MI,Lombardia,3,20022 +Cernusco sul Naviglio,15070,Milano,MI,Lombardia,3,20063 +Cerro al Lambro,15071,Milano,MI,Lombardia,3,20070 +Cerro Maggiore,15072,Milano,MI,Lombardia,3,20023 +Cesano Boscone,15074,Milano,MI,Lombardia,3,20090 +Cesate,15076,Milano,MI,Lombardia,3,20020 +Cinisello Balsamo,15077,Milano,MI,Lombardia,3,20092 +Cisliano,15078,Milano,MI,Lombardia,3,20080 +Cologno Monzese,15081,Milano,MI,Lombardia,3,20093 +Colturano,15082,Milano,MI,Lombardia,3,20060 +Corbetta,15085,Milano,MI,Lombardia,3,20011 +Cormano,15086,Milano,MI,Lombardia,3,20032 +Cornaredo,15087,Milano,MI,Lombardia,3,20010 +Corsico,15093,Milano,MI,Lombardia,3,20094 +Cuggiono,15096,Milano,MI,Lombardia,3,20012 +Cusago,15097,Milano,MI,Lombardia,3,20090 +Cusano Milanino,15098,Milano,MI,Lombardia,3,20095 +Dairago,15099,Milano,MI,Lombardia,3,20020 +Dresano,15101,Milano,MI,Lombardia,3,20070 +Gaggiano,15103,Milano,MI,Lombardia,3,20083 +Garbagnate Milanese,15105,Milano,MI,Lombardia,3,20024 +Gessate,15106,Milano,MI,Lombardia,3,20060 +Gorgonzola,15108,Milano,MI,Lombardia,3,20064 +Grezzago,15110,Milano,MI,Lombardia,3,20056 +Gudo Visconti,15112,Milano,MI,Lombardia,3,20088 +Inveruno,15113,Milano,MI,Lombardia,3,20010 +Inzago,15114,Milano,MI,Lombardia,3,20065 +Lacchiarella,15115,Milano,MI,Lombardia,3,20084 +Lainate,15116,Milano,MI,Lombardia,3,20020 +Legnano,15118,Milano,MI,Lombardia,3,20025 +Liscate,15122,Milano,MI,Lombardia,3,20050 +Locate di Triulzi,15125,Milano,MI,Lombardia,3,20085 +Magenta,15130,Milano,MI,Lombardia,3,20013 +Magnago,15131,Milano,MI,Lombardia,3,20020 +Marcallo con Casone,15134,Milano,MI,Lombardia,3,20010 +Masate,15136,Milano,MI,Lombardia,3,20060 +Mediglia,15139,Milano,MI,Lombardia,3,20060 +Melegnano,15140,Milano,MI,Lombardia,3,20077 +Melzo,15142,Milano,MI,Lombardia,3,20066 +Mesero,15144,Milano,MI,Lombardia,3,20010 +Milano,15146,Milano,MI,Lombardia,3,20121 +Morimondo,15150,Milano,MI,Lombardia,3,20081 +Motta Visconti,15151,Milano,MI,Lombardia,3,20086 +Nerviano,15154,Milano,MI,Lombardia,3,20014 +Nosate,15155,Milano,MI,Lombardia,3,20020 +Novate Milanese,15157,Milano,MI,Lombardia,3,20026 +Noviglio,15158,Milano,MI,Lombardia,3,20082 +Opera,15159,Milano,MI,Lombardia,3,20073 +Ossona,15164,Milano,MI,Lombardia,3,20010 +Ozzero,15165,Milano,MI,Lombardia,3,20080 +Paderno Dugnano,15166,Milano,MI,Lombardia,3,20037 +Pantigliate,15167,Milano,MI,Lombardia,3,20090 +Parabiago,15168,Milano,MI,Lombardia,3,20015 +Paullo,15169,Milano,MI,Lombardia,3,20067 +Pero,15170,Milano,MI,Lombardia,3,20016 +Peschiera Borromeo,15171,Milano,MI,Lombardia,3,20068 +Pessano con Bornago,15172,Milano,MI,Lombardia,3,20060 +Pieve Emanuele,15173,Milano,MI,Lombardia,3,20090 +Pioltello,15175,Milano,MI,Lombardia,3,20096 +Pogliano Milanese,15176,Milano,MI,Lombardia,3,20010 +Pozzo d'Adda,15177,Milano,MI,Lombardia,3,20060 +Pozzuolo Martesana,15178,Milano,MI,Lombardia,3,20060 +Pregnana Milanese,15179,Milano,MI,Lombardia,3,20010 +Rescaldina,15181,Milano,MI,Lombardia,3,20027 +Rho,15182,Milano,MI,Lombardia,3,20017 +Robecchetto con Induno,15183,Milano,MI,Lombardia,3,20020 +Robecco sul Naviglio,15184,Milano,MI,Lombardia,3,20087 +Rodano,15185,Milano,MI,Lombardia,3,20053 +Rosate,15188,Milano,MI,Lombardia,3,20088 +Rozzano,15189,Milano,MI,Lombardia,3,20089 +San Colombano al Lambro,15191,Milano,MI,Lombardia,3,20078 +San Donato Milanese,15192,Milano,MI,Lombardia,3,20097 +San Giorgio su Legnano,15194,Milano,MI,Lombardia,3,20010 +San Giuliano Milanese,15195,Milano,MI,Lombardia,3,20098 +Santo Stefano Ticino,15200,Milano,MI,Lombardia,3,20010 +San Vittore Olona,15201,Milano,MI,Lombardia,3,20028 +San Zenone al Lambro,15202,Milano,MI,Lombardia,3,20070 +Sedriano,15204,Milano,MI,Lombardia,3,20018 +Segrate,15205,Milano,MI,Lombardia,3,20090 +Senago,15206,Milano,MI,Lombardia,3,20030 +Sesto San Giovanni,15209,Milano,MI,Lombardia,3,20099 +Settala,15210,Milano,MI,Lombardia,3,20090 +Settimo Milanese,15211,Milano,MI,Lombardia,3,20019 +Solaro,15213,Milano,MI,Lombardia,3,20020 +Trezzano Rosa,15219,Milano,MI,Lombardia,3,20060 +Trezzano sul Naviglio,15220,Milano,MI,Lombardia,3,20090 +Trezzo sull'Adda,15221,Milano,MI,Lombardia,3,20056 +Tribiano,15222,Milano,MI,Lombardia,3,20067 +Truccazzano,15224,Milano,MI,Lombardia,3,20060 +Turbigo,15226,Milano,MI,Lombardia,3,20029 +Vanzago,15229,Milano,MI,Lombardia,3,20010 +Vaprio d'Adda,15230,Milano,MI,Lombardia,3,20069 +Vernate,15236,Milano,MI,Lombardia,3,20080 +Vignate,15237,Milano,MI,Lombardia,3,20060 +Vimodrone,15242,Milano,MI,Lombardia,3,20055 +Vittuone,15243,Milano,MI,Lombardia,3,20010 +Vizzolo Predabissi,15244,Milano,MI,Lombardia,3,20070 +Zibido San Giacomo,15247,Milano,MI,Lombardia,3,20080 +Villa Cortese,15248,Milano,MI,Lombardia,3,20035 +Vanzaghello,15249,Milano,MI,Lombardia,3,20020 +Baranzate,15250,Milano,MI,Lombardia,3,20021 +Vermezzo con Zelo,15251,Milano,MI,Lombardia,3,20080 +Adrara San Martino,16001,Bergamo,BG,Lombardia,3,24060 +Adrara San Rocco,16002,Bergamo,BG,Lombardia,3,24060 +Albano Sant'Alessandro,16003,Bergamo,BG,Lombardia,3,24061 +Albino,16004,Bergamo,BG,Lombardia,3,24021 +Almè,16005,Bergamo,BG,Lombardia,3,24011 +Almenno San Bartolomeo,16006,Bergamo,BG,Lombardia,3,24030 +Almenno San Salvatore,16007,Bergamo,BG,Lombardia,3,24031 +Alzano Lombardo,16008,Bergamo,BG,Lombardia,3,24022 +Ambivere,16009,Bergamo,BG,Lombardia,3,24030 +Antegnate,16010,Bergamo,BG,Lombardia,3,24051 +Arcene,16011,Bergamo,BG,Lombardia,3,24040 +Ardesio,16012,Bergamo,BG,Lombardia,3,24020 +Arzago d'Adda,16013,Bergamo,BG,Lombardia,3,24040 +Averara,16014,Bergamo,BG,Lombardia,3,24010 +Aviatico,16015,Bergamo,BG,Lombardia,3,24020 +Azzano San Paolo,16016,Bergamo,BG,Lombardia,3,24052 +Azzone,16017,Bergamo,BG,Lombardia,3,24020 +Bagnatica,16018,Bergamo,BG,Lombardia,3,24060 +Barbata,16019,Bergamo,BG,Lombardia,3,24040 +Bariano,16020,Bergamo,BG,Lombardia,3,24050 +Barzana,16021,Bergamo,BG,Lombardia,3,24030 +Bedulita,16022,Bergamo,BG,Lombardia,3,24030 +Berbenno,16023,Bergamo,BG,Lombardia,3,24030 +Bergamo,16024,Bergamo,BG,Lombardia,3,24122 +Berzo San Fermo,16025,Bergamo,BG,Lombardia,3,24060 +Bianzano,16026,Bergamo,BG,Lombardia,3,24060 +Blello,16027,Bergamo,BG,Lombardia,3,24010 +Bolgare,16028,Bergamo,BG,Lombardia,3,24060 +Boltiere,16029,Bergamo,BG,Lombardia,3,24040 +Bonate Sopra,16030,Bergamo,BG,Lombardia,3,24040 +Bonate Sotto,16031,Bergamo,BG,Lombardia,3,24040 +Borgo di Terzo,16032,Bergamo,BG,Lombardia,3,24060 +Bossico,16033,Bergamo,BG,Lombardia,3,24060 +Bottanuco,16034,Bergamo,BG,Lombardia,3,24040 +Bracca,16035,Bergamo,BG,Lombardia,3,24010 +Branzi,16036,Bergamo,BG,Lombardia,3,24010 +Brembate,16037,Bergamo,BG,Lombardia,3,24041 +Brembate di Sopra,16038,Bergamo,BG,Lombardia,3,24030 +Brignano Gera d'Adda,16040,Bergamo,BG,Lombardia,3,24053 +Brumano,16041,Bergamo,BG,Lombardia,3,24037 +Brusaporto,16042,Bergamo,BG,Lombardia,3,24060 +Calcinate,16043,Bergamo,BG,Lombardia,3,24050 +Calcio,16044,Bergamo,BG,Lombardia,3,24054 +Calusco d'Adda,16046,Bergamo,BG,Lombardia,3,24033 +Calvenzano,16047,Bergamo,BG,Lombardia,3,24040 +Camerata Cornello,16048,Bergamo,BG,Lombardia,3,24010 +Canonica d'Adda,16049,Bergamo,BG,Lombardia,3,24040 +Capizzone,16050,Bergamo,BG,Lombardia,3,24030 +Capriate San Gervasio,16051,Bergamo,BG,Lombardia,3,24042 +Caprino Bergamasco,16052,Bergamo,BG,Lombardia,3,24030 +Caravaggio,16053,Bergamo,BG,Lombardia,3,24043 +Carobbio degli Angeli,16055,Bergamo,BG,Lombardia,3,24060 +Carona,16056,Bergamo,BG,Lombardia,3,24010 +Carvico,16057,Bergamo,BG,Lombardia,3,24030 +Casazza,16058,Bergamo,BG,Lombardia,3,24060 +Casirate d'Adda,16059,Bergamo,BG,Lombardia,3,24040 +Casnigo,16060,Bergamo,BG,Lombardia,3,24020 +Cassiglio,16061,Bergamo,BG,Lombardia,3,24010 +Castelli Calepio,16062,Bergamo,BG,Lombardia,3,24060 +Castel Rozzone,16063,Bergamo,BG,Lombardia,3,24040 +Castione della Presolana,16064,Bergamo,BG,Lombardia,3,24020 +Castro,16065,Bergamo,BG,Lombardia,3,24063 +Cavernago,16066,Bergamo,BG,Lombardia,3,24050 +Cazzano Sant'Andrea,16067,Bergamo,BG,Lombardia,3,24026 +Cenate Sopra,16068,Bergamo,BG,Lombardia,3,24060 +Cenate Sotto,16069,Bergamo,BG,Lombardia,3,24069 +Cene,16070,Bergamo,BG,Lombardia,3,24020 +Cerete,16071,Bergamo,BG,Lombardia,3,24020 +Chignolo d'Isola,16072,Bergamo,BG,Lombardia,3,24040 +Chiuduno,16073,Bergamo,BG,Lombardia,3,24060 +Cisano Bergamasco,16074,Bergamo,BG,Lombardia,3,24034 +Ciserano,16075,Bergamo,BG,Lombardia,3,24040 +Cividate al Piano,16076,Bergamo,BG,Lombardia,3,24050 +Clusone,16077,Bergamo,BG,Lombardia,3,24023 +Colere,16078,Bergamo,BG,Lombardia,3,24020 +Cologno al Serio,16079,Bergamo,BG,Lombardia,3,24055 +Colzate,16080,Bergamo,BG,Lombardia,3,24020 +Comun Nuovo,16081,Bergamo,BG,Lombardia,3,24040 +Corna Imagna,16082,Bergamo,BG,Lombardia,3,24030 +Cortenuova,16083,Bergamo,BG,Lombardia,3,24050 +Costa di Mezzate,16084,Bergamo,BG,Lombardia,3,24060 +Costa Valle Imagna,16085,Bergamo,BG,Lombardia,3,24030 +Costa Volpino,16086,Bergamo,BG,Lombardia,3,24062 +Covo,16087,Bergamo,BG,Lombardia,3,24050 +Credaro,16088,Bergamo,BG,Lombardia,3,24060 +Curno,16089,Bergamo,BG,Lombardia,3,24035 +Cusio,16090,Bergamo,BG,Lombardia,3,24010 +Dalmine,16091,Bergamo,BG,Lombardia,3,24044 +Dossena,16092,Bergamo,BG,Lombardia,3,24010 +Endine Gaiano,16093,Bergamo,BG,Lombardia,3,24060 +Entratico,16094,Bergamo,BG,Lombardia,3,24060 +Fara Gera d'Adda,16096,Bergamo,BG,Lombardia,3,24045 +Fara Olivana con Sola,16097,Bergamo,BG,Lombardia,3,24058 +Filago,16098,Bergamo,BG,Lombardia,3,24040 +Fino del Monte,16099,Bergamo,BG,Lombardia,3,24020 +Fiorano al Serio,16100,Bergamo,BG,Lombardia,3,24020 +Fontanella,16101,Bergamo,BG,Lombardia,3,24056 +Fonteno,16102,Bergamo,BG,Lombardia,3,24060 +Foppolo,16103,Bergamo,BG,Lombardia,3,24010 +Foresto Sparso,16104,Bergamo,BG,Lombardia,3,24060 +Fornovo San Giovanni,16105,Bergamo,BG,Lombardia,3,24040 +Fuipiano Valle Imagna,16106,Bergamo,BG,Lombardia,3,24030 +Gandellino,16107,Bergamo,BG,Lombardia,3,24020 +Gandino,16108,Bergamo,BG,Lombardia,3,24024 +Gandosso,16109,Bergamo,BG,Lombardia,3,24060 +Gaverina Terme,16110,Bergamo,BG,Lombardia,3,24060 +Gazzaniga,16111,Bergamo,BG,Lombardia,3,24025 +Ghisalba,16113,Bergamo,BG,Lombardia,3,24050 +Gorlago,16114,Bergamo,BG,Lombardia,3,24060 +Gorle,16115,Bergamo,BG,Lombardia,3,24020 +Gorno,16116,Bergamo,BG,Lombardia,3,24020 +Grassobbio,16117,Bergamo,BG,Lombardia,3,24050 +Gromo,16118,Bergamo,BG,Lombardia,3,24020 +Grone,16119,Bergamo,BG,Lombardia,3,24060 +Grumello del Monte,16120,Bergamo,BG,Lombardia,3,24064 +Isola di Fondra,16121,Bergamo,BG,Lombardia,3,24010 +Isso,16122,Bergamo,BG,Lombardia,3,24040 +Lallio,16123,Bergamo,BG,Lombardia,3,24040 +Leffe,16124,Bergamo,BG,Lombardia,3,24026 +Lenna,16125,Bergamo,BG,Lombardia,3,24010 +Levate,16126,Bergamo,BG,Lombardia,3,24040 +Locatello,16127,Bergamo,BG,Lombardia,3,24030 +Lovere,16128,Bergamo,BG,Lombardia,3,24065 +Lurano,16129,Bergamo,BG,Lombardia,3,24050 +Luzzana,16130,Bergamo,BG,Lombardia,3,24069 +Madone,16131,Bergamo,BG,Lombardia,3,24040 +Mapello,16132,Bergamo,BG,Lombardia,3,24030 +Martinengo,16133,Bergamo,BG,Lombardia,3,24057 +Mezzoldo,16134,Bergamo,BG,Lombardia,3,24010 +Misano di Gera d'Adda,16135,Bergamo,BG,Lombardia,3,24040 +Moio de' Calvi,16136,Bergamo,BG,Lombardia,3,24010 +Monasterolo del Castello,16137,Bergamo,BG,Lombardia,3,24060 +Montello,16139,Bergamo,BG,Lombardia,3,24060 +Morengo,16140,Bergamo,BG,Lombardia,3,24050 +Mornico al Serio,16141,Bergamo,BG,Lombardia,3,24050 +Mozzanica,16142,Bergamo,BG,Lombardia,3,24050 +Mozzo,16143,Bergamo,BG,Lombardia,3,24030 +Nembro,16144,Bergamo,BG,Lombardia,3,24027 +Olmo al Brembo,16145,Bergamo,BG,Lombardia,3,24010 +Oltre il Colle,16146,Bergamo,BG,Lombardia,3,24013 +Oltressenda Alta,16147,Bergamo,BG,Lombardia,3,24020 +Oneta,16148,Bergamo,BG,Lombardia,3,24020 +Onore,16149,Bergamo,BG,Lombardia,3,24020 +Orio al Serio,16150,Bergamo,BG,Lombardia,3,24050 +Ornica,16151,Bergamo,BG,Lombardia,3,24010 +Osio Sopra,16152,Bergamo,BG,Lombardia,3,24040 +Osio Sotto,16153,Bergamo,BG,Lombardia,3,24046 +Pagazzano,16154,Bergamo,BG,Lombardia,3,24040 +Paladina,16155,Bergamo,BG,Lombardia,3,24030 +Palazzago,16156,Bergamo,BG,Lombardia,3,24030 +Palosco,16157,Bergamo,BG,Lombardia,3,24050 +Parre,16158,Bergamo,BG,Lombardia,3,24020 +Parzanica,16159,Bergamo,BG,Lombardia,3,24060 +Pedrengo,16160,Bergamo,BG,Lombardia,3,24066 +Peia,16161,Bergamo,BG,Lombardia,3,24020 +Pianico,16162,Bergamo,BG,Lombardia,3,24060 +Piario,16163,Bergamo,BG,Lombardia,3,24020 +Piazza Brembana,16164,Bergamo,BG,Lombardia,3,24014 +Piazzatorre,16165,Bergamo,BG,Lombardia,3,24010 +Piazzolo,16166,Bergamo,BG,Lombardia,3,24010 +Pognano,16167,Bergamo,BG,Lombardia,3,24040 +Ponte Nossa,16168,Bergamo,BG,Lombardia,3,24028 +Ponteranica,16169,Bergamo,BG,Lombardia,3,24010 +Ponte San Pietro,16170,Bergamo,BG,Lombardia,3,24036 +Pontida,16171,Bergamo,BG,Lombardia,3,24030 +Pontirolo Nuovo,16172,Bergamo,BG,Lombardia,3,24040 +Pradalunga,16173,Bergamo,BG,Lombardia,3,24020 +Predore,16174,Bergamo,BG,Lombardia,3,24060 +Premolo,16175,Bergamo,BG,Lombardia,3,24020 +Presezzo,16176,Bergamo,BG,Lombardia,3,24030 +Pumenengo,16177,Bergamo,BG,Lombardia,3,24050 +Ranica,16178,Bergamo,BG,Lombardia,3,24020 +Ranzanico,16179,Bergamo,BG,Lombardia,3,24060 +Riva di Solto,16180,Bergamo,BG,Lombardia,3,24060 +Rogno,16182,Bergamo,BG,Lombardia,3,24060 +Romano di Lombardia,16183,Bergamo,BG,Lombardia,3,24058 +Roncobello,16184,Bergamo,BG,Lombardia,3,24010 +Roncola,16185,Bergamo,BG,Lombardia,3,24030 +Rota d'Imagna,16186,Bergamo,BG,Lombardia,3,24037 +Rovetta,16187,Bergamo,BG,Lombardia,3,24020 +San Giovanni Bianco,16188,Bergamo,BG,Lombardia,3,24015 +San Paolo d'Argon,16189,Bergamo,BG,Lombardia,3,24060 +San Pellegrino Terme,16190,Bergamo,BG,Lombardia,3,24016 +Santa Brigida,16191,Bergamo,BG,Lombardia,3,24010 +Sarnico,16193,Bergamo,BG,Lombardia,3,24067 +Scanzorosciate,16194,Bergamo,BG,Lombardia,3,24020 +Schilpario,16195,Bergamo,BG,Lombardia,3,24020 +Sedrina,16196,Bergamo,BG,Lombardia,3,24010 +Selvino,16197,Bergamo,BG,Lombardia,3,24020 +Seriate,16198,Bergamo,BG,Lombardia,3,24068 +Serina,16199,Bergamo,BG,Lombardia,3,24017 +Solto Collina,16200,Bergamo,BG,Lombardia,3,24060 +Songavazzo,16201,Bergamo,BG,Lombardia,3,24020 +Sorisole,16202,Bergamo,BG,Lombardia,3,24010 +Sotto il Monte Giovanni XXIII,16203,Bergamo,BG,Lombardia,3,24039 +Sovere,16204,Bergamo,BG,Lombardia,3,24060 +Spinone al Lago,16205,Bergamo,BG,Lombardia,3,24060 +Spirano,16206,Bergamo,BG,Lombardia,3,24050 +Stezzano,16207,Bergamo,BG,Lombardia,3,24040 +Strozza,16208,Bergamo,BG,Lombardia,3,24030 +Suisio,16209,Bergamo,BG,Lombardia,3,24040 +Taleggio,16210,Bergamo,BG,Lombardia,3,24010 +Tavernola Bergamasca,16211,Bergamo,BG,Lombardia,3,24060 +Telgate,16212,Bergamo,BG,Lombardia,3,24060 +Terno d'Isola,16213,Bergamo,BG,Lombardia,3,24030 +Torre Boldone,16214,Bergamo,BG,Lombardia,3,24020 +Torre de' Busi,16215,Bergamo,BG,Lombardia,3,23806 +Torre de' Roveri,16216,Bergamo,BG,Lombardia,3,24060 +Torre Pallavicina,16217,Bergamo,BG,Lombardia,3,24050 +Trescore Balneario,16218,Bergamo,BG,Lombardia,3,24069 +Treviglio,16219,Bergamo,BG,Lombardia,3,24047 +Treviolo,16220,Bergamo,BG,Lombardia,3,24048 +Ubiale Clanezzo,16221,Bergamo,BG,Lombardia,3,24010 +Urgnano,16222,Bergamo,BG,Lombardia,3,24059 +Valbondione,16223,Bergamo,BG,Lombardia,3,24020 +Valbrembo,16224,Bergamo,BG,Lombardia,3,24030 +Valgoglio,16225,Bergamo,BG,Lombardia,3,24020 +Valleve,16226,Bergamo,BG,Lombardia,3,24010 +Valnegra,16227,Bergamo,BG,Lombardia,3,24010 +Valtorta,16229,Bergamo,BG,Lombardia,3,24010 +Vedeseta,16230,Bergamo,BG,Lombardia,3,24010 +Verdellino,16232,Bergamo,BG,Lombardia,3,24040 +Verdello,16233,Bergamo,BG,Lombardia,3,24049 +Vertova,16234,Bergamo,BG,Lombardia,3,24029 +Viadanica,16235,Bergamo,BG,Lombardia,3,24060 +Vigano San Martino,16236,Bergamo,BG,Lombardia,3,24060 +Vigolo,16237,Bergamo,BG,Lombardia,3,24060 +Villa d'Adda,16238,Bergamo,BG,Lombardia,3,24030 +Villa d'Almè,16239,Bergamo,BG,Lombardia,3,24018 +Villa di Serio,16240,Bergamo,BG,Lombardia,3,24020 +Villa d'Ogna,16241,Bergamo,BG,Lombardia,3,24020 +Villongo,16242,Bergamo,BG,Lombardia,3,24060 +Vilminore di Scalve,16243,Bergamo,BG,Lombardia,3,24020 +Zandobbio,16244,Bergamo,BG,Lombardia,3,24060 +Zanica,16245,Bergamo,BG,Lombardia,3,24050 +Zogno,16246,Bergamo,BG,Lombardia,3,24019 +Costa Serina,16247,Bergamo,BG,Lombardia,3,24010 +Algua,16248,Bergamo,BG,Lombardia,3,24010 +Cornalba,16249,Bergamo,BG,Lombardia,3,24017 +Medolago,16250,Bergamo,BG,Lombardia,3,24030 +Solza,16251,Bergamo,BG,Lombardia,3,24030 +Sant'Omobono Terme,16252,Bergamo,BG,Lombardia,3,24038 +Val Brembilla,16253,Bergamo,BG,Lombardia,3,24012 +Acquafredda,17001,Brescia,BS,Lombardia,3,25010 +Adro,17002,Brescia,BS,Lombardia,3,25030 +Agnosine,17003,Brescia,BS,Lombardia,3,25071 +Alfianello,17004,Brescia,BS,Lombardia,3,25020 +Anfo,17005,Brescia,BS,Lombardia,3,25070 +Angolo Terme,17006,Brescia,BS,Lombardia,3,25040 +Artogne,17007,Brescia,BS,Lombardia,3,25040 +Azzano Mella,17008,Brescia,BS,Lombardia,3,25020 +Bagnolo Mella,17009,Brescia,BS,Lombardia,3,25021 +Bagolino,17010,Brescia,BS,Lombardia,3,25072 +Barbariga,17011,Brescia,BS,Lombardia,3,25030 +Barghe,17012,Brescia,BS,Lombardia,3,25070 +Bassano Bresciano,17013,Brescia,BS,Lombardia,3,25020 +Bedizzole,17014,Brescia,BS,Lombardia,3,25081 +Berlingo,17015,Brescia,BS,Lombardia,3,25030 +Berzo Demo,17016,Brescia,BS,Lombardia,3,25040 +Berzo Inferiore,17017,Brescia,BS,Lombardia,3,25040 +Bienno,17018,Brescia,BS,Lombardia,3,25040 +Bione,17019,Brescia,BS,Lombardia,3,25070 +Borgo San Giacomo,17020,Brescia,BS,Lombardia,3,25022 +Borgosatollo,17021,Brescia,BS,Lombardia,3,25010 +Borno,17022,Brescia,BS,Lombardia,3,25042 +Botticino,17023,Brescia,BS,Lombardia,3,25082 +Bovegno,17024,Brescia,BS,Lombardia,3,25061 +Bovezzo,17025,Brescia,BS,Lombardia,3,25073 +Brandico,17026,Brescia,BS,Lombardia,3,25030 +Braone,17027,Brescia,BS,Lombardia,3,25040 +Breno,17028,Brescia,BS,Lombardia,3,25043 +Brescia,17029,Brescia,BS,Lombardia,3,25121 +Brione,17030,Brescia,BS,Lombardia,3,25060 +Caino,17031,Brescia,BS,Lombardia,3,25070 +Calcinato,17032,Brescia,BS,Lombardia,3,25011 +Calvagese della Riviera,17033,Brescia,BS,Lombardia,3,25080 +Calvisano,17034,Brescia,BS,Lombardia,3,25012 +Capo di Ponte,17035,Brescia,BS,Lombardia,3,25044 +Capovalle,17036,Brescia,BS,Lombardia,3,25070 +Capriano del Colle,17037,Brescia,BS,Lombardia,3,25020 +Capriolo,17038,Brescia,BS,Lombardia,3,25031 +Carpenedolo,17039,Brescia,BS,Lombardia,3,25013 +Castegnato,17040,Brescia,BS,Lombardia,3,25045 +Castelcovati,17041,Brescia,BS,Lombardia,3,25030 +Castel Mella,17042,Brescia,BS,Lombardia,3,25030 +Castenedolo,17043,Brescia,BS,Lombardia,3,25014 +Casto,17044,Brescia,BS,Lombardia,3,25070 +Castrezzato,17045,Brescia,BS,Lombardia,3,25030 +Cazzago San Martino,17046,Brescia,BS,Lombardia,3,25046 +Cedegolo,17047,Brescia,BS,Lombardia,3,25051 +Cellatica,17048,Brescia,BS,Lombardia,3,25060 +Cerveno,17049,Brescia,BS,Lombardia,3,25040 +Ceto,17050,Brescia,BS,Lombardia,3,25040 +Cevo,17051,Brescia,BS,Lombardia,3,25040 +Chiari,17052,Brescia,BS,Lombardia,3,25032 +Cigole,17053,Brescia,BS,Lombardia,3,25020 +Cimbergo,17054,Brescia,BS,Lombardia,3,25050 +Cividate Camuno,17055,Brescia,BS,Lombardia,3,25040 +Coccaglio,17056,Brescia,BS,Lombardia,3,25030 +Collebeato,17057,Brescia,BS,Lombardia,3,25060 +Collio,17058,Brescia,BS,Lombardia,3,25060 +Cologne,17059,Brescia,BS,Lombardia,3,25033 +Comezzano-Cizzago,17060,Brescia,BS,Lombardia,3,25030 +Concesio,17061,Brescia,BS,Lombardia,3,25062 +Corte Franca,17062,Brescia,BS,Lombardia,3,25040 +Corteno Golgi,17063,Brescia,BS,Lombardia,3,25040 +Corzano,17064,Brescia,BS,Lombardia,3,25030 +Darfo Boario Terme,17065,Brescia,BS,Lombardia,3,25047 +Dello,17066,Brescia,BS,Lombardia,3,25020 +Desenzano del Garda,17067,Brescia,BS,Lombardia,3,25015 +Edolo,17068,Brescia,BS,Lombardia,3,25048 +Erbusco,17069,Brescia,BS,Lombardia,3,25030 +Esine,17070,Brescia,BS,Lombardia,3,25040 +Fiesse,17071,Brescia,BS,Lombardia,3,25020 +Flero,17072,Brescia,BS,Lombardia,3,25020 +Gambara,17073,Brescia,BS,Lombardia,3,25020 +Gardone Riviera,17074,Brescia,BS,Lombardia,3,25083 +Gardone Val Trompia,17075,Brescia,BS,Lombardia,3,25063 +Gargnano,17076,Brescia,BS,Lombardia,3,25084 +Gavardo,17077,Brescia,BS,Lombardia,3,25085 +Ghedi,17078,Brescia,BS,Lombardia,3,25016 +Gianico,17079,Brescia,BS,Lombardia,3,25040 +Gottolengo,17080,Brescia,BS,Lombardia,3,25023 +Gussago,17081,Brescia,BS,Lombardia,3,25064 +Idro,17082,Brescia,BS,Lombardia,3,25074 +Incudine,17083,Brescia,BS,Lombardia,3,25040 +Irma,17084,Brescia,BS,Lombardia,3,25061 +Iseo,17085,Brescia,BS,Lombardia,3,25049 +Isorella,17086,Brescia,BS,Lombardia,3,25010 +Lavenone,17087,Brescia,BS,Lombardia,3,25074 +Leno,17088,Brescia,BS,Lombardia,3,25024 +Limone sul Garda,17089,Brescia,BS,Lombardia,3,25010 +Lodrino,17090,Brescia,BS,Lombardia,3,25060 +Lograto,17091,Brescia,BS,Lombardia,3,25030 +Lonato del Garda,17092,Brescia,BS,Lombardia,3,25017 +Longhena,17093,Brescia,BS,Lombardia,3,25030 +Losine,17094,Brescia,BS,Lombardia,3,25050 +Lozio,17095,Brescia,BS,Lombardia,3,25040 +Lumezzane,17096,Brescia,BS,Lombardia,3,25065 +Maclodio,17097,Brescia,BS,Lombardia,3,25030 +Magasa,17098,Brescia,BS,Lombardia,3,25080 +Mairano,17099,Brescia,BS,Lombardia,3,25030 +Malegno,17100,Brescia,BS,Lombardia,3,25053 +Malonno,17101,Brescia,BS,Lombardia,3,25040 +Manerba del Garda,17102,Brescia,BS,Lombardia,3,25080 +Manerbio,17103,Brescia,BS,Lombardia,3,25025 +Marcheno,17104,Brescia,BS,Lombardia,3,25060 +Marmentino,17105,Brescia,BS,Lombardia,3,25060 +Marone,17106,Brescia,BS,Lombardia,3,25054 +Mazzano,17107,Brescia,BS,Lombardia,3,25080 +Milzano,17108,Brescia,BS,Lombardia,3,25020 +Moniga del Garda,17109,Brescia,BS,Lombardia,3,25080 +Monno,17110,Brescia,BS,Lombardia,3,25040 +Monte Isola,17111,Brescia,BS,Lombardia,3,25050 +Monticelli Brusati,17112,Brescia,BS,Lombardia,3,25040 +Montichiari,17113,Brescia,BS,Lombardia,3,25018 +Montirone,17114,Brescia,BS,Lombardia,3,25010 +Mura,17115,Brescia,BS,Lombardia,3,25070 +Muscoline,17116,Brescia,BS,Lombardia,3,25080 +Nave,17117,Brescia,BS,Lombardia,3,25075 +Niardo,17118,Brescia,BS,Lombardia,3,25050 +Nuvolento,17119,Brescia,BS,Lombardia,3,25080 +Nuvolera,17120,Brescia,BS,Lombardia,3,25080 +Odolo,17121,Brescia,BS,Lombardia,3,25076 +Offlaga,17122,Brescia,BS,Lombardia,3,25020 +Ome,17123,Brescia,BS,Lombardia,3,25050 +Ono San Pietro,17124,Brescia,BS,Lombardia,3,25040 +Orzinuovi,17125,Brescia,BS,Lombardia,3,25034 +Orzivecchi,17126,Brescia,BS,Lombardia,3,25030 +Ospitaletto,17127,Brescia,BS,Lombardia,3,25035 +Ossimo,17128,Brescia,BS,Lombardia,3,25050 +Padenghe sul Garda,17129,Brescia,BS,Lombardia,3,25080 +Paderno Franciacorta,17130,Brescia,BS,Lombardia,3,25050 +Paisco Loveno,17131,Brescia,BS,Lombardia,3,25050 +Paitone,17132,Brescia,BS,Lombardia,3,25080 +Palazzolo sull'Oglio,17133,Brescia,BS,Lombardia,3,25036 +Paratico,17134,Brescia,BS,Lombardia,3,25030 +Paspardo,17135,Brescia,BS,Lombardia,3,25050 +Passirano,17136,Brescia,BS,Lombardia,3,25050 +Pavone del Mella,17137,Brescia,BS,Lombardia,3,25020 +San Paolo,17138,Brescia,BS,Lombardia,3,25020 +Pertica Alta,17139,Brescia,BS,Lombardia,3,25070 +Pertica Bassa,17140,Brescia,BS,Lombardia,3,25078 +Pezzaze,17141,Brescia,BS,Lombardia,3,25060 +Pian Camuno,17142,Brescia,BS,Lombardia,3,25050 +Pisogne,17143,Brescia,BS,Lombardia,3,25055 +Polaveno,17144,Brescia,BS,Lombardia,3,25060 +Polpenazze del Garda,17145,Brescia,BS,Lombardia,3,25080 +Pompiano,17146,Brescia,BS,Lombardia,3,25030 +Poncarale,17147,Brescia,BS,Lombardia,3,25020 +Ponte di Legno,17148,Brescia,BS,Lombardia,3,25056 +Pontevico,17149,Brescia,BS,Lombardia,3,25026 +Pontoglio,17150,Brescia,BS,Lombardia,3,25037 +Pozzolengo,17151,Brescia,BS,Lombardia,3,25010 +Pralboino,17152,Brescia,BS,Lombardia,3,25020 +Preseglie,17153,Brescia,BS,Lombardia,3,25070 +Prevalle,17155,Brescia,BS,Lombardia,3,25080 +Provaglio d'Iseo,17156,Brescia,BS,Lombardia,3,25050 +Provaglio Val Sabbia,17157,Brescia,BS,Lombardia,3,25070 +Puegnago del Garda,17158,Brescia,BS,Lombardia,3,25080 +Quinzano d'Oglio,17159,Brescia,BS,Lombardia,3,25027 +Remedello,17160,Brescia,BS,Lombardia,3,25010 +Rezzato,17161,Brescia,BS,Lombardia,3,25086 +Roccafranca,17162,Brescia,BS,Lombardia,3,25030 +Rodengo Saiano,17163,Brescia,BS,Lombardia,3,25050 +Roè Volciano,17164,Brescia,BS,Lombardia,3,25077 +Roncadelle,17165,Brescia,BS,Lombardia,3,25030 +Rovato,17166,Brescia,BS,Lombardia,3,25038 +Rudiano,17167,Brescia,BS,Lombardia,3,25030 +Sabbio Chiese,17168,Brescia,BS,Lombardia,3,25070 +Sale Marasino,17169,Brescia,BS,Lombardia,3,25057 +Salò,17170,Brescia,BS,Lombardia,3,25087 +San Felice del Benaco,17171,Brescia,BS,Lombardia,3,25010 +San Gervasio Bresciano,17172,Brescia,BS,Lombardia,3,25020 +San Zeno Naviglio,17173,Brescia,BS,Lombardia,3,25010 +Sarezzo,17174,Brescia,BS,Lombardia,3,25068 +Saviore dell'Adamello,17175,Brescia,BS,Lombardia,3,25040 +Sellero,17176,Brescia,BS,Lombardia,3,25050 +Seniga,17177,Brescia,BS,Lombardia,3,25020 +Serle,17178,Brescia,BS,Lombardia,3,25080 +Sirmione,17179,Brescia,BS,Lombardia,3,25019 +Soiano del Lago,17180,Brescia,BS,Lombardia,3,25080 +Sonico,17181,Brescia,BS,Lombardia,3,25048 +Sulzano,17182,Brescia,BS,Lombardia,3,25058 +Tavernole sul Mella,17183,Brescia,BS,Lombardia,3,25060 +Temù,17184,Brescia,BS,Lombardia,3,25050 +Tignale,17185,Brescia,BS,Lombardia,3,25080 +Torbole Casaglia,17186,Brescia,BS,Lombardia,3,25030 +Toscolano-Maderno,17187,Brescia,BS,Lombardia,3,25088 +Travagliato,17188,Brescia,BS,Lombardia,3,25039 +Tremosine sul Garda,17189,Brescia,BS,Lombardia,3,25010 +Trenzano,17190,Brescia,BS,Lombardia,3,25030 +Treviso Bresciano,17191,Brescia,BS,Lombardia,3,25070 +Urago d'Oglio,17192,Brescia,BS,Lombardia,3,25030 +Vallio Terme,17193,Brescia,BS,Lombardia,3,25080 +Valvestino,17194,Brescia,BS,Lombardia,3,25080 +Verolanuova,17195,Brescia,BS,Lombardia,3,25028 +Verolavecchia,17196,Brescia,BS,Lombardia,3,25029 +Vestone,17197,Brescia,BS,Lombardia,3,25078 +Vezza d'Oglio,17198,Brescia,BS,Lombardia,3,25059 +Villa Carcina,17199,Brescia,BS,Lombardia,3,25069 +Villachiara,17200,Brescia,BS,Lombardia,3,25030 +Villanuova sul Clisi,17201,Brescia,BS,Lombardia,3,25089 +Vione,17202,Brescia,BS,Lombardia,3,25050 +Visano,17203,Brescia,BS,Lombardia,3,25010 +Vobarno,17204,Brescia,BS,Lombardia,3,25079 +Zone,17205,Brescia,BS,Lombardia,3,25050 +Piancogno,17206,Brescia,BS,Lombardia,3,25052 +Alagna,18001,Pavia,PV,Lombardia,3,27020 +Albaredo Arnaboldi,18002,Pavia,PV,Lombardia,3,27040 +Albonese,18003,Pavia,PV,Lombardia,3,27020 +Albuzzano,18004,Pavia,PV,Lombardia,3,27010 +Arena Po,18005,Pavia,PV,Lombardia,3,27040 +Badia Pavese,18006,Pavia,PV,Lombardia,3,27010 +Bagnaria,18007,Pavia,PV,Lombardia,3,27050 +Barbianello,18008,Pavia,PV,Lombardia,3,27041 +Bascapè,18009,Pavia,PV,Lombardia,3,27010 +Bastida Pancarana,18011,Pavia,PV,Lombardia,3,27050 +Battuda,18012,Pavia,PV,Lombardia,3,27020 +Belgioioso,18013,Pavia,PV,Lombardia,3,27011 +Bereguardo,18014,Pavia,PV,Lombardia,3,27021 +Borgarello,18015,Pavia,PV,Lombardia,3,27010 +Borgo Priolo,18016,Pavia,PV,Lombardia,3,27040 +Borgoratto Mormorolo,18017,Pavia,PV,Lombardia,3,27040 +Borgo San Siro,18018,Pavia,PV,Lombardia,3,27020 +Bornasco,18019,Pavia,PV,Lombardia,3,27010 +Bosnasco,18020,Pavia,PV,Lombardia,3,27040 +Brallo di Pregola,18021,Pavia,PV,Lombardia,3,27050 +Breme,18022,Pavia,PV,Lombardia,3,27020 +Bressana Bottarone,18023,Pavia,PV,Lombardia,3,27042 +Broni,18024,Pavia,PV,Lombardia,3,27043 +Calvignano,18025,Pavia,PV,Lombardia,3,27040 +Campospinoso,18026,Pavia,PV,Lombardia,3,27040 +Candia Lomellina,18027,Pavia,PV,Lombardia,3,27031 +Canneto Pavese,18029,Pavia,PV,Lombardia,3,27044 +Carbonara al Ticino,18030,Pavia,PV,Lombardia,3,27020 +Casanova Lonati,18031,Pavia,PV,Lombardia,3,27041 +Casatisma,18032,Pavia,PV,Lombardia,3,27040 +Casei Gerola,18033,Pavia,PV,Lombardia,3,27050 +Casorate Primo,18034,Pavia,PV,Lombardia,3,27022 +Cassolnovo,18035,Pavia,PV,Lombardia,3,27023 +Castana,18036,Pavia,PV,Lombardia,3,27040 +Casteggio,18037,Pavia,PV,Lombardia,3,27045 +Castelletto di Branduzzo,18038,Pavia,PV,Lombardia,3,27040 +Castello d'Agogna,18039,Pavia,PV,Lombardia,3,27030 +Castelnovetto,18040,Pavia,PV,Lombardia,3,27030 +Cava Manara,18041,Pavia,PV,Lombardia,3,27051 +Cecima,18042,Pavia,PV,Lombardia,3,27050 +Ceranova,18043,Pavia,PV,Lombardia,3,27010 +Ceretto Lomellina,18044,Pavia,PV,Lombardia,3,27030 +Cergnago,18045,Pavia,PV,Lombardia,3,27020 +Certosa di Pavia,18046,Pavia,PV,Lombardia,3,27012 +Cervesina,18047,Pavia,PV,Lombardia,3,27050 +Chignolo Po,18048,Pavia,PV,Lombardia,3,27013 +Cigognola,18049,Pavia,PV,Lombardia,3,27040 +Cilavegna,18050,Pavia,PV,Lombardia,3,27024 +Codevilla,18051,Pavia,PV,Lombardia,3,27050 +Confienza,18052,Pavia,PV,Lombardia,3,27030 +Copiano,18053,Pavia,PV,Lombardia,3,27010 +Corana,18054,Pavia,PV,Lombardia,3,27050 +Corvino San Quirico,18057,Pavia,PV,Lombardia,3,27050 +Costa de' Nobili,18058,Pavia,PV,Lombardia,3,27010 +Cozzo,18059,Pavia,PV,Lombardia,3,27030 +Cura Carpignano,18060,Pavia,PV,Lombardia,3,27010 +Dorno,18061,Pavia,PV,Lombardia,3,27020 +Ferrera Erbognone,18062,Pavia,PV,Lombardia,3,27032 +Filighera,18063,Pavia,PV,Lombardia,3,27010 +Fortunago,18064,Pavia,PV,Lombardia,3,27040 +Frascarolo,18065,Pavia,PV,Lombardia,3,27030 +Galliavola,18066,Pavia,PV,Lombardia,3,27034 +Gambarana,18067,Pavia,PV,Lombardia,3,27030 +Gambolò,18068,Pavia,PV,Lombardia,3,27025 +Garlasco,18069,Pavia,PV,Lombardia,3,27026 +Gerenzago,18071,Pavia,PV,Lombardia,3,27010 +Giussago,18072,Pavia,PV,Lombardia,3,27010 +Godiasco Salice Terme,18073,Pavia,PV,Lombardia,3,27052 +Golferenzo,18074,Pavia,PV,Lombardia,3,27047 +Gravellona Lomellina,18075,Pavia,PV,Lombardia,3,27020 +Gropello Cairoli,18076,Pavia,PV,Lombardia,3,27027 +Inverno e Monteleone,18077,Pavia,PV,Lombardia,3,27010 +Landriano,18078,Pavia,PV,Lombardia,3,27015 +Langosco,18079,Pavia,PV,Lombardia,3,27030 +Lardirago,18080,Pavia,PV,Lombardia,3,27016 +Linarolo,18081,Pavia,PV,Lombardia,3,27010 +Lirio,18082,Pavia,PV,Lombardia,3,27040 +Lomello,18083,Pavia,PV,Lombardia,3,27034 +Lungavilla,18084,Pavia,PV,Lombardia,3,27053 +Magherno,18085,Pavia,PV,Lombardia,3,27010 +Marcignago,18086,Pavia,PV,Lombardia,3,27020 +Marzano,18087,Pavia,PV,Lombardia,3,27010 +Mede,18088,Pavia,PV,Lombardia,3,27035 +Menconico,18089,Pavia,PV,Lombardia,3,27050 +Mezzana Bigli,18090,Pavia,PV,Lombardia,3,27030 +Mezzana Rabattone,18091,Pavia,PV,Lombardia,3,27030 +Mezzanino,18092,Pavia,PV,Lombardia,3,27040 +Miradolo Terme,18093,Pavia,PV,Lombardia,3,27010 +Montalto Pavese,18094,Pavia,PV,Lombardia,3,27040 +Montebello della Battaglia,18095,Pavia,PV,Lombardia,3,27054 +Montecalvo Versiggia,18096,Pavia,PV,Lombardia,3,27047 +Montescano,18097,Pavia,PV,Lombardia,3,27040 +Montesegale,18098,Pavia,PV,Lombardia,3,27052 +Monticelli Pavese,18099,Pavia,PV,Lombardia,3,27010 +Montù Beccaria,18100,Pavia,PV,Lombardia,3,27040 +Mornico Losana,18101,Pavia,PV,Lombardia,3,27040 +Mortara,18102,Pavia,PV,Lombardia,3,27036 +Nicorvo,18103,Pavia,PV,Lombardia,3,27020 +Olevano di Lomellina,18104,Pavia,PV,Lombardia,3,27020 +Oliva Gessi,18105,Pavia,PV,Lombardia,3,27050 +Ottobiano,18106,Pavia,PV,Lombardia,3,27030 +Palestro,18107,Pavia,PV,Lombardia,3,27030 +Pancarana,18108,Pavia,PV,Lombardia,3,27050 +Parona,18109,Pavia,PV,Lombardia,3,27020 +Pavia,18110,Pavia,PV,Lombardia,3,27100 +Pietra de' Giorgi,18111,Pavia,PV,Lombardia,3,27040 +Pieve Albignola,18112,Pavia,PV,Lombardia,3,27030 +Pieve del Cairo,18113,Pavia,PV,Lombardia,3,27037 +Pieve Porto Morone,18114,Pavia,PV,Lombardia,3,27017 +Pinarolo Po,18115,Pavia,PV,Lombardia,3,27040 +Pizzale,18116,Pavia,PV,Lombardia,3,27050 +Ponte Nizza,18117,Pavia,PV,Lombardia,3,27050 +Portalbera,18118,Pavia,PV,Lombardia,3,27040 +Rea,18119,Pavia,PV,Lombardia,3,27040 +Redavalle,18120,Pavia,PV,Lombardia,3,27050 +Retorbido,18121,Pavia,PV,Lombardia,3,27050 +Rivanazzano Terme,18122,Pavia,PV,Lombardia,3,27055 +Robbio,18123,Pavia,PV,Lombardia,3,27038 +Robecco Pavese,18124,Pavia,PV,Lombardia,3,27042 +Rocca de' Giorgi,18125,Pavia,PV,Lombardia,3,27040 +Rocca Susella,18126,Pavia,PV,Lombardia,3,27052 +Rognano,18127,Pavia,PV,Lombardia,3,27010 +Romagnese,18128,Pavia,PV,Lombardia,3,27050 +Roncaro,18129,Pavia,PV,Lombardia,3,27010 +Rosasco,18130,Pavia,PV,Lombardia,3,27030 +Rovescala,18131,Pavia,PV,Lombardia,3,27040 +San Cipriano Po,18133,Pavia,PV,Lombardia,3,27043 +San Damiano al Colle,18134,Pavia,PV,Lombardia,3,27040 +San Genesio ed Uniti,18135,Pavia,PV,Lombardia,3,27010 +San Giorgio di Lomellina,18136,Pavia,PV,Lombardia,3,27020 +San Martino Siccomario,18137,Pavia,PV,Lombardia,3,27028 +Sannazzaro de' Burgondi,18138,Pavia,PV,Lombardia,3,27039 +Santa Cristina e Bissone,18139,Pavia,PV,Lombardia,3,27010 +Santa Giuletta,18140,Pavia,PV,Lombardia,3,27046 +Sant'Alessio con Vialone,18141,Pavia,PV,Lombardia,3,27016 +Santa Margherita di Staffora,18142,Pavia,PV,Lombardia,3,27050 +Santa Maria della Versa,18143,Pavia,PV,Lombardia,3,27047 +Sant'Angelo Lomellina,18144,Pavia,PV,Lombardia,3,27030 +San Zenone al Po,18145,Pavia,PV,Lombardia,3,27010 +Sartirana Lomellina,18146,Pavia,PV,Lombardia,3,27020 +Scaldasole,18147,Pavia,PV,Lombardia,3,27020 +Semiana,18148,Pavia,PV,Lombardia,3,27020 +Silvano Pietra,18149,Pavia,PV,Lombardia,3,27050 +Siziano,18150,Pavia,PV,Lombardia,3,27010 +Sommo,18151,Pavia,PV,Lombardia,3,27048 +Spessa,18152,Pavia,PV,Lombardia,3,27010 +Stradella,18153,Pavia,PV,Lombardia,3,27049 +Suardi,18154,Pavia,PV,Lombardia,3,27030 +Torrazza Coste,18155,Pavia,PV,Lombardia,3,27050 +Torre Beretti e Castellaro,18156,Pavia,PV,Lombardia,3,27030 +Torre d'Arese,18157,Pavia,PV,Lombardia,3,27010 +Torre de' Negri,18158,Pavia,PV,Lombardia,3,27011 +Torre d'Isola,18159,Pavia,PV,Lombardia,3,27020 +Torrevecchia Pia,18160,Pavia,PV,Lombardia,3,27010 +Torricella Verzate,18161,Pavia,PV,Lombardia,3,27050 +Travacò Siccomario,18162,Pavia,PV,Lombardia,3,27020 +Trivolzio,18163,Pavia,PV,Lombardia,3,27020 +Tromello,18164,Pavia,PV,Lombardia,3,27020 +Trovo,18165,Pavia,PV,Lombardia,3,27020 +Val di Nizza,18166,Pavia,PV,Lombardia,3,27050 +Valeggio,18167,Pavia,PV,Lombardia,3,27020 +Valle Lomellina,18168,Pavia,PV,Lombardia,3,27020 +Valle Salimbene,18169,Pavia,PV,Lombardia,3,27010 +Varzi,18171,Pavia,PV,Lombardia,3,27057 +Velezzo Lomellina,18172,Pavia,PV,Lombardia,3,27020 +Vellezzo Bellini,18173,Pavia,PV,Lombardia,3,27010 +Verretto,18174,Pavia,PV,Lombardia,3,27053 +Verrua Po,18175,Pavia,PV,Lombardia,3,27040 +Vidigulfo,18176,Pavia,PV,Lombardia,3,27018 +Vigevano,18177,Pavia,PV,Lombardia,3,27029 +Villa Biscossi,18178,Pavia,PV,Lombardia,3,27035 +Villanova d'Ardenghi,18179,Pavia,PV,Lombardia,3,27030 +Villanterio,18180,Pavia,PV,Lombardia,3,27019 +Vistarino,18181,Pavia,PV,Lombardia,3,27010 +Voghera,18182,Pavia,PV,Lombardia,3,27058 +Volpara,18183,Pavia,PV,Lombardia,3,27047 +Zavattarello,18184,Pavia,PV,Lombardia,3,27059 +Zeccone,18185,Pavia,PV,Lombardia,3,27010 +Zeme,18186,Pavia,PV,Lombardia,3,27030 +Zenevredo,18187,Pavia,PV,Lombardia,3,27049 +Zerbo,18188,Pavia,PV,Lombardia,3,27017 +Zerbolò,18189,Pavia,PV,Lombardia,3,27020 +Zinasco,18190,Pavia,PV,Lombardia,3,27030 +Cornale e Bastida,18191,Pavia,PV,Lombardia,3,27056 +Corteolona e Genzone,18192,Pavia,PV,Lombardia,3,27014 +Colli Verdi,18193,Pavia,PV,Lombardia,3,27061 +Acquanegra Cremonese,19001,Cremona,CR,Lombardia,3,26020 +Agnadello,19002,Cremona,CR,Lombardia,3,26020 +Annicco,19003,Cremona,CR,Lombardia,3,26021 +Azzanello,19004,Cremona,CR,Lombardia,3,26010 +Bagnolo Cremasco,19005,Cremona,CR,Lombardia,3,26010 +Bonemerse,19006,Cremona,CR,Lombardia,3,26040 +Bordolano,19007,Cremona,CR,Lombardia,3,26020 +Calvatone,19009,Cremona,CR,Lombardia,3,26030 +Camisano,19010,Cremona,CR,Lombardia,3,26010 +Campagnola Cremasca,19011,Cremona,CR,Lombardia,3,26010 +Capergnanica,19012,Cremona,CR,Lombardia,3,26010 +Cappella Cantone,19013,Cremona,CR,Lombardia,3,26020 +Cappella de' Picenardi,19014,Cremona,CR,Lombardia,3,26030 +Capralba,19015,Cremona,CR,Lombardia,3,26010 +Casalbuttano ed Uniti,19016,Cremona,CR,Lombardia,3,26011 +Casale Cremasco-Vidolasco,19017,Cremona,CR,Lombardia,3,26010 +Casaletto Ceredano,19018,Cremona,CR,Lombardia,3,26010 +Casaletto di Sopra,19019,Cremona,CR,Lombardia,3,26014 +Casaletto Vaprio,19020,Cremona,CR,Lombardia,3,26010 +Casalmaggiore,19021,Cremona,CR,Lombardia,3,26041 +Casalmorano,19022,Cremona,CR,Lombardia,3,26020 +Casteldidone,19023,Cremona,CR,Lombardia,3,26030 +Castel Gabbiano,19024,Cremona,CR,Lombardia,3,26010 +Castelleone,19025,Cremona,CR,Lombardia,3,26012 +Castelverde,19026,Cremona,CR,Lombardia,3,26022 +Castelvisconti,19027,Cremona,CR,Lombardia,3,26010 +Cella Dati,19028,Cremona,CR,Lombardia,3,26040 +Chieve,19029,Cremona,CR,Lombardia,3,26010 +Cicognolo,19030,Cremona,CR,Lombardia,3,26030 +Cingia de' Botti,19031,Cremona,CR,Lombardia,3,26042 +Corte de' Cortesi con Cignone,19032,Cremona,CR,Lombardia,3,26020 +Corte de' Frati,19033,Cremona,CR,Lombardia,3,26010 +Credera Rubbiano,19034,Cremona,CR,Lombardia,3,26010 +Crema,19035,Cremona,CR,Lombardia,3,26013 +Cremona,19036,Cremona,CR,Lombardia,3,26100 +Cremosano,19037,Cremona,CR,Lombardia,3,26010 +Crotta d'Adda,19038,Cremona,CR,Lombardia,3,26020 +Cumignano sul Naviglio,19039,Cremona,CR,Lombardia,3,26020 +Derovere,19040,Cremona,CR,Lombardia,3,26040 +Dovera,19041,Cremona,CR,Lombardia,3,26010 +Fiesco,19043,Cremona,CR,Lombardia,3,26010 +Formigara,19044,Cremona,CR,Lombardia,3,26020 +Gabbioneta-Binanuova,19045,Cremona,CR,Lombardia,3,26030 +Gadesco-Pieve Delmona,19046,Cremona,CR,Lombardia,3,26030 +Genivolta,19047,Cremona,CR,Lombardia,3,26020 +Gerre de' Caprioli,19048,Cremona,CR,Lombardia,3,26040 +Gombito,19049,Cremona,CR,Lombardia,3,26020 +Grontardo,19050,Cremona,CR,Lombardia,3,26044 +Grumello Cremonese ed Uniti,19051,Cremona,CR,Lombardia,3,26023 +Gussola,19052,Cremona,CR,Lombardia,3,26040 +Isola Dovarese,19053,Cremona,CR,Lombardia,3,26031 +Izano,19054,Cremona,CR,Lombardia,3,26010 +Madignano,19055,Cremona,CR,Lombardia,3,26020 +Malagnino,19056,Cremona,CR,Lombardia,3,26030 +Martignana di Po,19057,Cremona,CR,Lombardia,3,26040 +Monte Cremasco,19058,Cremona,CR,Lombardia,3,26010 +Montodine,19059,Cremona,CR,Lombardia,3,26010 +Moscazzano,19060,Cremona,CR,Lombardia,3,26010 +Motta Baluffi,19061,Cremona,CR,Lombardia,3,26045 +Offanengo,19062,Cremona,CR,Lombardia,3,26010 +Olmeneta,19063,Cremona,CR,Lombardia,3,26010 +Ostiano,19064,Cremona,CR,Lombardia,3,26032 +Paderno Ponchielli,19065,Cremona,CR,Lombardia,3,26024 +Palazzo Pignano,19066,Cremona,CR,Lombardia,3,26020 +Pandino,19067,Cremona,CR,Lombardia,3,26025 +Persico Dosimo,19068,Cremona,CR,Lombardia,3,26043 +Pescarolo ed Uniti,19069,Cremona,CR,Lombardia,3,26033 +Pessina Cremonese,19070,Cremona,CR,Lombardia,3,26030 +Pianengo,19072,Cremona,CR,Lombardia,3,26010 +Pieranica,19073,Cremona,CR,Lombardia,3,26017 +Pieve d'Olmi,19074,Cremona,CR,Lombardia,3,26040 +Pieve San Giacomo,19075,Cremona,CR,Lombardia,3,26035 +Pizzighettone,19076,Cremona,CR,Lombardia,3,26026 +Pozzaglio ed Uniti,19077,Cremona,CR,Lombardia,3,26010 +Quintano,19078,Cremona,CR,Lombardia,3,26017 +Ricengo,19079,Cremona,CR,Lombardia,3,26010 +Ripalta Arpina,19080,Cremona,CR,Lombardia,3,26010 +Ripalta Cremasca,19081,Cremona,CR,Lombardia,3,26010 +Ripalta Guerina,19082,Cremona,CR,Lombardia,3,26010 +Rivarolo del Re ed Uniti,19083,Cremona,CR,Lombardia,3,26036 +Rivolta d'Adda,19084,Cremona,CR,Lombardia,3,26027 +Robecco d'Oglio,19085,Cremona,CR,Lombardia,3,26010 +Romanengo,19086,Cremona,CR,Lombardia,3,26014 +Salvirola,19087,Cremona,CR,Lombardia,3,26010 +San Bassano,19088,Cremona,CR,Lombardia,3,26020 +San Daniele Po,19089,Cremona,CR,Lombardia,3,26046 +San Giovanni in Croce,19090,Cremona,CR,Lombardia,3,26037 +San Martino del Lago,19091,Cremona,CR,Lombardia,3,26040 +Scandolara Ravara,19092,Cremona,CR,Lombardia,3,26040 +Scandolara Ripa d'Oglio,19093,Cremona,CR,Lombardia,3,26047 +Sergnano,19094,Cremona,CR,Lombardia,3,26010 +Sesto ed Uniti,19095,Cremona,CR,Lombardia,3,26028 +Solarolo Rainerio,19096,Cremona,CR,Lombardia,3,26030 +Soncino,19097,Cremona,CR,Lombardia,3,26029 +Soresina,19098,Cremona,CR,Lombardia,3,26015 +Sospiro,19099,Cremona,CR,Lombardia,3,26048 +Spinadesco,19100,Cremona,CR,Lombardia,3,26020 +Spineda,19101,Cremona,CR,Lombardia,3,26030 +Spino d'Adda,19102,Cremona,CR,Lombardia,3,26016 +Stagno Lombardo,19103,Cremona,CR,Lombardia,3,26049 +Ticengo,19104,Cremona,CR,Lombardia,3,26020 +Torlino Vimercati,19105,Cremona,CR,Lombardia,3,26017 +Tornata,19106,Cremona,CR,Lombardia,3,26030 +Torre de' Picenardi,19107,Cremona,CR,Lombardia,3,26038 +Torricella del Pizzo,19108,Cremona,CR,Lombardia,3,26040 +Trescore Cremasco,19109,Cremona,CR,Lombardia,3,26017 +Trigolo,19110,Cremona,CR,Lombardia,3,26018 +Vaiano Cremasco,19111,Cremona,CR,Lombardia,3,26010 +Vailate,19112,Cremona,CR,Lombardia,3,26019 +Vescovato,19113,Cremona,CR,Lombardia,3,26039 +Volongo,19114,Cremona,CR,Lombardia,3,26030 +Voltido,19115,Cremona,CR,Lombardia,3,26030 +Piadena Drizzona,19116,Cremona,CR,Lombardia,3,26034 +Acquanegra sul Chiese,20001,Mantova,MN,Lombardia,3,46011 +Asola,20002,Mantova,MN,Lombardia,3,46041 +Bagnolo San Vito,20003,Mantova,MN,Lombardia,3,46031 +Bozzolo,20007,Mantova,MN,Lombardia,3,46012 +Canneto sull'Oglio,20008,Mantova,MN,Lombardia,3,46013 +Casalmoro,20010,Mantova,MN,Lombardia,3,46040 +Casaloldo,20011,Mantova,MN,Lombardia,3,46040 +Casalromano,20012,Mantova,MN,Lombardia,3,46040 +Castelbelforte,20013,Mantova,MN,Lombardia,3,46032 +Castel d'Ario,20014,Mantova,MN,Lombardia,3,46033 +Castel Goffredo,20015,Mantova,MN,Lombardia,3,46042 +Castellucchio,20016,Mantova,MN,Lombardia,3,46014 +Castiglione delle Stiviere,20017,Mantova,MN,Lombardia,3,46043 +Cavriana,20018,Mantova,MN,Lombardia,3,46040 +Ceresara,20019,Mantova,MN,Lombardia,3,46040 +Commessaggio,20020,Mantova,MN,Lombardia,3,46010 +Curtatone,20021,Mantova,MN,Lombardia,3,46010 +Dosolo,20022,Mantova,MN,Lombardia,3,46030 +Gazoldo degli Ippoliti,20024,Mantova,MN,Lombardia,3,46040 +Gazzuolo,20025,Mantova,MN,Lombardia,3,46010 +Goito,20026,Mantova,MN,Lombardia,3,46044 +Gonzaga,20027,Mantova,MN,Lombardia,3,46023 +Guidizzolo,20028,Mantova,MN,Lombardia,3,46040 +Magnacavallo,20029,Mantova,MN,Lombardia,3,46020 +Mantova,20030,Mantova,MN,Lombardia,3,46100 +Marcaria,20031,Mantova,MN,Lombardia,3,46010 +Mariana Mantovana,20032,Mantova,MN,Lombardia,3,46010 +Marmirolo,20033,Mantova,MN,Lombardia,3,46045 +Medole,20034,Mantova,MN,Lombardia,3,46046 +Moglia,20035,Mantova,MN,Lombardia,3,46024 +Monzambano,20036,Mantova,MN,Lombardia,3,46040 +Motteggiana,20037,Mantova,MN,Lombardia,3,46020 +Ostiglia,20038,Mantova,MN,Lombardia,3,46035 +Pegognaga,20039,Mantova,MN,Lombardia,3,46020 +Piubega,20041,Mantova,MN,Lombardia,3,46040 +Poggio Rusco,20042,Mantova,MN,Lombardia,3,46025 +Pomponesco,20043,Mantova,MN,Lombardia,3,46030 +Ponti sul Mincio,20044,Mantova,MN,Lombardia,3,46040 +Porto Mantovano,20045,Mantova,MN,Lombardia,3,46047 +Quingentole,20046,Mantova,MN,Lombardia,3,46020 +Quistello,20047,Mantova,MN,Lombardia,3,46026 +Redondesco,20048,Mantova,MN,Lombardia,3,46010 +Rivarolo Mantovano,20050,Mantova,MN,Lombardia,3,46017 +Rodigo,20051,Mantova,MN,Lombardia,3,46040 +Roncoferraro,20052,Mantova,MN,Lombardia,3,46037 +Roverbella,20053,Mantova,MN,Lombardia,3,46048 +Sabbioneta,20054,Mantova,MN,Lombardia,3,46018 +San Benedetto Po,20055,Mantova,MN,Lombardia,3,46027 +San Giacomo delle Segnate,20056,Mantova,MN,Lombardia,3,46020 +San Giorgio Bigarello,20057,Mantova,MN,Lombardia,3,46030 +San Giovanni del Dosso,20058,Mantova,MN,Lombardia,3,46020 +San Martino dall'Argine,20059,Mantova,MN,Lombardia,3,46010 +Schivenoglia,20060,Mantova,MN,Lombardia,3,46020 +Sermide e Felonica,20061,Mantova,MN,Lombardia,3,46028 +Serravalle a Po,20062,Mantova,MN,Lombardia,3,46030 +Solferino,20063,Mantova,MN,Lombardia,3,46040 +Sustinente,20064,Mantova,MN,Lombardia,3,46030 +Suzzara,20065,Mantova,MN,Lombardia,3,46029 +Viadana,20066,Mantova,MN,Lombardia,3,46019 +Villimpenta,20068,Mantova,MN,Lombardia,3,46039 +Volta Mantovana,20070,Mantova,MN,Lombardia,3,46049 +Borgo Virgilio,20071,Mantova,MN,Lombardia,3,46034 +Borgo Mantovano,20072,Mantova,MN,Lombardia,3,46036 +Borgocarbonara,20073,Mantova,MN,Lombardia,3,46020 +Abbadia Lariana,97001,Lecco,LC,Lombardia,3,23821 +Airuno,97002,Lecco,LC,Lombardia,3,23881 +Annone di Brianza,97003,Lecco,LC,Lombardia,3,23841 +Ballabio,97004,Lecco,LC,Lombardia,3,23811 +Barzago,97005,Lecco,LC,Lombardia,3,23890 +Barzanò,97006,Lecco,LC,Lombardia,3,23891 +Barzio,97007,Lecco,LC,Lombardia,3,23816 +Bellano,97008,Lecco,LC,Lombardia,3,23822 +Bosisio Parini,97009,Lecco,LC,Lombardia,3,23842 +Brivio,97010,Lecco,LC,Lombardia,3,23883 +Bulciago,97011,Lecco,LC,Lombardia,3,23892 +Calco,97012,Lecco,LC,Lombardia,3,23885 +Calolziocorte,97013,Lecco,LC,Lombardia,3,23801 +Carenno,97014,Lecco,LC,Lombardia,3,23802 +Casargo,97015,Lecco,LC,Lombardia,3,23831 +Casatenovo,97016,Lecco,LC,Lombardia,3,23880 +Cassago Brianza,97017,Lecco,LC,Lombardia,3,23893 +Cassina Valsassina,97018,Lecco,LC,Lombardia,3,23817 +Castello di Brianza,97019,Lecco,LC,Lombardia,3,23884 +Cernusco Lombardone,97020,Lecco,LC,Lombardia,3,23870 +Cesana Brianza,97021,Lecco,LC,Lombardia,3,23861 +Civate,97022,Lecco,LC,Lombardia,3,23862 +Colico,97023,Lecco,LC,Lombardia,3,23823 +Colle Brianza,97024,Lecco,LC,Lombardia,3,23886 +Cortenova,97025,Lecco,LC,Lombardia,3,23813 +Costa Masnaga,97026,Lecco,LC,Lombardia,3,23845 +Crandola Valsassina,97027,Lecco,LC,Lombardia,3,23832 +Cremella,97028,Lecco,LC,Lombardia,3,23894 +Cremeno,97029,Lecco,LC,Lombardia,3,23814 +Dervio,97030,Lecco,LC,Lombardia,3,23824 +Dolzago,97031,Lecco,LC,Lombardia,3,23843 +Dorio,97032,Lecco,LC,Lombardia,3,23824 +Ello,97033,Lecco,LC,Lombardia,3,23848 +Erve,97034,Lecco,LC,Lombardia,3,23805 +Esino Lario,97035,Lecco,LC,Lombardia,3,23825 +Galbiate,97036,Lecco,LC,Lombardia,3,23851 +Garbagnate Monastero,97037,Lecco,LC,Lombardia,3,23846 +Garlate,97038,Lecco,LC,Lombardia,3,23852 +Imbersago,97039,Lecco,LC,Lombardia,3,23898 +Introbio,97040,Lecco,LC,Lombardia,3,23815 +Lecco,97042,Lecco,LC,Lombardia,3,23900 +Lierna,97043,Lecco,LC,Lombardia,3,23827 +Lomagna,97044,Lecco,LC,Lombardia,3,23871 +Malgrate,97045,Lecco,LC,Lombardia,3,23864 +Mandello del Lario,97046,Lecco,LC,Lombardia,3,23826 +Margno,97047,Lecco,LC,Lombardia,3,23832 +Merate,97048,Lecco,LC,Lombardia,3,23807 +Missaglia,97049,Lecco,LC,Lombardia,3,23873 +Moggio,97050,Lecco,LC,Lombardia,3,23817 +Molteno,97051,Lecco,LC,Lombardia,3,23847 +Monte Marenzo,97052,Lecco,LC,Lombardia,3,23804 +Montevecchia,97053,Lecco,LC,Lombardia,3,23874 +Monticello Brianza,97054,Lecco,LC,Lombardia,3,23876 +Morterone,97055,Lecco,LC,Lombardia,3,23811 +Nibionno,97056,Lecco,LC,Lombardia,3,23895 +Oggiono,97057,Lecco,LC,Lombardia,3,23848 +Olgiate Molgora,97058,Lecco,LC,Lombardia,3,23887 +Olginate,97059,Lecco,LC,Lombardia,3,23854 +Oliveto Lario,97060,Lecco,LC,Lombardia,3,23865 +Osnago,97061,Lecco,LC,Lombardia,3,23875 +Paderno d'Adda,97062,Lecco,LC,Lombardia,3,23877 +Pagnona,97063,Lecco,LC,Lombardia,3,23833 +Parlasco,97064,Lecco,LC,Lombardia,3,23837 +Pasturo,97065,Lecco,LC,Lombardia,3,23818 +Perledo,97067,Lecco,LC,Lombardia,3,23828 +Pescate,97068,Lecco,LC,Lombardia,3,23855 +Premana,97069,Lecco,LC,Lombardia,3,23834 +Primaluna,97070,Lecco,LC,Lombardia,3,23819 +Robbiate,97071,Lecco,LC,Lombardia,3,23899 +Rogeno,97072,Lecco,LC,Lombardia,3,23849 +Santa Maria Hoè,97074,Lecco,LC,Lombardia,3,23889 +Sirone,97075,Lecco,LC,Lombardia,3,23844 +Sirtori,97076,Lecco,LC,Lombardia,3,23896 +Sueglio,97077,Lecco,LC,Lombardia,3,23835 +Suello,97078,Lecco,LC,Lombardia,3,23867 +Taceno,97079,Lecco,LC,Lombardia,3,23837 +Valgreghentino,97082,Lecco,LC,Lombardia,3,23857 +Valmadrera,97083,Lecco,LC,Lombardia,3,23868 +Varenna,97084,Lecco,LC,Lombardia,3,23829 +Vercurago,97086,Lecco,LC,Lombardia,3,23808 +Viganò,97090,Lecco,LC,Lombardia,3,23897 +Verderio,97091,Lecco,LC,Lombardia,3,23879 +La Valletta Brianza,97092,Lecco,LC,Lombardia,3,23888 +Valvarrone,97093,Lecco,LC,Lombardia,3,23836 +Abbadia Cerreto,98001,Lodi,LO,Lombardia,3,26834 +Bertonico,98002,Lodi,LO,Lombardia,3,26821 +Boffalora d'Adda,98003,Lodi,LO,Lombardia,3,26811 +Borghetto Lodigiano,98004,Lodi,LO,Lombardia,3,26812 +Borgo San Giovanni,98005,Lodi,LO,Lombardia,3,26851 +Brembio,98006,Lodi,LO,Lombardia,3,26822 +Casaletto Lodigiano,98008,Lodi,LO,Lombardia,3,26852 +Casalmaiocco,98009,Lodi,LO,Lombardia,3,26831 +Casalpusterlengo,98010,Lodi,LO,Lombardia,3,26841 +Caselle Landi,98011,Lodi,LO,Lombardia,3,26842 +Caselle Lurani,98012,Lodi,LO,Lombardia,3,26853 +Castelnuovo Bocca d'Adda,98013,Lodi,LO,Lombardia,3,26843 +Castiglione d'Adda,98014,Lodi,LO,Lombardia,3,26823 +Castiraga Vidardo,98015,Lodi,LO,Lombardia,3,26866 +Cavenago d'Adda,98017,Lodi,LO,Lombardia,3,26824 +Cervignano d'Adda,98018,Lodi,LO,Lombardia,3,26832 +Codogno,98019,Lodi,LO,Lombardia,3,26845 +Comazzo,98020,Lodi,LO,Lombardia,3,26833 +Cornegliano Laudense,98021,Lodi,LO,Lombardia,3,26854 +Corno Giovine,98022,Lodi,LO,Lombardia,3,26846 +Cornovecchio,98023,Lodi,LO,Lombardia,3,26842 +Corte Palasio,98024,Lodi,LO,Lombardia,3,26834 +Crespiatica,98025,Lodi,LO,Lombardia,3,26835 +Fombio,98026,Lodi,LO,Lombardia,3,26861 +Galgagnano,98027,Lodi,LO,Lombardia,3,26832 +Graffignana,98028,Lodi,LO,Lombardia,3,26813 +Guardamiglio,98029,Lodi,LO,Lombardia,3,26862 +Livraga,98030,Lodi,LO,Lombardia,3,26814 +Lodi,98031,Lodi,LO,Lombardia,3,26900 +Lodi Vecchio,98032,Lodi,LO,Lombardia,3,26855 +Maccastorna,98033,Lodi,LO,Lombardia,3,26843 +Mairago,98034,Lodi,LO,Lombardia,3,26825 +Maleo,98035,Lodi,LO,Lombardia,3,26847 +Marudo,98036,Lodi,LO,Lombardia,3,26866 +Massalengo,98037,Lodi,LO,Lombardia,3,26815 +Meleti,98038,Lodi,LO,Lombardia,3,26843 +Merlino,98039,Lodi,LO,Lombardia,3,26833 +Montanaso Lombardo,98040,Lodi,LO,Lombardia,3,26836 +Mulazzano,98041,Lodi,LO,Lombardia,3,26837 +Orio Litta,98042,Lodi,LO,Lombardia,3,26863 +Ospedaletto Lodigiano,98043,Lodi,LO,Lombardia,3,26864 +Ossago Lodigiano,98044,Lodi,LO,Lombardia,3,26816 +Pieve Fissiraga,98045,Lodi,LO,Lombardia,3,26854 +Salerano sul Lambro,98046,Lodi,LO,Lombardia,3,26857 +San Fiorano,98047,Lodi,LO,Lombardia,3,26848 +San Martino in Strada,98048,Lodi,LO,Lombardia,3,26817 +San Rocco al Porto,98049,Lodi,LO,Lombardia,3,26865 +Sant'Angelo Lodigiano,98050,Lodi,LO,Lombardia,3,26866 +Santo Stefano Lodigiano,98051,Lodi,LO,Lombardia,3,26849 +Secugnago,98052,Lodi,LO,Lombardia,3,26826 +Senna Lodigiana,98053,Lodi,LO,Lombardia,3,26856 +Somaglia,98054,Lodi,LO,Lombardia,3,26867 +Sordio,98055,Lodi,LO,Lombardia,3,26858 +Tavazzano con Villavesco,98056,Lodi,LO,Lombardia,3,26838 +Terranova dei Passerini,98057,Lodi,LO,Lombardia,3,26827 +Turano Lodigiano,98058,Lodi,LO,Lombardia,3,26828 +Valera Fratta,98059,Lodi,LO,Lombardia,3,26859 +Villanova del Sillaro,98060,Lodi,LO,Lombardia,3,26818 +Zelo Buon Persico,98061,Lodi,LO,Lombardia,3,26839 +Castelgerundo,98062,Lodi,LO,Lombardia,3,26844 +Agrate Brianza,108001,Monza e della Brianza,MB,Lombardia,3,20864 +Aicurzio,108002,Monza e della Brianza,MB,Lombardia,3,20886 +Albiate,108003,Monza e della Brianza,MB,Lombardia,3,20847 +Arcore,108004,Monza e della Brianza,MB,Lombardia,3,20862 +Barlassina,108005,Monza e della Brianza,MB,Lombardia,3,20825 +Bellusco,108006,Monza e della Brianza,MB,Lombardia,3,20882 +Bernareggio,108007,Monza e della Brianza,MB,Lombardia,3,20881 +Besana in Brianza,108008,Monza e della Brianza,MB,Lombardia,3,20842 +Biassono,108009,Monza e della Brianza,MB,Lombardia,3,20853 +Bovisio-Masciago,108010,Monza e della Brianza,MB,Lombardia,3,20813 +Briosco,108011,Monza e della Brianza,MB,Lombardia,3,20836 +Brugherio,108012,Monza e della Brianza,MB,Lombardia,3,20861 +Burago di Molgora,108013,Monza e della Brianza,MB,Lombardia,3,20875 +Camparada,108014,Monza e della Brianza,MB,Lombardia,3,20857 +Carate Brianza,108015,Monza e della Brianza,MB,Lombardia,3,20841 +Carnate,108016,Monza e della Brianza,MB,Lombardia,3,20866 +Cavenago di Brianza,108017,Monza e della Brianza,MB,Lombardia,3,20873 +Ceriano Laghetto,108018,Monza e della Brianza,MB,Lombardia,3,20816 +Cesano Maderno,108019,Monza e della Brianza,MB,Lombardia,3,20811 +Cogliate,108020,Monza e della Brianza,MB,Lombardia,3,20815 +Concorezzo,108021,Monza e della Brianza,MB,Lombardia,3,20863 +Correzzana,108022,Monza e della Brianza,MB,Lombardia,3,20856 +Desio,108023,Monza e della Brianza,MB,Lombardia,3,20832 +Giussano,108024,Monza e della Brianza,MB,Lombardia,3,20833 +Lazzate,108025,Monza e della Brianza,MB,Lombardia,3,20824 +Lesmo,108026,Monza e della Brianza,MB,Lombardia,3,20855 +Limbiate,108027,Monza e della Brianza,MB,Lombardia,3,20812 +Lissone,108028,Monza e della Brianza,MB,Lombardia,3,20851 +Macherio,108029,Monza e della Brianza,MB,Lombardia,3,20846 +Meda,108030,Monza e della Brianza,MB,Lombardia,3,20821 +Mezzago,108031,Monza e della Brianza,MB,Lombardia,3,20883 +Misinto,108032,Monza e della Brianza,MB,Lombardia,3,20826 +Monza,108033,Monza e della Brianza,MB,Lombardia,3,20900 +Muggiò,108034,Monza e della Brianza,MB,Lombardia,3,20835 +Nova Milanese,108035,Monza e della Brianza,MB,Lombardia,3,20834 +Ornago,108036,Monza e della Brianza,MB,Lombardia,3,20876 +Renate,108037,Monza e della Brianza,MB,Lombardia,3,20838 +Ronco Briantino,108038,Monza e della Brianza,MB,Lombardia,3,20885 +Seregno,108039,Monza e della Brianza,MB,Lombardia,3,20831 +Seveso,108040,Monza e della Brianza,MB,Lombardia,3,20822 +Sovico,108041,Monza e della Brianza,MB,Lombardia,3,20845 +Sulbiate,108042,Monza e della Brianza,MB,Lombardia,3,20884 +Triuggio,108043,Monza e della Brianza,MB,Lombardia,3,20844 +Usmate Velate,108044,Monza e della Brianza,MB,Lombardia,3,20865 +Varedo,108045,Monza e della Brianza,MB,Lombardia,3,20814 +Vedano al Lambro,108046,Monza e della Brianza,MB,Lombardia,3,20854 +Veduggio con Colzano,108047,Monza e della Brianza,MB,Lombardia,3,20837 +Verano Brianza,108048,Monza e della Brianza,MB,Lombardia,3,20843 +Villasanta,108049,Monza e della Brianza,MB,Lombardia,3,20852 +Vimercate,108050,Monza e della Brianza,MB,Lombardia,3,20871 +Busnago,108051,Monza e della Brianza,MB,Lombardia,3,20874 +Caponago,108052,Monza e della Brianza,MB,Lombardia,3,20867 +Cornate d'Adda,108053,Monza e della Brianza,MB,Lombardia,3,20872 +Lentate sul Seveso,108054,Monza e della Brianza,MB,Lombardia,3,20823 +Roncello,108055,Monza e della Brianza,MB,Lombardia,3,20877 +Aldino,21001,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Andriano,21002,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Anterivo,21003,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Appiano sulla strada del vino,21004,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39057 +Avelengo,21005,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Badia,21006,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39036 +Barbiano,21007,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Bolzano,21008,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39100 +Braies,21009,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Brennero,21010,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39041 +Bressanone,21011,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39042 +Bronzolo,21012,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39051 +Brunico,21013,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39031 +Caines,21014,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Caldaro sulla strada del vino,21015,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39052 +Campo di Trens,21016,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Campo Tures,21017,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39032 +Castelbello-Ciardes,21018,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39020 +Castelrotto,21019,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Cermes,21020,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Chienes,21021,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Chiusa,21022,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39043 +Cornedo all'Isarco,21023,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39053 +Cortaccia sulla strada del vino,21024,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Cortina sulla strada del vino,21025,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Corvara in Badia,21026,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39033 +Curon Venosta,21027,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39027 +Dobbiaco,21028,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39034 +Egna,21029,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39044 +Falzes,21030,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Fiè allo Sciliar,21031,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39050 +Fortezza,21032,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39045 +Funes,21033,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Gais,21034,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Gargazzone,21035,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Glorenza,21036,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39020 +Laces,21037,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39021 +Lagundo,21038,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39022 +Laion,21039,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Laives,21040,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39055 +Lana,21041,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39011 +Lasa,21042,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39023 +Lauregno,21043,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Luson,21044,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Magrè sulla strada del vino,21045,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Malles Venosta,21046,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39024 +Marebbe,21047,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Marlengo,21048,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39020 +Martello,21049,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39020 +Meltina,21050,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Merano,21051,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39012 +Monguelfo-Tesido,21052,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39035 +Montagna,21053,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Moso in Passiria,21054,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39013 +Nalles,21055,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Naturno,21056,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39025 +Naz-Sciaves,21057,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Nova Levante,21058,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39056 +Nova Ponente,21059,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39050 +Ora,21060,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Ortisei,21061,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39046 +Parcines,21062,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39020 +Perca,21063,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Plaus,21064,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39025 +Ponte Gardena,21065,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Postal,21066,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39014 +Prato allo Stelvio,21067,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39026 +Predoi,21068,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Proves,21069,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Racines,21070,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Rasun-Anterselva,21071,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Renon,21072,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39054 +Rifiano,21073,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Rio di Pusteria,21074,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39037 +Rodengo,21075,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39037 +Salorno sulla strada del vino,21076,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +San Candido,21077,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39038 +San Genesio Atesino,21079,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39050 +San Leonardo in Passiria,21080,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39015 +San Lorenzo di Sebato,21081,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +San Martino in Badia,21082,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +San Martino in Passiria,21083,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +San Pancrazio,21084,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Santa Cristina Valgardena,21085,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39047 +Sarentino,21086,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39058 +Scena,21087,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39017 +Selva dei Molini,21088,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Selva di Val Gardena,21089,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39048 +Senales,21091,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39020 +Sesto,21092,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Silandro,21093,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39028 +Sluderno,21094,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39020 +Stelvio,21095,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39029 +Terento,21096,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Terlano,21097,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39018 +Termeno sulla strada del vino,21098,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Tesimo,21099,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Tires,21100,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39050 +Tirolo,21101,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39019 +Trodena nel parco naturale,21102,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Tubre,21103,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39020 +Ultimo,21104,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39016 +Vadena,21105,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39051 +Valdaora,21106,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Val di Vizze,21107,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39049 +Valle Aurina,21108,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Valle di Casies,21109,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Vandoies,21110,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Varna,21111,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Verano,21112,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Villabassa,21113,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39039 +Villandro,21114,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +Vipiteno,21115,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39049 +Velturno,21116,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39040 +La Valle,21117,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39030 +Senale-San Felice,21118,Bolzano/Bozen,BZ,Trentino-Alto Adige/Südtirol,4,39010 +Ala,22001,Trento,TN,Trentino-Alto Adige/Südtirol,4,38061 +Albiano,22002,Trento,TN,Trentino-Alto Adige/Südtirol,4,38041 +Aldeno,22003,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Andalo,22005,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Arco,22006,Trento,TN,Trentino-Alto Adige/Südtirol,4,38062 +Avio,22007,Trento,TN,Trentino-Alto Adige/Südtirol,4,38063 +Baselga di Pinè,22009,Trento,TN,Trentino-Alto Adige/Südtirol,4,38042 +Bedollo,22011,Trento,TN,Trentino-Alto Adige/Südtirol,4,38043 +Besenello,22013,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Bieno,22015,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Bleggio Superiore,22017,Trento,TN,Trentino-Alto Adige/Südtirol,4,38071 +Bocenago,22018,Trento,TN,Trentino-Alto Adige/Südtirol,4,38080 +Bondone,22021,Trento,TN,Trentino-Alto Adige/Südtirol,4,38080 +Borgo Valsugana,22022,Trento,TN,Trentino-Alto Adige/Südtirol,4,38051 +Brentonico,22025,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Bresimo,22026,Trento,TN,Trentino-Alto Adige/Südtirol,4,38020 +Caderzone Terme,22029,Trento,TN,Trentino-Alto Adige/Südtirol,4,38080 +Calceranica al Lago,22032,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Caldes,22033,Trento,TN,Trentino-Alto Adige/Südtirol,4,38022 +Caldonazzo,22034,Trento,TN,Trentino-Alto Adige/Südtirol,4,38052 +Calliano,22035,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Campitello di Fassa,22036,Trento,TN,Trentino-Alto Adige/Südtirol,4,38031 +Campodenno,22037,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Canal San Bovo,22038,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Canazei,22039,Trento,TN,Trentino-Alto Adige/Südtirol,4,38032 +Capriana,22040,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Carisolo,22042,Trento,TN,Trentino-Alto Adige/Südtirol,4,38080 +Carzano,22043,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Castel Condino,22045,Trento,TN,Trentino-Alto Adige/Südtirol,4,38082 +Castello-Molina di Fiemme,22047,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Castello Tesino,22048,Trento,TN,Trentino-Alto Adige/Südtirol,4,38053 +Castelnuovo,22049,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Cavalese,22050,Trento,TN,Trentino-Alto Adige/Südtirol,4,38033 +Cavareno,22051,Trento,TN,Trentino-Alto Adige/Südtirol,4,38011 +Cavedago,22052,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Cavedine,22053,Trento,TN,Trentino-Alto Adige/Südtirol,4,38073 +Cavizzana,22054,Trento,TN,Trentino-Alto Adige/Südtirol,4,38022 +Cimone,22058,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Cinte Tesino,22059,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Cis,22060,Trento,TN,Trentino-Alto Adige/Südtirol,4,38020 +Civezzano,22061,Trento,TN,Trentino-Alto Adige/Südtirol,4,38045 +Cles,22062,Trento,TN,Trentino-Alto Adige/Südtirol,4,38023 +Commezzadura,22064,Trento,TN,Trentino-Alto Adige/Südtirol,4,38020 +Croviana,22068,Trento,TN,Trentino-Alto Adige/Südtirol,4,38027 +Dambel,22071,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Denno,22074,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Drena,22078,Trento,TN,Trentino-Alto Adige/Südtirol,4,38074 +Dro,22079,Trento,TN,Trentino-Alto Adige/Südtirol,4,38074 +Fai della Paganella,22081,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Fiavè,22083,Trento,TN,Trentino-Alto Adige/Südtirol,4,38075 +Fierozzo,22085,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Folgaria,22087,Trento,TN,Trentino-Alto Adige/Südtirol,4,38064 +Fornace,22089,Trento,TN,Trentino-Alto Adige/Südtirol,4,38040 +Frassilongo,22090,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Garniga Terme,22091,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Giovo,22092,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Giustino,22093,Trento,TN,Trentino-Alto Adige/Südtirol,4,38086 +Grigno,22095,Trento,TN,Trentino-Alto Adige/Südtirol,4,38055 +Imer,22097,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Isera,22098,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Lavarone,22102,Trento,TN,Trentino-Alto Adige/Südtirol,4,38046 +Lavis,22103,Trento,TN,Trentino-Alto Adige/Südtirol,4,38015 +Levico Terme,22104,Trento,TN,Trentino-Alto Adige/Südtirol,4,38056 +Livo,22106,Trento,TN,Trentino-Alto Adige/Südtirol,4,38020 +Lona-Lases,22108,Trento,TN,Trentino-Alto Adige/Südtirol,4,38040 +Luserna,22109,Trento,TN,Trentino-Alto Adige/Südtirol,4,38040 +Malé,22110,Trento,TN,Trentino-Alto Adige/Südtirol,4,38027 +Massimeno,22112,Trento,TN,Trentino-Alto Adige/Südtirol,4,38086 +Mazzin,22113,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Mezzana,22114,Trento,TN,Trentino-Alto Adige/Südtirol,4,38020 +Mezzano,22115,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Mezzocorona,22116,Trento,TN,Trentino-Alto Adige/Südtirol,4,38016 +Mezzolombardo,22117,Trento,TN,Trentino-Alto Adige/Südtirol,4,38017 +Moena,22118,Trento,TN,Trentino-Alto Adige/Südtirol,4,38035 +Molveno,22120,Trento,TN,Trentino-Alto Adige/Südtirol,4,38018 +Mori,22123,Trento,TN,Trentino-Alto Adige/Südtirol,4,38065 +Nago-Torbole,22124,Trento,TN,Trentino-Alto Adige/Südtirol,4,38069 +Nogaredo,22127,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Nomi,22128,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Novaledo,22129,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Ospedaletto,22130,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Ossana,22131,Trento,TN,Trentino-Alto Adige/Südtirol,4,38026 +Palù del Fersina,22133,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Panchià,22134,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Ronzo-Chienis,22135,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Peio,22136,Trento,TN,Trentino-Alto Adige/Südtirol,4,38024 +Pellizzano,22137,Trento,TN,Trentino-Alto Adige/Südtirol,4,38020 +Pelugo,22138,Trento,TN,Trentino-Alto Adige/Südtirol,4,38079 +Pergine Valsugana,22139,Trento,TN,Trentino-Alto Adige/Südtirol,4,38057 +Pieve Tesino,22142,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Pinzolo,22143,Trento,TN,Trentino-Alto Adige/Südtirol,4,38086 +Pomarolo,22144,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Predazzo,22147,Trento,TN,Trentino-Alto Adige/Südtirol,4,38037 +Rabbi,22150,Trento,TN,Trentino-Alto Adige/Südtirol,4,38020 +Riva del Garda,22153,Trento,TN,Trentino-Alto Adige/Südtirol,4,38066 +Romeno,22155,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Roncegno Terme,22156,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Ronchi Valsugana,22157,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Ronzone,22159,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Roverè della Luna,22160,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Rovereto,22161,Trento,TN,Trentino-Alto Adige/Südtirol,4,38068 +Ruffrè-Mendola,22162,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Rumo,22163,Trento,TN,Trentino-Alto Adige/Südtirol,4,38020 +Sagron Mis,22164,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Samone,22165,Trento,TN,Trentino-Alto Adige/Südtirol,4,38059 +San Michele all'Adige,22167,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Sant'Orsola Terme,22168,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Sanzeno,22169,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Sarnonico,22170,Trento,TN,Trentino-Alto Adige/Südtirol,4,38011 +Scurelle,22171,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Segonzano,22172,Trento,TN,Trentino-Alto Adige/Südtirol,4,38047 +Sfruz,22173,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Soraga di Fassa,22176,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Sover,22177,Trento,TN,Trentino-Alto Adige/Südtirol,4,38048 +Spiazzo,22179,Trento,TN,Trentino-Alto Adige/Südtirol,4,38088 +Spormaggiore,22180,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Sporminore,22181,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Stenico,22182,Trento,TN,Trentino-Alto Adige/Südtirol,4,38070 +Storo,22183,Trento,TN,Trentino-Alto Adige/Südtirol,4,38089 +Strembo,22184,Trento,TN,Trentino-Alto Adige/Südtirol,4,38080 +Telve,22188,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Telve di Sopra,22189,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Tenna,22190,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Tenno,22191,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Terragnolo,22193,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Terzolas,22195,Trento,TN,Trentino-Alto Adige/Südtirol,4,38027 +Tesero,22196,Trento,TN,Trentino-Alto Adige/Südtirol,4,38038 +Tione di Trento,22199,Trento,TN,Trentino-Alto Adige/Südtirol,4,38079 +Ton,22200,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Torcegno,22202,Trento,TN,Trentino-Alto Adige/Südtirol,4,38050 +Trambileno,22203,Trento,TN,Trentino-Alto Adige/Südtirol,4,38068 +Trento,22205,Trento,TN,Trentino-Alto Adige/Südtirol,4,38121 +Valfloriana,22209,Trento,TN,Trentino-Alto Adige/Südtirol,4,38040 +Vallarsa,22210,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Vermiglio,22213,Trento,TN,Trentino-Alto Adige/Südtirol,4,38029 +Vignola-Falesina,22216,Trento,TN,Trentino-Alto Adige/Südtirol,4,38057 +Villa Lagarina,22222,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Volano,22224,Trento,TN,Trentino-Alto Adige/Südtirol,4,38060 +Ziano di Fiemme,22226,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Comano Terme,22228,Trento,TN,Trentino-Alto Adige/Südtirol,4,38077 +Ledro,22229,Trento,TN,Trentino-Alto Adige/Südtirol,4,38067 +Predaia,22230,Trento,TN,Trentino-Alto Adige/Südtirol,4,38012 +San Lorenzo Dorsino,22231,Trento,TN,Trentino-Alto Adige/Südtirol,4,38078 +Valdaone,22232,Trento,TN,Trentino-Alto Adige/Südtirol,4,38080 +Dimaro Folgarida,22233,Trento,TN,Trentino-Alto Adige/Südtirol,4,38025 +Pieve di Bono-Prezzo,22234,Trento,TN,Trentino-Alto Adige/Südtirol,4,38085 +Altavalle,22235,Trento,TN,Trentino-Alto Adige/Südtirol,4,38092 +Altopiano della Vigolana,22236,Trento,TN,Trentino-Alto Adige/Südtirol,4,38049 +Amblar-Don,22237,Trento,TN,Trentino-Alto Adige/Südtirol,4,38011 +Borgo Chiese,22238,Trento,TN,Trentino-Alto Adige/Südtirol,4,38083 +Borgo Lares,22239,Trento,TN,Trentino-Alto Adige/Südtirol,4,38079 +Castel Ivano,22240,Trento,TN,Trentino-Alto Adige/Südtirol,4,38059 +Cembra Lisignago,22241,Trento,TN,Trentino-Alto Adige/Südtirol,4,38034 +Contà,22242,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Madruzzo,22243,Trento,TN,Trentino-Alto Adige/Südtirol,4,38076 +Porte di Rendena,22244,Trento,TN,Trentino-Alto Adige/Südtirol,4,38094 +Primiero San Martino di Castrozza,22245,Trento,TN,Trentino-Alto Adige/Südtirol,4,38054 +Sella Giudicarie,22246,Trento,TN,Trentino-Alto Adige/Südtirol,4,38087 +Tre Ville,22247,Trento,TN,Trentino-Alto Adige/Südtirol,4,38070 +Vallelaghi,22248,Trento,TN,Trentino-Alto Adige/Südtirol,4,38070 +Ville d'Anaunia,22249,Trento,TN,Trentino-Alto Adige/Südtirol,4,38019 +San Giovanni di Fassa,22250,Trento,TN,Trentino-Alto Adige/Südtirol,4,38039 +Terre d'Adige,22251,Trento,TN,Trentino-Alto Adige/Südtirol,4,38010 +Borgo d'Anaunia,22252,Trento,TN,Trentino-Alto Adige/Südtirol,4,38013 +Novella,22253,Trento,TN,Trentino-Alto Adige/Südtirol,4,38028 +Ville di Fiemme,22254,Trento,TN,Trentino-Alto Adige/Südtirol,4,38030 +Affi,23001,Verona,VR,Veneto,5,37010 +Albaredo d'Adige,23002,Verona,VR,Veneto,5,37041 +Angiari,23003,Verona,VR,Veneto,5,37050 +Arcole,23004,Verona,VR,Veneto,5,37040 +Badia Calavena,23005,Verona,VR,Veneto,5,37030 +Bardolino,23006,Verona,VR,Veneto,5,37011 +Belfiore,23007,Verona,VR,Veneto,5,37050 +Bevilacqua,23008,Verona,VR,Veneto,5,37040 +Bonavigo,23009,Verona,VR,Veneto,5,37040 +Boschi Sant'Anna,23010,Verona,VR,Veneto,5,37040 +Bosco Chiesanuova,23011,Verona,VR,Veneto,5,37021 +Bovolone,23012,Verona,VR,Veneto,5,37051 +Brentino Belluno,23013,Verona,VR,Veneto,5,37020 +Brenzone sul Garda,23014,Verona,VR,Veneto,5,37010 +Bussolengo,23015,Verona,VR,Veneto,5,37012 +Buttapietra,23016,Verona,VR,Veneto,5,37060 +Caldiero,23017,Verona,VR,Veneto,5,37042 +Caprino Veronese,23018,Verona,VR,Veneto,5,37013 +Casaleone,23019,Verona,VR,Veneto,5,37052 +Castagnaro,23020,Verona,VR,Veneto,5,37043 +Castel d'Azzano,23021,Verona,VR,Veneto,5,37060 +Castelnuovo del Garda,23022,Verona,VR,Veneto,5,37014 +Cavaion Veronese,23023,Verona,VR,Veneto,5,37010 +Cazzano di Tramigna,23024,Verona,VR,Veneto,5,37030 +Cerea,23025,Verona,VR,Veneto,5,37053 +Cerro Veronese,23026,Verona,VR,Veneto,5,37020 +Cologna Veneta,23027,Verona,VR,Veneto,5,37044 +Colognola ai Colli,23028,Verona,VR,Veneto,5,37030 +Concamarise,23029,Verona,VR,Veneto,5,37050 +Costermano sul Garda,23030,Verona,VR,Veneto,5,37010 +Dolcè,23031,Verona,VR,Veneto,5,37020 +Erbè,23032,Verona,VR,Veneto,5,37060 +Erbezzo,23033,Verona,VR,Veneto,5,37020 +Ferrara di Monte Baldo,23034,Verona,VR,Veneto,5,37020 +Fumane,23035,Verona,VR,Veneto,5,37022 +Garda,23036,Verona,VR,Veneto,5,37016 +Gazzo Veronese,23037,Verona,VR,Veneto,5,37060 +Grezzana,23038,Verona,VR,Veneto,5,37023 +Illasi,23039,Verona,VR,Veneto,5,37031 +Isola della Scala,23040,Verona,VR,Veneto,5,37063 +Isola Rizza,23041,Verona,VR,Veneto,5,37050 +Lavagno,23042,Verona,VR,Veneto,5,37030 +Lazise,23043,Verona,VR,Veneto,5,37017 +Legnago,23044,Verona,VR,Veneto,5,37045 +Malcesine,23045,Verona,VR,Veneto,5,37018 +Marano di Valpolicella,23046,Verona,VR,Veneto,5,37020 +Mezzane di Sotto,23047,Verona,VR,Veneto,5,37030 +Minerbe,23048,Verona,VR,Veneto,5,37046 +Montecchia di Crosara,23049,Verona,VR,Veneto,5,37030 +Monteforte d'Alpone,23050,Verona,VR,Veneto,5,37032 +Mozzecane,23051,Verona,VR,Veneto,5,37060 +Negrar di Valpolicella,23052,Verona,VR,Veneto,5,37024 +Nogara,23053,Verona,VR,Veneto,5,37054 +Nogarole Rocca,23054,Verona,VR,Veneto,5,37060 +Oppeano,23055,Verona,VR,Veneto,5,37050 +Palù,23056,Verona,VR,Veneto,5,37050 +Pastrengo,23057,Verona,VR,Veneto,5,37010 +Pescantina,23058,Verona,VR,Veneto,5,37026 +Peschiera del Garda,23059,Verona,VR,Veneto,5,37019 +Povegliano Veronese,23060,Verona,VR,Veneto,5,37064 +Pressana,23061,Verona,VR,Veneto,5,37040 +Rivoli Veronese,23062,Verona,VR,Veneto,5,37010 +Roncà,23063,Verona,VR,Veneto,5,37030 +Ronco all'Adige,23064,Verona,VR,Veneto,5,37055 +Roverchiara,23065,Verona,VR,Veneto,5,37050 +Roveredo di Guà,23066,Verona,VR,Veneto,5,37040 +Roverè Veronese,23067,Verona,VR,Veneto,5,37028 +Salizzole,23068,Verona,VR,Veneto,5,37056 +San Bonifacio,23069,Verona,VR,Veneto,5,37047 +San Giovanni Ilarione,23070,Verona,VR,Veneto,5,37035 +San Giovanni Lupatoto,23071,Verona,VR,Veneto,5,37057 +Sanguinetto,23072,Verona,VR,Veneto,5,37058 +San Martino Buon Albergo,23073,Verona,VR,Veneto,5,37036 +San Mauro di Saline,23074,Verona,VR,Veneto,5,37030 +San Pietro di Morubio,23075,Verona,VR,Veneto,5,37050 +San Pietro in Cariano,23076,Verona,VR,Veneto,5,37029 +Sant'Ambrogio di Valpolicella,23077,Verona,VR,Veneto,5,37015 +Sant'Anna d'Alfaedo,23078,Verona,VR,Veneto,5,37020 +San Zeno di Montagna,23079,Verona,VR,Veneto,5,37010 +Selva di Progno,23080,Verona,VR,Veneto,5,37030 +Soave,23081,Verona,VR,Veneto,5,37038 +Sommacampagna,23082,Verona,VR,Veneto,5,37066 +Sona,23083,Verona,VR,Veneto,5,37060 +Sorgà,23084,Verona,VR,Veneto,5,37060 +Terrazzo,23085,Verona,VR,Veneto,5,37040 +Torri del Benaco,23086,Verona,VR,Veneto,5,37010 +Tregnago,23087,Verona,VR,Veneto,5,37039 +Trevenzuolo,23088,Verona,VR,Veneto,5,37060 +Valeggio sul Mincio,23089,Verona,VR,Veneto,5,37067 +Velo Veronese,23090,Verona,VR,Veneto,5,37030 +Verona,23091,Verona,VR,Veneto,5,37121 +Veronella,23092,Verona,VR,Veneto,5,37040 +Vestenanova,23093,Verona,VR,Veneto,5,37030 +Vigasio,23094,Verona,VR,Veneto,5,37068 +Villa Bartolomea,23095,Verona,VR,Veneto,5,37049 +Villafranca di Verona,23096,Verona,VR,Veneto,5,37069 +Zevio,23097,Verona,VR,Veneto,5,37059 +Zimella,23098,Verona,VR,Veneto,5,37040 +Agugliaro,24001,Vicenza,VI,Veneto,5,36020 +Albettone,24002,Vicenza,VI,Veneto,5,36020 +Alonte,24003,Vicenza,VI,Veneto,5,36045 +Altavilla Vicentina,24004,Vicenza,VI,Veneto,5,36077 +Altissimo,24005,Vicenza,VI,Veneto,5,36070 +Arcugnano,24006,Vicenza,VI,Veneto,5,36057 +Arsiero,24007,Vicenza,VI,Veneto,5,36011 +Arzignano,24008,Vicenza,VI,Veneto,5,36071 +Asiago,24009,Vicenza,VI,Veneto,5,36012 +Asigliano Veneto,24010,Vicenza,VI,Veneto,5,36020 +Bassano del Grappa,24012,Vicenza,VI,Veneto,5,36061 +Bolzano Vicentino,24013,Vicenza,VI,Veneto,5,36050 +Breganze,24014,Vicenza,VI,Veneto,5,36042 +Brendola,24015,Vicenza,VI,Veneto,5,36040 +Bressanvido,24016,Vicenza,VI,Veneto,5,36050 +Brogliano,24017,Vicenza,VI,Veneto,5,36070 +Caldogno,24018,Vicenza,VI,Veneto,5,36030 +Caltrano,24019,Vicenza,VI,Veneto,5,36030 +Calvene,24020,Vicenza,VI,Veneto,5,36030 +Camisano Vicentino,24021,Vicenza,VI,Veneto,5,36043 +Campiglia dei Berici,24022,Vicenza,VI,Veneto,5,36020 +Carrè,24024,Vicenza,VI,Veneto,5,36010 +Cartigliano,24025,Vicenza,VI,Veneto,5,36050 +Cassola,24026,Vicenza,VI,Veneto,5,36022 +Castegnero,24027,Vicenza,VI,Veneto,5,36020 +Castelgomberto,24028,Vicenza,VI,Veneto,5,36070 +Chiampo,24029,Vicenza,VI,Veneto,5,36072 +Chiuppano,24030,Vicenza,VI,Veneto,5,36010 +Cogollo del Cengio,24032,Vicenza,VI,Veneto,5,36010 +Cornedo Vicentino,24034,Vicenza,VI,Veneto,5,36073 +Costabissara,24035,Vicenza,VI,Veneto,5,36030 +Creazzo,24036,Vicenza,VI,Veneto,5,36051 +Crespadoro,24037,Vicenza,VI,Veneto,5,36070 +Dueville,24038,Vicenza,VI,Veneto,5,36031 +Enego,24039,Vicenza,VI,Veneto,5,36052 +Fara Vicentino,24040,Vicenza,VI,Veneto,5,36030 +Foza,24041,Vicenza,VI,Veneto,5,36010 +Gallio,24042,Vicenza,VI,Veneto,5,36032 +Gambellara,24043,Vicenza,VI,Veneto,5,36053 +Gambugliano,24044,Vicenza,VI,Veneto,5,36050 +Grisignano di Zocco,24046,Vicenza,VI,Veneto,5,36040 +Grumolo delle Abbadesse,24047,Vicenza,VI,Veneto,5,36040 +Isola Vicentina,24048,Vicenza,VI,Veneto,5,36033 +Laghi,24049,Vicenza,VI,Veneto,5,36010 +Lastebasse,24050,Vicenza,VI,Veneto,5,36040 +Longare,24051,Vicenza,VI,Veneto,5,36023 +Lonigo,24052,Vicenza,VI,Veneto,5,36045 +Lugo di Vicenza,24053,Vicenza,VI,Veneto,5,36030 +Malo,24055,Vicenza,VI,Veneto,5,36034 +Marano Vicentino,24056,Vicenza,VI,Veneto,5,36035 +Marostica,24057,Vicenza,VI,Veneto,5,36063 +Montebello Vicentino,24060,Vicenza,VI,Veneto,5,36054 +Montecchio Maggiore,24061,Vicenza,VI,Veneto,5,36075 +Montecchio Precalcino,24062,Vicenza,VI,Veneto,5,36030 +Monte di Malo,24063,Vicenza,VI,Veneto,5,36030 +Montegalda,24064,Vicenza,VI,Veneto,5,36047 +Montegaldella,24065,Vicenza,VI,Veneto,5,36047 +Monteviale,24066,Vicenza,VI,Veneto,5,36050 +Monticello Conte Otto,24067,Vicenza,VI,Veneto,5,36010 +Montorso Vicentino,24068,Vicenza,VI,Veneto,5,36050 +Mussolente,24070,Vicenza,VI,Veneto,5,36065 +Nanto,24071,Vicenza,VI,Veneto,5,36024 +Nogarole Vicentino,24072,Vicenza,VI,Veneto,5,36070 +Nove,24073,Vicenza,VI,Veneto,5,36055 +Noventa Vicentina,24074,Vicenza,VI,Veneto,5,36025 +Orgiano,24075,Vicenza,VI,Veneto,5,36040 +Pedemonte,24076,Vicenza,VI,Veneto,5,36040 +Pianezze,24077,Vicenza,VI,Veneto,5,36060 +Piovene Rocchette,24078,Vicenza,VI,Veneto,5,36013 +Pojana Maggiore,24079,Vicenza,VI,Veneto,5,36026 +Posina,24080,Vicenza,VI,Veneto,5,36010 +Pove del Grappa,24081,Vicenza,VI,Veneto,5,36020 +Pozzoleone,24082,Vicenza,VI,Veneto,5,36050 +Quinto Vicentino,24083,Vicenza,VI,Veneto,5,36050 +Recoaro Terme,24084,Vicenza,VI,Veneto,5,36076 +Roana,24085,Vicenza,VI,Veneto,5,36010 +Romano d'Ezzelino,24086,Vicenza,VI,Veneto,5,36060 +Rosà,24087,Vicenza,VI,Veneto,5,36027 +Rossano Veneto,24088,Vicenza,VI,Veneto,5,36028 +Rotzo,24089,Vicenza,VI,Veneto,5,36010 +Salcedo,24090,Vicenza,VI,Veneto,5,36040 +Sandrigo,24091,Vicenza,VI,Veneto,5,36066 +San Pietro Mussolino,24094,Vicenza,VI,Veneto,5,36070 +Santorso,24095,Vicenza,VI,Veneto,5,36014 +San Vito di Leguzzano,24096,Vicenza,VI,Veneto,5,36030 +Sarcedo,24097,Vicenza,VI,Veneto,5,36030 +Sarego,24098,Vicenza,VI,Veneto,5,36040 +Schiavon,24099,Vicenza,VI,Veneto,5,36060 +Schio,24100,Vicenza,VI,Veneto,5,36015 +Solagna,24101,Vicenza,VI,Veneto,5,36020 +Sossano,24102,Vicenza,VI,Veneto,5,36040 +Sovizzo,24103,Vicenza,VI,Veneto,5,36050 +Tezze sul Brenta,24104,Vicenza,VI,Veneto,5,36056 +Thiene,24105,Vicenza,VI,Veneto,5,36016 +Tonezza del Cimone,24106,Vicenza,VI,Veneto,5,36040 +Torrebelvicino,24107,Vicenza,VI,Veneto,5,36036 +Torri di Quartesolo,24108,Vicenza,VI,Veneto,5,36040 +Trissino,24110,Vicenza,VI,Veneto,5,36070 +Valdagno,24111,Vicenza,VI,Veneto,5,36078 +Valdastico,24112,Vicenza,VI,Veneto,5,36040 +Valli del Pasubio,24113,Vicenza,VI,Veneto,5,36030 +Velo d'Astico,24115,Vicenza,VI,Veneto,5,36010 +Vicenza,24116,Vicenza,VI,Veneto,5,36100 +Villaga,24117,Vicenza,VI,Veneto,5,36021 +Villaverla,24118,Vicenza,VI,Veneto,5,36030 +Zanè,24119,Vicenza,VI,Veneto,5,36010 +Zermeghedo,24120,Vicenza,VI,Veneto,5,36050 +Zovencedo,24121,Vicenza,VI,Veneto,5,36020 +Zugliano,24122,Vicenza,VI,Veneto,5,36030 +Val Liona,24123,Vicenza,VI,Veneto,5,36040 +Barbarano Mossano,24124,Vicenza,VI,Veneto,5,36048 +Valbrenta,24125,Vicenza,VI,Veneto,5,36020 +Colceresa,24126,Vicenza,VI,Veneto,5,36064 +Lusiana Conco,24127,Vicenza,VI,Veneto,5,36046 +Agordo,25001,Belluno,BL,Veneto,5,32021 +Alano di Piave,25002,Belluno,BL,Veneto,5,32031 +Alleghe,25003,Belluno,BL,Veneto,5,32022 +Arsiè,25004,Belluno,BL,Veneto,5,32030 +Auronzo di Cadore,25005,Belluno,BL,Veneto,5,32041 +Belluno,25006,Belluno,BL,Veneto,5,32100 +Borca di Cadore,25007,Belluno,BL,Veneto,5,32040 +Calalzo di Cadore,25008,Belluno,BL,Veneto,5,32042 +Cencenighe Agordino,25010,Belluno,BL,Veneto,5,32020 +Cesiomaggiore,25011,Belluno,BL,Veneto,5,32030 +Chies d'Alpago,25012,Belluno,BL,Veneto,5,32010 +Cibiana di Cadore,25013,Belluno,BL,Veneto,5,32040 +Colle Santa Lucia,25014,Belluno,BL,Veneto,5,32020 +Comelico Superiore,25015,Belluno,BL,Veneto,5,32040 +Cortina d'Ampezzo,25016,Belluno,BL,Veneto,5,32043 +Danta di Cadore,25017,Belluno,BL,Veneto,5,32040 +Domegge di Cadore,25018,Belluno,BL,Veneto,5,32040 +Falcade,25019,Belluno,BL,Veneto,5,32020 +Feltre,25021,Belluno,BL,Veneto,5,32032 +Fonzaso,25022,Belluno,BL,Veneto,5,32030 +Canale d'Agordo,25023,Belluno,BL,Veneto,5,32020 +Gosaldo,25025,Belluno,BL,Veneto,5,32020 +Lamon,25026,Belluno,BL,Veneto,5,32033 +La Valle Agordina,25027,Belluno,BL,Veneto,5,32020 +Limana,25029,Belluno,BL,Veneto,5,32020 +Livinallongo del Col di Lana,25030,Belluno,BL,Veneto,5,32020 +Lorenzago di Cadore,25032,Belluno,BL,Veneto,5,32040 +Lozzo di Cadore,25033,Belluno,BL,Veneto,5,32040 +Ospitale di Cadore,25035,Belluno,BL,Veneto,5,32010 +Pedavena,25036,Belluno,BL,Veneto,5,32034 +Perarolo di Cadore,25037,Belluno,BL,Veneto,5,32010 +Pieve di Cadore,25039,Belluno,BL,Veneto,5,32044 +Ponte nelle Alpi,25040,Belluno,BL,Veneto,5,32014 +Rivamonte Agordino,25043,Belluno,BL,Veneto,5,32020 +Rocca Pietore,25044,Belluno,BL,Veneto,5,32020 +San Gregorio nelle Alpi,25045,Belluno,BL,Veneto,5,32030 +San Nicolò di Comelico,25046,Belluno,BL,Veneto,5,32040 +San Pietro di Cadore,25047,Belluno,BL,Veneto,5,32040 +Santa Giustina,25048,Belluno,BL,Veneto,5,32035 +San Tomaso Agordino,25049,Belluno,BL,Veneto,5,32020 +Santo Stefano di Cadore,25050,Belluno,BL,Veneto,5,32045 +San Vito di Cadore,25051,Belluno,BL,Veneto,5,32046 +Sedico,25053,Belluno,BL,Veneto,5,32036 +Selva di Cadore,25054,Belluno,BL,Veneto,5,32020 +Seren del Grappa,25055,Belluno,BL,Veneto,5,32030 +Sospirolo,25056,Belluno,BL,Veneto,5,32037 +Soverzene,25057,Belluno,BL,Veneto,5,32010 +Sovramonte,25058,Belluno,BL,Veneto,5,32030 +Taibon Agordino,25059,Belluno,BL,Veneto,5,32027 +Tambre,25060,Belluno,BL,Veneto,5,32010 +Vallada Agordina,25062,Belluno,BL,Veneto,5,32020 +Valle di Cadore,25063,Belluno,BL,Veneto,5,32040 +Vigo di Cadore,25065,Belluno,BL,Veneto,5,32040 +Vodo Cadore,25066,Belluno,BL,Veneto,5,32040 +Voltago Agordino,25067,Belluno,BL,Veneto,5,32020 +Zoppè di Cadore,25069,Belluno,BL,Veneto,5,32010 +Quero Vas,25070,Belluno,BL,Veneto,5,32038 +Longarone,25071,Belluno,BL,Veneto,5,32013 +Alpago,25072,Belluno,BL,Veneto,5,32010 +Val di Zoldo,25073,Belluno,BL,Veneto,5,32010 +Borgo Valbelluna,25074,Belluno,BL,Veneto,5,32026 +Altivole,26001,Treviso,TV,Veneto,5,31030 +Arcade,26002,Treviso,TV,Veneto,5,31030 +Asolo,26003,Treviso,TV,Veneto,5,31011 +Borso del Grappa,26004,Treviso,TV,Veneto,5,31030 +Breda di Piave,26005,Treviso,TV,Veneto,5,31030 +Caerano di San Marco,26006,Treviso,TV,Veneto,5,31031 +Cappella Maggiore,26007,Treviso,TV,Veneto,5,31012 +Carbonera,26008,Treviso,TV,Veneto,5,31030 +Casale sul Sile,26009,Treviso,TV,Veneto,5,31032 +Casier,26010,Treviso,TV,Veneto,5,31030 +Castelcucco,26011,Treviso,TV,Veneto,5,31030 +Castelfranco Veneto,26012,Treviso,TV,Veneto,5,31033 +Castello di Godego,26013,Treviso,TV,Veneto,5,31030 +Cavaso del Tomba,26014,Treviso,TV,Veneto,5,31034 +Cessalto,26015,Treviso,TV,Veneto,5,31040 +Chiarano,26016,Treviso,TV,Veneto,5,31040 +Cimadolmo,26017,Treviso,TV,Veneto,5,31010 +Cison di Valmarino,26018,Treviso,TV,Veneto,5,31030 +Codognè,26019,Treviso,TV,Veneto,5,31013 +Colle Umberto,26020,Treviso,TV,Veneto,5,31014 +Conegliano,26021,Treviso,TV,Veneto,5,31015 +Cordignano,26022,Treviso,TV,Veneto,5,31016 +Cornuda,26023,Treviso,TV,Veneto,5,31041 +Crocetta del Montello,26025,Treviso,TV,Veneto,5,31035 +Farra di Soligo,26026,Treviso,TV,Veneto,5,31010 +Follina,26027,Treviso,TV,Veneto,5,31051 +Fontanelle,26028,Treviso,TV,Veneto,5,31043 +Fonte,26029,Treviso,TV,Veneto,5,31010 +Fregona,26030,Treviso,TV,Veneto,5,31010 +Gaiarine,26031,Treviso,TV,Veneto,5,31018 +Giavera del Montello,26032,Treviso,TV,Veneto,5,31040 +Godega di Sant'Urbano,26033,Treviso,TV,Veneto,5,31010 +Gorgo al Monticano,26034,Treviso,TV,Veneto,5,31040 +Istrana,26035,Treviso,TV,Veneto,5,31036 +Loria,26036,Treviso,TV,Veneto,5,31037 +Mansuè,26037,Treviso,TV,Veneto,5,31040 +Mareno di Piave,26038,Treviso,TV,Veneto,5,31010 +Maser,26039,Treviso,TV,Veneto,5,31010 +Maserada sul Piave,26040,Treviso,TV,Veneto,5,31052 +Meduna di Livenza,26041,Treviso,TV,Veneto,5,31040 +Miane,26042,Treviso,TV,Veneto,5,31050 +Mogliano Veneto,26043,Treviso,TV,Veneto,5,31021 +Monastier di Treviso,26044,Treviso,TV,Veneto,5,31050 +Monfumo,26045,Treviso,TV,Veneto,5,31010 +Montebelluna,26046,Treviso,TV,Veneto,5,31044 +Morgano,26047,Treviso,TV,Veneto,5,31050 +Moriago della Battaglia,26048,Treviso,TV,Veneto,5,31010 +Motta di Livenza,26049,Treviso,TV,Veneto,5,31045 +Nervesa della Battaglia,26050,Treviso,TV,Veneto,5,31040 +Oderzo,26051,Treviso,TV,Veneto,5,31046 +Ormelle,26052,Treviso,TV,Veneto,5,31024 +Orsago,26053,Treviso,TV,Veneto,5,31010 +Paese,26055,Treviso,TV,Veneto,5,31038 +Pederobba,26056,Treviso,TV,Veneto,5,31040 +Pieve di Soligo,26057,Treviso,TV,Veneto,5,31053 +Ponte di Piave,26058,Treviso,TV,Veneto,5,31047 +Ponzano Veneto,26059,Treviso,TV,Veneto,5,31050 +Portobuffolè,26060,Treviso,TV,Veneto,5,31040 +Possagno,26061,Treviso,TV,Veneto,5,31054 +Povegliano,26062,Treviso,TV,Veneto,5,31050 +Preganziol,26063,Treviso,TV,Veneto,5,31022 +Quinto di Treviso,26064,Treviso,TV,Veneto,5,31055 +Refrontolo,26065,Treviso,TV,Veneto,5,31020 +Resana,26066,Treviso,TV,Veneto,5,31023 +Revine Lago,26067,Treviso,TV,Veneto,5,31020 +Riese Pio X,26068,Treviso,TV,Veneto,5,31039 +Roncade,26069,Treviso,TV,Veneto,5,31056 +Salgareda,26070,Treviso,TV,Veneto,5,31040 +San Biagio di Callalta,26071,Treviso,TV,Veneto,5,31048 +San Fior,26072,Treviso,TV,Veneto,5,31020 +San Pietro di Feletto,26073,Treviso,TV,Veneto,5,31020 +San Polo di Piave,26074,Treviso,TV,Veneto,5,31020 +Santa Lucia di Piave,26075,Treviso,TV,Veneto,5,31025 +San Vendemiano,26076,Treviso,TV,Veneto,5,31020 +San Zenone degli Ezzelini,26077,Treviso,TV,Veneto,5,31020 +Sarmede,26078,Treviso,TV,Veneto,5,31026 +Segusino,26079,Treviso,TV,Veneto,5,31040 +Sernaglia della Battaglia,26080,Treviso,TV,Veneto,5,31020 +Silea,26081,Treviso,TV,Veneto,5,31057 +Spresiano,26082,Treviso,TV,Veneto,5,31027 +Susegana,26083,Treviso,TV,Veneto,5,31058 +Tarzo,26084,Treviso,TV,Veneto,5,31020 +Trevignano,26085,Treviso,TV,Veneto,5,31040 +Treviso,26086,Treviso,TV,Veneto,5,31100 +Valdobbiadene,26087,Treviso,TV,Veneto,5,31049 +Vazzola,26088,Treviso,TV,Veneto,5,31028 +Vedelago,26089,Treviso,TV,Veneto,5,31050 +Vidor,26090,Treviso,TV,Veneto,5,31020 +Villorba,26091,Treviso,TV,Veneto,5,31020 +Vittorio Veneto,26092,Treviso,TV,Veneto,5,31029 +Volpago del Montello,26093,Treviso,TV,Veneto,5,31040 +Zenson di Piave,26094,Treviso,TV,Veneto,5,31050 +Zero Branco,26095,Treviso,TV,Veneto,5,31059 +Pieve del Grappa,26096,Treviso,TV,Veneto,5,31017 +Annone Veneto,27001,Venezia,VE,Veneto,5,30020 +Campagna Lupia,27002,Venezia,VE,Veneto,5,30010 +Campolongo Maggiore,27003,Venezia,VE,Veneto,5,30010 +Camponogara,27004,Venezia,VE,Veneto,5,30010 +Caorle,27005,Venezia,VE,Veneto,5,30021 +Cavarzere,27006,Venezia,VE,Veneto,5,30014 +Ceggia,27007,Venezia,VE,Veneto,5,30022 +Chioggia,27008,Venezia,VE,Veneto,5,30015 +Cinto Caomaggiore,27009,Venezia,VE,Veneto,5,30020 +Cona,27010,Venezia,VE,Veneto,5,30010 +Concordia Sagittaria,27011,Venezia,VE,Veneto,5,30023 +Dolo,27012,Venezia,VE,Veneto,5,30031 +Eraclea,27013,Venezia,VE,Veneto,5,30020 +Fiesso d'Artico,27014,Venezia,VE,Veneto,5,30032 +Fossalta di Piave,27015,Venezia,VE,Veneto,5,30020 +Fossalta di Portogruaro,27016,Venezia,VE,Veneto,5,30025 +Fossò,27017,Venezia,VE,Veneto,5,30030 +Gruaro,27018,Venezia,VE,Veneto,5,30020 +Jesolo,27019,Venezia,VE,Veneto,5,30016 +Marcon,27020,Venezia,VE,Veneto,5,30020 +Martellago,27021,Venezia,VE,Veneto,5,30030 +Meolo,27022,Venezia,VE,Veneto,5,30020 +Mira,27023,Venezia,VE,Veneto,5,30034 +Mirano,27024,Venezia,VE,Veneto,5,30035 +Musile di Piave,27025,Venezia,VE,Veneto,5,30024 +Noale,27026,Venezia,VE,Veneto,5,30033 +Noventa di Piave,27027,Venezia,VE,Veneto,5,30020 +Pianiga,27028,Venezia,VE,Veneto,5,30030 +Portogruaro,27029,Venezia,VE,Veneto,5,30026 +Pramaggiore,27030,Venezia,VE,Veneto,5,30020 +Quarto d'Altino,27031,Venezia,VE,Veneto,5,30020 +Salzano,27032,Venezia,VE,Veneto,5,30030 +San Donà di Piave,27033,Venezia,VE,Veneto,5,30027 +San Michele al Tagliamento,27034,Venezia,VE,Veneto,5,30028 +Santa Maria di Sala,27035,Venezia,VE,Veneto,5,30036 +San Stino di Livenza,27036,Venezia,VE,Veneto,5,30029 +Scorzè,27037,Venezia,VE,Veneto,5,30037 +Spinea,27038,Venezia,VE,Veneto,5,30038 +Stra,27039,Venezia,VE,Veneto,5,30039 +Teglio Veneto,27040,Venezia,VE,Veneto,5,30025 +Torre di Mosto,27041,Venezia,VE,Veneto,5,30020 +Venezia,27042,Venezia,VE,Veneto,5,30100 +Vigonovo,27043,Venezia,VE,Veneto,5,30030 +Cavallino-Treporti,27044,Venezia,VE,Veneto,5,30013 +Abano Terme,28001,Padova,PD,Veneto,5,35031 +Agna,28002,Padova,PD,Veneto,5,35021 +Albignasego,28003,Padova,PD,Veneto,5,35020 +Anguillara Veneta,28004,Padova,PD,Veneto,5,35022 +Arquà Petrarca,28005,Padova,PD,Veneto,5,35032 +Arre,28006,Padova,PD,Veneto,5,35020 +Arzergrande,28007,Padova,PD,Veneto,5,35020 +Bagnoli di Sopra,28008,Padova,PD,Veneto,5,35023 +Baone,28009,Padova,PD,Veneto,5,35030 +Barbona,28010,Padova,PD,Veneto,5,35040 +Battaglia Terme,28011,Padova,PD,Veneto,5,35041 +Boara Pisani,28012,Padova,PD,Veneto,5,35040 +Borgoricco,28013,Padova,PD,Veneto,5,35010 +Bovolenta,28014,Padova,PD,Veneto,5,35024 +Brugine,28015,Padova,PD,Veneto,5,35020 +Cadoneghe,28016,Padova,PD,Veneto,5,35010 +Campodarsego,28017,Padova,PD,Veneto,5,35011 +Campodoro,28018,Padova,PD,Veneto,5,35010 +Camposampiero,28019,Padova,PD,Veneto,5,35012 +Campo San Martino,28020,Padova,PD,Veneto,5,35010 +Candiana,28021,Padova,PD,Veneto,5,35020 +Carceri,28022,Padova,PD,Veneto,5,35040 +Carmignano di Brenta,28023,Padova,PD,Veneto,5,35010 +Cartura,28026,Padova,PD,Veneto,5,35025 +Casale di Scodosia,28027,Padova,PD,Veneto,5,35040 +Casalserugo,28028,Padova,PD,Veneto,5,35020 +Castelbaldo,28029,Padova,PD,Veneto,5,35040 +Cervarese Santa Croce,28030,Padova,PD,Veneto,5,35030 +Cinto Euganeo,28031,Padova,PD,Veneto,5,35030 +Cittadella,28032,Padova,PD,Veneto,5,35013 +Codevigo,28033,Padova,PD,Veneto,5,35020 +Conselve,28034,Padova,PD,Veneto,5,35026 +Correzzola,28035,Padova,PD,Veneto,5,35020 +Curtarolo,28036,Padova,PD,Veneto,5,35010 +Este,28037,Padova,PD,Veneto,5,35042 +Fontaniva,28038,Padova,PD,Veneto,5,35014 +Galliera Veneta,28039,Padova,PD,Veneto,5,35015 +Galzignano Terme,28040,Padova,PD,Veneto,5,35030 +Gazzo,28041,Padova,PD,Veneto,5,35010 +Grantorto,28042,Padova,PD,Veneto,5,35010 +Granze,28043,Padova,PD,Veneto,5,35040 +Legnaro,28044,Padova,PD,Veneto,5,35020 +Limena,28045,Padova,PD,Veneto,5,35010 +Loreggia,28046,Padova,PD,Veneto,5,35010 +Lozzo Atestino,28047,Padova,PD,Veneto,5,35034 +Maserà di Padova,28048,Padova,PD,Veneto,5,35020 +Masi,28049,Padova,PD,Veneto,5,35040 +Massanzago,28050,Padova,PD,Veneto,5,35010 +Megliadino San Vitale,28052,Padova,PD,Veneto,5,35040 +Merlara,28053,Padova,PD,Veneto,5,35040 +Mestrino,28054,Padova,PD,Veneto,5,35035 +Monselice,28055,Padova,PD,Veneto,5,35043 +Montagnana,28056,Padova,PD,Veneto,5,35044 +Montegrotto Terme,28057,Padova,PD,Veneto,5,35036 +Noventa Padovana,28058,Padova,PD,Veneto,5,35027 +Ospedaletto Euganeo,28059,Padova,PD,Veneto,5,35045 +Padova,28060,Padova,PD,Veneto,5,35122 +Pernumia,28061,Padova,PD,Veneto,5,35020 +Piacenza d'Adige,28062,Padova,PD,Veneto,5,35040 +Piazzola sul Brenta,28063,Padova,PD,Veneto,5,35016 +Piombino Dese,28064,Padova,PD,Veneto,5,35017 +Piove di Sacco,28065,Padova,PD,Veneto,5,35028 +Polverara,28066,Padova,PD,Veneto,5,35020 +Ponso,28067,Padova,PD,Veneto,5,35040 +Pontelongo,28068,Padova,PD,Veneto,5,35029 +Ponte San Nicolò,28069,Padova,PD,Veneto,5,35020 +Pozzonovo,28070,Padova,PD,Veneto,5,35020 +Rovolon,28071,Padova,PD,Veneto,5,35030 +Rubano,28072,Padova,PD,Veneto,5,35030 +Saccolongo,28073,Padova,PD,Veneto,5,35030 +San Giorgio delle Pertiche,28075,Padova,PD,Veneto,5,35010 +San Giorgio in Bosco,28076,Padova,PD,Veneto,5,35010 +San Martino di Lupari,28077,Padova,PD,Veneto,5,35018 +San Pietro in Gu,28078,Padova,PD,Veneto,5,35010 +San Pietro Viminario,28079,Padova,PD,Veneto,5,35020 +Santa Giustina in Colle,28080,Padova,PD,Veneto,5,35010 +Sant'Angelo di Piove di Sacco,28082,Padova,PD,Veneto,5,35020 +Sant'Elena,28083,Padova,PD,Veneto,5,35040 +Sant'Urbano,28084,Padova,PD,Veneto,5,35040 +Saonara,28085,Padova,PD,Veneto,5,35020 +Selvazzano Dentro,28086,Padova,PD,Veneto,5,35030 +Solesino,28087,Padova,PD,Veneto,5,35047 +Stanghella,28088,Padova,PD,Veneto,5,35048 +Teolo,28089,Padova,PD,Veneto,5,35037 +Terrassa Padovana,28090,Padova,PD,Veneto,5,35020 +Tombolo,28091,Padova,PD,Veneto,5,35019 +Torreglia,28092,Padova,PD,Veneto,5,35038 +Trebaseleghe,28093,Padova,PD,Veneto,5,35010 +Tribano,28094,Padova,PD,Veneto,5,35020 +Urbana,28095,Padova,PD,Veneto,5,35040 +Veggiano,28096,Padova,PD,Veneto,5,35030 +Vescovana,28097,Padova,PD,Veneto,5,35040 +Vighizzolo d'Este,28098,Padova,PD,Veneto,5,35040 +Vigodarzere,28099,Padova,PD,Veneto,5,35010 +Vigonza,28100,Padova,PD,Veneto,5,35010 +Villa del Conte,28101,Padova,PD,Veneto,5,35010 +Villa Estense,28102,Padova,PD,Veneto,5,35040 +Villafranca Padovana,28103,Padova,PD,Veneto,5,35010 +Villanova di Camposampiero,28104,Padova,PD,Veneto,5,35010 +Vo',28105,Padova,PD,Veneto,5,35030 +Due Carrare,28106,Padova,PD,Veneto,5,35020 +Borgo Veneto,28107,Padova,PD,Veneto,5,35046 +Adria,29001,Rovigo,RO,Veneto,5,45011 +Ariano nel Polesine,29002,Rovigo,RO,Veneto,5,45012 +Arquà Polesine,29003,Rovigo,RO,Veneto,5,45031 +Badia Polesine,29004,Rovigo,RO,Veneto,5,45021 +Bagnolo di Po,29005,Rovigo,RO,Veneto,5,45022 +Bergantino,29006,Rovigo,RO,Veneto,5,45032 +Bosaro,29007,Rovigo,RO,Veneto,5,45033 +Calto,29008,Rovigo,RO,Veneto,5,45030 +Canaro,29009,Rovigo,RO,Veneto,5,45034 +Canda,29010,Rovigo,RO,Veneto,5,45020 +Castelguglielmo,29011,Rovigo,RO,Veneto,5,45020 +Castelmassa,29012,Rovigo,RO,Veneto,5,45035 +Castelnovo Bariano,29013,Rovigo,RO,Veneto,5,45030 +Ceneselli,29014,Rovigo,RO,Veneto,5,45030 +Ceregnano,29015,Rovigo,RO,Veneto,5,45010 +Corbola,29017,Rovigo,RO,Veneto,5,45015 +Costa di Rovigo,29018,Rovigo,RO,Veneto,5,45023 +Crespino,29019,Rovigo,RO,Veneto,5,45030 +Ficarolo,29021,Rovigo,RO,Veneto,5,45036 +Fiesso Umbertiano,29022,Rovigo,RO,Veneto,5,45024 +Frassinelle Polesine,29023,Rovigo,RO,Veneto,5,45030 +Fratta Polesine,29024,Rovigo,RO,Veneto,5,45025 +Gaiba,29025,Rovigo,RO,Veneto,5,45030 +Gavello,29026,Rovigo,RO,Veneto,5,45010 +Giacciano con Baruchella,29027,Rovigo,RO,Veneto,5,45020 +Guarda Veneta,29028,Rovigo,RO,Veneto,5,45030 +Lendinara,29029,Rovigo,RO,Veneto,5,45026 +Loreo,29030,Rovigo,RO,Veneto,5,45017 +Lusia,29031,Rovigo,RO,Veneto,5,45020 +Melara,29032,Rovigo,RO,Veneto,5,45037 +Occhiobello,29033,Rovigo,RO,Veneto,5,45030 +Papozze,29034,Rovigo,RO,Veneto,5,45010 +Pettorazza Grimani,29035,Rovigo,RO,Veneto,5,45010 +Pincara,29036,Rovigo,RO,Veneto,5,45020 +Polesella,29037,Rovigo,RO,Veneto,5,45038 +Pontecchio Polesine,29038,Rovigo,RO,Veneto,5,45030 +Porto Tolle,29039,Rovigo,RO,Veneto,5,45018 +Rosolina,29040,Rovigo,RO,Veneto,5,45010 +Rovigo,29041,Rovigo,RO,Veneto,5,45100 +Salara,29042,Rovigo,RO,Veneto,5,45030 +San Bellino,29043,Rovigo,RO,Veneto,5,45020 +San Martino di Venezze,29044,Rovigo,RO,Veneto,5,45030 +Stienta,29045,Rovigo,RO,Veneto,5,45039 +Taglio di Po,29046,Rovigo,RO,Veneto,5,45019 +Trecenta,29047,Rovigo,RO,Veneto,5,45027 +Villadose,29048,Rovigo,RO,Veneto,5,45010 +Villamarzana,29049,Rovigo,RO,Veneto,5,45030 +Villanova del Ghebbo,29050,Rovigo,RO,Veneto,5,45020 +Villanova Marchesana,29051,Rovigo,RO,Veneto,5,45030 +Porto Viro,29052,Rovigo,RO,Veneto,5,45014 +Aiello del Friuli,30001,Udine,UD,Friuli-Venezia Giulia,6,33041 +Amaro,30002,Udine,UD,Friuli-Venezia Giulia,6,33020 +Ampezzo,30003,Udine,UD,Friuli-Venezia Giulia,6,33021 +Aquileia,30004,Udine,UD,Friuli-Venezia Giulia,6,33051 +Arta Terme,30005,Udine,UD,Friuli-Venezia Giulia,6,33022 +Artegna,30006,Udine,UD,Friuli-Venezia Giulia,6,33011 +Attimis,30007,Udine,UD,Friuli-Venezia Giulia,6,33040 +Bagnaria Arsa,30008,Udine,UD,Friuli-Venezia Giulia,6,33050 +Basiliano,30009,Udine,UD,Friuli-Venezia Giulia,6,33031 +Bertiolo,30010,Udine,UD,Friuli-Venezia Giulia,6,33032 +Bicinicco,30011,Udine,UD,Friuli-Venezia Giulia,6,33050 +Bordano,30012,Udine,UD,Friuli-Venezia Giulia,6,33010 +Buja,30013,Udine,UD,Friuli-Venezia Giulia,6,33030 +Buttrio,30014,Udine,UD,Friuli-Venezia Giulia,6,33042 +Camino al Tagliamento,30015,Udine,UD,Friuli-Venezia Giulia,6,33030 +Campoformido,30016,Udine,UD,Friuli-Venezia Giulia,6,33030 +Carlino,30018,Udine,UD,Friuli-Venezia Giulia,6,33050 +Cassacco,30019,Udine,UD,Friuli-Venezia Giulia,6,33010 +Castions di Strada,30020,Udine,UD,Friuli-Venezia Giulia,6,33050 +Cavazzo Carnico,30021,Udine,UD,Friuli-Venezia Giulia,6,33020 +Cercivento,30022,Udine,UD,Friuli-Venezia Giulia,6,33020 +Cervignano del Friuli,30023,Udine,UD,Friuli-Venezia Giulia,6,33052 +Chiopris-Viscone,30024,Udine,UD,Friuli-Venezia Giulia,6,33048 +Chiusaforte,30025,Udine,UD,Friuli-Venezia Giulia,6,33010 +Cividale del Friuli,30026,Udine,UD,Friuli-Venezia Giulia,6,33043 +Codroipo,30027,Udine,UD,Friuli-Venezia Giulia,6,33033 +Colloredo di Monte Albano,30028,Udine,UD,Friuli-Venezia Giulia,6,33010 +Comeglians,30029,Udine,UD,Friuli-Venezia Giulia,6,33023 +Corno di Rosazzo,30030,Udine,UD,Friuli-Venezia Giulia,6,33040 +Coseano,30031,Udine,UD,Friuli-Venezia Giulia,6,33030 +Dignano,30032,Udine,UD,Friuli-Venezia Giulia,6,33030 +Dogna,30033,Udine,UD,Friuli-Venezia Giulia,6,33010 +Drenchia,30034,Udine,UD,Friuli-Venezia Giulia,6,33040 +Enemonzo,30035,Udine,UD,Friuli-Venezia Giulia,6,33020 +Faedis,30036,Udine,UD,Friuli-Venezia Giulia,6,33040 +Fagagna,30037,Udine,UD,Friuli-Venezia Giulia,6,33034 +Flaibano,30039,Udine,UD,Friuli-Venezia Giulia,6,33030 +Forni Avoltri,30040,Udine,UD,Friuli-Venezia Giulia,6,33020 +Forni di Sopra,30041,Udine,UD,Friuli-Venezia Giulia,6,33024 +Forni di Sotto,30042,Udine,UD,Friuli-Venezia Giulia,6,33020 +Gemona del Friuli,30043,Udine,UD,Friuli-Venezia Giulia,6,33013 +Gonars,30044,Udine,UD,Friuli-Venezia Giulia,6,33050 +Grimacco,30045,Udine,UD,Friuli-Venezia Giulia,6,33040 +Latisana,30046,Udine,UD,Friuli-Venezia Giulia,6,33053 +Lauco,30047,Udine,UD,Friuli-Venezia Giulia,6,33029 +Lestizza,30048,Udine,UD,Friuli-Venezia Giulia,6,33050 +Lignano Sabbiadoro,30049,Udine,UD,Friuli-Venezia Giulia,6,33054 +Lusevera,30051,Udine,UD,Friuli-Venezia Giulia,6,33010 +Magnano in Riviera,30052,Udine,UD,Friuli-Venezia Giulia,6,33010 +Majano,30053,Udine,UD,Friuli-Venezia Giulia,6,33030 +Malborghetto Valbruna,30054,Udine,UD,Friuli-Venezia Giulia,6,33010 +Manzano,30055,Udine,UD,Friuli-Venezia Giulia,6,33044 +Marano Lagunare,30056,Udine,UD,Friuli-Venezia Giulia,6,33050 +Martignacco,30057,Udine,UD,Friuli-Venezia Giulia,6,33035 +Mereto di Tomba,30058,Udine,UD,Friuli-Venezia Giulia,6,33036 +Moggio Udinese,30059,Udine,UD,Friuli-Venezia Giulia,6,33015 +Moimacco,30060,Udine,UD,Friuli-Venezia Giulia,6,33040 +Montenars,30061,Udine,UD,Friuli-Venezia Giulia,6,33010 +Mortegliano,30062,Udine,UD,Friuli-Venezia Giulia,6,33050 +Moruzzo,30063,Udine,UD,Friuli-Venezia Giulia,6,33030 +Muzzana del Turgnano,30064,Udine,UD,Friuli-Venezia Giulia,6,33055 +Nimis,30065,Udine,UD,Friuli-Venezia Giulia,6,33045 +Osoppo,30066,Udine,UD,Friuli-Venezia Giulia,6,33010 +Ovaro,30067,Udine,UD,Friuli-Venezia Giulia,6,33025 +Pagnacco,30068,Udine,UD,Friuli-Venezia Giulia,6,33010 +Palazzolo dello Stella,30069,Udine,UD,Friuli-Venezia Giulia,6,33056 +Palmanova,30070,Udine,UD,Friuli-Venezia Giulia,6,33057 +Paluzza,30071,Udine,UD,Friuli-Venezia Giulia,6,33026 +Pasian di Prato,30072,Udine,UD,Friuli-Venezia Giulia,6,33037 +Paularo,30073,Udine,UD,Friuli-Venezia Giulia,6,33027 +Pavia di Udine,30074,Udine,UD,Friuli-Venezia Giulia,6,33050 +Pocenia,30075,Udine,UD,Friuli-Venezia Giulia,6,33050 +Pontebba,30076,Udine,UD,Friuli-Venezia Giulia,6,33016 +Porpetto,30077,Udine,UD,Friuli-Venezia Giulia,6,33050 +Povoletto,30078,Udine,UD,Friuli-Venezia Giulia,6,33040 +Pozzuolo del Friuli,30079,Udine,UD,Friuli-Venezia Giulia,6,33050 +Pradamano,30080,Udine,UD,Friuli-Venezia Giulia,6,33040 +Prato Carnico,30081,Udine,UD,Friuli-Venezia Giulia,6,33020 +Precenicco,30082,Udine,UD,Friuli-Venezia Giulia,6,33050 +Premariacco,30083,Udine,UD,Friuli-Venezia Giulia,6,33040 +Preone,30084,Udine,UD,Friuli-Venezia Giulia,6,33020 +Prepotto,30085,Udine,UD,Friuli-Venezia Giulia,6,33040 +Pulfero,30086,Udine,UD,Friuli-Venezia Giulia,6,33046 +Ragogna,30087,Udine,UD,Friuli-Venezia Giulia,6,33030 +Ravascletto,30088,Udine,UD,Friuli-Venezia Giulia,6,33020 +Raveo,30089,Udine,UD,Friuli-Venezia Giulia,6,33029 +Reana del Rojale,30090,Udine,UD,Friuli-Venezia Giulia,6,33010 +Remanzacco,30091,Udine,UD,Friuli-Venezia Giulia,6,33047 +Resia,30092,Udine,UD,Friuli-Venezia Giulia,6,33010 +Resiutta,30093,Udine,UD,Friuli-Venezia Giulia,6,33010 +Rigolato,30094,Udine,UD,Friuli-Venezia Giulia,6,33020 +Rive d'Arcano,30095,Udine,UD,Friuli-Venezia Giulia,6,33030 +Ronchis,30097,Udine,UD,Friuli-Venezia Giulia,6,33050 +Ruda,30098,Udine,UD,Friuli-Venezia Giulia,6,33050 +San Daniele del Friuli,30099,Udine,UD,Friuli-Venezia Giulia,6,33038 +San Giorgio di Nogaro,30100,Udine,UD,Friuli-Venezia Giulia,6,33058 +San Giovanni al Natisone,30101,Udine,UD,Friuli-Venezia Giulia,6,33048 +San Leonardo,30102,Udine,UD,Friuli-Venezia Giulia,6,33040 +San Pietro al Natisone,30103,Udine,UD,Friuli-Venezia Giulia,6,33049 +Santa Maria la Longa,30104,Udine,UD,Friuli-Venezia Giulia,6,33050 +San Vito al Torre,30105,Udine,UD,Friuli-Venezia Giulia,6,33050 +San Vito di Fagagna,30106,Udine,UD,Friuli-Venezia Giulia,6,33030 +Sauris,30107,Udine,UD,Friuli-Venezia Giulia,6,33020 +Savogna,30108,Udine,UD,Friuli-Venezia Giulia,6,33040 +Sedegliano,30109,Udine,UD,Friuli-Venezia Giulia,6,33039 +Socchieve,30110,Udine,UD,Friuli-Venezia Giulia,6,33020 +Stregna,30111,Udine,UD,Friuli-Venezia Giulia,6,33040 +Sutrio,30112,Udine,UD,Friuli-Venezia Giulia,6,33020 +Taipana,30113,Udine,UD,Friuli-Venezia Giulia,6,33040 +Talmassons,30114,Udine,UD,Friuli-Venezia Giulia,6,33030 +Tarcento,30116,Udine,UD,Friuli-Venezia Giulia,6,33017 +Tarvisio,30117,Udine,UD,Friuli-Venezia Giulia,6,33018 +Tavagnacco,30118,Udine,UD,Friuli-Venezia Giulia,6,33010 +Terzo d'Aquileia,30120,Udine,UD,Friuli-Venezia Giulia,6,33050 +Tolmezzo,30121,Udine,UD,Friuli-Venezia Giulia,6,33028 +Torreano,30122,Udine,UD,Friuli-Venezia Giulia,6,33040 +Torviscosa,30123,Udine,UD,Friuli-Venezia Giulia,6,33050 +Trasaghis,30124,Udine,UD,Friuli-Venezia Giulia,6,33010 +Treppo Grande,30126,Udine,UD,Friuli-Venezia Giulia,6,33010 +Tricesimo,30127,Udine,UD,Friuli-Venezia Giulia,6,33019 +Trivignano Udinese,30128,Udine,UD,Friuli-Venezia Giulia,6,33050 +Udine,30129,Udine,UD,Friuli-Venezia Giulia,6,33100 +Varmo,30130,Udine,UD,Friuli-Venezia Giulia,6,33030 +Venzone,30131,Udine,UD,Friuli-Venezia Giulia,6,33010 +Verzegnis,30132,Udine,UD,Friuli-Venezia Giulia,6,33020 +Villa Santina,30133,Udine,UD,Friuli-Venezia Giulia,6,33029 +Visco,30135,Udine,UD,Friuli-Venezia Giulia,6,33040 +Zuglio,30136,Udine,UD,Friuli-Venezia Giulia,6,33020 +Forgaria nel Friuli,30137,Udine,UD,Friuli-Venezia Giulia,6,33030 +Campolongo Tapogliano,30138,Udine,UD,Friuli-Venezia Giulia,6,33040 +Rivignano Teor,30188,Udine,UD,Friuli-Venezia Giulia,6,33061 +Sappada,30189,Udine,UD,Friuli-Venezia Giulia,6,33012 +Fiumicello Villa Vicentina,30190,Udine,UD,Friuli-Venezia Giulia,6,33050 +Treppo Ligosullo,30191,Udine,UD,Friuli-Venezia Giulia,6,33014 +Capriva del Friuli,31001,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Cormons,31002,Gorizia,GO,Friuli-Venezia Giulia,6,34071 +Doberdò del Lago,31003,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Dolegna del Collio,31004,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Farra d'Isonzo,31005,Gorizia,GO,Friuli-Venezia Giulia,6,34072 +Fogliano Redipuglia,31006,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Gorizia,31007,Gorizia,GO,Friuli-Venezia Giulia,6,34170 +Gradisca d'Isonzo,31008,Gorizia,GO,Friuli-Venezia Giulia,6,34072 +Grado,31009,Gorizia,GO,Friuli-Venezia Giulia,6,34073 +Mariano del Friuli,31010,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Medea,31011,Gorizia,GO,Friuli-Venezia Giulia,6,34076 +Monfalcone,31012,Gorizia,GO,Friuli-Venezia Giulia,6,34074 +Moraro,31013,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Mossa,31014,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Romans d'Isonzo,31015,Gorizia,GO,Friuli-Venezia Giulia,6,34076 +Ronchi dei Legionari,31016,Gorizia,GO,Friuli-Venezia Giulia,6,34077 +Sagrado,31017,Gorizia,GO,Friuli-Venezia Giulia,6,34078 +San Canzian d'Isonzo,31018,Gorizia,GO,Friuli-Venezia Giulia,6,34075 +San Floriano del Collio,31019,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +San Lorenzo Isontino,31020,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +San Pier d'Isonzo,31021,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Savogna d'Isonzo,31022,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Staranzano,31023,Gorizia,GO,Friuli-Venezia Giulia,6,34079 +Turriaco,31024,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Villesse,31025,Gorizia,GO,Friuli-Venezia Giulia,6,34070 +Duino Aurisina,32001,Trieste,TS,Friuli-Venezia Giulia,6,34011 +Monrupino,32002,Trieste,TS,Friuli-Venezia Giulia,6,34016 +Muggia,32003,Trieste,TS,Friuli-Venezia Giulia,6,34015 +San Dorligo della Valle,32004,Trieste,TS,Friuli-Venezia Giulia,6,34018 +Sgonico,32005,Trieste,TS,Friuli-Venezia Giulia,6,34010 +Trieste,32006,Trieste,TS,Friuli-Venezia Giulia,6,34121 +Andreis,93001,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Arba,93002,Pordenone,PN,Friuli-Venezia Giulia,6,33090 +Aviano,93004,Pordenone,PN,Friuli-Venezia Giulia,6,33081 +Azzano Decimo,93005,Pordenone,PN,Friuli-Venezia Giulia,6,33082 +Barcis,93006,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Brugnera,93007,Pordenone,PN,Friuli-Venezia Giulia,6,33070 +Budoia,93008,Pordenone,PN,Friuli-Venezia Giulia,6,33070 +Caneva,93009,Pordenone,PN,Friuli-Venezia Giulia,6,33070 +Casarsa della Delizia,93010,Pordenone,PN,Friuli-Venezia Giulia,6,33072 +Castelnovo del Friuli,93011,Pordenone,PN,Friuli-Venezia Giulia,6,33090 +Cavasso Nuovo,93012,Pordenone,PN,Friuli-Venezia Giulia,6,33092 +Chions,93013,Pordenone,PN,Friuli-Venezia Giulia,6,33083 +Cimolais,93014,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Claut,93015,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Clauzetto,93016,Pordenone,PN,Friuli-Venezia Giulia,6,33090 +Cordenons,93017,Pordenone,PN,Friuli-Venezia Giulia,6,33084 +Cordovado,93018,Pordenone,PN,Friuli-Venezia Giulia,6,33075 +Erto e Casso,93019,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Fanna,93020,Pordenone,PN,Friuli-Venezia Giulia,6,33092 +Fiume Veneto,93021,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Fontanafredda,93022,Pordenone,PN,Friuli-Venezia Giulia,6,33074 +Frisanco,93024,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Maniago,93025,Pordenone,PN,Friuli-Venezia Giulia,6,33085 +Meduno,93026,Pordenone,PN,Friuli-Venezia Giulia,6,33092 +Montereale Valcellina,93027,Pordenone,PN,Friuli-Venezia Giulia,6,33086 +Morsano al Tagliamento,93028,Pordenone,PN,Friuli-Venezia Giulia,6,33075 +Pasiano di Pordenone,93029,Pordenone,PN,Friuli-Venezia Giulia,6,33087 +Pinzano al Tagliamento,93030,Pordenone,PN,Friuli-Venezia Giulia,6,33094 +Polcenigo,93031,Pordenone,PN,Friuli-Venezia Giulia,6,33070 +Porcia,93032,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Pordenone,93033,Pordenone,PN,Friuli-Venezia Giulia,6,33170 +Prata di Pordenone,93034,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Pravisdomini,93035,Pordenone,PN,Friuli-Venezia Giulia,6,33076 +Roveredo in Piano,93036,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Sacile,93037,Pordenone,PN,Friuli-Venezia Giulia,6,33077 +San Giorgio della Richinvelda,93038,Pordenone,PN,Friuli-Venezia Giulia,6,33095 +San Martino al Tagliamento,93039,Pordenone,PN,Friuli-Venezia Giulia,6,33098 +San Quirino,93040,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +San Vito al Tagliamento,93041,Pordenone,PN,Friuli-Venezia Giulia,6,33078 +Sequals,93042,Pordenone,PN,Friuli-Venezia Giulia,6,33090 +Sesto al Reghena,93043,Pordenone,PN,Friuli-Venezia Giulia,6,33079 +Spilimbergo,93044,Pordenone,PN,Friuli-Venezia Giulia,6,33097 +Tramonti di Sopra,93045,Pordenone,PN,Friuli-Venezia Giulia,6,33090 +Tramonti di Sotto,93046,Pordenone,PN,Friuli-Venezia Giulia,6,33090 +Travesio,93047,Pordenone,PN,Friuli-Venezia Giulia,6,33090 +Vito d'Asio,93049,Pordenone,PN,Friuli-Venezia Giulia,6,33090 +Vivaro,93050,Pordenone,PN,Friuli-Venezia Giulia,6,33099 +Zoppola,93051,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Vajont,93052,Pordenone,PN,Friuli-Venezia Giulia,6,33080 +Valvasone Arzene,93053,Pordenone,PN,Friuli-Venezia Giulia,6,33098 +Airole,8001,Imperia,IM,Liguria,7,18030 +Apricale,8002,Imperia,IM,Liguria,7,18035 +Aquila d'Arroscia,8003,Imperia,IM,Liguria,7,18020 +Armo,8004,Imperia,IM,Liguria,7,18026 +Aurigo,8005,Imperia,IM,Liguria,7,18020 +Badalucco,8006,Imperia,IM,Liguria,7,18010 +Bajardo,8007,Imperia,IM,Liguria,7,18031 +Bordighera,8008,Imperia,IM,Liguria,7,18012 +Borghetto d'Arroscia,8009,Imperia,IM,Liguria,7,18020 +Borgomaro,8010,Imperia,IM,Liguria,7,18021 +Camporosso,8011,Imperia,IM,Liguria,7,18033 +Caravonica,8012,Imperia,IM,Liguria,7,18020 +Castellaro,8014,Imperia,IM,Liguria,7,18011 +Castel Vittorio,8015,Imperia,IM,Liguria,7,18030 +Ceriana,8016,Imperia,IM,Liguria,7,18034 +Cervo,8017,Imperia,IM,Liguria,7,18010 +Cesio,8018,Imperia,IM,Liguria,7,18022 +Chiusanico,8019,Imperia,IM,Liguria,7,18027 +Chiusavecchia,8020,Imperia,IM,Liguria,7,18027 +Cipressa,8021,Imperia,IM,Liguria,7,18017 +Civezza,8022,Imperia,IM,Liguria,7,18017 +Cosio d'Arroscia,8023,Imperia,IM,Liguria,7,18023 +Costarainera,8024,Imperia,IM,Liguria,7,18017 +Diano Arentino,8025,Imperia,IM,Liguria,7,18013 +Diano Castello,8026,Imperia,IM,Liguria,7,18013 +Diano Marina,8027,Imperia,IM,Liguria,7,18013 +Diano San Pietro,8028,Imperia,IM,Liguria,7,18013 +Dolceacqua,8029,Imperia,IM,Liguria,7,18035 +Dolcedo,8030,Imperia,IM,Liguria,7,18020 +Imperia,8031,Imperia,IM,Liguria,7,18100 +Isolabona,8032,Imperia,IM,Liguria,7,18035 +Lucinasco,8033,Imperia,IM,Liguria,7,18020 +Mendatica,8034,Imperia,IM,Liguria,7,18025 +Molini di Triora,8035,Imperia,IM,Liguria,7,18010 +Montegrosso Pian Latte,8037,Imperia,IM,Liguria,7,18025 +Olivetta San Michele,8038,Imperia,IM,Liguria,7,18030 +Ospedaletti,8039,Imperia,IM,Liguria,7,18014 +Perinaldo,8040,Imperia,IM,Liguria,7,18032 +Pietrabruna,8041,Imperia,IM,Liguria,7,18010 +Pieve di Teco,8042,Imperia,IM,Liguria,7,18026 +Pigna,8043,Imperia,IM,Liguria,7,18037 +Pompeiana,8044,Imperia,IM,Liguria,7,18015 +Pontedassio,8045,Imperia,IM,Liguria,7,18027 +Pornassio,8046,Imperia,IM,Liguria,7,18024 +Prelà,8047,Imperia,IM,Liguria,7,18020 +Ranzo,8048,Imperia,IM,Liguria,7,18020 +Rezzo,8049,Imperia,IM,Liguria,7,18026 +Riva Ligure,8050,Imperia,IM,Liguria,7,18015 +Rocchetta Nervina,8051,Imperia,IM,Liguria,7,18030 +San Bartolomeo al Mare,8052,Imperia,IM,Liguria,7,18016 +San Biagio della Cima,8053,Imperia,IM,Liguria,7,18036 +San Lorenzo al Mare,8054,Imperia,IM,Liguria,7,18017 +Sanremo,8055,Imperia,IM,Liguria,7,18038 +Santo Stefano al Mare,8056,Imperia,IM,Liguria,7,18010 +Seborga,8057,Imperia,IM,Liguria,7,18012 +Soldano,8058,Imperia,IM,Liguria,7,18036 +Taggia,8059,Imperia,IM,Liguria,7,18018 +Terzorio,8060,Imperia,IM,Liguria,7,18010 +Triora,8061,Imperia,IM,Liguria,7,18010 +Vallebona,8062,Imperia,IM,Liguria,7,18012 +Vallecrosia,8063,Imperia,IM,Liguria,7,18019 +Vasia,8064,Imperia,IM,Liguria,7,18020 +Ventimiglia,8065,Imperia,IM,Liguria,7,18039 +Vessalico,8066,Imperia,IM,Liguria,7,18026 +Villa Faraldi,8067,Imperia,IM,Liguria,7,18010 +Montalto Carpasio,8068,Imperia,IM,Liguria,7,18010 +Alassio,9001,Savona,SV,Liguria,7,17021 +Albenga,9002,Savona,SV,Liguria,7,17031 +Albissola Marina,9003,Savona,SV,Liguria,7,17012 +Albisola Superiore,9004,Savona,SV,Liguria,7,17011 +Altare,9005,Savona,SV,Liguria,7,17041 +Andora,9006,Savona,SV,Liguria,7,17051 +Arnasco,9007,Savona,SV,Liguria,7,17032 +Balestrino,9008,Savona,SV,Liguria,7,17020 +Bardineto,9009,Savona,SV,Liguria,7,17057 +Bergeggi,9010,Savona,SV,Liguria,7,17028 +Boissano,9011,Savona,SV,Liguria,7,17054 +Borghetto Santo Spirito,9012,Savona,SV,Liguria,7,17052 +Borgio Verezzi,9013,Savona,SV,Liguria,7,17022 +Bormida,9014,Savona,SV,Liguria,7,17045 +Cairo Montenotte,9015,Savona,SV,Liguria,7,17014 +Calice Ligure,9016,Savona,SV,Liguria,7,17020 +Calizzano,9017,Savona,SV,Liguria,7,17057 +Carcare,9018,Savona,SV,Liguria,7,17043 +Casanova Lerrone,9019,Savona,SV,Liguria,7,17033 +Castelbianco,9020,Savona,SV,Liguria,7,17030 +Castelvecchio di Rocca Barbena,9021,Savona,SV,Liguria,7,17034 +Celle Ligure,9022,Savona,SV,Liguria,7,17015 +Cengio,9023,Savona,SV,Liguria,7,17056 +Ceriale,9024,Savona,SV,Liguria,7,17023 +Cisano sul Neva,9025,Savona,SV,Liguria,7,17035 +Cosseria,9026,Savona,SV,Liguria,7,17017 +Dego,9027,Savona,SV,Liguria,7,17058 +Erli,9028,Savona,SV,Liguria,7,17030 +Finale Ligure,9029,Savona,SV,Liguria,7,17024 +Garlenda,9030,Savona,SV,Liguria,7,17033 +Giustenice,9031,Savona,SV,Liguria,7,17027 +Giusvalla,9032,Savona,SV,Liguria,7,17010 +Laigueglia,9033,Savona,SV,Liguria,7,17053 +Loano,9034,Savona,SV,Liguria,7,17025 +Magliolo,9035,Savona,SV,Liguria,7,17020 +Mallare,9036,Savona,SV,Liguria,7,17045 +Massimino,9037,Savona,SV,Liguria,7,12071 +Millesimo,9038,Savona,SV,Liguria,7,17017 +Mioglia,9039,Savona,SV,Liguria,7,17040 +Murialdo,9040,Savona,SV,Liguria,7,17013 +Nasino,9041,Savona,SV,Liguria,7,17030 +Noli,9042,Savona,SV,Liguria,7,17026 +Onzo,9043,Savona,SV,Liguria,7,17037 +Orco Feglino,9044,Savona,SV,Liguria,7,17024 +Ortovero,9045,Savona,SV,Liguria,7,17037 +Osiglia,9046,Savona,SV,Liguria,7,17010 +Pallare,9047,Savona,SV,Liguria,7,17043 +Piana Crixia,9048,Savona,SV,Liguria,7,17058 +Pietra Ligure,9049,Savona,SV,Liguria,7,17027 +Plodio,9050,Savona,SV,Liguria,7,17043 +Pontinvrea,9051,Savona,SV,Liguria,7,17042 +Quiliano,9052,Savona,SV,Liguria,7,17047 +Rialto,9053,Savona,SV,Liguria,7,17020 +Roccavignale,9054,Savona,SV,Liguria,7,17017 +Sassello,9055,Savona,SV,Liguria,7,17046 +Savona,9056,Savona,SV,Liguria,7,17100 +Spotorno,9057,Savona,SV,Liguria,7,17028 +Stella,9058,Savona,SV,Liguria,7,17044 +Stellanello,9059,Savona,SV,Liguria,7,17020 +Testico,9060,Savona,SV,Liguria,7,17020 +Toirano,9061,Savona,SV,Liguria,7,17055 +Tovo San Giacomo,9062,Savona,SV,Liguria,7,17020 +Urbe,9063,Savona,SV,Liguria,7,17048 +Vado Ligure,9064,Savona,SV,Liguria,7,17047 +Varazze,9065,Savona,SV,Liguria,7,17019 +Vendone,9066,Savona,SV,Liguria,7,17032 +Vezzi Portio,9067,Savona,SV,Liguria,7,17028 +Villanova d'Albenga,9068,Savona,SV,Liguria,7,17038 +Zuccarello,9069,Savona,SV,Liguria,7,17039 +Arenzano,10001,Genova,GE,Liguria,7,16011 +Avegno,10002,Genova,GE,Liguria,7,16030 +Bargagli,10003,Genova,GE,Liguria,7,16021 +Bogliasco,10004,Genova,GE,Liguria,7,16031 +Borzonasca,10005,Genova,GE,Liguria,7,16041 +Busalla,10006,Genova,GE,Liguria,7,16012 +Camogli,10007,Genova,GE,Liguria,7,16032 +Campo Ligure,10008,Genova,GE,Liguria,7,16013 +Campomorone,10009,Genova,GE,Liguria,7,16014 +Carasco,10010,Genova,GE,Liguria,7,16042 +Casarza Ligure,10011,Genova,GE,Liguria,7,16030 +Casella,10012,Genova,GE,Liguria,7,16015 +Castiglione Chiavarese,10013,Genova,GE,Liguria,7,16030 +Ceranesi,10014,Genova,GE,Liguria,7,16014 +Chiavari,10015,Genova,GE,Liguria,7,16043 +Cicagna,10016,Genova,GE,Liguria,7,16044 +Cogoleto,10017,Genova,GE,Liguria,7,16016 +Cogorno,10018,Genova,GE,Liguria,7,16030 +Coreglia Ligure,10019,Genova,GE,Liguria,7,16040 +Crocefieschi,10020,Genova,GE,Liguria,7,16010 +Davagna,10021,Genova,GE,Liguria,7,16022 +Fascia,10022,Genova,GE,Liguria,7,16020 +Favale di Malvaro,10023,Genova,GE,Liguria,7,16040 +Fontanigorda,10024,Genova,GE,Liguria,7,16023 +Genova,10025,Genova,GE,Liguria,7,16124 +Gorreto,10026,Genova,GE,Liguria,7,16020 +Isola del Cantone,10027,Genova,GE,Liguria,7,16017 +Lavagna,10028,Genova,GE,Liguria,7,16033 +Leivi,10029,Genova,GE,Liguria,7,16040 +Lorsica,10030,Genova,GE,Liguria,7,16045 +Lumarzo,10031,Genova,GE,Liguria,7,16024 +Masone,10032,Genova,GE,Liguria,7,16010 +Mele,10033,Genova,GE,Liguria,7,16010 +Mezzanego,10034,Genova,GE,Liguria,7,16046 +Mignanego,10035,Genova,GE,Liguria,7,16018 +Moconesi,10036,Genova,GE,Liguria,7,16047 +Moneglia,10037,Genova,GE,Liguria,7,16030 +Montebruno,10038,Genova,GE,Liguria,7,16025 +Montoggio,10039,Genova,GE,Liguria,7,16026 +Ne,10040,Genova,GE,Liguria,7,16040 +Neirone,10041,Genova,GE,Liguria,7,16040 +Orero,10042,Genova,GE,Liguria,7,16040 +Pieve Ligure,10043,Genova,GE,Liguria,7,16030 +Portofino,10044,Genova,GE,Liguria,7,16034 +Propata,10045,Genova,GE,Liguria,7,16027 +Rapallo,10046,Genova,GE,Liguria,7,16035 +Recco,10047,Genova,GE,Liguria,7,16036 +Rezzoaglio,10048,Genova,GE,Liguria,7,16048 +Ronco Scrivia,10049,Genova,GE,Liguria,7,16019 +Rondanina,10050,Genova,GE,Liguria,7,16025 +Rossiglione,10051,Genova,GE,Liguria,7,16010 +Rovegno,10052,Genova,GE,Liguria,7,16028 +San Colombano Certenoli,10053,Genova,GE,Liguria,7,16040 +Santa Margherita Ligure,10054,Genova,GE,Liguria,7,16038 +Sant'Olcese,10055,Genova,GE,Liguria,7,16010 +Santo Stefano d'Aveto,10056,Genova,GE,Liguria,7,16049 +Savignone,10057,Genova,GE,Liguria,7,16010 +Serra Riccò,10058,Genova,GE,Liguria,7,16010 +Sestri Levante,10059,Genova,GE,Liguria,7,16039 +Sori,10060,Genova,GE,Liguria,7,16030 +Tiglieto,10061,Genova,GE,Liguria,7,16010 +Torriglia,10062,Genova,GE,Liguria,7,16029 +Tribogna,10063,Genova,GE,Liguria,7,16030 +Uscio,10064,Genova,GE,Liguria,7,16030 +Valbrevenna,10065,Genova,GE,Liguria,7,16010 +Vobbia,10066,Genova,GE,Liguria,7,16010 +Zoagli,10067,Genova,GE,Liguria,7,16030 +Ameglia,11001,La Spezia,SP,Liguria,7,19031 +Arcola,11002,La Spezia,SP,Liguria,7,19021 +Beverino,11003,La Spezia,SP,Liguria,7,19020 +Bolano,11004,La Spezia,SP,Liguria,7,19020 +Bonassola,11005,La Spezia,SP,Liguria,7,19011 +Borghetto di Vara,11006,La Spezia,SP,Liguria,7,19020 +Brugnato,11007,La Spezia,SP,Liguria,7,19020 +Calice al Cornoviglio,11008,La Spezia,SP,Liguria,7,19020 +Carro,11009,La Spezia,SP,Liguria,7,19012 +Carrodano,11010,La Spezia,SP,Liguria,7,19020 +Castelnuovo Magra,11011,La Spezia,SP,Liguria,7,19033 +Deiva Marina,11012,La Spezia,SP,Liguria,7,19013 +Follo,11013,La Spezia,SP,Liguria,7,19020 +Framura,11014,La Spezia,SP,Liguria,7,19014 +La Spezia,11015,La Spezia,SP,Liguria,7,19124 +Lerici,11016,La Spezia,SP,Liguria,7,19032 +Levanto,11017,La Spezia,SP,Liguria,7,19015 +Maissana,11018,La Spezia,SP,Liguria,7,19010 +Monterosso al Mare,11019,La Spezia,SP,Liguria,7,19016 +Luni,11020,La Spezia,SP,Liguria,7,19034 +Pignone,11021,La Spezia,SP,Liguria,7,19020 +Portovenere,11022,La Spezia,SP,Liguria,7,19025 +Riccò del Golfo di Spezia,11023,La Spezia,SP,Liguria,7,19020 +Riomaggiore,11024,La Spezia,SP,Liguria,7,19017 +Rocchetta di Vara,11025,La Spezia,SP,Liguria,7,19020 +Santo Stefano di Magra,11026,La Spezia,SP,Liguria,7,19037 +Sarzana,11027,La Spezia,SP,Liguria,7,19038 +Sesta Godano,11028,La Spezia,SP,Liguria,7,19020 +Varese Ligure,11029,La Spezia,SP,Liguria,7,19028 +Vernazza,11030,La Spezia,SP,Liguria,7,19018 +Vezzano Ligure,11031,La Spezia,SP,Liguria,7,19020 +Zignago,11032,La Spezia,SP,Liguria,7,19020 +Agazzano,33001,Piacenza,PC,Emilia-Romagna,8,29010 +Alseno,33002,Piacenza,PC,Emilia-Romagna,8,29010 +Besenzone,33003,Piacenza,PC,Emilia-Romagna,8,29010 +Bettola,33004,Piacenza,PC,Emilia-Romagna,8,29021 +Bobbio,33005,Piacenza,PC,Emilia-Romagna,8,29022 +Borgonovo Val Tidone,33006,Piacenza,PC,Emilia-Romagna,8,29011 +Cadeo,33007,Piacenza,PC,Emilia-Romagna,8,29010 +Calendasco,33008,Piacenza,PC,Emilia-Romagna,8,29010 +Caorso,33010,Piacenza,PC,Emilia-Romagna,8,29012 +Carpaneto Piacentino,33011,Piacenza,PC,Emilia-Romagna,8,29013 +Castell'Arquato,33012,Piacenza,PC,Emilia-Romagna,8,29014 +Castel San Giovanni,33013,Piacenza,PC,Emilia-Romagna,8,29015 +Castelvetro Piacentino,33014,Piacenza,PC,Emilia-Romagna,8,29010 +Cerignale,33015,Piacenza,PC,Emilia-Romagna,8,29020 +Coli,33016,Piacenza,PC,Emilia-Romagna,8,29020 +Corte Brugnatella,33017,Piacenza,PC,Emilia-Romagna,8,29020 +Cortemaggiore,33018,Piacenza,PC,Emilia-Romagna,8,29016 +Farini,33019,Piacenza,PC,Emilia-Romagna,8,29023 +Ferriere,33020,Piacenza,PC,Emilia-Romagna,8,29024 +Fiorenzuola d'Arda,33021,Piacenza,PC,Emilia-Romagna,8,29017 +Gazzola,33022,Piacenza,PC,Emilia-Romagna,8,29010 +Gossolengo,33023,Piacenza,PC,Emilia-Romagna,8,29020 +Gragnano Trebbiense,33024,Piacenza,PC,Emilia-Romagna,8,29010 +Gropparello,33025,Piacenza,PC,Emilia-Romagna,8,29025 +Lugagnano Val d'Arda,33026,Piacenza,PC,Emilia-Romagna,8,29018 +Monticelli d'Ongina,33027,Piacenza,PC,Emilia-Romagna,8,29010 +Morfasso,33028,Piacenza,PC,Emilia-Romagna,8,29020 +Ottone,33030,Piacenza,PC,Emilia-Romagna,8,29026 +Piacenza,33032,Piacenza,PC,Emilia-Romagna,8,29120 +Pianello Val Tidone,33033,Piacenza,PC,Emilia-Romagna,8,29010 +Piozzano,33034,Piacenza,PC,Emilia-Romagna,8,29010 +Podenzano,33035,Piacenza,PC,Emilia-Romagna,8,29027 +Ponte dell'Olio,33036,Piacenza,PC,Emilia-Romagna,8,29028 +Pontenure,33037,Piacenza,PC,Emilia-Romagna,8,29010 +Rivergaro,33038,Piacenza,PC,Emilia-Romagna,8,29029 +Rottofreno,33039,Piacenza,PC,Emilia-Romagna,8,29010 +San Giorgio Piacentino,33040,Piacenza,PC,Emilia-Romagna,8,29019 +San Pietro in Cerro,33041,Piacenza,PC,Emilia-Romagna,8,29010 +Sarmato,33042,Piacenza,PC,Emilia-Romagna,8,29010 +Travo,33043,Piacenza,PC,Emilia-Romagna,8,29020 +Vernasca,33044,Piacenza,PC,Emilia-Romagna,8,29010 +Vigolzone,33045,Piacenza,PC,Emilia-Romagna,8,29020 +Villanova sull'Arda,33046,Piacenza,PC,Emilia-Romagna,8,29010 +Zerba,33047,Piacenza,PC,Emilia-Romagna,8,29020 +Ziano Piacentino,33048,Piacenza,PC,Emilia-Romagna,8,29010 +Alta Val Tidone,33049,Piacenza,PC,Emilia-Romagna,8,29010 +Albareto,34001,Parma,PR,Emilia-Romagna,8,43051 +Bardi,34002,Parma,PR,Emilia-Romagna,8,43032 +Bedonia,34003,Parma,PR,Emilia-Romagna,8,43041 +Berceto,34004,Parma,PR,Emilia-Romagna,8,43042 +Bore,34005,Parma,PR,Emilia-Romagna,8,43030 +Borgo Val di Taro,34006,Parma,PR,Emilia-Romagna,8,43043 +Busseto,34007,Parma,PR,Emilia-Romagna,8,43011 +Calestano,34008,Parma,PR,Emilia-Romagna,8,43030 +Collecchio,34009,Parma,PR,Emilia-Romagna,8,43044 +Colorno,34010,Parma,PR,Emilia-Romagna,8,43052 +Compiano,34011,Parma,PR,Emilia-Romagna,8,43053 +Corniglio,34012,Parma,PR,Emilia-Romagna,8,43021 +Felino,34013,Parma,PR,Emilia-Romagna,8,43035 +Fidenza,34014,Parma,PR,Emilia-Romagna,8,43036 +Fontanellato,34015,Parma,PR,Emilia-Romagna,8,43012 +Fontevivo,34016,Parma,PR,Emilia-Romagna,8,43010 +Fornovo di Taro,34017,Parma,PR,Emilia-Romagna,8,43045 +Langhirano,34018,Parma,PR,Emilia-Romagna,8,43013 +Lesignano de' Bagni,34019,Parma,PR,Emilia-Romagna,8,43037 +Medesano,34020,Parma,PR,Emilia-Romagna,8,43014 +Monchio delle Corti,34022,Parma,PR,Emilia-Romagna,8,43010 +Montechiarugolo,34023,Parma,PR,Emilia-Romagna,8,43022 +Neviano degli Arduini,34024,Parma,PR,Emilia-Romagna,8,43024 +Noceto,34025,Parma,PR,Emilia-Romagna,8,43015 +Palanzano,34026,Parma,PR,Emilia-Romagna,8,43025 +Parma,34027,Parma,PR,Emilia-Romagna,8,43121 +Pellegrino Parmense,34028,Parma,PR,Emilia-Romagna,8,43047 +Roccabianca,34030,Parma,PR,Emilia-Romagna,8,43010 +Sala Baganza,34031,Parma,PR,Emilia-Romagna,8,43038 +Salsomaggiore Terme,34032,Parma,PR,Emilia-Romagna,8,43039 +San Secondo Parmense,34033,Parma,PR,Emilia-Romagna,8,43017 +Solignano,34035,Parma,PR,Emilia-Romagna,8,43040 +Soragna,34036,Parma,PR,Emilia-Romagna,8,43019 +Terenzo,34038,Parma,PR,Emilia-Romagna,8,43040 +Tizzano Val Parma,34039,Parma,PR,Emilia-Romagna,8,43028 +Tornolo,34040,Parma,PR,Emilia-Romagna,8,43059 +Torrile,34041,Parma,PR,Emilia-Romagna,8,43056 +Traversetolo,34042,Parma,PR,Emilia-Romagna,8,43029 +Valmozzola,34044,Parma,PR,Emilia-Romagna,8,43050 +Varano de' Melegari,34045,Parma,PR,Emilia-Romagna,8,43040 +Varsi,34046,Parma,PR,Emilia-Romagna,8,43049 +Sissa Trecasali,34049,Parma,PR,Emilia-Romagna,8,43018 +Polesine Zibello,34050,Parma,PR,Emilia-Romagna,8,43010 +Sorbolo Mezzani,34051,Parma,PR,Emilia-Romagna,8,43058 +Albinea,35001,Reggio nell'Emilia,RE,Emilia-Romagna,8,42020 +Bagnolo in Piano,35002,Reggio nell'Emilia,RE,Emilia-Romagna,8,42011 +Baiso,35003,Reggio nell'Emilia,RE,Emilia-Romagna,8,42031 +Bibbiano,35004,Reggio nell'Emilia,RE,Emilia-Romagna,8,42021 +Boretto,35005,Reggio nell'Emilia,RE,Emilia-Romagna,8,42022 +Brescello,35006,Reggio nell'Emilia,RE,Emilia-Romagna,8,42041 +Cadelbosco di Sopra,35008,Reggio nell'Emilia,RE,Emilia-Romagna,8,42023 +Campagnola Emilia,35009,Reggio nell'Emilia,RE,Emilia-Romagna,8,42012 +Campegine,35010,Reggio nell'Emilia,RE,Emilia-Romagna,8,42040 +Carpineti,35011,Reggio nell'Emilia,RE,Emilia-Romagna,8,42033 +Casalgrande,35012,Reggio nell'Emilia,RE,Emilia-Romagna,8,42013 +Casina,35013,Reggio nell'Emilia,RE,Emilia-Romagna,8,42034 +Castellarano,35014,Reggio nell'Emilia,RE,Emilia-Romagna,8,42014 +Castelnovo di Sotto,35015,Reggio nell'Emilia,RE,Emilia-Romagna,8,42024 +Castelnovo ne' Monti,35016,Reggio nell'Emilia,RE,Emilia-Romagna,8,42035 +Cavriago,35017,Reggio nell'Emilia,RE,Emilia-Romagna,8,42025 +Canossa,35018,Reggio nell'Emilia,RE,Emilia-Romagna,8,42026 +Correggio,35020,Reggio nell'Emilia,RE,Emilia-Romagna,8,42015 +Fabbrico,35021,Reggio nell'Emilia,RE,Emilia-Romagna,8,42042 +Gattatico,35022,Reggio nell'Emilia,RE,Emilia-Romagna,8,42043 +Gualtieri,35023,Reggio nell'Emilia,RE,Emilia-Romagna,8,42044 +Guastalla,35024,Reggio nell'Emilia,RE,Emilia-Romagna,8,42016 +Luzzara,35026,Reggio nell'Emilia,RE,Emilia-Romagna,8,42045 +Montecchio Emilia,35027,Reggio nell'Emilia,RE,Emilia-Romagna,8,42027 +Novellara,35028,Reggio nell'Emilia,RE,Emilia-Romagna,8,42017 +Poviglio,35029,Reggio nell'Emilia,RE,Emilia-Romagna,8,42028 +Quattro Castella,35030,Reggio nell'Emilia,RE,Emilia-Romagna,8,42020 +Reggiolo,35032,Reggio nell'Emilia,RE,Emilia-Romagna,8,42046 +Reggio nell'Emilia,35033,Reggio nell'Emilia,RE,Emilia-Romagna,8,42121 +Rio Saliceto,35034,Reggio nell'Emilia,RE,Emilia-Romagna,8,42010 +Rolo,35035,Reggio nell'Emilia,RE,Emilia-Romagna,8,42047 +Rubiera,35036,Reggio nell'Emilia,RE,Emilia-Romagna,8,42048 +San Martino in Rio,35037,Reggio nell'Emilia,RE,Emilia-Romagna,8,42018 +San Polo d'Enza,35038,Reggio nell'Emilia,RE,Emilia-Romagna,8,42020 +Sant'Ilario d'Enza,35039,Reggio nell'Emilia,RE,Emilia-Romagna,8,42049 +Scandiano,35040,Reggio nell'Emilia,RE,Emilia-Romagna,8,42019 +Toano,35041,Reggio nell'Emilia,RE,Emilia-Romagna,8,42010 +Vetto,35042,Reggio nell'Emilia,RE,Emilia-Romagna,8,42020 +Vezzano sul Crostolo,35043,Reggio nell'Emilia,RE,Emilia-Romagna,8,42030 +Viano,35044,Reggio nell'Emilia,RE,Emilia-Romagna,8,42030 +Villa Minozzo,35045,Reggio nell'Emilia,RE,Emilia-Romagna,8,42030 +Ventasso,35046,Reggio nell'Emilia,RE,Emilia-Romagna,8,42032 +Bastiglia,36001,Modena,MO,Emilia-Romagna,8,41030 +Bomporto,36002,Modena,MO,Emilia-Romagna,8,41030 +Campogalliano,36003,Modena,MO,Emilia-Romagna,8,41011 +Camposanto,36004,Modena,MO,Emilia-Romagna,8,41031 +Carpi,36005,Modena,MO,Emilia-Romagna,8,41012 +Castelfranco Emilia,36006,Modena,MO,Emilia-Romagna,8,41013 +Castelnuovo Rangone,36007,Modena,MO,Emilia-Romagna,8,41051 +Castelvetro di Modena,36008,Modena,MO,Emilia-Romagna,8,41014 +Cavezzo,36009,Modena,MO,Emilia-Romagna,8,41032 +Concordia sulla Secchia,36010,Modena,MO,Emilia-Romagna,8,41033 +Fanano,36011,Modena,MO,Emilia-Romagna,8,41021 +Finale Emilia,36012,Modena,MO,Emilia-Romagna,8,41034 +Fiorano Modenese,36013,Modena,MO,Emilia-Romagna,8,41042 +Fiumalbo,36014,Modena,MO,Emilia-Romagna,8,41022 +Formigine,36015,Modena,MO,Emilia-Romagna,8,41043 +Frassinoro,36016,Modena,MO,Emilia-Romagna,8,41044 +Guiglia,36017,Modena,MO,Emilia-Romagna,8,41052 +Lama Mocogno,36018,Modena,MO,Emilia-Romagna,8,41023 +Maranello,36019,Modena,MO,Emilia-Romagna,8,41053 +Marano sul Panaro,36020,Modena,MO,Emilia-Romagna,8,41054 +Medolla,36021,Modena,MO,Emilia-Romagna,8,41036 +Mirandola,36022,Modena,MO,Emilia-Romagna,8,41037 +Modena,36023,Modena,MO,Emilia-Romagna,8,41121 +Montecreto,36024,Modena,MO,Emilia-Romagna,8,41025 +Montefiorino,36025,Modena,MO,Emilia-Romagna,8,41045 +Montese,36026,Modena,MO,Emilia-Romagna,8,41055 +Nonantola,36027,Modena,MO,Emilia-Romagna,8,41015 +Novi di Modena,36028,Modena,MO,Emilia-Romagna,8,41016 +Palagano,36029,Modena,MO,Emilia-Romagna,8,41046 +Pavullo nel Frignano,36030,Modena,MO,Emilia-Romagna,8,41026 +Pievepelago,36031,Modena,MO,Emilia-Romagna,8,41027 +Polinago,36032,Modena,MO,Emilia-Romagna,8,41040 +Prignano sulla Secchia,36033,Modena,MO,Emilia-Romagna,8,41048 +Ravarino,36034,Modena,MO,Emilia-Romagna,8,41017 +Riolunato,36035,Modena,MO,Emilia-Romagna,8,41020 +San Cesario sul Panaro,36036,Modena,MO,Emilia-Romagna,8,41018 +San Felice sul Panaro,36037,Modena,MO,Emilia-Romagna,8,41038 +San Possidonio,36038,Modena,MO,Emilia-Romagna,8,41039 +San Prospero,36039,Modena,MO,Emilia-Romagna,8,41030 +Sassuolo,36040,Modena,MO,Emilia-Romagna,8,41049 +Savignano sul Panaro,36041,Modena,MO,Emilia-Romagna,8,41056 +Serramazzoni,36042,Modena,MO,Emilia-Romagna,8,41028 +Sestola,36043,Modena,MO,Emilia-Romagna,8,41029 +Soliera,36044,Modena,MO,Emilia-Romagna,8,41019 +Spilamberto,36045,Modena,MO,Emilia-Romagna,8,41057 +Vignola,36046,Modena,MO,Emilia-Romagna,8,41058 +Zocca,36047,Modena,MO,Emilia-Romagna,8,41059 +Anzola dell'Emilia,37001,Bologna,BO,Emilia-Romagna,8,40011 +Argelato,37002,Bologna,BO,Emilia-Romagna,8,40050 +Baricella,37003,Bologna,BO,Emilia-Romagna,8,40052 +Bentivoglio,37005,Bologna,BO,Emilia-Romagna,8,40010 +Bologna,37006,Bologna,BO,Emilia-Romagna,8,40121 +Borgo Tossignano,37007,Bologna,BO,Emilia-Romagna,8,40021 +Budrio,37008,Bologna,BO,Emilia-Romagna,8,40054 +Calderara di Reno,37009,Bologna,BO,Emilia-Romagna,8,40012 +Camugnano,37010,Bologna,BO,Emilia-Romagna,8,40032 +Casalecchio di Reno,37011,Bologna,BO,Emilia-Romagna,8,40033 +Casalfiumanese,37012,Bologna,BO,Emilia-Romagna,8,40020 +Castel d'Aiano,37013,Bologna,BO,Emilia-Romagna,8,40034 +Castel del Rio,37014,Bologna,BO,Emilia-Romagna,8,40022 +Castel di Casio,37015,Bologna,BO,Emilia-Romagna,8,40030 +Castel Guelfo di Bologna,37016,Bologna,BO,Emilia-Romagna,8,40023 +Castello d'Argile,37017,Bologna,BO,Emilia-Romagna,8,40050 +Castel Maggiore,37019,Bologna,BO,Emilia-Romagna,8,40013 +Castel San Pietro Terme,37020,Bologna,BO,Emilia-Romagna,8,40024 +Castenaso,37021,Bologna,BO,Emilia-Romagna,8,40055 +Castiglione dei Pepoli,37022,Bologna,BO,Emilia-Romagna,8,40035 +Crevalcore,37024,Bologna,BO,Emilia-Romagna,8,40014 +Dozza,37025,Bologna,BO,Emilia-Romagna,8,40060 +Fontanelice,37026,Bologna,BO,Emilia-Romagna,8,40025 +Gaggio Montano,37027,Bologna,BO,Emilia-Romagna,8,40041 +Galliera,37028,Bologna,BO,Emilia-Romagna,8,40015 +Granarolo dell'Emilia,37030,Bologna,BO,Emilia-Romagna,8,40057 +Grizzana Morandi,37031,Bologna,BO,Emilia-Romagna,8,40030 +Imola,37032,Bologna,BO,Emilia-Romagna,8,40026 +Lizzano in Belvedere,37033,Bologna,BO,Emilia-Romagna,8,40042 +Loiano,37034,Bologna,BO,Emilia-Romagna,8,40050 +Malalbergo,37035,Bologna,BO,Emilia-Romagna,8,40051 +Marzabotto,37036,Bologna,BO,Emilia-Romagna,8,40043 +Medicina,37037,Bologna,BO,Emilia-Romagna,8,40059 +Minerbio,37038,Bologna,BO,Emilia-Romagna,8,40061 +Molinella,37039,Bologna,BO,Emilia-Romagna,8,40062 +Monghidoro,37040,Bologna,BO,Emilia-Romagna,8,40063 +Monterenzio,37041,Bologna,BO,Emilia-Romagna,8,40050 +Monte San Pietro,37042,Bologna,BO,Emilia-Romagna,8,40050 +Monzuno,37044,Bologna,BO,Emilia-Romagna,8,40036 +Mordano,37045,Bologna,BO,Emilia-Romagna,8,40027 +Ozzano dell'Emilia,37046,Bologna,BO,Emilia-Romagna,8,40064 +Pianoro,37047,Bologna,BO,Emilia-Romagna,8,40065 +Pieve di Cento,37048,Bologna,BO,Emilia-Romagna,8,40066 +Sala Bolognese,37050,Bologna,BO,Emilia-Romagna,8,40010 +San Benedetto Val di Sambro,37051,Bologna,BO,Emilia-Romagna,8,40048 +San Giorgio di Piano,37052,Bologna,BO,Emilia-Romagna,8,40016 +San Giovanni in Persiceto,37053,Bologna,BO,Emilia-Romagna,8,40017 +San Lazzaro di Savena,37054,Bologna,BO,Emilia-Romagna,8,40068 +San Pietro in Casale,37055,Bologna,BO,Emilia-Romagna,8,40018 +Sant'Agata Bolognese,37056,Bologna,BO,Emilia-Romagna,8,40019 +Sasso Marconi,37057,Bologna,BO,Emilia-Romagna,8,40037 +Vergato,37059,Bologna,BO,Emilia-Romagna,8,40038 +Zola Predosa,37060,Bologna,BO,Emilia-Romagna,8,40069 +Valsamoggia,37061,Bologna,BO,Emilia-Romagna,8,40053 +Alto Reno Terme,37062,Bologna,BO,Emilia-Romagna,8,40046 +Argenta,38001,Ferrara,FE,Emilia-Romagna,8,44011 +Bondeno,38003,Ferrara,FE,Emilia-Romagna,8,44012 +Cento,38004,Ferrara,FE,Emilia-Romagna,8,44042 +Codigoro,38005,Ferrara,FE,Emilia-Romagna,8,44021 +Comacchio,38006,Ferrara,FE,Emilia-Romagna,8,44022 +Copparo,38007,Ferrara,FE,Emilia-Romagna,8,44034 +Ferrara,38008,Ferrara,FE,Emilia-Romagna,8,44121 +Jolanda di Savoia,38010,Ferrara,FE,Emilia-Romagna,8,44037 +Lagosanto,38011,Ferrara,FE,Emilia-Romagna,8,44023 +Masi Torello,38012,Ferrara,FE,Emilia-Romagna,8,44020 +Mesola,38014,Ferrara,FE,Emilia-Romagna,8,44026 +Ostellato,38017,Ferrara,FE,Emilia-Romagna,8,44020 +Poggio Renatico,38018,Ferrara,FE,Emilia-Romagna,8,44028 +Portomaggiore,38019,Ferrara,FE,Emilia-Romagna,8,44015 +Vigarano Mainarda,38022,Ferrara,FE,Emilia-Romagna,8,44049 +Voghiera,38023,Ferrara,FE,Emilia-Romagna,8,44019 +Goro,38025,Ferrara,FE,Emilia-Romagna,8,44020 +Fiscaglia,38027,Ferrara,FE,Emilia-Romagna,8,44027 +Terre del Reno,38028,Ferrara,FE,Emilia-Romagna,8,44047 +Riva del Po,38029,Ferrara,FE,Emilia-Romagna,8,44033 +Tresignana,38030,Ferrara,FE,Emilia-Romagna,8,44039 +Alfonsine,39001,Ravenna,RA,Emilia-Romagna,8,48011 +Bagnacavallo,39002,Ravenna,RA,Emilia-Romagna,8,48012 +Bagnara di Romagna,39003,Ravenna,RA,Emilia-Romagna,8,48010 +Brisighella,39004,Ravenna,RA,Emilia-Romagna,8,48013 +Casola Valsenio,39005,Ravenna,RA,Emilia-Romagna,8,48010 +Castel Bolognese,39006,Ravenna,RA,Emilia-Romagna,8,48014 +Cervia,39007,Ravenna,RA,Emilia-Romagna,8,48015 +Conselice,39008,Ravenna,RA,Emilia-Romagna,8,48017 +Cotignola,39009,Ravenna,RA,Emilia-Romagna,8,48010 +Faenza,39010,Ravenna,RA,Emilia-Romagna,8,48018 +Fusignano,39011,Ravenna,RA,Emilia-Romagna,8,48010 +Lugo,39012,Ravenna,RA,Emilia-Romagna,8,48022 +Massa Lombarda,39013,Ravenna,RA,Emilia-Romagna,8,48024 +Ravenna,39014,Ravenna,RA,Emilia-Romagna,8,48121 +Riolo Terme,39015,Ravenna,RA,Emilia-Romagna,8,48025 +Russi,39016,Ravenna,RA,Emilia-Romagna,8,48026 +Sant'Agata sul Santerno,39017,Ravenna,RA,Emilia-Romagna,8,48020 +Solarolo,39018,Ravenna,RA,Emilia-Romagna,8,48027 +Bagno di Romagna,40001,Forlì-Cesena,FC,Emilia-Romagna,8,47021 +Bertinoro,40003,Forlì-Cesena,FC,Emilia-Romagna,8,47032 +Borghi,40004,Forlì-Cesena,FC,Emilia-Romagna,8,47030 +Castrocaro Terme e Terra del Sole,40005,Forlì-Cesena,FC,Emilia-Romagna,8,47011 +Cesena,40007,Forlì-Cesena,FC,Emilia-Romagna,8,47520 +Cesenatico,40008,Forlì-Cesena,FC,Emilia-Romagna,8,47042 +Civitella di Romagna,40009,Forlì-Cesena,FC,Emilia-Romagna,8,47012 +Dovadola,40011,Forlì-Cesena,FC,Emilia-Romagna,8,47013 +Forlì,40012,Forlì-Cesena,FC,Emilia-Romagna,8,47121 +Forlimpopoli,40013,Forlì-Cesena,FC,Emilia-Romagna,8,47034 +Galeata,40014,Forlì-Cesena,FC,Emilia-Romagna,8,47010 +Gambettola,40015,Forlì-Cesena,FC,Emilia-Romagna,8,47035 +Gatteo,40016,Forlì-Cesena,FC,Emilia-Romagna,8,47043 +Longiano,40018,Forlì-Cesena,FC,Emilia-Romagna,8,47020 +Meldola,40019,Forlì-Cesena,FC,Emilia-Romagna,8,47014 +Mercato Saraceno,40020,Forlì-Cesena,FC,Emilia-Romagna,8,47025 +Modigliana,40022,Forlì-Cesena,FC,Emilia-Romagna,8,47015 +Montiano,40028,Forlì-Cesena,FC,Emilia-Romagna,8,47020 +Portico e San Benedetto,40031,Forlì-Cesena,FC,Emilia-Romagna,8,47010 +Predappio,40032,Forlì-Cesena,FC,Emilia-Romagna,8,47016 +Premilcuore,40033,Forlì-Cesena,FC,Emilia-Romagna,8,47010 +Rocca San Casciano,40036,Forlì-Cesena,FC,Emilia-Romagna,8,47017 +Roncofreddo,40037,Forlì-Cesena,FC,Emilia-Romagna,8,47020 +San Mauro Pascoli,40041,Forlì-Cesena,FC,Emilia-Romagna,8,47030 +Santa Sofia,40043,Forlì-Cesena,FC,Emilia-Romagna,8,47018 +Sarsina,40044,Forlì-Cesena,FC,Emilia-Romagna,8,47027 +Savignano sul Rubicone,40045,Forlì-Cesena,FC,Emilia-Romagna,8,47039 +Sogliano al Rubicone,40046,Forlì-Cesena,FC,Emilia-Romagna,8,47030 +Tredozio,40049,Forlì-Cesena,FC,Emilia-Romagna,8,47019 +Verghereto,40050,Forlì-Cesena,FC,Emilia-Romagna,8,47028 +Bellaria-Igea Marina,99001,Rimini,RN,Emilia-Romagna,8,47814 +Cattolica,99002,Rimini,RN,Emilia-Romagna,8,47841 +Coriano,99003,Rimini,RN,Emilia-Romagna,8,47853 +Gemmano,99004,Rimini,RN,Emilia-Romagna,8,47855 +Misano Adriatico,99005,Rimini,RN,Emilia-Romagna,8,47843 +Mondaino,99006,Rimini,RN,Emilia-Romagna,8,47836 +Montefiore Conca,99008,Rimini,RN,Emilia-Romagna,8,47834 +Montegridolfo,99009,Rimini,RN,Emilia-Romagna,8,47837 +Morciano di Romagna,99011,Rimini,RN,Emilia-Romagna,8,47833 +Riccione,99013,Rimini,RN,Emilia-Romagna,8,47838 +Rimini,99014,Rimini,RN,Emilia-Romagna,8,47921 +Saludecio,99015,Rimini,RN,Emilia-Romagna,8,47835 +San Clemente,99016,Rimini,RN,Emilia-Romagna,8,47832 +San Giovanni in Marignano,99017,Rimini,RN,Emilia-Romagna,8,47842 +Santarcangelo di Romagna,99018,Rimini,RN,Emilia-Romagna,8,47822 +Verucchio,99020,Rimini,RN,Emilia-Romagna,8,47826 +Casteldelci,99021,Rimini,RN,Emilia-Romagna,8,47861 +Maiolo,99022,Rimini,RN,Emilia-Romagna,8,47862 +Novafeltria,99023,Rimini,RN,Emilia-Romagna,8,47863 +Pennabilli,99024,Rimini,RN,Emilia-Romagna,8,47864 +San Leo,99025,Rimini,RN,Emilia-Romagna,8,47865 +Sant'Agata Feltria,99026,Rimini,RN,Emilia-Romagna,8,47866 +Talamello,99027,Rimini,RN,Emilia-Romagna,8,47867 +Poggio Torriana,99028,Rimini,RN,Emilia-Romagna,8,47824 +Montescudo-Monte Colombo,99029,Rimini,RN,Emilia-Romagna,8,47854 +Aulla,45001,Massa-Carrara,MS,Toscana,9,54011 +Bagnone,45002,Massa-Carrara,MS,Toscana,9,54021 +Carrara,45003,Massa-Carrara,MS,Toscana,9,54033 +Casola in Lunigiana,45004,Massa-Carrara,MS,Toscana,9,54014 +Comano,45005,Massa-Carrara,MS,Toscana,9,54015 +Filattiera,45006,Massa-Carrara,MS,Toscana,9,54023 +Fivizzano,45007,Massa-Carrara,MS,Toscana,9,54013 +Fosdinovo,45008,Massa-Carrara,MS,Toscana,9,54035 +Licciana Nardi,45009,Massa-Carrara,MS,Toscana,9,54016 +Massa,45010,Massa-Carrara,MS,Toscana,9,54100 +Montignoso,45011,Massa-Carrara,MS,Toscana,9,54038 +Mulazzo,45012,Massa-Carrara,MS,Toscana,9,54026 +Podenzana,45013,Massa-Carrara,MS,Toscana,9,54010 +Pontremoli,45014,Massa-Carrara,MS,Toscana,9,54027 +Tresana,45015,Massa-Carrara,MS,Toscana,9,54012 +Villafranca in Lunigiana,45016,Massa-Carrara,MS,Toscana,9,54028 +Zeri,45017,Massa-Carrara,MS,Toscana,9,54029 +Altopascio,46001,Lucca,LU,Toscana,9,55011 +Bagni di Lucca,46002,Lucca,LU,Toscana,9,55022 +Barga,46003,Lucca,LU,Toscana,9,55051 +Borgo a Mozzano,46004,Lucca,LU,Toscana,9,55023 +Camaiore,46005,Lucca,LU,Toscana,9,55041 +Camporgiano,46006,Lucca,LU,Toscana,9,55031 +Capannori,46007,Lucca,LU,Toscana,9,55012 +Careggine,46008,Lucca,LU,Toscana,9,55030 +Castelnuovo di Garfagnana,46009,Lucca,LU,Toscana,9,55032 +Castiglione di Garfagnana,46010,Lucca,LU,Toscana,9,55033 +Coreglia Antelminelli,46011,Lucca,LU,Toscana,9,55025 +Forte dei Marmi,46013,Lucca,LU,Toscana,9,55042 +Fosciandora,46014,Lucca,LU,Toscana,9,55020 +Gallicano,46015,Lucca,LU,Toscana,9,55027 +Lucca,46017,Lucca,LU,Toscana,9,55100 +Massarosa,46018,Lucca,LU,Toscana,9,55054 +Minucciano,46019,Lucca,LU,Toscana,9,55034 +Molazzana,46020,Lucca,LU,Toscana,9,55020 +Montecarlo,46021,Lucca,LU,Toscana,9,55015 +Pescaglia,46022,Lucca,LU,Toscana,9,55064 +Piazza al Serchio,46023,Lucca,LU,Toscana,9,55035 +Pietrasanta,46024,Lucca,LU,Toscana,9,55045 +Pieve Fosciana,46025,Lucca,LU,Toscana,9,55036 +Porcari,46026,Lucca,LU,Toscana,9,55016 +San Romano in Garfagnana,46027,Lucca,LU,Toscana,9,55038 +Seravezza,46028,Lucca,LU,Toscana,9,55047 +Stazzema,46030,Lucca,LU,Toscana,9,55040 +Vagli Sotto,46031,Lucca,LU,Toscana,9,55030 +Viareggio,46033,Lucca,LU,Toscana,9,55049 +Villa Basilica,46034,Lucca,LU,Toscana,9,55019 +Villa Collemandina,46035,Lucca,LU,Toscana,9,55030 +Fabbriche di Vergemoli,46036,Lucca,LU,Toscana,9,55021 +Sillano Giuncugnano,46037,Lucca,LU,Toscana,9,55030 +Agliana,47002,Pistoia,PT,Toscana,9,51031 +Buggiano,47003,Pistoia,PT,Toscana,9,51011 +Lamporecchio,47005,Pistoia,PT,Toscana,9,51035 +Larciano,47006,Pistoia,PT,Toscana,9,51036 +Marliana,47007,Pistoia,PT,Toscana,9,51010 +Massa e Cozzile,47008,Pistoia,PT,Toscana,9,51010 +Monsummano Terme,47009,Pistoia,PT,Toscana,9,51015 +Montale,47010,Pistoia,PT,Toscana,9,51037 +Montecatini-Terme,47011,Pistoia,PT,Toscana,9,51016 +Pescia,47012,Pistoia,PT,Toscana,9,51017 +Pieve a Nievole,47013,Pistoia,PT,Toscana,9,51018 +Pistoia,47014,Pistoia,PT,Toscana,9,51100 +Ponte Buggianese,47016,Pistoia,PT,Toscana,9,51019 +Quarrata,47017,Pistoia,PT,Toscana,9,51039 +Sambuca Pistoiese,47018,Pistoia,PT,Toscana,9,51020 +Serravalle Pistoiese,47020,Pistoia,PT,Toscana,9,51030 +Uzzano,47021,Pistoia,PT,Toscana,9,51010 +Chiesina Uzzanese,47022,Pistoia,PT,Toscana,9,51013 +Abetone Cutigliano,47023,Pistoia,PT,Toscana,9,51024 +San Marcello Piteglio,47024,Pistoia,PT,Toscana,9,51028 +Bagno a Ripoli,48001,Firenze,FI,Toscana,9,50012 +Barberino di Mugello,48002,Firenze,FI,Toscana,9,50031 +Borgo San Lorenzo,48004,Firenze,FI,Toscana,9,50032 +Calenzano,48005,Firenze,FI,Toscana,9,50041 +Campi Bisenzio,48006,Firenze,FI,Toscana,9,50013 +Capraia e Limite,48008,Firenze,FI,Toscana,9,50050 +Castelfiorentino,48010,Firenze,FI,Toscana,9,50051 +Cerreto Guidi,48011,Firenze,FI,Toscana,9,50050 +Certaldo,48012,Firenze,FI,Toscana,9,50052 +Dicomano,48013,Firenze,FI,Toscana,9,50062 +Empoli,48014,Firenze,FI,Toscana,9,50053 +Fiesole,48015,Firenze,FI,Toscana,9,50014 +Firenze,48017,Firenze,FI,Toscana,9,50122 +Firenzuola,48018,Firenze,FI,Toscana,9,50033 +Fucecchio,48019,Firenze,FI,Toscana,9,50054 +Gambassi Terme,48020,Firenze,FI,Toscana,9,50050 +Greve in Chianti,48021,Firenze,FI,Toscana,9,50022 +Impruneta,48022,Firenze,FI,Toscana,9,50023 +Lastra a Signa,48024,Firenze,FI,Toscana,9,50055 +Londa,48025,Firenze,FI,Toscana,9,50060 +Marradi,48026,Firenze,FI,Toscana,9,50034 +Montaione,48027,Firenze,FI,Toscana,9,50050 +Montelupo Fiorentino,48028,Firenze,FI,Toscana,9,50056 +Montespertoli,48030,Firenze,FI,Toscana,9,50025 +Palazzuolo sul Senio,48031,Firenze,FI,Toscana,9,50035 +Pelago,48032,Firenze,FI,Toscana,9,50060 +Pontassieve,48033,Firenze,FI,Toscana,9,50065 +Reggello,48035,Firenze,FI,Toscana,9,50066 +Rignano sull'Arno,48036,Firenze,FI,Toscana,9,50067 +Rufina,48037,Firenze,FI,Toscana,9,50068 +San Casciano in Val di Pesa,48038,Firenze,FI,Toscana,9,50026 +San Godenzo,48039,Firenze,FI,Toscana,9,50060 +Scandicci,48041,Firenze,FI,Toscana,9,50018 +Sesto Fiorentino,48043,Firenze,FI,Toscana,9,50019 +Signa,48044,Firenze,FI,Toscana,9,50058 +Vaglia,48046,Firenze,FI,Toscana,9,50036 +Vicchio,48049,Firenze,FI,Toscana,9,50039 +Vinci,48050,Firenze,FI,Toscana,9,50059 +Figline e Incisa Valdarno,48052,Firenze,FI,Toscana,9,50063 +Scarperia e San Piero,48053,Firenze,FI,Toscana,9,50038 +Barberino Tavarnelle,48054,Firenze,FI,Toscana,9,50028 +Bibbona,49001,Livorno,LI,Toscana,9,57020 +Campiglia Marittima,49002,Livorno,LI,Toscana,9,57021 +Campo nell'Elba,49003,Livorno,LI,Toscana,9,57034 +Capoliveri,49004,Livorno,LI,Toscana,9,57031 +Capraia Isola,49005,Livorno,LI,Toscana,9,57032 +Castagneto Carducci,49006,Livorno,LI,Toscana,9,57022 +Cecina,49007,Livorno,LI,Toscana,9,57023 +Collesalvetti,49008,Livorno,LI,Toscana,9,57014 +Livorno,49009,Livorno,LI,Toscana,9,57123 +Marciana,49010,Livorno,LI,Toscana,9,57030 +Marciana Marina,49011,Livorno,LI,Toscana,9,57033 +Piombino,49012,Livorno,LI,Toscana,9,57025 +Porto Azzurro,49013,Livorno,LI,Toscana,9,57036 +Portoferraio,49014,Livorno,LI,Toscana,9,57037 +Rosignano Marittimo,49017,Livorno,LI,Toscana,9,57016 +San Vincenzo,49018,Livorno,LI,Toscana,9,57027 +Sassetta,49019,Livorno,LI,Toscana,9,57020 +Suvereto,49020,Livorno,LI,Toscana,9,57028 +Rio,49021,Livorno,LI,Toscana,9,57038 +Bientina,50001,Pisa,PI,Toscana,9,56031 +Buti,50002,Pisa,PI,Toscana,9,56032 +Calci,50003,Pisa,PI,Toscana,9,56011 +Calcinaia,50004,Pisa,PI,Toscana,9,56012 +Capannoli,50005,Pisa,PI,Toscana,9,56033 +Casale Marittimo,50006,Pisa,PI,Toscana,9,56040 +Cascina,50008,Pisa,PI,Toscana,9,56021 +Castelfranco di Sotto,50009,Pisa,PI,Toscana,9,56022 +Castellina Marittima,50010,Pisa,PI,Toscana,9,56040 +Castelnuovo di Val di Cecina,50011,Pisa,PI,Toscana,9,56041 +Chianni,50012,Pisa,PI,Toscana,9,56034 +Fauglia,50014,Pisa,PI,Toscana,9,56043 +Guardistallo,50015,Pisa,PI,Toscana,9,56040 +Lajatico,50016,Pisa,PI,Toscana,9,56030 +Montecatini Val di Cecina,50019,Pisa,PI,Toscana,9,56040 +Montescudaio,50020,Pisa,PI,Toscana,9,56040 +Monteverdi Marittimo,50021,Pisa,PI,Toscana,9,56040 +Montopoli in Val d'Arno,50022,Pisa,PI,Toscana,9,56020 +Orciano Pisano,50023,Pisa,PI,Toscana,9,56040 +Palaia,50024,Pisa,PI,Toscana,9,56036 +Peccioli,50025,Pisa,PI,Toscana,9,56037 +Pisa,50026,Pisa,PI,Toscana,9,56120 +Pomarance,50027,Pisa,PI,Toscana,9,56045 +Ponsacco,50028,Pisa,PI,Toscana,9,56038 +Pontedera,50029,Pisa,PI,Toscana,9,56025 +Riparbella,50030,Pisa,PI,Toscana,9,56046 +San Giuliano Terme,50031,Pisa,PI,Toscana,9,56017 +San Miniato,50032,Pisa,PI,Toscana,9,56028 +Santa Croce sull'Arno,50033,Pisa,PI,Toscana,9,56029 +Santa Luce,50034,Pisa,PI,Toscana,9,56040 +Santa Maria a Monte,50035,Pisa,PI,Toscana,9,56020 +Terricciola,50036,Pisa,PI,Toscana,9,56030 +Vecchiano,50037,Pisa,PI,Toscana,9,56019 +Vicopisano,50038,Pisa,PI,Toscana,9,56010 +Volterra,50039,Pisa,PI,Toscana,9,56048 +Casciana Terme Lari,50040,Pisa,PI,Toscana,9,56035 +Crespina Lorenzana,50041,Pisa,PI,Toscana,9,56042 +Anghiari,51001,Arezzo,AR,Toscana,9,52031 +Arezzo,51002,Arezzo,AR,Toscana,9,52100 +Badia Tedalda,51003,Arezzo,AR,Toscana,9,52032 +Bibbiena,51004,Arezzo,AR,Toscana,9,52011 +Bucine,51005,Arezzo,AR,Toscana,9,52021 +Capolona,51006,Arezzo,AR,Toscana,9,52010 +Caprese Michelangelo,51007,Arezzo,AR,Toscana,9,52033 +Castel Focognano,51008,Arezzo,AR,Toscana,9,52016 +Castel San Niccolò,51010,Arezzo,AR,Toscana,9,52018 +Castiglion Fibocchi,51011,Arezzo,AR,Toscana,9,52029 +Castiglion Fiorentino,51012,Arezzo,AR,Toscana,9,52043 +Cavriglia,51013,Arezzo,AR,Toscana,9,52022 +Chitignano,51014,Arezzo,AR,Toscana,9,52010 +Chiusi della Verna,51015,Arezzo,AR,Toscana,9,52010 +Civitella in Val di Chiana,51016,Arezzo,AR,Toscana,9,52041 +Cortona,51017,Arezzo,AR,Toscana,9,52044 +Foiano della Chiana,51018,Arezzo,AR,Toscana,9,52045 +Loro Ciuffenna,51020,Arezzo,AR,Toscana,9,52024 +Lucignano,51021,Arezzo,AR,Toscana,9,52046 +Marciano della Chiana,51022,Arezzo,AR,Toscana,9,52047 +Montemignaio,51023,Arezzo,AR,Toscana,9,52010 +Monterchi,51024,Arezzo,AR,Toscana,9,52035 +Monte San Savino,51025,Arezzo,AR,Toscana,9,52048 +Montevarchi,51026,Arezzo,AR,Toscana,9,52025 +Ortignano Raggiolo,51027,Arezzo,AR,Toscana,9,52010 +Pieve Santo Stefano,51030,Arezzo,AR,Toscana,9,52036 +Poppi,51031,Arezzo,AR,Toscana,9,52014 +San Giovanni Valdarno,51033,Arezzo,AR,Toscana,9,52027 +Sansepolcro,51034,Arezzo,AR,Toscana,9,52037 +Sestino,51035,Arezzo,AR,Toscana,9,52038 +Subbiano,51037,Arezzo,AR,Toscana,9,52010 +Talla,51038,Arezzo,AR,Toscana,9,52010 +Terranuova Bracciolini,51039,Arezzo,AR,Toscana,9,52028 +Castelfranco Piandiscò,51040,Arezzo,AR,Toscana,9,52026 +Pratovecchio Stia,51041,Arezzo,AR,Toscana,9,52015 +Laterina Pergine Valdarno,51042,Arezzo,AR,Toscana,9,52020 +Abbadia San Salvatore,52001,Siena,SI,Toscana,9,53021 +Asciano,52002,Siena,SI,Toscana,9,53041 +Buonconvento,52003,Siena,SI,Toscana,9,53022 +Casole d'Elsa,52004,Siena,SI,Toscana,9,53031 +Castellina in Chianti,52005,Siena,SI,Toscana,9,53011 +Castelnuovo Berardenga,52006,Siena,SI,Toscana,9,53019 +Castiglione d'Orcia,52007,Siena,SI,Toscana,9,53023 +Cetona,52008,Siena,SI,Toscana,9,53040 +Chianciano Terme,52009,Siena,SI,Toscana,9,53042 +Chiusdino,52010,Siena,SI,Toscana,9,53012 +Chiusi,52011,Siena,SI,Toscana,9,53043 +Colle di Val d'Elsa,52012,Siena,SI,Toscana,9,53034 +Gaiole in Chianti,52013,Siena,SI,Toscana,9,53013 +Montepulciano,52015,Siena,SI,Toscana,9,53045 +Monteriggioni,52016,Siena,SI,Toscana,9,53035 +Monteroni d'Arbia,52017,Siena,SI,Toscana,9,53014 +Monticiano,52018,Siena,SI,Toscana,9,53015 +Murlo,52019,Siena,SI,Toscana,9,53016 +Piancastagnaio,52020,Siena,SI,Toscana,9,53025 +Pienza,52021,Siena,SI,Toscana,9,53026 +Poggibonsi,52022,Siena,SI,Toscana,9,53036 +Radda in Chianti,52023,Siena,SI,Toscana,9,53017 +Radicofani,52024,Siena,SI,Toscana,9,53040 +Radicondoli,52025,Siena,SI,Toscana,9,53030 +Rapolano Terme,52026,Siena,SI,Toscana,9,53040 +San Casciano dei Bagni,52027,Siena,SI,Toscana,9,53040 +San Gimignano,52028,Siena,SI,Toscana,9,53037 +San Quirico d'Orcia,52030,Siena,SI,Toscana,9,53027 +Sarteano,52031,Siena,SI,Toscana,9,53047 +Siena,52032,Siena,SI,Toscana,9,53100 +Sinalunga,52033,Siena,SI,Toscana,9,53048 +Sovicille,52034,Siena,SI,Toscana,9,53018 +Torrita di Siena,52035,Siena,SI,Toscana,9,53049 +Trequanda,52036,Siena,SI,Toscana,9,53020 +Montalcino,52037,Siena,SI,Toscana,9,53024 +Arcidosso,53001,Grosseto,GR,Toscana,9,58031 +Campagnatico,53002,Grosseto,GR,Toscana,9,58042 +Capalbio,53003,Grosseto,GR,Toscana,9,58011 +Castel del Piano,53004,Grosseto,GR,Toscana,9,58033 +Castell'Azzara,53005,Grosseto,GR,Toscana,9,58034 +Castiglione della Pescaia,53006,Grosseto,GR,Toscana,9,58043 +Cinigiano,53007,Grosseto,GR,Toscana,9,58044 +Civitella Paganico,53008,Grosseto,GR,Toscana,9,58045 +Follonica,53009,Grosseto,GR,Toscana,9,58022 +Gavorrano,53010,Grosseto,GR,Toscana,9,58023 +Grosseto,53011,Grosseto,GR,Toscana,9,58100 +Isola del Giglio,53012,Grosseto,GR,Toscana,9,58012 +Magliano in Toscana,53013,Grosseto,GR,Toscana,9,58051 +Manciano,53014,Grosseto,GR,Toscana,9,58014 +Massa Marittima,53015,Grosseto,GR,Toscana,9,58024 +Monte Argentario,53016,Grosseto,GR,Toscana,9,58019 +Montieri,53017,Grosseto,GR,Toscana,9,58026 +Orbetello,53018,Grosseto,GR,Toscana,9,58015 +Pitigliano,53019,Grosseto,GR,Toscana,9,58017 +Roccalbegna,53020,Grosseto,GR,Toscana,9,58053 +Roccastrada,53021,Grosseto,GR,Toscana,9,58036 +Santa Fiora,53022,Grosseto,GR,Toscana,9,58037 +Scansano,53023,Grosseto,GR,Toscana,9,58054 +Scarlino,53024,Grosseto,GR,Toscana,9,58020 +Seggiano,53025,Grosseto,GR,Toscana,9,58038 +Sorano,53026,Grosseto,GR,Toscana,9,58010 +Monterotondo Marittimo,53027,Grosseto,GR,Toscana,9,58025 +Semproniano,53028,Grosseto,GR,Toscana,9,58055 +Cantagallo,100001,Prato,PO,Toscana,9,59025 +Carmignano,100002,Prato,PO,Toscana,9,59015 +Montemurlo,100003,Prato,PO,Toscana,9,59013 +Poggio a Caiano,100004,Prato,PO,Toscana,9,59016 +Prato,100005,Prato,PO,Toscana,9,59100 +Vaiano,100006,Prato,PO,Toscana,9,59021 +Vernio,100007,Prato,PO,Toscana,9,59024 +Assisi,54001,Perugia,PG,Umbria,10,6081 +Bastia Umbra,54002,Perugia,PG,Umbria,10,6083 +Bettona,54003,Perugia,PG,Umbria,10,6084 +Bevagna,54004,Perugia,PG,Umbria,10,6031 +Campello sul Clitunno,54005,Perugia,PG,Umbria,10,6042 +Cannara,54006,Perugia,PG,Umbria,10,6033 +Cascia,54007,Perugia,PG,Umbria,10,6043 +Castel Ritaldi,54008,Perugia,PG,Umbria,10,6044 +Castiglione del Lago,54009,Perugia,PG,Umbria,10,6061 +Cerreto di Spoleto,54010,Perugia,PG,Umbria,10,6041 +Citerna,54011,Perugia,PG,Umbria,10,6010 +Città della Pieve,54012,Perugia,PG,Umbria,10,6062 +Città di Castello,54013,Perugia,PG,Umbria,10,6012 +Collazzone,54014,Perugia,PG,Umbria,10,6050 +Corciano,54015,Perugia,PG,Umbria,10,6073 +Costacciaro,54016,Perugia,PG,Umbria,10,6021 +Deruta,54017,Perugia,PG,Umbria,10,6053 +Foligno,54018,Perugia,PG,Umbria,10,6034 +Fossato di Vico,54019,Perugia,PG,Umbria,10,6022 +Fratta Todina,54020,Perugia,PG,Umbria,10,6054 +Giano dell'Umbria,54021,Perugia,PG,Umbria,10,6030 +Gualdo Cattaneo,54022,Perugia,PG,Umbria,10,6035 +Gualdo Tadino,54023,Perugia,PG,Umbria,10,6023 +Gubbio,54024,Perugia,PG,Umbria,10,6024 +Lisciano Niccone,54025,Perugia,PG,Umbria,10,6060 +Magione,54026,Perugia,PG,Umbria,10,6063 +Marsciano,54027,Perugia,PG,Umbria,10,6055 +Massa Martana,54028,Perugia,PG,Umbria,10,6056 +Monte Castello di Vibio,54029,Perugia,PG,Umbria,10,6057 +Montefalco,54030,Perugia,PG,Umbria,10,6036 +Monteleone di Spoleto,54031,Perugia,PG,Umbria,10,6045 +Monte Santa Maria Tiberina,54032,Perugia,PG,Umbria,10,6010 +Montone,54033,Perugia,PG,Umbria,10,6014 +Nocera Umbra,54034,Perugia,PG,Umbria,10,6025 +Norcia,54035,Perugia,PG,Umbria,10,6046 +Paciano,54036,Perugia,PG,Umbria,10,6060 +Panicale,54037,Perugia,PG,Umbria,10,6064 +Passignano sul Trasimeno,54038,Perugia,PG,Umbria,10,6065 +Perugia,54039,Perugia,PG,Umbria,10,6121 +Piegaro,54040,Perugia,PG,Umbria,10,6066 +Pietralunga,54041,Perugia,PG,Umbria,10,6026 +Poggiodomo,54042,Perugia,PG,Umbria,10,6040 +Preci,54043,Perugia,PG,Umbria,10,6047 +San Giustino,54044,Perugia,PG,Umbria,10,6016 +Sant'Anatolia di Narco,54045,Perugia,PG,Umbria,10,6040 +Scheggia e Pascelupo,54046,Perugia,PG,Umbria,10,6027 +Scheggino,54047,Perugia,PG,Umbria,10,6040 +Sellano,54048,Perugia,PG,Umbria,10,6030 +Sigillo,54049,Perugia,PG,Umbria,10,6028 +Spello,54050,Perugia,PG,Umbria,10,6038 +Spoleto,54051,Perugia,PG,Umbria,10,6049 +Todi,54052,Perugia,PG,Umbria,10,6059 +Torgiano,54053,Perugia,PG,Umbria,10,6089 +Trevi,54054,Perugia,PG,Umbria,10,6039 +Tuoro sul Trasimeno,54055,Perugia,PG,Umbria,10,6069 +Umbertide,54056,Perugia,PG,Umbria,10,6019 +Valfabbrica,54057,Perugia,PG,Umbria,10,6029 +Vallo di Nera,54058,Perugia,PG,Umbria,10,6040 +Valtopina,54059,Perugia,PG,Umbria,10,6030 +Acquasparta,55001,Terni,TR,Umbria,10,5021 +Allerona,55002,Terni,TR,Umbria,10,5011 +Alviano,55003,Terni,TR,Umbria,10,5020 +Amelia,55004,Terni,TR,Umbria,10,5022 +Arrone,55005,Terni,TR,Umbria,10,5031 +Attigliano,55006,Terni,TR,Umbria,10,5012 +Baschi,55007,Terni,TR,Umbria,10,5023 +Calvi dell'Umbria,55008,Terni,TR,Umbria,10,5032 +Castel Giorgio,55009,Terni,TR,Umbria,10,5013 +Castel Viscardo,55010,Terni,TR,Umbria,10,5014 +Fabro,55011,Terni,TR,Umbria,10,5015 +Ferentillo,55012,Terni,TR,Umbria,10,5034 +Ficulle,55013,Terni,TR,Umbria,10,5016 +Giove,55014,Terni,TR,Umbria,10,5024 +Guardea,55015,Terni,TR,Umbria,10,5025 +Lugnano in Teverina,55016,Terni,TR,Umbria,10,5020 +Montecastrilli,55017,Terni,TR,Umbria,10,5026 +Montecchio,55018,Terni,TR,Umbria,10,5020 +Montefranco,55019,Terni,TR,Umbria,10,5030 +Montegabbione,55020,Terni,TR,Umbria,10,5010 +Monteleone d'Orvieto,55021,Terni,TR,Umbria,10,5017 +Narni,55022,Terni,TR,Umbria,10,5035 +Orvieto,55023,Terni,TR,Umbria,10,5018 +Otricoli,55024,Terni,TR,Umbria,10,5030 +Parrano,55025,Terni,TR,Umbria,10,5010 +Penna in Teverina,55026,Terni,TR,Umbria,10,5028 +Polino,55027,Terni,TR,Umbria,10,5030 +Porano,55028,Terni,TR,Umbria,10,5010 +San Gemini,55029,Terni,TR,Umbria,10,5029 +San Venanzo,55030,Terni,TR,Umbria,10,5010 +Stroncone,55031,Terni,TR,Umbria,10,5039 +Terni,55032,Terni,TR,Umbria,10,5100 +Avigliano Umbro,55033,Terni,TR,Umbria,10,5020 +Acqualagna,41001,Pesaro e Urbino,PU,Marche,11,61041 +Apecchio,41002,Pesaro e Urbino,PU,Marche,11,61042 +Belforte all'Isauro,41005,Pesaro e Urbino,PU,Marche,11,61026 +Borgo Pace,41006,Pesaro e Urbino,PU,Marche,11,61040 +Cagli,41007,Pesaro e Urbino,PU,Marche,11,61043 +Cantiano,41008,Pesaro e Urbino,PU,Marche,11,61044 +Carpegna,41009,Pesaro e Urbino,PU,Marche,11,61021 +Cartoceto,41010,Pesaro e Urbino,PU,Marche,11,61030 +Fano,41013,Pesaro e Urbino,PU,Marche,11,61032 +Fermignano,41014,Pesaro e Urbino,PU,Marche,11,61033 +Fossombrone,41015,Pesaro e Urbino,PU,Marche,11,61034 +Fratte Rosa,41016,Pesaro e Urbino,PU,Marche,11,61040 +Frontino,41017,Pesaro e Urbino,PU,Marche,11,61021 +Frontone,41018,Pesaro e Urbino,PU,Marche,11,61040 +Gabicce Mare,41019,Pesaro e Urbino,PU,Marche,11,61011 +Gradara,41020,Pesaro e Urbino,PU,Marche,11,61012 +Isola del Piano,41021,Pesaro e Urbino,PU,Marche,11,61030 +Lunano,41022,Pesaro e Urbino,PU,Marche,11,61026 +Macerata Feltria,41023,Pesaro e Urbino,PU,Marche,11,61023 +Mercatello sul Metauro,41025,Pesaro e Urbino,PU,Marche,11,61040 +Mercatino Conca,41026,Pesaro e Urbino,PU,Marche,11,61013 +Mombaroccio,41027,Pesaro e Urbino,PU,Marche,11,61024 +Mondavio,41028,Pesaro e Urbino,PU,Marche,11,61040 +Mondolfo,41029,Pesaro e Urbino,PU,Marche,11,61037 +Montecalvo in Foglia,41030,Pesaro e Urbino,PU,Marche,11,61020 +Monte Cerignone,41031,Pesaro e Urbino,PU,Marche,11,61010 +Montecopiolo,99030,Rimini,RN,Emilia-Romagna,8,47868 +Montefelcino,41034,Pesaro e Urbino,PU,Marche,11,61030 +Monte Grimano Terme,41035,Pesaro e Urbino,PU,Marche,11,61010 +Montelabbate,41036,Pesaro e Urbino,PU,Marche,11,61025 +Monte Porzio,41038,Pesaro e Urbino,PU,Marche,11,61040 +Peglio,41041,Pesaro e Urbino,PU,Marche,11,61049 +Pergola,41043,Pesaro e Urbino,PU,Marche,11,61045 +Pesaro,41044,Pesaro e Urbino,PU,Marche,11,61024 +Petriano,41045,Pesaro e Urbino,PU,Marche,11,61020 +Piandimeleto,41047,Pesaro e Urbino,PU,Marche,11,61026 +Pietrarubbia,41048,Pesaro e Urbino,PU,Marche,11,61023 +Piobbico,41049,Pesaro e Urbino,PU,Marche,11,61046 +San Costanzo,41051,Pesaro e Urbino,PU,Marche,11,61039 +San Lorenzo in Campo,41054,Pesaro e Urbino,PU,Marche,11,61047 +Sant'Angelo in Vado,41057,Pesaro e Urbino,PU,Marche,11,61048 +Sant'Ippolito,41058,Pesaro e Urbino,PU,Marche,11,61040 +Sassofeltrio,99031,Rimini,RN,Emilia-Romagna,8,47869 +Serra Sant'Abbondio,41061,Pesaro e Urbino,PU,Marche,11,61040 +Tavoleto,41064,Pesaro e Urbino,PU,Marche,11,61020 +Tavullia,41065,Pesaro e Urbino,PU,Marche,11,61010 +Urbania,41066,Pesaro e Urbino,PU,Marche,11,61049 +Urbino,41067,Pesaro e Urbino,PU,Marche,11,61029 +Vallefoglia,41068,Pesaro e Urbino,PU,Marche,11,61022 +Colli al Metauro,41069,Pesaro e Urbino,PU,Marche,11,61030 +Terre Roveresche,41070,Pesaro e Urbino,PU,Marche,11,61038 +Sassocorvaro Auditore,41071,Pesaro e Urbino,PU,Marche,11,61028 +Agugliano,42001,Ancona,AN,Marche,11,60020 +Ancona,42002,Ancona,AN,Marche,11,60100 +Arcevia,42003,Ancona,AN,Marche,11,60011 +Barbara,42004,Ancona,AN,Marche,11,60010 +Belvedere Ostrense,42005,Ancona,AN,Marche,11,60030 +Camerano,42006,Ancona,AN,Marche,11,60021 +Camerata Picena,42007,Ancona,AN,Marche,11,60020 +Castelbellino,42008,Ancona,AN,Marche,11,60030 +Castelfidardo,42010,Ancona,AN,Marche,11,60022 +Castelleone di Suasa,42011,Ancona,AN,Marche,11,60010 +Castelplanio,42012,Ancona,AN,Marche,11,60031 +Cerreto d'Esi,42013,Ancona,AN,Marche,11,60043 +Chiaravalle,42014,Ancona,AN,Marche,11,60033 +Corinaldo,42015,Ancona,AN,Marche,11,60013 +Cupramontana,42016,Ancona,AN,Marche,11,60034 +Fabriano,42017,Ancona,AN,Marche,11,60044 +Falconara Marittima,42018,Ancona,AN,Marche,11,60015 +Filottrano,42019,Ancona,AN,Marche,11,60024 +Genga,42020,Ancona,AN,Marche,11,60040 +Jesi,42021,Ancona,AN,Marche,11,60035 +Loreto,42022,Ancona,AN,Marche,11,60025 +Maiolati Spontini,42023,Ancona,AN,Marche,11,60030 +Mergo,42024,Ancona,AN,Marche,11,60030 +Monsano,42025,Ancona,AN,Marche,11,60030 +Montecarotto,42026,Ancona,AN,Marche,11,60036 +Montemarciano,42027,Ancona,AN,Marche,11,60018 +Monte Roberto,42029,Ancona,AN,Marche,11,60030 +Monte San Vito,42030,Ancona,AN,Marche,11,60037 +Morro d'Alba,42031,Ancona,AN,Marche,11,60030 +Numana,42032,Ancona,AN,Marche,11,60026 +Offagna,42033,Ancona,AN,Marche,11,60020 +Osimo,42034,Ancona,AN,Marche,11,60027 +Ostra,42035,Ancona,AN,Marche,11,60010 +Ostra Vetere,42036,Ancona,AN,Marche,11,60010 +Poggio San Marcello,42037,Ancona,AN,Marche,11,60030 +Polverigi,42038,Ancona,AN,Marche,11,60020 +Rosora,42040,Ancona,AN,Marche,11,60030 +San Marcello,42041,Ancona,AN,Marche,11,60030 +San Paolo di Jesi,42042,Ancona,AN,Marche,11,60038 +Santa Maria Nuova,42043,Ancona,AN,Marche,11,60030 +Sassoferrato,42044,Ancona,AN,Marche,11,60041 +Senigallia,42045,Ancona,AN,Marche,11,60019 +Serra de' Conti,42046,Ancona,AN,Marche,11,60030 +Serra San Quirico,42047,Ancona,AN,Marche,11,60048 +Sirolo,42048,Ancona,AN,Marche,11,60020 +Staffolo,42049,Ancona,AN,Marche,11,60039 +Trecastelli,42050,Ancona,AN,Marche,11,60012 +Apiro,43002,Macerata,MC,Marche,11,62021 +Appignano,43003,Macerata,MC,Marche,11,62010 +Belforte del Chienti,43004,Macerata,MC,Marche,11,62020 +Bolognola,43005,Macerata,MC,Marche,11,62035 +Caldarola,43006,Macerata,MC,Marche,11,62020 +Camerino,43007,Macerata,MC,Marche,11,62032 +Camporotondo di Fiastrone,43008,Macerata,MC,Marche,11,62020 +Castelraimondo,43009,Macerata,MC,Marche,11,62022 +Castelsantangelo sul Nera,43010,Macerata,MC,Marche,11,62039 +Cessapalombo,43011,Macerata,MC,Marche,11,62020 +Cingoli,43012,Macerata,MC,Marche,11,62011 +Civitanova Marche,43013,Macerata,MC,Marche,11,62012 +Colmurano,43014,Macerata,MC,Marche,11,62020 +Corridonia,43015,Macerata,MC,Marche,11,62014 +Esanatoglia,43016,Macerata,MC,Marche,11,62024 +Fiastra,43017,Macerata,MC,Marche,11,62035 +Fiuminata,43019,Macerata,MC,Marche,11,62025 +Gagliole,43020,Macerata,MC,Marche,11,62022 +Gualdo,43021,Macerata,MC,Marche,11,62020 +Loro Piceno,43022,Macerata,MC,Marche,11,62020 +Macerata,43023,Macerata,MC,Marche,11,62100 +Matelica,43024,Macerata,MC,Marche,11,62024 +Mogliano,43025,Macerata,MC,Marche,11,62010 +Montecassiano,43026,Macerata,MC,Marche,11,62010 +Monte Cavallo,43027,Macerata,MC,Marche,11,62036 +Montecosaro,43028,Macerata,MC,Marche,11,62010 +Montefano,43029,Macerata,MC,Marche,11,62010 +Montelupone,43030,Macerata,MC,Marche,11,62010 +Monte San Giusto,43031,Macerata,MC,Marche,11,62015 +Monte San Martino,43032,Macerata,MC,Marche,11,62020 +Morrovalle,43033,Macerata,MC,Marche,11,62010 +Muccia,43034,Macerata,MC,Marche,11,62034 +Penna San Giovanni,43035,Macerata,MC,Marche,11,62020 +Petriolo,43036,Macerata,MC,Marche,11,62014 +Pieve Torina,43038,Macerata,MC,Marche,11,62036 +Pioraco,43039,Macerata,MC,Marche,11,62025 +Poggio San Vicino,43040,Macerata,MC,Marche,11,62021 +Pollenza,43041,Macerata,MC,Marche,11,62010 +Porto Recanati,43042,Macerata,MC,Marche,11,62017 +Potenza Picena,43043,Macerata,MC,Marche,11,62018 +Recanati,43044,Macerata,MC,Marche,11,62019 +Ripe San Ginesio,43045,Macerata,MC,Marche,11,62020 +San Ginesio,43046,Macerata,MC,Marche,11,62026 +San Severino Marche,43047,Macerata,MC,Marche,11,62027 +Sant'Angelo in Pontano,43048,Macerata,MC,Marche,11,62020 +Sarnano,43049,Macerata,MC,Marche,11,62028 +Sefro,43050,Macerata,MC,Marche,11,62025 +Serrapetrona,43051,Macerata,MC,Marche,11,62020 +Serravalle di Chienti,43052,Macerata,MC,Marche,11,62038 +Tolentino,43053,Macerata,MC,Marche,11,62029 +Treia,43054,Macerata,MC,Marche,11,62010 +Urbisaglia,43055,Macerata,MC,Marche,11,62010 +Ussita,43056,Macerata,MC,Marche,11,62039 +Visso,43057,Macerata,MC,Marche,11,62039 +Valfornace,43058,Macerata,MC,Marche,11,62035 +Acquasanta Terme,44001,Ascoli Piceno,AP,Marche,11,63095 +Acquaviva Picena,44002,Ascoli Piceno,AP,Marche,11,63075 +Appignano del Tronto,44005,Ascoli Piceno,AP,Marche,11,63083 +Arquata del Tronto,44006,Ascoli Piceno,AP,Marche,11,63096 +Ascoli Piceno,44007,Ascoli Piceno,AP,Marche,11,63100 +Carassai,44010,Ascoli Piceno,AP,Marche,11,63063 +Castel di Lama,44011,Ascoli Piceno,AP,Marche,11,63082 +Castignano,44012,Ascoli Piceno,AP,Marche,11,63072 +Castorano,44013,Ascoli Piceno,AP,Marche,11,63081 +Colli del Tronto,44014,Ascoli Piceno,AP,Marche,11,63079 +Comunanza,44015,Ascoli Piceno,AP,Marche,11,63087 +Cossignano,44016,Ascoli Piceno,AP,Marche,11,63067 +Cupra Marittima,44017,Ascoli Piceno,AP,Marche,11,63064 +Folignano,44020,Ascoli Piceno,AP,Marche,11,63084 +Force,44021,Ascoli Piceno,AP,Marche,11,63086 +Grottammare,44023,Ascoli Piceno,AP,Marche,11,63066 +Maltignano,44027,Ascoli Piceno,AP,Marche,11,63085 +Massignano,44029,Ascoli Piceno,AP,Marche,11,63061 +Monsampolo del Tronto,44031,Ascoli Piceno,AP,Marche,11,63077 +Montalto delle Marche,44032,Ascoli Piceno,AP,Marche,11,63068 +Montedinove,44034,Ascoli Piceno,AP,Marche,11,63069 +Montefiore dell'Aso,44036,Ascoli Piceno,AP,Marche,11,63062 +Montegallo,44038,Ascoli Piceno,AP,Marche,11,63094 +Montemonaco,44044,Ascoli Piceno,AP,Marche,11,63088 +Monteprandone,44045,Ascoli Piceno,AP,Marche,11,63076 +Offida,44054,Ascoli Piceno,AP,Marche,11,63073 +Palmiano,44056,Ascoli Piceno,AP,Marche,11,63092 +Ripatransone,44063,Ascoli Piceno,AP,Marche,11,63065 +Roccafluvione,44064,Ascoli Piceno,AP,Marche,11,63093 +Rotella,44065,Ascoli Piceno,AP,Marche,11,63071 +San Benedetto del Tronto,44066,Ascoli Piceno,AP,Marche,11,63074 +Spinetoli,44071,Ascoli Piceno,AP,Marche,11,63078 +Venarotta,44073,Ascoli Piceno,AP,Marche,11,63091 +Altidona,109001,Fermo,FM,Marche,11,63824 +Amandola,109002,Fermo,FM,Marche,11,63857 +Belmonte Piceno,109003,Fermo,FM,Marche,11,63838 +Campofilone,109004,Fermo,FM,Marche,11,63828 +Falerone,109005,Fermo,FM,Marche,11,63837 +Fermo,109006,Fermo,FM,Marche,11,63900 +Francavilla d'Ete,109007,Fermo,FM,Marche,11,63816 +Grottazzolina,109008,Fermo,FM,Marche,11,63844 +Lapedona,109009,Fermo,FM,Marche,11,63823 +Magliano di Tenna,109010,Fermo,FM,Marche,11,63832 +Massa Fermana,109011,Fermo,FM,Marche,11,63834 +Monsampietro Morico,109012,Fermo,FM,Marche,11,63842 +Montappone,109013,Fermo,FM,Marche,11,63835 +Montefalcone Appennino,109014,Fermo,FM,Marche,11,63855 +Montefortino,109015,Fermo,FM,Marche,11,63858 +Monte Giberto,109016,Fermo,FM,Marche,11,63846 +Montegiorgio,109017,Fermo,FM,Marche,11,63833 +Montegranaro,109018,Fermo,FM,Marche,11,63812 +Monteleone di Fermo,109019,Fermo,FM,Marche,11,63841 +Montelparo,109020,Fermo,FM,Marche,11,63853 +Monte Rinaldo,109021,Fermo,FM,Marche,11,63852 +Monterubbiano,109022,Fermo,FM,Marche,11,63825 +Monte San Pietrangeli,109023,Fermo,FM,Marche,11,63815 +Monte Urano,109024,Fermo,FM,Marche,11,63813 +Monte Vidon Combatte,109025,Fermo,FM,Marche,11,63847 +Monte Vidon Corrado,109026,Fermo,FM,Marche,11,63836 +Montottone,109027,Fermo,FM,Marche,11,63843 +Moresco,109028,Fermo,FM,Marche,11,63826 +Ortezzano,109029,Fermo,FM,Marche,11,63851 +Pedaso,109030,Fermo,FM,Marche,11,63827 +Petritoli,109031,Fermo,FM,Marche,11,63848 +Ponzano di Fermo,109032,Fermo,FM,Marche,11,63845 +Porto San Giorgio,109033,Fermo,FM,Marche,11,63822 +Porto Sant'Elpidio,109034,Fermo,FM,Marche,11,63821 +Rapagnano,109035,Fermo,FM,Marche,11,63831 +Santa Vittoria in Matenano,109036,Fermo,FM,Marche,11,63854 +Sant'Elpidio a Mare,109037,Fermo,FM,Marche,11,63811 +Servigliano,109038,Fermo,FM,Marche,11,63839 +Smerillo,109039,Fermo,FM,Marche,11,63856 +Torre San Patrizio,109040,Fermo,FM,Marche,11,63814 +Acquapendente,56001,Viterbo,VT,Lazio,12,1021 +Arlena di Castro,56002,Viterbo,VT,Lazio,12,1010 +Bagnoregio,56003,Viterbo,VT,Lazio,12,1022 +Barbarano Romano,56004,Viterbo,VT,Lazio,12,1010 +Bassano Romano,56005,Viterbo,VT,Lazio,12,1030 +Bassano in Teverina,56006,Viterbo,VT,Lazio,12,1030 +Blera,56007,Viterbo,VT,Lazio,12,1010 +Bolsena,56008,Viterbo,VT,Lazio,12,1023 +Bomarzo,56009,Viterbo,VT,Lazio,12,1020 +Calcata,56010,Viterbo,VT,Lazio,12,1030 +Canepina,56011,Viterbo,VT,Lazio,12,1030 +Canino,56012,Viterbo,VT,Lazio,12,1011 +Capodimonte,56013,Viterbo,VT,Lazio,12,1010 +Capranica,56014,Viterbo,VT,Lazio,12,1012 +Caprarola,56015,Viterbo,VT,Lazio,12,1032 +Carbognano,56016,Viterbo,VT,Lazio,12,1030 +Castel Sant'Elia,56017,Viterbo,VT,Lazio,12,1030 +Castiglione in Teverina,56018,Viterbo,VT,Lazio,12,1024 +Celleno,56019,Viterbo,VT,Lazio,12,1020 +Cellere,56020,Viterbo,VT,Lazio,12,1010 +Civita Castellana,56021,Viterbo,VT,Lazio,12,1033 +Civitella d'Agliano,56022,Viterbo,VT,Lazio,12,1020 +Corchiano,56023,Viterbo,VT,Lazio,12,1030 +Fabrica di Roma,56024,Viterbo,VT,Lazio,12,1034 +Faleria,56025,Viterbo,VT,Lazio,12,1030 +Farnese,56026,Viterbo,VT,Lazio,12,1010 +Gallese,56027,Viterbo,VT,Lazio,12,1035 +Gradoli,56028,Viterbo,VT,Lazio,12,1010 +Graffignano,56029,Viterbo,VT,Lazio,12,1020 +Grotte di Castro,56030,Viterbo,VT,Lazio,12,1025 +Ischia di Castro,56031,Viterbo,VT,Lazio,12,1010 +Latera,56032,Viterbo,VT,Lazio,12,1010 +Lubriano,56033,Viterbo,VT,Lazio,12,1020 +Marta,56034,Viterbo,VT,Lazio,12,1010 +Montalto di Castro,56035,Viterbo,VT,Lazio,12,1014 +Montefiascone,56036,Viterbo,VT,Lazio,12,1027 +Monte Romano,56037,Viterbo,VT,Lazio,12,1010 +Monterosi,56038,Viterbo,VT,Lazio,12,1030 +Nepi,56039,Viterbo,VT,Lazio,12,1036 +Onano,56040,Viterbo,VT,Lazio,12,1010 +Oriolo Romano,56041,Viterbo,VT,Lazio,12,1010 +Orte,56042,Viterbo,VT,Lazio,12,1028 +Piansano,56043,Viterbo,VT,Lazio,12,1010 +Proceno,56044,Viterbo,VT,Lazio,12,1020 +Ronciglione,56045,Viterbo,VT,Lazio,12,1037 +Villa San Giovanni in Tuscia,56046,Viterbo,VT,Lazio,12,1010 +San Lorenzo Nuovo,56047,Viterbo,VT,Lazio,12,1020 +Soriano nel Cimino,56048,Viterbo,VT,Lazio,12,1038 +Sutri,56049,Viterbo,VT,Lazio,12,1015 +Tarquinia,56050,Viterbo,VT,Lazio,12,1016 +Tessennano,56051,Viterbo,VT,Lazio,12,1010 +Tuscania,56052,Viterbo,VT,Lazio,12,1017 +Valentano,56053,Viterbo,VT,Lazio,12,1018 +Vallerano,56054,Viterbo,VT,Lazio,12,1030 +Vasanello,56055,Viterbo,VT,Lazio,12,1030 +Vejano,56056,Viterbo,VT,Lazio,12,1010 +Vetralla,56057,Viterbo,VT,Lazio,12,1019 +Vignanello,56058,Viterbo,VT,Lazio,12,1039 +Viterbo,56059,Viterbo,VT,Lazio,12,1100 +Vitorchiano,56060,Viterbo,VT,Lazio,12,1030 +Accumoli,57001,Rieti,RI,Lazio,12,2011 +Amatrice,57002,Rieti,RI,Lazio,12,2012 +Antrodoco,57003,Rieti,RI,Lazio,12,2013 +Ascrea,57004,Rieti,RI,Lazio,12,2020 +Belmonte in Sabina,57005,Rieti,RI,Lazio,12,2020 +Borbona,57006,Rieti,RI,Lazio,12,2010 +Borgorose,57007,Rieti,RI,Lazio,12,2021 +Borgo Velino,57008,Rieti,RI,Lazio,12,2010 +Cantalice,57009,Rieti,RI,Lazio,12,2014 +Cantalupo in Sabina,57010,Rieti,RI,Lazio,12,2040 +Casaprota,57011,Rieti,RI,Lazio,12,2030 +Casperia,57012,Rieti,RI,Lazio,12,2041 +Castel di Tora,57013,Rieti,RI,Lazio,12,2020 +Castelnuovo di Farfa,57014,Rieti,RI,Lazio,12,2031 +Castel Sant'Angelo,57015,Rieti,RI,Lazio,12,2010 +Cittaducale,57016,Rieti,RI,Lazio,12,2015 +Cittareale,57017,Rieti,RI,Lazio,12,2010 +Collalto Sabino,57018,Rieti,RI,Lazio,12,2022 +Colle di Tora,57019,Rieti,RI,Lazio,12,2020 +Collegiove,57020,Rieti,RI,Lazio,12,2020 +Collevecchio,57021,Rieti,RI,Lazio,12,2042 +Colli sul Velino,57022,Rieti,RI,Lazio,12,2010 +Concerviano,57023,Rieti,RI,Lazio,12,2020 +Configni,57024,Rieti,RI,Lazio,12,2040 +Contigliano,57025,Rieti,RI,Lazio,12,2043 +Cottanello,57026,Rieti,RI,Lazio,12,2040 +Fara in Sabina,57027,Rieti,RI,Lazio,12,2032 +Fiamignano,57028,Rieti,RI,Lazio,12,2023 +Forano,57029,Rieti,RI,Lazio,12,2044 +Frasso Sabino,57030,Rieti,RI,Lazio,12,2030 +Greccio,57031,Rieti,RI,Lazio,12,2045 +Labro,57032,Rieti,RI,Lazio,12,2010 +Leonessa,57033,Rieti,RI,Lazio,12,2016 +Longone Sabino,57034,Rieti,RI,Lazio,12,2020 +Magliano Sabina,57035,Rieti,RI,Lazio,12,2046 +Marcetelli,57036,Rieti,RI,Lazio,12,2020 +Micigliano,57037,Rieti,RI,Lazio,12,2010 +Mompeo,57038,Rieti,RI,Lazio,12,2040 +Montasola,57039,Rieti,RI,Lazio,12,2040 +Montebuono,57040,Rieti,RI,Lazio,12,2040 +Monteleone Sabino,57041,Rieti,RI,Lazio,12,2033 +Montenero Sabino,57042,Rieti,RI,Lazio,12,2040 +Monte San Giovanni in Sabina,57043,Rieti,RI,Lazio,12,2040 +Montopoli di Sabina,57044,Rieti,RI,Lazio,12,2034 +Morro Reatino,57045,Rieti,RI,Lazio,12,2010 +Nespolo,57046,Rieti,RI,Lazio,12,2020 +Orvinio,57047,Rieti,RI,Lazio,12,2035 +Paganico Sabino,57048,Rieti,RI,Lazio,12,2020 +Pescorocchiano,57049,Rieti,RI,Lazio,12,2024 +Petrella Salto,57050,Rieti,RI,Lazio,12,2025 +Poggio Bustone,57051,Rieti,RI,Lazio,12,2018 +Poggio Catino,57052,Rieti,RI,Lazio,12,2040 +Poggio Mirteto,57053,Rieti,RI,Lazio,12,2047 +Poggio Moiano,57054,Rieti,RI,Lazio,12,2037 +Poggio Nativo,57055,Rieti,RI,Lazio,12,2030 +Poggio San Lorenzo,57056,Rieti,RI,Lazio,12,2030 +Posta,57057,Rieti,RI,Lazio,12,2019 +Pozzaglia Sabina,57058,Rieti,RI,Lazio,12,2030 +Rieti,57059,Rieti,RI,Lazio,12,2100 +Rivodutri,57060,Rieti,RI,Lazio,12,2010 +Roccantica,57061,Rieti,RI,Lazio,12,2040 +Rocca Sinibalda,57062,Rieti,RI,Lazio,12,2026 +Salisano,57063,Rieti,RI,Lazio,12,2040 +Scandriglia,57064,Rieti,RI,Lazio,12,2038 +Selci,57065,Rieti,RI,Lazio,12,2040 +Stimigliano,57066,Rieti,RI,Lazio,12,2048 +Tarano,57067,Rieti,RI,Lazio,12,2040 +Toffia,57068,Rieti,RI,Lazio,12,2039 +Torricella in Sabina,57069,Rieti,RI,Lazio,12,2030 +Torri in Sabina,57070,Rieti,RI,Lazio,12,2049 +Turania,57071,Rieti,RI,Lazio,12,2020 +Vacone,57072,Rieti,RI,Lazio,12,2040 +Varco Sabino,57073,Rieti,RI,Lazio,12,2020 +Affile,58001,Roma,RM,Lazio,12,21 +Agosta,58002,Roma,RM,Lazio,12,20 +Albano Laziale,58003,Roma,RM,Lazio,12,41 +Allumiere,58004,Roma,RM,Lazio,12,51 +Anguillara Sabazia,58005,Roma,RM,Lazio,12,61 +Anticoli Corrado,58006,Roma,RM,Lazio,12,22 +Anzio,58007,Roma,RM,Lazio,12,42 +Arcinazzo Romano,58008,Roma,RM,Lazio,12,20 +Ariccia,58009,Roma,RM,Lazio,12,40 +Arsoli,58010,Roma,RM,Lazio,12,23 +Artena,58011,Roma,RM,Lazio,12,31 +Bellegra,58012,Roma,RM,Lazio,12,30 +Bracciano,58013,Roma,RM,Lazio,12,62 +Camerata Nuova,58014,Roma,RM,Lazio,12,20 +Campagnano di Roma,58015,Roma,RM,Lazio,12,63 +Canale Monterano,58016,Roma,RM,Lazio,12,60 +Canterano,58017,Roma,RM,Lazio,12,20 +Capena,58018,Roma,RM,Lazio,12,60 +Capranica Prenestina,58019,Roma,RM,Lazio,12,30 +Carpineto Romano,58020,Roma,RM,Lazio,12,32 +Casape,58021,Roma,RM,Lazio,12,10 +Castel Gandolfo,58022,Roma,RM,Lazio,12,40 +Castel Madama,58023,Roma,RM,Lazio,12,24 +Castelnuovo di Porto,58024,Roma,RM,Lazio,12,60 +Castel San Pietro Romano,58025,Roma,RM,Lazio,12,30 +Cave,58026,Roma,RM,Lazio,12,33 +Cerreto Laziale,58027,Roma,RM,Lazio,12,20 +Cervara di Roma,58028,Roma,RM,Lazio,12,20 +Cerveteri,58029,Roma,RM,Lazio,12,52 +Ciciliano,58030,Roma,RM,Lazio,12,20 +Cineto Romano,58031,Roma,RM,Lazio,12,20 +Civitavecchia,58032,Roma,RM,Lazio,12,53 +Civitella San Paolo,58033,Roma,RM,Lazio,12,60 +Colleferro,58034,Roma,RM,Lazio,12,34 +Colonna,58035,Roma,RM,Lazio,12,30 +Fiano Romano,58036,Roma,RM,Lazio,12,65 +Filacciano,58037,Roma,RM,Lazio,12,60 +Formello,58038,Roma,RM,Lazio,12,60 +Frascati,58039,Roma,RM,Lazio,12,44 +Gallicano nel Lazio,58040,Roma,RM,Lazio,12,10 +Gavignano,58041,Roma,RM,Lazio,12,30 +Genazzano,58042,Roma,RM,Lazio,12,30 +Genzano di Roma,58043,Roma,RM,Lazio,12,45 +Gerano,58044,Roma,RM,Lazio,12,25 +Gorga,58045,Roma,RM,Lazio,12,30 +Grottaferrata,58046,Roma,RM,Lazio,12,46 +Guidonia Montecelio,58047,Roma,RM,Lazio,12,12 +Jenne,58048,Roma,RM,Lazio,12,20 +Labico,58049,Roma,RM,Lazio,12,30 +Lanuvio,58050,Roma,RM,Lazio,12,40 +Licenza,58051,Roma,RM,Lazio,12,26 +Magliano Romano,58052,Roma,RM,Lazio,12,60 +Mandela,58053,Roma,RM,Lazio,12,20 +Manziana,58054,Roma,RM,Lazio,12,66 +Marano Equo,58055,Roma,RM,Lazio,12,20 +Marcellina,58056,Roma,RM,Lazio,12,10 +Marino,58057,Roma,RM,Lazio,12,47 +Mazzano Romano,58058,Roma,RM,Lazio,12,60 +Mentana,58059,Roma,RM,Lazio,12,13 +Monte Compatri,58060,Roma,RM,Lazio,12,40 +Monteflavio,58061,Roma,RM,Lazio,12,10 +Montelanico,58062,Roma,RM,Lazio,12,30 +Montelibretti,58063,Roma,RM,Lazio,12,10 +Monte Porzio Catone,58064,Roma,RM,Lazio,12,40 +Monterotondo,58065,Roma,RM,Lazio,12,15 +Montorio Romano,58066,Roma,RM,Lazio,12,10 +Moricone,58067,Roma,RM,Lazio,12,10 +Morlupo,58068,Roma,RM,Lazio,12,67 +Nazzano,58069,Roma,RM,Lazio,12,60 +Nemi,58070,Roma,RM,Lazio,12,40 +Nerola,58071,Roma,RM,Lazio,12,17 +Nettuno,58072,Roma,RM,Lazio,12,48 +Olevano Romano,58073,Roma,RM,Lazio,12,35 +Palestrina,58074,Roma,RM,Lazio,12,36 +Palombara Sabina,58075,Roma,RM,Lazio,12,18 +Percile,58076,Roma,RM,Lazio,12,20 +Pisoniano,58077,Roma,RM,Lazio,12,20 +Poli,58078,Roma,RM,Lazio,12,10 +Pomezia,58079,Roma,RM,Lazio,12,71 +Ponzano Romano,58080,Roma,RM,Lazio,12,60 +Riano,58081,Roma,RM,Lazio,12,60 +Rignano Flaminio,58082,Roma,RM,Lazio,12,68 +Riofreddo,58083,Roma,RM,Lazio,12,20 +Rocca Canterano,58084,Roma,RM,Lazio,12,20 +Rocca di Cave,58085,Roma,RM,Lazio,12,30 +Rocca di Papa,58086,Roma,RM,Lazio,12,40 +Roccagiovine,58087,Roma,RM,Lazio,12,20 +Rocca Priora,58088,Roma,RM,Lazio,12,40 +Rocca Santo Stefano,58089,Roma,RM,Lazio,12,30 +Roiate,58090,Roma,RM,Lazio,12,30 +Roma,58091,Roma,RM,Lazio,12,186 +Roviano,58092,Roma,RM,Lazio,12,27 +Sacrofano,58093,Roma,RM,Lazio,12,60 +Sambuci,58094,Roma,RM,Lazio,12,20 +San Gregorio da Sassola,58095,Roma,RM,Lazio,12,10 +San Polo dei Cavalieri,58096,Roma,RM,Lazio,12,10 +Santa Marinella,58097,Roma,RM,Lazio,12,58 +Sant'Angelo Romano,58098,Roma,RM,Lazio,12,10 +Sant'Oreste,58099,Roma,RM,Lazio,12,60 +San Vito Romano,58100,Roma,RM,Lazio,12,30 +Saracinesco,58101,Roma,RM,Lazio,12,20 +Segni,58102,Roma,RM,Lazio,12,37 +Subiaco,58103,Roma,RM,Lazio,12,28 +Tivoli,58104,Roma,RM,Lazio,12,19 +Tolfa,58105,Roma,RM,Lazio,12,59 +Torrita Tiberina,58106,Roma,RM,Lazio,12,60 +Trevignano Romano,58107,Roma,RM,Lazio,12,69 +Vallepietra,58108,Roma,RM,Lazio,12,20 +Vallinfreda,58109,Roma,RM,Lazio,12,20 +Valmontone,58110,Roma,RM,Lazio,12,38 +Velletri,58111,Roma,RM,Lazio,12,49 +Vicovaro,58112,Roma,RM,Lazio,12,29 +Vivaro Romano,58113,Roma,RM,Lazio,12,20 +Zagarolo,58114,Roma,RM,Lazio,12,39 +Lariano,58115,Roma,RM,Lazio,12,40 +Ladispoli,58116,Roma,RM,Lazio,12,55 +Ardea,58117,Roma,RM,Lazio,12,40 +Ciampino,58118,Roma,RM,Lazio,12,43 +San Cesareo,58119,Roma,RM,Lazio,12,30 +Fiumicino,58120,Roma,RM,Lazio,12,54 +Fonte Nuova,58122,Roma,RM,Lazio,12,13 +Aprilia,59001,Latina,LT,Lazio,12,4011 +Bassiano,59002,Latina,LT,Lazio,12,4010 +Campodimele,59003,Latina,LT,Lazio,12,4020 +Castelforte,59004,Latina,LT,Lazio,12,4021 +Cisterna di Latina,59005,Latina,LT,Lazio,12,4012 +Cori,59006,Latina,LT,Lazio,12,4010 +Fondi,59007,Latina,LT,Lazio,12,4022 +Formia,59008,Latina,LT,Lazio,12,4023 +Gaeta,59009,Latina,LT,Lazio,12,4024 +Itri,59010,Latina,LT,Lazio,12,4020 +Latina,59011,Latina,LT,Lazio,12,4100 +Lenola,59012,Latina,LT,Lazio,12,4025 +Maenza,59013,Latina,LT,Lazio,12,4010 +Minturno,59014,Latina,LT,Lazio,12,4026 +Monte San Biagio,59015,Latina,LT,Lazio,12,4020 +Norma,59016,Latina,LT,Lazio,12,4010 +Pontinia,59017,Latina,LT,Lazio,12,4014 +Ponza,59018,Latina,LT,Lazio,12,4027 +Priverno,59019,Latina,LT,Lazio,12,4015 +Prossedi,59020,Latina,LT,Lazio,12,4010 +Roccagorga,59021,Latina,LT,Lazio,12,4010 +Rocca Massima,59022,Latina,LT,Lazio,12,4010 +Roccasecca dei Volsci,59023,Latina,LT,Lazio,12,4010 +Sabaudia,59024,Latina,LT,Lazio,12,4016 +San Felice Circeo,59025,Latina,LT,Lazio,12,4017 +Santi Cosma e Damiano,59026,Latina,LT,Lazio,12,4020 +Sermoneta,59027,Latina,LT,Lazio,12,4013 +Sezze,59028,Latina,LT,Lazio,12,4018 +Sonnino,59029,Latina,LT,Lazio,12,4010 +Sperlonga,59030,Latina,LT,Lazio,12,4029 +Spigno Saturnia,59031,Latina,LT,Lazio,12,4020 +Terracina,59032,Latina,LT,Lazio,12,4019 +Ventotene,59033,Latina,LT,Lazio,12,4020 +Acquafondata,60001,Frosinone,FR,Lazio,12,3040 +Acuto,60002,Frosinone,FR,Lazio,12,3010 +Alatri,60003,Frosinone,FR,Lazio,12,3011 +Alvito,60004,Frosinone,FR,Lazio,12,3041 +Amaseno,60005,Frosinone,FR,Lazio,12,3021 +Anagni,60006,Frosinone,FR,Lazio,12,3012 +Aquino,60007,Frosinone,FR,Lazio,12,3031 +Arce,60008,Frosinone,FR,Lazio,12,3032 +Arnara,60009,Frosinone,FR,Lazio,12,3020 +Arpino,60010,Frosinone,FR,Lazio,12,3033 +Atina,60011,Frosinone,FR,Lazio,12,3042 +Ausonia,60012,Frosinone,FR,Lazio,12,3040 +Belmonte Castello,60013,Frosinone,FR,Lazio,12,3040 +Boville Ernica,60014,Frosinone,FR,Lazio,12,3022 +Broccostella,60015,Frosinone,FR,Lazio,12,3030 +Campoli Appennino,60016,Frosinone,FR,Lazio,12,3030 +Casalattico,60017,Frosinone,FR,Lazio,12,3030 +Casalvieri,60018,Frosinone,FR,Lazio,12,3034 +Cassino,60019,Frosinone,FR,Lazio,12,3043 +Castelliri,60020,Frosinone,FR,Lazio,12,3030 +Castelnuovo Parano,60021,Frosinone,FR,Lazio,12,3040 +Castrocielo,60022,Frosinone,FR,Lazio,12,3030 +Castro dei Volsci,60023,Frosinone,FR,Lazio,12,3020 +Ceccano,60024,Frosinone,FR,Lazio,12,3023 +Ceprano,60025,Frosinone,FR,Lazio,12,3024 +Cervaro,60026,Frosinone,FR,Lazio,12,3044 +Colfelice,60027,Frosinone,FR,Lazio,12,3030 +Collepardo,60028,Frosinone,FR,Lazio,12,3010 +Colle San Magno,60029,Frosinone,FR,Lazio,12,3030 +Coreno Ausonio,60030,Frosinone,FR,Lazio,12,3040 +Esperia,60031,Frosinone,FR,Lazio,12,3045 +Falvaterra,60032,Frosinone,FR,Lazio,12,3020 +Ferentino,60033,Frosinone,FR,Lazio,12,3013 +Filettino,60034,Frosinone,FR,Lazio,12,3010 +Fiuggi,60035,Frosinone,FR,Lazio,12,3014 +Fontana Liri,60036,Frosinone,FR,Lazio,12,3035 +Fontechiari,60037,Frosinone,FR,Lazio,12,3030 +Frosinone,60038,Frosinone,FR,Lazio,12,3100 +Fumone,60039,Frosinone,FR,Lazio,12,3010 +Gallinaro,60040,Frosinone,FR,Lazio,12,3040 +Giuliano di Roma,60041,Frosinone,FR,Lazio,12,3020 +Guarcino,60042,Frosinone,FR,Lazio,12,3016 +Isola del Liri,60043,Frosinone,FR,Lazio,12,3036 +Monte San Giovanni Campano,60044,Frosinone,FR,Lazio,12,3025 +Morolo,60045,Frosinone,FR,Lazio,12,3017 +Paliano,60046,Frosinone,FR,Lazio,12,3018 +Pastena,60047,Frosinone,FR,Lazio,12,3020 +Patrica,60048,Frosinone,FR,Lazio,12,3010 +Pescosolido,60049,Frosinone,FR,Lazio,12,3030 +Picinisco,60050,Frosinone,FR,Lazio,12,3040 +Pico,60051,Frosinone,FR,Lazio,12,3020 +Piedimonte San Germano,60052,Frosinone,FR,Lazio,12,3030 +Piglio,60053,Frosinone,FR,Lazio,12,3010 +Pignataro Interamna,60054,Frosinone,FR,Lazio,12,3040 +Pofi,60055,Frosinone,FR,Lazio,12,3026 +Pontecorvo,60056,Frosinone,FR,Lazio,12,3037 +Posta Fibreno,60057,Frosinone,FR,Lazio,12,3030 +Ripi,60058,Frosinone,FR,Lazio,12,3027 +Rocca d'Arce,60059,Frosinone,FR,Lazio,12,3030 +Roccasecca,60060,Frosinone,FR,Lazio,12,3038 +San Biagio Saracinisco,60061,Frosinone,FR,Lazio,12,3040 +San Donato Val di Comino,60062,Frosinone,FR,Lazio,12,3046 +San Giorgio a Liri,60063,Frosinone,FR,Lazio,12,3047 +San Giovanni Incarico,60064,Frosinone,FR,Lazio,12,3028 +Sant'Ambrogio sul Garigliano,60065,Frosinone,FR,Lazio,12,3040 +Sant'Andrea del Garigliano,60066,Frosinone,FR,Lazio,12,3040 +Sant'Apollinare,60067,Frosinone,FR,Lazio,12,3048 +Sant'Elia Fiumerapido,60068,Frosinone,FR,Lazio,12,3049 +Santopadre,60069,Frosinone,FR,Lazio,12,3030 +San Vittore del Lazio,60070,Frosinone,FR,Lazio,12,3040 +Serrone,60071,Frosinone,FR,Lazio,12,3010 +Settefrati,60072,Frosinone,FR,Lazio,12,3040 +Sgurgola,60073,Frosinone,FR,Lazio,12,3010 +Sora,60074,Frosinone,FR,Lazio,12,3039 +Strangolagalli,60075,Frosinone,FR,Lazio,12,3020 +Supino,60076,Frosinone,FR,Lazio,12,3019 +Terelle,60077,Frosinone,FR,Lazio,12,3040 +Torre Cajetani,60078,Frosinone,FR,Lazio,12,3010 +Torrice,60079,Frosinone,FR,Lazio,12,3020 +Trevi nel Lazio,60080,Frosinone,FR,Lazio,12,3010 +Trivigliano,60081,Frosinone,FR,Lazio,12,3010 +Vallecorsa,60082,Frosinone,FR,Lazio,12,3020 +Vallemaio,60083,Frosinone,FR,Lazio,12,3040 +Vallerotonda,60084,Frosinone,FR,Lazio,12,3040 +Veroli,60085,Frosinone,FR,Lazio,12,3029 +Vicalvi,60086,Frosinone,FR,Lazio,12,3030 +Vico nel Lazio,60087,Frosinone,FR,Lazio,12,3010 +Villa Latina,60088,Frosinone,FR,Lazio,12,3040 +Villa Santa Lucia,60089,Frosinone,FR,Lazio,12,3030 +Villa Santo Stefano,60090,Frosinone,FR,Lazio,12,3020 +Viticuso,60091,Frosinone,FR,Lazio,12,3040 +Acciano,66001,L'Aquila,AQ,Abruzzo,13,67020 +Aielli,66002,L'Aquila,AQ,Abruzzo,13,67041 +Alfedena,66003,L'Aquila,AQ,Abruzzo,13,67030 +Anversa degli Abruzzi,66004,L'Aquila,AQ,Abruzzo,13,67030 +Ateleta,66005,L'Aquila,AQ,Abruzzo,13,67030 +Avezzano,66006,L'Aquila,AQ,Abruzzo,13,67051 +Balsorano,66007,L'Aquila,AQ,Abruzzo,13,67052 +Barete,66008,L'Aquila,AQ,Abruzzo,13,67010 +Barisciano,66009,L'Aquila,AQ,Abruzzo,13,67021 +Barrea,66010,L'Aquila,AQ,Abruzzo,13,67030 +Bisegna,66011,L'Aquila,AQ,Abruzzo,13,67050 +Bugnara,66012,L'Aquila,AQ,Abruzzo,13,67030 +Cagnano Amiterno,66013,L'Aquila,AQ,Abruzzo,13,67012 +Calascio,66014,L'Aquila,AQ,Abruzzo,13,67020 +Campo di Giove,66015,L'Aquila,AQ,Abruzzo,13,67030 +Campotosto,66016,L'Aquila,AQ,Abruzzo,13,67013 +Canistro,66017,L'Aquila,AQ,Abruzzo,13,67050 +Cansano,66018,L'Aquila,AQ,Abruzzo,13,67030 +Capestrano,66019,L'Aquila,AQ,Abruzzo,13,67022 +Capistrello,66020,L'Aquila,AQ,Abruzzo,13,67053 +Capitignano,66021,L'Aquila,AQ,Abruzzo,13,67014 +Caporciano,66022,L'Aquila,AQ,Abruzzo,13,67020 +Cappadocia,66023,L'Aquila,AQ,Abruzzo,13,67060 +Carapelle Calvisio,66024,L'Aquila,AQ,Abruzzo,13,67020 +Carsoli,66025,L'Aquila,AQ,Abruzzo,13,67061 +Castel del Monte,66026,L'Aquila,AQ,Abruzzo,13,67023 +Castel di Ieri,66027,L'Aquila,AQ,Abruzzo,13,67020 +Castel di Sangro,66028,L'Aquila,AQ,Abruzzo,13,67031 +Castellafiume,66029,L'Aquila,AQ,Abruzzo,13,67050 +Castelvecchio Calvisio,66030,L'Aquila,AQ,Abruzzo,13,67020 +Castelvecchio Subequo,66031,L'Aquila,AQ,Abruzzo,13,67024 +Celano,66032,L'Aquila,AQ,Abruzzo,13,67043 +Cerchio,66033,L'Aquila,AQ,Abruzzo,13,67044 +Civita d'Antino,66034,L'Aquila,AQ,Abruzzo,13,67050 +Civitella Alfedena,66035,L'Aquila,AQ,Abruzzo,13,67030 +Civitella Roveto,66036,L'Aquila,AQ,Abruzzo,13,67054 +Cocullo,66037,L'Aquila,AQ,Abruzzo,13,67030 +Collarmele,66038,L'Aquila,AQ,Abruzzo,13,67040 +Collelongo,66039,L'Aquila,AQ,Abruzzo,13,67050 +Collepietro,66040,L'Aquila,AQ,Abruzzo,13,67020 +Corfinio,66041,L'Aquila,AQ,Abruzzo,13,67030 +Fagnano Alto,66042,L'Aquila,AQ,Abruzzo,13,67020 +Fontecchio,66043,L'Aquila,AQ,Abruzzo,13,67020 +Fossa,66044,L'Aquila,AQ,Abruzzo,13,67020 +Gagliano Aterno,66045,L'Aquila,AQ,Abruzzo,13,67020 +Gioia dei Marsi,66046,L'Aquila,AQ,Abruzzo,13,67055 +Goriano Sicoli,66047,L'Aquila,AQ,Abruzzo,13,67030 +Introdacqua,66048,L'Aquila,AQ,Abruzzo,13,67030 +L'Aquila,66049,L'Aquila,AQ,Abruzzo,13,67100 +Lecce nei Marsi,66050,L'Aquila,AQ,Abruzzo,13,67050 +Luco dei Marsi,66051,L'Aquila,AQ,Abruzzo,13,67056 +Lucoli,66052,L'Aquila,AQ,Abruzzo,13,67045 +Magliano de' Marsi,66053,L'Aquila,AQ,Abruzzo,13,67062 +Massa d'Albe,66054,L'Aquila,AQ,Abruzzo,13,67050 +Molina Aterno,66055,L'Aquila,AQ,Abruzzo,13,67020 +Montereale,66056,L'Aquila,AQ,Abruzzo,13,67015 +Morino,66057,L'Aquila,AQ,Abruzzo,13,67050 +Navelli,66058,L'Aquila,AQ,Abruzzo,13,67020 +Ocre,66059,L'Aquila,AQ,Abruzzo,13,67040 +Ofena,66060,L'Aquila,AQ,Abruzzo,13,67025 +Opi,66061,L'Aquila,AQ,Abruzzo,13,67030 +Oricola,66062,L'Aquila,AQ,Abruzzo,13,67063 +Ortona dei Marsi,66063,L'Aquila,AQ,Abruzzo,13,67050 +Ortucchio,66064,L'Aquila,AQ,Abruzzo,13,67050 +Ovindoli,66065,L'Aquila,AQ,Abruzzo,13,67046 +Pacentro,66066,L'Aquila,AQ,Abruzzo,13,67030 +Pereto,66067,L'Aquila,AQ,Abruzzo,13,67064 +Pescasseroli,66068,L'Aquila,AQ,Abruzzo,13,67032 +Pescina,66069,L'Aquila,AQ,Abruzzo,13,67057 +Pescocostanzo,66070,L'Aquila,AQ,Abruzzo,13,67033 +Pettorano sul Gizio,66071,L'Aquila,AQ,Abruzzo,13,67034 +Pizzoli,66072,L'Aquila,AQ,Abruzzo,13,67017 +Poggio Picenze,66073,L'Aquila,AQ,Abruzzo,13,67026 +Prata d'Ansidonia,66074,L'Aquila,AQ,Abruzzo,13,67020 +Pratola Peligna,66075,L'Aquila,AQ,Abruzzo,13,67035 +Prezza,66076,L'Aquila,AQ,Abruzzo,13,67030 +Raiano,66077,L'Aquila,AQ,Abruzzo,13,67027 +Rivisondoli,66078,L'Aquila,AQ,Abruzzo,13,67036 +Roccacasale,66079,L'Aquila,AQ,Abruzzo,13,67030 +Rocca di Botte,66080,L'Aquila,AQ,Abruzzo,13,67066 +Rocca di Cambio,66081,L'Aquila,AQ,Abruzzo,13,67047 +Rocca di Mezzo,66082,L'Aquila,AQ,Abruzzo,13,67048 +Rocca Pia,66083,L'Aquila,AQ,Abruzzo,13,67030 +Roccaraso,66084,L'Aquila,AQ,Abruzzo,13,67037 +San Benedetto dei Marsi,66085,L'Aquila,AQ,Abruzzo,13,67058 +San Benedetto in Perillis,66086,L'Aquila,AQ,Abruzzo,13,67020 +San Demetrio ne' Vestini,66087,L'Aquila,AQ,Abruzzo,13,67028 +San Pio delle Camere,66088,L'Aquila,AQ,Abruzzo,13,67020 +Sante Marie,66089,L'Aquila,AQ,Abruzzo,13,67067 +Sant'Eusanio Forconese,66090,L'Aquila,AQ,Abruzzo,13,67020 +Santo Stefano di Sessanio,66091,L'Aquila,AQ,Abruzzo,13,67020 +San Vincenzo Valle Roveto,66092,L'Aquila,AQ,Abruzzo,13,67050 +Scanno,66093,L'Aquila,AQ,Abruzzo,13,67038 +Scontrone,66094,L'Aquila,AQ,Abruzzo,13,67030 +Scoppito,66095,L'Aquila,AQ,Abruzzo,13,67019 +Scurcola Marsicana,66096,L'Aquila,AQ,Abruzzo,13,67068 +Secinaro,66097,L'Aquila,AQ,Abruzzo,13,67029 +Sulmona,66098,L'Aquila,AQ,Abruzzo,13,67039 +Tagliacozzo,66099,L'Aquila,AQ,Abruzzo,13,67069 +Tione degli Abruzzi,66100,L'Aquila,AQ,Abruzzo,13,67020 +Tornimparte,66101,L'Aquila,AQ,Abruzzo,13,67049 +Trasacco,66102,L'Aquila,AQ,Abruzzo,13,67059 +Villalago,66103,L'Aquila,AQ,Abruzzo,13,67030 +Villa Santa Lucia degli Abruzzi,66104,L'Aquila,AQ,Abruzzo,13,67020 +Villa Sant'Angelo,66105,L'Aquila,AQ,Abruzzo,13,67020 +Villavallelonga,66106,L'Aquila,AQ,Abruzzo,13,67050 +Villetta Barrea,66107,L'Aquila,AQ,Abruzzo,13,67030 +Vittorito,66108,L'Aquila,AQ,Abruzzo,13,67030 +Alba Adriatica,67001,Teramo,TE,Abruzzo,13,64011 +Ancarano,67002,Teramo,TE,Abruzzo,13,64010 +Arsita,67003,Teramo,TE,Abruzzo,13,64031 +Atri,67004,Teramo,TE,Abruzzo,13,64032 +Basciano,67005,Teramo,TE,Abruzzo,13,64030 +Bellante,67006,Teramo,TE,Abruzzo,13,64020 +Bisenti,67007,Teramo,TE,Abruzzo,13,64033 +Campli,67008,Teramo,TE,Abruzzo,13,64012 +Canzano,67009,Teramo,TE,Abruzzo,13,64020 +Castel Castagna,67010,Teramo,TE,Abruzzo,13,64030 +Castellalto,67011,Teramo,TE,Abruzzo,13,64020 +Castelli,67012,Teramo,TE,Abruzzo,13,64041 +Castiglione Messer Raimondo,67013,Teramo,TE,Abruzzo,13,64034 +Castilenti,67014,Teramo,TE,Abruzzo,13,64035 +Cellino Attanasio,67015,Teramo,TE,Abruzzo,13,64036 +Cermignano,67016,Teramo,TE,Abruzzo,13,64037 +Civitella del Tronto,67017,Teramo,TE,Abruzzo,13,64010 +Colledara,67018,Teramo,TE,Abruzzo,13,64042 +Colonnella,67019,Teramo,TE,Abruzzo,13,64010 +Controguerra,67020,Teramo,TE,Abruzzo,13,64010 +Corropoli,67021,Teramo,TE,Abruzzo,13,64013 +Cortino,67022,Teramo,TE,Abruzzo,13,64040 +Crognaleto,67023,Teramo,TE,Abruzzo,13,64043 +Fano Adriano,67024,Teramo,TE,Abruzzo,13,64044 +Giulianova,67025,Teramo,TE,Abruzzo,13,64021 +Isola del Gran Sasso d'Italia,67026,Teramo,TE,Abruzzo,13,64045 +Montefino,67027,Teramo,TE,Abruzzo,13,64030 +Montorio al Vomano,67028,Teramo,TE,Abruzzo,13,64046 +Morro d'Oro,67029,Teramo,TE,Abruzzo,13,64020 +Mosciano Sant'Angelo,67030,Teramo,TE,Abruzzo,13,64023 +Nereto,67031,Teramo,TE,Abruzzo,13,64015 +Notaresco,67032,Teramo,TE,Abruzzo,13,64024 +Penna Sant'Andrea,67033,Teramo,TE,Abruzzo,13,64039 +Pietracamela,67034,Teramo,TE,Abruzzo,13,64047 +Pineto,67035,Teramo,TE,Abruzzo,13,64025 +Rocca Santa Maria,67036,Teramo,TE,Abruzzo,13,64010 +Roseto degli Abruzzi,67037,Teramo,TE,Abruzzo,13,64026 +Sant'Egidio alla Vibrata,67038,Teramo,TE,Abruzzo,13,64016 +Sant'Omero,67039,Teramo,TE,Abruzzo,13,64027 +Silvi,67040,Teramo,TE,Abruzzo,13,64028 +Teramo,67041,Teramo,TE,Abruzzo,13,64100 +Torano Nuovo,67042,Teramo,TE,Abruzzo,13,64010 +Torricella Sicura,67043,Teramo,TE,Abruzzo,13,64010 +Tortoreto,67044,Teramo,TE,Abruzzo,13,64018 +Tossicia,67045,Teramo,TE,Abruzzo,13,64049 +Valle Castellana,67046,Teramo,TE,Abruzzo,13,64010 +Martinsicuro,67047,Teramo,TE,Abruzzo,13,64014 +Abbateggio,68001,Pescara,PE,Abruzzo,13,65020 +Alanno,68002,Pescara,PE,Abruzzo,13,65020 +Bolognano,68003,Pescara,PE,Abruzzo,13,65020 +Brittoli,68004,Pescara,PE,Abruzzo,13,65010 +Bussi sul Tirino,68005,Pescara,PE,Abruzzo,13,65022 +Cappelle sul Tavo,68006,Pescara,PE,Abruzzo,13,65010 +Caramanico Terme,68007,Pescara,PE,Abruzzo,13,65023 +Carpineto della Nora,68008,Pescara,PE,Abruzzo,13,65010 +Castiglione a Casauria,68009,Pescara,PE,Abruzzo,13,65020 +Catignano,68010,Pescara,PE,Abruzzo,13,65011 +Cepagatti,68011,Pescara,PE,Abruzzo,13,65012 +Città Sant'Angelo,68012,Pescara,PE,Abruzzo,13,65013 +Civitaquana,68013,Pescara,PE,Abruzzo,13,65010 +Civitella Casanova,68014,Pescara,PE,Abruzzo,13,65010 +Collecorvino,68015,Pescara,PE,Abruzzo,13,65010 +Corvara,68016,Pescara,PE,Abruzzo,13,65020 +Cugnoli,68017,Pescara,PE,Abruzzo,13,65020 +Elice,68018,Pescara,PE,Abruzzo,13,65010 +Farindola,68019,Pescara,PE,Abruzzo,13,65010 +Lettomanoppello,68020,Pescara,PE,Abruzzo,13,65020 +Loreto Aprutino,68021,Pescara,PE,Abruzzo,13,65014 +Manoppello,68022,Pescara,PE,Abruzzo,13,65024 +Montebello di Bertona,68023,Pescara,PE,Abruzzo,13,65010 +Montesilvano,68024,Pescara,PE,Abruzzo,13,65015 +Moscufo,68025,Pescara,PE,Abruzzo,13,65010 +Nocciano,68026,Pescara,PE,Abruzzo,13,65010 +Penne,68027,Pescara,PE,Abruzzo,13,65017 +Pescara,68028,Pescara,PE,Abruzzo,13,65121 +Pescosansonesco,68029,Pescara,PE,Abruzzo,13,65020 +Pianella,68030,Pescara,PE,Abruzzo,13,65019 +Picciano,68031,Pescara,PE,Abruzzo,13,65010 +Pietranico,68032,Pescara,PE,Abruzzo,13,65020 +Popoli,68033,Pescara,PE,Abruzzo,13,65026 +Roccamorice,68034,Pescara,PE,Abruzzo,13,65020 +Rosciano,68035,Pescara,PE,Abruzzo,13,65020 +Salle,68036,Pescara,PE,Abruzzo,13,65020 +Sant'Eufemia a Maiella,68037,Pescara,PE,Abruzzo,13,65020 +San Valentino in Abruzzo Citeriore,68038,Pescara,PE,Abruzzo,13,65020 +Scafa,68039,Pescara,PE,Abruzzo,13,65027 +Serramonacesca,68040,Pescara,PE,Abruzzo,13,65025 +Spoltore,68041,Pescara,PE,Abruzzo,13,65010 +Tocco da Casauria,68042,Pescara,PE,Abruzzo,13,65028 +Torre de' Passeri,68043,Pescara,PE,Abruzzo,13,65029 +Turrivalignani,68044,Pescara,PE,Abruzzo,13,65020 +Vicoli,68045,Pescara,PE,Abruzzo,13,65010 +Villa Celiera,68046,Pescara,PE,Abruzzo,13,65010 +Altino,69001,Chieti,CH,Abruzzo,13,66040 +Archi,69002,Chieti,CH,Abruzzo,13,66044 +Ari,69003,Chieti,CH,Abruzzo,13,66010 +Arielli,69004,Chieti,CH,Abruzzo,13,66030 +Atessa,69005,Chieti,CH,Abruzzo,13,66041 +Bomba,69006,Chieti,CH,Abruzzo,13,66042 +Borrello,69007,Chieti,CH,Abruzzo,13,66040 +Bucchianico,69008,Chieti,CH,Abruzzo,13,66011 +Montebello sul Sangro,69009,Chieti,CH,Abruzzo,13,66040 +Canosa Sannita,69010,Chieti,CH,Abruzzo,13,66010 +Carpineto Sinello,69011,Chieti,CH,Abruzzo,13,66030 +Carunchio,69012,Chieti,CH,Abruzzo,13,66050 +Casacanditella,69013,Chieti,CH,Abruzzo,13,66010 +Casalanguida,69014,Chieti,CH,Abruzzo,13,66031 +Casalbordino,69015,Chieti,CH,Abruzzo,13,66021 +Casalincontrada,69016,Chieti,CH,Abruzzo,13,66012 +Casoli,69017,Chieti,CH,Abruzzo,13,66043 +Castel Frentano,69018,Chieti,CH,Abruzzo,13,66032 +Castelguidone,69019,Chieti,CH,Abruzzo,13,66040 +Castiglione Messer Marino,69020,Chieti,CH,Abruzzo,13,66033 +Celenza sul Trigno,69021,Chieti,CH,Abruzzo,13,66050 +Chieti,69022,Chieti,CH,Abruzzo,13,66100 +Civitaluparella,69023,Chieti,CH,Abruzzo,13,66040 +Civitella Messer Raimondo,69024,Chieti,CH,Abruzzo,13,66010 +Colledimacine,69025,Chieti,CH,Abruzzo,13,66010 +Colledimezzo,69026,Chieti,CH,Abruzzo,13,66040 +Crecchio,69027,Chieti,CH,Abruzzo,13,66014 +Cupello,69028,Chieti,CH,Abruzzo,13,66051 +Dogliola,69029,Chieti,CH,Abruzzo,13,66050 +Fara Filiorum Petri,69030,Chieti,CH,Abruzzo,13,66010 +Fara San Martino,69031,Chieti,CH,Abruzzo,13,66015 +Filetto,69032,Chieti,CH,Abruzzo,13,66030 +Fossacesia,69033,Chieti,CH,Abruzzo,13,66022 +Fraine,69034,Chieti,CH,Abruzzo,13,66050 +Francavilla al Mare,69035,Chieti,CH,Abruzzo,13,66023 +Fresagrandinaria,69036,Chieti,CH,Abruzzo,13,66050 +Frisa,69037,Chieti,CH,Abruzzo,13,66030 +Furci,69038,Chieti,CH,Abruzzo,13,66050 +Gamberale,69039,Chieti,CH,Abruzzo,13,66040 +Gessopalena,69040,Chieti,CH,Abruzzo,13,66010 +Gissi,69041,Chieti,CH,Abruzzo,13,66052 +Giuliano Teatino,69042,Chieti,CH,Abruzzo,13,66010 +Guardiagrele,69043,Chieti,CH,Abruzzo,13,66016 +Guilmi,69044,Chieti,CH,Abruzzo,13,66050 +Lama dei Peligni,69045,Chieti,CH,Abruzzo,13,66010 +Lanciano,69046,Chieti,CH,Abruzzo,13,66034 +Lentella,69047,Chieti,CH,Abruzzo,13,66050 +Lettopalena,69048,Chieti,CH,Abruzzo,13,66010 +Liscia,69049,Chieti,CH,Abruzzo,13,66050 +Miglianico,69050,Chieti,CH,Abruzzo,13,66010 +Montazzoli,69051,Chieti,CH,Abruzzo,13,66030 +Monteferrante,69052,Chieti,CH,Abruzzo,13,66040 +Montelapiano,69053,Chieti,CH,Abruzzo,13,66040 +Montenerodomo,69054,Chieti,CH,Abruzzo,13,66010 +Monteodorisio,69055,Chieti,CH,Abruzzo,13,66050 +Mozzagrogna,69056,Chieti,CH,Abruzzo,13,66030 +Orsogna,69057,Chieti,CH,Abruzzo,13,66036 +Ortona,69058,Chieti,CH,Abruzzo,13,66026 +Paglieta,69059,Chieti,CH,Abruzzo,13,66020 +Palena,69060,Chieti,CH,Abruzzo,13,66017 +Palmoli,69061,Chieti,CH,Abruzzo,13,66050 +Palombaro,69062,Chieti,CH,Abruzzo,13,66010 +Pennadomo,69063,Chieti,CH,Abruzzo,13,66040 +Pennapiedimonte,69064,Chieti,CH,Abruzzo,13,66010 +Perano,69065,Chieti,CH,Abruzzo,13,66040 +Pizzoferrato,69066,Chieti,CH,Abruzzo,13,66040 +Poggiofiorito,69067,Chieti,CH,Abruzzo,13,66030 +Pollutri,69068,Chieti,CH,Abruzzo,13,66020 +Pretoro,69069,Chieti,CH,Abruzzo,13,66010 +Quadri,69070,Chieti,CH,Abruzzo,13,66040 +Rapino,69071,Chieti,CH,Abruzzo,13,66010 +Ripa Teatina,69072,Chieti,CH,Abruzzo,13,66010 +Roccamontepiano,69073,Chieti,CH,Abruzzo,13,66010 +Rocca San Giovanni,69074,Chieti,CH,Abruzzo,13,66020 +Roccascalegna,69075,Chieti,CH,Abruzzo,13,66040 +Roccaspinalveti,69076,Chieti,CH,Abruzzo,13,66050 +Roio del Sangro,69077,Chieti,CH,Abruzzo,13,66040 +Rosello,69078,Chieti,CH,Abruzzo,13,66040 +San Buono,69079,Chieti,CH,Abruzzo,13,66050 +San Giovanni Lipioni,69080,Chieti,CH,Abruzzo,13,66050 +San Giovanni Teatino,69081,Chieti,CH,Abruzzo,13,66020 +San Martino sulla Marrucina,69082,Chieti,CH,Abruzzo,13,66010 +San Salvo,69083,Chieti,CH,Abruzzo,13,66050 +Santa Maria Imbaro,69084,Chieti,CH,Abruzzo,13,66030 +Sant'Eusanio del Sangro,69085,Chieti,CH,Abruzzo,13,66037 +San Vito Chietino,69086,Chieti,CH,Abruzzo,13,66038 +Scerni,69087,Chieti,CH,Abruzzo,13,66020 +Schiavi di Abruzzo,69088,Chieti,CH,Abruzzo,13,66045 +Taranta Peligna,69089,Chieti,CH,Abruzzo,13,66018 +Tollo,69090,Chieti,CH,Abruzzo,13,66010 +Torino di Sangro,69091,Chieti,CH,Abruzzo,13,66020 +Tornareccio,69092,Chieti,CH,Abruzzo,13,66046 +Torrebruna,69093,Chieti,CH,Abruzzo,13,66050 +Torrevecchia Teatina,69094,Chieti,CH,Abruzzo,13,66010 +Torricella Peligna,69095,Chieti,CH,Abruzzo,13,66019 +Treglio,69096,Chieti,CH,Abruzzo,13,66030 +Tufillo,69097,Chieti,CH,Abruzzo,13,66050 +Vacri,69098,Chieti,CH,Abruzzo,13,66010 +Vasto,69099,Chieti,CH,Abruzzo,13,66054 +Villalfonsina,69100,Chieti,CH,Abruzzo,13,66020 +Villamagna,69101,Chieti,CH,Abruzzo,13,66010 +Villa Santa Maria,69102,Chieti,CH,Abruzzo,13,66047 +Pietraferrazzana,69103,Chieti,CH,Abruzzo,13,66040 +Fallo,69104,Chieti,CH,Abruzzo,13,66040 +Acquaviva Collecroce,70001,Campobasso,CB,Molise,14,86030 +Baranello,70002,Campobasso,CB,Molise,14,86011 +Bojano,70003,Campobasso,CB,Molise,14,86021 +Bonefro,70004,Campobasso,CB,Molise,14,86041 +Busso,70005,Campobasso,CB,Molise,14,86010 +Campobasso,70006,Campobasso,CB,Molise,14,86100 +Campochiaro,70007,Campobasso,CB,Molise,14,86020 +Campodipietra,70008,Campobasso,CB,Molise,14,86010 +Campolieto,70009,Campobasso,CB,Molise,14,86040 +Campomarino,70010,Campobasso,CB,Molise,14,86042 +Casacalenda,70011,Campobasso,CB,Molise,14,86043 +Casalciprano,70012,Campobasso,CB,Molise,14,86010 +Castelbottaccio,70013,Campobasso,CB,Molise,14,86030 +Castellino del Biferno,70014,Campobasso,CB,Molise,14,86020 +Castelmauro,70015,Campobasso,CB,Molise,14,86031 +Castropignano,70016,Campobasso,CB,Molise,14,86010 +Cercemaggiore,70017,Campobasso,CB,Molise,14,86012 +Cercepiccola,70018,Campobasso,CB,Molise,14,86010 +Civitacampomarano,70019,Campobasso,CB,Molise,14,86030 +Colle d'Anchise,70020,Campobasso,CB,Molise,14,86020 +Colletorto,70021,Campobasso,CB,Molise,14,86044 +Duronia,70022,Campobasso,CB,Molise,14,86020 +Ferrazzano,70023,Campobasso,CB,Molise,14,86010 +Fossalto,70024,Campobasso,CB,Molise,14,86020 +Gambatesa,70025,Campobasso,CB,Molise,14,86013 +Gildone,70026,Campobasso,CB,Molise,14,86010 +Guardialfiera,70027,Campobasso,CB,Molise,14,86030 +Guardiaregia,70028,Campobasso,CB,Molise,14,86014 +Guglionesi,70029,Campobasso,CB,Molise,14,86034 +Jelsi,70030,Campobasso,CB,Molise,14,86015 +Larino,70031,Campobasso,CB,Molise,14,86035 +Limosano,70032,Campobasso,CB,Molise,14,86022 +Lucito,70033,Campobasso,CB,Molise,14,86030 +Lupara,70034,Campobasso,CB,Molise,14,86030 +Macchia Valfortore,70035,Campobasso,CB,Molise,14,86040 +Mafalda,70036,Campobasso,CB,Molise,14,86030 +Matrice,70037,Campobasso,CB,Molise,14,86030 +Mirabello Sannitico,70038,Campobasso,CB,Molise,14,86010 +Molise,70039,Campobasso,CB,Molise,14,86020 +Monacilioni,70040,Campobasso,CB,Molise,14,86040 +Montagano,70041,Campobasso,CB,Molise,14,86023 +Montecilfone,70042,Campobasso,CB,Molise,14,86032 +Montefalcone nel Sannio,70043,Campobasso,CB,Molise,14,86033 +Montelongo,70044,Campobasso,CB,Molise,14,86040 +Montemitro,70045,Campobasso,CB,Molise,14,86030 +Montenero di Bisaccia,70046,Campobasso,CB,Molise,14,86036 +Montorio nei Frentani,70047,Campobasso,CB,Molise,14,86040 +Morrone del Sannio,70048,Campobasso,CB,Molise,14,86040 +Oratino,70049,Campobasso,CB,Molise,14,86010 +Palata,70050,Campobasso,CB,Molise,14,86037 +Petacciato,70051,Campobasso,CB,Molise,14,86038 +Petrella Tifernina,70052,Campobasso,CB,Molise,14,86024 +Pietracatella,70053,Campobasso,CB,Molise,14,86040 +Pietracupa,70054,Campobasso,CB,Molise,14,86020 +Portocannone,70055,Campobasso,CB,Molise,14,86045 +Provvidenti,70056,Campobasso,CB,Molise,14,86040 +Riccia,70057,Campobasso,CB,Molise,14,86016 +Ripabottoni,70058,Campobasso,CB,Molise,14,86040 +Ripalimosani,70059,Campobasso,CB,Molise,14,86025 +Roccavivara,70060,Campobasso,CB,Molise,14,86020 +Rotello,70061,Campobasso,CB,Molise,14,86040 +Salcito,70062,Campobasso,CB,Molise,14,86026 +San Biase,70063,Campobasso,CB,Molise,14,86020 +San Felice del Molise,70064,Campobasso,CB,Molise,14,86030 +San Giacomo degli Schiavoni,70065,Campobasso,CB,Molise,14,86030 +San Giovanni in Galdo,70066,Campobasso,CB,Molise,14,86010 +San Giuliano del Sannio,70067,Campobasso,CB,Molise,14,86010 +San Giuliano di Puglia,70068,Campobasso,CB,Molise,14,86040 +San Martino in Pensilis,70069,Campobasso,CB,Molise,14,86046 +San Massimo,70070,Campobasso,CB,Molise,14,86027 +San Polo Matese,70071,Campobasso,CB,Molise,14,86020 +Santa Croce di Magliano,70072,Campobasso,CB,Molise,14,86047 +Sant'Angelo Limosano,70073,Campobasso,CB,Molise,14,86020 +Sant'Elia a Pianisi,70074,Campobasso,CB,Molise,14,86048 +Sepino,70075,Campobasso,CB,Molise,14,86017 +Spinete,70076,Campobasso,CB,Molise,14,86020 +Tavenna,70077,Campobasso,CB,Molise,14,86030 +Termoli,70078,Campobasso,CB,Molise,14,86039 +Torella del Sannio,70079,Campobasso,CB,Molise,14,86028 +Toro,70080,Campobasso,CB,Molise,14,86018 +Trivento,70081,Campobasso,CB,Molise,14,86029 +Tufara,70082,Campobasso,CB,Molise,14,86010 +Ururi,70083,Campobasso,CB,Molise,14,86049 +Vinchiaturo,70084,Campobasso,CB,Molise,14,86019 +Acquaviva d'Isernia,94001,Isernia,IS,Molise,14,86080 +Agnone,94002,Isernia,IS,Molise,14,86081 +Bagnoli del Trigno,94003,Isernia,IS,Molise,14,86091 +Belmonte del Sannio,94004,Isernia,IS,Molise,14,86080 +Cantalupo nel Sannio,94005,Isernia,IS,Molise,14,86092 +Capracotta,94006,Isernia,IS,Molise,14,86082 +Carovilli,94007,Isernia,IS,Molise,14,86083 +Carpinone,94008,Isernia,IS,Molise,14,86093 +Castel del Giudice,94009,Isernia,IS,Molise,14,86080 +Castelpetroso,94010,Isernia,IS,Molise,14,86090 +Castelpizzuto,94011,Isernia,IS,Molise,14,86090 +Castel San Vincenzo,94012,Isernia,IS,Molise,14,86071 +Castelverrino,94013,Isernia,IS,Molise,14,86080 +Cerro al Volturno,94014,Isernia,IS,Molise,14,86072 +Chiauci,94015,Isernia,IS,Molise,14,86097 +Civitanova del Sannio,94016,Isernia,IS,Molise,14,86094 +Colli a Volturno,94017,Isernia,IS,Molise,14,86073 +Conca Casale,94018,Isernia,IS,Molise,14,86070 +Filignano,94019,Isernia,IS,Molise,14,86074 +Forlì del Sannio,94020,Isernia,IS,Molise,14,86084 +Fornelli,94021,Isernia,IS,Molise,14,86070 +Frosolone,94022,Isernia,IS,Molise,14,86095 +Isernia,94023,Isernia,IS,Molise,14,86170 +Longano,94024,Isernia,IS,Molise,14,86090 +Macchia d'Isernia,94025,Isernia,IS,Molise,14,86070 +Macchiagodena,94026,Isernia,IS,Molise,14,86096 +Miranda,94027,Isernia,IS,Molise,14,86080 +Montaquila,94028,Isernia,IS,Molise,14,86070 +Montenero Val Cocchiara,94029,Isernia,IS,Molise,14,86080 +Monteroduni,94030,Isernia,IS,Molise,14,86075 +Pesche,94031,Isernia,IS,Molise,14,86090 +Pescolanciano,94032,Isernia,IS,Molise,14,86097 +Pescopennataro,94033,Isernia,IS,Molise,14,86080 +Pettoranello del Molise,94034,Isernia,IS,Molise,14,86090 +Pietrabbondante,94035,Isernia,IS,Molise,14,86085 +Pizzone,94036,Isernia,IS,Molise,14,86071 +Poggio Sannita,94037,Isernia,IS,Molise,14,86086 +Pozzilli,94038,Isernia,IS,Molise,14,86077 +Rionero Sannitico,94039,Isernia,IS,Molise,14,86087 +Roccamandolfi,94040,Isernia,IS,Molise,14,86092 +Roccasicura,94041,Isernia,IS,Molise,14,86080 +Rocchetta a Volturno,94042,Isernia,IS,Molise,14,86070 +San Pietro Avellana,94043,Isernia,IS,Molise,14,86088 +Sant'Agapito,94044,Isernia,IS,Molise,14,86070 +Santa Maria del Molise,94045,Isernia,IS,Molise,14,86096 +Sant'Angelo del Pesco,94046,Isernia,IS,Molise,14,86080 +Sant'Elena Sannita,94047,Isernia,IS,Molise,14,86095 +Scapoli,94048,Isernia,IS,Molise,14,86070 +Sessano del Molise,94049,Isernia,IS,Molise,14,86097 +Sesto Campano,94050,Isernia,IS,Molise,14,86078 +Vastogirardi,94051,Isernia,IS,Molise,14,86089 +Venafro,94052,Isernia,IS,Molise,14,86079 +Ailano,61001,Caserta,CE,Campania,15,81010 +Alife,61002,Caserta,CE,Campania,15,81011 +Alvignano,61003,Caserta,CE,Campania,15,81012 +Arienzo,61004,Caserta,CE,Campania,15,81021 +Aversa,61005,Caserta,CE,Campania,15,81031 +Baia e Latina,61006,Caserta,CE,Campania,15,81010 +Bellona,61007,Caserta,CE,Campania,15,81041 +Caianello,61008,Caserta,CE,Campania,15,81059 +Caiazzo,61009,Caserta,CE,Campania,15,81013 +Calvi Risorta,61010,Caserta,CE,Campania,15,81042 +Camigliano,61011,Caserta,CE,Campania,15,81050 +Cancello ed Arnone,61012,Caserta,CE,Campania,15,81030 +Capodrise,61013,Caserta,CE,Campania,15,81020 +Capriati a Volturno,61014,Caserta,CE,Campania,15,81014 +Capua,61015,Caserta,CE,Campania,15,81043 +Carinaro,61016,Caserta,CE,Campania,15,81032 +Carinola,61017,Caserta,CE,Campania,15,81030 +Casagiove,61018,Caserta,CE,Campania,15,81022 +Casal di Principe,61019,Caserta,CE,Campania,15,81033 +Casaluce,61020,Caserta,CE,Campania,15,81030 +Casapulla,61021,Caserta,CE,Campania,15,81020 +Caserta,61022,Caserta,CE,Campania,15,81100 +Castel Campagnano,61023,Caserta,CE,Campania,15,81010 +Castel di Sasso,61024,Caserta,CE,Campania,15,81040 +Castello del Matese,61025,Caserta,CE,Campania,15,81016 +Castel Morrone,61026,Caserta,CE,Campania,15,81020 +Castel Volturno,61027,Caserta,CE,Campania,15,81030 +Cervino,61028,Caserta,CE,Campania,15,81023 +Cesa,61029,Caserta,CE,Campania,15,81030 +Ciorlano,61030,Caserta,CE,Campania,15,81010 +Conca della Campania,61031,Caserta,CE,Campania,15,81044 +Curti,61032,Caserta,CE,Campania,15,81040 +Dragoni,61033,Caserta,CE,Campania,15,81010 +Fontegreca,61034,Caserta,CE,Campania,15,81014 +Formicola,61035,Caserta,CE,Campania,15,81040 +Francolise,61036,Caserta,CE,Campania,15,81050 +Frignano,61037,Caserta,CE,Campania,15,81030 +Gallo Matese,61038,Caserta,CE,Campania,15,81010 +Galluccio,61039,Caserta,CE,Campania,15,81044 +Giano Vetusto,61040,Caserta,CE,Campania,15,81042 +Gioia Sannitica,61041,Caserta,CE,Campania,15,81010 +Grazzanise,61042,Caserta,CE,Campania,15,81046 +Gricignano di Aversa,61043,Caserta,CE,Campania,15,81030 +Letino,61044,Caserta,CE,Campania,15,81010 +Liberi,61045,Caserta,CE,Campania,15,81040 +Lusciano,61046,Caserta,CE,Campania,15,81030 +Macerata Campania,61047,Caserta,CE,Campania,15,81047 +Maddaloni,61048,Caserta,CE,Campania,15,81024 +Marcianise,61049,Caserta,CE,Campania,15,81025 +Marzano Appio,61050,Caserta,CE,Campania,15,81035 +Mignano Monte Lungo,61051,Caserta,CE,Campania,15,81049 +Mondragone,61052,Caserta,CE,Campania,15,81034 +Orta di Atella,61053,Caserta,CE,Campania,15,81030 +Parete,61054,Caserta,CE,Campania,15,81030 +Pastorano,61055,Caserta,CE,Campania,15,81050 +Piana di Monte Verna,61056,Caserta,CE,Campania,15,81013 +Piedimonte Matese,61057,Caserta,CE,Campania,15,81016 +Pietramelara,61058,Caserta,CE,Campania,15,81051 +Pietravairano,61059,Caserta,CE,Campania,15,81040 +Pignataro Maggiore,61060,Caserta,CE,Campania,15,81052 +Pontelatone,61061,Caserta,CE,Campania,15,81040 +Portico di Caserta,61062,Caserta,CE,Campania,15,81050 +Prata Sannita,61063,Caserta,CE,Campania,15,81010 +Pratella,61064,Caserta,CE,Campania,15,81010 +Presenzano,61065,Caserta,CE,Campania,15,81050 +Raviscanina,61066,Caserta,CE,Campania,15,81017 +Recale,61067,Caserta,CE,Campania,15,81020 +Riardo,61068,Caserta,CE,Campania,15,81053 +Rocca d'Evandro,61069,Caserta,CE,Campania,15,81040 +Roccamonfina,61070,Caserta,CE,Campania,15,81035 +Roccaromana,61071,Caserta,CE,Campania,15,81051 +Rocchetta e Croce,61072,Caserta,CE,Campania,15,81042 +Ruviano,61073,Caserta,CE,Campania,15,81010 +San Cipriano d'Aversa,61074,Caserta,CE,Campania,15,81036 +San Felice a Cancello,61075,Caserta,CE,Campania,15,81027 +San Gregorio Matese,61076,Caserta,CE,Campania,15,81010 +San Marcellino,61077,Caserta,CE,Campania,15,81030 +San Nicola la Strada,61078,Caserta,CE,Campania,15,81020 +San Pietro Infine,61079,Caserta,CE,Campania,15,81049 +San Potito Sannitico,61080,Caserta,CE,Campania,15,81016 +San Prisco,61081,Caserta,CE,Campania,15,81054 +Santa Maria a Vico,61082,Caserta,CE,Campania,15,81028 +Santa Maria Capua Vetere,61083,Caserta,CE,Campania,15,81055 +Santa Maria la Fossa,61084,Caserta,CE,Campania,15,81050 +San Tammaro,61085,Caserta,CE,Campania,15,81050 +Sant'Angelo d'Alife,61086,Caserta,CE,Campania,15,81017 +Sant'Arpino,61087,Caserta,CE,Campania,15,81030 +Sessa Aurunca,61088,Caserta,CE,Campania,15,81037 +Sparanise,61089,Caserta,CE,Campania,15,81056 +Succivo,61090,Caserta,CE,Campania,15,81030 +Teano,61091,Caserta,CE,Campania,15,81057 +Teverola,61092,Caserta,CE,Campania,15,81030 +Tora e Piccilli,61093,Caserta,CE,Campania,15,81044 +Trentola Ducenta,61094,Caserta,CE,Campania,15,81038 +Vairano Patenora,61095,Caserta,CE,Campania,15,81058 +Valle Agricola,61096,Caserta,CE,Campania,15,81010 +Valle di Maddaloni,61097,Caserta,CE,Campania,15,81020 +Villa di Briano,61098,Caserta,CE,Campania,15,81030 +Villa Literno,61099,Caserta,CE,Campania,15,81039 +Vitulazio,61100,Caserta,CE,Campania,15,81041 +Falciano del Massico,61101,Caserta,CE,Campania,15,81030 +Cellole,61102,Caserta,CE,Campania,15,81030 +Casapesenna,61103,Caserta,CE,Campania,15,81030 +San Marco Evangelista,61104,Caserta,CE,Campania,15,81020 +Airola,62001,Benevento,BN,Campania,15,82011 +Amorosi,62002,Benevento,BN,Campania,15,82031 +Apice,62003,Benevento,BN,Campania,15,82021 +Apollosa,62004,Benevento,BN,Campania,15,82030 +Arpaia,62005,Benevento,BN,Campania,15,82011 +Arpaise,62006,Benevento,BN,Campania,15,82010 +Baselice,62007,Benevento,BN,Campania,15,82020 +Benevento,62008,Benevento,BN,Campania,15,82100 +Bonea,62009,Benevento,BN,Campania,15,82013 +Bucciano,62010,Benevento,BN,Campania,15,82010 +Buonalbergo,62011,Benevento,BN,Campania,15,82020 +Calvi,62012,Benevento,BN,Campania,15,82018 +Campolattaro,62013,Benevento,BN,Campania,15,82020 +Campoli del Monte Taburno,62014,Benevento,BN,Campania,15,82030 +Casalduni,62015,Benevento,BN,Campania,15,82027 +Castelfranco in Miscano,62016,Benevento,BN,Campania,15,82022 +Castelpagano,62017,Benevento,BN,Campania,15,82024 +Castelpoto,62018,Benevento,BN,Campania,15,82030 +Castelvenere,62019,Benevento,BN,Campania,15,82037 +Castelvetere in Val Fortore,62020,Benevento,BN,Campania,15,82023 +Cautano,62021,Benevento,BN,Campania,15,82030 +Ceppaloni,62022,Benevento,BN,Campania,15,82010 +Cerreto Sannita,62023,Benevento,BN,Campania,15,82032 +Circello,62024,Benevento,BN,Campania,15,82020 +Colle Sannita,62025,Benevento,BN,Campania,15,82024 +Cusano Mutri,62026,Benevento,BN,Campania,15,82033 +Dugenta,62027,Benevento,BN,Campania,15,82030 +Durazzano,62028,Benevento,BN,Campania,15,82015 +Faicchio,62029,Benevento,BN,Campania,15,82030 +Foglianise,62030,Benevento,BN,Campania,15,82030 +Foiano di Val Fortore,62031,Benevento,BN,Campania,15,82020 +Forchia,62032,Benevento,BN,Campania,15,82011 +Fragneto l'Abate,62033,Benevento,BN,Campania,15,82020 +Fragneto Monforte,62034,Benevento,BN,Campania,15,82020 +Frasso Telesino,62035,Benevento,BN,Campania,15,82030 +Ginestra degli Schiavoni,62036,Benevento,BN,Campania,15,82020 +Guardia Sanframondi,62037,Benevento,BN,Campania,15,82034 +Limatola,62038,Benevento,BN,Campania,15,82030 +Melizzano,62039,Benevento,BN,Campania,15,82030 +Moiano,62040,Benevento,BN,Campania,15,82010 +Molinara,62041,Benevento,BN,Campania,15,82020 +Montefalcone di Val Fortore,62042,Benevento,BN,Campania,15,82025 +Montesarchio,62043,Benevento,BN,Campania,15,82016 +Morcone,62044,Benevento,BN,Campania,15,82026 +Paduli,62045,Benevento,BN,Campania,15,82020 +Pago Veiano,62046,Benevento,BN,Campania,15,82020 +Pannarano,62047,Benevento,BN,Campania,15,82017 +Paolisi,62048,Benevento,BN,Campania,15,82011 +Paupisi,62049,Benevento,BN,Campania,15,82030 +Pesco Sannita,62050,Benevento,BN,Campania,15,82020 +Pietraroja,62051,Benevento,BN,Campania,15,82030 +Pietrelcina,62052,Benevento,BN,Campania,15,82020 +Ponte,62053,Benevento,BN,Campania,15,82030 +Pontelandolfo,62054,Benevento,BN,Campania,15,82027 +Puglianello,62055,Benevento,BN,Campania,15,82030 +Reino,62056,Benevento,BN,Campania,15,82020 +San Bartolomeo in Galdo,62057,Benevento,BN,Campania,15,82028 +San Giorgio del Sannio,62058,Benevento,BN,Campania,15,82018 +San Giorgio La Molara,62059,Benevento,BN,Campania,15,82020 +San Leucio del Sannio,62060,Benevento,BN,Campania,15,82010 +San Lorenzello,62061,Benevento,BN,Campania,15,82030 +San Lorenzo Maggiore,62062,Benevento,BN,Campania,15,82034 +San Lupo,62063,Benevento,BN,Campania,15,82034 +San Marco dei Cavoti,62064,Benevento,BN,Campania,15,82029 +San Martino Sannita,62065,Benevento,BN,Campania,15,82010 +San Nazzaro,62066,Benevento,BN,Campania,15,82018 +San Nicola Manfredi,62067,Benevento,BN,Campania,15,82010 +San Salvatore Telesino,62068,Benevento,BN,Campania,15,82030 +Santa Croce del Sannio,62069,Benevento,BN,Campania,15,82020 +Sant'Agata de' Goti,62070,Benevento,BN,Campania,15,82019 +Sant'Angelo a Cupolo,62071,Benevento,BN,Campania,15,82010 +Sassinoro,62072,Benevento,BN,Campania,15,82026 +Solopaca,62073,Benevento,BN,Campania,15,82036 +Telese Terme,62074,Benevento,BN,Campania,15,82037 +Tocco Caudio,62075,Benevento,BN,Campania,15,82030 +Torrecuso,62076,Benevento,BN,Campania,15,82030 +Vitulano,62077,Benevento,BN,Campania,15,82038 +Sant'Arcangelo Trimonte,62078,Benevento,BN,Campania,15,82021 +Acerra,63001,Napoli,NA,Campania,15,80011 +Afragola,63002,Napoli,NA,Campania,15,80021 +Agerola,63003,Napoli,NA,Campania,15,80051 +Anacapri,63004,Napoli,NA,Campania,15,80071 +Arzano,63005,Napoli,NA,Campania,15,80022 +Bacoli,63006,Napoli,NA,Campania,15,80070 +Barano d'Ischia,63007,Napoli,NA,Campania,15,80070 +Boscoreale,63008,Napoli,NA,Campania,15,80041 +Boscotrecase,63009,Napoli,NA,Campania,15,80042 +Brusciano,63010,Napoli,NA,Campania,15,80031 +Caivano,63011,Napoli,NA,Campania,15,80023 +Calvizzano,63012,Napoli,NA,Campania,15,80012 +Camposano,63013,Napoli,NA,Campania,15,80030 +Capri,63014,Napoli,NA,Campania,15,80073 +Carbonara di Nola,63015,Napoli,NA,Campania,15,80030 +Cardito,63016,Napoli,NA,Campania,15,80024 +Casalnuovo di Napoli,63017,Napoli,NA,Campania,15,80013 +Casamarciano,63018,Napoli,NA,Campania,15,80032 +Casamicciola Terme,63019,Napoli,NA,Campania,15,80074 +Casandrino,63020,Napoli,NA,Campania,15,80025 +Casavatore,63021,Napoli,NA,Campania,15,80020 +Casola di Napoli,63022,Napoli,NA,Campania,15,80050 +Casoria,63023,Napoli,NA,Campania,15,80026 +Castellammare di Stabia,63024,Napoli,NA,Campania,15,80053 +Castello di Cisterna,63025,Napoli,NA,Campania,15,80030 +Cercola,63026,Napoli,NA,Campania,15,80040 +Cicciano,63027,Napoli,NA,Campania,15,80033 +Cimitile,63028,Napoli,NA,Campania,15,80030 +Comiziano,63029,Napoli,NA,Campania,15,80030 +Crispano,63030,Napoli,NA,Campania,15,80020 +Forio,63031,Napoli,NA,Campania,15,80075 +Frattamaggiore,63032,Napoli,NA,Campania,15,80027 +Frattaminore,63033,Napoli,NA,Campania,15,80020 +Giugliano in Campania,63034,Napoli,NA,Campania,15,80014 +Gragnano,63035,Napoli,NA,Campania,15,80054 +Grumo Nevano,63036,Napoli,NA,Campania,15,80028 +Ischia,63037,Napoli,NA,Campania,15,80077 +Lacco Ameno,63038,Napoli,NA,Campania,15,80076 +Lettere,63039,Napoli,NA,Campania,15,80050 +Liveri,63040,Napoli,NA,Campania,15,80030 +Marano di Napoli,63041,Napoli,NA,Campania,15,80016 +Mariglianella,63042,Napoli,NA,Campania,15,80030 +Marigliano,63043,Napoli,NA,Campania,15,80034 +Massa Lubrense,63044,Napoli,NA,Campania,15,80061 +Melito di Napoli,63045,Napoli,NA,Campania,15,80017 +Meta,63046,Napoli,NA,Campania,15,80062 +Monte di Procida,63047,Napoli,NA,Campania,15,80070 +Mugnano di Napoli,63048,Napoli,NA,Campania,15,80018 +Napoli,63049,Napoli,NA,Campania,15,80123 +Nola,63050,Napoli,NA,Campania,15,80035 +Ottaviano,63051,Napoli,NA,Campania,15,80044 +Palma Campania,63052,Napoli,NA,Campania,15,80036 +Piano di Sorrento,63053,Napoli,NA,Campania,15,80063 +Pimonte,63054,Napoli,NA,Campania,15,80050 +Poggiomarino,63055,Napoli,NA,Campania,15,80040 +Pollena Trocchia,63056,Napoli,NA,Campania,15,80040 +Pomigliano d'Arco,63057,Napoli,NA,Campania,15,80038 +Pompei,63058,Napoli,NA,Campania,15,80045 +Portici,63059,Napoli,NA,Campania,15,80055 +Pozzuoli,63060,Napoli,NA,Campania,15,80078 +Procida,63061,Napoli,NA,Campania,15,80079 +Qualiano,63062,Napoli,NA,Campania,15,80019 +Quarto,63063,Napoli,NA,Campania,15,80010 +Ercolano,63064,Napoli,NA,Campania,15,80056 +Roccarainola,63065,Napoli,NA,Campania,15,80030 +San Gennaro Vesuviano,63066,Napoli,NA,Campania,15,80040 +San Giorgio a Cremano,63067,Napoli,NA,Campania,15,80046 +San Giuseppe Vesuviano,63068,Napoli,NA,Campania,15,80047 +San Paolo Bel Sito,63069,Napoli,NA,Campania,15,80030 +San Sebastiano al Vesuvio,63070,Napoli,NA,Campania,15,80040 +Sant'Agnello,63071,Napoli,NA,Campania,15,80065 +Sant'Anastasia,63072,Napoli,NA,Campania,15,80048 +Sant'Antimo,63073,Napoli,NA,Campania,15,80029 +Sant'Antonio Abate,63074,Napoli,NA,Campania,15,80057 +San Vitaliano,63075,Napoli,NA,Campania,15,80030 +Saviano,63076,Napoli,NA,Campania,15,80039 +Scisciano,63077,Napoli,NA,Campania,15,80030 +Serrara Fontana,63078,Napoli,NA,Campania,15,80070 +Somma Vesuviana,63079,Napoli,NA,Campania,15,80049 +Sorrento,63080,Napoli,NA,Campania,15,80067 +Striano,63081,Napoli,NA,Campania,15,80040 +Terzigno,63082,Napoli,NA,Campania,15,80040 +Torre Annunziata,63083,Napoli,NA,Campania,15,80058 +Torre del Greco,63084,Napoli,NA,Campania,15,80059 +Tufino,63085,Napoli,NA,Campania,15,80030 +Vico Equense,63086,Napoli,NA,Campania,15,80069 +Villaricca,63087,Napoli,NA,Campania,15,80010 +Visciano,63088,Napoli,NA,Campania,15,80030 +Volla,63089,Napoli,NA,Campania,15,80040 +Santa Maria la Carità,63090,Napoli,NA,Campania,15,80050 +Trecase,63091,Napoli,NA,Campania,15,80040 +Massa di Somma,63092,Napoli,NA,Campania,15,80040 +Aiello del Sabato,64001,Avellino,AV,Campania,15,83020 +Altavilla Irpina,64002,Avellino,AV,Campania,15,83011 +Andretta,64003,Avellino,AV,Campania,15,83040 +Aquilonia,64004,Avellino,AV,Campania,15,83041 +Ariano Irpino,64005,Avellino,AV,Campania,15,83031 +Atripalda,64006,Avellino,AV,Campania,15,83042 +Avella,64007,Avellino,AV,Campania,15,83021 +Avellino,64008,Avellino,AV,Campania,15,83100 +Bagnoli Irpino,64009,Avellino,AV,Campania,15,83043 +Baiano,64010,Avellino,AV,Campania,15,83022 +Bisaccia,64011,Avellino,AV,Campania,15,83044 +Bonito,64012,Avellino,AV,Campania,15,83032 +Cairano,64013,Avellino,AV,Campania,15,83040 +Calabritto,64014,Avellino,AV,Campania,15,83040 +Calitri,64015,Avellino,AV,Campania,15,83045 +Candida,64016,Avellino,AV,Campania,15,83040 +Caposele,64017,Avellino,AV,Campania,15,83040 +Capriglia Irpina,64018,Avellino,AV,Campania,15,83010 +Carife,64019,Avellino,AV,Campania,15,83040 +Casalbore,64020,Avellino,AV,Campania,15,83034 +Cassano Irpino,64021,Avellino,AV,Campania,15,83040 +Castel Baronia,64022,Avellino,AV,Campania,15,83040 +Castelfranci,64023,Avellino,AV,Campania,15,83040 +Castelvetere sul Calore,64024,Avellino,AV,Campania,15,83040 +Cervinara,64025,Avellino,AV,Campania,15,83012 +Cesinali,64026,Avellino,AV,Campania,15,83020 +Chianche,64027,Avellino,AV,Campania,15,83010 +Chiusano di San Domenico,64028,Avellino,AV,Campania,15,83040 +Contrada,64029,Avellino,AV,Campania,15,83020 +Conza della Campania,64030,Avellino,AV,Campania,15,83040 +Domicella,64031,Avellino,AV,Campania,15,83020 +Flumeri,64032,Avellino,AV,Campania,15,83040 +Fontanarosa,64033,Avellino,AV,Campania,15,83040 +Forino,64034,Avellino,AV,Campania,15,83020 +Frigento,64035,Avellino,AV,Campania,15,83040 +Gesualdo,64036,Avellino,AV,Campania,15,83040 +Greci,64037,Avellino,AV,Campania,15,83030 +Grottaminarda,64038,Avellino,AV,Campania,15,83035 +Grottolella,64039,Avellino,AV,Campania,15,83010 +Guardia Lombardi,64040,Avellino,AV,Campania,15,83040 +Lacedonia,64041,Avellino,AV,Campania,15,83046 +Lapio,64042,Avellino,AV,Campania,15,83030 +Lauro,64043,Avellino,AV,Campania,15,83023 +Lioni,64044,Avellino,AV,Campania,15,83047 +Luogosano,64045,Avellino,AV,Campania,15,83040 +Manocalzati,64046,Avellino,AV,Campania,15,83030 +Marzano di Nola,64047,Avellino,AV,Campania,15,83020 +Melito Irpino,64048,Avellino,AV,Campania,15,83030 +Mercogliano,64049,Avellino,AV,Campania,15,83013 +Mirabella Eclano,64050,Avellino,AV,Campania,15,83036 +Montaguto,64051,Avellino,AV,Campania,15,83030 +Montecalvo Irpino,64052,Avellino,AV,Campania,15,83037 +Montefalcione,64053,Avellino,AV,Campania,15,83030 +Monteforte Irpino,64054,Avellino,AV,Campania,15,83024 +Montefredane,64055,Avellino,AV,Campania,15,83030 +Montefusco,64056,Avellino,AV,Campania,15,83030 +Montella,64057,Avellino,AV,Campania,15,83048 +Montemarano,64058,Avellino,AV,Campania,15,83040 +Montemiletto,64059,Avellino,AV,Campania,15,83038 +Monteverde,64060,Avellino,AV,Campania,15,83049 +Morra De Sanctis,64063,Avellino,AV,Campania,15,83040 +Moschiano,64064,Avellino,AV,Campania,15,83020 +Mugnano del Cardinale,64065,Avellino,AV,Campania,15,83027 +Nusco,64066,Avellino,AV,Campania,15,83051 +Ospedaletto d'Alpinolo,64067,Avellino,AV,Campania,15,83014 +Pago del Vallo di Lauro,64068,Avellino,AV,Campania,15,83020 +Parolise,64069,Avellino,AV,Campania,15,83050 +Paternopoli,64070,Avellino,AV,Campania,15,83052 +Petruro Irpino,64071,Avellino,AV,Campania,15,83010 +Pietradefusi,64072,Avellino,AV,Campania,15,83030 +Pietrastornina,64073,Avellino,AV,Campania,15,83015 +Prata di Principato Ultra,64074,Avellino,AV,Campania,15,83030 +Pratola Serra,64075,Avellino,AV,Campania,15,83039 +Quadrelle,64076,Avellino,AV,Campania,15,83020 +Quindici,64077,Avellino,AV,Campania,15,83020 +Roccabascerana,64078,Avellino,AV,Campania,15,83016 +Rocca San Felice,64079,Avellino,AV,Campania,15,83050 +Rotondi,64080,Avellino,AV,Campania,15,83017 +Salza Irpina,64081,Avellino,AV,Campania,15,83050 +San Mango sul Calore,64082,Avellino,AV,Campania,15,83050 +San Martino Valle Caudina,64083,Avellino,AV,Campania,15,83018 +San Michele di Serino,64084,Avellino,AV,Campania,15,83020 +San Nicola Baronia,64085,Avellino,AV,Campania,15,83050 +San Potito Ultra,64086,Avellino,AV,Campania,15,83050 +San Sossio Baronia,64087,Avellino,AV,Campania,15,83050 +Santa Lucia di Serino,64088,Avellino,AV,Campania,15,83020 +Sant'Andrea di Conza,64089,Avellino,AV,Campania,15,83053 +Sant'Angelo all'Esca,64090,Avellino,AV,Campania,15,83050 +Sant'Angelo a Scala,64091,Avellino,AV,Campania,15,83010 +Sant'Angelo dei Lombardi,64092,Avellino,AV,Campania,15,83054 +Santa Paolina,64093,Avellino,AV,Campania,15,83030 +Santo Stefano del Sole,64095,Avellino,AV,Campania,15,83050 +Savignano Irpino,64096,Avellino,AV,Campania,15,83030 +Scampitella,64097,Avellino,AV,Campania,15,83050 +Senerchia,64098,Avellino,AV,Campania,15,83050 +Serino,64099,Avellino,AV,Campania,15,83028 +Sirignano,64100,Avellino,AV,Campania,15,83020 +Solofra,64101,Avellino,AV,Campania,15,83029 +Sorbo Serpico,64102,Avellino,AV,Campania,15,83050 +Sperone,64103,Avellino,AV,Campania,15,83020 +Sturno,64104,Avellino,AV,Campania,15,83055 +Summonte,64105,Avellino,AV,Campania,15,83010 +Taurano,64106,Avellino,AV,Campania,15,83020 +Taurasi,64107,Avellino,AV,Campania,15,83030 +Teora,64108,Avellino,AV,Campania,15,83056 +Torella dei Lombardi,64109,Avellino,AV,Campania,15,83057 +Torre Le Nocelle,64110,Avellino,AV,Campania,15,83030 +Torrioni,64111,Avellino,AV,Campania,15,83010 +Trevico,64112,Avellino,AV,Campania,15,83058 +Tufo,64113,Avellino,AV,Campania,15,83010 +Vallata,64114,Avellino,AV,Campania,15,83059 +Vallesaccarda,64115,Avellino,AV,Campania,15,83050 +Venticano,64116,Avellino,AV,Campania,15,83030 +Villamaina,64117,Avellino,AV,Campania,15,83050 +Villanova del Battista,64118,Avellino,AV,Campania,15,83030 +Volturara Irpina,64119,Avellino,AV,Campania,15,83050 +Zungoli,64120,Avellino,AV,Campania,15,83030 +Montoro,64121,Avellino,AV,Campania,15,83025 +Acerno,65001,Salerno,SA,Campania,15,84042 +Agropoli,65002,Salerno,SA,Campania,15,84043 +Albanella,65003,Salerno,SA,Campania,15,84044 +Alfano,65004,Salerno,SA,Campania,15,84040 +Altavilla Silentina,65005,Salerno,SA,Campania,15,84045 +Amalfi,65006,Salerno,SA,Campania,15,84011 +Angri,65007,Salerno,SA,Campania,15,84012 +Aquara,65008,Salerno,SA,Campania,15,84020 +Ascea,65009,Salerno,SA,Campania,15,84046 +Atena Lucana,65010,Salerno,SA,Campania,15,84030 +Atrani,65011,Salerno,SA,Campania,15,84010 +Auletta,65012,Salerno,SA,Campania,15,84031 +Baronissi,65013,Salerno,SA,Campania,15,84081 +Battipaglia,65014,Salerno,SA,Campania,15,84091 +Bellosguardo,65015,Salerno,SA,Campania,15,84020 +Bracigliano,65016,Salerno,SA,Campania,15,84082 +Buccino,65017,Salerno,SA,Campania,15,84021 +Buonabitacolo,65018,Salerno,SA,Campania,15,84032 +Caggiano,65019,Salerno,SA,Campania,15,84030 +Calvanico,65020,Salerno,SA,Campania,15,84080 +Camerota,65021,Salerno,SA,Campania,15,84040 +Campagna,65022,Salerno,SA,Campania,15,84022 +Campora,65023,Salerno,SA,Campania,15,84040 +Cannalonga,65024,Salerno,SA,Campania,15,84040 +Capaccio Paestum,65025,Salerno,SA,Campania,15,84047 +Casalbuono,65026,Salerno,SA,Campania,15,84030 +Casaletto Spartano,65027,Salerno,SA,Campania,15,84030 +Casal Velino,65028,Salerno,SA,Campania,15,84040 +Caselle in Pittari,65029,Salerno,SA,Campania,15,84030 +Castelcivita,65030,Salerno,SA,Campania,15,84020 +Castellabate,65031,Salerno,SA,Campania,15,84048 +Castelnuovo Cilento,65032,Salerno,SA,Campania,15,84040 +Castelnuovo di Conza,65033,Salerno,SA,Campania,15,84020 +Castel San Giorgio,65034,Salerno,SA,Campania,15,84083 +Castel San Lorenzo,65035,Salerno,SA,Campania,15,84049 +Castiglione del Genovesi,65036,Salerno,SA,Campania,15,84090 +Cava de' Tirreni,65037,Salerno,SA,Campania,15,84013 +Celle di Bulgheria,65038,Salerno,SA,Campania,15,84040 +Centola,65039,Salerno,SA,Campania,15,84051 +Ceraso,65040,Salerno,SA,Campania,15,84052 +Cetara,65041,Salerno,SA,Campania,15,84010 +Cicerale,65042,Salerno,SA,Campania,15,84053 +Colliano,65043,Salerno,SA,Campania,15,84020 +Conca dei Marini,65044,Salerno,SA,Campania,15,84010 +Controne,65045,Salerno,SA,Campania,15,84020 +Contursi Terme,65046,Salerno,SA,Campania,15,84024 +Corbara,65047,Salerno,SA,Campania,15,84010 +Corleto Monforte,65048,Salerno,SA,Campania,15,84020 +Cuccaro Vetere,65049,Salerno,SA,Campania,15,84050 +Eboli,65050,Salerno,SA,Campania,15,84025 +Felitto,65051,Salerno,SA,Campania,15,84055 +Fisciano,65052,Salerno,SA,Campania,15,84084 +Furore,65053,Salerno,SA,Campania,15,84010 +Futani,65054,Salerno,SA,Campania,15,84050 +Giffoni Sei Casali,65055,Salerno,SA,Campania,15,84090 +Giffoni Valle Piana,65056,Salerno,SA,Campania,15,84095 +Gioi,65057,Salerno,SA,Campania,15,84056 +Giungano,65058,Salerno,SA,Campania,15,84050 +Ispani,65059,Salerno,SA,Campania,15,84050 +Laureana Cilento,65060,Salerno,SA,Campania,15,84050 +Laurino,65061,Salerno,SA,Campania,15,84057 +Laurito,65062,Salerno,SA,Campania,15,84050 +Laviano,65063,Salerno,SA,Campania,15,84020 +Lustra,65064,Salerno,SA,Campania,15,84050 +Magliano Vetere,65065,Salerno,SA,Campania,15,84050 +Maiori,65066,Salerno,SA,Campania,15,84010 +Mercato San Severino,65067,Salerno,SA,Campania,15,84085 +Minori,65068,Salerno,SA,Campania,15,84010 +Moio della Civitella,65069,Salerno,SA,Campania,15,84060 +Montano Antilia,65070,Salerno,SA,Campania,15,84060 +Montecorice,65071,Salerno,SA,Campania,15,84060 +Montecorvino Pugliano,65072,Salerno,SA,Campania,15,84090 +Montecorvino Rovella,65073,Salerno,SA,Campania,15,84096 +Monteforte Cilento,65074,Salerno,SA,Campania,15,84060 +Monte San Giacomo,65075,Salerno,SA,Campania,15,84030 +Montesano sulla Marcellana,65076,Salerno,SA,Campania,15,84033 +Morigerati,65077,Salerno,SA,Campania,15,84030 +Nocera Inferiore,65078,Salerno,SA,Campania,15,84014 +Nocera Superiore,65079,Salerno,SA,Campania,15,84015 +Novi Velia,65080,Salerno,SA,Campania,15,84060 +Ogliastro Cilento,65081,Salerno,SA,Campania,15,84061 +Olevano sul Tusciano,65082,Salerno,SA,Campania,15,84062 +Oliveto Citra,65083,Salerno,SA,Campania,15,84020 +Omignano,65084,Salerno,SA,Campania,15,84060 +Orria,65085,Salerno,SA,Campania,15,84060 +Ottati,65086,Salerno,SA,Campania,15,84020 +Padula,65087,Salerno,SA,Campania,15,84034 +Pagani,65088,Salerno,SA,Campania,15,84016 +Palomonte,65089,Salerno,SA,Campania,15,84020 +Pellezzano,65090,Salerno,SA,Campania,15,84080 +Perdifumo,65091,Salerno,SA,Campania,15,84060 +Perito,65092,Salerno,SA,Campania,15,84060 +Pertosa,65093,Salerno,SA,Campania,15,84030 +Petina,65094,Salerno,SA,Campania,15,84020 +Piaggine,65095,Salerno,SA,Campania,15,84065 +Pisciotta,65096,Salerno,SA,Campania,15,84066 +Polla,65097,Salerno,SA,Campania,15,84035 +Pollica,65098,Salerno,SA,Campania,15,84068 +Pontecagnano Faiano,65099,Salerno,SA,Campania,15,84098 +Positano,65100,Salerno,SA,Campania,15,84017 +Postiglione,65101,Salerno,SA,Campania,15,84026 +Praiano,65102,Salerno,SA,Campania,15,84010 +Prignano Cilento,65103,Salerno,SA,Campania,15,84060 +Ravello,65104,Salerno,SA,Campania,15,84010 +Ricigliano,65105,Salerno,SA,Campania,15,84020 +Roccadaspide,65106,Salerno,SA,Campania,15,84069 +Roccagloriosa,65107,Salerno,SA,Campania,15,84060 +Roccapiemonte,65108,Salerno,SA,Campania,15,84086 +Rofrano,65109,Salerno,SA,Campania,15,84070 +Romagnano al Monte,65110,Salerno,SA,Campania,15,84020 +Roscigno,65111,Salerno,SA,Campania,15,84020 +Rutino,65112,Salerno,SA,Campania,15,84070 +Sacco,65113,Salerno,SA,Campania,15,84070 +Sala Consilina,65114,Salerno,SA,Campania,15,84036 +Salento,65115,Salerno,SA,Campania,15,84070 +Salerno,65116,Salerno,SA,Campania,15,84121 +Salvitelle,65117,Salerno,SA,Campania,15,84020 +San Cipriano Picentino,65118,Salerno,SA,Campania,15,84099 +San Giovanni a Piro,65119,Salerno,SA,Campania,15,84070 +San Gregorio Magno,65120,Salerno,SA,Campania,15,84020 +San Mango Piemonte,65121,Salerno,SA,Campania,15,84090 +San Marzano sul Sarno,65122,Salerno,SA,Campania,15,84010 +San Mauro Cilento,65123,Salerno,SA,Campania,15,84070 +San Mauro la Bruca,65124,Salerno,SA,Campania,15,84070 +San Pietro al Tanagro,65125,Salerno,SA,Campania,15,84030 +San Rufo,65126,Salerno,SA,Campania,15,84030 +Santa Marina,65127,Salerno,SA,Campania,15,84070 +Sant'Angelo a Fasanella,65128,Salerno,SA,Campania,15,84027 +Sant'Arsenio,65129,Salerno,SA,Campania,15,84037 +Sant'Egidio del Monte Albino,65130,Salerno,SA,Campania,15,84010 +Santomenna,65131,Salerno,SA,Campania,15,84020 +San Valentino Torio,65132,Salerno,SA,Campania,15,84010 +Sanza,65133,Salerno,SA,Campania,15,84030 +Sapri,65134,Salerno,SA,Campania,15,84073 +Sarno,65135,Salerno,SA,Campania,15,84087 +Sassano,65136,Salerno,SA,Campania,15,84038 +Scafati,65137,Salerno,SA,Campania,15,84018 +Scala,65138,Salerno,SA,Campania,15,84010 +Serramezzana,65139,Salerno,SA,Campania,15,84070 +Serre,65140,Salerno,SA,Campania,15,84028 +Sessa Cilento,65141,Salerno,SA,Campania,15,84074 +Siano,65142,Salerno,SA,Campania,15,84088 +Sicignano degli Alburni,65143,Salerno,SA,Campania,15,84029 +Stella Cilento,65144,Salerno,SA,Campania,15,84070 +Stio,65145,Salerno,SA,Campania,15,84075 +Teggiano,65146,Salerno,SA,Campania,15,84039 +Torchiara,65147,Salerno,SA,Campania,15,84076 +Torraca,65148,Salerno,SA,Campania,15,84030 +Torre Orsaia,65149,Salerno,SA,Campania,15,84077 +Tortorella,65150,Salerno,SA,Campania,15,84030 +Tramonti,65151,Salerno,SA,Campania,15,84010 +Trentinara,65152,Salerno,SA,Campania,15,84070 +Valle dell'Angelo,65153,Salerno,SA,Campania,15,84070 +Vallo della Lucania,65154,Salerno,SA,Campania,15,84078 +Valva,65155,Salerno,SA,Campania,15,84020 +Vibonati,65156,Salerno,SA,Campania,15,84079 +Vietri sul Mare,65157,Salerno,SA,Campania,15,84019 +Bellizzi,65158,Salerno,SA,Campania,15,84092 +Accadia,71001,Foggia,FG,Puglia,16,71021 +Alberona,71002,Foggia,FG,Puglia,16,71031 +Anzano di Puglia,71003,Foggia,FG,Puglia,16,71020 +Apricena,71004,Foggia,FG,Puglia,16,71011 +Ascoli Satriano,71005,Foggia,FG,Puglia,16,71022 +Biccari,71006,Foggia,FG,Puglia,16,71032 +Bovino,71007,Foggia,FG,Puglia,16,71023 +Cagnano Varano,71008,Foggia,FG,Puglia,16,71010 +Candela,71009,Foggia,FG,Puglia,16,71024 +Carapelle,71010,Foggia,FG,Puglia,16,71041 +Carlantino,71011,Foggia,FG,Puglia,16,71030 +Carpino,71012,Foggia,FG,Puglia,16,71010 +Casalnuovo Monterotaro,71013,Foggia,FG,Puglia,16,71033 +Casalvecchio di Puglia,71014,Foggia,FG,Puglia,16,71030 +Castelluccio dei Sauri,71015,Foggia,FG,Puglia,16,71025 +Castelluccio Valmaggiore,71016,Foggia,FG,Puglia,16,71020 +Castelnuovo della Daunia,71017,Foggia,FG,Puglia,16,71034 +Celenza Valfortore,71018,Foggia,FG,Puglia,16,71035 +Celle di San Vito,71019,Foggia,FG,Puglia,16,71020 +Cerignola,71020,Foggia,FG,Puglia,16,71042 +Chieuti,71021,Foggia,FG,Puglia,16,71010 +Deliceto,71022,Foggia,FG,Puglia,16,71026 +Faeto,71023,Foggia,FG,Puglia,16,71020 +Foggia,71024,Foggia,FG,Puglia,16,71121 +Ischitella,71025,Foggia,FG,Puglia,16,71010 +Isole Tremiti,71026,Foggia,FG,Puglia,16,71040 +Lesina,71027,Foggia,FG,Puglia,16,71010 +Lucera,71028,Foggia,FG,Puglia,16,71036 +Manfredonia,71029,Foggia,FG,Puglia,16,71043 +Mattinata,71031,Foggia,FG,Puglia,16,71030 +Monteleone di Puglia,71032,Foggia,FG,Puglia,16,71020 +Monte Sant'Angelo,71033,Foggia,FG,Puglia,16,71037 +Motta Montecorvino,71034,Foggia,FG,Puglia,16,71030 +Orsara di Puglia,71035,Foggia,FG,Puglia,16,71027 +Orta Nova,71036,Foggia,FG,Puglia,16,71045 +Panni,71037,Foggia,FG,Puglia,16,71020 +Peschici,71038,Foggia,FG,Puglia,16,71010 +Pietramontecorvino,71039,Foggia,FG,Puglia,16,71038 +Poggio Imperiale,71040,Foggia,FG,Puglia,16,71010 +Rignano Garganico,71041,Foggia,FG,Puglia,16,71010 +Rocchetta Sant'Antonio,71042,Foggia,FG,Puglia,16,71020 +Rodi Garganico,71043,Foggia,FG,Puglia,16,71012 +Roseto Valfortore,71044,Foggia,FG,Puglia,16,71039 +San Giovanni Rotondo,71046,Foggia,FG,Puglia,16,71013 +San Marco in Lamis,71047,Foggia,FG,Puglia,16,71014 +San Marco la Catola,71048,Foggia,FG,Puglia,16,71030 +San Nicandro Garganico,71049,Foggia,FG,Puglia,16,71015 +San Paolo di Civitate,71050,Foggia,FG,Puglia,16,71010 +San Severo,71051,Foggia,FG,Puglia,16,71016 +Sant'Agata di Puglia,71052,Foggia,FG,Puglia,16,71028 +Serracapriola,71053,Foggia,FG,Puglia,16,71010 +Stornara,71054,Foggia,FG,Puglia,16,71047 +Stornarella,71055,Foggia,FG,Puglia,16,71048 +Torremaggiore,71056,Foggia,FG,Puglia,16,71017 +Troia,71058,Foggia,FG,Puglia,16,71029 +Vico del Gargano,71059,Foggia,FG,Puglia,16,71018 +Vieste,71060,Foggia,FG,Puglia,16,71019 +Volturara Appula,71061,Foggia,FG,Puglia,16,71030 +Volturino,71062,Foggia,FG,Puglia,16,71030 +Ordona,71063,Foggia,FG,Puglia,16,71040 +Zapponeta,71064,Foggia,FG,Puglia,16,71030 +Acquaviva delle Fonti,72001,Bari,BA,Puglia,16,70021 +Adelfia,72002,Bari,BA,Puglia,16,70010 +Alberobello,72003,Bari,BA,Puglia,16,70011 +Altamura,72004,Bari,BA,Puglia,16,70022 +Bari,72006,Bari,BA,Puglia,16,70122 +Binetto,72008,Bari,BA,Puglia,16,70020 +Bitetto,72010,Bari,BA,Puglia,16,70020 +Bitonto,72011,Bari,BA,Puglia,16,70032 +Bitritto,72012,Bari,BA,Puglia,16,70020 +Capurso,72014,Bari,BA,Puglia,16,70010 +Casamassima,72015,Bari,BA,Puglia,16,70010 +Cassano delle Murge,72016,Bari,BA,Puglia,16,70020 +Castellana Grotte,72017,Bari,BA,Puglia,16,70013 +Cellamare,72018,Bari,BA,Puglia,16,70010 +Conversano,72019,Bari,BA,Puglia,16,70014 +Corato,72020,Bari,BA,Puglia,16,70033 +Gioia del Colle,72021,Bari,BA,Puglia,16,70023 +Giovinazzo,72022,Bari,BA,Puglia,16,70054 +Gravina in Puglia,72023,Bari,BA,Puglia,16,70024 +Grumo Appula,72024,Bari,BA,Puglia,16,70025 +Locorotondo,72025,Bari,BA,Puglia,16,70010 +Modugno,72027,Bari,BA,Puglia,16,70026 +Mola di Bari,72028,Bari,BA,Puglia,16,70042 +Molfetta,72029,Bari,BA,Puglia,16,70056 +Monopoli,72030,Bari,BA,Puglia,16,70043 +Noci,72031,Bari,BA,Puglia,16,70015 +Noicattaro,72032,Bari,BA,Puglia,16,70016 +Palo del Colle,72033,Bari,BA,Puglia,16,70027 +Poggiorsini,72034,Bari,BA,Puglia,16,70020 +Polignano a Mare,72035,Bari,BA,Puglia,16,70044 +Putignano,72036,Bari,BA,Puglia,16,70017 +Rutigliano,72037,Bari,BA,Puglia,16,70018 +Ruvo di Puglia,72038,Bari,BA,Puglia,16,70037 +Sammichele di Bari,72039,Bari,BA,Puglia,16,70010 +Sannicandro di Bari,72040,Bari,BA,Puglia,16,70028 +Santeramo in Colle,72041,Bari,BA,Puglia,16,70029 +Terlizzi,72043,Bari,BA,Puglia,16,70038 +Toritto,72044,Bari,BA,Puglia,16,70020 +Triggiano,72046,Bari,BA,Puglia,16,70019 +Turi,72047,Bari,BA,Puglia,16,70010 +Valenzano,72048,Bari,BA,Puglia,16,70010 +Avetrana,73001,Taranto,TA,Puglia,16,74020 +Carosino,73002,Taranto,TA,Puglia,16,74021 +Castellaneta,73003,Taranto,TA,Puglia,16,74011 +Crispiano,73004,Taranto,TA,Puglia,16,74012 +Faggiano,73005,Taranto,TA,Puglia,16,74020 +Fragagnano,73006,Taranto,TA,Puglia,16,74022 +Ginosa,73007,Taranto,TA,Puglia,16,74013 +Grottaglie,73008,Taranto,TA,Puglia,16,74023 +Laterza,73009,Taranto,TA,Puglia,16,74014 +Leporano,73010,Taranto,TA,Puglia,16,74020 +Lizzano,73011,Taranto,TA,Puglia,16,74020 +Manduria,73012,Taranto,TA,Puglia,16,74024 +Martina Franca,73013,Taranto,TA,Puglia,16,74015 +Maruggio,73014,Taranto,TA,Puglia,16,74020 +Massafra,73015,Taranto,TA,Puglia,16,74016 +Monteiasi,73016,Taranto,TA,Puglia,16,74020 +Montemesola,73017,Taranto,TA,Puglia,16,74020 +Monteparano,73018,Taranto,TA,Puglia,16,74020 +Mottola,73019,Taranto,TA,Puglia,16,74017 +Palagianello,73020,Taranto,TA,Puglia,16,74018 +Palagiano,73021,Taranto,TA,Puglia,16,74019 +Pulsano,73022,Taranto,TA,Puglia,16,74026 +Roccaforzata,73023,Taranto,TA,Puglia,16,74020 +San Giorgio Ionico,73024,Taranto,TA,Puglia,16,74027 +San Marzano di San Giuseppe,73025,Taranto,TA,Puglia,16,74020 +Sava,73026,Taranto,TA,Puglia,16,74028 +Taranto,73027,Taranto,TA,Puglia,16,74120 +Torricella,73028,Taranto,TA,Puglia,16,74020 +Statte,73029,Taranto,TA,Puglia,16,74010 +Brindisi,74001,Brindisi,BR,Puglia,16,72100 +Carovigno,74002,Brindisi,BR,Puglia,16,72012 +Ceglie Messapica,74003,Brindisi,BR,Puglia,16,72013 +Cellino San Marco,74004,Brindisi,BR,Puglia,16,72020 +Cisternino,74005,Brindisi,BR,Puglia,16,72014 +Erchie,74006,Brindisi,BR,Puglia,16,72020 +Fasano,74007,Brindisi,BR,Puglia,16,72015 +Francavilla Fontana,74008,Brindisi,BR,Puglia,16,72021 +Latiano,74009,Brindisi,BR,Puglia,16,72022 +Mesagne,74010,Brindisi,BR,Puglia,16,72023 +Oria,74011,Brindisi,BR,Puglia,16,72024 +Ostuni,74012,Brindisi,BR,Puglia,16,72017 +San Donaci,74013,Brindisi,BR,Puglia,16,72025 +San Michele Salentino,74014,Brindisi,BR,Puglia,16,72018 +San Pancrazio Salentino,74015,Brindisi,BR,Puglia,16,72026 +San Pietro Vernotico,74016,Brindisi,BR,Puglia,16,72027 +San Vito dei Normanni,74017,Brindisi,BR,Puglia,16,72019 +Torchiarolo,74018,Brindisi,BR,Puglia,16,72020 +Torre Santa Susanna,74019,Brindisi,BR,Puglia,16,72028 +Villa Castelli,74020,Brindisi,BR,Puglia,16,72029 +Alessano,75002,Lecce,LE,Puglia,16,73031 +Alezio,75003,Lecce,LE,Puglia,16,73011 +Alliste,75004,Lecce,LE,Puglia,16,73040 +Andrano,75005,Lecce,LE,Puglia,16,73032 +Aradeo,75006,Lecce,LE,Puglia,16,73040 +Arnesano,75007,Lecce,LE,Puglia,16,73010 +Bagnolo del Salento,75008,Lecce,LE,Puglia,16,73020 +Botrugno,75009,Lecce,LE,Puglia,16,73020 +Calimera,75010,Lecce,LE,Puglia,16,73021 +Campi Salentina,75011,Lecce,LE,Puglia,16,73012 +Cannole,75012,Lecce,LE,Puglia,16,73020 +Caprarica di Lecce,75013,Lecce,LE,Puglia,16,73010 +Carmiano,75014,Lecce,LE,Puglia,16,73041 +Carpignano Salentino,75015,Lecce,LE,Puglia,16,73020 +Casarano,75016,Lecce,LE,Puglia,16,73042 +Castri di Lecce,75017,Lecce,LE,Puglia,16,73020 +Castrignano de' Greci,75018,Lecce,LE,Puglia,16,73020 +Castrignano del Capo,75019,Lecce,LE,Puglia,16,73040 +Cavallino,75020,Lecce,LE,Puglia,16,73020 +Collepasso,75021,Lecce,LE,Puglia,16,73040 +Copertino,75022,Lecce,LE,Puglia,16,73043 +Corigliano d'Otranto,75023,Lecce,LE,Puglia,16,73022 +Corsano,75024,Lecce,LE,Puglia,16,73033 +Cursi,75025,Lecce,LE,Puglia,16,73020 +Cutrofiano,75026,Lecce,LE,Puglia,16,73020 +Diso,75027,Lecce,LE,Puglia,16,73030 +Gagliano del Capo,75028,Lecce,LE,Puglia,16,73034 +Galatina,75029,Lecce,LE,Puglia,16,73013 +Galatone,75030,Lecce,LE,Puglia,16,73044 +Gallipoli,75031,Lecce,LE,Puglia,16,73014 +Giuggianello,75032,Lecce,LE,Puglia,16,73030 +Giurdignano,75033,Lecce,LE,Puglia,16,73020 +Guagnano,75034,Lecce,LE,Puglia,16,73010 +Lecce,75035,Lecce,LE,Puglia,16,73100 +Lequile,75036,Lecce,LE,Puglia,16,73010 +Leverano,75037,Lecce,LE,Puglia,16,73045 +Lizzanello,75038,Lecce,LE,Puglia,16,73023 +Maglie,75039,Lecce,LE,Puglia,16,73024 +Martano,75040,Lecce,LE,Puglia,16,73025 +Martignano,75041,Lecce,LE,Puglia,16,73020 +Matino,75042,Lecce,LE,Puglia,16,73046 +Melendugno,75043,Lecce,LE,Puglia,16,73026 +Melissano,75044,Lecce,LE,Puglia,16,73040 +Melpignano,75045,Lecce,LE,Puglia,16,73020 +Miggiano,75046,Lecce,LE,Puglia,16,73035 +Minervino di Lecce,75047,Lecce,LE,Puglia,16,73027 +Monteroni di Lecce,75048,Lecce,LE,Puglia,16,73047 +Montesano Salentino,75049,Lecce,LE,Puglia,16,73030 +Morciano di Leuca,75050,Lecce,LE,Puglia,16,73040 +Muro Leccese,75051,Lecce,LE,Puglia,16,73036 +Nardò,75052,Lecce,LE,Puglia,16,73048 +Neviano,75053,Lecce,LE,Puglia,16,73040 +Nociglia,75054,Lecce,LE,Puglia,16,73020 +Novoli,75055,Lecce,LE,Puglia,16,73051 +Ortelle,75056,Lecce,LE,Puglia,16,73030 +Otranto,75057,Lecce,LE,Puglia,16,73028 +Palmariggi,75058,Lecce,LE,Puglia,16,73020 +Parabita,75059,Lecce,LE,Puglia,16,73052 +Patù,75060,Lecce,LE,Puglia,16,73053 +Poggiardo,75061,Lecce,LE,Puglia,16,73037 +Racale,75063,Lecce,LE,Puglia,16,73055 +Ruffano,75064,Lecce,LE,Puglia,16,73049 +Salice Salentino,75065,Lecce,LE,Puglia,16,73015 +Salve,75066,Lecce,LE,Puglia,16,73050 +Sanarica,75067,Lecce,LE,Puglia,16,73030 +San Cesario di Lecce,75068,Lecce,LE,Puglia,16,73016 +San Donato di Lecce,75069,Lecce,LE,Puglia,16,73010 +Sannicola,75070,Lecce,LE,Puglia,16,73017 +San Pietro in Lama,75071,Lecce,LE,Puglia,16,73010 +Santa Cesarea Terme,75072,Lecce,LE,Puglia,16,73020 +Scorrano,75073,Lecce,LE,Puglia,16,73020 +Seclì,75074,Lecce,LE,Puglia,16,73050 +Sogliano Cavour,75075,Lecce,LE,Puglia,16,73010 +Soleto,75076,Lecce,LE,Puglia,16,73010 +Specchia,75077,Lecce,LE,Puglia,16,73040 +Spongano,75078,Lecce,LE,Puglia,16,73038 +Squinzano,75079,Lecce,LE,Puglia,16,73018 +Sternatia,75080,Lecce,LE,Puglia,16,73010 +Supersano,75081,Lecce,LE,Puglia,16,73040 +Surano,75082,Lecce,LE,Puglia,16,73030 +Surbo,75083,Lecce,LE,Puglia,16,73010 +Taurisano,75084,Lecce,LE,Puglia,16,73056 +Taviano,75085,Lecce,LE,Puglia,16,73057 +Tiggiano,75086,Lecce,LE,Puglia,16,73030 +Trepuzzi,75087,Lecce,LE,Puglia,16,73019 +Tricase,75088,Lecce,LE,Puglia,16,73039 +Tuglie,75089,Lecce,LE,Puglia,16,73058 +Ugento,75090,Lecce,LE,Puglia,16,73059 +Uggiano la Chiesa,75091,Lecce,LE,Puglia,16,73020 +Veglie,75092,Lecce,LE,Puglia,16,73010 +Vernole,75093,Lecce,LE,Puglia,16,73029 +Zollino,75094,Lecce,LE,Puglia,16,73010 +San Cassiano,75095,Lecce,LE,Puglia,16,73020 +Castro,75096,Lecce,LE,Puglia,16,73030 +Porto Cesareo,75097,Lecce,LE,Puglia,16,73010 +Presicce-Acquarica,75098,Lecce,LE,Puglia,16,73054 +Andria,110001,Barletta-Andria-Trani,BT,Puglia,16,76123 +Barletta,110002,Barletta-Andria-Trani,BT,Puglia,16,76121 +Bisceglie,110003,Barletta-Andria-Trani,BT,Puglia,16,76011 +Canosa di Puglia,110004,Barletta-Andria-Trani,BT,Puglia,16,76012 +Margherita di Savoia,110005,Barletta-Andria-Trani,BT,Puglia,16,76016 +Minervino Murge,110006,Barletta-Andria-Trani,BT,Puglia,16,76013 +San Ferdinando di Puglia,110007,Barletta-Andria-Trani,BT,Puglia,16,76017 +Spinazzola,110008,Barletta-Andria-Trani,BT,Puglia,16,76014 +Trani,110009,Barletta-Andria-Trani,BT,Puglia,16,76125 +Trinitapoli,110010,Barletta-Andria-Trani,BT,Puglia,16,76015 +Abriola,76001,Potenza,PZ,Basilicata,17,85010 +Acerenza,76002,Potenza,PZ,Basilicata,17,85011 +Albano di Lucania,76003,Potenza,PZ,Basilicata,17,85010 +Anzi,76004,Potenza,PZ,Basilicata,17,85010 +Armento,76005,Potenza,PZ,Basilicata,17,85010 +Atella,76006,Potenza,PZ,Basilicata,17,85020 +Avigliano,76007,Potenza,PZ,Basilicata,17,85021 +Balvano,76008,Potenza,PZ,Basilicata,17,85050 +Banzi,76009,Potenza,PZ,Basilicata,17,85010 +Baragiano,76010,Potenza,PZ,Basilicata,17,85050 +Barile,76011,Potenza,PZ,Basilicata,17,85022 +Bella,76012,Potenza,PZ,Basilicata,17,85051 +Brienza,76013,Potenza,PZ,Basilicata,17,85050 +Brindisi Montagna,76014,Potenza,PZ,Basilicata,17,85010 +Calvello,76015,Potenza,PZ,Basilicata,17,85010 +Calvera,76016,Potenza,PZ,Basilicata,17,85030 +Campomaggiore,76017,Potenza,PZ,Basilicata,17,85010 +Cancellara,76018,Potenza,PZ,Basilicata,17,85010 +Carbone,76019,Potenza,PZ,Basilicata,17,85030 +San Paolo Albanese,76020,Potenza,PZ,Basilicata,17,85030 +Castelgrande,76021,Potenza,PZ,Basilicata,17,85050 +Castelluccio Inferiore,76022,Potenza,PZ,Basilicata,17,85040 +Castelluccio Superiore,76023,Potenza,PZ,Basilicata,17,85040 +Castelmezzano,76024,Potenza,PZ,Basilicata,17,85010 +Castelsaraceno,76025,Potenza,PZ,Basilicata,17,85031 +Castronuovo di Sant'Andrea,76026,Potenza,PZ,Basilicata,17,85030 +Cersosimo,76027,Potenza,PZ,Basilicata,17,85030 +Chiaromonte,76028,Potenza,PZ,Basilicata,17,85032 +Corleto Perticara,76029,Potenza,PZ,Basilicata,17,85012 +Episcopia,76030,Potenza,PZ,Basilicata,17,85033 +Fardella,76031,Potenza,PZ,Basilicata,17,85034 +Filiano,76032,Potenza,PZ,Basilicata,17,85020 +Forenza,76033,Potenza,PZ,Basilicata,17,85023 +Francavilla in Sinni,76034,Potenza,PZ,Basilicata,17,85034 +Gallicchio,76035,Potenza,PZ,Basilicata,17,85010 +Genzano di Lucania,76036,Potenza,PZ,Basilicata,17,85013 +Grumento Nova,76037,Potenza,PZ,Basilicata,17,85050 +Guardia Perticara,76038,Potenza,PZ,Basilicata,17,85010 +Lagonegro,76039,Potenza,PZ,Basilicata,17,85042 +Latronico,76040,Potenza,PZ,Basilicata,17,85043 +Laurenzana,76041,Potenza,PZ,Basilicata,17,85014 +Lauria,76042,Potenza,PZ,Basilicata,17,85044 +Lavello,76043,Potenza,PZ,Basilicata,17,85024 +Maratea,76044,Potenza,PZ,Basilicata,17,85046 +Marsico Nuovo,76045,Potenza,PZ,Basilicata,17,85052 +Marsicovetere,76046,Potenza,PZ,Basilicata,17,85050 +Maschito,76047,Potenza,PZ,Basilicata,17,85020 +Melfi,76048,Potenza,PZ,Basilicata,17,85025 +Missanello,76049,Potenza,PZ,Basilicata,17,85010 +Moliterno,76050,Potenza,PZ,Basilicata,17,85047 +Montemilone,76051,Potenza,PZ,Basilicata,17,85020 +Montemurro,76052,Potenza,PZ,Basilicata,17,85053 +Muro Lucano,76053,Potenza,PZ,Basilicata,17,85054 +Nemoli,76054,Potenza,PZ,Basilicata,17,85040 +Noepoli,76055,Potenza,PZ,Basilicata,17,85035 +Oppido Lucano,76056,Potenza,PZ,Basilicata,17,85015 +Palazzo San Gervasio,76057,Potenza,PZ,Basilicata,17,85026 +Pescopagano,76058,Potenza,PZ,Basilicata,17,85020 +Picerno,76059,Potenza,PZ,Basilicata,17,85055 +Pietragalla,76060,Potenza,PZ,Basilicata,17,85016 +Pietrapertosa,76061,Potenza,PZ,Basilicata,17,85010 +Pignola,76062,Potenza,PZ,Basilicata,17,85010 +Potenza,76063,Potenza,PZ,Basilicata,17,85100 +Rapolla,76064,Potenza,PZ,Basilicata,17,85027 +Rapone,76065,Potenza,PZ,Basilicata,17,85020 +Rionero in Vulture,76066,Potenza,PZ,Basilicata,17,85028 +Ripacandida,76067,Potenza,PZ,Basilicata,17,85020 +Rivello,76068,Potenza,PZ,Basilicata,17,85040 +Roccanova,76069,Potenza,PZ,Basilicata,17,85036 +Rotonda,76070,Potenza,PZ,Basilicata,17,85048 +Ruoti,76071,Potenza,PZ,Basilicata,17,85056 +Ruvo del Monte,76072,Potenza,PZ,Basilicata,17,85020 +San Chirico Nuovo,76073,Potenza,PZ,Basilicata,17,85010 +San Chirico Raparo,76074,Potenza,PZ,Basilicata,17,85030 +San Costantino Albanese,76075,Potenza,PZ,Basilicata,17,85030 +San Fele,76076,Potenza,PZ,Basilicata,17,85020 +San Martino d'Agri,76077,Potenza,PZ,Basilicata,17,85030 +San Severino Lucano,76078,Potenza,PZ,Basilicata,17,85030 +Sant'Angelo Le Fratte,76079,Potenza,PZ,Basilicata,17,85050 +Sant'Arcangelo,76080,Potenza,PZ,Basilicata,17,85037 +Sarconi,76081,Potenza,PZ,Basilicata,17,85050 +Sasso di Castalda,76082,Potenza,PZ,Basilicata,17,85050 +Satriano di Lucania,76083,Potenza,PZ,Basilicata,17,85050 +Savoia di Lucania,76084,Potenza,PZ,Basilicata,17,85050 +Senise,76085,Potenza,PZ,Basilicata,17,85038 +Spinoso,76086,Potenza,PZ,Basilicata,17,85039 +Teana,76087,Potenza,PZ,Basilicata,17,85032 +Terranova di Pollino,76088,Potenza,PZ,Basilicata,17,85030 +Tito,76089,Potenza,PZ,Basilicata,17,85050 +Tolve,76090,Potenza,PZ,Basilicata,17,85017 +Tramutola,76091,Potenza,PZ,Basilicata,17,85057 +Trecchina,76092,Potenza,PZ,Basilicata,17,85049 +Trivigno,76093,Potenza,PZ,Basilicata,17,85018 +Vaglio Basilicata,76094,Potenza,PZ,Basilicata,17,85010 +Venosa,76095,Potenza,PZ,Basilicata,17,85029 +Vietri di Potenza,76096,Potenza,PZ,Basilicata,17,85058 +Viggianello,76097,Potenza,PZ,Basilicata,17,85040 +Viggiano,76098,Potenza,PZ,Basilicata,17,85059 +Ginestra,76099,Potenza,PZ,Basilicata,17,85020 +Paterno,76100,Potenza,PZ,Basilicata,17,85050 +Accettura,77001,Matera,MT,Basilicata,17,75011 +Aliano,77002,Matera,MT,Basilicata,17,75010 +Bernalda,77003,Matera,MT,Basilicata,17,75012 +Calciano,77004,Matera,MT,Basilicata,17,75010 +Cirigliano,77005,Matera,MT,Basilicata,17,75010 +Colobraro,77006,Matera,MT,Basilicata,17,75021 +Craco,77007,Matera,MT,Basilicata,17,75010 +Ferrandina,77008,Matera,MT,Basilicata,17,75013 +Garaguso,77009,Matera,MT,Basilicata,17,75010 +Gorgoglione,77010,Matera,MT,Basilicata,17,75010 +Grassano,77011,Matera,MT,Basilicata,17,75014 +Grottole,77012,Matera,MT,Basilicata,17,75010 +Irsina,77013,Matera,MT,Basilicata,17,75022 +Matera,77014,Matera,MT,Basilicata,17,75100 +Miglionico,77015,Matera,MT,Basilicata,17,75010 +Montalbano Jonico,77016,Matera,MT,Basilicata,17,75023 +Montescaglioso,77017,Matera,MT,Basilicata,17,75024 +Nova Siri,77018,Matera,MT,Basilicata,17,75020 +Oliveto Lucano,77019,Matera,MT,Basilicata,17,75010 +Pisticci,77020,Matera,MT,Basilicata,17,75015 +Policoro,77021,Matera,MT,Basilicata,17,75025 +Pomarico,77022,Matera,MT,Basilicata,17,75016 +Rotondella,77023,Matera,MT,Basilicata,17,75026 +Salandra,77024,Matera,MT,Basilicata,17,75017 +San Giorgio Lucano,77025,Matera,MT,Basilicata,17,75027 +San Mauro Forte,77026,Matera,MT,Basilicata,17,75010 +Stigliano,77027,Matera,MT,Basilicata,17,75018 +Tricarico,77028,Matera,MT,Basilicata,17,75019 +Tursi,77029,Matera,MT,Basilicata,17,75028 +Valsinni,77030,Matera,MT,Basilicata,17,75029 +Scanzano Jonico,77031,Matera,MT,Basilicata,17,75020 +Acquaformosa,78001,Cosenza,CS,Calabria,18,87010 +Acquappesa,78002,Cosenza,CS,Calabria,18,87020 +Acri,78003,Cosenza,CS,Calabria,18,87041 +Aiello Calabro,78004,Cosenza,CS,Calabria,18,87031 +Aieta,78005,Cosenza,CS,Calabria,18,87020 +Albidona,78006,Cosenza,CS,Calabria,18,87070 +Alessandria del Carretto,78007,Cosenza,CS,Calabria,18,87070 +Altilia,78008,Cosenza,CS,Calabria,18,87040 +Altomonte,78009,Cosenza,CS,Calabria,18,87042 +Amantea,78010,Cosenza,CS,Calabria,18,87032 +Amendolara,78011,Cosenza,CS,Calabria,18,87071 +Aprigliano,78012,Cosenza,CS,Calabria,18,87051 +Belmonte Calabro,78013,Cosenza,CS,Calabria,18,87033 +Belsito,78014,Cosenza,CS,Calabria,18,87030 +Belvedere Marittimo,78015,Cosenza,CS,Calabria,18,87021 +Bianchi,78016,Cosenza,CS,Calabria,18,87050 +Bisignano,78017,Cosenza,CS,Calabria,18,87043 +Bocchigliero,78018,Cosenza,CS,Calabria,18,87060 +Bonifati,78019,Cosenza,CS,Calabria,18,87020 +Buonvicino,78020,Cosenza,CS,Calabria,18,87020 +Calopezzati,78021,Cosenza,CS,Calabria,18,87060 +Caloveto,78022,Cosenza,CS,Calabria,18,87060 +Campana,78023,Cosenza,CS,Calabria,18,87061 +Canna,78024,Cosenza,CS,Calabria,18,87070 +Cariati,78025,Cosenza,CS,Calabria,18,87062 +Carolei,78026,Cosenza,CS,Calabria,18,87030 +Carpanzano,78027,Cosenza,CS,Calabria,18,87050 +Cassano all'Ionio,78029,Cosenza,CS,Calabria,18,87011 +Castiglione Cosentino,78030,Cosenza,CS,Calabria,18,87040 +Castrolibero,78031,Cosenza,CS,Calabria,18,87040 +Castroregio,78032,Cosenza,CS,Calabria,18,87070 +Castrovillari,78033,Cosenza,CS,Calabria,18,87012 +Celico,78034,Cosenza,CS,Calabria,18,87053 +Cellara,78035,Cosenza,CS,Calabria,18,87050 +Cerchiara di Calabria,78036,Cosenza,CS,Calabria,18,87070 +Cerisano,78037,Cosenza,CS,Calabria,18,87044 +Cervicati,78038,Cosenza,CS,Calabria,18,87010 +Cerzeto,78039,Cosenza,CS,Calabria,18,87040 +Cetraro,78040,Cosenza,CS,Calabria,18,87022 +Civita,78041,Cosenza,CS,Calabria,18,87010 +Cleto,78042,Cosenza,CS,Calabria,18,87030 +Colosimi,78043,Cosenza,CS,Calabria,18,87050 +Cosenza,78045,Cosenza,CS,Calabria,18,87100 +Cropalati,78046,Cosenza,CS,Calabria,18,87060 +Crosia,78047,Cosenza,CS,Calabria,18,87060 +Diamante,78048,Cosenza,CS,Calabria,18,87023 +Dipignano,78049,Cosenza,CS,Calabria,18,87045 +Domanico,78050,Cosenza,CS,Calabria,18,87030 +Fagnano Castello,78051,Cosenza,CS,Calabria,18,87013 +Falconara Albanese,78052,Cosenza,CS,Calabria,18,87030 +Figline Vegliaturo,78053,Cosenza,CS,Calabria,18,87050 +Firmo,78054,Cosenza,CS,Calabria,18,87010 +Fiumefreddo Bruzio,78055,Cosenza,CS,Calabria,18,87030 +Francavilla Marittima,78056,Cosenza,CS,Calabria,18,87072 +Frascineto,78057,Cosenza,CS,Calabria,18,87010 +Fuscaldo,78058,Cosenza,CS,Calabria,18,87024 +Grimaldi,78059,Cosenza,CS,Calabria,18,87034 +Grisolia,78060,Cosenza,CS,Calabria,18,87020 +Guardia Piemontese,78061,Cosenza,CS,Calabria,18,87020 +Lago,78062,Cosenza,CS,Calabria,18,87035 +Laino Borgo,78063,Cosenza,CS,Calabria,18,87014 +Laino Castello,78064,Cosenza,CS,Calabria,18,87015 +Lappano,78065,Cosenza,CS,Calabria,18,87050 +Lattarico,78066,Cosenza,CS,Calabria,18,87010 +Longobardi,78067,Cosenza,CS,Calabria,18,87030 +Longobucco,78068,Cosenza,CS,Calabria,18,87066 +Lungro,78069,Cosenza,CS,Calabria,18,87010 +Luzzi,78070,Cosenza,CS,Calabria,18,87040 +Maierà,78071,Cosenza,CS,Calabria,18,87020 +Malito,78072,Cosenza,CS,Calabria,18,87030 +Malvito,78073,Cosenza,CS,Calabria,18,87010 +Mandatoriccio,78074,Cosenza,CS,Calabria,18,87060 +Mangone,78075,Cosenza,CS,Calabria,18,87050 +Marano Marchesato,78076,Cosenza,CS,Calabria,18,87040 +Marano Principato,78077,Cosenza,CS,Calabria,18,87040 +Marzi,78078,Cosenza,CS,Calabria,18,87050 +Mendicino,78079,Cosenza,CS,Calabria,18,87040 +Mongrassano,78080,Cosenza,CS,Calabria,18,87040 +Montalto Uffugo,78081,Cosenza,CS,Calabria,18,87046 +Montegiordano,78082,Cosenza,CS,Calabria,18,87070 +Morano Calabro,78083,Cosenza,CS,Calabria,18,87016 +Mormanno,78084,Cosenza,CS,Calabria,18,87026 +Mottafollone,78085,Cosenza,CS,Calabria,18,87010 +Nocara,78086,Cosenza,CS,Calabria,18,87070 +Oriolo,78087,Cosenza,CS,Calabria,18,87073 +Orsomarso,78088,Cosenza,CS,Calabria,18,87020 +Paludi,78089,Cosenza,CS,Calabria,18,87060 +Panettieri,78090,Cosenza,CS,Calabria,18,87050 +Paola,78091,Cosenza,CS,Calabria,18,87027 +Papasidero,78092,Cosenza,CS,Calabria,18,87020 +Parenti,78093,Cosenza,CS,Calabria,18,87040 +Paterno Calabro,78094,Cosenza,CS,Calabria,18,87040 +Pedivigliano,78096,Cosenza,CS,Calabria,18,87050 +Piane Crati,78097,Cosenza,CS,Calabria,18,87050 +Pietrafitta,78098,Cosenza,CS,Calabria,18,87050 +Pietrapaola,78099,Cosenza,CS,Calabria,18,87060 +Plataci,78100,Cosenza,CS,Calabria,18,87070 +Praia a Mare,78101,Cosenza,CS,Calabria,18,87028 +Rende,78102,Cosenza,CS,Calabria,18,87036 +Rocca Imperiale,78103,Cosenza,CS,Calabria,18,87074 +Roggiano Gravina,78104,Cosenza,CS,Calabria,18,87017 +Rogliano,78105,Cosenza,CS,Calabria,18,87054 +Rose,78106,Cosenza,CS,Calabria,18,87040 +Roseto Capo Spulico,78107,Cosenza,CS,Calabria,18,87070 +Rota Greca,78109,Cosenza,CS,Calabria,18,87010 +Rovito,78110,Cosenza,CS,Calabria,18,87050 +San Basile,78111,Cosenza,CS,Calabria,18,87010 +San Benedetto Ullano,78112,Cosenza,CS,Calabria,18,87040 +San Cosmo Albanese,78113,Cosenza,CS,Calabria,18,87060 +San Demetrio Corone,78114,Cosenza,CS,Calabria,18,87069 +San Donato di Ninea,78115,Cosenza,CS,Calabria,18,87010 +San Fili,78116,Cosenza,CS,Calabria,18,87037 +Sangineto,78117,Cosenza,CS,Calabria,18,87020 +San Giorgio Albanese,78118,Cosenza,CS,Calabria,18,87060 +San Giovanni in Fiore,78119,Cosenza,CS,Calabria,18,87055 +San Lorenzo Bellizzi,78120,Cosenza,CS,Calabria,18,87070 +San Lorenzo del Vallo,78121,Cosenza,CS,Calabria,18,87040 +San Lucido,78122,Cosenza,CS,Calabria,18,87038 +San Marco Argentano,78123,Cosenza,CS,Calabria,18,87018 +San Martino di Finita,78124,Cosenza,CS,Calabria,18,87010 +San Nicola Arcella,78125,Cosenza,CS,Calabria,18,87020 +San Pietro in Amantea,78126,Cosenza,CS,Calabria,18,87030 +San Pietro in Guarano,78127,Cosenza,CS,Calabria,18,87047 +San Sosti,78128,Cosenza,CS,Calabria,18,87010 +Santa Caterina Albanese,78129,Cosenza,CS,Calabria,18,87010 +Santa Domenica Talao,78130,Cosenza,CS,Calabria,18,87020 +Sant'Agata di Esaro,78131,Cosenza,CS,Calabria,18,87010 +Santa Maria del Cedro,78132,Cosenza,CS,Calabria,18,87020 +Santa Sofia d'Epiro,78133,Cosenza,CS,Calabria,18,87048 +Santo Stefano di Rogliano,78134,Cosenza,CS,Calabria,18,87056 +San Vincenzo La Costa,78135,Cosenza,CS,Calabria,18,87030 +Saracena,78136,Cosenza,CS,Calabria,18,87010 +Scala Coeli,78137,Cosenza,CS,Calabria,18,87060 +Scalea,78138,Cosenza,CS,Calabria,18,87029 +Scigliano,78139,Cosenza,CS,Calabria,18,87057 +Serra d'Aiello,78140,Cosenza,CS,Calabria,18,87030 +Spezzano Albanese,78142,Cosenza,CS,Calabria,18,87019 +Spezzano della Sila,78143,Cosenza,CS,Calabria,18,87058 +Tarsia,78145,Cosenza,CS,Calabria,18,87040 +Terranova da Sibari,78146,Cosenza,CS,Calabria,18,87010 +Terravecchia,78147,Cosenza,CS,Calabria,18,87060 +Torano Castello,78148,Cosenza,CS,Calabria,18,87010 +Tortora,78149,Cosenza,CS,Calabria,18,87020 +Trebisacce,78150,Cosenza,CS,Calabria,18,87075 +Vaccarizzo Albanese,78152,Cosenza,CS,Calabria,18,87060 +Verbicaro,78153,Cosenza,CS,Calabria,18,87020 +Villapiana,78154,Cosenza,CS,Calabria,18,87076 +Zumpano,78155,Cosenza,CS,Calabria,18,87040 +Casali del Manco,78156,Cosenza,CS,Calabria,18,87050 +Corigliano-Rossano,78157,Cosenza,CS,Calabria,18,87064 +Albi,79002,Catanzaro,CZ,Calabria,18,88055 +Amaroni,79003,Catanzaro,CZ,Calabria,18,88050 +Amato,79004,Catanzaro,CZ,Calabria,18,88040 +Andali,79005,Catanzaro,CZ,Calabria,18,88050 +Argusto,79007,Catanzaro,CZ,Calabria,18,88060 +Badolato,79008,Catanzaro,CZ,Calabria,18,88060 +Belcastro,79009,Catanzaro,CZ,Calabria,18,88050 +Borgia,79011,Catanzaro,CZ,Calabria,18,88021 +Botricello,79012,Catanzaro,CZ,Calabria,18,88070 +Caraffa di Catanzaro,79017,Catanzaro,CZ,Calabria,18,88050 +Cardinale,79018,Catanzaro,CZ,Calabria,18,88062 +Carlopoli,79020,Catanzaro,CZ,Calabria,18,88040 +Catanzaro,79023,Catanzaro,CZ,Calabria,18,88100 +Cenadi,79024,Catanzaro,CZ,Calabria,18,88067 +Centrache,79025,Catanzaro,CZ,Calabria,18,88067 +Cerva,79027,Catanzaro,CZ,Calabria,18,88050 +Chiaravalle Centrale,79029,Catanzaro,CZ,Calabria,18,88064 +Cicala,79030,Catanzaro,CZ,Calabria,18,88040 +Conflenti,79033,Catanzaro,CZ,Calabria,18,88040 +Cortale,79034,Catanzaro,CZ,Calabria,18,88020 +Cropani,79036,Catanzaro,CZ,Calabria,18,88051 +Curinga,79039,Catanzaro,CZ,Calabria,18,88022 +Davoli,79042,Catanzaro,CZ,Calabria,18,88060 +Decollatura,79043,Catanzaro,CZ,Calabria,18,88041 +Falerna,79047,Catanzaro,CZ,Calabria,18,88042 +Feroleto Antico,79048,Catanzaro,CZ,Calabria,18,88040 +Fossato Serralta,79052,Catanzaro,CZ,Calabria,18,88050 +Gagliato,79055,Catanzaro,CZ,Calabria,18,88060 +Gasperina,79056,Catanzaro,CZ,Calabria,18,88060 +Gimigliano,79058,Catanzaro,CZ,Calabria,18,88045 +Girifalco,79059,Catanzaro,CZ,Calabria,18,88024 +Gizzeria,79060,Catanzaro,CZ,Calabria,18,88040 +Guardavalle,79061,Catanzaro,CZ,Calabria,18,88065 +Isca sullo Ionio,79063,Catanzaro,CZ,Calabria,18,88060 +Jacurso,79065,Catanzaro,CZ,Calabria,18,88020 +Magisano,79068,Catanzaro,CZ,Calabria,18,88050 +Maida,79069,Catanzaro,CZ,Calabria,18,88025 +Marcedusa,79071,Catanzaro,CZ,Calabria,18,88050 +Marcellinara,79072,Catanzaro,CZ,Calabria,18,88044 +Martirano,79073,Catanzaro,CZ,Calabria,18,88040 +Martirano Lombardo,79074,Catanzaro,CZ,Calabria,18,88040 +Miglierina,79077,Catanzaro,CZ,Calabria,18,88040 +Montauro,79080,Catanzaro,CZ,Calabria,18,88060 +Montepaone,79081,Catanzaro,CZ,Calabria,18,88060 +Motta Santa Lucia,79083,Catanzaro,CZ,Calabria,18,88040 +Nocera Terinese,79087,Catanzaro,CZ,Calabria,18,88047 +Olivadi,79088,Catanzaro,CZ,Calabria,18,88067 +Palermiti,79089,Catanzaro,CZ,Calabria,18,88050 +Pentone,79092,Catanzaro,CZ,Calabria,18,88050 +Petrizzi,79094,Catanzaro,CZ,Calabria,18,88060 +Petronà,79095,Catanzaro,CZ,Calabria,18,88050 +Pianopoli,79096,Catanzaro,CZ,Calabria,18,88040 +Platania,79099,Catanzaro,CZ,Calabria,18,88040 +San Floro,79108,Catanzaro,CZ,Calabria,18,88021 +San Mango d'Aquino,79110,Catanzaro,CZ,Calabria,18,88040 +San Pietro a Maida,79114,Catanzaro,CZ,Calabria,18,88025 +San Pietro Apostolo,79115,Catanzaro,CZ,Calabria,18,88040 +San Sostene,79116,Catanzaro,CZ,Calabria,18,88060 +Santa Caterina dello Ionio,79117,Catanzaro,CZ,Calabria,18,88060 +Sant'Andrea Apostolo dello Ionio,79118,Catanzaro,CZ,Calabria,18,88060 +San Vito sullo Ionio,79122,Catanzaro,CZ,Calabria,18,88067 +Satriano,79123,Catanzaro,CZ,Calabria,18,88060 +Sellia,79126,Catanzaro,CZ,Calabria,18,88050 +Sellia Marina,79127,Catanzaro,CZ,Calabria,18,88050 +Serrastretta,79129,Catanzaro,CZ,Calabria,18,88040 +Sersale,79130,Catanzaro,CZ,Calabria,18,88054 +Settingiano,79131,Catanzaro,CZ,Calabria,18,88040 +Simeri Crichi,79133,Catanzaro,CZ,Calabria,18,88050 +Sorbo San Basile,79134,Catanzaro,CZ,Calabria,18,88050 +Soverato,79137,Catanzaro,CZ,Calabria,18,88068 +Soveria Mannelli,79138,Catanzaro,CZ,Calabria,18,88049 +Soveria Simeri,79139,Catanzaro,CZ,Calabria,18,88050 +Squillace,79142,Catanzaro,CZ,Calabria,18,88069 +Stalettì,79143,Catanzaro,CZ,Calabria,18,88069 +Taverna,79146,Catanzaro,CZ,Calabria,18,88055 +Tiriolo,79147,Catanzaro,CZ,Calabria,18,88056 +Torre di Ruggiero,79148,Catanzaro,CZ,Calabria,18,88060 +Vallefiorita,79151,Catanzaro,CZ,Calabria,18,88050 +Zagarise,79157,Catanzaro,CZ,Calabria,18,88050 +Lamezia Terme,79160,Catanzaro,CZ,Calabria,18,88046 +Africo,80001,Reggio Calabria,RC,Calabria,18,89030 +Agnana Calabra,80002,Reggio Calabria,RC,Calabria,18,89040 +Anoia,80003,Reggio Calabria,RC,Calabria,18,89020 +Antonimina,80004,Reggio Calabria,RC,Calabria,18,89040 +Ardore,80005,Reggio Calabria,RC,Calabria,18,89031 +Bagaladi,80006,Reggio Calabria,RC,Calabria,18,89060 +Bagnara Calabra,80007,Reggio Calabria,RC,Calabria,18,89011 +Benestare,80008,Reggio Calabria,RC,Calabria,18,89030 +Bianco,80009,Reggio Calabria,RC,Calabria,18,89032 +Bivongi,80010,Reggio Calabria,RC,Calabria,18,89040 +Bova,80011,Reggio Calabria,RC,Calabria,18,89033 +Bovalino,80012,Reggio Calabria,RC,Calabria,18,89034 +Bova Marina,80013,Reggio Calabria,RC,Calabria,18,89035 +Brancaleone,80014,Reggio Calabria,RC,Calabria,18,89036 +Bruzzano Zeffirio,80015,Reggio Calabria,RC,Calabria,18,89030 +Calanna,80016,Reggio Calabria,RC,Calabria,18,89050 +Camini,80017,Reggio Calabria,RC,Calabria,18,89040 +Campo Calabro,80018,Reggio Calabria,RC,Calabria,18,89052 +Candidoni,80019,Reggio Calabria,RC,Calabria,18,89020 +Canolo,80020,Reggio Calabria,RC,Calabria,18,89040 +Caraffa del Bianco,80021,Reggio Calabria,RC,Calabria,18,89030 +Cardeto,80022,Reggio Calabria,RC,Calabria,18,89060 +Careri,80023,Reggio Calabria,RC,Calabria,18,89030 +Casignana,80024,Reggio Calabria,RC,Calabria,18,89030 +Caulonia,80025,Reggio Calabria,RC,Calabria,18,89041 +Ciminà,80026,Reggio Calabria,RC,Calabria,18,89040 +Cinquefrondi,80027,Reggio Calabria,RC,Calabria,18,89021 +Cittanova,80028,Reggio Calabria,RC,Calabria,18,89022 +Condofuri,80029,Reggio Calabria,RC,Calabria,18,89030 +Cosoleto,80030,Reggio Calabria,RC,Calabria,18,89050 +Delianuova,80031,Reggio Calabria,RC,Calabria,18,89012 +Feroleto della Chiesa,80032,Reggio Calabria,RC,Calabria,18,89050 +Ferruzzano,80033,Reggio Calabria,RC,Calabria,18,89030 +Fiumara,80034,Reggio Calabria,RC,Calabria,18,89050 +Galatro,80035,Reggio Calabria,RC,Calabria,18,89054 +Gerace,80036,Reggio Calabria,RC,Calabria,18,89040 +Giffone,80037,Reggio Calabria,RC,Calabria,18,89020 +Gioia Tauro,80038,Reggio Calabria,RC,Calabria,18,89013 +Gioiosa Ionica,80039,Reggio Calabria,RC,Calabria,18,89042 +Grotteria,80040,Reggio Calabria,RC,Calabria,18,89043 +Laganadi,80041,Reggio Calabria,RC,Calabria,18,89050 +Laureana di Borrello,80042,Reggio Calabria,RC,Calabria,18,89023 +Locri,80043,Reggio Calabria,RC,Calabria,18,89044 +Mammola,80044,Reggio Calabria,RC,Calabria,18,89045 +Marina di Gioiosa Ionica,80045,Reggio Calabria,RC,Calabria,18,89046 +Maropati,80046,Reggio Calabria,RC,Calabria,18,89020 +Martone,80047,Reggio Calabria,RC,Calabria,18,89040 +Melicuccà,80048,Reggio Calabria,RC,Calabria,18,89020 +Melicucco,80049,Reggio Calabria,RC,Calabria,18,89020 +Melito di Porto Salvo,80050,Reggio Calabria,RC,Calabria,18,89063 +Molochio,80051,Reggio Calabria,RC,Calabria,18,89010 +Monasterace,80052,Reggio Calabria,RC,Calabria,18,89040 +Montebello Jonico,80053,Reggio Calabria,RC,Calabria,18,89064 +Motta San Giovanni,80054,Reggio Calabria,RC,Calabria,18,89065 +Oppido Mamertina,80055,Reggio Calabria,RC,Calabria,18,89014 +Palizzi,80056,Reggio Calabria,RC,Calabria,18,89038 +Palmi,80057,Reggio Calabria,RC,Calabria,18,89015 +Pazzano,80058,Reggio Calabria,RC,Calabria,18,89040 +Placanica,80059,Reggio Calabria,RC,Calabria,18,89040 +Platì,80060,Reggio Calabria,RC,Calabria,18,89039 +Polistena,80061,Reggio Calabria,RC,Calabria,18,89024 +Portigliola,80062,Reggio Calabria,RC,Calabria,18,89040 +Reggio di Calabria,80063,Reggio Calabria,RC,Calabria,18,89124 +Riace,80064,Reggio Calabria,RC,Calabria,18,89040 +Rizziconi,80065,Reggio Calabria,RC,Calabria,18,89016 +Roccaforte del Greco,80066,Reggio Calabria,RC,Calabria,18,89060 +Roccella Ionica,80067,Reggio Calabria,RC,Calabria,18,89047 +Roghudi,80068,Reggio Calabria,RC,Calabria,18,89060 +Rosarno,80069,Reggio Calabria,RC,Calabria,18,89025 +Samo,80070,Reggio Calabria,RC,Calabria,18,89030 +San Giorgio Morgeto,80071,Reggio Calabria,RC,Calabria,18,89017 +San Giovanni di Gerace,80072,Reggio Calabria,RC,Calabria,18,89040 +San Lorenzo,80073,Reggio Calabria,RC,Calabria,18,89069 +San Luca,80074,Reggio Calabria,RC,Calabria,18,89030 +San Pietro di Caridà,80075,Reggio Calabria,RC,Calabria,18,89020 +San Procopio,80076,Reggio Calabria,RC,Calabria,18,89020 +San Roberto,80077,Reggio Calabria,RC,Calabria,18,89050 +Santa Cristina d'Aspromonte,80078,Reggio Calabria,RC,Calabria,18,89056 +Sant'Agata del Bianco,80079,Reggio Calabria,RC,Calabria,18,89030 +Sant'Alessio in Aspromonte,80080,Reggio Calabria,RC,Calabria,18,89050 +Sant'Eufemia d'Aspromonte,80081,Reggio Calabria,RC,Calabria,18,89027 +Sant'Ilario dello Ionio,80082,Reggio Calabria,RC,Calabria,18,89040 +Santo Stefano in Aspromonte,80083,Reggio Calabria,RC,Calabria,18,89057 +Scido,80084,Reggio Calabria,RC,Calabria,18,89010 +Scilla,80085,Reggio Calabria,RC,Calabria,18,89058 +Seminara,80086,Reggio Calabria,RC,Calabria,18,89028 +Serrata,80087,Reggio Calabria,RC,Calabria,18,89020 +Siderno,80088,Reggio Calabria,RC,Calabria,18,89048 +Sinopoli,80089,Reggio Calabria,RC,Calabria,18,89020 +Staiti,80090,Reggio Calabria,RC,Calabria,18,89030 +Stignano,80091,Reggio Calabria,RC,Calabria,18,89040 +Stilo,80092,Reggio Calabria,RC,Calabria,18,89049 +Taurianova,80093,Reggio Calabria,RC,Calabria,18,89029 +Terranova Sappo Minulio,80094,Reggio Calabria,RC,Calabria,18,89010 +Varapodio,80095,Reggio Calabria,RC,Calabria,18,89010 +Villa San Giovanni,80096,Reggio Calabria,RC,Calabria,18,89018 +San Ferdinando,80097,Reggio Calabria,RC,Calabria,18,89026 +Belvedere di Spinello,101001,Crotone,KR,Calabria,18,88824 +Caccuri,101002,Crotone,KR,Calabria,18,88833 +Carfizzi,101003,Crotone,KR,Calabria,18,88817 +Casabona,101004,Crotone,KR,Calabria,18,88822 +Castelsilano,101005,Crotone,KR,Calabria,18,88834 +Cerenzia,101006,Crotone,KR,Calabria,18,88833 +Cirò,101007,Crotone,KR,Calabria,18,88813 +Cirò Marina,101008,Crotone,KR,Calabria,18,88811 +Cotronei,101009,Crotone,KR,Calabria,18,88836 +Crotone,101010,Crotone,KR,Calabria,18,88900 +Crucoli,101011,Crotone,KR,Calabria,18,88812 +Cutro,101012,Crotone,KR,Calabria,18,88842 +Isola di Capo Rizzuto,101013,Crotone,KR,Calabria,18,88841 +Melissa,101014,Crotone,KR,Calabria,18,88814 +Mesoraca,101015,Crotone,KR,Calabria,18,88838 +Pallagorio,101016,Crotone,KR,Calabria,18,88818 +Petilia Policastro,101017,Crotone,KR,Calabria,18,88837 +Roccabernarda,101018,Crotone,KR,Calabria,18,88835 +Rocca di Neto,101019,Crotone,KR,Calabria,18,88821 +San Mauro Marchesato,101020,Crotone,KR,Calabria,18,88831 +San Nicola dell'Alto,101021,Crotone,KR,Calabria,18,88817 +Santa Severina,101022,Crotone,KR,Calabria,18,88832 +Savelli,101023,Crotone,KR,Calabria,18,88825 +Scandale,101024,Crotone,KR,Calabria,18,88831 +Strongoli,101025,Crotone,KR,Calabria,18,88816 +Umbriatico,101026,Crotone,KR,Calabria,18,88823 +Verzino,101027,Crotone,KR,Calabria,18,88819 +Acquaro,102001,Vibo Valentia,VV,Calabria,18,89832 +Arena,102002,Vibo Valentia,VV,Calabria,18,89832 +Briatico,102003,Vibo Valentia,VV,Calabria,18,89817 +Brognaturo,102004,Vibo Valentia,VV,Calabria,18,89822 +Capistrano,102005,Vibo Valentia,VV,Calabria,18,89818 +Cessaniti,102006,Vibo Valentia,VV,Calabria,18,89816 +Dasà,102007,Vibo Valentia,VV,Calabria,18,89832 +Dinami,102008,Vibo Valentia,VV,Calabria,18,89833 +Drapia,102009,Vibo Valentia,VV,Calabria,18,89862 +Fabrizia,102010,Vibo Valentia,VV,Calabria,18,89823 +Filadelfia,102011,Vibo Valentia,VV,Calabria,18,89814 +Filandari,102012,Vibo Valentia,VV,Calabria,18,89841 +Filogaso,102013,Vibo Valentia,VV,Calabria,18,89843 +Francavilla Angitola,102014,Vibo Valentia,VV,Calabria,18,89815 +Francica,102015,Vibo Valentia,VV,Calabria,18,89851 +Gerocarne,102016,Vibo Valentia,VV,Calabria,18,89831 +Ionadi,102017,Vibo Valentia,VV,Calabria,18,89851 +Joppolo,102018,Vibo Valentia,VV,Calabria,18,89863 +Limbadi,102019,Vibo Valentia,VV,Calabria,18,89844 +Maierato,102020,Vibo Valentia,VV,Calabria,18,89843 +Mileto,102021,Vibo Valentia,VV,Calabria,18,89852 +Mongiana,102022,Vibo Valentia,VV,Calabria,18,89823 +Monterosso Calabro,102023,Vibo Valentia,VV,Calabria,18,89819 +Nardodipace,102024,Vibo Valentia,VV,Calabria,18,89824 +Nicotera,102025,Vibo Valentia,VV,Calabria,18,89844 +Parghelia,102026,Vibo Valentia,VV,Calabria,18,89861 +Pizzo,102027,Vibo Valentia,VV,Calabria,18,89812 +Pizzoni,102028,Vibo Valentia,VV,Calabria,18,89834 +Polia,102029,Vibo Valentia,VV,Calabria,18,89813 +Ricadi,102030,Vibo Valentia,VV,Calabria,18,89866 +Rombiolo,102031,Vibo Valentia,VV,Calabria,18,89841 +San Calogero,102032,Vibo Valentia,VV,Calabria,18,89842 +San Costantino Calabro,102033,Vibo Valentia,VV,Calabria,18,89851 +San Gregorio d'Ippona,102034,Vibo Valentia,VV,Calabria,18,89853 +San Nicola da Crissa,102035,Vibo Valentia,VV,Calabria,18,89821 +Sant'Onofrio,102036,Vibo Valentia,VV,Calabria,18,89843 +Serra San Bruno,102037,Vibo Valentia,VV,Calabria,18,89822 +Simbario,102038,Vibo Valentia,VV,Calabria,18,89822 +Sorianello,102039,Vibo Valentia,VV,Calabria,18,89831 +Soriano Calabro,102040,Vibo Valentia,VV,Calabria,18,89831 +Spadola,102041,Vibo Valentia,VV,Calabria,18,89822 +Spilinga,102042,Vibo Valentia,VV,Calabria,18,89864 +Stefanaconi,102043,Vibo Valentia,VV,Calabria,18,89843 +Tropea,102044,Vibo Valentia,VV,Calabria,18,89861 +Vallelonga,102045,Vibo Valentia,VV,Calabria,18,89821 +Vazzano,102046,Vibo Valentia,VV,Calabria,18,89834 +Vibo Valentia,102047,Vibo Valentia,VV,Calabria,18,89900 +Zaccanopoli,102048,Vibo Valentia,VV,Calabria,18,89867 +Zambrone,102049,Vibo Valentia,VV,Calabria,18,89868 +Zungri,102050,Vibo Valentia,VV,Calabria,18,89867 +Alcamo,81001,Trapani,TP,Sicilia,19,91011 +Buseto Palizzolo,81002,Trapani,TP,Sicilia,19,91012 +Calatafimi-Segesta,81003,Trapani,TP,Sicilia,19,91013 +Campobello di Mazara,81004,Trapani,TP,Sicilia,19,91021 +Castellammare del Golfo,81005,Trapani,TP,Sicilia,19,91014 +Castelvetrano,81006,Trapani,TP,Sicilia,19,91022 +Custonaci,81007,Trapani,TP,Sicilia,19,91015 +Erice,81008,Trapani,TP,Sicilia,19,91016 +Favignana,81009,Trapani,TP,Sicilia,19,91023 +Gibellina,81010,Trapani,TP,Sicilia,19,91024 +Marsala,81011,Trapani,TP,Sicilia,19,91025 +Mazara del Vallo,81012,Trapani,TP,Sicilia,19,91026 +Paceco,81013,Trapani,TP,Sicilia,19,91027 +Pantelleria,81014,Trapani,TP,Sicilia,19,91017 +Partanna,81015,Trapani,TP,Sicilia,19,91028 +Poggioreale,81016,Trapani,TP,Sicilia,19,91020 +Salaparuta,81017,Trapani,TP,Sicilia,19,91020 +Salemi,81018,Trapani,TP,Sicilia,19,91018 +Santa Ninfa,81019,Trapani,TP,Sicilia,19,91029 +San Vito Lo Capo,81020,Trapani,TP,Sicilia,19,91010 +Trapani,81021,Trapani,TP,Sicilia,19,91100 +Valderice,81022,Trapani,TP,Sicilia,19,91019 +Vita,81023,Trapani,TP,Sicilia,19,91010 +Petrosino,81024,Trapani,TP,Sicilia,19,91020 +Misiliscemi,81025,Trapani,TP,Sicilia,19,91031 +Alia,82001,Palermo,PA,Sicilia,19,90021 +Alimena,82002,Palermo,PA,Sicilia,19,90020 +Aliminusa,82003,Palermo,PA,Sicilia,19,90020 +Altavilla Milicia,82004,Palermo,PA,Sicilia,19,90010 +Altofonte,82005,Palermo,PA,Sicilia,19,90030 +Bagheria,82006,Palermo,PA,Sicilia,19,90011 +Balestrate,82007,Palermo,PA,Sicilia,19,90041 +Baucina,82008,Palermo,PA,Sicilia,19,90020 +Belmonte Mezzagno,82009,Palermo,PA,Sicilia,19,90031 +Bisacquino,82010,Palermo,PA,Sicilia,19,90032 +Bolognetta,82011,Palermo,PA,Sicilia,19,90030 +Bompietro,82012,Palermo,PA,Sicilia,19,90020 +Borgetto,82013,Palermo,PA,Sicilia,19,90042 +Caccamo,82014,Palermo,PA,Sicilia,19,90012 +Caltavuturo,82015,Palermo,PA,Sicilia,19,90022 +Campofelice di Fitalia,82016,Palermo,PA,Sicilia,19,90030 +Campofelice di Roccella,82017,Palermo,PA,Sicilia,19,90010 +Campofiorito,82018,Palermo,PA,Sicilia,19,90030 +Camporeale,82019,Palermo,PA,Sicilia,19,90043 +Capaci,82020,Palermo,PA,Sicilia,19,90040 +Carini,82021,Palermo,PA,Sicilia,19,90044 +Castelbuono,82022,Palermo,PA,Sicilia,19,90013 +Casteldaccia,82023,Palermo,PA,Sicilia,19,90014 +Castellana Sicula,82024,Palermo,PA,Sicilia,19,90020 +Castronovo di Sicilia,82025,Palermo,PA,Sicilia,19,90030 +Cefalà Diana,82026,Palermo,PA,Sicilia,19,90030 +Cefalù,82027,Palermo,PA,Sicilia,19,90015 +Cerda,82028,Palermo,PA,Sicilia,19,90010 +Chiusa Sclafani,82029,Palermo,PA,Sicilia,19,90033 +Ciminna,82030,Palermo,PA,Sicilia,19,90023 +Cinisi,82031,Palermo,PA,Sicilia,19,90045 +Collesano,82032,Palermo,PA,Sicilia,19,90016 +Contessa Entellina,82033,Palermo,PA,Sicilia,19,90030 +Corleone,82034,Palermo,PA,Sicilia,19,90034 +Ficarazzi,82035,Palermo,PA,Sicilia,19,90010 +Gangi,82036,Palermo,PA,Sicilia,19,90024 +Geraci Siculo,82037,Palermo,PA,Sicilia,19,90010 +Giardinello,82038,Palermo,PA,Sicilia,19,90040 +Giuliana,82039,Palermo,PA,Sicilia,19,90030 +Godrano,82040,Palermo,PA,Sicilia,19,90030 +Gratteri,82041,Palermo,PA,Sicilia,19,90010 +Isnello,82042,Palermo,PA,Sicilia,19,90010 +Isola delle Femmine,82043,Palermo,PA,Sicilia,19,90040 +Lascari,82044,Palermo,PA,Sicilia,19,90010 +Lercara Friddi,82045,Palermo,PA,Sicilia,19,90025 +Marineo,82046,Palermo,PA,Sicilia,19,90035 +Mezzojuso,82047,Palermo,PA,Sicilia,19,90030 +Misilmeri,82048,Palermo,PA,Sicilia,19,90036 +Monreale,82049,Palermo,PA,Sicilia,19,90046 +Montelepre,82050,Palermo,PA,Sicilia,19,90040 +Montemaggiore Belsito,82051,Palermo,PA,Sicilia,19,90020 +Palazzo Adriano,82052,Palermo,PA,Sicilia,19,90030 +Palermo,82053,Palermo,PA,Sicilia,19,90133 +Partinico,82054,Palermo,PA,Sicilia,19,90047 +Petralia Soprana,82055,Palermo,PA,Sicilia,19,90026 +Petralia Sottana,82056,Palermo,PA,Sicilia,19,90027 +Piana degli Albanesi,82057,Palermo,PA,Sicilia,19,90037 +Polizzi Generosa,82058,Palermo,PA,Sicilia,19,90028 +Pollina,82059,Palermo,PA,Sicilia,19,90010 +Prizzi,82060,Palermo,PA,Sicilia,19,90038 +Roccamena,82061,Palermo,PA,Sicilia,19,90040 +Roccapalumba,82062,Palermo,PA,Sicilia,19,90020 +San Cipirello,82063,Palermo,PA,Sicilia,19,90040 +San Giuseppe Jato,82064,Palermo,PA,Sicilia,19,90048 +San Mauro Castelverde,82065,Palermo,PA,Sicilia,19,90010 +Santa Cristina Gela,82066,Palermo,PA,Sicilia,19,90030 +Santa Flavia,82067,Palermo,PA,Sicilia,19,90017 +Sciara,82068,Palermo,PA,Sicilia,19,90020 +Sclafani Bagni,82069,Palermo,PA,Sicilia,19,90020 +Termini Imerese,82070,Palermo,PA,Sicilia,19,90018 +Terrasini,82071,Palermo,PA,Sicilia,19,90049 +Torretta,82072,Palermo,PA,Sicilia,19,90040 +Trabia,82073,Palermo,PA,Sicilia,19,90019 +Trappeto,82074,Palermo,PA,Sicilia,19,90040 +Ustica,82075,Palermo,PA,Sicilia,19,90010 +Valledolmo,82076,Palermo,PA,Sicilia,19,90029 +Ventimiglia di Sicilia,82077,Palermo,PA,Sicilia,19,90020 +Vicari,82078,Palermo,PA,Sicilia,19,90020 +Villabate,82079,Palermo,PA,Sicilia,19,90039 +Villafrati,82080,Palermo,PA,Sicilia,19,90030 +Scillato,82081,Palermo,PA,Sicilia,19,90020 +Blufi,82082,Palermo,PA,Sicilia,19,90020 +Alcara li Fusi,83001,Messina,ME,Sicilia,19,98070 +Alì,83002,Messina,ME,Sicilia,19,98020 +Alì Terme,83003,Messina,ME,Sicilia,19,98021 +Antillo,83004,Messina,ME,Sicilia,19,98030 +Barcellona Pozzo di Gotto,83005,Messina,ME,Sicilia,19,98051 +Basicò,83006,Messina,ME,Sicilia,19,98060 +Brolo,83007,Messina,ME,Sicilia,19,98061 +Capizzi,83008,Messina,ME,Sicilia,19,98031 +Capo d'Orlando,83009,Messina,ME,Sicilia,19,98071 +Capri Leone,83010,Messina,ME,Sicilia,19,98070 +Caronia,83011,Messina,ME,Sicilia,19,98072 +Casalvecchio Siculo,83012,Messina,ME,Sicilia,19,98032 +Castel di Lucio,83013,Messina,ME,Sicilia,19,98070 +Castell'Umberto,83014,Messina,ME,Sicilia,19,98070 +Castelmola,83015,Messina,ME,Sicilia,19,98030 +Castroreale,83016,Messina,ME,Sicilia,19,98053 +Cesarò,83017,Messina,ME,Sicilia,19,98033 +Condrò,83018,Messina,ME,Sicilia,19,98040 +Falcone,83019,Messina,ME,Sicilia,19,98060 +Ficarra,83020,Messina,ME,Sicilia,19,98062 +Fiumedinisi,83021,Messina,ME,Sicilia,19,98022 +Floresta,83022,Messina,ME,Sicilia,19,98030 +Fondachelli-Fantina,83023,Messina,ME,Sicilia,19,98050 +Forza d'Agrò,83024,Messina,ME,Sicilia,19,98030 +Francavilla di Sicilia,83025,Messina,ME,Sicilia,19,98034 +Frazzanò,83026,Messina,ME,Sicilia,19,98070 +Furci Siculo,83027,Messina,ME,Sicilia,19,98023 +Furnari,83028,Messina,ME,Sicilia,19,98054 +Gaggi,83029,Messina,ME,Sicilia,19,98030 +Galati Mamertino,83030,Messina,ME,Sicilia,19,98070 +Gallodoro,83031,Messina,ME,Sicilia,19,98030 +Giardini-Naxos,83032,Messina,ME,Sicilia,19,98035 +Gioiosa Marea,83033,Messina,ME,Sicilia,19,98063 +Graniti,83034,Messina,ME,Sicilia,19,98036 +Gualtieri Sicaminò,83035,Messina,ME,Sicilia,19,98040 +Itala,83036,Messina,ME,Sicilia,19,98025 +Leni,83037,Messina,ME,Sicilia,19,98050 +Letojanni,83038,Messina,ME,Sicilia,19,98037 +Librizzi,83039,Messina,ME,Sicilia,19,98064 +Limina,83040,Messina,ME,Sicilia,19,98030 +Lipari,83041,Messina,ME,Sicilia,19,98055 +Longi,83042,Messina,ME,Sicilia,19,98070 +Malfa,83043,Messina,ME,Sicilia,19,98050 +Malvagna,83044,Messina,ME,Sicilia,19,98030 +Mandanici,83045,Messina,ME,Sicilia,19,98020 +Mazzarrà Sant'Andrea,83046,Messina,ME,Sicilia,19,98056 +Merì,83047,Messina,ME,Sicilia,19,98040 +Messina,83048,Messina,ME,Sicilia,19,98122 +Milazzo,83049,Messina,ME,Sicilia,19,98057 +Militello Rosmarino,83050,Messina,ME,Sicilia,19,98070 +Mirto,83051,Messina,ME,Sicilia,19,98070 +Mistretta,83052,Messina,ME,Sicilia,19,98073 +Moio Alcantara,83053,Messina,ME,Sicilia,19,98030 +Monforte San Giorgio,83054,Messina,ME,Sicilia,19,98041 +Mongiuffi Melia,83055,Messina,ME,Sicilia,19,98030 +Montagnareale,83056,Messina,ME,Sicilia,19,98060 +Montalbano Elicona,83057,Messina,ME,Sicilia,19,98065 +Motta Camastra,83058,Messina,ME,Sicilia,19,98030 +Motta d'Affermo,83059,Messina,ME,Sicilia,19,98070 +Naso,83060,Messina,ME,Sicilia,19,98074 +Nizza di Sicilia,83061,Messina,ME,Sicilia,19,98026 +Novara di Sicilia,83062,Messina,ME,Sicilia,19,98058 +Oliveri,83063,Messina,ME,Sicilia,19,98060 +Pace del Mela,83064,Messina,ME,Sicilia,19,98042 +Pagliara,83065,Messina,ME,Sicilia,19,98020 +Patti,83066,Messina,ME,Sicilia,19,98066 +Pettineo,83067,Messina,ME,Sicilia,19,98070 +Piraino,83068,Messina,ME,Sicilia,19,98060 +Raccuja,83069,Messina,ME,Sicilia,19,98067 +Reitano,83070,Messina,ME,Sicilia,19,98070 +Roccafiorita,83071,Messina,ME,Sicilia,19,98030 +Roccalumera,83072,Messina,ME,Sicilia,19,98027 +Roccavaldina,83073,Messina,ME,Sicilia,19,98040 +Roccella Valdemone,83074,Messina,ME,Sicilia,19,98030 +Rodì Milici,83075,Messina,ME,Sicilia,19,98059 +Rometta,83076,Messina,ME,Sicilia,19,98043 +San Filippo del Mela,83077,Messina,ME,Sicilia,19,98044 +San Fratello,83078,Messina,ME,Sicilia,19,98075 +San Marco d'Alunzio,83079,Messina,ME,Sicilia,19,98070 +San Pier Niceto,83080,Messina,ME,Sicilia,19,98045 +San Piero Patti,83081,Messina,ME,Sicilia,19,98068 +San Salvatore di Fitalia,83082,Messina,ME,Sicilia,19,98070 +Santa Domenica Vittoria,83083,Messina,ME,Sicilia,19,98030 +Sant'Agata di Militello,83084,Messina,ME,Sicilia,19,98076 +Sant'Alessio Siculo,83085,Messina,ME,Sicilia,19,98030 +Santa Lucia del Mela,83086,Messina,ME,Sicilia,19,98046 +Santa Marina Salina,83087,Messina,ME,Sicilia,19,98050 +Sant'Angelo di Brolo,83088,Messina,ME,Sicilia,19,98060 +Santa Teresa di Riva,83089,Messina,ME,Sicilia,19,98028 +San Teodoro,83090,Messina,ME,Sicilia,19,98030 +Santo Stefano di Camastra,83091,Messina,ME,Sicilia,19,98077 +Saponara,83092,Messina,ME,Sicilia,19,98047 +Savoca,83093,Messina,ME,Sicilia,19,98038 +Scaletta Zanclea,83094,Messina,ME,Sicilia,19,98029 +Sinagra,83095,Messina,ME,Sicilia,19,98069 +Spadafora,83096,Messina,ME,Sicilia,19,98048 +Taormina,83097,Messina,ME,Sicilia,19,98039 +Torregrotta,83098,Messina,ME,Sicilia,19,98040 +Tortorici,83099,Messina,ME,Sicilia,19,98078 +Tripi,83100,Messina,ME,Sicilia,19,98060 +Tusa,83101,Messina,ME,Sicilia,19,98079 +Ucria,83102,Messina,ME,Sicilia,19,98060 +Valdina,83103,Messina,ME,Sicilia,19,98040 +Venetico,83104,Messina,ME,Sicilia,19,98040 +Villafranca Tirrena,83105,Messina,ME,Sicilia,19,98049 +Terme Vigliatore,83106,Messina,ME,Sicilia,19,98050 +Acquedolci,83107,Messina,ME,Sicilia,19,98070 +Torrenova,83108,Messina,ME,Sicilia,19,98070 +Agrigento,84001,Agrigento,AG,Sicilia,19,92100 +Alessandria della Rocca,84002,Agrigento,AG,Sicilia,19,92010 +Aragona,84003,Agrigento,AG,Sicilia,19,92021 +Bivona,84004,Agrigento,AG,Sicilia,19,92010 +Burgio,84005,Agrigento,AG,Sicilia,19,92010 +Calamonaci,84006,Agrigento,AG,Sicilia,19,92010 +Caltabellotta,84007,Agrigento,AG,Sicilia,19,92010 +Camastra,84008,Agrigento,AG,Sicilia,19,92020 +Cammarata,84009,Agrigento,AG,Sicilia,19,92022 +Campobello di Licata,84010,Agrigento,AG,Sicilia,19,92023 +Canicattì,84011,Agrigento,AG,Sicilia,19,92024 +Casteltermini,84012,Agrigento,AG,Sicilia,19,92025 +Castrofilippo,84013,Agrigento,AG,Sicilia,19,92020 +Cattolica Eraclea,84014,Agrigento,AG,Sicilia,19,92011 +Cianciana,84015,Agrigento,AG,Sicilia,19,92012 +Comitini,84016,Agrigento,AG,Sicilia,19,92020 +Favara,84017,Agrigento,AG,Sicilia,19,92026 +Grotte,84018,Agrigento,AG,Sicilia,19,92020 +Joppolo Giancaxio,84019,Agrigento,AG,Sicilia,19,92010 +Lampedusa e Linosa,84020,Agrigento,AG,Sicilia,19,92010 +Licata,84021,Agrigento,AG,Sicilia,19,92027 +Lucca Sicula,84022,Agrigento,AG,Sicilia,19,92010 +Menfi,84023,Agrigento,AG,Sicilia,19,92013 +Montallegro,84024,Agrigento,AG,Sicilia,19,92010 +Montevago,84025,Agrigento,AG,Sicilia,19,92010 +Naro,84026,Agrigento,AG,Sicilia,19,92028 +Palma di Montechiaro,84027,Agrigento,AG,Sicilia,19,92020 +Porto Empedocle,84028,Agrigento,AG,Sicilia,19,92014 +Racalmuto,84029,Agrigento,AG,Sicilia,19,92020 +Raffadali,84030,Agrigento,AG,Sicilia,19,92015 +Ravanusa,84031,Agrigento,AG,Sicilia,19,92029 +Realmonte,84032,Agrigento,AG,Sicilia,19,92010 +Ribera,84033,Agrigento,AG,Sicilia,19,92016 +Sambuca di Sicilia,84034,Agrigento,AG,Sicilia,19,92017 +San Biagio Platani,84035,Agrigento,AG,Sicilia,19,92020 +San Giovanni Gemini,84036,Agrigento,AG,Sicilia,19,92020 +Santa Elisabetta,84037,Agrigento,AG,Sicilia,19,92020 +Santa Margherita di Belice,84038,Agrigento,AG,Sicilia,19,92018 +Sant'Angelo Muxaro,84039,Agrigento,AG,Sicilia,19,92020 +Santo Stefano Quisquina,84040,Agrigento,AG,Sicilia,19,92020 +Sciacca,84041,Agrigento,AG,Sicilia,19,92019 +Siculiana,84042,Agrigento,AG,Sicilia,19,92010 +Villafranca Sicula,84043,Agrigento,AG,Sicilia,19,92020 +Acquaviva Platani,85001,Caltanissetta,CL,Sicilia,19,93010 +Bompensiere,85002,Caltanissetta,CL,Sicilia,19,93010 +Butera,85003,Caltanissetta,CL,Sicilia,19,93011 +Caltanissetta,85004,Caltanissetta,CL,Sicilia,19,93100 +Campofranco,85005,Caltanissetta,CL,Sicilia,19,93010 +Delia,85006,Caltanissetta,CL,Sicilia,19,93010 +Gela,85007,Caltanissetta,CL,Sicilia,19,93012 +Marianopoli,85008,Caltanissetta,CL,Sicilia,19,93010 +Mazzarino,85009,Caltanissetta,CL,Sicilia,19,93013 +Milena,85010,Caltanissetta,CL,Sicilia,19,93010 +Montedoro,85011,Caltanissetta,CL,Sicilia,19,93010 +Mussomeli,85012,Caltanissetta,CL,Sicilia,19,93014 +Niscemi,85013,Caltanissetta,CL,Sicilia,19,93015 +Resuttano,85014,Caltanissetta,CL,Sicilia,19,93010 +Riesi,85015,Caltanissetta,CL,Sicilia,19,93016 +San Cataldo,85016,Caltanissetta,CL,Sicilia,19,93017 +Santa Caterina Villarmosa,85017,Caltanissetta,CL,Sicilia,19,93018 +Serradifalco,85018,Caltanissetta,CL,Sicilia,19,93010 +Sommatino,85019,Caltanissetta,CL,Sicilia,19,93019 +Sutera,85020,Caltanissetta,CL,Sicilia,19,93010 +Vallelunga Pratameno,85021,Caltanissetta,CL,Sicilia,19,93010 +Villalba,85022,Caltanissetta,CL,Sicilia,19,93010 +Agira,86001,Enna,EN,Sicilia,19,94011 +Aidone,86002,Enna,EN,Sicilia,19,94010 +Assoro,86003,Enna,EN,Sicilia,19,94010 +Barrafranca,86004,Enna,EN,Sicilia,19,94012 +Calascibetta,86005,Enna,EN,Sicilia,19,94010 +Catenanuova,86006,Enna,EN,Sicilia,19,94010 +Centuripe,86007,Enna,EN,Sicilia,19,94010 +Cerami,86008,Enna,EN,Sicilia,19,94010 +Enna,86009,Enna,EN,Sicilia,19,94100 +Gagliano Castelferrato,86010,Enna,EN,Sicilia,19,94010 +Leonforte,86011,Enna,EN,Sicilia,19,94013 +Nicosia,86012,Enna,EN,Sicilia,19,94014 +Nissoria,86013,Enna,EN,Sicilia,19,94010 +Piazza Armerina,86014,Enna,EN,Sicilia,19,94015 +Pietraperzia,86015,Enna,EN,Sicilia,19,94016 +Regalbuto,86016,Enna,EN,Sicilia,19,94017 +Sperlinga,86017,Enna,EN,Sicilia,19,94010 +Troina,86018,Enna,EN,Sicilia,19,94018 +Valguarnera Caropepe,86019,Enna,EN,Sicilia,19,94019 +Villarosa,86020,Enna,EN,Sicilia,19,94010 +Aci Bonaccorsi,87001,Catania,CT,Sicilia,19,95020 +Aci Castello,87002,Catania,CT,Sicilia,19,95021 +Aci Catena,87003,Catania,CT,Sicilia,19,95022 +Acireale,87004,Catania,CT,Sicilia,19,95024 +Aci Sant'Antonio,87005,Catania,CT,Sicilia,19,95025 +Adrano,87006,Catania,CT,Sicilia,19,95031 +Belpasso,87007,Catania,CT,Sicilia,19,95032 +Biancavilla,87008,Catania,CT,Sicilia,19,95033 +Bronte,87009,Catania,CT,Sicilia,19,95034 +Calatabiano,87010,Catania,CT,Sicilia,19,95011 +Caltagirone,87011,Catania,CT,Sicilia,19,95041 +Camporotondo Etneo,87012,Catania,CT,Sicilia,19,95040 +Castel di Iudica,87013,Catania,CT,Sicilia,19,95040 +Castiglione di Sicilia,87014,Catania,CT,Sicilia,19,95012 +Catania,87015,Catania,CT,Sicilia,19,95124 +Fiumefreddo di Sicilia,87016,Catania,CT,Sicilia,19,95013 +Giarre,87017,Catania,CT,Sicilia,19,95014 +Grammichele,87018,Catania,CT,Sicilia,19,95042 +Gravina di Catania,87019,Catania,CT,Sicilia,19,95030 +Licodia Eubea,87020,Catania,CT,Sicilia,19,95040 +Linguaglossa,87021,Catania,CT,Sicilia,19,95015 +Maletto,87022,Catania,CT,Sicilia,19,95035 +Mascali,87023,Catania,CT,Sicilia,19,95016 +Mascalucia,87024,Catania,CT,Sicilia,19,95030 +Militello in Val di Catania,87025,Catania,CT,Sicilia,19,95043 +Milo,87026,Catania,CT,Sicilia,19,95010 +Mineo,87027,Catania,CT,Sicilia,19,95044 +Mirabella Imbaccari,87028,Catania,CT,Sicilia,19,95040 +Misterbianco,87029,Catania,CT,Sicilia,19,95045 +Motta Sant'Anastasia,87030,Catania,CT,Sicilia,19,95040 +Nicolosi,87031,Catania,CT,Sicilia,19,95030 +Palagonia,87032,Catania,CT,Sicilia,19,95046 +Paternò,87033,Catania,CT,Sicilia,19,95047 +Pedara,87034,Catania,CT,Sicilia,19,95030 +Piedimonte Etneo,87035,Catania,CT,Sicilia,19,95017 +Raddusa,87036,Catania,CT,Sicilia,19,95040 +Ramacca,87037,Catania,CT,Sicilia,19,95040 +Randazzo,87038,Catania,CT,Sicilia,19,95036 +Riposto,87039,Catania,CT,Sicilia,19,95018 +San Cono,87040,Catania,CT,Sicilia,19,95040 +San Giovanni la Punta,87041,Catania,CT,Sicilia,19,95037 +San Gregorio di Catania,87042,Catania,CT,Sicilia,19,95027 +San Michele di Ganzaria,87043,Catania,CT,Sicilia,19,95040 +San Pietro Clarenza,87044,Catania,CT,Sicilia,19,95030 +Sant'Agata li Battiati,87045,Catania,CT,Sicilia,19,95030 +Sant'Alfio,87046,Catania,CT,Sicilia,19,95010 +Santa Maria di Licodia,87047,Catania,CT,Sicilia,19,95038 +Santa Venerina,87048,Catania,CT,Sicilia,19,95010 +Scordia,87049,Catania,CT,Sicilia,19,95048 +Trecastagni,87050,Catania,CT,Sicilia,19,95039 +Tremestieri Etneo,87051,Catania,CT,Sicilia,19,95030 +Valverde,87052,Catania,CT,Sicilia,19,95028 +Viagrande,87053,Catania,CT,Sicilia,19,95029 +Vizzini,87054,Catania,CT,Sicilia,19,95049 +Zafferana Etnea,87055,Catania,CT,Sicilia,19,95019 +Mazzarrone,87056,Catania,CT,Sicilia,19,95040 +Maniace,87057,Catania,CT,Sicilia,19,95030 +Ragalna,87058,Catania,CT,Sicilia,19,95030 +Acate,88001,Ragusa,RG,Sicilia,19,97011 +Chiaramonte Gulfi,88002,Ragusa,RG,Sicilia,19,97012 +Comiso,88003,Ragusa,RG,Sicilia,19,97013 +Giarratana,88004,Ragusa,RG,Sicilia,19,97010 +Ispica,88005,Ragusa,RG,Sicilia,19,97014 +Modica,88006,Ragusa,RG,Sicilia,19,97015 +Monterosso Almo,88007,Ragusa,RG,Sicilia,19,97010 +Pozzallo,88008,Ragusa,RG,Sicilia,19,97016 +Ragusa,88009,Ragusa,RG,Sicilia,19,97100 +Santa Croce Camerina,88010,Ragusa,RG,Sicilia,19,97017 +Scicli,88011,Ragusa,RG,Sicilia,19,97018 +Vittoria,88012,Ragusa,RG,Sicilia,19,97019 +Augusta,89001,Siracusa,SR,Sicilia,19,96011 +Avola,89002,Siracusa,SR,Sicilia,19,96012 +Buccheri,89003,Siracusa,SR,Sicilia,19,96010 +Buscemi,89004,Siracusa,SR,Sicilia,19,96010 +Canicattini Bagni,89005,Siracusa,SR,Sicilia,19,96010 +Carlentini,89006,Siracusa,SR,Sicilia,19,96013 +Cassaro,89007,Siracusa,SR,Sicilia,19,96010 +Ferla,89008,Siracusa,SR,Sicilia,19,96010 +Floridia,89009,Siracusa,SR,Sicilia,19,96014 +Francofonte,89010,Siracusa,SR,Sicilia,19,96015 +Lentini,89011,Siracusa,SR,Sicilia,19,96016 +Melilli,89012,Siracusa,SR,Sicilia,19,96010 +Noto,89013,Siracusa,SR,Sicilia,19,96017 +Pachino,89014,Siracusa,SR,Sicilia,19,96018 +Palazzolo Acreide,89015,Siracusa,SR,Sicilia,19,96010 +Rosolini,89016,Siracusa,SR,Sicilia,19,96019 +Siracusa,89017,Siracusa,SR,Sicilia,19,96100 +Solarino,89018,Siracusa,SR,Sicilia,19,96010 +Sortino,89019,Siracusa,SR,Sicilia,19,96010 +Portopalo di Capo Passero,89020,Siracusa,SR,Sicilia,19,96010 +Priolo Gargallo,89021,Siracusa,SR,Sicilia,19,96010 +Aggius,90001,Sassari,SS,Sardegna,20,7020 +Alà dei Sardi,90002,Sassari,SS,Sardegna,20,7020 +Alghero,90003,Sassari,SS,Sardegna,20,7041 +Anela,90004,Sassari,SS,Sardegna,20,7010 +Ardara,90005,Sassari,SS,Sardegna,20,7010 +Arzachena,90006,Sassari,SS,Sardegna,20,7021 +Banari,90007,Sassari,SS,Sardegna,20,7040 +Benetutti,90008,Sassari,SS,Sardegna,20,7010 +Berchidda,90009,Sassari,SS,Sardegna,20,7022 +Bessude,90010,Sassari,SS,Sardegna,20,7040 +Bonnanaro,90011,Sassari,SS,Sardegna,20,7043 +Bono,90012,Sassari,SS,Sardegna,20,7011 +Bonorva,90013,Sassari,SS,Sardegna,20,7012 +Bortigiadas,90014,Sassari,SS,Sardegna,20,7030 +Borutta,90015,Sassari,SS,Sardegna,20,7040 +Bottidda,90016,Sassari,SS,Sardegna,20,7010 +Buddusò,90017,Sassari,SS,Sardegna,20,7020 +Bultei,90018,Sassari,SS,Sardegna,20,7010 +Bulzi,90019,Sassari,SS,Sardegna,20,7030 +Burgos,90020,Sassari,SS,Sardegna,20,7010 +Calangianus,90021,Sassari,SS,Sardegna,20,7023 +Cargeghe,90022,Sassari,SS,Sardegna,20,7030 +Castelsardo,90023,Sassari,SS,Sardegna,20,7031 +Cheremule,90024,Sassari,SS,Sardegna,20,7040 +Chiaramonti,90025,Sassari,SS,Sardegna,20,7030 +Codrongianos,90026,Sassari,SS,Sardegna,20,7040 +Cossoine,90027,Sassari,SS,Sardegna,20,7010 +Esporlatu,90028,Sassari,SS,Sardegna,20,7010 +Florinas,90029,Sassari,SS,Sardegna,20,7030 +Giave,90030,Sassari,SS,Sardegna,20,7010 +Illorai,90031,Sassari,SS,Sardegna,20,7010 +Ittireddu,90032,Sassari,SS,Sardegna,20,7010 +Ittiri,90033,Sassari,SS,Sardegna,20,7044 +Laerru,90034,Sassari,SS,Sardegna,20,7030 +La Maddalena,90035,Sassari,SS,Sardegna,20,7024 +Luogosanto,90036,Sassari,SS,Sardegna,20,7020 +Luras,90037,Sassari,SS,Sardegna,20,7025 +Mara,90038,Sassari,SS,Sardegna,20,7010 +Martis,90039,Sassari,SS,Sardegna,20,7030 +Monteleone Rocca Doria,90040,Sassari,SS,Sardegna,20,7010 +Monti,90041,Sassari,SS,Sardegna,20,7020 +Mores,90042,Sassari,SS,Sardegna,20,7013 +Muros,90043,Sassari,SS,Sardegna,20,7030 +Nughedu San Nicolò,90044,Sassari,SS,Sardegna,20,7010 +Nule,90045,Sassari,SS,Sardegna,20,7010 +Nulvi,90046,Sassari,SS,Sardegna,20,7032 +Olbia,90047,Sassari,SS,Sardegna,20,7026 +Olmedo,90048,Sassari,SS,Sardegna,20,7040 +Oschiri,90049,Sassari,SS,Sardegna,20,7027 +Osilo,90050,Sassari,SS,Sardegna,20,7033 +Ossi,90051,Sassari,SS,Sardegna,20,7045 +Ozieri,90052,Sassari,SS,Sardegna,20,7014 +Padria,90053,Sassari,SS,Sardegna,20,7015 +Palau,90054,Sassari,SS,Sardegna,20,7020 +Pattada,90055,Sassari,SS,Sardegna,20,7016 +Perfugas,90056,Sassari,SS,Sardegna,20,7034 +Ploaghe,90057,Sassari,SS,Sardegna,20,7017 +Porto Torres,90058,Sassari,SS,Sardegna,20,7046 +Pozzomaggiore,90059,Sassari,SS,Sardegna,20,7018 +Putifigari,90060,Sassari,SS,Sardegna,20,7040 +Romana,90061,Sassari,SS,Sardegna,20,7010 +Aglientu,90062,Sassari,SS,Sardegna,20,7020 +Santa Teresa Gallura,90063,Sassari,SS,Sardegna,20,7028 +Sassari,90064,Sassari,SS,Sardegna,20,7100 +Sedini,90065,Sassari,SS,Sardegna,20,7035 +Semestene,90066,Sassari,SS,Sardegna,20,7010 +Sennori,90067,Sassari,SS,Sardegna,20,7036 +Siligo,90068,Sassari,SS,Sardegna,20,7040 +Sorso,90069,Sassari,SS,Sardegna,20,7037 +Tempio Pausania,90070,Sassari,SS,Sardegna,20,7029 +Thiesi,90071,Sassari,SS,Sardegna,20,7047 +Tissi,90072,Sassari,SS,Sardegna,20,7040 +Torralba,90073,Sassari,SS,Sardegna,20,7048 +Trinità d'Agultu e Vignola,90074,Sassari,SS,Sardegna,20,7038 +Tula,90075,Sassari,SS,Sardegna,20,7010 +Uri,90076,Sassari,SS,Sardegna,20,7040 +Usini,90077,Sassari,SS,Sardegna,20,7049 +Villanova Monteleone,90078,Sassari,SS,Sardegna,20,7019 +Valledoria,90079,Sassari,SS,Sardegna,20,7039 +Telti,90080,Sassari,SS,Sardegna,20,7020 +Badesi,90081,Sassari,SS,Sardegna,20,7030 +Viddalba,90082,Sassari,SS,Sardegna,20,7030 +Golfo Aranci,90083,Sassari,SS,Sardegna,20,7020 +Loiri Porto San Paolo,90084,Sassari,SS,Sardegna,20,7020 +Sant'Antonio di Gallura,90085,Sassari,SS,Sardegna,20,7030 +Tergu,90086,Sassari,SS,Sardegna,20,7030 +Santa Maria Coghinas,90087,Sassari,SS,Sardegna,20,7030 +Erula,90088,Sassari,SS,Sardegna,20,7030 +Stintino,90089,Sassari,SS,Sardegna,20,7040 +Padru,90090,Sassari,SS,Sardegna,20,7020 +Budoni,90091,Sassari,SS,Sardegna,20,8020 +San Teodoro,90092,Sassari,SS,Sardegna,20,07052 +Aritzo,91001,Nuoro,NU,Sardegna,20,8031 +Arzana,91002,Nuoro,NU,Sardegna,20,8040 +Atzara,91003,Nuoro,NU,Sardegna,20,8030 +Austis,91004,Nuoro,NU,Sardegna,20,8030 +Bari Sardo,91005,Nuoro,NU,Sardegna,20,8042 +Baunei,91006,Nuoro,NU,Sardegna,20,8040 +Belvì,91007,Nuoro,NU,Sardegna,20,8030 +Birori,91008,Nuoro,NU,Sardegna,20,8010 +Bitti,91009,Nuoro,NU,Sardegna,20,8021 +Bolotana,91010,Nuoro,NU,Sardegna,20,8011 +Borore,91011,Nuoro,NU,Sardegna,20,8016 +Bortigali,91012,Nuoro,NU,Sardegna,20,8012 +Desulo,91016,Nuoro,NU,Sardegna,20,8032 +Dorgali,91017,Nuoro,NU,Sardegna,20,8022 +Dualchi,91018,Nuoro,NU,Sardegna,20,8010 +Elini,91019,Nuoro,NU,Sardegna,20,8040 +Fonni,91024,Nuoro,NU,Sardegna,20,8023 +Gadoni,91025,Nuoro,NU,Sardegna,20,8030 +Gairo,91026,Nuoro,NU,Sardegna,20,8040 +Galtellì,91027,Nuoro,NU,Sardegna,20,8020 +Gavoi,91028,Nuoro,NU,Sardegna,20,8020 +Girasole,91031,Nuoro,NU,Sardegna,20,8040 +Ilbono,91032,Nuoro,NU,Sardegna,20,8040 +Irgoli,91033,Nuoro,NU,Sardegna,20,8020 +Jerzu,91035,Nuoro,NU,Sardegna,20,8044 +Lanusei,91037,Nuoro,NU,Sardegna,20,8045 +Lei,91038,Nuoro,NU,Sardegna,20,8010 +Loceri,91039,Nuoro,NU,Sardegna,20,8040 +Loculi,91040,Nuoro,NU,Sardegna,20,8020 +Lodè,91041,Nuoro,NU,Sardegna,20,8020 +Lotzorai,91042,Nuoro,NU,Sardegna,20,8040 +Lula,91043,Nuoro,NU,Sardegna,20,8020 +Macomer,91044,Nuoro,NU,Sardegna,20,8015 +Mamoiada,91046,Nuoro,NU,Sardegna,20,8024 +Meana Sardo,91047,Nuoro,NU,Sardegna,20,8030 +Noragugume,91050,Nuoro,NU,Sardegna,20,8010 +Nuoro,91051,Nuoro,NU,Sardegna,20,8100 +Oliena,91055,Nuoro,NU,Sardegna,20,8025 +Ollolai,91056,Nuoro,NU,Sardegna,20,8020 +Olzai,91057,Nuoro,NU,Sardegna,20,8020 +Onanì,91058,Nuoro,NU,Sardegna,20,8020 +Onifai,91059,Nuoro,NU,Sardegna,20,8020 +Oniferi,91060,Nuoro,NU,Sardegna,20,8020 +Orani,91061,Nuoro,NU,Sardegna,20,8026 +Orgosolo,91062,Nuoro,NU,Sardegna,20,8027 +Orosei,91063,Nuoro,NU,Sardegna,20,8028 +Orotelli,91064,Nuoro,NU,Sardegna,20,8020 +Ortueri,91066,Nuoro,NU,Sardegna,20,8036 +Orune,91067,Nuoro,NU,Sardegna,20,8020 +Osidda,91068,Nuoro,NU,Sardegna,20,8020 +Osini,91069,Nuoro,NU,Sardegna,20,8040 +Ottana,91070,Nuoro,NU,Sardegna,20,8020 +Ovodda,91071,Nuoro,NU,Sardegna,20,8020 +Perdasdefogu,91072,Nuoro,NU,Sardegna,20,8046 +Posada,91073,Nuoro,NU,Sardegna,20,8020 +Sarule,91077,Nuoro,NU,Sardegna,20,8020 +Silanus,91083,Nuoro,NU,Sardegna,20,8017 +Sindia,91084,Nuoro,NU,Sardegna,20,8018 +Siniscola,91085,Nuoro,NU,Sardegna,20,8029 +Sorgono,91086,Nuoro,NU,Sardegna,20,8038 +Talana,91088,Nuoro,NU,Sardegna,20,8040 +Tertenia,91089,Nuoro,NU,Sardegna,20,8047 +Teti,91090,Nuoro,NU,Sardegna,20,8030 +Tiana,91091,Nuoro,NU,Sardegna,20,8020 +Tonara,91093,Nuoro,NU,Sardegna,20,8039 +Torpè,91094,Nuoro,NU,Sardegna,20,8020 +Tortolì,91095,Nuoro,NU,Sardegna,20,8048 +Triei,91097,Nuoro,NU,Sardegna,20,8040 +Ulassai,91098,Nuoro,NU,Sardegna,20,8040 +Urzulei,91099,Nuoro,NU,Sardegna,20,8040 +Ussassai,91100,Nuoro,NU,Sardegna,20,8040 +Villagrande Strisaili,91101,Nuoro,NU,Sardegna,20,8049 +Cardedu,91103,Nuoro,NU,Sardegna,20,8040 +Lodine,91104,Nuoro,NU,Sardegna,20,8020 +Assemini,92003,Cagliari,CA,Sardegna,20,9032 +Cagliari,92009,Cagliari,CA,Sardegna,20,9124 +Capoterra,92011,Cagliari,CA,Sardegna,20,9012 +Decimomannu,92015,Cagliari,CA,Sardegna,20,9033 +Maracalagonis,92037,Cagliari,CA,Sardegna,20,9040 +Pula,92050,Cagliari,CA,Sardegna,20,9010 +Quartu Sant'Elena,92051,Cagliari,CA,Sardegna,20,9045 +Sarroch,92066,Cagliari,CA,Sardegna,20,9018 +Selargius,92068,Cagliari,CA,Sardegna,20,9047 +Sestu,92074,Cagliari,CA,Sardegna,20,9028 +Settimo San Pietro,92075,Cagliari,CA,Sardegna,20,9040 +Sinnai,92080,Cagliari,CA,Sardegna,20,9048 +Uta,92090,Cagliari,CA,Sardegna,20,9010 +Villa San Pietro,92099,Cagliari,CA,Sardegna,20,9010 +Quartucciu,92105,Cagliari,CA,Sardegna,20,9044 +Elmas,92108,Cagliari,CA,Sardegna,20,9030 +Monserrato,92109,Cagliari,CA,Sardegna,20,9042 +Abbasanta,95001,Oristano,OR,Sardegna,20,9071 +Aidomaggiore,95002,Oristano,OR,Sardegna,20,9070 +Albagiara,95003,Oristano,OR,Sardegna,20,9090 +Ales,95004,Oristano,OR,Sardegna,20,9091 +Allai,95005,Oristano,OR,Sardegna,20,9080 +Arborea,95006,Oristano,OR,Sardegna,20,9092 +Ardauli,95007,Oristano,OR,Sardegna,20,9081 +Assolo,95008,Oristano,OR,Sardegna,20,9080 +Asuni,95009,Oristano,OR,Sardegna,20,9080 +Baradili,95010,Oristano,OR,Sardegna,20,9090 +Baratili San Pietro,95011,Oristano,OR,Sardegna,20,9070 +Baressa,95012,Oristano,OR,Sardegna,20,9090 +Bauladu,95013,Oristano,OR,Sardegna,20,9070 +Bidonì,95014,Oristano,OR,Sardegna,20,9080 +Bonarcado,95015,Oristano,OR,Sardegna,20,9070 +Boroneddu,95016,Oristano,OR,Sardegna,20,9080 +Busachi,95017,Oristano,OR,Sardegna,20,9082 +Cabras,95018,Oristano,OR,Sardegna,20,9072 +Cuglieri,95019,Oristano,OR,Sardegna,20,9073 +Fordongianus,95020,Oristano,OR,Sardegna,20,9083 +Ghilarza,95021,Oristano,OR,Sardegna,20,9074 +Gonnoscodina,95022,Oristano,OR,Sardegna,20,9090 +Gonnosnò,95023,Oristano,OR,Sardegna,20,9090 +Gonnostramatza,95024,Oristano,OR,Sardegna,20,9093 +Marrubiu,95025,Oristano,OR,Sardegna,20,9094 +Masullas,95026,Oristano,OR,Sardegna,20,9090 +Milis,95027,Oristano,OR,Sardegna,20,9070 +Mogorella,95028,Oristano,OR,Sardegna,20,9080 +Mogoro,95029,Oristano,OR,Sardegna,20,9095 +Morgongiori,95030,Oristano,OR,Sardegna,20,9090 +Narbolia,95031,Oristano,OR,Sardegna,20,9070 +Neoneli,95032,Oristano,OR,Sardegna,20,9080 +Norbello,95033,Oristano,OR,Sardegna,20,9070 +Nughedu Santa Vittoria,95034,Oristano,OR,Sardegna,20,9080 +Nurachi,95035,Oristano,OR,Sardegna,20,9070 +Nureci,95036,Oristano,OR,Sardegna,20,9080 +Ollastra,95037,Oristano,OR,Sardegna,20,9088 +Oristano,95038,Oristano,OR,Sardegna,20,9170 +Palmas Arborea,95039,Oristano,OR,Sardegna,20,9090 +Pau,95040,Oristano,OR,Sardegna,20,9090 +Paulilatino,95041,Oristano,OR,Sardegna,20,9070 +Pompu,95042,Oristano,OR,Sardegna,20,9093 +Riola Sardo,95043,Oristano,OR,Sardegna,20,9070 +Ruinas,95044,Oristano,OR,Sardegna,20,9085 +Samugheo,95045,Oristano,OR,Sardegna,20,9086 +San Nicolò d'Arcidano,95046,Oristano,OR,Sardegna,20,9097 +Santa Giusta,95047,Oristano,OR,Sardegna,20,9096 +Villa Sant'Antonio,95048,Oristano,OR,Sardegna,20,9080 +Santu Lussurgiu,95049,Oristano,OR,Sardegna,20,9075 +San Vero Milis,95050,Oristano,OR,Sardegna,20,9070 +Scano di Montiferro,95051,Oristano,OR,Sardegna,20,9078 +Sedilo,95052,Oristano,OR,Sardegna,20,9076 +Seneghe,95053,Oristano,OR,Sardegna,20,9070 +Senis,95054,Oristano,OR,Sardegna,20,9080 +Sennariolo,95055,Oristano,OR,Sardegna,20,9078 +Siamaggiore,95056,Oristano,OR,Sardegna,20,9070 +Siamanna,95057,Oristano,OR,Sardegna,20,9080 +Simala,95058,Oristano,OR,Sardegna,20,9090 +Simaxis,95059,Oristano,OR,Sardegna,20,9088 +Sini,95060,Oristano,OR,Sardegna,20,9090 +Siris,95061,Oristano,OR,Sardegna,20,9090 +Solarussa,95062,Oristano,OR,Sardegna,20,9077 +Sorradile,95063,Oristano,OR,Sardegna,20,9080 +Tadasuni,95064,Oristano,OR,Sardegna,20,9080 +Terralba,95065,Oristano,OR,Sardegna,20,9098 +Tramatza,95066,Oristano,OR,Sardegna,20,9070 +Tresnuraghes,95067,Oristano,OR,Sardegna,20,9079 +Ulà Tirso,95068,Oristano,OR,Sardegna,20,9080 +Uras,95069,Oristano,OR,Sardegna,20,9099 +Usellus,95070,Oristano,OR,Sardegna,20,9090 +Villanova Truschedu,95071,Oristano,OR,Sardegna,20,9084 +Villaurbana,95072,Oristano,OR,Sardegna,20,9080 +Villa Verde,95073,Oristano,OR,Sardegna,20,9090 +Zeddiani,95074,Oristano,OR,Sardegna,20,9070 +Zerfaliu,95075,Oristano,OR,Sardegna,20,9070 +Siapiccia,95076,Oristano,OR,Sardegna,20,9080 +Curcuris,95077,Oristano,OR,Sardegna,20,9090 +Soddì,95078,Oristano,OR,Sardegna,20,9080 +Bosa,95079,Oristano,OR,Sardegna,20,8013 +Flussio,95080,Oristano,OR,Sardegna,20,8010 +Laconi,95082,Oristano,OR,Sardegna,20,8034 +Magomadas,95083,Oristano,OR,Sardegna,20,8010 +Modolo,95084,Oristano,OR,Sardegna,20,8019 +Montresta,95085,Oristano,OR,Sardegna,20,8010 +Sagama,95086,Oristano,OR,Sardegna,20,8010 +Suni,95087,Oristano,OR,Sardegna,20,8010 +Tinnura,95088,Oristano,OR,Sardegna,20,8010 +Arbus,111001,Sud Sardegna,SU,Sardegna,20,9031 +Armungia,111002,Sud Sardegna,SU,Sardegna,20,9040 +Ballao,111003,Sud Sardegna,SU,Sardegna,20,9040 +Barrali,111004,Sud Sardegna,SU,Sardegna,20,9040 +Barumini,111005,Sud Sardegna,SU,Sardegna,20,9021 +Buggerru,111006,Sud Sardegna,SU,Sardegna,20,9010 +Burcei,111007,Sud Sardegna,SU,Sardegna,20,9040 +Calasetta,111008,Sud Sardegna,SU,Sardegna,20,9011 +Carbonia,111009,Sud Sardegna,SU,Sardegna,20,9013 +Carloforte,111010,Sud Sardegna,SU,Sardegna,20,9014 +Castiadas,111011,Sud Sardegna,SU,Sardegna,20,9040 +Collinas,111012,Sud Sardegna,SU,Sardegna,20,9020 +Decimoputzu,111013,Sud Sardegna,SU,Sardegna,20,9010 +Dolianova,111014,Sud Sardegna,SU,Sardegna,20,9041 +Domus de Maria,111015,Sud Sardegna,SU,Sardegna,20,9010 +Domusnovas,111016,Sud Sardegna,SU,Sardegna,20,9015 +Donori,111017,Sud Sardegna,SU,Sardegna,20,9040 +Escalaplano,111018,Sud Sardegna,SU,Sardegna,20,8043 +Escolca,111019,Sud Sardegna,SU,Sardegna,20,8030 +Esterzili,111020,Sud Sardegna,SU,Sardegna,20,8030 +Fluminimaggiore,111021,Sud Sardegna,SU,Sardegna,20,9010 +Furtei,111022,Sud Sardegna,SU,Sardegna,20,9040 +Genoni,111023,Sud Sardegna,SU,Sardegna,20,8030 +Genuri,111024,Sud Sardegna,SU,Sardegna,20,9020 +Gergei,111025,Sud Sardegna,SU,Sardegna,20,8030 +Gesico,111026,Sud Sardegna,SU,Sardegna,20,9040 +Gesturi,111027,Sud Sardegna,SU,Sardegna,20,9020 +Giba,111028,Sud Sardegna,SU,Sardegna,20,9010 +Goni,111029,Sud Sardegna,SU,Sardegna,20,9040 +Gonnesa,111030,Sud Sardegna,SU,Sardegna,20,9010 +Gonnosfanadiga,111031,Sud Sardegna,SU,Sardegna,20,9035 +Guamaggiore,111032,Sud Sardegna,SU,Sardegna,20,9040 +Guasila,111033,Sud Sardegna,SU,Sardegna,20,9040 +Guspini,111034,Sud Sardegna,SU,Sardegna,20,9036 +Iglesias,111035,Sud Sardegna,SU,Sardegna,20,9016 +Isili,111036,Sud Sardegna,SU,Sardegna,20,8033 +Las Plassas,111037,Sud Sardegna,SU,Sardegna,20,9020 +Lunamatrona,111038,Sud Sardegna,SU,Sardegna,20,9022 +Mandas,111039,Sud Sardegna,SU,Sardegna,20,9040 +Masainas,111040,Sud Sardegna,SU,Sardegna,20,9010 +Monastir,111041,Sud Sardegna,SU,Sardegna,20,9023 +Muravera,111042,Sud Sardegna,SU,Sardegna,20,9043 +Musei,111043,Sud Sardegna,SU,Sardegna,20,9010 +Narcao,111044,Sud Sardegna,SU,Sardegna,20,9010 +Nuragus,111045,Sud Sardegna,SU,Sardegna,20,8030 +Nurallao,111046,Sud Sardegna,SU,Sardegna,20,8030 +Nuraminis,111047,Sud Sardegna,SU,Sardegna,20,9024 +Nurri,111048,Sud Sardegna,SU,Sardegna,20,8035 +Nuxis,111049,Sud Sardegna,SU,Sardegna,20,9010 +Orroli,111050,Sud Sardegna,SU,Sardegna,20,8030 +Ortacesus,111051,Sud Sardegna,SU,Sardegna,20,9040 +Pabillonis,111052,Sud Sardegna,SU,Sardegna,20,9030 +Pauli Arbarei,111053,Sud Sardegna,SU,Sardegna,20,9020 +Perdaxius,111054,Sud Sardegna,SU,Sardegna,20,9010 +Pimentel,111055,Sud Sardegna,SU,Sardegna,20,9020 +Piscinas,111056,Sud Sardegna,SU,Sardegna,20,9010 +Portoscuso,111057,Sud Sardegna,SU,Sardegna,20,9010 +Sadali,111058,Sud Sardegna,SU,Sardegna,20,8030 +Samassi,111059,Sud Sardegna,SU,Sardegna,20,9030 +Samatzai,111060,Sud Sardegna,SU,Sardegna,20,9020 +San Basilio,111061,Sud Sardegna,SU,Sardegna,20,9040 +San Gavino Monreale,111062,Sud Sardegna,SU,Sardegna,20,9037 +San Giovanni Suergiu,111063,Sud Sardegna,SU,Sardegna,20,9010 +San Nicolò Gerrei,111064,Sud Sardegna,SU,Sardegna,20,9040 +San Sperate,111065,Sud Sardegna,SU,Sardegna,20,9026 +San Vito,111066,Sud Sardegna,SU,Sardegna,20,9040 +Sanluri,111067,Sud Sardegna,SU,Sardegna,20,9025 +Santadi,111068,Sud Sardegna,SU,Sardegna,20,9010 +Sant'Andrea Frius,111069,Sud Sardegna,SU,Sardegna,20,9040 +Sant'Anna Arresi,111070,Sud Sardegna,SU,Sardegna,20,9010 +Sant'Antioco,111071,Sud Sardegna,SU,Sardegna,20,9017 +Sardara,111072,Sud Sardegna,SU,Sardegna,20,9030 +Segariu,111073,Sud Sardegna,SU,Sardegna,20,9040 +Selegas,111074,Sud Sardegna,SU,Sardegna,20,9040 +Senorbì,111075,Sud Sardegna,SU,Sardegna,20,9040 +Serdiana,111076,Sud Sardegna,SU,Sardegna,20,9040 +Serramanna,111077,Sud Sardegna,SU,Sardegna,20,9038 +Serrenti,111078,Sud Sardegna,SU,Sardegna,20,9027 +Serri,111079,Sud Sardegna,SU,Sardegna,20,8030 +Setzu,111080,Sud Sardegna,SU,Sardegna,20,9029 +Seui,111081,Sud Sardegna,SU,Sardegna,20,8037 +Seulo,111082,Sud Sardegna,SU,Sardegna,20,8030 +Siddi,111083,Sud Sardegna,SU,Sardegna,20,9020 +Siliqua,111084,Sud Sardegna,SU,Sardegna,20,9010 +Silius,111085,Sud Sardegna,SU,Sardegna,20,9040 +Siurgus Donigala,111086,Sud Sardegna,SU,Sardegna,20,9040 +Soleminis,111087,Sud Sardegna,SU,Sardegna,20,9040 +Suelli,111088,Sud Sardegna,SU,Sardegna,20,9040 +Teulada,111089,Sud Sardegna,SU,Sardegna,20,9019 +Tratalias,111090,Sud Sardegna,SU,Sardegna,20,9010 +Tuili,111091,Sud Sardegna,SU,Sardegna,20,9029 +Turri,111092,Sud Sardegna,SU,Sardegna,20,9020 +Ussana,111093,Sud Sardegna,SU,Sardegna,20,9020 +Ussaramanna,111094,Sud Sardegna,SU,Sardegna,20,9020 +Vallermosa,111095,Sud Sardegna,SU,Sardegna,20,9010 +Villacidro,111096,Sud Sardegna,SU,Sardegna,20,9039 +Villamar,111097,Sud Sardegna,SU,Sardegna,20,9020 +Villamassargia,111098,Sud Sardegna,SU,Sardegna,20,9010 +Villanova Tulo,111099,Sud Sardegna,SU,Sardegna,20,8030 +Villanovaforru,111100,Sud Sardegna,SU,Sardegna,20,9020 +Villanovafranca,111101,Sud Sardegna,SU,Sardegna,20,9020 +Villaperuccio,111102,Sud Sardegna,SU,Sardegna,20,9010 +Villaputzu,111103,Sud Sardegna,SU,Sardegna,20,9040 +Villasalto,111104,Sud Sardegna,SU,Sardegna,20,9040 +Villasimius,111105,Sud Sardegna,SU,Sardegna,20,9049 +Villasor,111106,Sud Sardegna,SU,Sardegna,20,9034 +Villaspeciosa,111107,Sud Sardegna,SU,Sardegna,20,9010 diff --git a/edera-api/api/src/main/resources/csv/nations.csv b/edera-api/api/src/main/resources/csv/nations.csv new file mode 100644 index 0000000..6623e1b --- /dev/null +++ b/edera-api/api/src/main/resources/csv/nations.csv @@ -0,0 +1,233 @@ +code;description +AD;ANDORRA +AE;EMIRATI ARABI UNITI +AG;ANTIGUA/BARBUDA +AI;ANGUILLA +AL;ALBANIA +AM;ARMENIA +AN;ANTILLE OLANDESI +AO;ANGOLA +AR;ARGENTINA +AS;SAMOA (USA) +AT;AUSTRIA +AU;AUSTRALIA +AW;ARUBA +AZ;AZERBAIGIAN +BA;BOSNIA-ERZEGOVINA +BB;BARBADOS +BD;BANGLADESH +BE;BELGIO +BF;BURKINA FASO +BG;BULGARIA +BH;BAHREIN +BI;BURUNDI +BJ;BENIN +BM;BERMUDE +BN;BRUNEI +BO;BOLIVIA +BR;BRASILE +BS;BAHAMA +BT;BHUTAN +BW;BOTSWANA +BY;BIELORUSSIA +BZ;BELIZE +CA;CANADA +CC;ISOLE COCOS +CD;REP. DEMOCRATICA CO +CF;CENTRAFRICA +CG;REPUBBLICA DEL CONG +CH;SVIZZERA +CI;COSTA D'AVORIO +CK;ARCIPELAGO DI COOK +CL;CILE +CM;CAMERUN +CN;CINA +CO;COLOMBIA +CR;COSTA RICA +CU;CUBA +CV;CIPRO +CX;ISOLE CHRISTMAS +CY;CIPRO +CZ;REPUBBLICA CECA +DE;GERMANIA +DJ;GIBUTI +DK;DANIMARCA +DM;DOMINICA +DO;REPUBBLICA DOMINICA +DZ;ALGERIA +EC;ECUADOR +EE;ESTONIA +EG;EGITTO +ER;ERITREA +ES;SPAGNA +ET;ETIOPIA +FI;FINLANDIA +FJ;ISOLE FIGI +FK;ISOLE FALKLAND +FO;ISOLE FAEROER +FR;FRANCIA +GA;GABON +GB;GRAN BRETAGNA +GD;GRENADA +GE;GEORGIA +GF;GUIANA FRANCESE +GH;GHANA +GI;GIBILTERRA +GL;GROENLANDIA +GM;GAMBIA +GN;REPUBBLICA DI GUINE +GP;GUADALUPA +GQ;GUINEA EQUATORIALE +GR;GRECIA +GS;GEORGIA DEL SUD E S +GT;GUATEMALA +GU;GUAM +GW;GUINEA-BISSAU +GY;GUIANA +HK;HONG KONG +HN;HONDURAS +HR;CROAZIA +HT;HAITI +HU;UNGHERIA +ID;INDONESIA +IE;IRLANDA +IL;ISRAELE +IN;INDIA +IQ;IRAQ +IR;IRAN +IS;ISLANDA +IT;ITALIA +JM;GIAMAICA +JO;GIORDANIA +JP;GIAPPONE +KE;KENYA +KG;KIRGHIZISTAN +KH;CAMBOGIA +KI;KIRIBATI +KM;COMORE +KN;SAN CRISTOFORO E NE +KP;COREA DEL NORD +KR;COREA DEL SUD +KW;KUWAIT +KY;CAYMAN +KZ;KAZAKISTAN +LA;LAOS +LB;LIBANO +LC;SANTA LUCIA +LI;LIECHTENSTEIN +LK;SRI LANKA +LR;LIBERIA +LS;LESOTHO +LT;LITUANIA +LU;LUSSEMBURGO +LV;LETTONIA +LY;LIBIA +MA;MAROCCO +MC;MONTECARLO +MD;MOLDAVIA +MG;MADAGASCAR +MH;ISOLE MARSHALL +MK;MACEDONIA +ML;MALI +MM;MYANMAR (UNIONE) +MN;MONGOLIA +MO;MACAO +MP;ISOLE MARIANNE +MQ;MARTINICA +MR;MAURITANIA +MS;MONTSERRAT +MT;MALTA +MU;MAURIZIO +MV;MALDIVE +MW;MALAWI +MX;MESSICO +MY;MALAISIA +MZ;MOZAMBICO +NA;NAMIBIA +NC;NUOVA CALEDONIA +NE;NIGER +NF;ISOLA DI NORFOLK +NG;NIGERIA +NI;NICARAGUA +NL;OLANDA +NO;NORVEGIA +NP;NEPAL +NR;NAURU +NZ;NUOVA ZELANDA +OM;OMAN +PA;PANAMA +PE;PERU' +PF;POLINESIA FRANCESE +PG;PAPUA-NUOVA GUINEA +PH;FILIPPINE +PK;PAKISTAN +PL;POLONIA +PM;SAINT-PIERRE ET MIQ +PN;PITCAIRN +PR;PORTORICO +PT;PORTOGALLO +PW;ISOLE PALAU +PY;PARAGUAY +QA;QATAR +RE;REUNION +RO;ROMANIA +RU;RUSSIA +RW;RUANDA +SA;ARABIA SAUDITA +SB;ISOLE SALOMONE +SC;SEYCHELLES +SD;SUDAN +SE;SVEZIA +SG;SINGAPORE +SH;ASCENSION +SI;SLOVENIA +SK;REPUBBLICA SLOVACCA +SL;SIERRA LEONE +SM;SAN MARINO +SN;SENEGAL +SO;SOMALIA +SR;SURINAME +ST;SAO TOME' E PRINCIP +SU;UNIONE SOVIETICA +SV;SALVADOR +SY;SIRIA +SZ;SWAZILAND +TC;TURKS E CAICOS +TD;CIAD +TF;ANTARTIDE FRANCESE +TG;TOGO +TH;TAILANDIA +TJ;TAGISKISTAN +TK;ISOLE TOKELAU +TM;TURKMENISTAN +TN;TUNISIA +TO;TONGA +TP;TIMOR ORIENTALE +TR;TURCHIA +TT;TRINIDAD E TOBAGO +TV;TUVALU +TW;TAIWAN +TZ;TANZANIA +UA;UCRAINA +UG;UGANDA +UM;ISOLE MINORI (USA) +US;STATI UNITI D'AMERI +UY;URUGUAY +UZ;UZBEKISTAN +VA;CITTA' DEL VATICANO +VC;SAINT VINCENT E GRE +VE;VENEZUELA +VG;ISOLE VERGINI (BRIT +VI;ISOLE VERGINI (USA) +VN;VIETNAM +VU;VANUATU +WF;WALLIS E FUTUNA +WS;SAMOA OCCIDENTALI +XZ;KOSOVO +YE;YEMEN +YT;MAYOTTE +YU;SERBIA E MONTENEGRO +ZA;SUD AFRICA +ZM;ZAMBIA +ZR;ZAIRE +ZW;ZIMBABWE diff --git a/edera-api/api/src/main/resources/csv/provinces.csv b/edera-api/api/src/main/resources/csv/provinces.csv new file mode 100644 index 0000000..9b6b3ae --- /dev/null +++ b/edera-api/api/src/main/resources/csv/provinces.csv @@ -0,0 +1,112 @@ +name;region;code;nationCode +Agrigento;Sicilia;AG;IT +Alessandria;Piemonte;AL;IT +Ancona;Marche;AN;IT +Aosta;Valle d'Aosta;AO;IT +Arezzo;Toscana;AR;IT +Ascoli Piceno;Marche;AP;IT +Asti;Piemonte;AT;IT +Avellino;Campania;AV;IT +Bari;Puglia;BA;IT +Barletta-Andria-Trani;Puglia;BT;IT +Belluno;Veneto;BL;IT +Benevento;Campania;BN;IT +Bergamo;Lombardia;BG;IT +Biella;Piemonte;BI;IT +Bologna;Emilia Romagna;BO;IT +Bolzano;Trentino-Alto Adige;BZ;IT +Brescia;Lombardia;BS;IT +Brindisi;Puglia;BR;IT +Cagliari;Sardegna;CA;IT +Caltanissetta;Sicilia;CL;IT +Campobasso;Molise;CB;IT +Carbonia-Iglesias;Sardegna;CI;IT +Caserta;Campania;CE;IT +Catania;Sicilia;CT;IT +Catanzaro;Calabria;CZ;IT +Chieti;Abruzzo;CH;IT +Como;Lombardia;CO;IT +Cosenza;Calabria;CS;IT +Cremona;Lombardia;CR;IT +Crotone;Calabria;KR;IT +Cuneo;Piemonte;CN;IT +Enna;Sicilia;EN;IT +Fermo;Marche;FM;IT +Ferrara;Emilia Romagna;FE;IT +Firenze;Toscana;FI;IT +Foggia;Puglia;FG;IT +Forl�-Cesena;Emilia Romagna;FC;IT +Frosinone;Lazio;FR;IT +Genova;Liguria;GE;IT +Gorizia;Friuli-Venezia Giulia;GO;IT +Grosseto;Toscana;GR;IT +Imperia;Liguria;IM;IT +Isernia;Molise;IS;IT +La Spezia;Liguria;SP;IT +L'Aquila;Abruzzo;AQ;IT +Latina;Lazio;LT;IT +Lecce;Puglia;LE;IT +Lecco;Lombardia;LC;IT +Livorno;Toscana;LI;IT +Lodi;Lombardia;LO;IT +Lucca;Toscana;LU;IT +Macerata;Marche;MC;IT +Mantova;Lombardia;MN;IT +Massa-Carrara;Toscana;MS;IT +Matera;Basilicata;MT;IT +Messina;Sicilia;ME;IT +Milano;Lombardia;MI;IT +Modena;Emilia Romagna;MO;IT +Monza e della Brianza;Lombardia;MB;IT +Napoli;Campania;NA;IT +Novara;Piemonte;NO;IT +Nuoro;Sardegna;NU;IT +Olbia-Tempio;Sardegna;OT;IT +Oristano;Sardegna;OR;IT +Padova;Veneto;PD;IT +Palermo;Sicilia;PA;IT +Parma;Emilia Romagna;PR;IT +Pavia;Lombardia;PV;IT +Perugia;Umbria;PG;IT +Pesaro e Urbino;Marche;PU;IT +Pescara;Abruzzo;PE;IT +Piacenza;Emilia Romagna;PC;IT +Pisa;Toscana;PI;IT +Pistoia;Toscana;PT;IT +Pordenone;Friuli-Venezia Giulia;PN;IT +Potenza;Basilicata;PZ;IT +Prato;Toscana;PO;IT +Ragusa;Sicilia;RG;IT +Ravenna;Emilia Romagna;RA;IT +Reggio Calabria;Calabria;RC;IT +Reggio Emilia;Emilia Romagna;RE;IT +Rieti;Lazio;RI;IT +Rimini;Emilia Romagna;RN;IT +Roma;Lazio;RM;IT +Rovigo;Veneto;RO;IT +Salerno;Campania;SA;IT +Medio Campidano;Sardegna;VS;IT +Sassari;Sardegna;SS;IT +Savona;Liguria;SV;IT +Siena;Toscana;SI;IT +Siracusa;Sicilia;SR;IT +Sondrio;Lombardia;SO;IT +Taranto;Puglia;TA;IT +Teramo;Abruzzo;TE;IT +Terni;Umbria;TR;IT +Torino;Piemonte;TO;IT +Ogliastra;Sardegna;OG;IT +Trapani;Sicilia;TP;IT +Trento;Trentino-Alto Adige;TN;IT +Treviso;Veneto;TV;IT +Trieste;Friuli-Venezia Giulia;TS;IT +Udine;Friuli-Venezia Giulia;UD;IT +Varese;Lombardia;VA;IT +Venezia;Veneto;VE;IT +Verbano-Cusio-Ossola;Piemonte;VB;IT +Vercelli;Piemonte;VC;IT +Verona;Veneto;VR;IT +Vibo Valentia;Calabria;VV;IT +Vicenza;Veneto;VI;IT +Viterbo;Lazio;VT;IT +Sud Sardegna;Sardegna;SU;IT \ No newline at end of file diff --git a/edera-api/api/src/main/resources/csv/regions.csv b/edera-api/api/src/main/resources/csv/regions.csv new file mode 100644 index 0000000..3d71b6c --- /dev/null +++ b/edera-api/api/src/main/resources/csv/regions.csv @@ -0,0 +1,21 @@ +code;description;nationCode; +1;Abruzzo;IT; +2;Basilicata;IT; +3;Calabria;IT; +4;Campania;IT; +5;Emilia Romagna;IT; +6;Friuli-Venezia Giulia;IT; +7;Lazio;IT; +8;Liguria;IT; +9;Lombardia;IT; +10;Marche;IT; +11;Molise;IT; +12;Piemonte;IT; +13;Puglia;IT; +14;Sardegna;IT; +15;Sicilia;IT; +16;Toscana;IT; +17;Trentino-Alto Adige;IT; +18;Umbria;IT; +19;Valle d'Aosta;IT; +20;Veneto;IT; \ No newline at end of file diff --git a/edera-api/api/src/main/resources/docx/helper.docx b/edera-api/api/src/main/resources/docx/helper.docx new file mode 100644 index 0000000000000000000000000000000000000000..1bc4b5e2712ac201e0d63f786c5df9f2273f8084 GIT binary patch literal 5227 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 del fornitore %{supplier} con tag RFID associato %{location}" +}, { + "id" : "it.resources.entities/activity.name", + "code" : "resources.entities/activity.name", + "lang" : "it", + "text" : "Attività" +}, { + "id" : "it.resources.entities/activity.title", + "code" : "resources.entities/activity.title", + "lang" : "it", + "text" : "Attività:" +}, { + "id" : "it.resources.entities/audit-log.fields.created", + "code" : "resources.entities/audit-log.fields.created", + "lang" : "it", + "text" : "Data e ora" +}, { + "id" : "it.resources.entities/audit-log.fields.from", + "code" : "resources.entities/audit-log.fields.from", + "lang" : "it", + "text" : "Dalla data" +}, { + "id" : "it.resources.entities/audit-log.fields.message", + "code" : "resources.entities/audit-log.fields.message", + "lang" : "it", + "text" : "Messaggio" +}, { + "id" : "it.resources.entities/audit-log.fields.to", + "code" : "resources.entities/audit-log.fields.to", + "lang" : "it", + "text" : "Alla data" +}, { + "id" : "it.resources.entities/audit-log.fields.userId", + "code" : "resources.entities/audit-log.fields.userId", + "lang" : "it", + "text" : "Utente" +}, { + "id" : "it.resources.entities/customer-area.fields.description", + "code" : "resources.entities/customer-area.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/customer-area.fields.name", + "code" : "resources.entities/customer-area.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/customer-area.fields.office.address", + "code" : "resources.entities/customer-area.fields.office.address", + "lang" : "it", + "text" : "Indirizzo" +}, { + "id" : "it.resources.entities/customer-area.fields.office.cityId", + "code" : "resources.entities/customer-area.fields.office.cityId", + "lang" : "it", + "text" : "Città" +}, { + "id" : "it.resources.entities/customer-area.fields.officeId", + "code" : "resources.entities/customer-area.fields.officeId", + "lang" : "it", + "text" : "Ufficio" +}, { + "id" : "it.resources.entities/customer-area.fields.rfidDeviceId", + "code" : "resources.entities/customer-area.fields.rfidDeviceId", + "lang" : "it", + "text" : "Dispositivo RFID" +}, { + "id" : "it.resources.entities/customer-area.fields.updated", + "code" : "resources.entities/customer-area.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/customer-area.name", + "code" : "resources.entities/customer-area.name", + "lang" : "it", + "text" : "Area |||| Aree" +}, { + "id" : "it.resources.entities/customer-area.title.create", + "code" : "resources.entities/customer-area.title.create", + "lang" : "it", + "text" : "Nuova Area" +}, { + "id" : "it.resources.entities/customer-area.title.edit", + "code" : "resources.entities/customer-area.title.edit", + "lang" : "it", + "text" : "Modifica Area" +}, { + "id" : "it.resources.entities/customer-office.fields.address", + "code" : "resources.entities/customer-office.fields.address", + "lang" : "it", + "text" : "Indirizzo" +}, { + "id" : "it.resources.entities/customer-office.fields.city.name", + "code" : "resources.entities/customer-office.fields.city.name", + "lang" : "it", + "text" : "Città" +}, { + "id" : "it.resources.entities/customer-office.fields.cityId", + "code" : "resources.entities/customer-office.fields.cityId", + "lang" : "it", + "text" : "Città" +}, { + "id" : "it.resources.entities/customer-office.fields.headquarter", + "code" : "resources.entities/customer-office.fields.headquarter", + "lang" : "it", + "text" : "Sede Legale" +}, { + "id" : "it.resources.entities/customer-office.fields.nation.name", + "code" : "resources.entities/customer-office.fields.nation.name", + "lang" : "it", + "text" : "Nazione" +}, { + "id" : "it.resources.entities/customer-office.fields.nationId", + "code" : "resources.entities/customer-office.fields.nationId", + "lang" : "it", + "text" : "Nazione" +}, { + "id" : "it.resources.entities/customer-office.fields.province.name", + "code" : "resources.entities/customer-office.fields.province.name", + "lang" : "it", + "text" : "Provincia" +}, { + "id" : "it.resources.entities/customer-office.fields.provinceId", + "code" : "resources.entities/customer-office.fields.provinceId", + "lang" : "it", + "text" : "Provincia" +}, { + "id" : "it.resources.entities/customer-office.fields.region.name", + "code" : "resources.entities/customer-office.fields.region.name", + "lang" : "it", + "text" : "Regione" +}, { + "id" : "it.resources.entities/customer-office.fields.regionId", + "code" : "resources.entities/customer-office.fields.regionId", + "lang" : "it", + "text" : "Regione" +}, { + "id" : "it.resources.entities/customer-office.fields.updated", + "code" : "resources.entities/customer-office.fields.updated", + "lang" : "it", + "text" : "Ultima Modifica" +}, { + "id" : "it.resources.entities/customer-office.name", + "code" : "resources.entities/customer-office.name", + "lang" : "it", + "text" : "Sede |||| Sedi" +}, { + "id" : "it.resources.entities/customer-office.title.create", + "code" : "resources.entities/customer-office.title.create", + "lang" : "it", + "text" : "Nuova Sede" +}, { + "id" : "it.resources.entities/customer-office.title.edit", + "code" : "resources.entities/customer-office.title.edit", + "lang" : "it", + "text" : "Modifica Sede" +}, { + "id" : "it.resources.entities/customer-referent.fields.email", + "code" : "resources.entities/customer-referent.fields.email", + "lang" : "it", + "text" : "E-mail" +}, { + "id" : "it.resources.entities/customer-referent.fields.mobile", + "code" : "resources.entities/customer-referent.fields.mobile", + "lang" : "it", + "text" : "Telefono" +}, { + "id" : "it.resources.entities/customer-referent.fields.name", + "code" : "resources.entities/customer-referent.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/customer-referent.fields.office.cityId", + "code" : "resources.entities/customer-referent.fields.office.cityId", + "lang" : "it", + "text" : "Città" +}, { + "id" : "it.resources.entities/customer-referent.fields.officeId", + "code" : "resources.entities/customer-referent.fields.officeId", + "lang" : "it", + "text" : "Sede" +}, { + "id" : "it.resources.entities/customer-referent.fields.surname", + "code" : "resources.entities/customer-referent.fields.surname", + "lang" : "it", + "text" : "Cognome" +}, { + "id" : "it.resources.entities/customer-referent.fields.unit", + "code" : "resources.entities/customer-referent.fields.unit", + "lang" : "it", + "text" : "Reparto" +}, { + "id" : "it.resources.entities/customer-referent.fields.updated", + "code" : "resources.entities/customer-referent.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/customer-referent.name", + "code" : "resources.entities/customer-referent.name", + "lang" : "it", + "text" : "Referente |||| Referenti" +}, { + "id" : "it.resources.entities/customer-referent.title.create", + "code" : "resources.entities/customer-referent.title.create", + "lang" : "it", + "text" : "Nuovo Referente" +}, { + "id" : "it.resources.entities/customer-referent.title.edit", + "code" : "resources.entities/customer-referent.title.edit", + "lang" : "it", + "text" : "Modifica Referente" +}, { + "id" : "it.resources.entities/customer.actions.create", + "code" : "resources.entities/customer.actions.create", + "lang" : "it", + "text" : "Aggiungi" +}, { + "id" : "it.resources.entities/customer.breadcrumbs.edit", + "code" : "resources.entities/customer.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Cliente" +}, { + "id" : "it.resources.entities/customer.fields.active", + "code" : "resources.entities/customer.fields.active", + "lang" : "it", + "text" : "Attivo" +}, { + "id" : "it.resources.entities/customer.fields.name", + "code" : "resources.entities/customer.fields.name", + "lang" : "it", + "text" : "Ragione Sociale" +}, { + "id" : "it.resources.entities/customer.fields.updated", + "code" : "resources.entities/customer.fields.updated", + "lang" : "it", + "text" : "Ultima Modifica" +}, { + "id" : "it.resources.entities/customer.fields.vatCode", + "code" : "resources.entities/customer.fields.vatCode", + "lang" : "it", + "text" : "P.IVA" +}, { + "id" : "it.resources.entities/customer.name", + "code" : "resources.entities/customer.name", + "lang" : "it", + "text" : "Cliente |||| Clienti" +}, { + "id" : "it.resources.entities/customer.sections.offices", + "code" : "resources.entities/customer.sections.offices", + "lang" : "it", + "text" : "Sedi" +}, { + "id" : "it.resources.entities/customer.sections.referents", + "code" : "resources.entities/customer.sections.referents", + "lang" : "it", + "text" : "Referenti" +}, { + "id" : "it.resources.entities/customer.tabs.areas", + "code" : "resources.entities/customer.tabs.areas", + "lang" : "it", + "text" : "Aree" +}, { + "id" : "it.resources.entities/customer.tabs.details", + "code" : "resources.entities/customer.tabs.details", + "lang" : "it", + "text" : "Generali" +}, { + "id" : "it.resources.entities/customer.tabs.offices", + "code" : "resources.entities/customer.tabs.offices", + "lang" : "it", + "text" : "Uffici" +}, { + "id" : "it.resources.entities/customer.tabs.referents", + "code" : "resources.entities/customer.tabs.referents", + "lang" : "it", + "text" : "Referenti" +}, { + "id" : "it.resources.entities/customer.title.create", + "code" : "resources.entities/customer.title.create", + "lang" : "it", + "text" : "Nuovo Cliente" +}, { + "id" : "it.resources.entities/customer.title.edit", + "code" : "resources.entities/customer.title.edit", + "lang" : "it", + "text" : "Modifica cliente %{name}" +}, { + "id" : "it.resources.entities/device.alert", + "code" : "resources.entities/device.alert", + "lang" : "it", + "text" : "Di seguito è presente l'elenco dei dispositivi registrati per cui è disponibile il login con pin." +}, { + "id" : "it.resources.entities/device.breadcrumbs.create", + "code" : "resources.entities/device.breadcrumbs.create", + "lang" : "it", + "text" : "Nuovo Dispositivo" +}, { + "id" : "it.resources.entities/device.breadcrumbs.edit", + "code" : "resources.entities/device.breadcrumbs.edit", + "lang" : "it", + "text" : "Dettaglio Dispositivo" +}, { + "id" : "it.resources.entities/device.fields.code", + "code" : "resources.entities/device.fields.code", + "lang" : "it", + "text" : "Codice Univoco" +}, { + "id" : "it.resources.entities/device.fields.registrationDate", + "code" : "resources.entities/device.fields.registrationDate", + "lang" : "it", + "text" : "Data di registrazione" +}, { + "id" : "it.resources.entities/device.fields.secret", + "code" : "resources.entities/device.fields.secret", + "lang" : "it", + "text" : "Segreto condiviso" +}, { + "id" : "it.resources.entities/device.name", + "code" : "resources.entities/device.name", + "lang" : "it", + "text" : "Dispositivo |||| Dispositivi" +}, { + "id" : "it.resources.entities/device.title", + "code" : "resources.entities/device.title", + "lang" : "it", + "text" : "Dettagli Dispositivo" +}, { + "id" : "it.resources.entities/docx-template.breadcrumbs.create", + "code" : "resources.entities/docx-template.breadcrumbs.create", + "lang" : "it", + "text" : "Crea nuovo Modulo" +}, { + "id" : "it.resources.entities/docx-template.breadcrumbs.edit", + "code" : "resources.entities/docx-template.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Modulo" +}, { + "id" : "it.resources.entities/docx-template.edit", + "code" : "resources.entities/docx-template.edit", + "lang" : "it", + "text" : "Modifica Modulo" +}, { + "id" : "it.resources.entities/docx-template.fields.attachment", + "code" : "resources.entities/docx-template.fields.attachment", + "lang" : "it", + "text" : "Template" +}, { + "id" : "it.resources.entities/docx-template.fields.name", + "code" : "resources.entities/docx-template.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/docx-template.fields.updated", + "code" : "resources.entities/docx-template.fields.updated", + "lang" : "it", + "text" : "Ultima Modifica" +}, { + "id" : "it.resources.entities/docx-template.name", + "code" : "resources.entities/docx-template.name", + "lang" : "it", + "text" : "Modulistica" +}, { + "id" : "it.resources.entities/docx-template.title.create", + "code" : "resources.entities/docx-template.title.create", + "lang" : "it", + "text" : "Nuovo Modulo" +}, { + "id" : "it.resources.entities/docx-template.title.edit", + "code" : "resources.entities/docx-template.title.edit", + "lang" : "it", + "text" : "Modifica Modulo" +}, { + "id" : "it.resources.entities/docx-templates.fields.type.link", + "code" : "resources.entities/docx-templates.fields.type.link", + "lang" : "it", + "text" : "Per ottenere la documentazione aggiornata sulle variabili disponibili per la progettazione del template che hai selezionato clicca qui" +}, { + "id" : "it.resources.entities/equipment-attachment.fields.attachment", + "code" : "resources.entities/equipment-attachment.fields.attachment", + "lang" : "it", + "text" : "Allegato" +}, { + "id" : "it.resources.entities/equipment-attachment.fields.created", + "code" : "resources.entities/equipment-attachment.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/equipment-attachment.fields.description", + "code" : "resources.entities/equipment-attachment.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/equipment-attachment.fields.updated", + "code" : "resources.entities/equipment-attachment.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/equipment-attachment.name", + "code" : "resources.entities/equipment-attachment.name", + "lang" : "it", + "text" : "Allegato Attrezzatura |||| Allegati Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-attachment.title", + "code" : "resources.entities/equipment-attachment.title", + "lang" : "it", + "text" : "Allegato Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type-attachment.fields.attachment", + "code" : "resources.entities/equipment-type-attachment.fields.attachment", + "lang" : "it", + "text" : "Allegato" +}, { + "id" : "it.resources.entities/equipment-type-attachment.fields.created", + "code" : "resources.entities/equipment-type-attachment.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/equipment-type-attachment.fields.description", + "code" : "resources.entities/equipment-type-attachment.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/equipment-type-attachment.fields.updated", + "code" : "resources.entities/equipment-type-attachment.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/equipment-type-attachment.name", + "code" : "resources.entities/equipment-type-attachment.name", + "lang" : "it", + "text" : "Allegato Tipo Attrezzatura |||| Allegati Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type-attachment.title", + "code" : "resources.entities/equipment-type-attachment.title", + "lang" : "it", + "text" : "Allegato Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type-attachment.title.list", + "code" : "resources.entities/equipment-type-attachment.title.list", + "lang" : "it", + "text" : "Allegati Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.breadcrumbs.create", + "code" : "resources.entities/equipment-type.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.breadcrumbs.edit", + "code" : "resources.entities/equipment-type.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.fields.accessory", + "code" : "resources.entities/equipment-type.fields.accessory", + "lang" : "it", + "text" : "Accessorio" +}, { + "id" : "it.resources.entities/equipment-type.fields.attachment", + "code" : "resources.entities/equipment-type.fields.attachment", + "lang" : "it", + "text" : "Allegato" +}, { + "id" : "it.resources.entities/equipment-type.fields.breakpointInHours.help", + "code" : "resources.entities/equipment-type.fields.breakpointInHours.help", + "lang" : "it", + "text" : "Indicare il numero di ore garantite di utilizzo oltre le quali l'apparecchiatura può essere soggetta a rottura." +}, { + "id" : "it.resources.entities/equipment-type.fields.created", + "code" : "resources.entities/equipment-type.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/equipment-type.fields.name", + "code" : "resources.entities/equipment-type.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/equipment-type.fields.updated", + "code" : "resources.entities/equipment-type.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/equipment-type.name", + "code" : "resources.entities/equipment-type.name", + "lang" : "it", + "text" : "Tipo Attrezzatura |||| Tipi Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.section", + "code" : "resources.entities/equipment-type.section", + "lang" : "it", + "text" : "Dati aggiuntivi" +}, { + "id" : "it.resources.entities/equipment-type.title", + "code" : "resources.entities/equipment-type.title", + "lang" : "it", + "text" : "Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.title.list", + "code" : "resources.entities/equipment-type.title.list", + "lang" : "it", + "text" : "Sotto-Tipo Attrezzature" +}, { + "id" : "it.resources.entities/equipment.actions.backToFather", + "code" : "resources.entities/equipment.actions.backToFather", + "lang" : "it", + "text" : "Vai al Fornitore" +}, { + "id" : "it.resources.entities/equipment.breadcrumbs.create", + "code" : "resources.entities/equipment.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Attrezzatura" +}, { + "id" : "it.resources.entities/equipment.breadcrumbs.edit", + "code" : "resources.entities/equipment.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Attrezzatura" +}, { + "id" : "it.resources.entities/equipment.fields.created", + "code" : "resources.entities/equipment.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/equipment.fields.equipmentType.name", + "code" : "resources.entities/equipment.fields.equipmentType.name", + "lang" : "it", + "text" : "Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment.fields.equipmentTypeId", + "code" : "resources.entities/equipment.fields.equipmentTypeId", + "lang" : "it", + "text" : "Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment.fields.name", + "code" : "resources.entities/equipment.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/equipment.fields.supplier.businessName", + "code" : "resources.entities/equipment.fields.supplier.businessName", + "lang" : "it", + "text" : "Fornitore" +}, { + "id" : "it.resources.entities/equipment.fields.supplierId", + "code" : "resources.entities/equipment.fields.supplierId", + "lang" : "it", + "text" : "Fornitore" +}, { + "id" : "it.resources.entities/equipment.fields.updated", + "code" : "resources.entities/equipment.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/equipment.name", + "code" : "resources.entities/equipment.name", + "lang" : "it", + "text" : "Attrezzatura |||| Attrezzature" +}, { + "id" : "it.resources.entities/equipment.title", + "code" : "resources.entities/equipment.title", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/equipmentType.actions.backToFather", + "code" : "resources.entities/equipmentType.actions.backToFather", + "lang" : "it", + "text" : "Torna Indietro" +}, { + "id" : "it.resources.entities/i18n-message.breadcrumbs.create", + "code" : "resources.entities/i18n-message.breadcrumbs.create", + "lang" : "it", + "text" : "Nuovo Messaggio" +}, { + "id" : "it.resources.entities/i18n-message.breadcrumbs.edit", + "code" : "resources.entities/i18n-message.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Messaggio" +}, { + "id" : "it.resources.entities/i18n-message.fields.code", + "code" : "resources.entities/i18n-message.fields.code", + "lang" : "it", + "text" : "Codice" +}, { + "id" : "it.resources.entities/i18n-message.fields.lang", + "code" : "resources.entities/i18n-message.fields.lang", + "lang" : "it", + "text" : "Lingua" +}, { + "id" : "it.resources.entities/i18n-message.fields.text", + "code" : "resources.entities/i18n-message.fields.text", + "lang" : "it", + "text" : "Testo" +}, { + "id" : "it.resources.entities/i18n-message.fields.translated", + "code" : "resources.entities/i18n-message.fields.translated", + "lang" : "it", + "text" : "Tradotto" +}, { + "id" : "it.resources.entities/i18n-message.name", + "code" : "resources.entities/i18n-message.name", + "lang" : "it", + "text" : "Messaggi (i18n)" +}, { + "id" : "it.resources.entities/i18n-message.title", + "code" : "resources.entities/i18n-message.title", + "lang" : "it", + "text" : "Messaggio Localizzato" +}, { + "id" : "it.resources.entities/maintenance.actions.backToFather", + "code" : "resources.entities/maintenance.actions.backToFather", + "lang" : "it", + "text" : "Vai all'Attività" +}, { + "id" : "it.resources.entities/maintenance.breadcrumbs.create", + "code" : "resources.entities/maintenance.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Manutenzione" +}, { + "id" : "it.resources.entities/maintenance.breadcrumbs.edit", + "code" : "resources.entities/maintenance.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Manutenzione" +}, { + "id" : "it.resources.entities/maintenance.fields.activity.title", + "code" : "resources.entities/maintenance.fields.activity.title", + "lang" : "it", + "text" : "Attività" +}, { + "id" : "it.resources.entities/maintenance.fields.activityId", + "code" : "resources.entities/maintenance.fields.activityId", + "lang" : "it", + "text" : "Attività" +}, { + "id" : "it.resources.entities/maintenance.fields.created", + "code" : "resources.entities/maintenance.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/maintenance.fields.date", + "code" : "resources.entities/maintenance.fields.date", + "lang" : "it", + "text" : "Data" +}, { + "id" : "it.resources.entities/maintenance.fields.description", + "code" : "resources.entities/maintenance.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/maintenance.fields.equipmentTypeId", + "code" : "resources.entities/maintenance.fields.equipmentTypeId", + "lang" : "it", + "text" : "Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/maintenance.fields.interventionNumber", + "code" : "resources.entities/maintenance.fields.interventionNumber", + "lang" : "it", + "text" : "Numero Intervento" +}, { + "id" : "it.resources.entities/maintenance.fields.interventions", + "code" : "resources.entities/maintenance.fields.interventions", + "lang" : "it", + "text" : "Interventi" +}, { + "id" : "it.resources.entities/maintenance.fields.interventions.description", + "code" : "resources.entities/maintenance.fields.interventions.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/maintenance.fields.interventions.equipmentTypeId", + "code" : "resources.entities/maintenance.fields.interventions.equipmentTypeId", + "lang" : "it", + "text" : "Approvvigionamento" +}, { + "id" : "it.resources.entities/maintenance.fields.interventions.reorder", + "code" : "resources.entities/maintenance.fields.interventions.reorder", + "lang" : "it", + "text" : "Riordinato" +}, { + "id" : "it.resources.entities/maintenance.fields.interventions.substitution", + "code" : "resources.entities/maintenance.fields.interventions.substitution", + "lang" : "it", + "text" : "Sostituto" +}, { + "id" : "it.resources.entities/maintenance.fields.protocol.protocolNumber", + "code" : "resources.entities/maintenance.fields.protocol.protocolNumber", + "lang" : "it", + "text" : "Numero di Protocollo" +}, { + "id" : "it.resources.entities/maintenance.fields.protocolNumber", + "code" : "resources.entities/maintenance.fields.protocolNumber", + "lang" : "it", + "text" : "Numero di Protocollo" +}, { + "id" : "it.resources.entities/maintenance.fields.reorder", + "code" : "resources.entities/maintenance.fields.reorder", + "lang" : "it", + "text" : "Riordinato" +}, { + "id" : "it.resources.entities/maintenance.fields.substitution", + "code" : "resources.entities/maintenance.fields.substitution", + "lang" : "it", + "text" : "Sostituto" +}, { + "id" : "it.resources.entities/maintenance.fields.supplier.businessName", + "code" : "resources.entities/maintenance.fields.supplier.businessName", + "lang" : "it", + "text" : "Data" +}, { + "id" : "it.resources.entities/maintenance.fields.title", + "code" : "resources.entities/maintenance.fields.title", + "lang" : "it", + "text" : "Titolo" +}, { + "id" : "it.resources.entities/maintenance.fields.updated", + "code" : "resources.entities/maintenance.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/maintenance.fields.user.name", + "code" : "resources.entities/maintenance.fields.user.name", + "lang" : "it", + "text" : "Creato da" +}, { + "id" : "it.resources.entities/maintenance.name", + "code" : "resources.entities/maintenance.name", + "lang" : "it", + "text" : "Manutenzione |||| Manutenzioni" +}, { + "id" : "it.resources.entities/maintenance.title", + "code" : "resources.entities/maintenance.title", + "lang" : "it", + "text" : "Manutenzione" +}, { + "id" : "it.resources.entities/notification.name", + "code" : "resources.entities/notification.name", + "lang" : "it", + "text" : "Notifiche" +}, { + "id" : "it.resources.entities/price-list-item.fields.created", + "code" : "resources.entities/price-list-item.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/price-list-item.fields.equipment.equipmentTypeId", + "code" : "resources.entities/price-list-item.fields.equipment.equipmentTypeId", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/price-list-item.fields.equipmentId", + "code" : "resources.entities/price-list-item.fields.equipmentId", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/price-list-item.fields.equipmentType.name", + "code" : "resources.entities/price-list-item.fields.equipmentType.name", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/price-list-item.fields.price", + "code" : "resources.entities/price-list-item.fields.price", + "lang" : "it", + "text" : "Prezzo" +}, { + "id" : "it.resources.entities/price-list-item.fields.updated", + "code" : "resources.entities/price-list-item.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/price-list-item.name", + "code" : "resources.entities/price-list-item.name", + "lang" : "it", + "text" : "Listino Prezzi |||| Listini Prezzi" +}, { + "id" : "it.resources.entities/price-list-item.title", + "code" : "resources.entities/price-list-item.title", + "lang" : "it", + "text" : "Prezzo Attrezzatura" +}, { + "id" : "it.resources.entities/price-list-item.title.list", + "code" : "resources.entities/price-list-item.title.list", + "lang" : "it", + "text" : "Listino Prezzi" +}, { + "id" : "it.resources.entities/price-list.actions.back-to-supplier", + "code" : "resources.entities/price-list.actions.back-to-supplier", + "lang" : "it", + "text" : "Vai al Fornitore" +}, { + "id" : "it.resources.entities/price-list.fields.created", + "code" : "resources.entities/price-list.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/price-list.fields.end", + "code" : "resources.entities/price-list.fields.end", + "lang" : "it", + "text" : "Data Fine" +}, { + "id" : "it.resources.entities/price-list.fields.name", + "code" : "resources.entities/price-list.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/price-list.fields.start", + "code" : "resources.entities/price-list.fields.start", + "lang" : "it", + "text" : "Data Inizio" +}, { + "id" : "it.resources.entities/price-list.fields.updated", + "code" : "resources.entities/price-list.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/price-list.name", + "code" : "resources.entities/price-list.name", + "lang" : "it", + "text" : "Listino |||| Listini" +}, { + "id" : "it.resources.entities/price-list.title", + "code" : "resources.entities/price-list.title", + "lang" : "it", + "text" : "Listino" +}, { + "id" : "it.resources.entities/protocol-attachment.fields.attachment", + "code" : "resources.entities/protocol-attachment.fields.attachment", + "lang" : "it", + "text" : "Allegato" +}, { + "id" : "it.resources.entities/protocol-attachment.fields.created", + "code" : "resources.entities/protocol-attachment.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/protocol-attachment.fields.description", + "code" : "resources.entities/protocol-attachment.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/protocol-attachment.fields.updated", + "code" : "resources.entities/protocol-attachment.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/protocol-attachment.name", + "code" : "resources.entities/protocol-attachment.name", + "lang" : "it", + "text" : "Allegato Protocollo |||| Allegati Protocollo" +}, { + "id" : "it.resources.entities/protocol-attachment.title", + "code" : "resources.entities/protocol-attachment.title", + "lang" : "it", + "text" : "Allegati Protocollo" +}, { + "id" : "it.resources.entities/protocol-service.title", + "code" : "resources.entities/protocol-service.title", + "lang" : "it", + "text" : "Servizi Offerti" +}, { + "id" : "it.resources.entities/protocol.breadcrumbs.create", + "code" : "resources.entities/protocol.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Protocollo" +}, { + "id" : "it.resources.entities/protocol.breadcrumbs.edit", + "code" : "resources.entities/protocol.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Protocollo" +}, { + "id" : "it.resources.entities/protocol.fields.created", + "code" : "resources.entities/protocol.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/protocol.fields.customer.name", + "code" : "resources.entities/protocol.fields.customer.name", + "lang" : "it", + "text" : "Cliente" +}, { + "id" : "it.resources.entities/protocol.fields.customerId", + "code" : "resources.entities/protocol.fields.customerId", + "lang" : "it", + "text" : "Cliente" +}, { + "id" : "it.resources.entities/protocol.fields.description", + "code" : "resources.entities/protocol.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/protocol.fields.protocolDate", + "code" : "resources.entities/protocol.fields.protocolDate", + "lang" : "it", + "text" : "Data di Protocollo" +}, { + "id" : "it.resources.entities/protocol.fields.protocolNumber", + "code" : "resources.entities/protocol.fields.protocolNumber", + "lang" : "it", + "text" : "Numero di Protocollo" +}, { + "id" : "it.resources.entities/protocol.fields.title", + "code" : "resources.entities/protocol.fields.title", + "lang" : "it", + "text" : "Titolo" +}, { + "id" : "it.resources.entities/protocol.fields.updated", + "code" : "resources.entities/protocol.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/protocol.name", + "code" : "resources.entities/protocol.name", + "lang" : "it", + "text" : "Protocollo |||| Protocolli" +}, { + "id" : "it.resources.entities/protocol.services.end", + "code" : "resources.entities/protocol.services.end", + "lang" : "it", + "text" : "Scadenza" +}, { + "id" : "it.resources.entities/protocol.services.frequency", + "code" : "resources.entities/protocol.services.frequency", + "lang" : "it", + "text" : "Frequenza" +}, { + "id" : "it.resources.entities/protocol.services.fromActivityTypeId", + "code" : "resources.entities/protocol.services.fromActivityTypeId", + "lang" : "it", + "text" : "Tipo Attività Sorgente" +}, { + "id" : "it.resources.entities/protocol.services.toActivityTypeId", + "code" : "resources.entities/protocol.services.toActivityTypeId", + "lang" : "it", + "text" : "Tipo Attività (Destinazione)" +}, { + "id" : "it.resources.entities/protocol.tabs.details", + "code" : "resources.entities/protocol.tabs.details", + "lang" : "it", + "text" : "Info Generali" +}, { + "id" : "it.resources.entities/protocol.title", + "code" : "resources.entities/protocol.title", + "lang" : "it", + "text" : "Protocollo" +}, { + "id" : "it.resources.entities/rfid-device-track.fields.additionalData", + "code" : "resources.entities/rfid-device-track.fields.additionalData", + "lang" : "it", + "text" : "Dati Aggiuntivi" +}, { + "id" : "it.resources.entities/rfid-device-track.fields.areaId", + "code" : "resources.entities/rfid-device-track.fields.areaId", + "lang" : "it", + "text" : "Area" +}, { + "id" : "it.resources.entities/rfid-device-track.fields.from", + "code" : "resources.entities/rfid-device-track.fields.from", + "lang" : "it", + "text" : "Dalla data" +}, { + "id" : "it.resources.entities/rfid-device-track.fields.gateway.name", + "code" : "resources.entities/rfid-device-track.fields.gateway.name", + "lang" : "it", + "text" : "Gateway" +}, { + "id" : "it.resources.entities/rfid-device-track.fields.supplyId", + "code" : "resources.entities/rfid-device-track.fields.supplyId", + "lang" : "it", + "text" : "Approvvigionamento" +}, { + "id" : "it.resources.entities/rfid-device-track.fields.tag.name", + "code" : "resources.entities/rfid-device-track.fields.tag.name", + "lang" : "it", + "text" : "Tag" +}, { + "id" : "it.resources.entities/rfid-device-track.fields.to", + "code" : "resources.entities/rfid-device-track.fields.to", + "lang" : "it", + "text" : "Alla data" +}, { + "id" : "it.resources.entities/rfid-device-track.fields.ts", + "code" : "resources.entities/rfid-device-track.fields.ts", + "lang" : "it", + "text" : "Registrato il" +}, { + "id" : "it.resources.entities/rfid-device-track.name", + "code" : "resources.entities/rfid-device-track.name", + "lang" : "it", + "text" : "Tracciamento RFID |||| Tracciamento RFID" +}, { + "id" : "it.resources.entities/rfid-device-track.tabs.list", + "code" : "resources.entities/rfid-device-track.tabs.list", + "lang" : "it", + "text" : "Log Posizioni" +}, { + "id" : "it.resources.entities/rfid-device-track.tutorial.description", + "code" : "resources.entities/rfid-device-track.tutorial.description", + "lang" : "it", + "text" : "" +}, { + "id" : "it.resources.entities/rfid-device-track.tutorial.title", + "code" : "resources.entities/rfid-device-track.tutorial.title", + "lang" : "it", + "text" : "Tracciamento RFID" +}, { + "id" : "it.resources.entities/rfid-device.breadcrumbs.create", + "code" : "resources.entities/rfid-device.breadcrumbs.create", + "lang" : "it", + "text" : "Crea RFID" +}, { + "id" : "it.resources.entities/rfid-device.breadcrumbs.edit", + "code" : "resources.entities/rfid-device.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica RFID" +}, { + "id" : "it.resources.entities/rfid-device.fields.code", + "code" : "resources.entities/rfid-device.fields.code", + "lang" : "it", + "text" : "Codice Seriale" +}, { + "id" : "it.resources.entities/rfid-device.fields.name", + "code" : "resources.entities/rfid-device.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/rfid-device.fields.type", + "code" : "resources.entities/rfid-device.fields.type", + "lang" : "it", + "text" : "Tipo" +}, { + "id" : "it.resources.entities/rfid-device.fields.updated", + "code" : "resources.entities/rfid-device.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/rfid-device.name", + "code" : "resources.entities/rfid-device.name", + "lang" : "it", + "text" : "RFID |||| RFID" +}, { + "id" : "it.resources.entities/rfid-device.title.create", + "code" : "resources.entities/rfid-device.title.create", + "lang" : "it", + "text" : "Nuovo RFID" +}, { + "id" : "it.resources.entities/rfid-device.title.edit", + "code" : "resources.entities/rfid-device.title.edit", + "lang" : "it", + "text" : "Modifica RFID" +}, { + "id" : "it.resources.entities/supplier-referent.fields.created", + "code" : "resources.entities/supplier-referent.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/supplier-referent.fields.department", + "code" : "resources.entities/supplier-referent.fields.department", + "lang" : "it", + "text" : "Dipartimento" +}, { + "id" : "it.resources.entities/supplier-referent.fields.email", + "code" : "resources.entities/supplier-referent.fields.email", + "lang" : "it", + "text" : "Email" +}, { + "id" : "it.resources.entities/supplier-referent.fields.name", + "code" : "resources.entities/supplier-referent.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/supplier-referent.fields.phone", + "code" : "resources.entities/supplier-referent.fields.phone", + "lang" : "it", + "text" : "Numero di Telefono" +}, { + "id" : "it.resources.entities/supplier-referent.fields.surname", + "code" : "resources.entities/supplier-referent.fields.surname", + "lang" : "it", + "text" : "Cognome" +}, { + "id" : "it.resources.entities/supplier-referent.fields.updated", + "code" : "resources.entities/supplier-referent.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/supplier-referent.name", + "code" : "resources.entities/supplier-referent.name", + "lang" : "it", + "text" : "Referente Fornitore |||| Referenti Fornitore" +}, { + "id" : "it.resources.entities/supplier-referent.title", + "code" : "resources.entities/supplier-referent.title", + "lang" : "it", + "text" : "Referenti Fornitore" +}, { + "id" : "it.resources.entities/supplier.actions.create", + "code" : "resources.entities/supplier.actions.create", + "lang" : "it", + "text" : "Aggiungi" +}, { + "id" : "it.resources.entities/supplier.breadcrumbs.create", + "code" : "resources.entities/supplier.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Fornitore" +}, { + "id" : "it.resources.entities/supplier.breadcrumbs.edit", + "code" : "resources.entities/supplier.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Fornitore" +}, { + "id" : "it.resources.entities/supplier.fields.address", + "code" : "resources.entities/supplier.fields.address", + "lang" : "it", + "text" : "Indirizzo" +}, { + "id" : "it.resources.entities/supplier.fields.businessName", + "code" : "resources.entities/supplier.fields.businessName", + "lang" : "it", + "text" : "Ragione Sociale" +}, { + "id" : "it.resources.entities/supplier.fields.city.name", + "code" : "resources.entities/supplier.fields.city.name", + "lang" : "it", + "text" : "Comune" +}, { + "id" : "it.resources.entities/supplier.fields.cityId", + "code" : "resources.entities/supplier.fields.cityId", + "lang" : "it", + "text" : "Comune" +}, { + "id" : "it.resources.entities/supplier.fields.created", + "code" : "resources.entities/supplier.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/supplier.fields.updated", + "code" : "resources.entities/supplier.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/supplier.fields.vatNumber", + "code" : "resources.entities/supplier.fields.vatNumber", + "lang" : "it", + "text" : "Partita IVA" +}, { + "id" : "it.resources.entities/supplier.name", + "code" : "resources.entities/supplier.name", + "lang" : "it", + "text" : "Fornitore |||| Fornitori" +}, { + "id" : "it.resources.entities/supplier.tabs.equipment", + "code" : "resources.entities/supplier.tabs.equipment", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/supplier.tabs.price-list", + "code" : "resources.entities/supplier.tabs.price-list", + "lang" : "it", + "text" : "Listino" +}, { + "id" : "it.resources.entities/supplier.title", + "code" : "resources.entities/supplier.title", + "lang" : "it", + "text" : "Fornitore" +}, { + "id" : "it.resources.entities/supply.actions.backToFather", + "code" : "resources.entities/supply.actions.backToFather", + "lang" : "it", + "text" : "Torna Indietro" +}, { + "id" : "it.resources.entities/supply.alert", + "code" : "resources.entities/supply.alert", + "lang" : "it", + "text" : "Di seguito trovi le info relative all'approvvigionamento" +}, { + "id" : "it.resources.entities/supply.breadcrumbs.create", + "code" : "resources.entities/supply.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Approvvigionamento" +}, { + "id" : "it.resources.entities/supply.breadcrumbs.edit", + "code" : "resources.entities/supply.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Approvvigionamento" +}, { + "id" : "it.resources.entities/supply.fields.area.name", + "code" : "resources.entities/supply.fields.area.name", + "lang" : "it", + "text" : "Area" +}, { + "id" : "it.resources.entities/supply.fields.area.officeId", + "code" : "resources.entities/supply.fields.area.officeId", + "lang" : "it", + "text" : "Ufficio" +}, { + "id" : "it.resources.entities/supply.fields.areaId", + "code" : "resources.entities/supply.fields.areaId", + "lang" : "it", + "text" : "Area" +}, { + "id" : "it.resources.entities/supply.fields.breakpointInHours", + "code" : "resources.entities/supply.fields.breakpointInHours", + "lang" : "it", + "text" : "Ore di funzionamento" +}, { + "id" : "it.resources.entities/supply.fields.breakpointInHours.help", + "code" : "resources.entities/supply.fields.breakpointInHours.help", + "lang" : "it", + "text" : "Indicare il numero di ore garantite di utilizzo oltre le quali l'apparecchiatura può essere soggetta a rottura." +}, { + "id" : "it.resources.entities/supply.fields.created", + "code" : "resources.entities/supply.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/supply.fields.customer.name", + "code" : "resources.entities/supply.fields.customer.name", + "lang" : "it", + "text" : "Cliente" +}, { + "id" : "it.resources.entities/supply.fields.customerName", + "code" : "resources.entities/supply.fields.customerName", + "lang" : "it", + "text" : "Cliente" +}, { + "id" : "it.resources.entities/supply.fields.ddtNumber", + "code" : "resources.entities/supply.fields.ddtNumber", + "lang" : "it", + "text" : "Numero Documento di Consegna" +}, { + "id" : "it.resources.entities/supply.fields.deliveryDate", + "code" : "resources.entities/supply.fields.deliveryDate", + "lang" : "it", + "text" : "Data Consegna" +}, { + "id" : "it.resources.entities/supply.fields.duration", + "code" : "resources.entities/supply.fields.duration", + "lang" : "it", + "text" : "Tempo di utilizzo" +}, { + "id" : "it.resources.entities/supply.fields.duration.running", + "code" : "resources.entities/supply.fields.duration.running", + "lang" : "it", + "text" : "Ancora in uso" +}, { + "id" : "it.resources.entities/supply.fields.equipment.equipmentTypeId", + "code" : "resources.entities/supply.fields.equipment.equipmentTypeId", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/supply.fields.equipment.name", + "code" : "resources.entities/supply.fields.equipment.name", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/supply.fields.equipment.supplierId", + "code" : "resources.entities/supply.fields.equipment.supplierId", + "lang" : "it", + "text" : "Fornitore" +}, { + "id" : "it.resources.entities/supply.fields.equipmentId", + "code" : "resources.entities/supply.fields.equipmentId", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/supply.fields.equipmentType.name", + "code" : "resources.entities/supply.fields.equipmentType.name", + "lang" : "it", + "text" : "Attrezzatura" +}, { + "id" : "it.resources.entities/supply.fields.from", + "code" : "resources.entities/supply.fields.from", + "lang" : "it", + "text" : "Data Inizio" +}, { + "id" : "it.resources.entities/supply.fields.orderDate", + "code" : "resources.entities/supply.fields.orderDate", + "lang" : "it", + "text" : "Data Ordine" +}, { + "id" : "it.resources.entities/supply.fields.protocol.description", + "code" : "resources.entities/supply.fields.protocol.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/supply.fields.protocol.protocolDate", + "code" : "resources.entities/supply.fields.protocol.protocolDate", + "lang" : "it", + "text" : "Data di Protocollo" +}, { + "id" : "it.resources.entities/supply.fields.protocol.protocolNumber", + "code" : "resources.entities/supply.fields.protocol.protocolNumber", + "lang" : "it", + "text" : "Numero di Protocollo" +}, { + "id" : "it.resources.entities/supply.fields.protocol.title", + "code" : "resources.entities/supply.fields.protocol.title", + "lang" : "it", + "text" : "Titolo" +}, { + "id" : "it.resources.entities/supply.fields.protocolId", + "code" : "resources.entities/supply.fields.protocolId", + "lang" : "it", + "text" : "Protocollo" +}, { + "id" : "it.resources.entities/supply.fields.quantity", + "code" : "resources.entities/supply.fields.quantity", + "lang" : "it", + "text" : "Quantità" +}, { + "id" : "it.resources.entities/supply.fields.rfidDevice", + "code" : "resources.entities/supply.fields.rfidDevice", + "lang" : "it", + "text" : "Tag RFID" +}, { + "id" : "it.resources.entities/supply.fields.rfidDevice.name", + "code" : "resources.entities/supply.fields.rfidDevice.name", + "lang" : "it", + "text" : "Dispositivo RFID" +}, { + "id" : "it.resources.entities/supply.fields.rfidDeviceId", + "code" : "resources.entities/supply.fields.rfidDeviceId", + "lang" : "it", + "text" : "Tag RFID" +}, { + "id" : "it.resources.entities/supply.fields.serialNumber", + "code" : "resources.entities/supply.fields.serialNumber", + "lang" : "it", + "text" : "Numero Seriale" +}, { + "id" : "it.resources.entities/supply.fields.supplier.businessName", + "code" : "resources.entities/supply.fields.supplier.businessName", + "lang" : "it", + "text" : "Fornitore" +}, { + "id" : "it.resources.entities/supply.fields.supplierId", + "code" : "resources.entities/supply.fields.supplierId", + "lang" : "it", + "text" : "Fornitore" +}, { + "id" : "it.resources.entities/supply.fields.to", + "code" : "resources.entities/supply.fields.to", + "lang" : "it", + "text" : "Data Fine" +}, { + "id" : "it.resources.entities/supply.fields.updated", + "code" : "resources.entities/supply.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/supply.fields.usageStatus", + "code" : "resources.entities/supply.fields.usageStatus", + "lang" : "it", + "text" : "Stato" +}, { + "id" : "it.resources.entities/supply.group.usage", + "code" : "resources.entities/supply.group.usage", + "lang" : "it", + "text" : "Utilizzi" +}, { + "id" : "it.resources.entities/supply.info_message", + "code" : "resources.entities/supply.info_message", + "lang" : "it", + "text" : "Questo approvvigionamento appartiene al fornitore %{supplier} relativo all'attrezzatura %{equipment} con il protocollo %{protocol}" +}, { + "id" : "it.resources.entities/supply.name", + "code" : "resources.entities/supply.name", + "lang" : "it", + "text" : "Approvvigionamento |||| Approvvigionamenti" +}, { + "id" : "it.resources.entities/supply.rfid-device-last-position", + "code" : "resources.entities/supply.rfid-device-last-position", + "lang" : "it", + "text" : "Area: %{area}, Data e ora: %{ts}" +}, { + "id" : "it.resources.entities/supply.rfid-device-last-position.title", + "code" : "resources.entities/supply.rfid-device-last-position.title", + "lang" : "it", + "text" : "Ultima posizione registrata" +}, { + "id" : "it.resources.entities/supply.show.activity", + "code" : "resources.entities/supply.show.activity", + "lang" : "it", + "text" : "Storico Attività" +}, { + "id" : "it.resources.entities/supply.show.equipment-attachment", + "code" : "resources.entities/supply.show.equipment-attachment", + "lang" : "it", + "text" : "Allegati Attrezzatura" +}, { + "id" : "it.resources.entities/supply.show.protocol-info", + "code" : "resources.entities/supply.show.protocol-info", + "lang" : "it", + "text" : "Info Protocollo" +}, { + "id" : "it.resources.entities/supply.show.register-maintenance", + "code" : "resources.entities/supply.show.register-maintenance", + "lang" : "it", + "text" : "Registra una Manutenzione" +}, { + "id" : "it.resources.entities/supply.show.request-assistance", + "code" : "resources.entities/supply.show.request-assistance", + "lang" : "it", + "text" : "Richiedi Assistenza" +}, { + "id" : "it.resources.entities/supply.show.status-running", + "code" : "resources.entities/supply.show.status-running", + "lang" : "it", + "text" : "Sospendi" +}, { + "id" : "it.resources.entities/supply.show.status-stopped", + "code" : "resources.entities/supply.show.status-stopped", + "lang" : "it", + "text" : "Avvia" +}, { + "id" : "it.resources.entities/supply.show.supply-info", + "code" : "resources.entities/supply.show.supply-info", + "lang" : "it", + "text" : "Info Approvvigionamento" +}, { + "id" : "it.resources.entities/supply.show.usage-info", + "code" : "resources.entities/supply.show.usage-info", + "lang" : "it", + "text" : "Registro Utilizzi" +}, { + "id" : "it.resources.entities/supply.tabs.activity", + "code" : "resources.entities/supply.tabs.activity", + "lang" : "it", + "text" : "Storico Attività" +}, { + "id" : "it.resources.entities/supply.tabs.details", + "code" : "resources.entities/supply.tabs.details", + "lang" : "it", + "text" : "Info Generali" +}, { + "id" : "it.resources.entities/supply.tabs.equipment-attachment", + "code" : "resources.entities/supply.tabs.equipment-attachment", + "lang" : "it", + "text" : "Allegati Attrezzatura" +}, { + "id" : "it.resources.entities/supply.tabs.protocol", + "code" : "resources.entities/supply.tabs.protocol", + "lang" : "it", + "text" : "Protocollo" +}, { + "id" : "it.resources.entities/supply.tabs.rfid-device-track", + "code" : "resources.entities/supply.tabs.rfid-device-track", + "lang" : "it", + "text" : "Log Posizioni" +}, { + "id" : "it.resources.entities/supply.tabs.supply", + "code" : "resources.entities/supply.tabs.supply", + "lang" : "it", + "text" : "Approvvigionamento " +}, { + "id" : "it.resources.entities/supply.tabs.usage-chart", + "code" : "resources.entities/supply.tabs.usage-chart", + "lang" : "it", + "text" : "Grafico Utilizzi" +}, { + "id" : "it.resources.entities/supply.title", + "code" : "resources.entities/supply.title", + "lang" : "it", + "text" : "Approvvigionamento" +}, { + "id" : "it.resources.entities/usage.name", + "code" : "resources.entities/usage.name", + "lang" : "it", + "text" : "Utilizzo |||| Utilizzi" +}, { + "id" : "it.resources.entities/usage.tabs.chart", + "code" : "resources.entities/usage.tabs.chart", + "lang" : "it", + "text" : "Statistica Tempo di Utilizzo" +}, { + "id" : "it.resources.entities/usage.tabs.chart.breakPredictions", + "code" : "resources.entities/usage.tabs.chart.breakPredictions", + "lang" : "it", + "text" : "Previsione utilizzo e rottura" +}, { + "id" : "it.resources.entities/usage.tabs.chart.no-data-description", + "code" : "resources.entities/usage.tabs.chart.no-data-description", + "lang" : "it", + "text" : "Nessun dato disponibile con i filtri selezionati" +}, { + "id" : "it.resources.entities/usage.tabs.chart.predictions", + "code" : "resources.entities/usage.tabs.chart.predictions", + "lang" : "it", + "text" : "Predizione ore di funzionamento future" +}, { + "id" : "it.resources.entities/usage.tabs.record", + "code" : "resources.entities/usage.tabs.record", + "lang" : "it", + "text" : "Registro Utilizzi" +}, { + "id" : "it.resources.entities/user.breadcrumbs.create", + "code" : "resources.entities/user.breadcrumbs.create", + "lang" : "it", + "text" : "Nuovo Utente" +}, { + "id" : "it.resources.entities/user.breadcrumbs.edit", + "code" : "resources.entities/user.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Utente" +}, { + "id" : "it.resources.entities/user.fields.active", + "code" : "resources.entities/user.fields.active", + "lang" : "it", + "text" : "Attivo" +}, { + "id" : "it.resources.entities/user.fields.customerId", + "code" : "resources.entities/user.fields.customerId", + "lang" : "it", + "text" : "Cliente" +}, { + "id" : "it.resources.entities/user.fields.image", + "code" : "resources.entities/user.fields.image", + "lang" : "it", + "text" : "Immagine di profilo" +}, { + "id" : "it.resources.entities/user.fields.name", + "code" : "resources.entities/user.fields.name", + "lang" : "it", + "text" : "Nome e Cognome" +}, { + "id" : "it.resources.entities/user.fields.registrationDate", + "code" : "resources.entities/user.fields.registrationDate", + "lang" : "it", + "text" : "Data di registrazione" +}, { + "id" : "it.resources.entities/user.fields.role", + "code" : "resources.entities/user.fields.role", + "lang" : "it", + "text" : "Ruolo" +}, { + "id" : "it.resources.entities/user.name", + "code" : "resources.entities/user.name", + "lang" : "it", + "text" : "Utente |||| Utenti" +}, { + "id" : "it.resources.entities/user.title.create", + "code" : "resources.entities/user.title.create", + "lang" : "it", + "text" : "Nuovo Utente" +}, { + "id" : "it.resources.entities/user.title.edit", + "code" : "resources.entities/user.title.edit", + "lang" : "it", + "text" : "Modifica utente %{name}" +}, { + "id" : "it.resources.notifications.empty", + "code" : "resources.notifications.empty", + "lang" : "it", + "text" : "Ancora nessuna notifica!" +}, { + "id" : "it.resources.notifications.messages.readed.done", + "code" : "resources.notifications.messages.readed.done", + "lang" : "it", + "text" : "Notifiche segnate come lette." +}, { + "id" : "it.resources.notifications.messages.unreaded.done", + "code" : "resources.notifications.messages.unreaded.done", + "lang" : "it", + "text" : "Notifiche segnate come non lette." +}, { + "id" : "it.resources.transactions.fields.id", + "code" : "resources.transactions.fields.id", + "lang" : "it", + "text" : "#ID" +}, { + "id" : "it.resources.transactions.fields.notes.show_less", + "code" : "resources.transactions.fields.notes.show_less", + "lang" : "it", + "text" : "Mostra meno" +}, { + "id" : "it.resources.transactions.fields.state", + "code" : "resources.transactions.fields.state", + "lang" : "it", + "text" : "Stato" +}, { + "id" : "it.resources.user/change-password.fields.newPassword", + "code" : "resources.user/change-password.fields.newPassword", + "lang" : "it", + "text" : "Nuova Password" +}, { + "id" : "it.resources.user/change-password.fields.oldPassword", + "code" : "resources.user/change-password.fields.oldPassword", + "lang" : "it", + "text" : "Password precedente" +}, { + "id" : "it.resources.user/change-password.title", + "code" : "resources.user/change-password.title", + "lang" : "it", + "text" : "Cambio Password" +}, { + "id" : "it.test", + "code" : "test", + "lang" : "it", + "text" : "test" +}, { + "id" : "it.tracking.stats.rfid.title", + "code" : "tracking.stats.rfid.title", + "lang" : "it", + "text" : "Ultime Posizioni Registrate" +} ] \ No newline at end of file diff --git a/edera-api/api/src/test/java/applica/app/test/TestApplication.java b/edera-api/api/src/test/java/applica/app/test/TestApplication.java new file mode 100644 index 0000000..ab388fa --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/TestApplication.java @@ -0,0 +1,14 @@ +package applica.app.test; + +import applica.app.Application; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; +import org.springframework.context.annotation.ComponentScan; + +@DataMongoTest +@ComponentScan({ "applica.app.test.fixture", "applica.app.test" }) +public class TestApplication { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/edera-api/api/src/test/java/applica/app/test/TestDataFactory.java b/edera-api/api/src/test/java/applica/app/test/TestDataFactory.java new file mode 100644 index 0000000..1569b9a --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/TestDataFactory.java @@ -0,0 +1,36 @@ +package applica.app.test; + +import applica.iam.domain.Profile; +import applica.iam.domain.Role; +import applica.iam.domain.User; +import applica.iam.domain.UserId; +import org.springframework.util.DigestUtils; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class TestDataFactory { + + public static User createUser(String password) { + var userId = UserId.create(); + var pinCode = DigestUtils.md5DigestAsHex(UUID.randomUUID().toString().substring(0, 4).getBytes()); + return new User( + userId, + "testuser" + System.currentTimeMillis() + "@gmail.com", + password, + true, + 0, + null, + new Date(), + UUID.randomUUID().toString(), + false, + true, + List.of(Role.USER), + new Profile(Map.of("name", "Test user")), + pinCode + ); + } + +} diff --git a/edera-api/api/src/test/java/applica/app/test/configuration/TestConfiguration.java b/edera-api/api/src/test/java/applica/app/test/configuration/TestConfiguration.java new file mode 100644 index 0000000..a85ea0b --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/configuration/TestConfiguration.java @@ -0,0 +1,14 @@ +package applica.app.test.configuration; + +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.mail.MailSender; + +public class TestConfiguration { + + @Bean + public MailSender mailSender() { + return Mockito.mock(MailSender.class); + } + +} diff --git a/edera-api/api/src/test/java/applica/app/test/domain/docx/DocxBuilderTest.java b/edera-api/api/src/test/java/applica/app/test/domain/docx/DocxBuilderTest.java new file mode 100644 index 0000000..53ed32c --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/domain/docx/DocxBuilderTest.java @@ -0,0 +1,66 @@ +package applica.app.test.domain.docx; + +import applica.app.domain.docx.DocxBuilder; +import applica.app.domain.docx.DocxDataSource; +import applica.app.domain.docx.DocxException; +import org.junit.jupiter.api.*; + +import java.io.FileOutputStream; +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.*; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class DocxBuilderTest { + @Test + public void testGenerate() { + + var dataSource = new DocxDataSource(); + var row = dataSource.createRow(); + row.put("created", new Date().toString()); + row.put("number", "1"); + row.put("supply_name", "Test supply"); + row.put("activity_type_name", "Test activity type"); + row.put("description", "Test description"); + row.put("article", "Test article"); + row.put("reordered", "No"); + row.put("replaced", "Yes"); + + row = dataSource.createRow(); + row.put("created", new Date().toString()); + row.put("number", "2"); + row.put("supply_name", "Test supply 2"); + row.put("activity_type_name", "Test activity type 2"); + row.put("description", "Test description 2"); + row.put("article", "Test article 2"); + row.put("reordered", "Yes"); + row.put("replaced", "No"); + + assertDoesNotThrow(() -> exec("sample-google-workspace", dataSource)); + assertDoesNotThrow(() -> exec("sample-ms-office", dataSource)); + assertDoesNotThrow(() -> exec("sample-open-office", dataSource)); + assertThrows(DocxException.class, () -> exec("sample-ms-office-open-xml", dataSource)); + } + + private void exec(String template, DocxDataSource dataSource) throws DocxException { + + var jarPath = DocxBuilder.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + var cleanPath = jarPath.replace("/target/classes/", ""); + var rtfOut = String.format("%s/src/test/resources/out-%s.docx", cleanPath, template); + var rtfIn = String.format("%s/src/test/resources/%s.docx", cleanPath, template); + + try { + var builder = new DocxBuilder(); + var outputStream = builder.generate(rtfIn, dataSource); + assertNotNull(outputStream); + + var rtfOutStream = new FileOutputStream(rtfOut); + rtfOutStream.write(outputStream.readAllBytes()); + rtfOutStream.close(); + } + catch (Exception e) { + throw new DocxException(e.getMessage()); + } + } +} diff --git a/edera-api/api/src/test/java/applica/app/test/endtoend/IAMControllerTest.java b/edera-api/api/src/test/java/applica/app/test/endtoend/IAMControllerTest.java new file mode 100644 index 0000000..93672ae --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/endtoend/IAMControllerTest.java @@ -0,0 +1,245 @@ +package applica.app.test.endtoend; + +import applica.app.Application; +import applica.app.test.TestDataFactory; +import applica.app.test.configuration.TestConfiguration; +import applica.iam.domain.UsersRepository; +import applica.iam.sdk.ResponseCodes; +import applica.iam.sdk.requests.PinLoginRequest; +import applica.iam.sdk.requests.RegisterDeviceRequest; +import applica.iam.sdk.responses.PinLoginResponse; +import applica.iam.sdk.responses.RegisterDeviceResponse; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.SneakyThrows; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.util.StringUtils; +import org.springframework.web.context.WebApplicationContext; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(classes = { + TestConfiguration.class, + Application.class +}) +@ExtendWith({RestDocumentationExtension.class, SpringExtension.class}) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@ActiveProfiles("test") +public class IAMControllerTest { + private ObjectMapper mapper = new ObjectMapper(); + private MockMvc mvc; + @Autowired + private UsersRepository usersRepository; + + @Value("${app.test}") + boolean test; + + @BeforeAll + public void setUp(WebApplicationContext webApplicationContext) { + mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build(); + } + + @Test + @DisplayName("Test profile") + public void testProfile() { + assertTrue(test); + } + + @Test + @DisplayName("Should correctly register") + public void register() throws Exception { + var name = "test" + System.currentTimeMillis(); + mvc + .perform( + post("/iam/register") + .param("name", name) + .param("email", name + "@test.com") + .param("password", "testtest") + ) + .andExpect(status().isOk()); + } + @Test + @DisplayName("Should not login with incorrect credentials") + public void login() throws Exception { + mvc + .perform( + post("/iam/login") + .param("mail", "bimbobruno@gmail.com") + .param("password", "testtest") + ) + .andExpect(status().isUnauthorized()); + } + + @Test + @DisplayName("Should register and access to a protected url") + public void registerAndAccessProtectedUrl() throws Exception { + var name = "test" + String.valueOf(System.currentTimeMillis()); + var email = name + "@test.com"; + var password = "testtest"; + mvc + .perform( + post("/iam/register") + .param("name", name) + .param("email", email) + .param("password", password) + ) + .andExpect(status().isOk()); + + var user = usersRepository.findByUsername(email).orElseThrow(); + mvc + .perform( + post("/iam/activate") + .param("activationCode", user.getActivationCode()) + ) + .andExpect(status().isOk()); + + var mapper = new ObjectMapper(); + var loginResponse = mapper.readValue(mvc + .perform( + post("/iam/login") + .param("mail", email) + .param("password", password) + ) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsByteArray(), ObjectNode.class); + + mvc + .perform( + get("/tests/protected/user") + ) + .andExpect(status().isForbidden()); + + mvc + .perform( + get("/tests/protected/user") + .header("Authorization", "Bearer " + loginResponse.get("token").asText()) + ) + .andExpect(status().isOk()); + + mvc + .perform( + get("/tests/protected/admin") + .header("Authorization", "Bearer " + loginResponse.get("token").asText()) + ) + .andExpect(status().isForbidden()); + } + + @Test + @DisplayName("Should login with token") + public void tokenLogin() throws Exception { + var name = "test" + String.valueOf(System.currentTimeMillis()); + var email = name + "@test.com"; + var password = "testtest"; + mvc + .perform( + post("/iam/register") + .param("name", name) + .param("email", email) + .param("password", password) + ) + .andExpect(status().isOk()); + + var user = usersRepository.findByUsername(email).orElseThrow(); + mvc + .perform( + post("/iam/activate") + .param("activationCode", user.getActivationCode()) + ) + .andExpect(status().isOk()); + + var mapper = new ObjectMapper(); + var loginResponse = mapper.readValue(mvc + .perform( + post("/iam/login") + .param("mail", email) + .param("password", password) + ) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsByteArray(), ObjectNode.class); + + assertNotNull(loginResponse.get("token")); + + mvc + .perform( + post("/iam/token-login") + .param("token", loginResponse.get("token").asText()) + ) + .andExpect(status().isOk()); + + } + + @Test + @SneakyThrows + @DisplayName("Should register device") + public void testRegisterDevice() { + var deviceCode = UUID.randomUUID().toString(); + var registerDeviceRequest = new RegisterDeviceRequest(deviceCode); + var registerDeviceResponse = mvc.perform(post("/iam/register-device") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(registerDeviceRequest))) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); + + var registerDeviceResponseAsObject = mapper.readValue(registerDeviceResponse, RegisterDeviceResponse.class); + assertEquals(ResponseCodes.OK, registerDeviceResponseAsObject.getResponseCode()); + assertNotNull(registerDeviceResponseAsObject.getDevice()); + assertTrue(StringUtils.hasLength(registerDeviceResponseAsObject.getDevice().getSecret())); + } + + @Test + @SneakyThrows + @DisplayName("Double device registration should fail") + public void testDoubleDeviceRegistration() { + var deviceCode = UUID.randomUUID().toString(); + var device1Request = new RegisterDeviceRequest(deviceCode); + var device1Response = mvc.perform(post("/iam/register-device") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(device1Request))) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); + + var device1 = mapper.readValue(device1Response, RegisterDeviceResponse.class); + assertEquals(ResponseCodes.OK, device1.getResponseCode()); + assertNotNull(device1.getDevice()); + assertTrue(StringUtils.hasLength(device1.getDevice().getSecret())); + + var device2Response = mvc.perform(post("/iam/register-device") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(device1Request))) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); + + var device2 = mapper.readValue(device2Response, RegisterDeviceResponse.class); + assertEquals(device2.getDevice().getId(), device1.getDevice().getId()); + } + +} diff --git a/edera-api/api/src/test/java/applica/app/test/endtoend/RFIDDeviceTrackControllerTest.java b/edera-api/api/src/test/java/applica/app/test/endtoend/RFIDDeviceTrackControllerTest.java new file mode 100644 index 0000000..e5c9410 --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/endtoend/RFIDDeviceTrackControllerTest.java @@ -0,0 +1,102 @@ +package applica.app.test.endtoend; + +import applica.app.Application; +import applica.app.test.TestApplication; +import applica.app.test.configuration.TestConfiguration; +import applica.app.test.fixture.AreaFixture; +import applica.app.test.fixture.RFIDDeviceFixture; +import applica.app.test.fixture.SupplyFixture; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.requests.LoginRequest; +import com.github.javafaker.Faker; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.util.Base64; + +import static applica.iam.sdk.ResponseCodes.OK; +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(classes = { + TestConfiguration.class, + TestApplication.class, + Application.class +}) +@ExtendWith({RestDocumentationExtension.class, SpringExtension.class}) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@ActiveProfiles("test") +public class RFIDDeviceTrackControllerTest { + + private MockMvc mvc; + @Autowired + private IAMService iamService; + + @Autowired + private SupplyFixture supplyFixture; + @Autowired + private AreaFixture areaFixture; + @Autowired + private RFIDDeviceFixture rfidDeviceFixture; + + @BeforeAll + public void setUp(WebApplicationContext webApplicationContext) { + mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build(); + rfidDeviceFixture.setUp(); + areaFixture.setUp(); + supplyFixture.setUp(); + } + + @AfterAll + public void tearDown() { + rfidDeviceFixture.tearDown(); + areaFixture.tearDown(); + supplyFixture.tearDown(); + } + + @Test + @DisplayName("Should save a RFIDDeviceTrack") + public void testSaveARFIDDeviceTrack() throws Exception { + var fakeTag = rfidDeviceFixture.get(0); + var fakeGateway = rfidDeviceFixture.get(1); + + mvc.perform(get(String.format("/track?tag=%s×tamp=%d&gate=%s", + fakeTag.getCode(), + System.currentTimeMillis(), + fakeGateway.getCode()))) + .andExpect(status().isOk()); + + } + + @Test + @DisplayName("Should save a RFIDDeviceTrack with params") + public void testSaveARFIDDeviceTrackWithParams() throws Exception { + var fakeTag = rfidDeviceFixture.get(0); + var fakeGateway = rfidDeviceFixture.get(1); + var faker = new Faker(); + + mvc.perform(get(String.format("/track?tag=%s×tamp=%d&gate=%s&imei=%s&dragonball_character=%s", + fakeTag.getCode(), + System.currentTimeMillis(), + fakeGateway.getCode(), + faker.code().imei(), + faker.dragonBall().character()))) + .andExpect(status().isOk()); + + } +} diff --git a/edera-api/api/src/test/java/applica/app/test/fixture/AreaFixture.java b/edera-api/api/src/test/java/applica/app/test/fixture/AreaFixture.java new file mode 100644 index 0000000..2e00d8d --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/fixture/AreaFixture.java @@ -0,0 +1,39 @@ +package applica.app.test.fixture; + +import applica.app.domain.customer.Area; +import applica.crud.factory.CrudFactory; +import com.github.javafaker.Faker; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class AreaFixture extends Fixture{ + + final RFIDDeviceFixture rfidDeviceFixture; + public AreaFixture(CrudFactory crudFactory, RFIDDeviceFixture rfidDeviceFixture) { + super(crudFactory.createDataLayer(Area.class)); + this.rfidDeviceFixture = rfidDeviceFixture; + } + + @Override + public List prepareData() { + var list = new ArrayList(); + var faker = new Faker(); + var area = new Area(); + area.setName(faker.name().name()); + area.setDescription(faker.lorem().sentence()); + area.setCustomerId(faker.idNumber().validSvSeSsn()); + area.setOfficeId(faker.idNumber().validSvSeSsn()); + area.setRfidDeviceId(rfidDeviceFixture.get(1).getId()); + list.add(area); + + return list; + } + + @Override + public Object getId(Area entity) { + return entity.getId(); + } +} diff --git a/edera-api/api/src/test/java/applica/app/test/fixture/Fixture.java b/edera-api/api/src/test/java/applica/app/test/fixture/Fixture.java new file mode 100644 index 0000000..a8afdf8 --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/fixture/Fixture.java @@ -0,0 +1,59 @@ +package applica.app.test.fixture; + +import applica.crud.datalayer.DataLayer; +import lombok.Getter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.List; + + +public abstract class Fixture extends ArrayList { + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Getter + private DataLayer dataLayer; + + private boolean initialized = false; + + @Override + public T get(int index) { + if (!initialized) { + setUp(); + } + return super.get(index); + } + + public Fixture(DataLayer dataLayer) { + this.dataLayer = dataLayer; + } + + public abstract List prepareData(); + + public abstract Object getId(T entity); + + public void setUp() { + if (initialized) { + return; + } + logger.debug("Setting up {}", getClass().getName()); + var entitiesToCreate = prepareData(); + for (var entity : entitiesToCreate) { + dataLayer.save(entity); + add(entity); + } + Assert.isTrue(entitiesToCreate.size() == size(), "Entities created are not the same of entities added to fixture"); + initialized = true; + } + + public void tearDown() { + logger.debug("Tearing down {}", getClass().getName()); + for (var entity : this) { + dataLayer.delete(getId(entity)); + } + clear(); + initialized = false; + } +} \ No newline at end of file diff --git a/edera-api/api/src/test/java/applica/app/test/fixture/RFIDDeviceFixture.java b/edera-api/api/src/test/java/applica/app/test/fixture/RFIDDeviceFixture.java new file mode 100644 index 0000000..454dd38 --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/fixture/RFIDDeviceFixture.java @@ -0,0 +1,39 @@ +package applica.app.test.fixture; + +import applica.app.domain.rfid.RFIDDevice; +import applica.app.domain.rfid.RFIDDeviceType; +import applica.crud.factory.CrudFactory; +import com.github.javafaker.Faker; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class RFIDDeviceFixture extends Fixture{ + public RFIDDeviceFixture(CrudFactory crudFactory) { + super(crudFactory.createDataLayer(RFIDDevice.class)); + } + + @Override + public List prepareData() { + var faker = new Faker(); + var list = new ArrayList(); + var tag = new RFIDDevice(); + tag.setCode("123456789"); + tag.setType(RFIDDeviceType.TAG); + tag.setName(faker.name().name()); + list.add(tag); + var gateway = new RFIDDevice(); + gateway.setCode("987654321"); + gateway.setType(RFIDDeviceType.GATEWAY); + gateway.setName(faker.name().name()); + list.add(gateway); + return list; + } + + @Override + public Object getId(RFIDDevice entity) { + return entity.getId(); + } +} diff --git a/edera-api/api/src/test/java/applica/app/test/fixture/SupplyFixture.java b/edera-api/api/src/test/java/applica/app/test/fixture/SupplyFixture.java new file mode 100644 index 0000000..1d4d670 --- /dev/null +++ b/edera-api/api/src/test/java/applica/app/test/fixture/SupplyFixture.java @@ -0,0 +1,63 @@ +package applica.app.test.fixture; + +import applica.app.domain.supply.Supply; +import applica.app.domain.supply.UsageStatus; +import applica.crud.factory.CrudFactory; +import com.github.javafaker.Faker; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +@Component +public class SupplyFixture extends Fixture{ + + final RFIDDeviceFixture rfidDeviceFixture; + final AreaFixture areaFixture; + public SupplyFixture(CrudFactory crudFactory, RFIDDeviceFixture rfidDeviceFixture, AreaFixture areaFixture) { + super(crudFactory.createDataLayer(Supply.class)); + this.rfidDeviceFixture = rfidDeviceFixture; + this.areaFixture = areaFixture; + } + + @Override + public List prepareData() { + var list = new ArrayList(); + var faker = new Faker(); + var supplyTag = new Supply(); + supplyTag.setRfidDeviceId(rfidDeviceFixture.get(0).getId()); + supplyTag.setUsageId(faker.idNumber().validSvSeSsn()); + supplyTag.setDdtNumber(faker.numerify("DDT-###")); + supplyTag.setUsageStatus(UsageStatus.STOPPED); + supplyTag.setDeliveryDate(LocalDate.now()); + supplyTag.setEquipmentId(faker.idNumber().validSvSeSsn()); + supplyTag.setSupplierId(faker.idNumber().validSvSeSsn()); + supplyTag.setQuantity(faker.number().randomDigit()); + supplyTag.setProtocolId(faker.idNumber().validSvSeSsn()); + supplyTag.setOrderDate(LocalDate.now()); + supplyTag.setSerialNumber(faker.numerify("SN-###")); + list.add(supplyTag); + + var supplyArea = new Supply(); + supplyArea.setUsageId(faker.idNumber().validSvSeSsn()); + supplyArea.setDdtNumber(faker.numerify("DDT-###")); + supplyArea.setUsageStatus(UsageStatus.STOPPED); + supplyArea.setDeliveryDate(LocalDate.now()); + supplyArea.setEquipmentId(faker.idNumber().validSvSeSsn()); + supplyArea.setSupplierId(faker.idNumber().validSvSeSsn()); + supplyArea.setQuantity(faker.number().randomDigit()); + supplyArea.setAreaId(areaFixture.get(0).getId()); + supplyArea.setProtocolId(faker.idNumber().validSvSeSsn()); + supplyArea.setOrderDate(LocalDate.now()); + supplyArea.setSerialNumber(faker.numerify("SN-###")); + list.add(supplyArea); + + return list; + } + + @Override + public Object getId(Supply entity) { + return entity.getId(); + } +} diff --git a/edera-api/api/src/test/resources/i18n.json b/edera-api/api/src/test/resources/i18n.json new file mode 100644 index 0000000..c82094e --- /dev/null +++ b/edera-api/api/src/test/resources/i18n.json @@ -0,0 +1,1721 @@ +[ { + "id" : "it.Forbidden", + "code" : "Forbidden", + "lang" : "it", + "text" : "Accesso non consentito" +}, { + "id" : "it.app.date_format.long", + "code" : "app.date_format.long", + "lang" : "it", + "text" : "DD/MM/YYYY, HH:mm:ss" +}, { + "id" : "it.app.input.max_length_info", + "code" : "app.input.max_length_info", + "lang" : "it", + "text" : "Usati %{count} su %{max} caratteri disponibili (spazi inclusi)" +}, { + "id" : "it.app.label.day", + "code" : "app.label.day", + "lang" : "it", + "text" : "Data" +}, { + "id" : "it.app.label.end_at", + "code" : "app.label.end_at", + "lang" : "it", + "text" : "Alla data" +}, { + "id" : "it.app.welcome", + "code" : "app.welcome", + "lang" : "it", + "text" : "Benvenuto %{full_name}" +}, { + "id" : "it.crud.error.serialization", + "code" : "crud.error.serialization", + "lang" : "it", + "text" : "Errore nella serializzazione dei dati" +}, { + "id" : "it.error.validation", + "code" : "error.validation", + "lang" : "it", + "text" : "Errore di validazione" +}, { + "id" : "it.iam.error.email-address-already-exists", + "code" : "iam.error.email-address-already-exists", + "lang" : "it", + "text" : "Indirizzo e-mail già utilizzato" +}, { + "id" : "it.menu.groups.admin", + "code" : "menu.groups.admin", + "lang" : "it", + "text" : "Amministrazione" +}, { + "id" : "it.menu.items.command-logs", + "code" : "menu.items.command-logs", + "lang" : "it", + "text" : "Comandi (Logs)" +}, { + "id" : "it.menu.items.entities/i18n-message", + "code" : "menu.items.entities/i18n-message", + "lang" : "it", + "text" : "Messaggi (i18n)" +}, { + "id" : "it.menu.items.entities/notification", + "code" : "menu.items.entities/notification", + "lang" : "it", + "text" : "Notifiche" +}, { + "id" : "it.menu.items.entities/user", + "code" : "menu.items.entities/user", + "lang" : "it", + "text" : "Utenti" +}, { + "id" : "it.menu.items.notifications", + "code" : "menu.items.notifications", + "lang" : "it", + "text" : "Notifiche" +}, { + "id" : "it.menu.items.users", + "code" : "menu.items.users", + "lang" : "it", + "text" : "Utenti" +}, { + "id" : "it.ra.action.add", + "code" : "ra.action.add", + "lang" : "it", + "text" : "Aggiungi" +}, { + "id" : "it.ra.action.add_filter", + "code" : "ra.action.add_filter", + "lang" : "it", + "text" : "Filtri" +}, { + "id" : "it.ra.action.all", + "code" : "ra.action.all", + "lang" : "it", + "text" : "(Tutti)" +}, { + "id" : "it.ra.action.back", + "code" : "ra.action.back", + "lang" : "it", + "text" : "Indietro" +}, { + "id" : "it.ra.action.bulk_actions", + "code" : "ra.action.bulk_actions", + "lang" : "it", + "text" : "%{smart_count} selezionati" +}, { + "id" : "it.ra.action.cancel", + "code" : "ra.action.cancel", + "lang" : "it", + "text" : "Annulla" +}, { + "id" : "it.ra.action.clear_array_input", + "code" : "ra.action.clear_array_input", + "lang" : "it", + "text" : "Rimuovi tutti gli elementi" +}, { + "id" : "it.ra.action.clear_input_value", + "code" : "ra.action.clear_input_value", + "lang" : "it", + "text" : "Svuota il modulo" +}, { + "id" : "it.ra.action.clone", + "code" : "ra.action.clone", + "lang" : "it", + "text" : "Duplica" +}, { + "id" : "it.ra.action.close", + "code" : "ra.action.close", + "lang" : "it", + "text" : "Chiudi" +}, { + "id" : "it.ra.action.close_menu", + "code" : "ra.action.close_menu", + "lang" : "it", + "text" : "Chiudi il menu" +}, { + "id" : "it.ra.action.confirm", + "code" : "ra.action.confirm", + "lang" : "it", + "text" : "Conferma" +}, { + "id" : "it.ra.action.create", + "code" : "ra.action.create", + "lang" : "it", + "text" : "Crea" +}, { + "id" : "it.ra.action.delete", + "code" : "ra.action.delete", + "lang" : "it", + "text" : "Cancella" +}, { + "id" : "it.ra.action.edit", + "code" : "ra.action.edit", + "lang" : "it", + "text" : "Modifica" +}, { + "id" : "it.ra.action.expand", + "code" : "ra.action.expand", + "lang" : "it", + "text" : "Espandi" +}, { + "id" : "it.ra.action.export", + "code" : "ra.action.export", + "lang" : "it", + "text" : "Esporta" +}, { + "id" : "it.ra.action.list", + "code" : "ra.action.list", + "lang" : "it", + "text" : "Elenco" +}, { + "id" : "it.ra.action.next", + "code" : "ra.action.next", + "lang" : "it", + "text" : "Prosegui" +}, { + "id" : "it.ra.action.open_menu", + "code" : "ra.action.open_menu", + "lang" : "it", + "text" : "Apri il menu" +}, { + "id" : "it.ra.action.refresh", + "code" : "ra.action.refresh", + "lang" : "it", + "text" : "Aggiorna" +}, { + "id" : "it.ra.action.remove", + "code" : "ra.action.remove", + "lang" : "it", + "text" : "Rimuovi" +}, { + "id" : "it.ra.action.remove_filter", + "code" : "ra.action.remove_filter", + "lang" : "it", + "text" : "Rimuovi questo filtro" +}, { + "id" : "it.ra.action.save", + "code" : "ra.action.save", + "lang" : "it", + "text" : "Salva" +}, { + "id" : "it.ra.action.search", + "code" : "ra.action.search", + "lang" : "it", + "text" : "Ricerca" +}, { + "id" : "it.ra.action.show", + "code" : "ra.action.show", + "lang" : "it", + "text" : "Mostra" +}, { + "id" : "it.ra.action.sort", + "code" : "ra.action.sort", + "lang" : "it", + "text" : "Ordina" +}, { + "id" : "it.ra.action.undo", + "code" : "ra.action.undo", + "lang" : "it", + "text" : "Annulla" +}, { + "id" : "it.ra.action.unselect", + "code" : "ra.action.unselect", + "lang" : "it", + "text" : "Annulla selezione" +}, { + "id" : "it.ra.action.view_all", + "code" : "ra.action.view_all", + "lang" : "it", + "text" : "Visualizza Tutto" +}, { + "id" : "it.ra.active.false", + "code" : "ra.active.false", + "lang" : "it", + "text" : "Disattivata" +}, { + "id" : "it.ra.active.true", + "code" : "ra.active.true", + "lang" : "it", + "text" : "Attiva" +}, { + "id" : "it.ra.attachment.info", + "code" : "ra.attachment.info", + "lang" : "it", + "text" : "Creato da %{user} %{created}" +}, { + "id" : "it.ra.audit-log.entities/create", + "code" : "ra.audit-log.entities/create", + "lang" : "it", + "text" : "Creata entità di tipo %{entity}" +}, { + "id" : "it.ra.audit-log.entities/edit", + "code" : "ra.audit-log.entities/edit", + "lang" : "it", + "text" : "Modificata entità di tipo %{entity} con id %{id}" +}, { + "id" : "it.ra.audit-log.entities/find", + "code" : "ra.audit-log.entities/find", + "lang" : "it", + "text" : "Ricerca per %{entity}" +}, { + "id" : "it.ra.audit-log.entities/get", + "code" : "ra.audit-log.entities/get", + "lang" : "it", + "text" : "Visualizzata entità %{entity} con id %{id}" +}, { + "id" : "it.ra.audit-log.entities/post", + "code" : "ra.audit-log.entities/post", + "lang" : "it", + "text" : "Creata nuova entità di tipo %{entity}" +}, { + "id" : "it.ra.audit_log.default_explanation", + "code" : "ra.audit_log.default_explanation", + "lang" : "it", + "text" : "Operazione non identificata" +}, { + "id" : "it.ra.audit_log.default_message", + "code" : "ra.audit_log.default_message", + "lang" : "it", + "text" : "Eseguita chiamata %{method} su %{url}" +}, { + "id" : "it.ra.auth.account", + "code" : "ra.auth.account", + "lang" : "it", + "text" : "Username o email" +}, { + "id" : "it.ra.auth.activate", + "code" : "ra.auth.activate", + "lang" : "it", + "text" : "Attivazione Account" +}, { + "id" : "it.ra.auth.activate_pending", + "code" : "ra.auth.activate_pending", + "lang" : "it", + "text" : "Verifica dell'account in corso..." +}, { + "id" : "it.ra.auth.activate_success", + "code" : "ra.auth.activate_success", + "lang" : "it", + "text" : "Account attivato correttamente" +}, { + "id" : "it.ra.auth.already_have_account", + "code" : "ra.auth.already_have_account", + "lang" : "it", + "text" : "Hai già un account?" +}, { + "id" : "it.ra.auth.auth_check_error", + "code" : "ra.auth.auth_check_error", + "lang" : "it", + "text" : "E' necessario accedere per continuare" +}, { + "id" : "it.ra.auth.back_to_login", + "code" : "ra.auth.back_to_login", + "lang" : "it", + "text" : "Torna al login" +}, { + "id" : "it.ra.auth.change_password", + "code" : "ra.auth.change_password", + "lang" : "it", + "text" : "Cambia Password" +}, { + "id" : "it.ra.auth.create_account", + "code" : "ra.auth.create_account", + "lang" : "it", + "text" : "Registrati" +}, { + "id" : "it.ra.auth.forgot_password", + "code" : "ra.auth.forgot_password", + "lang" : "it", + "text" : "Password dimenticata?" +}, { + "id" : "it.ra.auth.impersonating.undo", + "code" : "ra.auth.impersonating.undo", + "lang" : "it", + "text" : "Smetti di impersonate %{name}" +}, { + "id" : "it.ra.auth.impersonating.undo.short", + "code" : "ra.auth.impersonating.undo.short", + "lang" : "it", + "text" : "Esci da %{name}" +}, { + "id" : "it.ra.auth.login.spid", + "code" : "ra.auth.login.spid", + "lang" : "it", + "text" : "Entra con SPID/CIE/CNS" +}, { + "id" : "it.ra.auth.logout", + "code" : "ra.auth.logout", + "lang" : "it", + "text" : "Disconnessione" +}, { + "id" : "it.ra.auth.password", + "code" : "ra.auth.password", + "lang" : "it", + "text" : "Password" +}, { + "id" : "it.ra.auth.password_changed", + "code" : "ra.auth.password_changed", + "lang" : "it", + "text" : "Password aggiornata correttamente" +}, { + "id" : "it.ra.auth.password_placeholder", + "code" : "ra.auth.password_placeholder", + "lang" : "it", + "text" : "La tua password" +}, { + "id" : "it.ra.auth.password_reset.button", + "code" : "ra.auth.password_reset.button", + "lang" : "it", + "text" : "Reimposta" +}, { + "id" : "it.ra.auth.password_reset.title", + "code" : "ra.auth.password_reset.title", + "lang" : "it", + "text" : "Reimposta password" +}, { + "id" : "it.ra.auth.recover", + "code" : "ra.auth.recover", + "lang" : "it", + "text" : "Invia E-mail conferma reset password" +}, { + "id" : "it.ra.auth.recover.inbox_help", + "code" : "ra.auth.recover.inbox_help", + "lang" : "it", + "text" : "Ricorda di controllare la cartella SPAM" +}, { + "id" : "it.ra.auth.recover.title", + "code" : "ra.auth.recover.title", + "lang" : "it", + "text" : "Recupera Password" +}, { + "id" : "it.ra.auth.recover_ok", + "code" : "ra.auth.recover_ok", + "lang" : "it", + "text" : "Recupero password eseguito, contorlla la tua e-mail" +}, { + "id" : "it.ra.auth.register", + "code" : "ra.auth.register", + "lang" : "it", + "text" : "Non hai ancora un account?" +}, { + "id" : "it.ra.auth.register.title", + "code" : "ra.auth.register.title", + "lang" : "it", + "text" : "Registrati" +}, { + "id" : "it.ra.auth.register_iam.error.email-address-already-exists", + "code" : "ra.auth.register_iam.error.email-address-already-exists", + "lang" : "it", + "text" : "Non è possibile utilizzare questo indirizzo e-mail" +}, { + "id" : "it.ra.auth.register_iam.error.email-not-valid", + "code" : "ra.auth.register_iam.error.email-not-valid", + "lang" : "it", + "text" : "L'indirizzo e-mail inserito non è valido" +}, { + "id" : "it.ra.auth.register_ok", + "code" : "ra.auth.register_ok", + "lang" : "it", + "text" : "Registrazione avvenuta correttamente, controlla la tua e-mail per confermare i dati inseriti" +}, { + "id" : "it.ra.auth.reset_password", + "code" : "ra.auth.reset_password", + "lang" : "it", + "text" : "Recupera Password" +}, { + "id" : "it.ra.auth.sign_in", + "code" : "ra.auth.sign_in", + "lang" : "it", + "text" : "Login" +}, { + "id" : "it.ra.auth.sign_in_error", + "code" : "ra.auth.sign_in_error", + "lang" : "it", + "text" : "Autenticazione fallita, riprovare." +}, { + "id" : "it.ra.auth.sign_in_success", + "code" : "ra.auth.sign_in_success", + "lang" : "it", + "text" : "Utente impersona con successo, ricaricamento pagina in corso..." +}, { + "id" : "it.ra.auth.sign_out_success", + "code" : "ra.auth.sign_out_success", + "lang" : "it", + "text" : "Logout da altro utente eseguito con successo, ricaricamento pagina in corso..." +}, { + "id" : "it.ra.auth.stop_impersonate", + "code" : "ra.auth.stop_impersonate", + "lang" : "it", + "text" : "Smetti di impersonare" +}, { + "id" : "it.ra.auth.user_menu", + "code" : "ra.auth.user_menu", + "lang" : "it", + "text" : "Profilo" +}, { + "id" : "it.ra.auth.username", + "code" : "ra.auth.username", + "lang" : "it", + "text" : "Nome utente" +}, { + "id" : "it.ra.boolean.false", + "code" : "ra.boolean.false", + "lang" : "it", + "text" : "No" +}, { + "id" : "it.ra.boolean.null", + "code" : "ra.boolean.null", + "lang" : "it", + "text" : "(Tutti)" +}, { + "id" : "it.ra.boolean.true", + "code" : "ra.boolean.true", + "lang" : "it", + "text" : "Si" +}, { + "id" : "it.ra.custom_pages.welcome.subtitle", + "code" : "ra.custom_pages.welcome.subtitle", + "lang" : "it", + "text" : "Utilizza le voci di menu a sinistra per navigare ed usufruire delle funzioni applicative." +}, { + "id" : "it.ra.custom_pages.welcome.title", + "code" : "ra.custom_pages.welcome.title", + "lang" : "it", + "text" : "Ciao!" +}, { + "id" : "it.ra.error.equipment-type.delete", + "code" : "ra.error.equipment-type.delete", + "lang" : "it", + "text" : "Impossibile eliminare il Tipo di Attrezzatura" +}, { + "id" : "it.ra.error.supplier.delete", + "code" : "ra.error.supplier.delete", + "lang" : "it", + "text" : "Impossibile eliminare il Fornitore" +}, { + "id" : "it.ra.image.upload_several", + "code" : "ra.image.upload_several", + "lang" : "it", + "text" : "Trascina le immagini da caricare, oppure clicca per selezionarle." +}, { + "id" : "it.ra.image.upload_single", + "code" : "ra.image.upload_single", + "lang" : "it", + "text" : "Trascina l'immagine da caricare, oppure clicca per selezionarla." +}, { + "id" : "it.ra.input.file.upload_several", + "code" : "ra.input.file.upload_several", + "lang" : "it", + "text" : "Trascina i files da caricare, oppure clicca per selezionare." +}, { + "id" : "it.ra.input.file.upload_single", + "code" : "ra.input.file.upload_single", + "lang" : "it", + "text" : "Trascina il file da caricare, oppure clicca per selezionarlo." +}, { + "id" : "it.ra.input.image.upload_single", + "code" : "ra.input.image.upload_single", + "lang" : "it", + "text" : "Seleziona o sposta qui il file da caricare" +}, { + "id" : "it.ra.input.password.toggle_hidden", + "code" : "ra.input.password.toggle_hidden", + "lang" : "it", + "text" : "Nascondi Password" +}, { + "id" : "it.ra.input.password.toggle_visible", + "code" : "ra.input.password.toggle_visible", + "lang" : "it", + "text" : "Mostra Password" +}, { + "id" : "it.ra.menu.control-panel", + "code" : "ra.menu.control-panel", + "lang" : "it", + "text" : "Impostazioni" +}, { + "id" : "it.ra.menu.custom_pages", + "code" : "ra.menu.custom_pages", + "lang" : "it", + "text" : "Dashboard" +}, { + "id" : "it.ra.menu.dashboard", + "code" : "ra.menu.dashboard", + "lang" : "it", + "text" : "Dashboard" +}, { + "id" : "it.ra.menu.item.custom_page", + "code" : "ra.menu.item.custom_page", + "lang" : "it", + "text" : "Home" +}, { + "id" : "it.ra.menu.item.entities/audit-log", + "code" : "ra.menu.item.entities/audit-log", + "lang" : "it", + "text" : "Audit Log" +}, { + "id" : "it.ra.menu.item.entities/customer", + "code" : "ra.menu.item.entities/customer", + "lang" : "it", + "text" : "Clienti" +}, { + "id" : "it.ra.menu.item.entities/device", + "code" : "ra.menu.item.entities/device", + "lang" : "it", + "text" : "Dispositivi" +}, { + "id" : "it.ra.menu.item.entities/equipment-type", + "code" : "ra.menu.item.entities/equipment-type", + "lang" : "it", + "text" : "Tipi Attrezzatura" +}, { + "id" : "it.ra.menu.item.entities/i18n-message", + "code" : "ra.menu.item.entities/i18n-message", + "lang" : "it", + "text" : "Messaggi (i18n)" +}, { + "id" : "it.ra.menu.item.entities/intervention-type", + "code" : "ra.menu.item.entities/intervention-type", + "lang" : "it", + "text" : "Tipi Intervento" +}, { + "id" : "it.ra.menu.item.entities/notification", + "code" : "ra.menu.item.entities/notification", + "lang" : "it", + "text" : "Notifiche" +}, { + "id" : "it.ra.menu.item.entities/rfid-device", + "code" : "ra.menu.item.entities/rfid-device", + "lang" : "it", + "text" : "Dispositivi RFID" +}, { + "id" : "it.ra.menu.item.entities/user", + "code" : "ra.menu.item.entities/user", + "lang" : "it", + "text" : "Utenti" +}, { + "id" : "it.ra.menu.item.notification", + "code" : "ra.menu.item.notification", + "lang" : "it", + "text" : "Notifiche" +}, { + "id" : "it.ra.menu.item.supplier", + "code" : "ra.menu.item.supplier", + "lang" : "it", + "text" : "Fornitori" +}, { + "id" : "it.ra.menu.maintenance", + "code" : "ra.menu.maintenance", + "lang" : "it", + "text" : "Manutenzione" +}, { + "id" : "it.ra.menu.security", + "code" : "ra.menu.security", + "lang" : "it", + "text" : "Sicurezza" +}, { + "id" : "it.ra.message.about", + "code" : "ra.message.about", + "lang" : "it", + "text" : "Informazioni" +}, { + "id" : "it.ra.message.are_you_sure", + "code" : "ra.message.are_you_sure", + "lang" : "it", + "text" : "Sei sicuro?" +}, { + "id" : "it.ra.message.bulk_delete_content", + "code" : "ra.message.bulk_delete_content", + "lang" : "it", + "text" : "Sei sicuro di voler cancellare questo %{name}? |||| Sei sicuro di voler eliminare questi %{smart_count}?" +}, { + "id" : "it.ra.message.bulk_delete_title", + "code" : "ra.message.bulk_delete_title", + "lang" : "it", + "text" : "Delete %{name} |||| Delete %{smart_count} %{name} items" +}, { + "id" : "it.ra.message.clear_array_input", + "code" : "ra.message.clear_array_input", + "lang" : "it", + "text" : "Sei sicuro di voler rimuovere tutti gli elementi?" +}, { + "id" : "it.ra.message.confirm_delete", + "code" : "ra.message.confirm_delete", + "lang" : "it", + "text" : "Sei sicuro di voler cancellare questo elemento?" +}, { + "id" : "it.ra.message.delete_content", + "code" : "ra.message.delete_content", + "lang" : "it", + "text" : "Sicuro di voler cancellare questo elemento?" +}, { + "id" : "it.ra.message.delete_title", + "code" : "ra.message.delete_title", + "lang" : "it", + "text" : "Conferma cancellazione" +}, { + "id" : "it.ra.message.details", + "code" : "ra.message.details", + "lang" : "it", + "text" : "Dettagli" +}, { + "id" : "it.ra.message.error", + "code" : "ra.message.error", + "lang" : "it", + "text" : "Si è verificato un errore locale per cui non è stato possibile completare l'operazione. " +}, { + "id" : "it.ra.message.invalid_form", + "code" : "ra.message.invalid_form", + "lang" : "it", + "text" : "Il modulo non è valido. Si prega di verificare la presenza di errori." +}, { + "id" : "it.ra.message.loading", + "code" : "ra.message.loading", + "lang" : "it", + "text" : "La pagina si sta caricando, solo un momento per favore" +}, { + "id" : "it.ra.message.no", + "code" : "ra.message.no", + "lang" : "it", + "text" : "No" +}, { + "id" : "it.ra.message.not_found", + "code" : "ra.message.not_found", + "lang" : "it", + "text" : "Hai inserito un URL errato, oppure hai cliccato un link errato" +}, { + "id" : "it.ra.message.profile_updated", + "code" : "ra.message.profile_updated", + "lang" : "it", + "text" : "Profilo aggiornato correttamente" +}, { + "id" : "it.ra.message.unsaved_changes", + "code" : "ra.message.unsaved_changes", + "lang" : "it", + "text" : "Alcune modifiche non sono state salvate. Sei sicuro di volerle ignorare?" +}, { + "id" : "it.ra.message.yes", + "code" : "ra.message.yes", + "lang" : "it", + "text" : "Si" +}, { + "id" : "it.ra.navigation.next", + "code" : "ra.navigation.next", + "lang" : "it", + "text" : "Successivo" +}, { + "id" : "it.ra.navigation.no_more_results", + "code" : "ra.navigation.no_more_results", + "lang" : "it", + "text" : "La pagina numero %{page} è fuori dall'intervallo. Prova la pagina precedente." +}, { + "id" : "it.ra.navigation.no_results", + "code" : "ra.navigation.no_results", + "lang" : "it", + "text" : "Nessun risultato trovato" +}, { + "id" : "it.ra.navigation.page_out_from_begin", + "code" : "ra.navigation.page_out_from_begin", + "lang" : "it", + "text" : "Il numero di pagina deve essere maggiore di 1" +}, { + "id" : "it.ra.navigation.page_out_from_end", + "code" : "ra.navigation.page_out_from_end", + "lang" : "it", + "text" : "Fine della paginazione" +}, { + "id" : "it.ra.navigation.page_out_of_boundaries", + "code" : "ra.navigation.page_out_of_boundaries", + "lang" : "it", + "text" : "Il numero di pagina %{page} è fuori dei limiti" +}, { + "id" : "it.ra.navigation.page_range_info", + "code" : "ra.navigation.page_range_info", + "lang" : "it", + "text" : "%{offsetBegin}-%{offsetEnd} di %{total}" +}, { + "id" : "it.ra.navigation.page_rows_per_page", + "code" : "ra.navigation.page_rows_per_page", + "lang" : "it", + "text" : "Righe per pagina" +}, { + "id" : "it.ra.navigation.prev", + "code" : "ra.navigation.prev", + "lang" : "it", + "text" : "Precedente" +}, { + "id" : "it.ra.navigation.skip_nav", + "code" : "ra.navigation.skip_nav", + "lang" : "it", + "text" : "Vai al contenuto" +}, { + "id" : "it.ra.no", + "code" : "ra.no", + "lang" : "it", + "text" : "No" +}, { + "id" : "it.ra.no_results", + "code" : "ra.no_results", + "lang" : "it", + "text" : "Nessun elemento registrato." +}, { + "id" : "it.ra.notification", + "code" : "ra.notification", + "lang" : "it", + "text" : "Notifica" +}, { + "id" : "it.ra.notification.bad_item", + "code" : "ra.notification.bad_item", + "lang" : "it", + "text" : "Record errato" +}, { + "id" : "it.ra.notification.canceled", + "code" : "ra.notification.canceled", + "lang" : "it", + "text" : "Azione annullata" +}, { + "id" : "it.ra.notification.created", + "code" : "ra.notification.created", + "lang" : "it", + "text" : "Salvataggio eseguito" +}, { + "id" : "it.ra.notification.data_provider_error", + "code" : "ra.notification.data_provider_error", + "lang" : "it", + "text" : "Errore del data provider. Controlla la console per i dettagli." +}, { + "id" : "it.ra.notification.deleted", + "code" : "ra.notification.deleted", + "lang" : "it", + "text" : "Record eliminato |||| %{smart_count} records eliminati" +}, { + "id" : "it.ra.notification.http_error", + "code" : "ra.notification.http_error", + "lang" : "it", + "text" : "Errore di comunicazione con il server dati" +}, { + "id" : "it.ra.notification.i18n_error", + "code" : "ra.notification.i18n_error", + "lang" : "it", + "text" : "Traduzioni non trovate per il linguaggio specificato" +}, { + "id" : "it.ra.notification.item_doesnt_exist", + "code" : "ra.notification.item_doesnt_exist", + "lang" : "it", + "text" : "Record inesistente" +}, { + "id" : "it.ra.notification.logged_out", + "code" : "ra.notification.logged_out", + "lang" : "it", + "text" : "La sessione è stata terminata, si prega di ripetere l'autenticazione." +}, { + "id" : "it.ra.notification.mark_as_readed", + "code" : "ra.notification.mark_as_readed", + "lang" : "it", + "text" : "Segna come letto" +}, { + "id" : "it.ra.notification.mark_as_unreaded", + "code" : "ra.notification.mark_as_unreaded", + "lang" : "it", + "text" : "Segna come non letto" +}, { + "id" : "it.ra.notification.readed", + "code" : "ra.notification.readed", + "lang" : "it", + "text" : "Letta in data %{readed}" +}, { + "id" : "it.ra.notification.readed_error", + "code" : "ra.notification.readed_error", + "lang" : "it", + "text" : "Impossibile segnare le notifiche selezionate." +}, { + "id" : "it.ra.notification.unreaded", + "code" : "ra.notification.unreaded", + "lang" : "it", + "text" : "Non lette" +}, { + "id" : "it.ra.notification.updated", + "code" : "ra.notification.updated", + "lang" : "it", + "text" : "Record aggiornato |||| %{smart_count} records aggiornati" +}, { + "id" : "it.ra.notifications.read_all", + "code" : "ra.notifications.read_all", + "lang" : "it", + "text" : "Segna tutte come lette" +}, { + "id" : "it.ra.notifications.title", + "code" : "ra.notifications.title", + "lang" : "it", + "text" : "Notifiche" +}, { + "id" : "it.ra.page.create", + "code" : "ra.page.create", + "lang" : "it", + "text" : "Aggiungi %{name}" +}, { + "id" : "it.ra.page.dashboard", + "code" : "ra.page.dashboard", + "lang" : "it", + "text" : "Cruscotto" +}, { + "id" : "it.ra.page.edit", + "code" : "ra.page.edit", + "lang" : "it", + "text" : "%{name} %{id}" +}, { + "id" : "it.ra.page.empty", + "code" : "ra.page.empty", + "lang" : "it", + "text" : "Nessun dato caricato per %{name}" +}, { + "id" : "it.ra.page.error", + "code" : "ra.page.error", + "lang" : "it", + "text" : "Qualcosa non ha funzionato" +}, { + "id" : "it.ra.page.invite", + "code" : "ra.page.invite", + "lang" : "it", + "text" : "Vuoi aggiungerne uno?" +}, { + "id" : "it.ra.page.list", + "code" : "ra.page.list", + "lang" : "it", + "text" : "%{name}" +}, { + "id" : "it.ra.page.loading", + "code" : "ra.page.loading", + "lang" : "it", + "text" : "Caricamento in corso" +}, { + "id" : "it.ra.page.not_found", + "code" : "ra.page.not_found", + "lang" : "it", + "text" : "Non trovato" +}, { + "id" : "it.ra.page.profile.title", + "code" : "ra.page.profile.title", + "lang" : "it", + "text" : "Informazioni profilo" +}, { + "id" : "it.ra.page.show", + "code" : "ra.page.show", + "lang" : "it", + "text" : "%{name} %{id}" +}, { + "id" : "it.ra.password.toggle_hidden", + "code" : "ra.password.toggle_hidden", + "lang" : "it", + "text" : "Mostra la password" +}, { + "id" : "it.ra.password.toggle_visible", + "code" : "ra.password.toggle_visible", + "lang" : "it", + "text" : "Nascondi la password" +}, { + "id" : "it.ra.reference_list.sorry", + "code" : "ra.reference_list.sorry", + "lang" : "it", + "text" : "Salva almeno una volta l'elemento corrente per poter aggiungere nuove informazioni in questa sezione." +}, { + "id" : "it.ra.references.all_missing", + "code" : "ra.references.all_missing", + "lang" : "it", + "text" : "Impossibile trovare i riferimenti associati." +}, { + "id" : "it.ra.references.many_missing", + "code" : "ra.references.many_missing", + "lang" : "it", + "text" : "Almeno uno dei riferimenti associati non sembra più disponibile." +}, { + "id" : "it.ra.references.single_missing", + "code" : "ra.references.single_missing", + "lang" : "it", + "text" : "Il riferimento associato non sembra più disponibile." +}, { + "id" : "it.ra.register.name", + "code" : "ra.register.name", + "lang" : "it", + "text" : "Nome Account" +}, { + "id" : "it.ra.roles.admin", + "code" : "ra.roles.admin", + "lang" : "it", + "text" : "Amministratore" +}, { + "id" : "it.ra.roles.mantainer", + "code" : "ra.roles.mantainer", + "lang" : "it", + "text" : "Manutentore" +}, { + "id" : "it.ra.roles.operator", + "code" : "ra.roles.operator", + "lang" : "it", + "text" : "Operatore" +}, { + "id" : "it.ra.roles.user", + "code" : "ra.roles.user", + "lang" : "it", + "text" : "Utilizzatore" +}, { + "id" : "it.ra.sort.ASC", + "code" : "ra.sort.ASC", + "lang" : "it", + "text" : "cresente" +}, { + "id" : "it.ra.sort.DESC", + "code" : "ra.sort.DESC", + "lang" : "it", + "text" : "decrescente" +}, { + "id" : "it.ra.sort.sort_by", + "code" : "ra.sort.sort_by", + "lang" : "it", + "text" : "Ordina per %{field} %{order}" +}, { + "id" : "it.ra.title.confirm_delete", + "code" : "ra.title.confirm_delete", + "lang" : "it", + "text" : "Conferma" +}, { + "id" : "it.ra.user.roles", + "code" : "ra.user.roles", + "lang" : "it", + "text" : "Ruoli" +}, { + "id" : "it.ra.validation.email", + "code" : "ra.validation.email", + "lang" : "it", + "text" : "Deve essere un valido indirizzo email" +}, { + "id" : "it.ra.validation.future_date", + "code" : "ra.validation.future_date", + "lang" : "it", + "text" : "La data deve essere successiva ad oggi" +}, { + "id" : "it.ra.validation.maxLength", + "code" : "ra.validation.maxLength", + "lang" : "it", + "text" : "Deve essere lungo %{max} caratteri al massimo" +}, { + "id" : "it.ra.validation.maxValue", + "code" : "ra.validation.maxValue", + "lang" : "it", + "text" : "Deve essere al massimo %{max}" +}, { + "id" : "it.ra.validation.minLength", + "code" : "ra.validation.minLength", + "lang" : "it", + "text" : "Deve essere lungo %{min} caratteri almeno" +}, { + "id" : "it.ra.validation.minValue", + "code" : "ra.validation.minValue", + "lang" : "it", + "text" : "Deve essere almeno %{min}" +}, { + "id" : "it.ra.validation.number", + "code" : "ra.validation.number", + "lang" : "it", + "text" : "Deve essere un numero" +}, { + "id" : "it.ra.validation.oneOf", + "code" : "ra.validation.oneOf", + "lang" : "it", + "text" : "Deve essere uno di: %{options}" +}, { + "id" : "it.ra.validation.regex", + "code" : "ra.validation.regex", + "lang" : "it", + "text" : "Deve rispettare il formato (espressione regolare): %{pattern}" +}, { + "id" : "it.ra.validation.required", + "code" : "ra.validation.required", + "lang" : "it", + "text" : "Campo obbligatorio" +}, { + "id" : "it.ra.validation_summary.message.success", + "code" : "ra.validation_summary.message.success", + "lang" : "it", + "text" : "Tutte le informazioni presenti nella sezione corrente sono state inserite correttamente." +}, { + "id" : "it.ra.yes", + "code" : "ra.yes", + "lang" : "it", + "text" : "Si" +}, { + "id" : "it.resources.entities/audit-log.fields.created", + "code" : "resources.entities/audit-log.fields.created", + "lang" : "it", + "text" : "Data e ora" +}, { + "id" : "it.resources.entities/audit-log.fields.from", + "code" : "resources.entities/audit-log.fields.from", + "lang" : "it", + "text" : "Dalla data" +}, { + "id" : "it.resources.entities/audit-log.fields.message", + "code" : "resources.entities/audit-log.fields.message", + "lang" : "it", + "text" : "Messaggio" +}, { + "id" : "it.resources.entities/audit-log.fields.to", + "code" : "resources.entities/audit-log.fields.to", + "lang" : "it", + "text" : "Alla data" +}, { + "id" : "it.resources.entities/audit-log.fields.userId", + "code" : "resources.entities/audit-log.fields.userId", + "lang" : "it", + "text" : "Utente" +}, { + "id" : "it.resources.entities/customer-area.fields.description", + "code" : "resources.entities/customer-area.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/customer-area.fields.name", + "code" : "resources.entities/customer-area.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/customer-area.fields.office.address", + "code" : "resources.entities/customer-area.fields.office.address", + "lang" : "it", + "text" : "Indirizzo" +}, { + "id" : "it.resources.entities/customer-area.fields.office.cityId", + "code" : "resources.entities/customer-area.fields.office.cityId", + "lang" : "it", + "text" : "Città" +}, { + "id" : "it.resources.entities/customer-area.fields.officeId", + "code" : "resources.entities/customer-area.fields.officeId", + "lang" : "it", + "text" : "Ufficio" +}, { + "id" : "it.resources.entities/customer-area.fields.updated", + "code" : "resources.entities/customer-area.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/customer-area.name", + "code" : "resources.entities/customer-area.name", + "lang" : "it", + "text" : "Area |||| Aree" +}, { + "id" : "it.resources.entities/customer-area.title.create", + "code" : "resources.entities/customer-area.title.create", + "lang" : "it", + "text" : "Nuova Area" +}, { + "id" : "it.resources.entities/customer-area.title.edit", + "code" : "resources.entities/customer-area.title.edit", + "lang" : "it", + "text" : "Modifica Area" +}, { + "id" : "it.resources.entities/customer-office.fields.address", + "code" : "resources.entities/customer-office.fields.address", + "lang" : "it", + "text" : "Indirizzo" +}, { + "id" : "it.resources.entities/customer-office.fields.cityId", + "code" : "resources.entities/customer-office.fields.cityId", + "lang" : "it", + "text" : "Città" +}, { + "id" : "it.resources.entities/customer-office.fields.headquarter", + "code" : "resources.entities/customer-office.fields.headquarter", + "lang" : "it", + "text" : "Sede Legale" +}, { + "id" : "it.resources.entities/customer-office.fields.updated", + "code" : "resources.entities/customer-office.fields.updated", + "lang" : "it", + "text" : "Ultima Modifica" +}, { + "id" : "it.resources.entities/customer-office.name", + "code" : "resources.entities/customer-office.name", + "lang" : "it", + "text" : "Sede |||| Sedi" +}, { + "id" : "it.resources.entities/customer-office.title.create", + "code" : "resources.entities/customer-office.title.create", + "lang" : "it", + "text" : "Nuova Sede" +}, { + "id" : "it.resources.entities/customer-office.title.edit", + "code" : "resources.entities/customer-office.title.edit", + "lang" : "it", + "text" : "Modifica Sede" +}, { + "id" : "it.resources.entities/customer-referent.fields.email", + "code" : "resources.entities/customer-referent.fields.email", + "lang" : "it", + "text" : "E-mail" +}, { + "id" : "it.resources.entities/customer-referent.fields.mobile", + "code" : "resources.entities/customer-referent.fields.mobile", + "lang" : "it", + "text" : "Telefono" +}, { + "id" : "it.resources.entities/customer-referent.fields.name", + "code" : "resources.entities/customer-referent.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/customer-referent.fields.office.cityId", + "code" : "resources.entities/customer-referent.fields.office.cityId", + "lang" : "it", + "text" : "Città" +}, { + "id" : "it.resources.entities/customer-referent.fields.officeId", + "code" : "resources.entities/customer-referent.fields.officeId", + "lang" : "it", + "text" : "Sede" +}, { + "id" : "it.resources.entities/customer-referent.fields.surname", + "code" : "resources.entities/customer-referent.fields.surname", + "lang" : "it", + "text" : "Cognome" +}, { + "id" : "it.resources.entities/customer-referent.fields.unit", + "code" : "resources.entities/customer-referent.fields.unit", + "lang" : "it", + "text" : "Reparto" +}, { + "id" : "it.resources.entities/customer-referent.fields.updated", + "code" : "resources.entities/customer-referent.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/customer-referent.name", + "code" : "resources.entities/customer-referent.name", + "lang" : "it", + "text" : "Referente |||| Referenti" +}, { + "id" : "it.resources.entities/customer-referent.title.create", + "code" : "resources.entities/customer-referent.title.create", + "lang" : "it", + "text" : "Nuovo Referente" +}, { + "id" : "it.resources.entities/customer-referent.title.edit", + "code" : "resources.entities/customer-referent.title.edit", + "lang" : "it", + "text" : "Modifica Referente" +}, { + "id" : "it.resources.entities/customer.actions.create", + "code" : "resources.entities/customer.actions.create", + "lang" : "it", + "text" : "Aggiungi" +}, { + "id" : "it.resources.entities/customer.breadcrumbs.edit", + "code" : "resources.entities/customer.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Cliente" +}, { + "id" : "it.resources.entities/customer.fields.active", + "code" : "resources.entities/customer.fields.active", + "lang" : "it", + "text" : "Attivo" +}, { + "id" : "it.resources.entities/customer.fields.name", + "code" : "resources.entities/customer.fields.name", + "lang" : "it", + "text" : "Ragione Sociale" +}, { + "id" : "it.resources.entities/customer.fields.updated", + "code" : "resources.entities/customer.fields.updated", + "lang" : "it", + "text" : "Ultima Modifica" +}, { + "id" : "it.resources.entities/customer.fields.vatCode", + "code" : "resources.entities/customer.fields.vatCode", + "lang" : "it", + "text" : "P.IVA" +}, { + "id" : "it.resources.entities/customer.name", + "code" : "resources.entities/customer.name", + "lang" : "it", + "text" : "Cliente |||| Clienti" +}, { + "id" : "it.resources.entities/customer.sections.offices", + "code" : "resources.entities/customer.sections.offices", + "lang" : "it", + "text" : "Sedi" +}, { + "id" : "it.resources.entities/customer.sections.referents", + "code" : "resources.entities/customer.sections.referents", + "lang" : "it", + "text" : "Referenti" +}, { + "id" : "it.resources.entities/customer.tabs.areas", + "code" : "resources.entities/customer.tabs.areas", + "lang" : "it", + "text" : "Aree" +}, { + "id" : "it.resources.entities/customer.tabs.details", + "code" : "resources.entities/customer.tabs.details", + "lang" : "it", + "text" : "Generali" +}, { + "id" : "it.resources.entities/customer.tabs.offices", + "code" : "resources.entities/customer.tabs.offices", + "lang" : "it", + "text" : "Uffici" +}, { + "id" : "it.resources.entities/customer.tabs.referents", + "code" : "resources.entities/customer.tabs.referents", + "lang" : "it", + "text" : "Referenti" +}, { + "id" : "it.resources.entities/customer.title.create", + "code" : "resources.entities/customer.title.create", + "lang" : "it", + "text" : "Nuovo Cliente" +}, { + "id" : "it.resources.entities/customer.title.edit", + "code" : "resources.entities/customer.title.edit", + "lang" : "it", + "text" : "Modifica cliente %{name}" +}, { + "id" : "it.resources.entities/device.alert", + "code" : "resources.entities/device.alert", + "lang" : "it", + "text" : "Di seguito è presente l'elenco dei dispositivi registrati per cui è disponibile il login con pin." +}, { + "id" : "it.resources.entities/device.breadcrumbs.create", + "code" : "resources.entities/device.breadcrumbs.create", + "lang" : "it", + "text" : "Nuovo Dispositivo" +}, { + "id" : "it.resources.entities/device.breadcrumbs.edit", + "code" : "resources.entities/device.breadcrumbs.edit", + "lang" : "it", + "text" : "Dettaglio Dispositivo" +}, { + "id" : "it.resources.entities/device.fields.code", + "code" : "resources.entities/device.fields.code", + "lang" : "it", + "text" : "Codice Univoco" +}, { + "id" : "it.resources.entities/device.fields.registrationDate", + "code" : "resources.entities/device.fields.registrationDate", + "lang" : "it", + "text" : "Data di registrazione" +}, { + "id" : "it.resources.entities/device.fields.secret", + "code" : "resources.entities/device.fields.secret", + "lang" : "it", + "text" : "Segreto condiviso" +}, { + "id" : "it.resources.entities/device.name", + "code" : "resources.entities/device.name", + "lang" : "it", + "text" : "Dispositivo |||| Dispositivi" +}, { + "id" : "it.resources.entities/device.title", + "code" : "resources.entities/device.title", + "lang" : "it", + "text" : "Dettagli Dispositivo" +}, { + "id" : "it.resources.entities/equipment-type-attachment.fields.attachment", + "code" : "resources.entities/equipment-type-attachment.fields.attachment", + "lang" : "it", + "text" : "Allegato" +}, { + "id" : "it.resources.entities/equipment-type-attachment.fields.description", + "code" : "resources.entities/equipment-type-attachment.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/equipment-type-attachment.name", + "code" : "resources.entities/equipment-type-attachment.name", + "lang" : "it", + "text" : "Allegato Tipo Attrezzatura |||| Allegati Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type-attachment.title", + "code" : "resources.entities/equipment-type-attachment.title", + "lang" : "it", + "text" : "Allegato Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type-attachment.title.list", + "code" : "resources.entities/equipment-type-attachment.title.list", + "lang" : "it", + "text" : "Allegati Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.breadcrumbs.create", + "code" : "resources.entities/equipment-type.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.breadcrumbs.edit", + "code" : "resources.entities/equipment-type.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.fields.accessory", + "code" : "resources.entities/equipment-type.fields.accessory", + "lang" : "it", + "text" : "Accessorio" +}, { + "id" : "it.resources.entities/equipment-type.fields.attachment", + "code" : "resources.entities/equipment-type.fields.attachment", + "lang" : "it", + "text" : "Allegato" +}, { + "id" : "it.resources.entities/equipment-type.fields.created", + "code" : "resources.entities/equipment-type.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/equipment-type.fields.name", + "code" : "resources.entities/equipment-type.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/equipment-type.fields.updated", + "code" : "resources.entities/equipment-type.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/equipment-type.name", + "code" : "resources.entities/equipment-type.name", + "lang" : "it", + "text" : "Tipo Attrezzatura |||| Tipi Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.title", + "code" : "resources.entities/equipment-type.title", + "lang" : "it", + "text" : "Tipo Attrezzatura" +}, { + "id" : "it.resources.entities/equipment-type.title.list", + "code" : "resources.entities/equipment-type.title.list", + "lang" : "it", + "text" : "Tipi Attrezzatura" +}, { + "id" : "it.resources.entities/equipmentType.actions.backToFather", + "code" : "resources.entities/equipmentType.actions.backToFather", + "lang" : "it", + "text" : "Torna Indietro" +}, { + "id" : "it.resources.entities/i18n-message.breadcrumbs.create", + "code" : "resources.entities/i18n-message.breadcrumbs.create", + "lang" : "it", + "text" : "Nuovo Messaggio" +}, { + "id" : "it.resources.entities/i18n-message.breadcrumbs.edit", + "code" : "resources.entities/i18n-message.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Messaggio" +}, { + "id" : "it.resources.entities/i18n-message.fields.code", + "code" : "resources.entities/i18n-message.fields.code", + "lang" : "it", + "text" : "Codice" +}, { + "id" : "it.resources.entities/i18n-message.fields.lang", + "code" : "resources.entities/i18n-message.fields.lang", + "lang" : "it", + "text" : "Lingua" +}, { + "id" : "it.resources.entities/i18n-message.fields.text", + "code" : "resources.entities/i18n-message.fields.text", + "lang" : "it", + "text" : "Testo" +}, { + "id" : "it.resources.entities/i18n-message.fields.translated", + "code" : "resources.entities/i18n-message.fields.translated", + "lang" : "it", + "text" : "Tradotto" +}, { + "id" : "it.resources.entities/i18n-message.name", + "code" : "resources.entities/i18n-message.name", + "lang" : "it", + "text" : "Messaggi (i18n)" +}, { + "id" : "it.resources.entities/i18n-message.title", + "code" : "resources.entities/i18n-message.title", + "lang" : "it", + "text" : "Messaggio Localizzato" +}, { + "id" : "it.resources.entities/intervention-type.breadcrumbs.create", + "code" : "resources.entities/intervention-type.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Tipo Intervento" +}, { + "id" : "it.resources.entities/intervention-type.breadcrumbs.edit", + "code" : "resources.entities/intervention-type.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Tipo Intervento" +}, { + "id" : "it.resources.entities/intervention-type.fields.created", + "code" : "resources.entities/intervention-type.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/intervention-type.fields.description", + "code" : "resources.entities/intervention-type.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/intervention-type.fields.path", + "code" : "resources.entities/intervention-type.fields.path", + "lang" : "it", + "text" : "Percorso" +}, { + "id" : "it.resources.entities/intervention-type.fields.updated", + "code" : "resources.entities/intervention-type.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/intervention-type.name", + "code" : "resources.entities/intervention-type.name", + "lang" : "it", + "text" : "Tipo Intervento |||| Tipi Intervento" +}, { + "id" : "it.resources.entities/intervention-type.title", + "code" : "resources.entities/intervention-type.title", + "lang" : "it", + "text" : "Tipo Intervento" +}, { + "id" : "it.resources.entities/notification.name", + "code" : "resources.entities/notification.name", + "lang" : "it", + "text" : "Notifiche" +}, { + "id" : "it.resources.entities/rfid-device.breadcrumbs.create", + "code" : "resources.entities/rfid-device.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Dispositivo RFID" +}, { + "id" : "it.resources.entities/rfid-device.breadcrumbs.edit", + "code" : "resources.entities/rfid-device.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Dispositivo RFID" +}, { + "id" : "it.resources.entities/rfid-device.fields.code", + "code" : "resources.entities/rfid-device.fields.code", + "lang" : "it", + "text" : "Codice Seriale" +}, { + "id" : "it.resources.entities/rfid-device.fields.name", + "code" : "resources.entities/rfid-device.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/rfid-device.fields.updated", + "code" : "resources.entities/rfid-device.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/rfid-device.name", + "code" : "resources.entities/rfid-device.name", + "lang" : "it", + "text" : "Dispositivo RFID |||| Dispositivi RFID" +}, { + "id" : "it.resources.entities/rfid-device.title.create", + "code" : "resources.entities/rfid-device.title.create", + "lang" : "it", + "text" : "Nuovo Dispositivo RFID" +}, { + "id" : "it.resources.entities/rfid-device.title.edit", + "code" : "resources.entities/rfid-device.title.edit", + "lang" : "it", + "text" : "Modifica Dispositivo RFID" +}, { + "id" : "it.resources.entities/supplier-referent.fields.created", + "code" : "resources.entities/supplier-referent.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/supplier-referent.fields.department", + "code" : "resources.entities/supplier-referent.fields.department", + "lang" : "it", + "text" : "Dipartimento" +}, { + "id" : "it.resources.entities/supplier-referent.fields.email", + "code" : "resources.entities/supplier-referent.fields.email", + "lang" : "it", + "text" : "Email" +}, { + "id" : "it.resources.entities/supplier-referent.fields.name", + "code" : "resources.entities/supplier-referent.fields.name", + "lang" : "it", + "text" : "Nome" +}, { + "id" : "it.resources.entities/supplier-referent.fields.phone", + "code" : "resources.entities/supplier-referent.fields.phone", + "lang" : "it", + "text" : "Numero di Telefono" +}, { + "id" : "it.resources.entities/supplier-referent.fields.surname", + "code" : "resources.entities/supplier-referent.fields.surname", + "lang" : "it", + "text" : "Cognome" +}, { + "id" : "it.resources.entities/supplier-referent.fields.updated", + "code" : "resources.entities/supplier-referent.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/supplier-referent.name", + "code" : "resources.entities/supplier-referent.name", + "lang" : "it", + "text" : "Referente Fornitore |||| Referenti Fornitore" +}, { + "id" : "it.resources.entities/supplier-referent.title", + "code" : "resources.entities/supplier-referent.title", + "lang" : "it", + "text" : "Referenti Fornitore" +}, { + "id" : "it.resources.entities/supplier.breadcrumbs.create", + "code" : "resources.entities/supplier.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Fornitore" +}, { + "id" : "it.resources.entities/supplier.breadcrumbs.edit", + "code" : "resources.entities/supplier.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Fornitore" +}, { + "id" : "it.resources.entities/supplier.fields.address", + "code" : "resources.entities/supplier.fields.address", + "lang" : "it", + "text" : "Indirizzo" +}, { + "id" : "it.resources.entities/supplier.fields.businessName", + "code" : "resources.entities/supplier.fields.businessName", + "lang" : "it", + "text" : "Ragione Sociale" +}, { + "id" : "it.resources.entities/supplier.fields.cityId", + "code" : "resources.entities/supplier.fields.cityId", + "lang" : "it", + "text" : "Comune" +}, { + "id" : "it.resources.entities/supplier.fields.created", + "code" : "resources.entities/supplier.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/supplier.fields.updated", + "code" : "resources.entities/supplier.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/supplier.fields.vatNumber", + "code" : "resources.entities/supplier.fields.vatNumber", + "lang" : "it", + "text" : "Partita IVA" +}, { + "id" : "it.resources.entities/supplier.name", + "code" : "resources.entities/supplier.name", + "lang" : "it", + "text" : "Fornitore |||| Fornitori" +}, { + "id" : "it.resources.entities/supplier.title", + "code" : "resources.entities/supplier.title", + "lang" : "it", + "text" : "Fornitore" +}, { + "id" : "it.resources.entities/user.breadcrumbs.create", + "code" : "resources.entities/user.breadcrumbs.create", + "lang" : "it", + "text" : "Nuovo Utente" +}, { + "id" : "it.resources.entities/user.breadcrumbs.edit", + "code" : "resources.entities/user.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Utente" +}, { + "id" : "it.resources.entities/user.fields.active", + "code" : "resources.entities/user.fields.active", + "lang" : "it", + "text" : "Attivo" +}, { + "id" : "it.resources.entities/user.fields.image", + "code" : "resources.entities/user.fields.image", + "lang" : "it", + "text" : "Immagine di profilo" +}, { + "id" : "it.resources.entities/user.fields.name", + "code" : "resources.entities/user.fields.name", + "lang" : "it", + "text" : "Nome e Cognome" +}, { + "id" : "it.resources.entities/user.fields.registrationDate", + "code" : "resources.entities/user.fields.registrationDate", + "lang" : "it", + "text" : "Data di registrazione" +}, { + "id" : "it.resources.entities/user.fields.role", + "code" : "resources.entities/user.fields.role", + "lang" : "it", + "text" : "Ruolo" +}, { + "id" : "it.resources.entities/user.name", + "code" : "resources.entities/user.name", + "lang" : "it", + "text" : "Utente |||| Utenti" +}, { + "id" : "it.resources.entities/user.title.create", + "code" : "resources.entities/user.title.create", + "lang" : "it", + "text" : "Nuovo Utente" +}, { + "id" : "it.resources.entities/user.title.edit", + "code" : "resources.entities/user.title.edit", + "lang" : "it", + "text" : "Modifica utente %{name}" +}, { + "id" : "it.resources.notifications.empty", + "code" : "resources.notifications.empty", + "lang" : "it", + "text" : "Ancora nessuna notifica!" +}, { + "id" : "it.resources.notifications.messages.readed.done", + "code" : "resources.notifications.messages.readed.done", + "lang" : "it", + "text" : "Notifiche segnate come lette." +}, { + "id" : "it.resources.notifications.messages.unreaded.done", + "code" : "resources.notifications.messages.unreaded.done", + "lang" : "it", + "text" : "Notifiche segnate come non lette." +}, { + "id" : "it.resources.transactions.fields.id", + "code" : "resources.transactions.fields.id", + "lang" : "it", + "text" : "#ID" +}, { + "id" : "it.resources.transactions.fields.notes.show_less", + "code" : "resources.transactions.fields.notes.show_less", + "lang" : "it", + "text" : "Mostra meno" +}, { + "id" : "it.resources.transactions.fields.state", + "code" : "resources.transactions.fields.state", + "lang" : "it", + "text" : "Stato" +}, { + "id" : "it.resources.user/change-password.fields.newPassword", + "code" : "resources.user/change-password.fields.newPassword", + "lang" : "it", + "text" : "Nuova Password" +}, { + "id" : "it.resources.user/change-password.fields.oldPassword", + "code" : "resources.user/change-password.fields.oldPassword", + "lang" : "it", + "text" : "Password precedente" +}, { + "id" : "it.resources.user/change-password.title", + "code" : "resources.user/change-password.title", + "lang" : "it", + "text" : "Cambio Password" +}, { + "id" : "it.test", + "code" : "test", + "lang" : "it", + "text" : "test" +} ] \ No newline at end of file diff --git a/edera-api/api/src/test/resources/sample-google-workspace.docx b/edera-api/api/src/test/resources/sample-google-workspace.docx new file mode 100644 index 0000000000000000000000000000000000000000..5402977667171072c64077f32382084c773290a2 GIT binary patch literal 5913 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 literal 0 HcmV?d00001 diff --git a/edera-api/api/src/test/resources/sample-ms-office-open-xml.docx b/edera-api/api/src/test/resources/sample-ms-office-open-xml.docx new file mode 100644 index 0000000000000000000000000000000000000000..7061e5220c068c001ca04ddd550d7114c5fee5c1 GIT binary patch literal 12298 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 literal 0 HcmV?d00001 diff --git a/edera-api/api/src/test/resources/sample-open-office.docx b/edera-api/api/src/test/resources/sample-open-office.docx new file mode 100644 index 0000000000000000000000000000000000000000..e8f487c0ce3a20450f8260ca3ff9e0c7dc6a767a GIT binary patch literal 1987329 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

)g7a7#-!r^6oV=LMTZT}wv=J>nqEWC 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%0A+Gn@CRp092`IAPwpiwY`In{ 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