From: Roberto Stomeo Date: Tue, 1 Jul 2025 14:42:34 +0000 (+0200) Subject: Initial commit edera-api X-Git-Url: https://git-hsc.dyrecta.com/?a=commitdiff_plain;h=61070799671f4d05f84c984194a4de9598c8cac3;p=pia_hsc.git Initial commit edera-api --- 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 0000000..1bc4b5e Binary files /dev/null and b/edera-api/api/src/main/resources/docx/helper.docx differ diff --git a/edera-api/api/src/main/resources/i18n.json b/edera-api/api/src/main/resources/i18n.json new file mode 100644 index 0000000..04afad3 --- /dev/null +++ b/edera-api/api/src/main/resources/i18n.json @@ -0,0 +1,3136 @@ +[ { + "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.generic", + "code" : "crud.error.generic", + "lang" : "it", + "text" : "Errore generico: impossibile eseguire l'operazione richiesta" +}, { + "id" : "it.crud.error.serialization", + "code" : "crud.error.serialization", + "lang" : "it", + "text" : "Errore nella serializzazione dei dati" +}, { + "id" : "it.docx-template.type.maintenance", + "code" : "docx-template.type.maintenance", + "lang" : "it", + "text" : "Manutenzione" +}, { + "id" : "it.error.invalid_json_response", + "code" : "error.invalid_json_response", + "lang" : "it", + "text" : "Risposta JSON non valida" +}, { + "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.iam.error.unauthorized", + "code" : "iam.error.unauthorized", + "lang" : "it", + "text" : "Non Autorizzato" +}, { + "id" : "it.iam.token-expired", + "code" : "iam.token-expired", + "lang" : "it", + "text" : "Sessione scaduta" +}, { + "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.move_down", + "code" : "ra.action.move_down", + "lang" : "it", + "text" : "Sposta sotto" +}, { + "id" : "it.ra.action.move_up", + "code" : "ra.action.move_up", + "lang" : "it", + "text" : "Sposta sopra" +}, { + "id" : "it.ra.action.next", + "code" : "ra.action.next", + "lang" : "it", + "text" : "Prosegui" +}, { + "id" : "it.ra.action.open", + "code" : "ra.action.open", + "lang" : "it", + "text" : "Apri" +}, { + "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.remove_item", + "code" : "ra.action.remove_item", + "lang" : "it", + "text" : "Sei sicuro di voler cancellare?" +}, { + "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.actions.print_docx", + "code" : "ra.actions.print_docx", + "lang" : "it", + "text" : "Stampa modulo..." +}, { + "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.activity.schedule.description", + "code" : "ra.activity.schedule.description", + "lang" : "it", + "text" : "E’ possibile programmare una nuova attività di tipo %s presso il cliente %s sul macchinario %s del fornitore %s, relativo al protocollo %s" +}, { + "id" : "it.ra.activity.schedule.title", + "code" : "ra.activity.schedule.title", + "lang" : "it", + "text" : "Nuova attività in programma" +}, { + "id" : "it.ra.activity.status.CLOSED", + "code" : "ra.activity.status.CLOSED", + "lang" : "it", + "text" : "Chiuso" +}, { + "id" : "it.ra.activity.status.OPEN", + "code" : "ra.activity.status.OPEN", + "lang" : "it", + "text" : "Aperto" +}, { + "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.first_access.change_password", + "code" : "ra.auth.first_access.change_password", + "lang" : "it", + "text" : "Attenzione" +}, { + "id" : "it.ra.auth.first_access.change_password_helper", + "code" : "ra.auth.first_access.change_password_helper", + "lang" : "it", + "text" : "Questo è il tuo primo accesso alla piattaforma e devi necessariamente cambiare la tua password, compila i campi di seguito e premi salva per confermare l'operazione." +}, { + "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.activity.save.supply-not-found", + "code" : "ra.error.activity.save.supply-not-found", + "lang" : "it", + "text" : "Errore durante il salvataggio: l'approvvigionamento selezionato è inesistente" +}, { + "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.invalid-date-range", + "code" : "ra.error.invalid-date-range", + "lang" : "it", + "text" : "Impossibile filtrare con le date selezionate" +}, { + "id" : "it.ra.error.maintenance.save.activity-not-found", + "code" : "ra.error.maintenance.save.activity-not-found", + "lang" : "it", + "text" : "Errore durante il salvataggio: l'attività selezionata è inesistente" +}, { + "id" : "it.ra.error.maintenance.save.protocol-not-found", + "code" : "ra.error.maintenance.save.protocol-not-found", + "lang" : "it", + "text" : "Errore durante il salvataggio: il protocollo è inesistente" +}, { + "id" : "it.ra.error.maintenance.save.supply-not-found", + "code" : "ra.error.maintenance.save.supply-not-found", + "lang" : "it", + "text" : "Errore durante il salvataggio: l'approvvigionamento è inesistente" +}, { + "id" : "it.ra.error.price-list-item.save.equipmentId-already-exists", + "code" : "ra.error.price-list-item.save.equipmentId-already-exists", + "lang" : "it", + "text" : "Impossibile salvare l'entità: l'Attrezzatura selezionata è già presente nel listino corrente" +}, { + "id" : "it.ra.error.price-list.save.start-after-end", + "code" : "ra.error.price-list.save.start-after-end", + "lang" : "it", + "text" : "Impossibile salvare il Listino: Data Inizio non può essere maggiore della data di Data Fine" +}, { + "id" : "it.ra.error.supplier.delete", + "code" : "ra.error.supplier.delete", + "lang" : "it", + "text" : "Impossibile eliminare il Fornitore" +}, { + "id" : "it.ra.error.supply.save.protocol-not-found", + "code" : "ra.error.supply.save.protocol-not-found", + "lang" : "it", + "text" : "Errore durante il salvataggio: il protocollo selezionato è inesistente" +}, { + "id" : "it.ra.form.docx_print.dirty", + "code" : "ra.form.docx_print.dirty", + "lang" : "it", + "text" : "Attenzione" +}, { + "id" : "it.ra.form.docx_print.dirty_message", + "code" : "ra.form.docx_print.dirty_message", + "lang" : "it", + "text" : "Se successivamente a questa modifica intendi stampare dei moduli devi sapere che i dati attualmente modificati non saranno presi in considerazione fino a quando gli stessi non saranno salvati." +}, { + "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/activity", + "code" : "ra.menu.item.entities/activity", + "lang" : "it", + "text" : "Attività" +}, { + "id" : "it.ra.menu.item.entities/activity-type", + "code" : "ra.menu.item.entities/activity-type", + "lang" : "it", + "text" : "Tipi Attività" +}, { + "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/docx-template", + "code" : "ra.menu.item.entities/docx-template", + "lang" : "it", + "text" : "Modulistica" +}, { + "id" : "it.ra.menu.item.entities/equipment", + "code" : "ra.menu.item.entities/equipment", + "lang" : "it", + "text" : "Attrezzature" +}, { + "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/maintenance", + "code" : "ra.menu.item.entities/maintenance", + "lang" : "it", + "text" : "Manutenzioni" +}, { + "id" : "it.ra.menu.item.entities/notification", + "code" : "ra.menu.item.entities/notification", + "lang" : "it", + "text" : "Notifiche" +}, { + "id" : "it.ra.menu.item.entities/protocol", + "code" : "ra.menu.item.entities/protocol", + "lang" : "it", + "text" : "Protocolli" +}, { + "id" : "it.ra.menu.item.entities/rfid-device", + "code" : "ra.menu.item.entities/rfid-device", + "lang" : "it", + "text" : "RFID" +}, { + "id" : "it.ra.menu.item.entities/rfid-device-track", + "code" : "ra.menu.item.entities/rfid-device-track", + "lang" : "it", + "text" : "Tracciamento RFID" +}, { + "id" : "it.ra.menu.item.entities/supply", + "code" : "ra.menu.item.entities/supply", + "lang" : "it", + "text" : "Approvvigionamenti" +}, { + "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.position", + "code" : "ra.menu.item.position", + "lang" : "it", + "text" : "Posizione" +}, { + "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.error_more_info", + "code" : "ra.message.error_more_info", + "lang" : "it", + "text" : "Per ottenere maggiori informazioni utilizza Strumenti di Sviluppo del tuo browser." +}, { + "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.remove_item", + "code" : "ra.message.remove_item", + "lang" : "it", + "text" : "Clicca \"Conferma\" per cancellare" +}, { + "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.notification.view_all", + "code" : "ra.notification.view_all", + "lang" : "it", + "text" : "Visualizza Tutte" +}, { + "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.position.report.title", + "code" : "ra.position.report.title", + "lang" : "it", + "text" : "Statistiche Posizione" +}, { + "id" : "it.ra.position.waiting-for-data", + "code" : "ra.position.waiting-for-data", + "lang" : "it", + "text" : "Seleziona un ufficio" +}, { + "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.customer", + "code" : "ra.roles.customer", + "lang" : "it", + "text" : "Cliente" +}, { + "id" : "it.ra.roles.maintainer", + "code" : "ra.roles.maintainer", + "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.status.closed", + "code" : "ra.status.closed", + "lang" : "it", + "text" : "Chiuso" +}, { + "id" : "it.ra.status.open", + "code" : "ra.status.open", + "lang" : "it", + "text" : "Aperto" +}, { + "id" : "it.ra.supply.card-status.RUNNING", + "code" : "ra.supply.card-status.RUNNING", + "lang" : "it", + "text" : "Stato: In uso" +}, { + "id" : "it.ra.supply.card-status.STOPPED", + "code" : "ra.supply.card-status.STOPPED", + "lang" : "it", + "text" : "Stato: Sospeso" +}, { + "id" : "it.ra.supply.status.RUNNING", + "code" : "ra.supply.status.RUNNING", + "lang" : "it", + "text" : "In Uso" +}, { + "id" : "it.ra.supply.status.STOPPED", + "code" : "ra.supply.status.STOPPED", + "lang" : "it", + "text" : "Sospeso" +}, { + "id" : "it.ra.time.days", + "code" : "ra.time.days", + "lang" : "it", + "text" : "Giorni" +}, { + "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.reporting.stats.breakPredictions.line", + "code" : "reporting.stats.breakPredictions.line", + "lang" : "it", + "text" : "Soglia" +}, { + "id" : "it.reporting.stats.breakPredictions.usageHours", + "code" : "reporting.stats.breakPredictions.usageHours", + "lang" : "it", + "text" : "Ore di utilizzo accumulate" +}, { + "id" : "it.reporting.stats.filters.office", + "code" : "reporting.stats.filters.office", + "lang" : "it", + "text" : "Ufficio" +}, { + "id" : "it.reporting.stats.loading", + "code" : "reporting.stats.loading", + "lang" : "it", + "text" : "Caricamento dati in corso..." +}, { + "id" : "it.reporting.stats.predictions.accumulated", + "code" : "reporting.stats.predictions.accumulated", + "lang" : "it", + "text" : "Ore cumulate" +}, { + "id" : "it.reporting.stats.predictions.break", + "code" : "reporting.stats.predictions.break", + "lang" : "it", + "text" : "Ore di lavoro accumulate" +}, { + "id" : "it.reporting.stats.predictions.broken", + "code" : "reporting.stats.predictions.broken", + "lang" : "it", + "text" : "Previsione rottura" +}, { + "id" : "it.reporting.stats.predictions.future", + "code" : "reporting.stats.predictions.future", + "lang" : "it", + "text" : "Proiezione" +}, { + "id" : "it.reporting.stats.predictions.history", + "code" : "reporting.stats.predictions.history", + "lang" : "it", + "text" : "Storico" +}, { + "id" : "it.reporting.stats.predictions.usageHours", + "code" : "reporting.stats.predictions.usageHours", + "lang" : "it", + "text" : "Ore di utilizzo" +}, { + "id" : "it.reporting.stats.supply.average-monthly-usage.title", + "code" : "reporting.stats.supply.average-monthly-usage.title", + "lang" : "it", + "text" : "Numero di utilizzi mese attuale:" +}, { + "id" : "it.reporting.stats.supply.monthly-usage-percentage.title", + "code" : "reporting.stats.supply.monthly-usage-percentage.title", + "lang" : "it", + "text" : "Utilizzo medio in questo mese:" +}, { + "id" : "it.reporting.stats.supply.monthly-usage.title", + "code" : "reporting.stats.supply.monthly-usage.title", + "lang" : "it", + "text" : "Tempo di utilizzo in questo mese:" +}, { + "id" : "it.reporting.stats.supply.yearly-usage.title", + "code" : "reporting.stats.supply.yearly-usage.title", + "lang" : "it", + "text" : "Tempo di utilizzo quest anno:" +}, { + "id" : "it.reporting.stats.track.monthly-movement.title", + "code" : "reporting.stats.track.monthly-movement.title", + "lang" : "it", + "text" : "Numero spostamenti in questo mese" +}, { + "id" : "it.reporting.stats.track.monthly-total-tracked-percentage.title", + "code" : "reporting.stats.track.monthly-total-tracked-percentage.title", + "lang" : "it", + "text" : "% Macchinari movimentati questo mese" +}, { + "id" : "it.reporting.stats.track.total-monthly-tracked.title", + "code" : "reporting.stats.track.total-monthly-tracked.title", + "lang" : "it", + "text" : "Numero macchinari movimentati questo mese" +}, { + "id" : "it.reporting.stats.track.yearly-movement.title", + "code" : "reporting.stats.track.yearly-movement.title", + "lang" : "it", + "text" : "Numero spostamenti quest’anno" +}, { + "id" : "it.reporting.stats.unit.days", + "code" : "reporting.stats.unit.days", + "lang" : "it", + "text" : "Giorni" +}, { + "id" : "it.reporting.stats.unit.hours", + "code" : "reporting.stats.unit.hours", + "lang" : "it", + "text" : "Ore" +}, { + "id" : "it.reporting.stats.usageDays", + "code" : "reporting.stats.usageDays", + "lang" : "it", + "text" : "Giorni di Utilizzo" +}, { + "id" : "it.reporting.stats.usageHours", + "code" : "reporting.stats.usageHours", + "lang" : "it", + "text" : "Ore di utilizzo" +}, { + "id" : "it.resources.entities.supply.notifications.started", + "code" : "resources.entities.supply.notifications.started", + "lang" : "it", + "text" : "Stato: In Uso" +}, { + "id" : "it.resources.entities.supply.notifications.stopped", + "code" : "resources.entities.supply.notifications.stopped", + "lang" : "it", + "text" : "Stato: Sospeso" +}, { + "id" : "it.resources.entities/activity-type.breadcrumbs.create", + "code" : "resources.entities/activity-type.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Tipo Attività" +}, { + "id" : "it.resources.entities/activity-type.breadcrumbs.edit", + "code" : "resources.entities/activity-type.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Tipo Attività" +}, { + "id" : "it.resources.entities/activity-type.fields.attachment", + "code" : "resources.entities/activity-type.fields.attachment", + "lang" : "it", + "text" : "Allegato" +}, { + "id" : "it.resources.entities/activity-type.fields.created", + "code" : "resources.entities/activity-type.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/activity-type.fields.description", + "code" : "resources.entities/activity-type.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/activity-type.fields.path", + "code" : "resources.entities/activity-type.fields.path", + "lang" : "it", + "text" : "Percorso" +}, { + "id" : "it.resources.entities/activity-type.fields.updated", + "code" : "resources.entities/activity-type.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/activity-type.name", + "code" : "resources.entities/activity-type.name", + "lang" : "it", + "text" : "Tipo Attività |||| Tipi Attività" +}, { + "id" : "it.resources.entities/activity-type.title", + "code" : "resources.entities/activity-type.title", + "lang" : "it", + "text" : "Tipo Attività" +}, { + "id" : "it.resources.entities/activity.actions.backToFather", + "code" : "resources.entities/activity.actions.backToFather", + "lang" : "it", + "text" : "Vai all'Approvvigionamento" +}, { + "id" : "it.resources.entities/activity.breadcrumbs.create", + "code" : "resources.entities/activity.breadcrumbs.create", + "lang" : "it", + "text" : "Crea Attività" +}, { + "id" : "it.resources.entities/activity.breadcrumbs.edit", + "code" : "resources.entities/activity.breadcrumbs.edit", + "lang" : "it", + "text" : "Modifica Attività" +}, { + "id" : "it.resources.entities/activity.fields.activityType.description", + "code" : "resources.entities/activity.fields.activityType.description", + "lang" : "it", + "text" : "Tipo Attività" +}, { + "id" : "it.resources.entities/activity.fields.activityTypeId", + "code" : "resources.entities/activity.fields.activityTypeId", + "lang" : "it", + "text" : "Tipo Attività" +}, { + "id" : "it.resources.entities/activity.fields.created", + "code" : "resources.entities/activity.fields.created", + "lang" : "it", + "text" : "Creato il" +}, { + "id" : "it.resources.entities/activity.fields.customer.id", + "code" : "resources.entities/activity.fields.customer.id", + "lang" : "it", + "text" : "Cliente" +}, { + "id" : "it.resources.entities/activity.fields.customer.name", + "code" : "resources.entities/activity.fields.customer.name", + "lang" : "it", + "text" : "Cliente" +}, { + "id" : "it.resources.entities/activity.fields.date", + "code" : "resources.entities/activity.fields.date", + "lang" : "it", + "text" : "Data" +}, { + "id" : "it.resources.entities/activity.fields.description", + "code" : "resources.entities/activity.fields.description", + "lang" : "it", + "text" : "Descrizione" +}, { + "id" : "it.resources.entities/activity.fields.status", + "code" : "resources.entities/activity.fields.status", + "lang" : "it", + "text" : "Stato" +}, { + "id" : "it.resources.entities/activity.fields.supply.equipmentId", + "code" : "resources.entities/activity.fields.supply.equipmentId", + "lang" : "it", + "text" : "Approvvigionamento" +}, { + "id" : "it.resources.entities/activity.fields.supply.supplierId", + "code" : "resources.entities/activity.fields.supply.supplierId", + "lang" : "it", + "text" : "Fornitore" +}, { + "id" : "it.resources.entities/activity.fields.supplyId", + "code" : "resources.entities/activity.fields.supplyId", + "lang" : "it", + "text" : "Approvvigionamento" +}, { + "id" : "it.resources.entities/activity.fields.title", + "code" : "resources.entities/activity.fields.title", + "lang" : "it", + "text" : "Titolo" +}, { + "id" : "it.resources.entities/activity.fields.updated", + "code" : "resources.entities/activity.fields.updated", + "lang" : "it", + "text" : "Ultimo Aggiornamento" +}, { + "id" : "it.resources.entities/activity.fields.user.name", + "code" : "resources.entities/activity.fields.user.name", + "lang" : "it", + "text" : "Creato da" +}, { + "id" : "it.resources.entities/activity.info_message", + "code" : "resources.entities/activity.info_message", + "lang" : "it", + "text" : "Questa attività si riferisce all'approvvigionamento %{supply} 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 0000000..5402977 Binary files /dev/null and b/edera-api/api/src/test/resources/sample-google-workspace.docx differ 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 0000000..7061e52 Binary files /dev/null and b/edera-api/api/src/test/resources/sample-ms-office-open-xml.docx differ diff --git a/edera-api/api/src/test/resources/sample-ms-office.docx b/edera-api/api/src/test/resources/sample-ms-office.docx new file mode 100644 index 0000000..1fde152 Binary files /dev/null and b/edera-api/api/src/test/resources/sample-ms-office.docx differ 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 0000000..e8f487c Binary files /dev/null and b/edera-api/api/src/test/resources/sample-open-office.docx differ diff --git a/edera-api/bitbucket-pipelines.yml b/edera-api/bitbucket-pipelines.yml new file mode 100644 index 0000000..92a70a2 --- /dev/null +++ b/edera-api/bitbucket-pipelines.yml @@ -0,0 +1,101 @@ +image: google/cloud-sdk:412.0.0-slim +definitions: + steps: + - step: &use-api-module + name: "Use api module" + script: + - export MODULE="api" + - mkdir ./build + - echo $MODULE > ./build/MODULE + artifacts: + - build/** + - step: &build + name: "Build" + caches: + - maven + - pip + script: + - export MODULE=$(cat ./build/MODULE) + - source scripts/set-env.sh + - apt update + - apt install -y openjdk-17-jdk maven + - cat scripts/tf/service-account.json.base64 | base64 --decode >> build/service-account.json + - gcloud auth activate-service-account --key-file build/service-account.json + - export REVISION=$(mvn help:evaluate -Dexpression=revision -q -DforceStdout) + - export VERSION=${REVISION}.${BITBUCKET_BUILD_NUMBER} + - echo $VERSION > ${MODULE}/src/main/resources/build.txt + - mvn -Drevision=${VERSION} -Dchangelist= package -DskipTests=true + - export EXECUTABLE="${MODULE}-${VERSION}.jar" + - echo cp "${MODULE}/target/${EXECUTABLE}" ./build + - cp "${MODULE}/target/${EXECUTABLE}" ./build + - echo $VERSION > ./build/VERSION + - echo $EXECUTABLE > ./build/EXECUTABLE + artifacts: + - build/** + - step: &publish + name: "Publish" + trigger: automatic + services: + - docker + script: + - source scripts/set-env.sh + - export EXECUTABLE=$(cat ./build/EXECUTABLE) + - export MODULE=$(cat ./build/MODULE) + - export VERSION=$(cat ./build/VERSION) + - export IMAGE_BASE="eu.gcr.io/${PROJECT_ID}/${NAMESPACE}-${MODULE}" + - export IMAGE="${IMAGE_BASE}:${VERSION}" + - export JAVA_ARGS="" + - export PROGRAM_ARGS="" + - gcloud auth activate-service-account --key-file build/service-account.json + - gcloud config set project ${PROJECT_ID} + - gcloud config set compute/zone europe-west1-b + - gcloud auth configure-docker + - >- + docker build -t ${IMAGE} \ + --build-arg PROFILE=${PROFILE} \ + --build-arg EXECUTABLE=${EXECUTABLE} \ + --build-arg JAVA_ARGS=${JAVA_ARGS} \ + --build-arg PROGRAM_ARGS=${PROGRAM_ARGS} \ + --build-arg MAIN=${MAIN} \ + -f ./scripts/docker/Dockerfile . + - docker push ${IMAGE} + - docker tag $IMAGE "${IMAGE_BASE}:latest" + - docker push "${IMAGE_BASE}:latest" + - git tag -a "${VERSION}" -m "version ${VERSION}" + - git push origin "${VERSION}" + - step: &deploy + name: Deploy + script: + - source scripts/set-env.sh + - export VERSION=$(cat ./build/VERSION) + - export EXECUTABLE=$(cat ./build/EXECUTABLE) + - export MODULE=$(cat ./build/MODULE) + - export IMAGE="eu.gcr.io/${PROJECT_ID}/${NAMESPACE}-${MODULE}:${VERSION}" + - gcloud auth activate-service-account --key-file build/service-account.json + - gcloud config set project ${PROJECT_ID} + - gcloud config set compute/zone europe-west1-b + - apt install kubectl + - apt install google-cloud-sdk-gke-gcloud-auth-plugin + - export USE_GKE_GCLOUD_AUTH_PLUGIN=True + - gcloud container clusters get-credentials applica + - kubectl set image deployment/${MODULE} ${MODULE}=${IMAGE} -n ${NAMESPACE} + - step: &test + image: maven:3.8.3-openjdk-17 + name: Build & Test + caches: + - maven + script: + - mvn test -Dspring.profiles.active=test +pipelines: + branches: + develop: + - step: *use-api-module + - step: *build + - step: *publish + - step: *deploy + + feature/*: + - step: *test + + hotfix/*: + - step: *test diff --git a/edera-api/mvnw b/edera-api/mvnw new file mode 100644 index 0000000..8a8fb22 --- /dev/null +++ b/edera-api/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/edera-api/mvnw.cmd b/edera-api/mvnw.cmd new file mode 100644 index 0000000..1d8ab01 --- /dev/null +++ b/edera-api/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/edera-api/notifications/pom.xml b/edera-api/notifications/pom.xml new file mode 100644 index 0000000..a71945f --- /dev/null +++ b/edera-api/notifications/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + applica.app + root + ${revision}${sha1}${changelist} + + + notifications + ${revision}${sha1}${changelist} + notifications + Manages user notifications and communications + + + + + applica.modules + iam-sdk + ${applica-iam.version} + + + + org.projectlombok + lombok + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + org.freemarker + freemarker + ${freemarker.version} + + + + org.springframework.boot + spring-boot-starter-mail + + + org.springframework + spring-tx + + + org.springframework.boot + spring-boot-starter-test + test + + + + \ No newline at end of file diff --git a/edera-api/notifications/src/main/java/applica/notifications/application/NotificationService.java b/edera-api/notifications/src/main/java/applica/notifications/application/NotificationService.java new file mode 100644 index 0000000..e39803a --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/application/NotificationService.java @@ -0,0 +1,5 @@ +package applica.notifications.application; + +public interface NotificationService { + +} diff --git a/edera-api/notifications/src/main/java/applica/notifications/application/UserActivatedEventHandler.java b/edera-api/notifications/src/main/java/applica/notifications/application/UserActivatedEventHandler.java new file mode 100644 index 0000000..e67e984 --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/application/UserActivatedEventHandler.java @@ -0,0 +1,44 @@ +package applica.notifications.application; + +import applica.integration.events.DomainEventHandler; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.events.UserActivatedEvent; +import applica.iam.sdk.requests.GetUserByIdRequest; +import applica.notifications.integration.MailMessage; +import applica.notifications.integration.MailMessageService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static applica.iam.sdk.ResponseCodes.OK; + +public class UserActivatedEventHandler extends DomainEventHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + private final MailMessageService mailMessageService; + private final IAMService iamService; + + public UserActivatedEventHandler(MailMessageService mailMessageService, IAMService iamService) { + this.mailMessageService = mailMessageService; + this.iamService = iamService; + } + + @Override + public void handle(UserActivatedEvent event) { + logger.info("Handling user activated event: {}", event); + + var response = iamService.getUserById(new GetUserByIdRequest(event.getUserId())); + if (!OK.equals(response.getResponseCode())) { + return; + } + var mailMessage = new MailMessage("activation", response.getUser()); + mailMessage.setTo(response.getUser().getEmail()); + mailMessage.setSubject("Activation completed successfully"); + mailMessageService.send(mailMessage); + + logger.info("Activation email sent to user: {}", response.getUser().getEmail()); + } + + @Override + public Class getEventClass() { + return UserActivatedEvent.class; + } +} diff --git a/edera-api/notifications/src/main/java/applica/notifications/application/UserPasswordChangedEventHandler.java b/edera-api/notifications/src/main/java/applica/notifications/application/UserPasswordChangedEventHandler.java new file mode 100644 index 0000000..b9fecc5 --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/application/UserPasswordChangedEventHandler.java @@ -0,0 +1,45 @@ +package applica.notifications.application; + +import applica.integration.events.DomainEventHandler; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.events.UserPasswordChangedEvent; +import applica.iam.sdk.requests.GetUserByIdRequest; +import applica.notifications.integration.MailMessage; +import applica.notifications.integration.MailMessageService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static applica.iam.sdk.ResponseCodes.OK; + +public class UserPasswordChangedEventHandler extends DomainEventHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + private final MailMessageService mailMessageService; + private final IAMService iamService; + + public UserPasswordChangedEventHandler(MailMessageService mailMessageService, IAMService iamService) { + this.mailMessageService = mailMessageService; + this.iamService = iamService; + } + + @Override + public void handle(UserPasswordChangedEvent event) { + logger.info("Handling user password changed event: {}", event); + + var response = iamService.getUserById(new GetUserByIdRequest(event.getUserId())); + if (!OK.equals(response.getResponseCode())) { + return; + } + + var mailMessage = new MailMessage("passwordChanged", response.getUser()); + mailMessage.setTo(response.getUser().getEmail()); + mailMessage.setSubject("Password changed"); + mailMessageService.send(mailMessage); + + logger.info("Password changed email sent to user: {}", response.getUser().getEmail()); + } + + @Override + public Class getEventClass() { + return UserPasswordChangedEvent.class; + } +} diff --git a/edera-api/notifications/src/main/java/applica/notifications/application/UserPasswordRecoveredEventHandler.java b/edera-api/notifications/src/main/java/applica/notifications/application/UserPasswordRecoveredEventHandler.java new file mode 100644 index 0000000..f91ffd0 --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/application/UserPasswordRecoveredEventHandler.java @@ -0,0 +1,49 @@ +package applica.notifications.application; + +import applica.integration.events.DomainEventHandler; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.events.UserPasswordRecoveredEvent; +import applica.iam.sdk.requests.GetUserByIdRequest; +import applica.notifications.integration.MailMessage; +import applica.notifications.integration.MailMessageService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; + +import static applica.iam.sdk.ResponseCodes.OK; + +public class UserPasswordRecoveredEventHandler extends DomainEventHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + private final MailMessageService mailMessageService; + private final IAMService iamService; + + public UserPasswordRecoveredEventHandler(MailMessageService mailMessageService, IAMService iamService) { + this.mailMessageService = mailMessageService; + this.iamService = iamService; + } + + @Override + public void handle(UserPasswordRecoveredEvent event) { + var response = iamService.getUserById(new GetUserByIdRequest(event.getUserId())); + if (!OK.equals(response.getResponseCode())) { + return; + } + + var dataModel = new HashMap(); + dataModel.put("user", response.getUser()); + dataModel.put("newPassword", event.getPassword()); + + var mailMessage = new MailMessage("recover", dataModel); + mailMessage.setTo(response.getUser().getEmail()); + mailMessage.setSubject("Password recovery completed successfully"); + mailMessageService.send(mailMessage); + + logger.info("Password recovery email sent to user: {}", response.getUser().getEmail()); + } + + @Override + public Class getEventClass() { + return UserPasswordRecoveredEvent.class; + } +} diff --git a/edera-api/notifications/src/main/java/applica/notifications/application/UserRegisteredEventHandler.java b/edera-api/notifications/src/main/java/applica/notifications/application/UserRegisteredEventHandler.java new file mode 100644 index 0000000..10a924d --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/application/UserRegisteredEventHandler.java @@ -0,0 +1,50 @@ +package applica.notifications.application; + +import applica.integration.events.DomainEventHandler; +import applica.iam.sdk.IAMService; +import applica.iam.sdk.events.UserRegisteredEvent; +import applica.iam.sdk.requests.GetUserByIdRequest; +import applica.notifications.integration.MailMessage; +import applica.notifications.integration.MailMessageService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; + +import static applica.iam.sdk.ResponseCodes.OK; + +public class UserRegisteredEventHandler extends DomainEventHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + private final MailMessageService mailMessageService; + private final IAMService iamService; + + public UserRegisteredEventHandler(MailMessageService mailMessageService, IAMService iamService) { + this.mailMessageService = mailMessageService; + this.iamService = iamService; + } + + @Override + public void handle(UserRegisteredEvent event) { + logger.info("Handling user registered event: {}", event); + var response = iamService.getUserById(new GetUserByIdRequest(event.getUserId())); + if (!OK.equals(response.getResponseCode())) { + return; + } + + var dataModel = new HashMap(); + dataModel.put("user", response.getUser()); + dataModel.put("activationCode", event.getActivationCode()); + dataModel.put("domainName", getDomainName()); + dataModel.put("password", event.getGeneratedPassword()); + + var mailMessage = new MailMessage("registration", dataModel); + mailMessage.setTo(response.getUser().getEmail()); + mailMessage.setSubject("Registration completed successfully"); + mailMessageService.send(mailMessage); + } + + @Override + public Class getEventClass() { + return UserRegisteredEvent.class; + } +} diff --git a/edera-api/notifications/src/main/java/applica/notifications/integration/DefaultMailMessageService.java b/edera-api/notifications/src/main/java/applica/notifications/integration/DefaultMailMessageService.java new file mode 100644 index 0000000..79f62f1 --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/integration/DefaultMailMessageService.java @@ -0,0 +1,55 @@ +package applica.notifications.integration; + +import freemarker.template.TemplateException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.MailSender; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.io.StringWriter; + +@SuppressWarnings("unused") +public class DefaultMailMessageService implements MailMessageService { + final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private FreemarkerHelper freemarker; + + @Autowired + private MailSender mailSender; + + @Value("${mail.from}") + private String defaultForm; + + @Override + public void send(MailMessage mailMessage) { + + if (!StringUtils.hasLength(mailMessage.getFrom())) { + mailMessage.setFrom(defaultForm); + } + mailMessage.setText(generateBody(mailMessage)); + mailSender.send(mailMessage); + } + + @Override + public void send(MailMessage... messages) { + for (MailMessage message : messages) { + send(message); + } + } + + private String generateBody(MailMessage mailMessage) { + var writer = new StringWriter(); + try { + var template = freemarker.getTemplate(mailMessage.getTemplate()); + template.process(mailMessage.getDataModel(), writer); + } catch (TemplateException | IOException e) { + logger.error("Unable to process mail registration template", e); + return null; + } + return writer.toString(); + } +} diff --git a/edera-api/notifications/src/main/java/applica/notifications/integration/FreemarkerHelper.java b/edera-api/notifications/src/main/java/applica/notifications/integration/FreemarkerHelper.java new file mode 100644 index 0000000..0451b61 --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/integration/FreemarkerHelper.java @@ -0,0 +1,19 @@ +package applica.notifications.integration; + +import freemarker.template.Configuration; +import freemarker.template.Template; + +import java.io.IOException; + +public class FreemarkerHelper { + final Configuration configuration; + + public FreemarkerHelper(String templatePath) { + configuration = new Configuration(Configuration.VERSION_2_3_31); + configuration.setClassLoaderForTemplateLoading(getClass().getClassLoader(), templatePath); + } + + public Template getTemplate(String name) throws IOException { + return configuration.getTemplate(name); + } +} diff --git a/edera-api/notifications/src/main/java/applica/notifications/integration/MailMessage.java b/edera-api/notifications/src/main/java/applica/notifications/integration/MailMessage.java new file mode 100644 index 0000000..8b2788d --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/integration/MailMessage.java @@ -0,0 +1,23 @@ +package applica.notifications.integration; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.mail.SimpleMailMessage; + +public class MailMessage extends SimpleMailMessage { + @Getter + @Setter + private String template; + + @Getter + @Setter + private Object dataModel; + + public MailMessage(String template, Object dataModel) { + if (!template.endsWith(".ftlh")) { + template += ".ftlh"; + } + this.template = template; + this.dataModel = dataModel; + } +} diff --git a/edera-api/notifications/src/main/java/applica/notifications/integration/MailMessageService.java b/edera-api/notifications/src/main/java/applica/notifications/integration/MailMessageService.java new file mode 100644 index 0000000..9e70fd5 --- /dev/null +++ b/edera-api/notifications/src/main/java/applica/notifications/integration/MailMessageService.java @@ -0,0 +1,6 @@ +package applica.notifications.integration; + +public interface MailMessageService { + void send(MailMessage message); + void send(MailMessage ... messages); +} diff --git a/edera-api/notifications/src/main/resources/templates/activation.ftlh b/edera-api/notifications/src/main/resources/templates/activation.ftlh new file mode 100644 index 0000000..12e176d --- /dev/null +++ b/edera-api/notifications/src/main/resources/templates/activation.ftlh @@ -0,0 +1,3 @@ +Buongiorno ${profile.name} + +Il tuo account è stato attivato con successo \ No newline at end of file diff --git a/edera-api/notifications/src/main/resources/templates/passwordChanged.ftlh b/edera-api/notifications/src/main/resources/templates/passwordChanged.ftlh new file mode 100644 index 0000000..da69c12 --- /dev/null +++ b/edera-api/notifications/src/main/resources/templates/passwordChanged.ftlh @@ -0,0 +1,3 @@ +Buongiorno ${profile.name} + +La tua password è stata cambiata correttamente \ No newline at end of file diff --git a/edera-api/notifications/src/main/resources/templates/recover.ftlh b/edera-api/notifications/src/main/resources/templates/recover.ftlh new file mode 100644 index 0000000..96a0f82 --- /dev/null +++ b/edera-api/notifications/src/main/resources/templates/recover.ftlh @@ -0,0 +1,3 @@ +Buongiorno ${user.profile.name} + +La tua password è stata cambiata con la seguente: ${newPassword} \ No newline at end of file diff --git a/edera-api/notifications/src/main/resources/templates/registration.ftlh b/edera-api/notifications/src/main/resources/templates/registration.ftlh new file mode 100644 index 0000000..8b227ea --- /dev/null +++ b/edera-api/notifications/src/main/resources/templates/registration.ftlh @@ -0,0 +1,7 @@ +Gentile ${user.profile.name}, +di seguito i tuoi dati di accesso: + +Username: ${user.email} +Password: ${password} + +Puoi accedere alla piattaforma cliccando qui. \ No newline at end of file diff --git a/edera-api/pom.xml b/edera-api/pom.xml new file mode 100644 index 0000000..cdf13c5 --- /dev/null +++ b/edera-api/pom.xml @@ -0,0 +1,113 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.0.7 + + + + applica.app + root + ${revision}${sha1}${changelist} + pom + + + + central + Default Repository + default + https://repo1.maven.org/maven2 + + false + + + + artifact-registry + artifactregistry://europe-west1-maven.pkg.dev/applica-general/applica-maven + + true + + + true + + + + + + 1.0 + -SNAPSHOT + + 17 + 1.3.0 + 0.9.1 + 2.3.1 + 1.7 + 1.9.4 + 2.11.0 + 0.1.2 + 4.2 + 1.0-alpha2 + 2.16.0 + 4.5.14 + 2.0.2 + UTF-8 + 1.0.3 + 1.0.13 + 1.0.24 + + + + api + notifications + + + + + + org.codehaus.mojo + flatten-maven-plugin + ${maven.flatten.plugin} + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M7 + + + + + + com.google.cloud.artifactregistry + artifactregistry-maven-wagon + 2.1.0 + + + + + \ No newline at end of file diff --git a/edera-api/scripts/create-infrastructure.sh b/edera-api/scripts/create-infrastructure.sh new file mode 100644 index 0000000..4c7fad0 --- /dev/null +++ b/edera-api/scripts/create-infrastructure.sh @@ -0,0 +1,4 @@ +source set-env.sh +cd tf +terraform init +terraform apply -var="project_id=${PROJECT_ID}" -var="project_name=${PROJECT_NAME}" \ No newline at end of file diff --git a/edera-api/scripts/docker/Dockerfile b/edera-api/scripts/docker/Dockerfile new file mode 100644 index 0000000..38e20d0 --- /dev/null +++ b/edera-api/scripts/docker/Dockerfile @@ -0,0 +1,16 @@ +FROM openjdk:17 +LABEL maintainer Bruno Fortunato (www.applica.guru) + +VOLUME /fileserver + +ARG PROFILE=production +ARG EXECUTABLE=applica.api.Application +ARG PORT=8080 +ARG JAVA_ARGS="" +ARG PROGRAM_ARGS="" +EXPOSE $PORT + +COPY build/* /app/ + +RUN echo java $JAVA_ARGS -jar "/app/$EXECUTABLE" --spring.profiles.active=$PROFILE $PROGRAM_ARGS >> /app/entrypoint.sh +ENTRYPOINT ["/bin/bash", "/app/entrypoint.sh"] diff --git a/edera-api/scripts/init-gcloud.sh b/edera-api/scripts/init-gcloud.sh new file mode 100644 index 0000000..e35f720 --- /dev/null +++ b/edera-api/scripts/init-gcloud.sh @@ -0,0 +1,7 @@ +source set-env.sh +gcloud config configurations create $PROJECT_ID +gcloud config set project $PROJECT_ID +gcloud auth login +gcloud config set compute/region europe-west1 +gcloud config set compute/zone europe-west1-b +gcloud config configurations list \ No newline at end of file diff --git a/edera-api/scripts/init-k8s.sh b/edera-api/scripts/init-k8s.sh new file mode 100644 index 0000000..cf0ed0f --- /dev/null +++ b/edera-api/scripts/init-k8s.sh @@ -0,0 +1,8 @@ +source set-env.sh +gcloud config configurations activate $PROJECT_ID +gcloud container clusters get-credentials default +kubectl get deployments +envsubst < mongodb.yml | kubectl apply -f - +envsubst < api.yml | kubectl apply -f - +envsubst < web.yml | kubectl apply -f - +envsubst < ingress.yml | kubectl apply -f - diff --git a/edera-api/scripts/kube/api.yml b/edera-api/scripts/kube/api.yml new file mode 100644 index 0000000..2b97013 --- /dev/null +++ b/edera-api/scripts/kube/api.yml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: api + labels: + app: api +spec: + replicas: 1 + selector: + matchLabels: + app: api + template: + metadata: + labels: + app: api + spec: + containers: + - image: eu.gcr.io/applica-general/edera-api:latest + name: api + ports: + - containerPort: 8080 + name: api + env: + - name: DOMAIN_NAME + value: https://edera.applica.guru + livenessProbe: + httpGet: + path: /api/actuator/health/liveness + port: api + initialDelaySeconds: 30 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /api/actuator/health/readiness + port: api + initialDelaySeconds: 30 + periodSeconds: 30 + imagePullPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: api + name: api +spec: + type: NodePort + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + selector: + app: api diff --git a/edera-api/scripts/kube/ingress.yml b/edera-api/scripts/kube/ingress.yml new file mode 100644 index 0000000..16d5a71 --- /dev/null +++ b/edera-api/scripts/kube/ingress.yml @@ -0,0 +1,28 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: app-ingress + annotations: + cert-manager.io/cluster-issuer: letsencrypt-production + ingress.kubernetes.io/add-base-url: "false" + ingress.kubernetes.io/rewrite-target: / + kubernetes.io/ingress.class: "nginx" + kubernetes.io/ingress.allow-http: "true" + nginx.ingress.kubernetes.io/ssl-redirect: "false" +spec: + ingressClassName: nginx + tls: + - hosts: + - edera.applica.guru + secretName: edera-secret + rules: + - host: edera.applica.guru + http: + paths: + - pathType: Prefix + backend: + service: + name: api + port: + number: 8080 + path: /api \ No newline at end of file diff --git a/edera-api/scripts/set-env.sh b/edera-api/scripts/set-env.sh new file mode 100644 index 0000000..4255e5a --- /dev/null +++ b/edera-api/scripts/set-env.sh @@ -0,0 +1,4 @@ +export PROJECT_ID=applica-general +export PROJECT_NAME=applica-general +export NAMESPACE=edera +export PROFILE=production \ No newline at end of file diff --git a/edera-api/scripts/tf/main.tf b/edera-api/scripts/tf/main.tf new file mode 100644 index 0000000..4ddc2c4 --- /dev/null +++ b/edera-api/scripts/tf/main.tf @@ -0,0 +1,75 @@ +data "google_billing_account" "billing_account" { + billing_account = var.billing_account + open = true +} + +resource "google_project" "project" { + name = var.project_name + project_id = var.project_id + + billing_account = data.google_billing_account.billing_account.billing_account +} + +resource "google_service_account" "service_account" { + account_id = "automation" + + depends_on = [google_project.project] +} + +resource "google_project_iam_member" "gcr_publisher_storage_admin" { + project = var.project_id + role = "roles/owner" + member = "serviceAccount:${google_service_account.service_account.email}" +} + +resource "google_service_account_key" "service_account_key" { + service_account_id = google_service_account.service_account.account_id +} + +resource "local_file" "service_account_key_file" { + content = google_service_account_key.service_account_key.private_key + filename = "${path.module}/service-account.json.base64" +} + +resource "google_project_service" "container_registry_service" { + project = var.project_id + service = "containerregistry.googleapis.com" + + depends_on = [google_project.project] +} +/* +resource "google_project_service" "container_service" { + project = var.project_id + service = "container.googleapis.com" + + depends_on = [google_project.project] +} +*/ +resource "google_container_registry" "container_registry" { + location = "EU" + + depends_on = [google_project_service.container_registry_service] +} + +/* +resource "google_container_cluster" "primary" { + name = "default" + location = var.zone + initial_node_count = 1 + node_config { + service_account = google_service_account.service_account.email + machine_type = "e2-micro" + oauth_scopes = [ + "https://www.googleapis.com/auth/cloud-platform" + ] + } + depends_on = [google_project.container_service] +} + +resource "google_compute_address" "ip_address" { + name = "external-ip" + + depends_on = [google_project.project] +} + +*/ \ No newline at end of file diff --git a/edera-api/scripts/tf/mongo-atlas.tf b/edera-api/scripts/tf/mongo-atlas.tf new file mode 100644 index 0000000..5d8916d --- /dev/null +++ b/edera-api/scripts/tf/mongo-atlas.tf @@ -0,0 +1,60 @@ +# resource "random_password" "password" { +# length = 16 +# special = true +# override_special = "!#$%&*()-_=+[]{}<>:?" +# } +# +# locals { +# mongodb_atlas_api_pub_key = var.mongodb_atlas_public_key +# mongodb_atlas_api_pri_key = var.mongodb_atlas_private_key +# mongodb_atlas_org_id = var.mongodb_atlas_org_id +# +# mongodb_atlas_database_username = var.project_id +# mongodb_atlas_database_user_password = random_password.password.result +# } +# +# +# resource "mongodbatlas_project" "project" { +# name = var.project_name +# org_id = var.mongodb_atlas_org_id +# } +# +# resource "mongodbatlas_cluster" "cluster" { +# project_id = mongodbatlas_project.project.id +# name = "default-cluster" +# +# provider_name = "TENANT" +# backing_provider_name = "GCP" +# provider_region_name = "WESTERN_EUROPE" +# provider_instance_size_name = "M0" +# } +# +# resource "mongodbatlas_database_user" "user" { +# username = local.mongodb_atlas_database_username +# password = local.mongodb_atlas_database_user_password +# project_id = mongodbatlas_project.project.id +# auth_database_name = "admin" +# +# roles { +# role_name = "readWriteAnyDatabase" +# database_name = "admin" +# } +# } +# +# resource "mongodbatlas_project_ip_access_list" "my_ipaddress" { +# project_id = mongodbatlas_project.project.id +# cidr_block = "0.0.0.0/0" +# comment = "Everyone (dev only)" +# } +# +# output "mongo_connection_string" { +# value = mongodbatlas_cluster.cluster.connection_strings.0.standard_srv +# } +# +# output "mongo_credentials" { +# value = { +# user = local.mongodb_atlas_database_username +# password = local.mongodb_atlas_database_user_password +# } +# sensitive = true +# } \ No newline at end of file diff --git a/edera-api/scripts/tf/provider.tf b/edera-api/scripts/tf/provider.tf new file mode 100644 index 0000000..93b069f --- /dev/null +++ b/edera-api/scripts/tf/provider.tf @@ -0,0 +1,5 @@ +provider "google" { + project = var.project_id + region = var.region + zone = var.zone +} \ No newline at end of file diff --git a/edera-api/scripts/tf/service-account.json.base64 b/edera-api/scripts/tf/service-account.json.base64 new file mode 100644 index 0000000..6841642 --- /dev/null +++ b/edera-api/scripts/tf/service-account.json.base64 @@ -0,0 +1,42 @@ +ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiYXBwbGljYS1n +ZW5lcmFsIiwKICAicHJpdmF0ZV9rZXlfaWQiOiAiNDk3YzZmNTU5N2Y0NTI3NWY3ZTlmZTQwMzFj +NGI4MjllMjY4NzEyMSIsCiAgInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVkt +LS0tLVxuTUlJRXZnSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2d3Z2dTa0FnRUFBb0lCQVFD +dDRrY1B3UVJ6bUQ3b1xucHlVQVBlTnBnS01TWGxTM25CYmVtSUFlcmk3dm5GeHJIMFV4RlJndmRN +VTlzRTJ6L0h5WXNTMGNnR1R3Y01Fd1xuQlVVYVF3UWpUMFVxdlBrN3ByY2lOWURSTXVNQXY1MW5Y +WkpRZ0RYeitMSG15VldhaE1VRTlMczM4YzJxeUFpalxuVTBjakhqTmxsMmp3S2J5OWJVNUVUcWlT +eEtxdE1FRVlwSUFzV2kvWG1iekx6NlVtSnladm56ZCtkRFNRQTU3aFxuY0NsOEFTdlBpQTdIeXVz +b1lzVWJ2S2xRS0tmcndtV3NBUllEVjdRc0t6bEpsR0ViWE1sWlozdzB1VCszVkxXOVxuTWMyS1Fo +SGpvaWpoTW9yRjdVdjVWMjJrTWkyL2V4RkI3L3ErbllCejU5K1MxUXZlRmpCd3E5L0gwQTRyTXpU +a1xubWZDYzhjMWZBZ01CQUFFQ2dnRUFOR1dsdlRrUUl0Y2pTYzhvSnJEL2lLaXpPeE5DMnd0Rmx2 +RUVWbnB0ZVZXNFxuUWExc0Y3VEFFM2pRQU4xU0pPVDJGTHI3R1lZVkpLRU5qZTlnbWQvTTdPanpz +a084cEwyQm5PVGJldTZuR2ZBalxudWVTbjlPc1ZsdjEvZWtoOEs3Skxma2xTNnpKSm8rZGdOdnNl +eWhYTkxoVllrVm82WGlpRWQ2L3VPei9aSUpPVVxuTFlHN1hPVHExNWhKcmZaM2trdDBBRldJc2NK +SXVFbFBlUTJOaDVWY3VSeVJwUVQwaFA0NUlRUTZFdElBWXp4OVxuUnRGUWFhd2tpWVFqZ0RkelFO +Qm1tUHN2ZWc4Y2JkQXlWZVlxcitaVkFiNk1pWjJ2N01RR0hyeEFBcnhSeXRMZlxuMmd2VUl0K3pv +dmJBemo3Q3h0YjUvS3JDdHUwMC9aWTcwNzRxTExnR1NRS0JnUUR2NXRkNmxWbUg5cXl3TThTc1xu +NnA5NE5lTVFrbU9vME41SjBUUisxTGFITnBkdjBaY3B0bEJDS0lCTXorVTBBc0p0cG11dlpGTGdH +cmp6U3E2cFxuVFlGUis0Mlc1NjJGMkoxWmlKZmdnWDdubWp3TmhUNzdrdWUwbjVWbE1iTHBUN0Iz +ajB6V3Ftc0hqZ09lZWhDblxueEIwOXpKcXJEYm96MkV3UGVvRkhDVjB5dHdLQmdRQzVqVmpJd21F +d01PU2g5UHF3QzJ5SVBYeS81UkpGTG4yL1xuNWxzUmhRbkkrTkxTZUJjWnRIV1BiOWcyNVF6SFVV +dWRRNGhiYWpHaDM1R2t5SGtIcjJ5MGVjdTFUd2pVTitGMFxubzdhejRzekk4a3kzRk9sRUpvdXM4 +enFNQWsrYnhFR1hrUUNkWmFiL0ltS0svR1dRK21RcXlDV0RtUkFvR3NVcVxuTEJNdUhKOXltUUtC +Z0YrRnJBRGNYT1RkWEk5Z1hZeDRjM3piQUFtR01IWjBqRDRhTmV2V2FNTllBbDU4dHRMZVxuREFE +N3ZYSllTU3czZVJGTjlZekZ4cFlETGVkNXNpZ3BlemVZa1Iwb0xKaWgwcTFtelFxUXBXWTBySHE1 +dG9WWFxuVGpsR1hhY0liZk9tVGw2Y3lYeWtLSysrWlVTQjJBWGsrYnUwcjFVeXh4U0RxRzExV3Vw +ZEdTWHJBb0dCQUo2YVxucm9CMGZvU2wxbGlGd2Q3RzlRK0RsMldqMWJraTQwUXNFRDNxZlJHM2R1 +V0cxeUFXdThKT3RQOC9UR3YzRm00blxuc3ArSkowR1ppN0hSMW5wMlBiSUt4ZENGN1NNUlhQckpr +YnN6cXg0ODFzeEw2SlJqYWxMOFdWZ2lCWkE4OG1BdlxuQnRxRGNIcDNGc3A4c2doNXJ6Tk9mNXA4 +Tkc1RGE3TC9sNmw3dCtOSkFvR0JBT2d6MHM1WGErRzZLTmlVN0IySFxuc0l2MmRNMzZvNlZ3a21P +T3FjdCtkVS8ycG12ZGM4aFpDbFZGYXBQeWZ4djFqVnNjSDUrZG5FaFJIaTEzYXdIU1xuVzc3MnQ5 +WUdBNWpGb2dnakVPRU5QbVR2QUwxd01NL0ExRCtmanVaWVArOEVDaEU0QmFmbVN3WWZGVzJRQmxE +eFxuZlhoOHNmT0FnMjhuMEc1QWNGcXZVSFJNXG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4i +LAogICJjbGllbnRfZW1haWwiOiAiYml0YnVja2V0LXBpcGVsaW5lc0BhcHBsaWNhLWdlbmVyYWwu +aWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLAogICJjbGllbnRfaWQiOiAiMTA4Mzk0ODE1Njc3NDgx +NDI2MjYwIiwKICAiYXV0aF91cmkiOiAiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1 +dGgyL2F1dGgiLAogICJ0b2tlbl91cmkiOiAiaHR0cHM6Ly9vYXV0aDIuZ29vZ2xlYXBpcy5jb20v +dG9rZW4iLAogICJhdXRoX3Byb3ZpZGVyX3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29v +Z2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwKICAiY2xpZW50X3g1MDlfY2VydF91cmwiOiAi +aHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vcm9ib3QvdjEvbWV0YWRhdGEveDUwOS9iaXRidWNr +ZXQtcGlwZWxpbmVzJTQwYXBwbGljYS1nZW5lcmFsLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwK +ICAidW5pdmVyc2VfZG9tYWluIjogImdvb2dsZWFwaXMuY29tIgp9Cg== \ No newline at end of file diff --git a/edera-api/scripts/tf/terraform.tfstate b/edera-api/scripts/tf/terraform.tfstate new file mode 100644 index 0000000..93fa8c2 --- /dev/null +++ b/edera-api/scripts/tf/terraform.tfstate @@ -0,0 +1,238 @@ +{ + "version": 4, + "terraform_version": "1.3.6", + "serial": 92, + "lineage": "55ea8741-2812-cc86-b261-6b858399bdf0", + "outputs": {}, + "resources": [ + { + "mode": "data", + "type": "google_billing_account", + "name": "billing_account", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "billing_account": "011783-8751C0-5C335B", + "display_name": "My Billing Account 1", + "id": "011783-8751C0-5C335B", + "name": "billingAccounts/011783-8751C0-5C335B", + "open": true, + "project_ids": [ + "archetype-api-1", + "archetype-api-2", + "commodo-onepunch", + "commodo-spaziorelax", + "compost-community", + "inponzio-257109", + "medical-viewer" + ] + }, + "sensitive_attributes": [] + } + ] + }, + { + "mode": "managed", + "type": "google_container_registry", + "name": "container_registry", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "bucket_self_link": "https://www.googleapis.com/storage/v1/b/eu.artifacts.archetype-api-2.appspot.com", + "id": "eu.artifacts.archetype-api-2.appspot.com", + "location": "EU", + "project": null + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "data.google_billing_account.billing_account", + "google_project.project", + "google_project_service.container_registry_service" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_project", + "name": "project", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 1, + "attributes": { + "auto_create_network": true, + "billing_account": "011783-8751C0-5C335B", + "folder_id": null, + "id": "projects/archetype-api-2", + "labels": {}, + "name": "archetype-api", + "number": "825727680893", + "org_id": null, + "project_id": "archetype-api-2", + "skip_delete": null, + "timeouts": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6NjAwMDAwMDAwMDAwLCJyZWFkIjo2MDAwMDAwMDAwMDAsInVwZGF0ZSI6NjAwMDAwMDAwMDAwfSwic2NoZW1hX3ZlcnNpb24iOiIxIn0=", + "dependencies": [ + "data.google_billing_account.billing_account" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_project_iam_member", + "name": "gcr_publisher_storage_admin", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "condition": [], + "etag": "BwXxh/eZ+/0=", + "id": "archetype-api-2/roles/owner/serviceAccount:automation@archetype-api-2.iam.gserviceaccount.com", + "member": "serviceAccount:automation@archetype-api-2.iam.gserviceaccount.com", + "project": "archetype-api-2", + "role": "roles/owner" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "google_service_account.service_account" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_project_service", + "name": "container_registry_service", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "disable_dependent_services": null, + "disable_on_destroy": true, + "id": "archetype-api-2/containerregistry.googleapis.com", + "project": "archetype-api-2", + "service": "containerregistry.googleapis.com", + "timeouts": null + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInJlYWQiOjYwMDAwMDAwMDAwMCwidXBkYXRlIjoxMjAwMDAwMDAwMDAwfX0=", + "dependencies": [ + "data.google_billing_account.billing_account", + "google_project.project" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_service_account", + "name": "service_account", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "account_id": "automation", + "description": "", + "disabled": false, + "display_name": "", + "email": "automation@archetype-api-2.iam.gserviceaccount.com", + "id": "projects/archetype-api-2/serviceAccounts/automation@archetype-api-2.iam.gserviceaccount.com", + "member": "serviceAccount:automation@archetype-api-2.iam.gserviceaccount.com", + "name": "projects/archetype-api-2/serviceAccounts/automation@archetype-api-2.iam.gserviceaccount.com", + "project": "archetype-api-2", + "timeouts": null, + "unique_id": "110113293688327852504" + }, + "sensitive_attributes": [], + "private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjozMDAwMDAwMDAwMDB9fQ==", + "dependencies": [ + "data.google_billing_account.billing_account", + "google_project.project" + ] + } + ] + }, + { + "mode": "managed", + "type": "google_service_account_key", + "name": "service_account_key", + "provider": "provider[\"registry.terraform.io/hashicorp/google\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "id": "projects/archetype-api-2/serviceAccounts/automation@archetype-api-2.iam.gserviceaccount.com/keys/b46d12f9f90569f6a6ffb813b8033dfbce52f491", + "keepers": null, + "key_algorithm": "KEY_ALG_RSA_2048", + "name": "projects/archetype-api-2/serviceAccounts/automation@archetype-api-2.iam.gserviceaccount.com/keys/b46d12f9f90569f6a6ffb813b8033dfbce52f491", + "private_key": "ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiYXJjaGV0eXBlLWFwaS0yIiwKICAicHJpdmF0ZV9rZXlfaWQiOiAiYjQ2ZDEyZjlmOTA1NjlmNmE2ZmZiODEzYjgwMzNkZmJjZTUyZjQ5MSIsCiAgInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVktLS0tLVxuTUlJRXZBSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS1l3Z2dTaUFnRUFBb0lCQVFDeXhMbFQvWFZuR1llblxuMG45U3ZXU3lnYW5PT2hGcE11V1Z3S3hvSlZtL241bnU0U2hWcHVVenNOQTdNL0YwNEw1RFBlNUg4ZWVTVE1Gd1xuZkJZWWZHZmZraWFlVFBzNm11SkpINzdDa1QvTTBDTUVVU2dBTjBtRVNUNWxtTnFIY1dNSTFheFE3VVR2Rndpc1xuTUh6SHRSVmtKaXlmbSt5MnNGSzByVk00V3NBUFNEU2hyYTVUQnBnSjlEQTdEOUZ0Z2VhTHg3WUNPNWFSMEN1NFxubjZjZjdLTzFwNjNvZFNsM2EwVEdxVGZ1V0dxRHNNbXoxUmI2NVlvM096YjMwczVxYi9wcVJZaGk4ekI3SUtDQ1xuWWVydVJhQ2UwczlBbTNwZ2FnY1NPVFJ1d3R0eTJobUZOdjZ3Nk1kUWdwSUpxSUI1b0hGKzRLUXdNaFJWbkd2UVxuWktlUXpHNzdBZ01CQUFFQ2dnRUFESFhaMVJqZGpnb2hnbmtSbHRyTW9nU1hxV0F5eG5wZHRrcHZ1ZktnaHRMQlxuRC8xeHFrYXZ3eUtYNFFpRjAvZTJTMG1OeWtYNk5pQlRlMXVxenBvZFEyQVVnUVFzbnJFZEJLdkp5QllIdEdidFxuaWVkK09rV2dRakE0d1N3ZVQwSi8vS1dvRlJ2MHFoV1k3U2VVQ3ZkOFBqYks5WFVRMHNzSGVNQjhCSG1PMllHNVxuQzJhMGc5Z3hIR2Zya1NtUDlpYzFDM1U4eU1QVE5Md3ZmU25URWkwU0FWKytUcVd2K1p5Z1ZZNENvWWxrN0h5SVxuNHZSTEdXZ1NibVBsL3FuU1hMVm9SN3FPK1JXZ1lxWnpkUmVwc2RGZVdhZ2kxSGNRcHRDMzlJMG1hU2taNHY0alxuVDhSR0tKNVExRVhLbDdKNENnUHhSN21QVGxZT08rcFUrU3hhdjA4SndRS0JnUURoLzFlbVZseUJ6QVNjM0h4NVxuUDl0M05xRU9BV0FEalduRHF2Y3N2MERPUXJYdTZ4Uzd4TlZkMjR1eHV2RWZITHFtMGhTWWJkT3FQTVVjOE5ZMFxuQnZvbktmbVdxQkJPcjIrK250V1ZrVU5DbUZieUQyaFFuN0ZmbnAxNFhDay9PNDBlR01CQ085RFljdmVmVXRKMVxubnNvQjFVS01yTXRyRzQ3YjZ5THVoNmhndlFLQmdRREtnRWJLM3M5NEszOExkbitOL3A4VkVWTUhLWjlHVWY4TlxuYWZFWWFvYlYvQW1HbHU2ZzJPSjFYZnR3dEw5Qk5aQVFGSkpzdnhzVExNVERXdFg5R3RlN001V0xUaUdSRkdMNlxuV1VrbXAwTHJGT3BhQlNnZHhEc3dXTjdSci81UXFvV1JTUkdIUjQrT3hzRkNxS2R1SWxrcWFjdHRtWVJ4aGNwRFxuQ0puVFNFR1dGd0tCZ0VmQkVzczFVRm5GdFJFNDBDeVBJZGRQK1FMQlhRTER1M2pzcDE0RnUwWEIySkhyQWNJOFxuVktKZ09wSkxrSk1ZUkFzRFdKYXRDQzljN0Jpc1B0WjJBS2ErcFFnNGhEVDNicnRQSXZGQ0ZlRG5EWFA5Z0ZsWVxuMnJCSlpDWDYzUDIrb3FlVHBEZGpWb1Bpdk14Uk41RXd3V0tqbTJXZTExZENnTEZDanV5OUZiRGhBb0dBR0RaV1xuUUpON2d3YlFYZktCTmQwbjhFRHVDSUUxaGhidnhBN1N3UFNid3FJc0VXZWlpS0RtRXRwMTRmZjZsalZ0VUQ3bFxuY3hNMmpZaGd6bXJpQXkxZWRnZW83Y3Nkd0ZjTHJwdFdYOFRILzR1MHFhYk1NU0x4WU1wL2VkcnRNWC95RUhrSVxuRzRDMjdYOWVSRFllTHREMGtGbXQ5U0RSOFREcUNqSFJFcTRsQ1drQ2dZQXNLaGUwbEloSHhYOG01aHVtblRiUFxuYkt1czMxemZ6NHFhdGJ0ZitkUlJZTi8wV3kveFBqOVNORjhSc1BZUlZOOVBRUXZCOUVzcExjbHNVaW5LMDArMFxuSk1jV2VmUHpJbVhlUU5GSEJzMUpGU1VtZlZEb3QrOEFPMm9OcXdST3dUcmxobllxK1FKK1V5b1lqS0R3bS9CMlxuR0JkVkw5V1V3NVpyZmxYbmU1THEydz09XG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4iLAogICJjbGllbnRfZW1haWwiOiAiYXV0b21hdGlvbkBhcmNoZXR5cGUtYXBpLTIuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLAogICJjbGllbnRfaWQiOiAiMTEwMTEzMjkzNjg4MzI3ODUyNTA0IiwKICAiYXV0aF91cmkiOiAiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL2F1dGgiLAogICJ0b2tlbl91cmkiOiAiaHR0cHM6Ly9vYXV0aDIuZ29vZ2xlYXBpcy5jb20vdG9rZW4iLAogICJhdXRoX3Byb3ZpZGVyX3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwKICAiY2xpZW50X3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vcm9ib3QvdjEvbWV0YWRhdGEveDUwOS9hdXRvbWF0aW9uJTQwYXJjaGV0eXBlLWFwaS0yLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg==", + "private_key_type": "TYPE_GOOGLE_CREDENTIALS_FILE", + "public_key": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvRENDQWVTZ0F3SUJBZ0lJTjF6QmJlakpuOVl3RFFZSktvWklodmNOQVFFRkJRQXdJREVlTUJ3R0ExVUUKQXhNVk1URXdNVEV6TWprek5qZzRNekkzT0RVeU5UQTBNQ0FYRFRJek1ERXdOVEUxTWpRek4xb1lEems1T1RreApNak14TWpNMU9UVTVXakFnTVI0d0hBWURWUVFERXhVeE1UQXhNVE15T1RNMk9EZ3pNamM0TlRJMU1EUXdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3l4TGxUL1hWbkdZZW4wbjlTdldTeWdhbk8KT2hGcE11V1Z3S3hvSlZtL241bnU0U2hWcHVVenNOQTdNL0YwNEw1RFBlNUg4ZWVTVE1Gd2ZCWVlmR2Zma2lhZQpUUHM2bXVKSkg3N0NrVC9NMENNRVVTZ0FOMG1FU1Q1bG1OcUhjV01JMWF4UTdVVHZGd2lzTUh6SHRSVmtKaXlmCm0reTJzRkswclZNNFdzQVBTRFNocmE1VEJwZ0o5REE3RDlGdGdlYUx4N1lDTzVhUjBDdTRuNmNmN0tPMXA2M28KZFNsM2EwVEdxVGZ1V0dxRHNNbXoxUmI2NVlvM096YjMwczVxYi9wcVJZaGk4ekI3SUtDQ1llcnVSYUNlMHM5QQptM3BnYWdjU09UUnV3dHR5MmhtRk52Nnc2TWRRZ3BJSnFJQjVvSEYrNEtRd01oUlZuR3ZRWktlUXpHNzdBZ01CCkFBR2pPREEyTUF3R0ExVWRFd0VCL3dRQ01BQXdEZ1lEVlIwUEFRSC9CQVFEQWdlQU1CWUdBMVVkSlFFQi93UU0KTUFvR0NDc0dBUVVGQndNQ01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQ1BFYTB0V2Z6dmgrdHNBVzFRU0hrUwp5dnQyUUNYQXZob1Y1N01QVGtjbzJCa0h0VGRMN3Zvb0pLNjBxdXR3cVQxRWh1eHV1NjJ2b2k2enpIRjlNRitlCnRtS3U0SDZ6ODRjNy8vM2FJTDhuVnJwT3VSUzJBeHA4UEUzRUVSUENxU1BJcHNJVHE5d0M1aFFHNzhpSVFUeHQKcFQzejlWencxTHg5aHk3WTkrTVFiNHU5ZW5CWlVsalIyVWtrSHJDcGtFNEF4cUJYUlVyU2lFQnlwUUdBNlBnTwo1TXhGakZFbm4rNGk5eWhQZDYyVnl5Umt4TDNvYXFYUFpZL2psVHRucGdIRGU3QTV4aXBOdmR6QkRTbzM1Nmc1CmlsOE5lZ2ZVcTllYjdKRkg3RGJxQURpcTVPWGQxUm1TM0htSmVPQll2bEdZYlRKQjdmT3hOVHcrYlF4TE5CY2wKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=", + "public_key_data": null, + "public_key_type": "TYPE_X509_PEM_FILE", + "service_account_id": "automation", + "valid_after": "2023-01-05T15:24:37Z", + "valid_before": "9999-12-31T23:59:59Z" + }, + "sensitive_attributes": [], + "private": "bnVsbA==", + "dependencies": [ + "data.google_billing_account.billing_account", + "google_project.project", + "google_service_account.service_account" + ] + } + ] + }, + { + "mode": "managed", + "type": "local_file", + "name": "service_account_key_file", + "provider": "provider[\"registry.terraform.io/hashicorp/local\"]", + "instances": [ + { + "schema_version": 0, + "attributes": { + "content": "ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiYXJjaGV0eXBlLWFwaS0yIiwKICAicHJpdmF0ZV9rZXlfaWQiOiAiYjQ2ZDEyZjlmOTA1NjlmNmE2ZmZiODEzYjgwMzNkZmJjZTUyZjQ5MSIsCiAgInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVktLS0tLVxuTUlJRXZBSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS1l3Z2dTaUFnRUFBb0lCQVFDeXhMbFQvWFZuR1llblxuMG45U3ZXU3lnYW5PT2hGcE11V1Z3S3hvSlZtL241bnU0U2hWcHVVenNOQTdNL0YwNEw1RFBlNUg4ZWVTVE1Gd1xuZkJZWWZHZmZraWFlVFBzNm11SkpINzdDa1QvTTBDTUVVU2dBTjBtRVNUNWxtTnFIY1dNSTFheFE3VVR2Rndpc1xuTUh6SHRSVmtKaXlmbSt5MnNGSzByVk00V3NBUFNEU2hyYTVUQnBnSjlEQTdEOUZ0Z2VhTHg3WUNPNWFSMEN1NFxubjZjZjdLTzFwNjNvZFNsM2EwVEdxVGZ1V0dxRHNNbXoxUmI2NVlvM096YjMwczVxYi9wcVJZaGk4ekI3SUtDQ1xuWWVydVJhQ2UwczlBbTNwZ2FnY1NPVFJ1d3R0eTJobUZOdjZ3Nk1kUWdwSUpxSUI1b0hGKzRLUXdNaFJWbkd2UVxuWktlUXpHNzdBZ01CQUFFQ2dnRUFESFhaMVJqZGpnb2hnbmtSbHRyTW9nU1hxV0F5eG5wZHRrcHZ1ZktnaHRMQlxuRC8xeHFrYXZ3eUtYNFFpRjAvZTJTMG1OeWtYNk5pQlRlMXVxenBvZFEyQVVnUVFzbnJFZEJLdkp5QllIdEdidFxuaWVkK09rV2dRakE0d1N3ZVQwSi8vS1dvRlJ2MHFoV1k3U2VVQ3ZkOFBqYks5WFVRMHNzSGVNQjhCSG1PMllHNVxuQzJhMGc5Z3hIR2Zya1NtUDlpYzFDM1U4eU1QVE5Md3ZmU25URWkwU0FWKytUcVd2K1p5Z1ZZNENvWWxrN0h5SVxuNHZSTEdXZ1NibVBsL3FuU1hMVm9SN3FPK1JXZ1lxWnpkUmVwc2RGZVdhZ2kxSGNRcHRDMzlJMG1hU2taNHY0alxuVDhSR0tKNVExRVhLbDdKNENnUHhSN21QVGxZT08rcFUrU3hhdjA4SndRS0JnUURoLzFlbVZseUJ6QVNjM0h4NVxuUDl0M05xRU9BV0FEalduRHF2Y3N2MERPUXJYdTZ4Uzd4TlZkMjR1eHV2RWZITHFtMGhTWWJkT3FQTVVjOE5ZMFxuQnZvbktmbVdxQkJPcjIrK250V1ZrVU5DbUZieUQyaFFuN0ZmbnAxNFhDay9PNDBlR01CQ085RFljdmVmVXRKMVxubnNvQjFVS01yTXRyRzQ3YjZ5THVoNmhndlFLQmdRREtnRWJLM3M5NEszOExkbitOL3A4VkVWTUhLWjlHVWY4TlxuYWZFWWFvYlYvQW1HbHU2ZzJPSjFYZnR3dEw5Qk5aQVFGSkpzdnhzVExNVERXdFg5R3RlN001V0xUaUdSRkdMNlxuV1VrbXAwTHJGT3BhQlNnZHhEc3dXTjdSci81UXFvV1JTUkdIUjQrT3hzRkNxS2R1SWxrcWFjdHRtWVJ4aGNwRFxuQ0puVFNFR1dGd0tCZ0VmQkVzczFVRm5GdFJFNDBDeVBJZGRQK1FMQlhRTER1M2pzcDE0RnUwWEIySkhyQWNJOFxuVktKZ09wSkxrSk1ZUkFzRFdKYXRDQzljN0Jpc1B0WjJBS2ErcFFnNGhEVDNicnRQSXZGQ0ZlRG5EWFA5Z0ZsWVxuMnJCSlpDWDYzUDIrb3FlVHBEZGpWb1Bpdk14Uk41RXd3V0tqbTJXZTExZENnTEZDanV5OUZiRGhBb0dBR0RaV1xuUUpON2d3YlFYZktCTmQwbjhFRHVDSUUxaGhidnhBN1N3UFNid3FJc0VXZWlpS0RtRXRwMTRmZjZsalZ0VUQ3bFxuY3hNMmpZaGd6bXJpQXkxZWRnZW83Y3Nkd0ZjTHJwdFdYOFRILzR1MHFhYk1NU0x4WU1wL2VkcnRNWC95RUhrSVxuRzRDMjdYOWVSRFllTHREMGtGbXQ5U0RSOFREcUNqSFJFcTRsQ1drQ2dZQXNLaGUwbEloSHhYOG01aHVtblRiUFxuYkt1czMxemZ6NHFhdGJ0ZitkUlJZTi8wV3kveFBqOVNORjhSc1BZUlZOOVBRUXZCOUVzcExjbHNVaW5LMDArMFxuSk1jV2VmUHpJbVhlUU5GSEJzMUpGU1VtZlZEb3QrOEFPMm9OcXdST3dUcmxobllxK1FKK1V5b1lqS0R3bS9CMlxuR0JkVkw5V1V3NVpyZmxYbmU1THEydz09XG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4iLAogICJjbGllbnRfZW1haWwiOiAiYXV0b21hdGlvbkBhcmNoZXR5cGUtYXBpLTIuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLAogICJjbGllbnRfaWQiOiAiMTEwMTEzMjkzNjg4MzI3ODUyNTA0IiwKICAiYXV0aF91cmkiOiAiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL2F1dGgiLAogICJ0b2tlbl91cmkiOiAiaHR0cHM6Ly9vYXV0aDIuZ29vZ2xlYXBpcy5jb20vdG9rZW4iLAogICJhdXRoX3Byb3ZpZGVyX3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwKICAiY2xpZW50X3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vcm9ib3QvdjEvbWV0YWRhdGEveDUwOS9hdXRvbWF0aW9uJTQwYXJjaGV0eXBlLWFwaS0yLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg==", + "content_base64": null, + "directory_permission": "0777", + "file_permission": "0777", + "filename": "./service-account.json.base64", + "id": "f2c804478e39143d210adb7faef050e2992002e4", + "sensitive_content": null, + "source": null + }, + "sensitive_attributes": [ + [ + { + "type": "get_attr", + "value": "content" + } + ] + ], + "private": "bnVsbA==", + "dependencies": [ + "data.google_billing_account.billing_account", + "google_project.project", + "google_service_account.service_account", + "google_service_account_key.service_account_key" + ] + } + ] + } + ], + "check_results": null +} diff --git a/edera-api/scripts/tf/variables.tf b/edera-api/scripts/tf/variables.tf new file mode 100644 index 0000000..63aa307 --- /dev/null +++ b/edera-api/scripts/tf/variables.tf @@ -0,0 +1,22 @@ +variable "project_id" { + type = string +} + +variable "project_name" { + type = string +} + +variable "region" { + type = string + default = "europe-west1" +} + +variable "zone" { + type = string + default = "europe-west1-b" +} + +variable "billing_account" { + type = string + default = "011783-8751C0-5C335B" +} \ No newline at end of file