Roberto Vormittag
Virgiliu Ratoi

v2018.11, 26-11-2018

About

JDK
Spring Boot
Maven

The ESPD service is a web-based solution which allows the Member States and European Institutions to exchange structured e-procurement information in a harmonised manner. The system is not a persistent storage but rather a transformation service which enables the management of XML based documents for each procurement submitted.

The ESPD service is provided as a web-based system and the output of it provided as XML files. In addition, the ESPD service will become part of the Connecting European Facility (CEF) eProcurement DSI (Digital Service Infrastructure). The CEF will help the Member States to implement an ESPD service in their own country and provide additional services to their users.

System requirements

The ESPD application requires the following tools to run so please make sure that you have them installed prior to proceeding with the installation of the project.

Installation

Configure the Git repository

  1. Fork the ESPD Git repository by clicking on the Fork button on the top-right corner of the repository page. Forking a repository allows you to freely experiment with changes without affecting the original project. Most commonly, forks are used to either propose changes to someone else’s project or to use someone else’s project as a starting point for your own idea.

  2. Create a local clone of your fork

    1. On GitHub, navigate to your fork of the ESPD Git repository.

    2. Under your repository name, click the Copy to clipboard button to copy the URL for the repository.

    3. Run the git clone <URL> command on your computer, after pasting the URL you copied in the previous step. Now, you have a local copy of your fork of the ESPD Git repository.

  3. Configure Git to sync your fork with the original ESPD Git repository. When you fork a project in order to propose changes to the original repository, you can configure Git to pull changes from the original, or upstream, repository into the local clone of your fork.

    1. On GitHub, navigate to the ESPD Git repository repository.

    2. Under the repository name, click the Copy to clipboard button to copy the URL for the repository.

    3. Change directories to the location of the fork you cloned in the previous step.

    4. Execute git remote -v to see the current configured remote repositories for your fork.

    5. Type git remote add upstream <URL> by pasting the URL you copied in Step b.

    6. To verify the new upstream repository you’ve specified for your fork, execute git remote -v again. You should see the URL for your fork as origin, and the URL for the original repository as upstream.

$ git remote -v
origin    https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
origin    https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
upstream  https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (fetch)
upstream  https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (push)

Now you can keep your fork synced with the upstream repository with a few Git commands. For more information, please see the Syncing a fork page.

Quite often people working in a team and using the same repository or upstream prefer different operating systems. This may result in problems with line endings because Unix, Linux, and OS X use LF and Windows uses CRLF to denote the end of a line. To have Git solve such problems automatically, you need to set the core.autocrlf attribute to true on Windows and to input on Linux and OS X. For more details on the meaning of the core.autocrlf attribute, see the article Dealing with Line Endings. You can change the configuration manually by running git config --global core.autocrlf true on Windows or git config --global core.autocrlf input on Linux and OS X.
Each major application version will have a dedicated branch so you can checkout the code for a particular version. The name convention adopted for release branches is YYYY.MM. The master branch contains the version currently deployed in production. The develop branch contains the code for the next version of ESPD. The gh-pages branch is reserved for documentation. If you want to be isolated from changes you should branch from master or from a specific release branch.

Building and running the ESPD application

This section goes into detail about how you can build and run the ESPD application.

Building the application

The ESPD uses Maven as the primary build system and is structured as a multi-module Maven project.

After getting access to the source code and cloning it on your computer, you can now build the project with Maven.

  1. Change directories to the location of the cloned Git repository on your machine.

  2. Perform a mvn clean package and the project dependencies should be downloaded and the espd-web and espd-docs modules should be built.

Running the application

The easiest way to run the application is with an embedded container (default is Tomcat) by invoking the main method from the eu.europa.ec.grow.espd.config.EspdApplication class in the same way as you would start a normal Java application.

  1. Perform a mvn clean package from the root folder of the project:

    1. The build should generate a WAR file at ${baseDir}/espd-web/target/espd-web.war

  2. Add the following startup parameters to you server:

    1. -Dspring.profiles.active=${your desired profile} specifies the Spring Boot profile to be used

    2. -Dted.api.user=${your TED user} where ${your TED user} is replaced by the TED API username

    3. -Dted.api.password=${your TED password} where ${your TED password} must be replaced by the TED API password

The application can be started with a shell script that can contain the following minimum configuration:

start.sh
java -Dspring.profiles.active=prod -Xms768m -Xmx768m -jar espd-web.war

Other application parameters can also be specified in exactly the same way, i.e. by prefixing them with a -D followed by the name of the parameter. You can consult the application.properties files for finding out the available options but please note that the ones specified at start-up have higher precedence than the ones specified in the .properties files.

It is recommended to set up the context path of the application when running in the embedded mode. This can be done in the application.properties file located in the espd-web project resources folder.
application.properties
# Context path of the application
server.context-path=/espd

Deploying the web application on a servlet container

The application can be deployed as a WAR file on a Servlet 3 compliant container such as Tomcat. For this, you need to package it as a WAR for the non-embedded Maven profile and provide some startup parameters on your server.

  1. Perform a mvn clean package -Pnon-embedded from the root folder of the project:

    1. The build should generate a WAR file at ${baseDir}/espd-web/target/espd-web.war

  2. The other steps are similar to the embedded server deployment mode

Using an IDE

You can also run the ESPD application from your favourite IDE by importing the project as a multi-module Maven project first.

You will need to install the Lombok plugin for your particular IDE. Lombok is a library designed to reduce Java boilerplate code through the use of annotations.
If you have problems importing the project in Eclipse try running the Maven command mvn eclipse:eclipse before the import. If after the import the Problems view display errors of type Plugin execution not covered by lifecycle configutation right-click on the error and set Eclipse to ignore the execution of the plugin.

Overview

The ESPD application is composed of two Maven modules:

  • espd-docs contains the documentation of the application

  • espd-web contains the source code to generate the deployable web archive (WAR) of the application

The Java library eu.europa.ec.grow.espd.exchange-model contains the JAXB classes of the ESPD Exchange Data Model.

The ESPD web application is quite simple in nature and can be deployed as an executable JAR file (with an embedded Tomcat server) or as a standard WAR file on a compliant Servlet 3 container like Tomcat, Jetty, Weblogic, Wildfly etc.

The main responsibilities of the application are handled as follows:

Java packages overview

The main Java package of the web application is 'eu.europa.ec.grow.espd` found in the espd-web module. It is further subdivided into the following important packages:

  • config

  • controller

  • domain

  • ted

  • util

  • xml

Config package

The config package contains the Java classes which provide the configuration for the global project EspdApplication, Spring MVC web configuration WebConfiguration, the JAXB configuration etc. You will notice that these classes are annotated with @Configuration and they generally define Spring beans that can be injected in other Spring managed classes of the application.

Controller package

The controller package consists of the Spring MVC controllers which are responsible for processing user requests, building an appropriate model and passing it to the view for rendering. Some controllers are REST controllers.

The most important one is EspdController and its responsibilities include dealing with the generation of the ESPD requests and responses, uploading files, printing and error handling. The main flow of the application is handled by this class.

Other controllers which are present in this package are the AboutController that is used to populate the /about page of the application and MessageSourceController which is responsible for loading the i18n messages needed by the client-side i18n engine.

Domain package

The domain package contains the elements involved in the representation of an ESPD request or response in the model (the M part of the MVC architectural pattern) of the web application. An ESPD request/response is represented internally as an EspdDocument which in turn contains fields for all the possible criteria, authority and economic operator information or procurement procedure data.

In the domain.enums sub-package you can find the enumerations holding the criteria, requirement groups, requirements, countries, languages, currencies etc which are used by the application. The criteria definitions load metadata coming from some JSON configuration files under src/main/resources/criteria and store the information dynamically in the criterion enumerations.

TED package

The ted package is responsible for the interaction with the TED REST service which provides the procurement procedure information for an ESPD request or response.

TED is the electronic version of the EU Official Journal dedicated to public procurement.

Util package

The util package contains various utility classes, for example, some of the application properties that are needed by the user interface are loaded by Spring in the EspdConfiguration class. The I18NFunc class loads the i18n messages needed by the client-side internationalization engine.

XML package

The xml package takes care of the marshalling/unmarshalling of the ESPD request and response XML files. It is further divided into a package for request, one for response and a common package with shared functionality between the other two. The classes from this package make use of the Template method design pattern to share common behaviour and design.

The request and response packages contain each an exporting and an importing sub-package. The exporting package is responsible for generating the ESPD request/response XML files while the importing package knows how to parse XML files representing ESPD request or response and convert them into the internal ESPD domain objects.

The EspdExchangeMarshaller is the main class that aggregates all of the classes from this package together and is injected in the EspdController to perform the marshalling/unmarshalling logic.

CriteriaTemplates serves as configuration for the user interface components of the criteria and requirements that are defined in the JSP and Apache Tiles files.

Web overview

The web static resources can be found in the standard Maven location, i.e. src/main/webapp. The static folder contains the CSS and Javascript files referenced by the web application. The JSP files are located in the WEB-INF/views folder where they are subsequently grouped in sub-folders. The src/main/resources folder contains the configuration files relating to internationalization, logging, web resource optimizations and general application properties.

Configuration

This section will describe the basic configuration for the most important components of the application.

Configuration files

Most of the configuration properties of the web application are specified in properties files which can be found inside the src/main/resources folder of the espd-web Maven module. There are different files for each profile under which the application can be started, for example the application-prod.properties file will be used for the prod profile which must be specified as a startup parameter as -Dspring.profiles.active=prod. If no profile is specified, then a default one will be used by Spring Boot and the corresponding configuration file would be just application.properties. Here you can find more information about properties and configuration with Spring Boot.

Spring

The ESPD application is built from the ground-up with Spring Boot, allowing us to simplify the project configuration and the management of third party libraries.

It does so by specifying in the main pom.xml of the project a parent POM pointing to the Spring Boot starter.

pom.xml
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.3.2.RELEASE</version>
</parent>

Since the application is using Spring Boot extensively by inheriting from spring-boot-starter-parent, this provides it with the following features:

  • Default Java compiler level

  • UTF-8 source encoding

  • A Dependency Management section, allowing you to omit <version> tags for common dependencies, inherited from the spring-boot-dependencies POM.

  • Sensible resource filtering, including application.properties and application.yml type of files

  • Sensible plugin configuration

For more information about the Spring Boot project, you can check the official documentation.

The eu.europa.ec.grow.espd.config package contains the Spring configuration classes. The main class of the application is EspdApplication which makes use of the @SpringBootApplication annotation in order to enable the Spring Boot auto configuration. The package also contains the web, JAXB and web resources configuration files.

Spring MVC

The web configuration part is found in the WebConfiguration class in conjunction with the following Spring Boot properties:

application-dev.properties
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

# Default locale to use
spring.mvc.locale=en

The WebConfiguration contains the definition of various Spring beans: view resolvers, tiles configuration, locale interceptors, monitoring filter.

WebConfiguration.java
@Bean
UrlBasedViewResolver viewResolver() {
  UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
  viewResolver.setViewClass(TilesView.class);
  return viewResolver;
}

@Bean
TilesConfigurer tilesConfigurer() {
  TilesConfigurer tilesConfig = new TilesConfigurer();
  tilesConfig.setDefinitions("/WEB-INF/tiles.xml");
  return tilesConfig;
}

Internationalization (i18n)

Concerning internationalization (i18n), the ESPD application takes advantage of the auto-configuration provided by Spring Boot in the MessageSourceAutoConfiguration class.

application.properties
# The location to the resource bundles needed by i18n
spring.messages.basename=i18n/messages

# Loaded resource bundle files cache expiration, in seconds. When set to -1, bundles are cached forever.
spring.messages.cache-seconds=3

The message files are located in the src/main/resources/i18n folder and follow a very simple naming convention of messages_${locale language}.

The application.properties file which is used only for local development is able to refresh potential changes in the message files without requiring a server restart by specifying the spring.messages.cache-seconds property.

The corresponding Java configuration is summarized below.

WebConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

@Bean
LocaleChangeInterceptor localeChangeInterceptor() {
  LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
  lci.setParamName("lang");
  return lci;
}

@Bean
LocaleResolver localeResolver() {
  CookieLocaleResolver resolver = new CookieLocaleResolver();
  resolver.setCookieName("ESPD_LOCALE");
  resolver.setDefaultLocale(Locale.ENGLISH);
  return resolver;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
  registry.addInterceptor(localeChangeInterceptor());
}

The LocaleResolver enables the application to automatically resolve messages files using the client’s locale which is stored in a ESPD_LOCALE cookie.

The LocaleChangeInterceptor uses an HTTP request parameter named lang to detect the language changes on the server side.

Web Resources Optimization

Static resources

ESPD uses advanced resource handling features provided by Spring MVC and Spring Boot. We have chosen a path that relies on optimizing resources at build-time using WRO4J and leveraging Spring MVC Resolvers and Transformers and WRO4J filter at run-time.

The static resources of the application (Javascript and CSS files) are versioned using a content-based hashing strategy and handled with the idea of cache busting where resources are served with aggressive HTTP cache directives (e.g. 1 year into the future) and relying on version-related changes in the URL to "bust" the cache when necessary. The content-based hash version changes whenever the content of the file changes and this happens at build time.

application-dev.properties
# Cache period for the resources served by the resource handler, in seconds (1 year).
spring.resources.cache-period=31622400

# Enable the Spring Resource Handling chain.
spring.resources.chain.enabled=true

# Enable the content Version Strategy.
spring.resources.chain.strategy.content.enabled=true

# Comma-separated list of patterns to apply to the Version Strategy.
spring.resources.chain.strategy.content.paths=/static/bundle/**

Links to resources are rewritten at run-time using a ResourceUrlEncodingFilter.

WebConfiguration.java
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
import org.springframework.context.annotation.Bean;

/**
* If the template engine you are using calls the response encodeURL() method, the version information
* will be automatically added to the URL of the static resources that will be cached.
* This will work in JSPs in conjunction with spring:url tag.
* <p>It needs to be mapped on '/*'.</p>
*
* @return
*/
@Bean
ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
  return new ResourceUrlEncodingFilter();
}

And this is how the static resources are referenced in the view part:

espdTemplate.jsp
<link rel="stylesheet" type="text/css" href="<s:url value="/static/bundle/all.css"/>">
<script src="<s:url value="/static/bundle/all.js"/>"></script>

For example, a request made to the all.js file would be translated into a request made to a Javascript file with a hash: https://ec.europa.eu/espdstatic/bundle/all-60d9cd4aee2d53a2a4bd69a5546a9d18.js.

WRO4J

Another set of static resources optimizations are handled with WRO4J using a simple Java filter at run-time and the Maven plugin at build-time. WRO4J concatenates and minifies the static resources like Javascript or CSS files into a single file per each type of resource so that the number of HTTP requests made by the clients that load the application is reduced drastically.

Run-time solution with a Servlet filter

The Java filter configuration makes use of Spring Boot auto-configuration provided by the wro4j-spring-boot-starter library.

This is only used by the default Spring Boot profile which should be active only at development time.
Wroj4Config.java
import ac.simons.spring.boot.wro4j.Wro4jAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Profile("default")
@Configuration
class Wro4jConfig extends Wro4jAutoConfiguration {

  // only used for development ('default' profile) when we need the Wro4J Filter

}

The run-time properties are defined in the application.properties file.

application.properties
# Integer value for specifying how often (in seconds) the resource changes should be checked. When this value is 0,
# the cache is never refreshed. When a resource change is detected, the cached group containing changed resource
# will be invalidated. This is useful during development, when resources are changed often.
wro4j.resourceWatcherUpdatePeriod=3

# Integer value for specifying how often (in seconds) the cache should be refreshed.
# When this value is 0, the cache is never refreshed.
wro4j.cacheUpdatePeriod=3

wro4j.disableCache=true

wro4j.debug=true

wro4j.filterUrl=/static/bundle

# A comma separated values describing pre processor aliases to be used during processing.
wro4j.managerFactory.preProcessors=fallbackCssDataUri, cssUrlRewriting, cssImport, semicolonAppender, cssMinJawr, jsMin
Build-time solution with Maven

The build-time solution uses a Maven plugin and needs two WRO4J configuration files placed under the src/main/resources folder.

wro.xml
<groups xmlns="http://www.isdc.ro/wro">
  <group name="all">
    <css minimize="false">/static/bootstrap-3.2.0/css/bootstrap.min.css</css>
    <css minimize="true">/static/css/espd.css</css>

    <js minimize="false">/static/jquery/jquery.min.js</js>
    <js minimize="false">/static/bootstrap-3.2.0/js/bootstrap.min.js</js>
    <js minimize="true">/static/js/init.js</js>
  </group>
</groups>
wro.properties
###############################################################################
#####     THIS FILE IS USED AT BUILD TIME BY THE WRO4J MAVEN PLUGIN      ######
###############################################################################

#If true, it is DEVELOPMENT mode, by default this value is true.
debug=false

# A comma separated values describing pre processor aliases to be used during processing.
preProcessors=fallbackCssDataUri,cssUrlRewriting,cssImport,semicolonAppender

postProcessors=cssVariables,cssMinJawr,jsMin

# The alias of the HashStrategy used to compute ETags & cache keys.
hashStrategy=MD5

# The alias of the NamingStrategy used to rename bundles.
namingStrategy=noOp

The Maven plugin bundles all the Javascript and CSS files into the src/main/webapp/static/bundle folder, applying minimization where necessary and creating a all.js and a all.css file.

espd-web.pom.xml
<configuration>
  <wroFile>${basedir}/src/main/resources/wro.xml</wroFile>
  <extraConfigFile>${basedir}/src/main/resources/wro.properties</extraConfigFile>
  <cssDestinationFolder>${basedir}/src/main/webapp/static/bundle/</cssDestinationFolder>
  <jsDestinationFolder>${basedir}/src/main/webapp/static/bundle/</jsDestinationFolder>
  <wroManagerFactory>ro.isdc...factory.ConfigurableWroManagerFactory</wroManagerFactory>
  <ignoreMissingResources>false</ignoreMissingResources>
  <incrementalBuildEnabled>true</incrementalBuildEnabled>
</configuration>

Lombok

To reduce some of the boilerplate code inherent to the Java language, the project uses the Lombok library which leverages Java annotations.

The library can be used in Eclipse by double clicking the lombok.jar and in IntelliJ by installing the Lombok plugin.

If you do not like the basic idea behind Lombok you can delombok the source code and go back to standard Java source code.

Here is a very simple example of how Lombok might be used inside the ESPD project.

TedRequest.java
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class TedRequest {

  private String receptionId;

}
LombokExample.java
public TedRequest prepare() {
  TedRequest request = TedRequest.builder()
                    .receptionId("16-000136-001")
                    .build();
  log.debug("This is the reception id: '{}'.", request.getReceptionId());
  return request;
}

Logging

Logging in the application is handled using the SLF4J API and the chosen implementation is provided by the Logback library.

Since the espd-web module depends on spring-boot-starter-web and this one transitively depends on spring-boot-starter-logging, the default logging implementation configured by Spring Boot is Logback.

The application-${profile}.properties files declare the path to the Logback configuration. The logging configuration files are stored in the espd-web/src/main/resources/logback folder.

application-dev.properties
# The path to the logback configuration file depending on the profile
logging.config=classpath:logback/logback-dev.xml

To use logging in the code, you can take advantage of the facilities provided by Lombok.

Logging.java
import lombok.extern.slf4j.Slf4j;

@Slf4j
class Logging {

  void logSomething(String parameter) {
    log.info("Logging the following value '{}'.", parameter);
  }
}

Monitoring and analytics

Java Melody

Basic monitoring of the ESPD application is handled using the Java Melody library by registering a Java filter inside the Spring application context.

WebConfiguration.java
import org.springframework.context.annotation.Bean;
import net.bull.javamelody.MonitoringFilter;
import net.bull.javamelody.Parameter;

@Bean
MonitoringFilter melodyMonitoringFilter() {
  return new MonitoringFilter();
}

@Bean
FilterRegistrationBean melodyFilterRegistration(MonitoringFilter melodyFilter) {
  FilterRegistrationBean frb = new FilterRegistrationBean(melodyFilter);
  frb.addInitParameter(Parameter.NO_DATABASE.getCode(), "true");
  frb.addInitParameter(Parameter.ALLOWED_ADDR_PATTERN.getCode(),
        "(158\\.16[6-8]\\..*)|(127\\.0\\.0\\.1)|(localhost)");
  frb.addInitParameter(Parameter.URL_EXCLUDE_PATTERN.getCode(), "(/img/.*)|(/js/.*)|(/css/.*)|(.*/.woff)");
  return frb;
}

The filter configuration makes the monitoring accessible only to a certain range of IP addresses, excludes requests pointing to static resources and specifies that no database monitoring should be active.

Additional monitoring capabilities could be added by activating the Spring Boot actuator features.

Piwik

Analytics capabilities for the application are provided via the Piwik server of DG Growth.

application-dev.properties
# Enable or disable the Piwik integration
piwik.enabled=false

# Piwik id for ESPD project
piwik.id=2

# Piwik server for ESPD project
piwik.server=https://webgate.ec.europa.eu/pwar/piwik.php

[NOTE] You might want to disable the integration with the Piwik server of DG Growth by setting the piwik.enabled parameter to false in the corresponding application.properties file.

Criteria definitions

With the 2016.06 version, the criteria requirement groups have been restructured with regards to interoperability with the VCD application and three JSON files have been added under src/main/resources/criteria. These files contain the definitions for the exclusion, selection and other criteria used by the static version of ESPD.

exclusionCriterion.json
{
  "name": "Conflict of interest due to its participation in the procurement procedure",
  "uuid": "b1b5ac18-f393-4280-9659-1367943c1a2e",
  "shortName": "Conflict of interest due to its participation in the procurement procedure",
  "description": "Is the economic operator aware of any conflict of interest, as indicated in national law, the relevant notice or the procurement documents due to its participation in the procurement procedure?",
  "criterionType": {
    "description": "Grounds for exclusion relating to possible conflicts of interests",
    "espdType": "CONFLICT_OF_INTEREST",
    "code": "CRITERION.EXCLUSION.CONFLICT_OF_INTEREST.PROCEDURE_PARTICIPATION"
  },
  "legislationReference": {
     "title": "DIRECTIVE 2014/24/EU OF THE EUROPEAN PARLIAMENT AND OF THE COUNCIL of 26 February 2014 on public procurement and repealing Directive 2004/18/EC",
     "description": "Directive 2014/24/EU",
     "url": "http://eur-lex.europa.eu/legal-content/EN/TXT/?uri=celex:32014L0024",
     "article": "57(4)"
  },
  "groups": [
    {
    "name": "G1",
    "id": "30450436-f559-4dfa-98ba-f0842ed9d2a0",
    "requirements": [
      {
      "id": "974c8196-9d1c-419c-9ca9-45bb9f5fd59a",
      "description": "Your answer?",
      "responseType": "INDICATOR",
      "espdCriterionFields": [
          "answer"
      ]
      }
    ]
    }
  ],
  "espdDocumentField": "conflictInterest"
}

ESPD Exchange Data Model

The ESPD-EDM is a separate project containing the XML schemas used to generate the JAXB annotated Java classes.

pom.xml
<dependency>
  <groupId>eu.europa.ec.grow.espd</groupId>
  <artifactId>exchange-model</artifactId>
  <version>${espd-exchange-model.version}</version>
</dependency>

The marshalling and unmarshalling of the XML files produced by the application is handled by a Spring Jaxb2Marshaller.

The JAXB configuration declares the packages to be scanned for potential JAXB annotated classes.

JaxbConfiguration.java
import grow.names.specification.ubl.schema.xsd.espdrequest_1.ESPDRequestType;
import grow.names.specification.ubl.schema.xsd.espdresponse_1.ESPDResponseType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import javax.xml.bind.Marshaller;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class JaxbConfiguration {

@Bean
public Jaxb2Marshaller jaxb2Marshaller() {
    Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
    jaxb2Marshaller.setPackagesToScan(ESPDRequestType.class.getPackage().getName(),
            ESPDResponseType.class.getPackage().getName());
    Map<String, Object> map = new HashMap<>(2);
    map.put(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    jaxb2Marshaller.setMarshallerProperties(map);
    return jaxb2Marshaller;
  }
}

Date and time

Date and time objects are handled with the Joda-Time library. There are two adapters that are used to populate the Date objects inside the JAXB POJOs. These adapters convert and parse String objects into LocalDate or LocalTime Joda-Time objects.

LocalDateAdapter.java
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public final class LocalDateAdapter {

  private static final DateTimeFormatter DATE_FORMAT = DateTimeFormat.forPattern("YYYY-MM-dd");

  private LocalDateAdapter() {

  }

  public static LocalDate unmarshal(String v) {
      return LocalDate.parse(v, DATE_FORMAT);
  }

  public static String marshal(LocalDate v) {
      return v.toString(DATE_FORMAT);
  }
}

REST template

The interaction with external RESTful APIs (e.g. TED) is done with the Spring RestTemplate.

There is one global Spring bean of type RestTemplate defined in the application.

EspdApplication.java
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@ComponentScan("eu.europa.ec.grow.espd")
public class EspdApplication extends SpringBootServletInitializer implements WebApplicationInitializer {

  @Value("${http.client.connect.timeout.millis:30000}")
  private int connectTimeout;

  @Bean
  ObjectMapper objectMapper() {
    return new ObjectMapper();
  }

  @Bean
  RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();

    SimpleClientHttpRequestFactory rf = (SimpleClientHttpRequestFactory) restTemplate.getRequestFactory();
    rf.setReadTimeout(connectTimeout);
    rf.setConnectTimeout(connectTimeout);

    return restTemplate;
  }
}

You can find an example of how to use the RestTemplate in the eu.europa.ec.grow.espd.ted.TedService class.

TED REST service

Information about the procurement procedure can be provided by the publication office via the TED REST service. In order to be able to retrieve the information from their remote service we need to provide four parameters.

application-dev.properties
# The base URL of the TED contract notice REST service
ted.api.base.url=https://esentool.ted.europa.eu/api/espd/v1.0/notice

# Timeout in milliseconds for the Spring RestTemplate client
rest.template.connect.timeout.millis=30000

# user for TED API
ted.api.user=passed as server startup parameter

# Password for TED API
ted.api.password=passed as server startup parameter

The part of the code that handles the TED service can be found in the eu.europa.ec.grow.espd.ted package.

PDF printing

Printing the ESPD Request and ESPD Response to PDF files is achieved via Apache FOP. To produce a PDF file, we start from the HTML content of the ESPD entity which we want to print and use an XSLT stylesheet that converts the HTML to XSL-FO. This is the first step in the processing chain. The second step will be done by Apache FOP when it reads the generated XSL-FO document and formats it to a PDF document.

XSL-FO is an XML vocabulary that is used to specify a pagination and other styling for page layout output. The acronym FO stands for Formatting Objects. XSL-FO can be used in conjunction with XSLT to convert from any XML format into a paginated layout ready for printing or displaying. The XSLT files taking care of the HTML transformation can be found in src/main/resources/tenderned/pdfrendering/xslt.

The printing implementation resides inside the eu.europa.ec.grow.espd.tenderned.HtmlToPdfTransformer class while the infrastructure setup of Apache FOP is defined in the eu.europa.ec.grow.espd.config.ApacheFopConfig class.

Apache FOP requires a configuration file whose location can be configured via the apache.fop.xml.configuration.location application parameter. The default locations point to files belonging to the src/main/resources/grow/fop/ folder.

In order to display the PDF correctly across all European languages we need to use a font which contains all the glyphs for these languages. Otherwise, if no glyph can be found for a given character, Apache FOP will issue a warning and use the glyph for "#" (if available) instead. The font also needs to be embedded in the PDF so that the document is correctly displayed on all clients which are viewing the generated files. For these reasons we are using a custom font called DejaVu.

Inside the fop-config.xml file we need to make sure that the font files are correctly configured and then properly loaded by Apache FOP across multiple Servlet containers. Please notice the ember-url attribute.

fop-config.xml
<font metrics-url="fonts/DejaVuSans/ttf/DejaVuSans.xml"
      embed-url="fonts/DejaVuSans/ttf/DejaVuSans.ttf">
  <font-triplet name="DejaVuSans" style="normal" weight="normal"/>
</font>

The application parameter apache.fop.defaultBaseUri can be specified to load the font files via different strategies. Embedded fonts can be loaded via absolute (Weblogic in Production mode) or relative paths or via classpath depending on the chosen strategy. When using an embedded server it is recommended to use the classpath approach.

The fonts are loaded by Apache FOP by using a custom org.apache.xmlgraphics.io.ResourceResolver which looks for them via the Spring ResourceLoader mechanism in a portable and consistent way across different Serlvet containers.

EspdResourceResolver.java
@Override
public Resource getResource(URI uri) throws IOException {
  log.debug("--- Fop resource resolver get resource: '{}'.", uri);
  InputStream is = resourceLoader.getResource(uri.toASCIIString()).getInputStream();
  return new Resource(is);
}

To be able to load the fonts when running the application with an embedded server we need to copy them in a location relative to the application context root.

pom.xml
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-war-plugin</artifactId>
  <configuration>
    <warName>${project.artifactId}</warName>
    <webResources>
      <resource>
        <directory>src/main/resources/fonts</directory>
        <targetPath>fonts</targetPath>
        <filtering>false</filtering>
      </resource>
    </webResources>
  </configuration>
</plugin>

Web Page Initialization Parameters

Certain HTTP parameters can be passed to the /initialization URL of the ESPD application to initialize specific fields. When issuing such a request, the application redirects the client to the /filter page.

  • lang is used to specify the language to be used by the application. It consists of a two letter code from the supported languages of the application. Example:

  • agent is used to choose between a contracting authority, contracting entity and economic operator. The only accepted values are:

    • ca for contracting authority

    • ce for contracting entity

    • eo for economic operator

  • action defines what the user would like to do. The accepted values are:

    • ca_create_espd_request for selecting the Create a new ESPD option as a contracting authority or contracting entity

    • ca_reuse_espd_request for selecting the Reuse an existing ESPD option as a contracting authority or contracting entity

    • ca_review_espd_response for selecting the Review ESPD option as a contracting authority or contracting entity

    • eo_import_espd for selecting the Import ESPD option as an economic operator

    • eo_merge_espds for selecting the Merge two ESPDs option as an economic operator

    • eo_create_espd_response for selecting the Create response option as an economic operator

  • country for selecting the desired country of the authority or economic operator. It must be the two letter code of the country in uppercase.

When the agent is a contracting authority or contracting entity, the following parameters are supported for filling in the fields belonging to Part I - Information about the procurement procedure section.

  • officialName

  • procurerCountry - must be a two letter country code in uppercase

  • title

  • description

  • fileRefByCA

  • tedReceptionId specifies the received notice number

When the agent is economic operator, the parameters below can additionally be configured to initialize Part II Information concerning the economic operator - Section A:

  • name

  • vatNumber

  • anotherNationalId

  • website

  • street

  • postalCode

  • city

  • country - must be a two letter country code in uppercase

  • contactName

  • contactEmail

  • contactPhone

Initialization page request example.sh
HTTP POST @ espd/initialization?country=RO&city=Drobeta&agent=eo&action=eo_create_espd_response&procurerCountry=FR&lang=ro

All the parameters described above are defined in the EspdInitializationParameters class. It is recommended to use HTTP POST requests but HTTP GET requests are also supported.

View

The client interface is based on the Spring MVC integration with Apache Tiles working as a template system for the JSP files. All of the HTML forms are CSS styled with Twitter Bootstrap and use Spring form tags to do the display and form binding.

Every JSP implements a responsive Twitter Bootstrap grid layout and some Twitter Bootstrap styles to make it look better.

Apache Tiles and the corresponding view resolvers are configured in the WebConfiguration.java file while tiles.xml contains the configuration for the Apache Tiles template definitions.

Forms

Client web form submission and validation is performed by Spring MVC Form Binding.

EspdController.java
@InitBinder
private void dateBinder(WebDataBinder binder) {
  SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
  CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
  binder.registerCustomEditor(Date.class, editor);
}

The HTML form is implemented by the spring:form tag to bind the controller object via @ModelAttribute. An EspdDocument object will be attached to each HTTP session via the @SessionAttributes("espd") declaration and is reset on each page access to the /welcome page.

EspdController.java
@ModelAttribute("espd")
public EspdDocument newDocument() {
  return new EspdDocument();
}

Internationalization (i18n)

A Web application with a worldwide user base needs to be easily adapted to support several human languages without impacting its design, through internationalization techniques (i18n). ESPD i18n is implemented through the use of Spring interceptors, locale resolvers and resource bundles for different locales.

LocaleChangeInterceptor and LocaleResolver are configured in the WebConfiguration class.

A MessageSource bean is provided by Spring Boot and configured in properties file to enable i18n for the ESPD application.

application.properties
# The location to the resource bundles needed by i18n
spring.messages.basename=i18n/messages

Translated messages could be retrieved with the given code by the Jsp tag spring:message.

example.jsp
<%@ taglib prefix="s" uri="http://www.springframework.org/tags" %>
<s:message code="createca_postcode"/><%-- by static code --%>
<s:message code="${cty.i18nCode}"/><%-- code from variable --%>

It is worth noting the use of custom classes providing more efficient use of the MessageSource bean in JSP. The class I18NFunc provides HTML code generating methods to use in JSPs for translated fields.

espdTemplate.jsp
<%-- Initialization of request objects --%>
eu.europa.ec.grow.espd.util.I18NFunc inst =
        new eu.europa.ec.grow.espd.util.I18NFunc(pageContext);
request.setAttribute("i18n", inst.message());
request.setAttribute("div18n", inst.div());
request.setAttribute("span18n", inst.span());

Using these classes is more concise and the generated code supports translation without page reload.

example.jsp
${i18n['createca_procurer_name']}
${div18n['createca_procurer_name']}
${span18n['createca_procurer_name']}

The JSP code above would generate the following HTML output:

example.html
Title:
<div data-i18n="createca_procurer_name">Title:</div>
<span data-i18n="createca_procurer_name">Title:</span>

Different combinations of custom i18n code generators provide translation labels, tooltips and placeholders without page reload.

example.jsp
<!-- label example -->
<label class="control-label">
  ${span18n['crit_year']
</label>
<!-- tooltip example -->
<span data-toggle="tooltip"data-i18n="${tooltip_code}" title="${tooltip_text}">
</span>
<!-- placeholder example -->
<form:input path="field"
  cssClass="form-control"
  data-i18n="crit_ratio_placeholder"
  placeholder="${i18n['crit_ratio_placeholder']}"/>

Dynamic web page translation

The ESPD Web content is translated to another language automatically without page refresh. The dynamic translation is implemented in Javascript with jQuery and the translation routine is found in the init.js file. The Javascript client makes an HTTP call to the /translate mapping defined inside the MessageSourceController class to fetch the required message labels and afterwards updates the DOM elements containing the data-i18n attribute.

Testing

Making sure that an application behaves correctly is a difficult job and ESPD is no exception from this rule, that’s why we have an extensive test suite of more than 600 automated unit tests. These tests try to focus on the domain model marshalling/unmarshalling logic of ESPD Requests and Responses and go into very detailed checks for each criterion, requirement or other domain entity of the application.

The unit tests are written using the Spock Framework in the Groovy programming language and we take advantage of its beautiful and highly expressive specification language.

The Maven configuration for running the tests at build time is defined in the espd-web/pom.xml file. It uses the gmavenplus-plugin to compile the Groovy test files and the maven-surefire-plugin to specify the file naming pattern of the tests that are supposed to be run.

espd-web/pom.xml
<plugin>
<!-- The gmavenplus plugin is used to compile Groovy code. To learn more about this plugin,
visit https://github.com/groovy/GMavenPlus/wiki -->
  <groupId>org.codehaus.gmavenplus</groupId>
  <artifactId>gmavenplus-plugin</artifactId>
  <version>1.5</version>
  <executions>
    <execution>
      <goals>
        <goal>compile</goal>
        <goal>testCompile</goal>
      </goals>
    </execution>
  </executions>
</plugin>
<!-- Optional plugins for using Spock -->
<!-- Only required if names of spec classes don't match default Surefire patterns (`*Test` etc.) -->
<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <useFile>false</useFile>
    <includes>
      <include>**/*Spec.java</include>
      <include>**/*Test.java</include>
    </includes>
  </configuration>
</plugin>

The tests can be run by invoking a mvn clean package or mvn clean verify command or from the IDE of your choice.

If you are using Eclipse you will have to install the Groovy Eclipse plugin.
If you are using IntelliJ you need to enable the Groovy plugin and it might also be useful to install the IntelliJ Spock plugin for improved working experience.

The location of the tests is under the espd-web/src/test/groovy folder. Inside the eu.europa.ec.grow.espd.xml package you will find the following sub-packages:

  • the base package contains some basic infrastructure for the unit tests

  • the request package contains the tests that handle an ESPD Request

  • the response package contains the tests that handle an ESPD Response

  • the samples folder contains the XML sample files that are used by the tests that handle the importing of an ESPD Request or Response

Anatomy of a test specification

Spock specification classes are derived from spock.lang.Specification. A concrete specification class might consist of fields, fixture methods, features methods and helper methods.

ListSpec.groovy
class ListSpec extends Specification {

  def "adding an element to a list leads to size increase"() { (1)
    given: "a new list instance is created" (2)
    def lst = new ArrayList()

    when:
    lst.add(666) (3)

    then:
    lst.size() == 1 (4)
  }
}
1 Feature method, is by convention named with a descriptive String literal.
2 Given block, here is where any setup work for this feature needs to be done.
3 When block describes a stimulus, a certain action under target by this feature specification.
4 Then block contains any expressions that can be used to validate the result of the code that was triggered by the when block.

Spock feature specifications are defined as methods inside a spock.lang.Specification class. They describe the feature by using a String literal instead of a method name.

A feature method holds multiple blocks, in our example we used given, when and then. The given block is special in that it is optional and allows us to configure local variables visible inside the feature method. The when block defines the stimulus and is a companion of the then block which describes the response to the stimulus.

The given block is just an alias for the setup block.

Note that the given method in the SpockSpec above additionally has a description String. Description Strings are optional and can be added after block labels (like given, when, then).

Testing the generation of an XML file

The code sample below represents a unit test that checks the XML output of an ESPD Response generation, more specifically the Reason requirement of the Fraud exclusion criterion.

FraudResponseTest.groovy
class FraudResponseTest extends AbstractExclusionCriteriaFixture {

  def "check the 'Reason' requirement response"() {
    given:
    def espd = new EspdDocument(fraud: new CriminalConvictionsCriterion(exists: true, reason: "Reason_03 here")) (1)

    when:
    def response = parseResponseXml(espd) (2)
    def idx = getResponseCriterionIndex(ExclusionCriterion.FRAUD)

    then:
    def subGroup = response.Criterion[idx].RequirementGroup[0] (3)
    def req = subGroup.Requirement[2] (4)
    checkRequirement(req, "7d35fb7c-da5b-4830-b598-4f347a04dceb", "Reason", "DESCRIPTION") (5)
    req.Response.size() == 1 (6)
    req.Response[0].Description.text() == "Reason_03 here" (7)
  }
}
1 The given clause initializes the ESPD domain object with the Fraud criterion which contains a Reason with the text Reason_03 here because the exists flag is set to true on the criterion.
2 The when clause delegates to the parseResponseXml method from the AbstractEspdXmlMarshalling class which generates the XML representation of an ESPD Response.
3 We get the first requirement group of the Fraud criterion
4 The Reason requirement is the third requirement of the group
5 Check the requirement id, description text and response type
6 We should have only a Response XML element
7 Make sure that the description text of the response has the actual value that was supplied in the given clause

The most common way of querying XML in Groovy is using GPath which is similar to XPath expressions but you can use it not only with XML but also with POJO classes. More information and examples of using GPath can be found in the Groovy programming language documentation on XML processing.

The parseResponseXml method uses a Groovy XmlSlurper object which returns GPathResult instances when parsing XML.

The then clause makes the business assertions about the expected requirement id, description text, response type and finally .

Testing the parsing of an XML file

The following example will show a test that reads an ESPD Response XML file and converts it into an ESPD domain object that is used by the user interface code. The XML sample contains the Setup of economic operator criterion with the Year requirement value set in the response.

SetupEconomicOperatorImportTest.groovy
class SetupEconomicOperatorImportTest extends AbstractXmlFileImport {

  def "10. should import all fields of 'Set up of economic operator'"() {
    when:
    def espd = parseXmlResponseFile("selection/setup_economic_operator_import.xml") (1)

    then:
    espd.setupEconomicOperator.exists == true (2)

    then: "selection criteria with no answer have a default value of true"
    espd.setupEconomicOperator.year1 == 2016 (3)
  }
}
1 Load the XML sample from selection/setup_economic_operator_import.xml and parse it into an EspdDocument domain object
2 Check that the exists indicator has been set for this criterion
3 Verify that the Quantity requirement response value stored in year1 is 2016

The XML file contains the Setup of economic operator criterion with the Quantity requirement (some of the data has been removed for clarity):

setup_economic_operator_import.xml
<ccv:Criterion>
  <ccv:RequirementGroup>
    <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">e9aa7763-c167-4352-8060-1a3d7d3e2662</cbc:ID>
    <ccv:Requirement responseDataType="QUANTITY">
      <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">a18b2c98-8552-45ca-9751-d4c94c05847a</cbc:ID>
      <cbc:Description>Please specify</cbc:Description>
      <ccv:Response>
        <cbc:Quantity unitCode="YEAR">2016</cbc:Quantity>
      </ccv:Response>
    </ccv:Requirement>
  </ccv:RequirementGroup>
</ccv:Criterion>

Data model

The ESPD-EDM model was designed to implement the data requirements expressed in the Annex 2 of the COMMISSION IMPLEMENTING REGULATION (EU) 2016/7 of 5 January 2016, establishing the standard form for the European Single Procurement Document. Additionally to these requirements, the model also took into account the Information Requirements Model specified in the CEN/BII-Workshops (namely Workshop 3), and the latest developments relating to the Virtual Company Dossier (VCD) in e-Sens.

The full data model documentation can be found at: ESPD Exchange Data Model documentation

The ESPD Request XML document overview

The UML Diagram below provides a simplified view of the ESPD Request document. Notice that the classes herein represented belong to 4 different data-packages. Consequently, each class name is preceded by one of the following prefixes representing different namespaces: espd, ccv, cev, and cac.

espd::ESPDRequest UML class diagram
Figure 1. espd::ESPDRequest UML class diagram

The figure above provides a high level view of the main concepts used in the ESPD Request relating to the Criterion entity. The UML diagram below, in turn, shows in detail the classes and attributes of the Core Criterion Data Model used in the ESPD Request XML document.

UML representation of the parts of the Core Criterion Data Model used in the ESPD Request XML documents
Figure 2. UML representation of the parts of the Core Criterion Data Model used in the ESPD Request XML documents

The UML diagram can be read as follows:

  • One Criterion contains one or more Groups of Requirements

  • One Criterion MAY have sub-Criteria

  • One Criterion MAY be linked to a specific Legislation.

  • One Group of Requirements contains one or more Requirements

In the ESPD documents a Criterion takes the form of

a question or statement about a specific subject that may lead to the exclusion or selection of an Economic Operator in a Procurement Project.

Thus, in the case of grounds for exclusion related to possible convictions, the question

Has the economic operator itself or any person who is a member of its administrative, management or supervisory body or has powers of representation, decision or control therein been the subject of a conviction by final judgement for participation in a criminal organisation, by a conviction rendered at the most five years ago or in which an exclusion period set out directly in the conviction continues to be applicable?

is to be considered a Criterion.

Requirements, on the other hand, relates to the way the Economic Operator has to answer one specific Criterion. In the case of the exclusion Criterion mentioned above, the Contracting Authority requires the Economic Operator (EO) to answer YES or NO, and if the EO answers YES, he is further required to provide additional details about the conviction.

Java packages

The eu.europa.ec.grow.espd.exchange-model Java library contains the XML schemas used to generate the JAXB annotated Java classes.

To include the ESPD Exchange Model classes inside your Java project just declare the following Maven dependency in your POM file:

pom.xml
<dependency>
  <groupId>eu.europa.ec.grow.espd</groupId>
  <artifactId>exchange-model</artifactId>
  <version>1.0.2</version>
</dependency>

XML changes

Version 2017.05

Part V should not be shown in an open procedure #67

In case Part I: Information concerning the procurement procedure and the contracting authority or contracting entity, section Information about the procurement procedure receives an additional member called Type of procedure.

List of values and its impact on Part V specified below: * Not specified (because it may not be selected) * Open procedure * Restricted procedure (Part V will be shown) * Competitive procedure with negotiation (Part V will be shown) * Competitive dialogue (Part V will be shown) * Innovation partnership (Part V will be shown)

Code list for these values are taken from version 1.0.2 and specified below:

Values of Procedure Type:

Title Value

Not specified

null

Open procedure

1

Restricted procedure

2

Competitive procedure with negotiation

10

Competitive dialogue

C

Innovation partnership

11

Procedure Type is not stored in XML.

In case "Part III: Exclusion Grounds", section "A: Grounds relating to criminal convictions", applying for all grounds regarding criminal convictions, there is no option to add (conviction) information for multiple representatives, in case of a conviction.

Requirement subgroups with id "f5276600-a2b6-4ff6-a90e-b31fe19dae41" became "unbounded" using functionality implemented for unbounded groups Able to add multiple references in selection criteria.

exclusionCriteria.json
"subgroups": [
            {
              "name": "G1.1",
              "id": "f5276600-a2b6-4ff6-a90e-b31fe19dae41",
              "fulfillmentIndicator": "true",
              "unbounded": "true"
            }
            ]

This change provides possibility to implement multiple fields group: - Date of conviction - Reason - Who has been convicted - Length of the period of exclusion - Have you taken measures to demonstrate your reliability ("Self-Cleaning") - Description

espd-responce.xml
<ccv:RequirementGroup>
     <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">7c637c0c-7703-4389-ba52-02997a055bd7</cbc:ID>
     <ccv:Requirement responseDataType="INDICATOR">
        <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">974c8196-9d1c-419c-9ca9-45bb9f5fd59a</cbc:ID>
        <cbc:Description>Your answer?</cbc:Description>
        <ccv:Response>
           <ccv-cbc:Indicator>true</ccv-cbc:Indicator>
        </ccv:Response>
     </ccv:Requirement>
     <ccv:RequirementGroup pi="GROUP_FULFILLED.ON_TRUE">
        <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">f5276600-a2b6-4ff6-a90e-b31fe19dae41</cbc:ID>
        <ccv:Requirement responseDataType="DATE">
           <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">ecf40999-7b64-4e10-b960-7f8ff8674cf6</cbc:ID>
           <cbc:Description>Date of conviction</cbc:Description>
           <ccv:Response>
              <cbc:Date>2017-05-04</cbc:Date>
           </ccv:Response>
        </ccv:Requirement>
        <ccv:Requirement responseDataType="DESCRIPTION">
           <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">7d35fb7c-da5b-4830-b598-4f347a04dceb</cbc:ID>
           <cbc:Description>Reason</cbc:Description>
           <ccv:Response>
              <cbc:Description>ert</cbc:Description>
           </ccv:Response>
        </ccv:Requirement>
        <ccv:Requirement responseDataType="DESCRIPTION">
           <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">c5012430-14da-454c-9d01-34cedc6a7ded</cbc:ID>
           <cbc:Description>Who has been convicted</cbc:Description>
           <ccv:Response>
              <cbc:Description>rt</cbc:Description>
           </ccv:Response>
        </ccv:Requirement>
        <ccv:Requirement responseDataType="PERIOD">
           <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">9ca9096f-edd2-4f19-b6b1-b55c83a2d5c8</cbc:ID>
           <cbc:Description>Length of the period of exclusion</cbc:Description>
           <ccv:Response>
              <cac:Period>
                 <cbc:Description>ert</cbc:Description>
              </cac:Period>
           </ccv:Response>
        </ccv:Requirement>
        <ccv:RequirementGroup>
           <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">5f9f09f7-f701-432c-9fdc-c22c124a74c9</cbc:ID>
           <ccv:Requirement responseDataType="INDICATOR">
              <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">20c5361b-7599-4ee6-b030-7f8323174d1e</cbc:ID>
              <cbc:Description>Have you taken measures to demonstrate your reliability (&quot;Self-Cleaning&quot;)?</cbc:Description>
              <ccv:Response>
                 <ccv-cbc:Indicator>false</ccv-cbc:Indicator>
              </ccv:Response>
           </ccv:Requirement>
           <ccv:RequirementGroup pi="GROUP_FULFILLED.ON_TRUE">
              <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">74e6c7b4-757b-4b40-ada6-fad6a997c310</cbc:ID>
              <ccv:Requirement responseDataType="DESCRIPTION">
                 <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">7b07904f-e080-401a-a3a1-9a3efeeda54b</cbc:ID>
                 <cbc:Description>Please describe them</cbc:Description>
                 <ccv:Response/>
              </ccv:Requirement>
           </ccv:RequirementGroup>
        </ccv:RequirementGroup>
     </ccv:RequirementGroup>
     <ccv:RequirementGroup pi="GROUP_FULFILLED.ON_TRUE">
        <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">f5276600-a2b6-4ff6-a90e-b31fe19dae41</cbc:ID>
        <ccv:Requirement responseDataType="DATE">
           <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">ecf40999-7b64-4e10-b960-7f8ff8674cf6</cbc:ID>
           <cbc:Description>Date of conviction</cbc:Description>
           <ccv:Response>
              <cbc:Date>2017-05-04</cbc:Date>
           </ccv:Response>
        </ccv:Requirement>
        <ccv:Requirement responseDataType="DESCRIPTION">
           <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">7d35fb7c-da5b-4830-b598-4f347a04dceb</cbc:ID>
           <cbc:Description>Reason</cbc:Description>
           <ccv:Response>
              <cbc:Description>ert</cbc:Description>
           </ccv:Response>
        </ccv:Requirement>
        <ccv:Requirement responseDataType="DESCRIPTION">
           <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">c5012430-14da-454c-9d01-34cedc6a7ded</cbc:ID>
           <cbc:Description>Who has been convicted</cbc:Description>
           <ccv:Response>
              <cbc:Description>rt</cbc:Description>
           </ccv:Response>
        </ccv:Requirement>
        <ccv:Requirement responseDataType="PERIOD">
           <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">9ca9096f-edd2-4f19-b6b1-b55c83a2d5c8</cbc:ID>
           <cbc:Description>Length of the period of exclusion</cbc:Description>
           <ccv:Response>
              <cac:Period>
                 <cbc:Description>ert</cbc:Description>
              </cac:Period>
           </ccv:Response>
        </ccv:Requirement>
        <ccv:RequirementGroup>
           <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">5f9f09f7-f701-432c-9fdc-c22c124a74c9</cbc:ID>
           <ccv:Requirement responseDataType="INDICATOR">
              <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">20c5361b-7599-4ee6-b030-7f8323174d1e</cbc:ID>
              <cbc:Description>Have you taken measures to demonstrate your reliability (&quot;Self-Cleaning&quot;)?</cbc:Description>
              <ccv:Response>
                 <ccv-cbc:Indicator>false</ccv-cbc:Indicator>
              </ccv:Response>
           </ccv:Requirement>
           <ccv:RequirementGroup pi="GROUP_FULFILLED.ON_TRUE">
              <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">74e6c7b4-757b-4b40-ada6-fad6a997c310</cbc:ID>
              <ccv:Requirement responseDataType="DESCRIPTION">
                 <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">7b07904f-e080-401a-a3a1-9a3efeeda54b</cbc:ID>
                 <cbc:Description>Please describe them</cbc:Description>
                 <ccv:Response/>
              </ccv:Requirement>
           </ccv:RequirementGroup>
        </ccv:RequirementGroup>
     </ccv:RequirementGroup>
</ccv:RequirementGroup>

In Part I (Information About Publication section) we need to provide the possibility to add a national reference number to help economic operators in a country to identify it on a national portal.

To fulfill this requirement we need to add a new XML element as in the following example:

espd-request.xml
<cac:AdditionalDocumentReference>
      <cbc:ID schemeAgencyID="EU-COM-GROW" schemeAgencyName="DG GROW (European Commission)" schemeVersionID="1.1">The national number here</cbc:ID>
      <cbc:DocumentTypeCode listID="ReferencesTypeCodes" listAgencyID="EU-COM-GROW" listVersionID="1.0">NATIONAL_NUMBER</cbc:DocumentTypeCode>
      <cac:Attachment>
         <cac:ExternalReference>
            <cbc:Description>-</cbc:Description>
         </cac:ExternalReference>
      </cac:Attachment>
</cac:AdditionalDocumentReference>

In Part IV (Selection Criteria) Section B (Economic and Financial Standing), currently the economic operator can only specify a Year for the following requirements:

1 General Yearly Turnover and
2 Specific Yearly Turnover

This change is about allowing the EO to specify instead the fiscal year by selecting a Start Date and an End Date. In the new definition the QUANTITY_YEAR field will be replaced by a START_DATE and END_DATE fields as follows:

selectionCriteria.js
      "groups": [
        {
          "name": "G1",
          "id": "c0cd9c1c-e90a-4ff9-bce3-ac0fe31abf16",
          "unbounded": "true",
          "requirements": [
            {
              "id": "42ec8116-31a7-4118-8612-5b04f5c8bde7",
              "description": "Start Date",
              "responseType": "DATE",
              "espdCriterionFields": [
                "startDate"
              ]
            },
            {
              "id": "3641b897-f9f0-4d90-909a-b6d4c4b1d645",
              "description": "End Date",
              "responseType": "DATE",
              "espdCriterionFields": [
                "endDate"
              ]
            },
            {
              "id": "42db0eaa-d2dd-48cb-83ac-38d73cab9b50",
              "description": "Amount",
              "responseType": "AMOUNT",
              "espdCriterionFields": [
                "amount",
                "currency"
              ]
            }
          ]
        },

For both the EO and the representatives of the EO a postcode can be specified. In case of the EO, this information is represented by the XML element espd-cac:ContractingParty.Party.PostalAddress.Postbox, in case of the EO representative the element espd-cac:EconomicOperatorParty.Party.Person.ResidenceAddress.Postbox is used.

As usage of the Postbox element in semantically wrong in both cases (i.e. a postbox number refers to a post office box registered for postal delivery by a postal service provider). The element […].PostalZone will be used instead.

Example:

espd-response.xml
<espd:ESPDResponse>
    .....
    <espd-cac:EconomicOperatorParty>
        <espd-cbc:SMEIndicator>false</espd-cbc:SMEIndicator>
        <espd-cac:RepresentativeNaturalPerson>
            <cac:PowerOfAttorney>
                <cac:AgentParty>
                    <cac:Person>
                        <cac:Contact/>
                        <cac:ResidenceAddress/>
                    </cac:Person>
                </cac:AgentParty>
            </cac:PowerOfAttorney>
        </espd-cac:RepresentativeNaturalPerson>
        <cac:Party>
            <cac:PartyName>
                <cbc:Name></cbc:Name>
            </cac:PartyName>
            <cac:PostalAddress>
                <cbc:PostalZone>1050</cbc:PostalZone>(1)
                <cac:Country>
                    <cbc:IdentificationCode listID="CountryCodeIdentifier" listAgencyID="EU-COM-GROW" listName="CountryCodeIdentifier" listVersionID="1.0.2">GR</cbc:IdentificationCode>
                </cac:Country>
            </cac:PostalAddress>
            <cac:Contact/>
        </cac:Party>
    </espd-cac:EconomicOperatorParty>
   ...
</espd:ESPDResponse>
1 XML element Postbox has been replaced by PostalZone

The xml element cbc:VersionID until now contains ESPD Service version. This will be modified so that xml element cbc:VersionID will contain ESPD Data Exchange Model version.

Example:

espd-response.xml
<espd:ESPDResponse>
    .....
   <cbc:VersionID schemeAgencyID="EU-COM-GROW">1.0.2</cbc:VersionID> (1)
   .....
</espd:ESPDResponse>
1 XML element cbc:VersionID contains the ESPD Data Exchange Model version.

Version 2016.12

The possibility of adding an unlimited number of criterion references for certain criteria introduces a new way of defining them. Each requirement group that can be repeated as many times as desired (called henceforth unbounded requirement group) will be defined only once in the criterion definition and its definition will be cloned as many times as necessary. This means that the requirement group definition will appear only once in the ESPD Request while on the ESPD Response it can be present multiple times.

The new definition of the selection criteria from part C (For works contracts: performance of works of the specified type, For supply contracts: performance of deliveries of the specified type, For service contracts: performance of services of the specified type will contain only two groups, as follows:

selectionCriteria.js
"groups": [
  {
    "name": "G1",
    "id": "96f00020-0a25-402e-b850-2378e83b5695",
    "unbounded": "true",
    "requirements": [
      {
        "id": "ab05ff3b-f3e1-4441-9b43-ee9912e29e92",
        "description": "Description",
        "responseType": "DESCRIPTION"
      },
      {
        "id": "42db0eaa-d2dd-48cb-83ac-38d73cab9b50",
        "description": "Amount",
        "responseType": "AMOUNT"
      },
      {
        "id": "42ec8116-31a7-4118-8612-5b04f5c8bde7",
        "description": "Start Date",
        "responseType": "DATE"
      },
      {
        "id": "3641b897-f9f0-4d90-909a-b6d4c4b1d645",
        "description": "End Date",
        "responseType": "DATE
      },
      {
        "id": "a92536ab-6783-40bb-a037-5d31f421fd85",
        "description": "Recipients",
        "responseType": "DESCRIPTION"
      }
    ]
  },
  {
    "name": "G2",
    "id": "9026e403-3eb6-4705-a9e9-e21a1efc867d",
    "requirements": [
      {
        "id": "9dae5670-cb75-4c97-901b-96ddac5a633a",
        "description": "Is this information available electronically?",
        "responseType": "INDICATOR"
      }
    ],
    "subgroups": [
      {
        "name": "G2.1",
        "id": "0a166f0a-0c5f-42b0-81e9-0fc9fa598a48",
        "fulfillmentIndicator": "true",
        "requirements": [
          {
            "id": "03bb1954-13ae-47d8-8ef8-b7fe0f22d700",
            "description": "URL",
            "responseType": "EVIDENCE_URL"
          },
          {
            "id": "e2d863a0-60cb-4e58-8c14-4c1595af48b7",
            "description": "Code",
            "responseType": "CODE"
          },
          {
            "id": "5cbf74d9-a1e2-4233-921d-8b298842ee7d",
            "description": "Issuer",
            "responseType": "DESCRIPTION"
          }
        ]
      }
    ]
  }
}

Please notice that we don’t have 5 groups with the same structure but different ids anymore, but only one, G1, and this group has a new property, unbounded set to true. This property will not be saved in the XML files but is used internally by the ESPD application to handle this scenario.

In order to support the ESPD Responses generated by versions prior to 2016.12 we need to define some mappings so that the old requirement group and requirement ids point only to one primary group or requirement. Whenever we encounter one of the ids from idsToBeReplaced we will use the entity referenced by the replacementId.

selectionCriteria.js
"requirementGroupMappings": [
  {
    "replacementId": "96f00020-0a25-402e-b850-2378e83b5695", // use only this requirement group from now on
    "idsToBeReplaced": [ // whenever we see these requirement groups we will use the new one above
      "c48572f9-47bf-423a-9885-2c78ae9ca718",
      "2c7a3581-2954-4142-8c1b-5c52d7c7e9b7",
      "d67a6126-dd6d-4ed2-bda7-214a19e13a63",
      "159fc086-cf34-48a4-a41b-afed62661383"
    ]
  }
],
"requirementMappings": [
  { // mapping for 'Description'
    "replacementId": "ab05ff3b-f3e1-4441-9b43-ee9912e29e92", // use only this requirement from now on
    "idsToBeReplaced": [ // whenever we see these requirements we will use the new one above
      "927def36-1fa3-4018-8b45-7ee2c5b1e0af",
      "e6ca4034-cfee-499a-9a47-c4f2862ef4d0",
      "b1640c24-b405-443e-bf5e-d7771f66aab6",
      "587129bc-a5e1-43be-94ac-6e5366d30c67"
    ]
  },
  { // mapping for 'Amount'
    "replacementId": "42db0eaa-d2dd-48cb-83ac-38d73cab9b50",
    "idsToBeReplaced": [
      "4acd0a02-c267-4d05-b456-c0565c2ffd46",
      "28fb4b41-5178-4b79-ba24-d9a62fa4a658",
      "9f278e42-aa1d-4b2e-97cd-832248aa5393",
      "cc1a0b1e-dbfd-4313-a4fb-2e543b05549b"
    ]
  },
  { // mapping for 'Start date'
    "replacementId": "42ec8116-31a7-4118-8612-5b04f5c8bde7",
    "idsToBeReplaced": [
      "8d0e5e16-85ed-4730-a784-d4db8f439c0c",
      "c953e635-580b-4d7c-a30c-2edbde3b8fdf",
      "9b263b45-fc63-4b01-a3dc-cb9c95dda449",
      "056cba1d-986b-4164-92b6-26a1cbdf0690"
    ]
  },
  { // mapping for 'End date'
    "replacementId": "3641b897-f9f0-4d90-909a-b6d4c4b1d645",
    "idsToBeReplaced": [
      "4c842551-fb07-4a13-91e6-5653820f7e80",
      "822934ff-da94-40d2-a799-f29ba7bba2b0",
      "7a95ddbd-05e8-4af4-973f-1b8d05f71e0f",
      "dd71df86-3ad5-42dd-add5-9bd51dc88f05"
     ]
   },
   { // mapping for 'Recipients'
     "replacementId": "a92536ab-6783-40bb-a037-5d31f421fd85",
     "idsToBeReplaced": [
       "c8babafa-b6fa-4e14-8749-d913d8f1d33b",
       "5157e1ff-d272-4382-98a9-6953f5a15300",
       "a84ea948-cf03-47b5-b4cf-a35f49910d10",
       "38a4802f-0b93-4e78-ad4e-2a057e1aa578"
     ]
  }
]

This update will affect the Economic Operator criterion EO registered with id 9b19e869-6c89-4cc4-bd6c-ac9ca8602165. The requirement Not applicable with id 67fd1dde-2a0a-486e-9469-79c78796fc22 will be removed from the parent criterion and will not be displayed and understood anymore by the ESPD service.

All the Information is available electronically requirement groups will contain one extra requirement, called Issuer. Please keep in mind that this modification will affect a lot of criteria.

For the exclusion criteria, the requirement will have this definition:

exclusionCriteria.js
{
  "id": "c3ccfa31-0c5e-4e3a-a3fd-db9fb83d78d4",
  "description": "Issuer",
  "responseType": "DESCRIPTION"
}

And for the selection criteria, the requirement will include the following definition:

selectionCriteria.js
{
  "id": "5cbf74d9-a1e2-4233-921d-8b298842ee7d",
  "description": "Issuer",
  "responseType": "DESCRIPTION"
}

The economic operator (other) criteria will contain the requirement below:

otherCriteria.js
{
  "id": "d8e1e818-d67b-4bb9-9aeb-4c10943a8342",
  "description": "Issuer",
  "responseType": "DESCRIPTION"
}

A requirement for Description has to be added to the Conflict of interest due to its participation in the procurement procedure exclusion criterion, inside a requirement group G1.1.

exclusionCriteria.js
"subgroups": [
  {
    "name": "G1.1",
    "id": "73f0fe4c-4ed9-4343-8096-d898cf200146",
    "fulfillmentIndicator": "true",
    "requirements": [
      {
        "id": "e098da8e-4717-4500-965f-f882d5b4e1ad",
        "description": "Please describe them",
        "responseType": "DESCRIPTION",
      }
    ]
  }
]

We need to add the self-cleaning subgroup to the section D exclusion criterion Purely national grounds.

Consequently, the G1.1 criterion group will contain the following subgroup structure:

exclusionCriteria.js
{
  "name": "G1.1.1",
  "id": "5f9f09f7-f701-432c-9fdc-c22c124a74c9",
  "requirements": [
    {
      "id": "20c5361b-7599-4ee6-b030-7f8323174d1e",
      "description": "Have you taken measures to demonstrate your reliability (\"Self-Cleaning\")?",
      "responseType": "INDICATOR"
    }
  ],
  "subgroups": [
    {
      "name": "G1.1.1.1",
      "id": "74e6c7b4-757b-4b40-ada6-fad6a997c310",
      "fulfillmentIndicator": "true",
      "requirements": [
        {
          "id": "7b07904f-e080-401a-a3a1-9a3efeeda54b",
          "description": "Please describe them",
          "responseType": "DESCRIPTION"
        }
      ]
    }
  ]
}

The structure of the General yearly turnover and Specific yearly turnover selection criteria has been simplified. They don’t need the following requirements:

  • Your answer? with id 15335c12-ad77-4728-b5ad-3c06a60d65a4

  • Please provide the requested data below with id 3a6fefd4-f458-4d43-97fb-0725fce5dce2

Subsequently, the G1 group e1886054-ada4-473c-9afc-2fde82c24cf4 and its internal structure have disappeared.

The new structure looks like this:

selectionCriteria.json
"groups": [
  {
    "name": "G1",
    "id": "c0cd9c1c-e90a-4ff9-bce3-ac0fe31abf16",
    "requirements": [
      {
        "id": "5aacceb3-280e-42f1-b2da-3d8ac7877fe9",
        "description": "Year",
        "responseType": "QUANTITY_YEAR"
      },
      {
        "id": "42db0eaa-d2dd-48cb-83ac-38d73cab9b50",
        "description": "Amount",
        "responseType": "AMOUNT"
      }
    ]
  },
  {
    "name": "G2",
    "id": "99c9d014-d0e1-473d-b6d4-a8549f2b19fa",
    "requirements": [
      {
        "id": "49a57870-7fb8-451f-a7af-fa0e7f8b97e7",
        "description": "Year",
        "responseType": "QUANTITY_YEAR"
      },
      {
        "id": "4acd0a02-c267-4d05-b456-c0565c2ffd46",
        "description": "Amount",
        "responseType": "AMOUNT"
      }
    ]
  },
  {
    "name": "G3",
    "id": "9f0e291f-05c9-4cb6-bc50-4c2d3b2049b2",
    "requirements": [
      {
        "id": "9d0cf1cb-27bc-4747-8579-47dce4d8d490",
        "description": "Year",
        "responseType": "QUANTITY_YEAR"
      },
      {
        "id": "28fb4b41-5178-4b79-ba24-d9a62fa4a658",
        "description": "Amount",
        "responseType": "AMOUNT"
      }
    ]
  },
  {
    "name": "G4",
    "id": "67b8d7fa-a0aa-43d6-a30b-e15b95326df2",
    "requirements": [
      {
        "id": "17a7353d-a7a4-43ee-9cc8-b9db83eeafb3",
        "description": "Year",
        "responseType": "QUANTITY_YEAR"
      },
      {
        "id": "9f278e42-aa1d-4b2e-97cd-832248aa5393",
        "description": "Amount",
        "responseType": "AMOUNT"
      }
    ]
  },
  {
    "name": "G5",
    "id": "c8c09a0c-b7a7-4271-bb6a-80f1c0e988f7",
    "requirements": [
      {
        "id": "34825634-5151-4e31-af1b-7eafadcf15be",
        "description": "Year",
        "responseType": "QUANTITY_YEAR"
      },
      {
        "id": "cc1a0b1e-dbfd-4313-a4fb-2e543b05549b",
        "description": "Amount",
        "responseType": "AMOUNT"
      }
    ]
  },
  {
    "name": "G6",
    "id": "9026e403-3eb6-4705-a9e9-e21a1efc867d",
    "requirements": [
      {
        "id": "9dae5670-cb75-4c97-901b-96ddac5a633a",
        "description": "Is this information available electronically?",
        "responseType": "INDICATOR"
      }
    ],
    "subgroups": [
      {
        "name": "G2.1",
        "id": "0a166f0a-0c5f-42b0-81e9-0fc9fa598a48",
        "fulfillmentIndicator": "true",
        "requirements": [
          {
            "id": "03bb1954-13ae-47d8-8ef8-b7fe0f22d700",
            "description": "URL",
            "responseType": "EVIDENCE_URL"
          },
          {
            "id": "e2d863a0-60cb-4e58-8c14-4c1595af48b7",
            "description": "Code",
            "responseType": "CODE"
          }
        ]
      }
    ]
  }
  ]
}

The Average yearly turnover and Specific average turnover criteria should match the paper version. Therefore, the structure of their G1 group with id e1886054-ada4-473c-9afc-2fde82c24cf4 changes completely. They will contain only two requirements on the first group, Number of years and Average turnover.

selectionCriteria.json
{
  "name": "G1",
  "id": "e1886054-ada4-473c-9afc-2fde82c24cf4",
  "requirements": [
    {
      "id": "b98ffd05-6572-4b07-a521-693a1754ed46",
      "description": "Number of years",
      "responseType": "QUANTITY_INTEGER"
    },
    {
      "id": "217637ba-6bdb-4c73-a38f-27fe0e71d9be",
      "description": "Average turnover",
      "responseType": "AMOUNT"
    }
  ]
}

The following criteria will need to contain two date requirements instead of one: Start date and End date.

  • For works contracts: performance of works of the specified type;

  • For supply contracts: performance of deliveries of the specified type;

  • For service contracts: performance of services of the specified type.

Please keep in mind that the other requirements will remain, only the Date requirement will be split into two new ones.

selectionCriteria.js
"groups": [
  {
    "name": "G1",
    "id": "96f00020-0a25-402e-b850-2378e83b5695",
    "requirements": [
      ...,
      {
        "id": "42ec8116-31a7-4118-8612-5b04f5c8bde7",
        "description": "Start Date",
        "responseType": "DATE"
      },
      {
        "id": "3641b897-f9f0-4d90-909a-b6d4c4b1d645",
        "description": "End Date",
        "responseType": "DATE"
      },
      ...
    ]
  },
  {
    "name": "G2",
    "id": "c48572f9-47bf-423a-9885-2c78ae9ca718",
    "requirements": [
      ...,
      {
        "id": "8d0e5e16-85ed-4730-a784-d4db8f439c0c",
        "description": "Start Date",
        "responseType": "DATE"
      },
      {
        "id": "4c842551-fb07-4a13-91e6-5653820f7e80",
        "description": "End Date",
        "responseType": "DATE"
      },
      ...
    ]
  },
  {
    "name": "G3",
    "id": "2c7a3581-2954-4142-8c1b-5c52d7c7e9b7",
    "requirements": [
      ...,
      {
        "id": "c953e635-580b-4d7c-a30c-2edbde3b8fdf",
        "description": "Start Date",
        "responseType": "DATE"
      },
      {
        "id": "822934ff-da94-40d2-a799-f29ba7bba2b0",
        "description": "End Date",
        "responseType": "DATE"
      },
      ...
    ]
  },
  {
    "name": "G4",
    "id": "d67a6126-dd6d-4ed2-bda7-214a19e13a63",
    "requirements": [
      ...,
      {
        "id": "9b263b45-fc63-4b01-a3dc-cb9c95dda449",
        "description": "Start Date",
        "responseType": "DATE"
      },
      {
        "id": "7a95ddbd-05e8-4af4-973f-1b8d05f71e0f",
        "description": "End Date",
        "responseType": "DATE"
      },
      ...
    ]
  },
  {
    "name": "G5",
    "id": "159fc086-cf34-48a4-a41b-afed62661383",
    "requirements": [
      ...,
      {
        "id": "056cba1d-986b-4164-92b6-26a1cbdf0690",
        "description": "Start Date",
        "responseType": "DATE"
      },
      {
        "id": "dd71df86-3ad5-42dd-add5-9bd51dc88f05",
        "description": "End Date",
        "responseType": "DATE"
      },
      ...
    ]
  }

Version 2016.08

Part II - Information concerning the economic operator, section A - Information about the economic operator contains the VAT number if applicable and If no VAT number is applicable, please indicate another national identification number, if required and applicable fields. In order to be able to distinguish between the VAT Number and National Number in the XML we are now using the schemeID attribute of the cac:EconomicOperatorParty.cac:Party.cac:PartyIdentification element. The two possible values which should be used are:

  • VAT_Number

  • National_Number

Example:

espd-response.xml
<espd-cac:EconomicOperatorParty>
  <espd-cbc:SMEIndicator>false</espd-cbc:SMEIndicator>
  <espd-cac:RepresentativeNaturalPerson>
    <cac:PowerOfAttorney>
      <cac:AgentParty>
        <cac:Person>
          <cac:Contact/>
          <cac:ResidenceAddress/>
        </cac:Person>
      </cac:AgentParty>
    </cac:PowerOfAttorney>
  </espd-cac:RepresentativeNaturalPerson>
  <cac:Party>
    <cac:PartyIdentification>
      <cbc:ID schemeAgencyID="EU-COM-GROW" schemeID="National_Number">123456</cbc:ID> (1)
    </cac:PartyIdentification>
    <cac:PartyIdentification>
      <cbc:ID schemeAgencyID="EU-COM-GROW" schemeID="VAT_Number">BE0999999999</cbc:ID> (2)
    </cac:PartyIdentification>
    <cac:PartyName>
      <cbc:Name>Dell</cbc:Name>
    </cac:PartyName>
    <cac:PostalAddress>
      <cac:Country>
        <cbc:IdentificationCode listID="CountryCodeIdentifier" listAgencyID="EU-COM-GROW" listName="CountryCodeIdentifier" listVersionID="1.0.2">AT</cbc:IdentificationCode>
      </cac:Country>
    </cac:PostalAddress>
    <cac:Contact/>
  </cac:Party>
</espd-cac:EconomicOperatorParty>
1 The national number
2 The VAT number

The id of the G1.1 group belonging to the Part III - Exclusion grounds, section A - Grounds relating to criminal convictions has been changed to f5276600-a2b6-4ff6-a90e-b31fe19dae41 due to a conflict with the G2.1(URL/Code) group of the Information available electronically parent group.

Example:

espd-response.xml
<ccv:RequirementGroup pi="GROUP_FULFILLED.ON_TRUE">
  <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">f5276600-a2b6-4ff6-a90e-b31fe19dae41</cbc:ID>
  <ccv:Requirement responseDataType="DATE">
    <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">ecf40999-7b64-4e10-b960-7f8ff8674cf6</cbc:ID>
    <cbc:Description>Date of conviction</cbc:Description>
    <ccv:Response>
      <cbc:Date>2015-12-09</cbc:Date>
    </ccv:Response>
  </ccv:Requirement>
  ...
</ccv:RequirementGroup>

Version 2016.07

A new field called Consortium name was added in Part II - Information concerning the economic operator, Section C - Information about reliance on the capacities of other entities.

The information is saved inside the <espd-cbc:EconomicOperatorGroupName/> element on an ESPD Response.

Example:

espd-response.xml
<espd:ESPDResponse>
   <cbc:UBLVersionID schemeAgencyID="OASIS-UBL-TC">2.1</cbc:UBLVersionID>
   <cbc:CustomizationID schemeName="CustomizationID" schemeAgencyID="BII" schemeVersionID="3.0">urn:www.cenbii.eu:transaction:biitrns092:ver3.0</cbc:CustomizationID>
   <cbc:ID schemeID="ISO/IEC 9834-8:2008 - 4UUID" schemeAgencyID="EU-COM-GROW" schemeAgencyName="DG GROW (European Commission)" schemeVersionID="1.1">3679123f-de23-4703-8161-cf6c8d9b8ad9</cbc:ID>
   <cbc:CopyIndicator>false</cbc:CopyIndicator>
   <cbc:VersionID schemeAgencyID="EU-COM-GROW">2016.08.01</cbc:VersionID>
   <cbc:IssueDate>2016-05-30</cbc:IssueDate>
   <cbc:IssueTime>00:00:00</cbc:IssueTime>
   <cbc:ContractFolderID schemeAgencyID="TeD">SMART 2015/0065</cbc:ContractFolderID>
   <espd-cbc:EconomicOperatorGroupName>Hodor consortium</espd-cbc:EconomicOperatorGroupName> (1)
   ...
</espd:ESPDResponse>
1 The name of the consortium is saved here

These are some changes affecting only the ESPD application which fixed some correctness issues regarding the XMLs generated by the application.

  1. Update country codes for version 1.0.2 of the data model, the new values are below.

EspdRequestMarshallingTest.groovy
then: "check address information"
result.ContractingParty.Party.PostalAddress.Country.IdentificationCode.@listAgencyID.text() == "EU-COM-GROW"
result.ContractingParty.Party.PostalAddress.Country.IdentificationCode.@listName.text() == "CountryCodeIdentifier"
result.ContractingParty.Party.PostalAddress.Country.IdentificationCode.@listVersionID.text() == "1.0.2"
  1. Update criterion and jurisdiction codes for version 1.0.2 of the data model, the new values are below.

AbstractCriteriaFixture.groovy
assert request.Criterion[idx].TypeCode.@listVersionID.text() == "1.0.2"
assert ref.JurisdictionLevelCode.@listVersionID.text() == "1.0.2"
  1. Update Study and research facilities and Educational and professional qualifications criterion type codes to match version 1.0.2 of the data model, the new values are below.

EducationalProfessionalQualificationsRequestTest.groovy
checkCriterionTypeCode(request, idx,
  "CRITERION.SELECTION.TECHNICAL_PROFESSIONAL_ABILITY.TECHNICAL.PROFESSIONAL_QUALIFICATIONS")
StudyResearchFacilitiesRequestTest.groovy
checkCriterionTypeCode(request, idx,
  "CRITERION.SELECTION.TECHNICAL_PROFESSIONAL_ABILITY.TECHNICAL.FACILITIES_FOR_STUDY_RESEARCH")

Version 2016.06.1

The id of the Please specify requirement belonging to the G1 group of the Subcontracting proportion criterion was changed due to a conflict with other existing ids. The new id is 15778db8-0d84-42ba-931b-774c1b3d3f9f.

SubcontractingProportionResponseTest.groovy
then: "main sub group"
def g1 = response.Criterion[idx].RequirementGroup[0]
g1.ID.text() == "575f7550-8a2d-4bad-b9d8-be07ab570076"
g1.@pi.text() == ""
g1.RequirementGroup.size() == 0
g1.Requirement.size() == 1
checkRequirement(g1.Requirement[0], "15778db8-0d84-42ba-931b-774c1b3d3f9f", "Please specify", "DESCRIPTION")

On Part VI - Concluding statements we added two new fields, Date and Place.

espd-response.xml
<espd:ESPDResponse>
  ...
  <cbc:IssueDate>2015-11-25</cbc:IssueDate> (1)
  <cbc:IssueTime>13:19:20</cbc:IssueTime>
  ...
  <cac:Signature>
    <cbc:ID>a47fe139-f2b1-4886-9c01-70033ad82fcb</cbc:ID>
    <cac:SignatoryParty>
      <cac:PhysicalLocation>
        <cbc:Name>Eastwatch by the Sea</cbc:Name> (2)
      </cac:PhysicalLocation>
    </cac:SignatoryParty>
  </cac:Signature>
  ...
</espd:ESPDResponse>
1 The Date information is saved here
2 The Place information is saved inside the Signature element

Version 2016.06

  1. The Name and Description of the Other criteria have been swapped.

EconomicOperatorParticipatingProcurementProcedureResponseTest.groovy
def response = parseResponseXml(espd)
def idx = getEoCriterionIndex(AwardCriterion.EO_PARTICIPATING_PROCUREMENT_PROCEDURE)

then: "CriterionID element"
checkCriterionId(response, idx, "ee51100f-8e3e-40c9-8f8b-57d5a15be1f2")

then: "CriterionTypeCode element"
checkCriterionTypeCode(response, idx, "DATA_ON_ECONOMIC_OPERATOR")

then: "CriterionName element"
response.Criterion[idx].Name.text() == "EO participating in procurement procedure" (1)

then: "CriterionDescription element"
response.Criterion[idx].Description.text() ==
  "Is the economic operator participating in the procurement procedure together with others?" (2)

then: "check all the sub groups"
response.Criterion[idx].RequirementGroup.size() == 1
1 The name (which used to be empty) is present now and goes here
2 The old name is now stored in the Description element
EconomicOperatorRegisteredResponseTest.groovy
then: "CriterionID element"
  checkCriterionId(response, idx, "9b19e869-6c89-4cc4-bd6c-ac9ca8602165")

then: "CriterionTypeCode element"
  checkCriterionTypeCode(response, idx, "DATA_ON_ECONOMIC_OPERATOR")

then: "CriterionName element"
  response.Criterion[idx].Name.text() == "EO registered"

then: "first sub group requirements"
  def r1_0 = response.Criterion[idx].RequirementGroup[0].Requirement[0]
  checkRequirement(r1_0, "67fd1dde-2a0a-486e-9469-79c78796fc22", "Not applicable", "INDICATOR")

  def r1_1 = response.Criterion[idx].RequirementGroup[0].Requirement[1]
  checkRequirement(r1_1, "7f18c64e-ae09-4646-9400-f3666d50af51", "", "INDICATOR")
  1. Restructure the requirement groups according to the VCD proposed solution

All the criteria were restructured into new requirement groups and the <ccv:RequirementGroup pi="GROUP_FULFILLED.ON_TRUE"> logic has been introduced. More information about the criteria and requirement groups instantiation can be found here:

The results of all the changes performed on this issue are reflected in the criterion configuration files below:

Version 2016.05

In case Part I - Information concerning the procurement procedure and the contracting authority or contracting entity, section Information about publication is missing the Notice number in the OJS field, when we want to save the ESPD Request/Response we need to provide an ID to the parent AdditionalDocumentReference element because the ID is mandatory. We will use the value 0000/S 000-000000 to represent the lack of the notice number in the OJS.

The generation of the TED information inside the ESPD Request in this case should look like the test below.

EspdRequestMarshallingTest.groovy
def "should contain AdditionalDocumentReference with default ID if the TED OJS number is missing"() {
  given:
  def espd = new EspdDocument(ojsNumber: "     ", tedReceptionId: "     ", (1)
    procedureTitle: "Belgium-Brussels: SMART 2015/0065 — Benchmarking deployment of eHealth among general practitioners 2015",
    procedureShortDesc: "Service category No 11: Management consulting services [6] and related services.",
    tedUrl: "http://ted.europa.eu/udl?uri=TED:NOTICE:002226-2016:TEXT:ES:HTML")

  when:
  def result = parseRequestXml(espd)

  then:
  result.AdditionalDocumentReference.size() == 1

  then:
  result.AdditionalDocumentReference[0].ID.text() == "0000/S 000-000000" (2)
  result.AdditionalDocumentReference[0].ID.@schemeID.text() == "COM-GROW-TEMPORARY-ID" (3)
  result.AdditionalDocumentReference[0].ID.@schemeAgencyID.text() == "EU-COM-GROW"
  result.AdditionalDocumentReference[0].ID.@schemeAgencyName.text() == "DG GROW (European Commission)"
  result.AdditionalDocumentReference[0].ID.@schemeVersionID.text() == "1.1"

  then:
  result.AdditionalDocumentReference[0].DocumentTypeCode.@listAgencyID.text() == "EU-COM-GROW"
  result.AdditionalDocumentReference[0].DocumentTypeCode.@listID.text() == "ReferencesTypeCodes"
  result.AdditionalDocumentReference[0].DocumentTypeCode.@listVersionID.text() == "1.0"
  result.AdditionalDocumentReference[0].DocumentTypeCode.text() == "TED_CN"

  then:
  result.AdditionalDocumentReference[0].Attachment.ExternalReference.FileName.text() == "Belgium-Brussels: SMART 2015/0065 — Benchmarking deployment of eHealth among general practitioners 2015"
  result.AdditionalDocumentReference[0].Attachment.ExternalReference.Description[0].text() == "Service category No 11: Management consulting services [6] and related services."
  result.AdditionalDocumentReference[0].Attachment.ExternalReference.URI.text() == "http://ted.europa.eu/udl?uri=TED:NOTICE:002226-2016:TEXT:ES:HTML"
}
1 The notice number in the OJS is missing (empty in this case)
2 This value should be saved in the ESPD Request
3 The schemeID should be COM-GROW-TEMPORARY-ID

The test below imports an ESPD Request with such a temporary notice number and checks that the information is ignored in this case.

request_temporary_ojs_number_import.xml
</espd-req:ESPDRequest>
  ...
  <cbc:ContractFolderID schemeAgencyID="TeD">SMART 2016/0069</cbc:ContractFolderID>
  ...
  <!-- For procurement projects above the threshold it is compulsory to specify the following data, by means of an AdditionalDocumentReference element, about the Contract Notice published in TeD: the OJEU S number[], date[], page[], Notice number in OJS: YYYY/S [][][]-[][][][][][], Title and Description of the Procurement Project -->
  <cac:AdditionalDocumentReference>
    <cbc:ID schemeID="COM-GROW-TEMPORARY-ID" schemeAgencyID="EU-COM-GROW" (1)
      schemeAgencyName="DG GROW (European Commission)" schemeVersionID="1.1">0000/S 000-000000</cbc:ID> (2)
    <cbc:DocumentTypeCode listAgencyID="EU-COM-GROW" listID="ReferencesTypeCodes" listVersionID="1.0">TED_CN</cbc:DocumentTypeCode>
    <cac:Attachment>
      <cac:ExternalReference>
        <cbc:URI>http://ted.europa.eu/udl?uri=TED:NOTICE:373035-2015:TEXT:EN:HTML</cbc:URI>
        <!-- Title of the Contract Notice -->
        <cbc:FileName>Belgium-Brussels: SMART 2015/0065 — Benchmarking deployment of eHealth among general practitioners 2015</cbc:FileName>
        <!-- Short description of the Procurement Project -->
        <cbc:Description>Service category No 11: Management consulting services [6] and related services.</cbc:Description>
        <cbc:Description>16-000136-001</cbc:Description>
      </cac:ExternalReference>
    </cac:Attachment>
  </cac:AdditionalDocumentReference>
...
</espd-req:ESPDRequest>
1 The code used in this special case
2 The value used to represent a missing notice number
EspdRequestOtherInformationImportTest.groovy
def "we should not load the ojs number if it is marked as a temporary one"() {
  given:
  def espdXml = importXmlRequestFile("request_temporary_ojs_number_import.xml")
  EspdDocument espd = marshaller.importEspdRequest(IOUtils.toInputStream(espdXml)).get()

  expect:
  espd.fileRefByCA == "SMART 2016/0069"
  espd.ojsNumber == null (1)
  espd.procedureTitle == "Belgium-Brussels: SMART 2015/0065 — Benchmarking deployment of eHealth among general practitioners 2015"
  espd.procedureShortDesc == "Service category No 11: Management consulting services [6] and related services."
  espd.tedUrl == "http://ted.europa.eu/udl?uri=TED:NOTICE:373035-2015:TEXT:EN:HTML"
  espd.tedReceptionId == "16-000136-001"
}
1 The notice number in the OJS should be ignored in this case

Version 2016.04.01

The exclusion criterion Conflict of interest due to its participation in the procurement procedure needs only the Yes/No requirement and not the rest.

espd-response.xml
<ccv:Criterion>
  <cbc:ID schemeID="CriteriaID" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">b1b5ac18-f393-4280-9659-1367943c1a2e</cbc:ID>
  <cbc:TypeCode listID="CriteriaTypeCode" listAgencyID="EU-COM-GROW" listVersionID="1.0.2">CRITERION.EXCLUSION.CONFLICT_OF_INTEREST.PROCEDURE_PARTICIPATION</cbc:TypeCode>
  <cbc:Name>Conflict of interest due to its participation in the procurement procedure</cbc:Name>
  ...
  <ccv:RequirementGroup>
    <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">30450436-f559-4dfa-98ba-f0842ed9d2a0</cbc:ID>
    <ccv:Requirement responseDataType="INDICATOR">
      <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">974c8196-9d1c-419c-9ca9-45bb9f5fd59a</cbc:ID>
      <cbc:Description>Your answer?</cbc:Description>
      <ccv:Response>
        <ccv-cbc:Indicator>false</ccv-cbc:Indicator>
      </ccv:Response>
    </ccv:Requirement>
  </ccv:RequirementGroup>
</ccv:Criterion>

The Guilty of misinterpretation exclusion criterion only needs the Yes/No requirement.

espd-response.xml
<ccv:Criterion>
  <cbc:ID schemeID="CriteriaID" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">696a75b2-6107-428f-8b74-82affb67e184</cbc:ID>
  <cbc:TypeCode listID="CriteriaTypeCode" listAgencyID="EU-COM-GROW" listVersionID="1.0.2">CRITERION.EXCLUSION.CONFLICT_OF_INTEREST.MISINTERPRETATION</cbc:TypeCode>
  <cbc:Name>Guilty of misinterpretation, withheld information, unable to provide required documents and obtained confidential information of this procedure</cbc:Name>
  ...
  <ccv:RequirementGroup>
    <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">30450436-f559-4dfa-98ba-f0842ed9d2a0</cbc:ID>
    <ccv:Requirement responseDataType="INDICATOR">
      <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">974c8196-9d1c-419c-9ca9-45bb9f5fd59a</cbc:ID>
      <cbc:Description>Your answer?</cbc:Description>
      <ccv:Response>
        <ccv-cbc:Indicator>false</ccv-cbc:Indicator>
      </ccv:Response>
    </ccv:Requirement>
  </ccv:RequirementGroup>
</ccv:Criterion>

For the economic operator criterion EO registered found in Part II - Information concerning the economic operator, section A - Information about the economic operator, the requirement with id 0e71abd3-198e-49c5-8128-5708617bb191 is transformed from a DESCRIPTION to an INDICATOR type of requirement.

espd-request.xml
...
<ccv:RequirementGroup pi="GROUP_FULFILLED.ON_FALSE">
  <cbc:ID schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">59e6f3ef-15cd-4e21-82ac-ea497ccd44e2</cbc:ID>
  <ccv:Requirement responseDataType="INDICATOR">
    <cbc:ID schemeID="CriterionRelatedIDs" schemeAgencyID="EU-COM-GROW" schemeVersionID="1.0">0e71abd3-198e-49c5-8128-5708617bb191</cbc:ID>
    <cbc:Description>e) Will the economic operator be able to provide a certificate with regard to the payment of social security contributions and taxes or provide information enabling the contracting authority or contracting entity to obtaining it directly by accessing a national database in any Member State that is available free of charge?</cbc:Description>
    <ccv:Response/>
  </ccv:Requirement>
  ...
</ccv:RequirementGroup>
...

Release notes

2018.11 (26th of November 2018)

2018.10 (15th of October 2018)

2018.04 (4th of April 2018)

  • Hide default check boxes on exclusion criteria page

2017.11.01 (16th of April 2018)

  • Update TED API URL

  • Criteria enum values small improvements

2017.11 (30th of November 2017)

Hotfix provided for translation issues

2017.06.03 (6th of November 2017)

Hotfix provided for translation issues

2017.06.02 (13th of July 2017)

Hotfix for issue with yearly turnovers

2017.06.01 (6th of July 2017)

Hotfix provided for interface issue

2017.03.04 (20th of June 2017)

2017.03.02 (5th of May 2017)

2017.03.01 (11th of April 2017)

This release contains a bugfix related to printing issues introduced in version 2017.03.

2017.02.01 (3rd of March 2017)

The duration of the user session stored on the server has been reduced back to 2 hours.

2017.01.01 (1st of February 2017)

2016.11.01 (2nd of December 2016)

Bug

2016.10.02 (28th of November 2016)

2016.10.01 (11th of November 2016)

Enhancement

2016.08.01 (19th of September 2016)

2016.06.01 (30th of June 2016)

Bug

  • [ESPD-90] - IE does not allow to copy text with paragraphs in textfield

  • [ESPD-96] - Exclusion ground part C must be preselected

  • [ESPD-104] - We are missing fields for Part VI

  • [ESPD-119] - Incorrect criterion definitions

Improvement

  • [ESPD-6] - Use procedure, exclusion as tabs

  • [ESPD-76] - Countries list

  • [ESPD-97] - Re-assign labels in the Home Page

  • [ESPD-100] - Selection criteria requirements duplicate ids

  • [ESPD-106] - Part V should not be shown to CAs

  • [ESPD-108] - VCD issues (continued from version 2016.06)

  • [ESPD-109] - Update of the text on the start page

  • [ESPD-110] - Remove all placeholders from the interface

New Feature

  • [ESPD-50] - Link to eCertis

  • [ESPD-95] - EO should be able to create an ESPD response from scratch as well

2016.06 (2nd of June 2016)

This most important updates of this release are:

  • The restructuring of criterion subgroups in order to achieve a better interoperability with the VCD application

  • Deploy the application as an executable WAR file

Improvement

  • [ESPD-92] - Issues of interoperability with VCD

  • [ESPD-94] - Official name of CA should not be anymore mandatory

  • [ESPD-99] - Deploy the application as an executable WAR file

  • [ESPD-102] - Update breadcrumb

  • [ESPD-107] - Update text in the Home page

2016.05 (12th of May 2016)

The main purpose of this release was to make public the open source version of the ESPD application on Github.

Bug

  • [ESPD-90] - IE does not allow to copy text with paragraphs in textfield

  • [ESPD-93] - Part 1 - title and short description are not exported

Task

  • [ESPD-91] - Read proof

2016.04.02 (2nd of May 2016)

Bug

  • [ESPD-93] - Part 1 - title and short description are not exported

2016.04.01 (25th of April 2016)

Bug

  • [ESPD-73] - Missing translation

  • [ESPD-78] - Modification of exclusion criterion 'Guilty of misinterpretation'

  • [ESPD-80] - Numbers are handled wrongly

  • [ESPD-81] - Number of years should be calculated automatically

  • [ESPD-83] - EO not able to import a previously created ESPD

  • [ESPD-84] - Textfield into Yes/No

  • [ESPD-85] - Review ESPD as CA goes to non existent page

  • [ESPD-88] - Modification of exclusion ground conflict of interest

Deploy

  • [ESPD-56] - Configure GIT

Improvement

  • [ESPD-86] - Printing possibility for CA

2016.04 (15th of April 2016)

Bug

  • [ESPD-62] - Tooltip bug (Amount concerned box)

  • [ESPD-63] - Results of testing (Editorial Issues)

  • [ESPD-69] - Part 2 > question e) on the Procedure page

  • [ESPD-74] - Tooltip strange symbol

  • [ESPD-75] - Breadcrumb links

Improvement

  • [ESPD-47] - Translation file

  • [ESPD-72] - Exclusion Grounds de-selectable Part C

New Feature

  • [ESPD-52] - Statistics

1.1 (10th of February 2016)

Test Sub-task

  • [ESPD-38] - Test of Tests from Application support

  • [ESPD-39] - Test of Tests from Application support

Bug

  • [ESPD-64] - Results of testing (Translation issues)

Improvement

  • [ESPD-37] - Information from TED to make ESPD easier

  • [ESPD-45] - Improve metadata

  • [ESPD-46] - Merge two ESPD files

  • [ESPD-49] - New EN version

Task

  • [ESPD-44] - Test from the application support

  • [ESPD-60] - Upload all translations

  • [ESPD-61] - Leaflet in all languages

Testing Issue

  • [ESPD-55] - Check ESPD service

1.0 (6th of November 2015)

First version of the application

License

The ESPD project is licensed under the European Union Public Licence.