diff --git a/src/main/java/org/olat/core/commons/persistence/PersistentObject.java b/src/main/java/org/olat/core/commons/persistence/PersistentObject.java
index 1c92f9fa8e4e25e7277781c8d3a5fb0bd007bd4d..bd0d980ebe6b4885c42cb848bb3f8fa5fb939ac0 100644
--- a/src/main/java/org/olat/core/commons/persistence/PersistentObject.java
+++ b/src/main/java/org/olat/core/commons/persistence/PersistentObject.java
@@ -44,12 +44,17 @@ public abstract class PersistentObject implements CreateInfo, Persistable {
 	private int version = 0;
 	protected Date creationDate;
 	
-	/**
-	 * @see org.olat.core.commons.persistence.Auditable#getCreationDate()
-	 */
+	@Override
 	public Date getCreationDate() {
 		return creationDate;
 	}
+
+	/**
+	 * @param date
+	 */
+	public void setCreationDate(Date date) {
+		creationDate = date;
+	}
 	
 	/**
 	 * For Hibernate only
@@ -59,14 +64,6 @@ public abstract class PersistentObject implements CreateInfo, Persistable {
 		this.version = version;
 	}
 
-	/**
-	 * For Hibernate only
-	 * @param date
-	 */
-	private void setCreationDate(Date date) {
-		creationDate = date;
-	}
-
 	/**
 	 * @return Long
 	 */
diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
index 4cabd9a4240b1233ad0129c8710f945b02ffb36b..2f3accee64df0b4971c64b157c6608003f62da5d 100644
--- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
+++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
@@ -103,6 +103,7 @@
 		<class>org.olat.course.nodes.cl.model.DBCheckbox</class>
 		<class>org.olat.course.nodes.cl.model.DBCheck</class>
 		<class>org.olat.course.certificate.model.CertificateImpl</class>
+		<class>org.olat.course.certificate.model.CertificateStandalone</class>
 		<class>org.olat.course.certificate.model.CertificateLightImpl</class>
 		<class>org.olat.course.certificate.model.CertificateTemplateImpl</class>
 		<class>org.olat.group.model.ContactView</class>
diff --git a/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java b/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java
index cb2b9340fbd503ea18b1d252abd8067aaf5a2782..c0eb72c2e4a6012f8ef7bdde12016829d68255c1 100644
--- a/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java
+++ b/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java
@@ -46,11 +46,13 @@ import org.olat.course.CourseModule;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.model.UserEfficiencyStatementImpl;
 import org.olat.course.assessment.model.UserEfficiencyStatementLight;
+import org.olat.course.assessment.model.UserEfficiencyStatementStandalone;
 import org.olat.course.config.CourseConfig;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
+import org.olat.resource.OLATResource;
 import org.olat.user.UserDataDeletable;
 import org.olat.user.UserManager;
 
@@ -129,12 +131,61 @@ public class EfficiencyStatementManager extends BasicManager implements UserData
 		RepositoryEntry re = repositoryManager.lookupRepositoryEntry(courseOres, false);
 		updateUserEfficiencyStatement(userCourseEnv, re.getKey(), courseOres);
 	}
+
+	public UserEfficiencyStatement createUserEfficiencyStatement(Date creationDate, Float score, Boolean passed, Identity identity, OLATResource resource) {
+		UserEfficiencyStatementImpl efficiencyProperty = new UserEfficiencyStatementImpl();
+		efficiencyProperty.setCreationDate(creationDate);
+		efficiencyProperty.setLastModified(new Date());
+		efficiencyProperty.setScore(score);
+		efficiencyProperty.setPassed(passed);
+
+		efficiencyProperty.setTotalNodes(0);
+		efficiencyProperty.setAttemptedNodes(0);
+		efficiencyProperty.setPassedNodes(0);
+
+		efficiencyProperty.setIdentity(identity);
+		efficiencyProperty.setResource(resource);
+
+		ICourse course = CourseFactory.loadCourse(resource.getResourceableId());
+		efficiencyProperty.setTitle(course.getCourseEnvironment().getCourseTitle());
+		efficiencyProperty.setShortTitle(course.getCourseEnvironment().getRunStructure().getRootNode().getShortTitle());
+		efficiencyProperty.setCourseRepoKey(course.getCourseEnvironment().getCourseGroupManager().getCourseEntry().getKey());
+
+		dbInstance.getCurrentEntityManager().persist(efficiencyProperty);
+
+		return efficiencyProperty;
+	}
+	
+	public UserEfficiencyStatement createStandAloneUserEfficiencyStatement(Date creationDate, Float score, Boolean passed,
+			Identity identity, Long resourceKey, String courseTitle) {
+		UserEfficiencyStatementStandalone efficiencyProperty = new UserEfficiencyStatementStandalone();
+		efficiencyProperty.setCreationDate(creationDate);
+		efficiencyProperty.setLastModified(new Date());
+		efficiencyProperty.setScore(score);
+		efficiencyProperty.setPassed(passed);
+
+		efficiencyProperty.setTotalNodes(0);
+		efficiencyProperty.setAttemptedNodes(0);
+		efficiencyProperty.setPassedNodes(0);
+
+		efficiencyProperty.setIdentity(identity);
+		efficiencyProperty.setResourceKey(resourceKey);
+
+		efficiencyProperty.setTitle(courseTitle);
+		efficiencyProperty.setShortTitle(courseTitle);
+		efficiencyProperty.setCourseRepoKey(null);
+
+		dbInstance.getCurrentEntityManager().persist(efficiencyProperty);
+
+		return efficiencyProperty;
+	}
+	
 	
 	/**
 	 * Updates the users efficiency statement for this course
 	 * @param userCourseEnv
 	 * @param repoEntryKey
-	 * @param checkForExistingProperty
+	 * @param courseOres
 	 */
 	private void updateUserEfficiencyStatement(final UserCourseEnvironment userCourseEnv, final Long repoEntryKey, OLATResourceable courseOres) {
     //	o_clusterOK: by ld
@@ -175,7 +226,7 @@ public class EfficiencyStatementManager extends BasicManager implements UserData
 				} else {
 					// update existing
 					if (isLogDebugEnabled()) {
-						logDebug("updatting efficiency statement property::" + efficiencyProperty.getKey() + " for id::" + identity.getName() + " repoEntry::" + repoEntryKey);
+						logDebug("updating efficiency statement property::" + efficiencyProperty.getKey() + " for id::" + identity.getName() + " repoEntry::" + repoEntryKey);
 					}	
 					fillEfficiencyStatement(efficiencyStatement, efficiencyProperty);
 					dbInstance.updateObject(efficiencyProperty);
@@ -305,7 +356,8 @@ public class EfficiencyStatementManager extends BasicManager implements UserData
 		try {
 			StringBuilder sb = new StringBuilder();
 			sb.append("select statement from ").append(UserEfficiencyStatementImpl.class.getName()).append(" as statement ")
-			  .append(" where statement.identity.key=:identityKey and statement.archivedResourceKey=:resourceKey");
+			  .append(" where statement.identity.key=:identityKey")
+			  .append(" and statement.resource.key=:resourceKey");
 
 			List<UserEfficiencyStatementImpl> statement = dbInstance.getCurrentEntityManager()
 					.createQuery(sb.toString(), UserEfficiencyStatementImpl.class)
@@ -577,7 +629,6 @@ public class EfficiencyStatementManager extends BasicManager implements UserData
 	
 	/**
 	 * Delete the given efficiency statement for this person
-	 * @param identity
 	 * @param efficiencyStatement
 	 */
 	public void deleteEfficiencyStatement(UserEfficiencyStatementLight efficiencyStatement) {
@@ -588,9 +639,8 @@ public class EfficiencyStatementManager extends BasicManager implements UserData
 	 * Create or update all efficiency statment lists for the given list of identities and this course
 	 * This is called from only one thread, since the course is locked at editing (either CourseEdit or CourseDetails edit).
 	 * 
-	 * @param course 
+	 * @param ores The resource to load the course
 	 * @param identities List of identities
-	 * @param checkForExistingRecord true: check if efficiency statement for this user exist;
 	 * false: always create new one (be careful with this one!)
 	 */	
 	public void updateEfficiencyStatements(OLATResourceable ores, List<Identity> identities) {
diff --git a/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java b/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java
index 1d998084bd379c67524b42b8589f44d7587d4deb..ef809efe934aa9bae5a2daf3041ad67ccb0536c2 100644
--- a/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java
+++ b/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java
@@ -893,7 +893,7 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements
 						CertificateTemplate template = null;
 						Long templateId = course.getCourseConfig().getCertificateTemplate();
 						if(templateId != null) {
-							template = certificatesManager.getTemplateById(new Long(templateId));
+							template = certificatesManager.getTemplateById(templateId);
 						}
 						CertificateInfos certificateInfos = new CertificateInfos(assessedIdentity, score, passed);
 						MailerResult result = new MailerResult();
diff --git a/src/main/java/org/olat/course/assessment/model/EfficiencyStatementVO.java b/src/main/java/org/olat/course/assessment/model/EfficiencyStatementVO.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff36b0657f38eff6521433af0c8aad5ebbc9b80a
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/model/EfficiencyStatementVO.java
@@ -0,0 +1,68 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.model;
+
+import java.util.Date;
+
+/**
+ * 
+ * Initial date: 17.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class EfficiencyStatementVO {
+
+	private Float score;
+	private Boolean passed;
+	private Date creationDate;
+	private String courseTitle;
+	
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	public Float getScore() {
+		return score;
+	}
+
+	public void setScore(Float score) {
+		this.score = score;
+	}
+
+	public Boolean getPassed() {
+		return passed;
+	}
+
+	public void setPassed(Boolean passed) {
+		this.passed = passed;
+	}
+
+	public String getCourseTitle() {
+		return courseTitle;
+	}
+
+	public void setCourseTitle(String courseTitle) {
+		this.courseTitle = courseTitle;
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml
index 4cd8c9a9471b259761f6adc7ff6d5d2421fef54e..49d14c41a12a5f60901cb4daf47e376c9697f147 100644
--- a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml
+++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.hbm.xml
@@ -44,6 +44,39 @@
                  cascade="none"/>
   </class>
   
+  <class name="org.olat.course.assessment.model.UserEfficiencyStatementStandalone" table="o_as_eff_statement">	
+	<cache usage="transactional" />
+
+	<id name="key" type="long" column="id"	unsaved-value="null">
+		<generator class="hilo"/>
+	</id>
+
+	<version name="version" access="field" column="version" type="int"/>
+	<property name="creationDate" column="creationdate" type="timestamp" />
+	<property name="lastModified" column="lastmodified" type="timestamp" />
+
+	<property name="score" column="score" type="float" />
+	<property name="passed" column="passed" type="boolean" />
+	<property name="totalNodes" column="total_nodes" type="int" />
+	<property name="attemptedNodes" column="attempted_nodes" type="int" />
+	<property name="passedNodes" column="passed_nodes" type="int" />
+
+	<property name="title" column="course_title" length="255"  type="string" />
+	<property name="shortTitle" column="course_short_title" length="128"  type="string" />
+	<property name="courseRepoKey" column="course_repo_key" type="long" />
+	<property name="statementXml" column="statement_xml" type="string" length="16777210" />
+	
+	<property name="resourceKey" column="fk_resource_id" type="long" />
+                 
+	<many-to-one name="identity"
+                 column="fk_identity"
+                 foreign-key="cx_eff_statement_to_identity"
+                 class="org.olat.basesecurity.IdentityImpl"
+                 outer-join="true"
+                 unique="false"
+                 cascade="none"/>
+  </class>
+  
   <class name="org.olat.course.assessment.model.UserEfficiencyStatementLight" table="o_as_eff_statement" mutable="false">
 	<id name="key" type="long" column="id"	unsaved-value="null">
 		<generator class="hilo"/>
diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.java b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.java
index ff13944b93261bd257021f131e761754ce46e7f0..40865dcd4786222bb6985928b5822720774beadb 100644
--- a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.java
+++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementImpl.java
@@ -51,15 +51,18 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use
 	private String statementXml;
 	
 	private Date lastModified;
-		
+
+	@Override
 	public Date getLastModified() {
 		return lastModified;
 	}
 
+	@Override
 	public void setLastModified(Date lastModified) {
 		this.lastModified = lastModified;
 	}
 
+	@Override
 	public Float getScore() {
 		return score;
 	}
@@ -67,7 +70,8 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use
 	public void setScore(Float score) {
 		this.score = score;
 	}
-		
+
+	@Override
 	public Boolean getPassed() {
 		return passed;
 	}
@@ -75,7 +79,8 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use
 	public void setPassed(Boolean passed) {
 		this.passed = passed;
 	}
-	
+
+	@Override
 	public Integer getTotalNodes() {
 		return totalNodes;
 	}
@@ -84,6 +89,7 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use
 		this.totalNodes = totalNodes;
 	}
 
+	@Override
 	public Integer getAttemptedNodes() {
 		return attemptedNodes;
 	}
@@ -92,6 +98,7 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use
 		this.attemptedNodes = attemptedNodes;
 	}
 
+	@Override
 	public Integer getPassedNodes() {
 		return passedNodes;
 	}
@@ -108,6 +115,7 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use
 		this.statementXml = statementXml;
 	}
 
+	@Override
 	public Identity getIdentity() {
 		return identity;
 	}
@@ -132,6 +140,7 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use
 		this.title = title;
 	}
 
+	@Override
 	public String getShortTitle() {
 		return shortTitle;
 	}
@@ -140,6 +149,7 @@ public class UserEfficiencyStatementImpl extends PersistentObject implements Use
 		this.shortTitle = shortTitle;
 	}
 
+	@Override
 	public Long getCourseRepoKey() {
 		return courseRepoKey;
 	}
diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementLight.java b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementLight.java
index a238fd147096bfc06fb9e6218ae9b5ccce00162a..bfd22f56b16c3553103e6da2a99e4c47b8e008d6 100644
--- a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementLight.java
+++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementLight.java
@@ -53,15 +53,18 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us
 	private Long archivedResourceKey;
 	
 	private Date lastModified;
-		
+
+	@Override	
 	public Date getLastModified() {
 		return lastModified;
 	}
 
+	@Override
 	public void setLastModified(Date lastModified) {
 		this.lastModified = lastModified;
 	}
 
+	@Override
 	public Float getScore() {
 		return score;
 	}
@@ -69,7 +72,8 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us
 	public void setScore(Float score) {
 		this.score = score;
 	}
-		
+
+	@Override
 	public Boolean getPassed() {
 		return passed;
 	}
@@ -77,7 +81,8 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us
 	public void setPassed(Boolean passed) {
 		this.passed = passed;
 	}
-	
+
+	@Override
 	public Integer getTotalNodes() {
 		return totalNodes;
 	}
@@ -86,6 +91,7 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us
 		this.totalNodes = totalNodes;
 	}
 
+	@Override
 	public Integer getAttemptedNodes() {
 		return attemptedNodes;
 	}
@@ -94,6 +100,7 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us
 		this.attemptedNodes = attemptedNodes;
 	}
 
+	@Override
 	public Integer getPassedNodes() {
 		return passedNodes;
 	}
@@ -102,6 +109,7 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us
 		this.passedNodes = passedNodes;
 	}
 
+	@Override
 	public Identity getIdentity() {
 		return identity;
 	}
@@ -118,6 +126,7 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us
 		this.resource = resource;
 	}
 
+	@Override
 	public String getShortTitle() {
 		return shortTitle;
 	}
@@ -134,6 +143,7 @@ public class UserEfficiencyStatementLight extends PersistentObject implements Us
 		this.archivedResourceKey = archivedResourceKey;
 	}
 
+	@Override
 	public Long getCourseRepoKey() {
 		return courseRepoKey;
 	}
diff --git a/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementStandalone.java b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementStandalone.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a3d2a9c3e546d6f482a01d4d01fdb411ab0d0d9
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/model/UserEfficiencyStatementStandalone.java
@@ -0,0 +1,182 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.model;
+
+import java.util.Date;
+
+import org.olat.core.commons.persistence.PersistentObject;
+import org.olat.core.id.Identity;
+import org.olat.core.id.ModifiedInfo;
+import org.olat.course.assessment.UserEfficiencyStatement;
+
+/**
+ * 
+ * Mapping used to save efficiency statement in import process where
+ * the course / resource doesn't exists.
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class UserEfficiencyStatementStandalone extends PersistentObject implements UserEfficiencyStatement, ModifiedInfo {
+
+	private static final long serialVersionUID = 2996458434418813284L;
+	
+	private Float score;
+	private Boolean passed;
+	private Integer totalNodes;
+	private Integer attemptedNodes;
+	private Integer passedNodes;
+	
+	private Identity identity;
+	private Long resourceKey;
+	
+	private String title;
+	private String shortTitle;
+	private Long courseRepoKey;
+	
+	private String statementXml;
+	
+	private Date lastModified;
+	
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+
+	@Override
+	public Float getScore() {
+		return score;
+	}
+		
+	public void setScore(Float score) {
+		this.score = score;
+	}
+
+	@Override
+	public Boolean getPassed() {
+		return passed;
+	}
+		
+	public void setPassed(Boolean passed) {
+		this.passed = passed;
+	}
+
+	@Override
+	public Integer getTotalNodes() {
+		return totalNodes;
+	}
+
+	public void setTotalNodes(Integer totalNodes) {
+		this.totalNodes = totalNodes;
+	}
+
+	@Override
+	public Integer getAttemptedNodes() {
+		return attemptedNodes;
+	}
+
+	public void setAttemptedNodes(Integer attemptedNodes) {
+		this.attemptedNodes = attemptedNodes;
+	}
+
+	@Override
+	public Integer getPassedNodes() {
+		return passedNodes;
+	}
+
+	public void setPassedNodes(Integer passedNodes) {
+		this.passedNodes = passedNodes;
+	}
+
+	public String getStatementXml() {
+		return statementXml;
+	}
+
+	public void setStatementXml(String statementXml) {
+		this.statementXml = statementXml;
+	}
+
+	@Override
+	public Identity getIdentity() {
+		return identity;
+	}
+	
+	public void setIdentity(Identity identity) {
+		this.identity = identity;
+	}
+	
+	public Long getResourceKey() {
+		return resourceKey;
+	}
+
+	public void setResourceKey(Long resourceKey) {
+		this.resourceKey = resourceKey;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getShortTitle() {
+		return shortTitle;
+	}
+
+	public void setShortTitle(String shortTitle) {
+		this.shortTitle = shortTitle;
+	}
+
+	public Long getCourseRepoKey() {
+		return courseRepoKey;
+	}
+
+	public void setCourseRepoKey(Long courseRepoKey) {
+		this.courseRepoKey = courseRepoKey;
+	}
+
+	@Override
+	public String toString() {
+		return super.toString();
+	}
+	
+	@Override
+	public int hashCode() {
+		return getKey() == null ? -82654 : getKey().hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof UserEfficiencyStatementStandalone) {
+			UserEfficiencyStatementStandalone statement = (UserEfficiencyStatementStandalone)obj;
+			return getKey() != null && getKey().equals(statement.getKey());
+		}
+		return false;
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/restapi/EfficiencyStatementWebService.java b/src/main/java/org/olat/course/assessment/restapi/EfficiencyStatementWebService.java
new file mode 100644
index 0000000000000000000000000000000000000000..00b40fbbb3cdb3bce528f5fdfae59050c89b1e87
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/restapi/EfficiencyStatementWebService.java
@@ -0,0 +1,106 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.restapi;
+
+import static org.olat.restapi.security.RestSecurityHelper.isAdmin;
+
+import java.util.Date;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.EfficiencyStatement;
+import org.olat.course.assessment.EfficiencyStatementManager;
+import org.olat.course.assessment.model.EfficiencyStatementVO;
+import org.olat.resource.OLATResource;
+
+import org.olat.resource.OLATResourceManager;
+
+/**
+ * 
+ * Initial date: 17.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Path("repo/courses/{resourceKey}/statements")
+public class EfficiencyStatementWebService {
+	
+
+	/**
+	 * Create a new efficiency statement.
+	 * 
+	 * @response.representation.200.doc If the statement was persisted 
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The identity or the resource cannot be found
+	 * @param identityKey The owner of the certificate
+	 * @param resourceKey The primary key of the resource of the repository entry of the course.
+	 * @return Nothing special
+	 */
+	@PUT
+	@Path("{identityKey}")
+	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response putEfficiencyStatement(@PathParam("identityKey") Long identityKey, @PathParam("resourceKey") Long resourceKey,
+						EfficiencyStatementVO efficiencyStatementVO, @Context HttpServletRequest request) {
+		
+		if(!isAdmin(request)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		BaseSecurity baseSecurity = CoreSpringFactory.getImpl(BaseSecurity.class);
+		Identity assessedIdentity = baseSecurity.loadIdentityByKey(identityKey);
+		if(assessedIdentity == null) {
+			return Response.serverError().status(Response.Status.NOT_FOUND).build();
+		}
+
+		EfficiencyStatementManager efficiencyStatementManager = CoreSpringFactory.getImpl(EfficiencyStatementManager.class);
+
+		EfficiencyStatement efficiencyStatement = efficiencyStatementManager.getUserEfficiencyStatementByResourceKey(resourceKey, assessedIdentity);
+		if(efficiencyStatement != null) {
+			return Response.serverError().status(Response.Status.CONFLICT).build();
+		}
+		
+		Date creationDate = efficiencyStatementVO.getCreationDate();
+		Float score = efficiencyStatementVO.getScore();
+		Boolean passed = efficiencyStatementVO.getPassed();
+
+		OLATResourceManager resourceManager = CoreSpringFactory.getImpl(OLATResourceManager.class);
+		OLATResource resource = resourceManager.findResourceById(resourceKey);
+		if(resource == null) {
+			String courseTitle = efficiencyStatementVO.getCourseTitle();
+			efficiencyStatementManager.createStandAloneUserEfficiencyStatement(creationDate, score, passed, assessedIdentity, resourceKey, courseTitle);
+		} else {
+			efficiencyStatementManager.createUserEfficiencyStatement(creationDate, score, passed, assessedIdentity, resource);
+		}
+		return Response.ok().build();
+	}
+
+}
diff --git a/src/main/java/org/olat/course/certificate/CertificatesManager.java b/src/main/java/org/olat/course/certificate/CertificatesManager.java
index 9bb8c348b1e75cc13a373c86726e7df6ab7675f0..ddecf4019b3be5fccb5888d78d104a89c19c0b57 100644
--- a/src/main/java/org/olat/course/certificate/CertificatesManager.java
+++ b/src/main/java/org/olat/course/certificate/CertificatesManager.java
@@ -85,6 +85,10 @@ public interface CertificatesManager {
 	public boolean isRecertificationAllowed(Identity identity, RepositoryEntry entry);
 	
 	public File previewCertificate(CertificateTemplate template, RepositoryEntry entry, Locale locale);
+
+	public Certificate uploadCertificate(Identity identity, Date creationDate, OLATResource resource, File certificateFile);
+	
+	public Certificate uploadStandaloneCertificate(Identity identity, Date creationDate, Long resourceKey, File certificateFile);
 	
 	public void generateCertificates(List<CertificateInfos> identities, RepositoryEntry entry, CertificateTemplate template, MailerResult result);
 
diff --git a/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java b/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java
index 33fe6c439518fb9d90b52ac2727906b12830edf1..323bbf197464725041f9cdcc4b803917f9364c3d 100644
--- a/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java
+++ b/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java
@@ -75,6 +75,7 @@ import org.olat.course.certificate.CertificatesManager;
 import org.olat.course.certificate.RecertificationTimeUnit;
 import org.olat.course.certificate.model.CertificateImpl;
 import org.olat.course.certificate.model.CertificateInfos;
+import org.olat.course.certificate.model.CertificateStandalone;
 import org.olat.course.certificate.model.CertificateTemplateImpl;
 import org.olat.course.certificate.ui.CertificateController;
 import org.olat.course.config.CourseConfig;
@@ -235,7 +236,8 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 	public Certificate getLastCertificate(IdentityRef identity, Long resourceKey) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select cer from certificate cer")
-		  .append(" where cer.olatResource.key=:resourceKey and cer.identity.key=:identityKey and cer.last=true order by cer.creationDate");
+		  .append(" where (cer.olatResource.key=:resourceKey or cer.archivedResourceKey=:resourceKey)")
+		  .append(" and cer.identity.key=:identityKey and cer.last=true order by cer.creationDate");
 		List<Certificate> certififcates = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Certificate.class)
 				.setParameter("resourceKey", resourceKey)
@@ -386,6 +388,74 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 		return allowed;
 	}
 
+	@Override
+	public Certificate uploadCertificate(Identity identity, Date creationDate, OLATResource resource, File certificateFile) {
+		CertificateImpl certificate = new CertificateImpl();
+		certificate.setOlatResource(resource);
+		certificate.setArchivedResourceKey(resource.getKey());
+		if(creationDate != null) {
+			certificate.setCreationDate(creationDate);
+		}
+		certificate.setLastModified(certificate.getCreationDate());
+		certificate.setIdentity(identity);
+		certificate.setUuid(UUID.randomUUID().toString());
+		certificate.setLast(true);
+
+		String dir = usersStorage.generateDir();
+		try (InputStream in = Files.newInputStream(certificateFile.toPath())) {
+			File dirFile = new File(getCertificateRoot(), dir);
+			dirFile.mkdirs();
+
+			File storedCertificateFile = new File(dirFile, "Certificate.pdf");
+			Files.copy(in, storedCertificateFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+
+			certificate.setName(storedCertificateFile.getName());
+			certificate.setPath(dir + storedCertificateFile.getName());
+
+			Date dateFirstCertification = getDateFirstCertification(identity, resource);
+			if (dateFirstCertification != null) {
+				removeLastFlag(identity, resource);
+			}
+
+			dbInstance.getCurrentEntityManager().persist(certificate);
+		} catch (Exception e) {
+			log.error("", e);
+		}
+
+		return certificate;
+	}
+	
+	@Override
+	public Certificate uploadStandaloneCertificate(Identity identity, Date creationDate, Long resourceKey, File certificateFile) {
+		CertificateStandalone certificate = new CertificateStandalone();
+		certificate.setArchivedResourceKey(resourceKey);
+		if(creationDate != null) {
+			certificate.setCreationDate(creationDate);
+		}
+		certificate.setLastModified(certificate.getCreationDate());
+		certificate.setIdentity(identity);
+		certificate.setUuid(UUID.randomUUID().toString());
+		certificate.setLast(true);
+
+		String dir = usersStorage.generateDir();
+		try (InputStream in = Files.newInputStream(certificateFile.toPath())) {
+			File dirFile = new File(getCertificateRoot(), dir);
+			dirFile.mkdirs();
+
+			File storedCertificateFile = new File(dirFile, "Certificate.pdf");
+			Files.copy(in, storedCertificateFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+
+			certificate.setName(storedCertificateFile.getName());
+			certificate.setPath(dir + storedCertificateFile.getName());
+
+			dbInstance.getCurrentEntityManager().persist(certificate);
+		} catch (Exception e) {
+			log.error("", e);
+		}
+
+		return certificate;
+	}
+
 	@Override
 	public void generateCertificates(List<CertificateInfos> certificateInfos, RepositoryEntry entry,
 			CertificateTemplate template, MailerResult result) {
@@ -429,12 +499,12 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 	@Override
 	public Certificate generateCertificate(CertificateInfos certificateInfos, RepositoryEntry entry,
 			CertificateTemplate template, MailerResult result) {
-		Certificate certificate = peristCertificate(certificateInfos, entry, template, result);
+		Certificate certificate = persistCertificate(certificateInfos, entry, template, result);
 		markPublisherNews(null, entry.getOlatResource());
 		return certificate;
 	}
 
-	private Certificate peristCertificate(CertificateInfos certificateInfos, RepositoryEntry entry,
+	private Certificate persistCertificate(CertificateInfos certificateInfos, RepositoryEntry entry,
 			CertificateTemplate template, MailerResult result) {
 		OLATResource resource = entry.getOlatResource();
 		Identity identity = certificateInfos.getAssessedIdentity();
@@ -442,7 +512,11 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 		CertificateImpl certificate = new CertificateImpl();
 		certificate.setOlatResource(resource);
 		certificate.setArchivedResourceKey(resource.getKey());
-		certificate.setCreationDate(new Date());
+		if(certificateInfos.getCreationDate() != null) {
+			certificate.setCreationDate(certificateInfos.getCreationDate());
+		} else {
+			certificate.setCreationDate(new Date());
+		}
 		certificate.setLastModified(certificate.getCreationDate());
 		certificate.setIdentity(identity);
 		certificate.setUuid(UUID.randomUUID().toString());
@@ -460,7 +534,7 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 			Date dateFirstCertification = getDateFirstCertification(identity, resource);
 
 			File certificateFile;
-			if(template.getPath().toLowerCase().endsWith("pdf")) {
+			if(template == null || template.getPath().toLowerCase().endsWith("pdf")) {
 				CertificateTemplateWorker worker = new CertificateTemplateWorker(identity, entry, score, passed,
 						dateCertification, dateFirstCertification, locale, userManager, this);
 				certificateFile = worker.fill(template, dirFile);
diff --git a/src/main/java/org/olat/course/certificate/model/CertificateInfos.java b/src/main/java/org/olat/course/certificate/model/CertificateInfos.java
index 10575711aa3b5e200e3cb7a3ffbb8bd7cff2b57e..9b33986d0e9299f6237cf18b1d2411c95965aa44 100644
--- a/src/main/java/org/olat/course/certificate/model/CertificateInfos.java
+++ b/src/main/java/org/olat/course/certificate/model/CertificateInfos.java
@@ -19,6 +19,8 @@
  */
 package org.olat.course.certificate.model;
 
+import java.util.Date;
+
 import org.olat.core.id.Identity;
 
 /**
@@ -33,6 +35,8 @@ public class CertificateInfos {
 	private final Boolean passed;
 	private final Identity assessedIdentity;
 	
+	private Date creationDate;
+	
 	public CertificateInfos(Identity assessedIdentity, Float score, Boolean passed) {
 		this.score = score;
 		this.passed = passed;
@@ -50,4 +54,12 @@ public class CertificateInfos {
 	public Identity getAssessedIdentity() {
 		return assessedIdentity;
 	}
+
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
 }
diff --git a/src/main/java/org/olat/course/certificate/model/CertificateStandalone.java b/src/main/java/org/olat/course/certificate/model/CertificateStandalone.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7784d0fcabaa9d0f7a848c100485a13787e6d18
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/model/CertificateStandalone.java
@@ -0,0 +1,179 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.certificate.model;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
+import org.olat.course.certificate.Certificate;
+
+/**
+ * 
+ * Initial date: 17.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="certificatestandalone")
+@Table(name="o_cer_certificate")
+public class CertificateStandalone implements Certificate, Persistable {
+
+	private static final long serialVersionUID = 2360631986446191873L;
+
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
+	private Date lastModified;
+	
+	@Column(name="c_uuid", nullable=false, insertable=true, updatable=false)
+	private String uuid;
+
+	@Column(name="c_name", nullable=false, insertable=true, updatable=false)
+	private String name;
+	@Column(name="c_path", nullable=false, insertable=true, updatable=false)
+	private String path;
+	@Column(name="c_last", nullable=false, insertable=true, updatable=true)
+	private boolean last;
+	@Column(name="c_archived_resource_id", nullable=false, insertable=true, updatable=false)
+	private Long archivedResourceKey;
+	
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY, optional=true)
+	@JoinColumn(name="fk_identity", nullable=false, insertable=true, updatable=false)
+	private Identity identity;
+
+	@Override
+	public Long getKey() {
+		return key;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+	
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+	
+	public String getUuid() {
+		return uuid;
+	}
+
+	public void setUuid(String uuid) {
+		this.uuid = uuid;
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public boolean isLast() {
+		return last;
+	}
+
+	public void setLast(boolean last) {
+		this.last = last;
+	}
+
+	public String getPath() {
+		return path;
+	}
+
+	public void setPath(String path) {
+		this.path = path;
+	}
+
+	public Long getArchivedResourceKey() {
+		return archivedResourceKey;
+	}
+
+	public void setArchivedResourceKey(Long archivedResourceKey) {
+		this.archivedResourceKey = archivedResourceKey;
+	}
+
+	public Identity getIdentity() {
+		return identity;
+	}
+
+	public void setIdentity(Identity identity) {
+		this.identity = identity;
+	}
+
+	@Override
+	public int hashCode() {
+		return key == null ? -23984 : key.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof CertificateStandalone) {
+			CertificateStandalone prefs = (CertificateStandalone)obj;
+			return key != null && key.equals(prefs.key);
+		}
+		return false;
+	}
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+	
+
+}
diff --git a/src/main/java/org/olat/course/certificate/restapi/CertificationWebService.java b/src/main/java/org/olat/course/certificate/restapi/CertificationWebService.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbaa0207c8a946acf7356e96fcd70d74f9f18f80
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/restapi/CertificationWebService.java
@@ -0,0 +1,221 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.certificate.restapi;
+
+import static org.olat.restapi.security.RestSecurityHelper.isAdmin;
+
+import java.io.File;
+import java.util.Date;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.id.Identity;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.mail.MailerResult;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.certificate.Certificate;
+import org.olat.course.certificate.CertificateTemplate;
+import org.olat.course.certificate.CertificatesManager;
+import org.olat.course.certificate.model.CertificateInfos;
+import org.olat.repository.RepositoryEntry;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
+import org.olat.restapi.support.MultipartReader;
+import org.olat.restapi.support.ObjectFactory;
+
+/**
+ * 
+ * Initial date: 17.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Path("repo/courses/{resourceKey}/certificates")
+public class CertificationWebService {
+
+	/**
+	 * Return the certificate as PDF file.
+	 * 
+	 * @response.representation.200.mediaType application/pdf
+	 * @response.representation.200.doc The certificate as file
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The owner or the certificate cannot be found
+	 * @param identityKey The owner of the certificate
+	 * @param resourceKey The primary key of the resource of the repository entry of the course.
+	 * @param request The request
+	 * @return The certificate
+	 */
+	@GET
+	@Path("{identityKey}")
+	@Produces({"application/pdf"})
+	public Response getCertificate(@PathParam("identityKey") Long identityKey, @PathParam("resourceKey") Long resourceKey,
+			@Context HttpServletRequest request) {
+		if(!isAdmin(request)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+
+		CertificatesManager certificatesManager = CoreSpringFactory.getImpl(CertificatesManager.class);
+		BaseSecurity baseSecurity = CoreSpringFactory.getImpl(BaseSecurity.class);
+
+		Identity identity = baseSecurity.loadIdentityByKey(identityKey);
+		if(identity == null) {
+			return Response.serverError().status(Response.Status.NOT_FOUND).build();
+		}
+		Certificate certificate = certificatesManager.getLastCertificate(identity, resourceKey);
+		if(certificate == null) {
+			return Response.serverError().status(Response.Status.NOT_FOUND).build();
+		}
+
+		VFSLeaf certificateFile = certificatesManager.getCertificateLeaf(certificate);
+		return Response.ok(certificateFile.getInputStream()).build();
+	}
+	
+	/**
+	 * Generate a new certificate.
+	 * 
+	 * @response.representation.200.doc If the certificate was created 
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The identity or the resource cannot be found
+	 * @response.representation.500.doc An unexpected error happened during the creation of the certificate
+	 * @param identityKey The owner of the certificate
+	 * @param resourceKey The primary key of the resource of the repository entry of the course.
+	 * @param score The score which appears in the certificate
+	 * @param passed The passed/failed which appears in the certificate (true/false)
+	 * @param creationDate The date of the certification
+	 * @param request The request
+	 * @return Nothing special
+	 */
+	@PUT
+	@Path("{identityKey}")
+	public Response putCertificate(@PathParam("identityKey") Long identityKey, @PathParam("resourceKey") Long resourceKey,
+			@QueryParam("score") Float score, @QueryParam("passed") Boolean passed,
+			@QueryParam("creationDate") String creationDate,
+			@Context HttpServletRequest request) {
+		
+		if(!isAdmin(request)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+
+		BaseSecurity baseSecurity = CoreSpringFactory.getImpl(BaseSecurity.class);
+		Identity assessedIdentity = baseSecurity.loadIdentityByKey(identityKey);
+		if(assessedIdentity == null) {
+			return Response.serverError().status(Response.Status.NOT_FOUND).build();
+		}
+
+		OLATResourceManager resourceManager = CoreSpringFactory.getImpl(OLATResourceManager.class);
+		OLATResource resource = resourceManager.findResourceById(resourceKey);
+		if(resource == null) {
+			return Response.serverError().status(Response.Status.NOT_FOUND).build();
+		} else {
+			CertificatesManager certificatesManager = CoreSpringFactory.getImpl(CertificatesManager.class);
+			
+			ICourse course = CourseFactory.loadCourse(resource.getResourceableId());
+			RepositoryEntry entry = course.getCourseEnvironment().getCourseGroupManager().getCourseEntry();
+
+			CertificateTemplate template = null;
+			Long templateId = course.getCourseConfig().getCertificateTemplate();
+			if(templateId != null) {
+				template = certificatesManager.getTemplateById(templateId);
+			}
+			
+			MailerResult result = new MailerResult();
+			CertificateInfos certificateInfos = new CertificateInfos(assessedIdentity, score, passed);
+			if(StringHelper.containsNonWhitespace(creationDate)) {
+				Date date = ObjectFactory.parseDate(creationDate);
+				certificateInfos.setCreationDate(date);
+			}
+			Certificate certificate = certificatesManager.generateCertificate(certificateInfos, entry, template, result);
+			if(certificate != null) {
+				return Response.ok().build();
+			}
+			return Response.serverError().status(Response.Status.INTERNAL_SERVER_ERROR).build();
+		}	
+	}
+
+	/**
+	 * Upload a new certificate.
+	 * 
+	 * @response.representation.200.doc if the certificate was uploaded 
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+	 * @response.representation.404.doc The identity or the resource cannot be found
+	 * @param identityKey The owner of the certificate
+	 * @param resourceKey The primary key of the resource of the repository entry of the course.
+	 * @param request The request
+	 * @return Nothing special
+	 */
+	@POST
+	@Path("{identityKey}")
+	@Consumes(MediaType.MULTIPART_FORM_DATA)
+	public Response postCertificate(@PathParam("identityKey") Long identityKey, @PathParam("resourceKey") Long resourceKey,
+			@Context HttpServletRequest request) {
+		
+		if(!isAdmin(request)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+
+		MultipartReader partsReader = null;
+		try {
+			partsReader = new MultipartReader(request);
+			File tmpFile = partsReader.getFile();
+			String creationDateStr = partsReader.getValue("creationDate");
+			Date creationDate = null;
+			if(StringHelper.containsNonWhitespace(creationDateStr)) {
+				creationDate = ObjectFactory.parseDate(creationDateStr);
+			}
+
+			CertificatesManager certificatesManager = CoreSpringFactory.getImpl(CertificatesManager.class);
+			BaseSecurity baseSecurity = CoreSpringFactory.getImpl(BaseSecurity.class);
+			Identity assessedIdentity = baseSecurity.loadIdentityByKey(identityKey);
+			if(assessedIdentity == null) {
+				return Response.serverError().status(Response.Status.NOT_FOUND).build();
+			}
+
+			OLATResourceManager resourceManager = CoreSpringFactory.getImpl(OLATResourceManager.class);
+			OLATResource resource = resourceManager.findResourceById(resourceKey);
+			if(resource == null) {
+				certificatesManager.uploadStandaloneCertificate(assessedIdentity, creationDate, resourceKey, tmpFile);
+			} else {
+				certificatesManager.uploadCertificate(assessedIdentity, creationDate, resource, tmpFile);
+			}
+
+			return Response.ok().build();
+		} catch (Throwable e) {
+			throw new WebApplicationException(e);
+		}	finally {
+			MultipartReader.closeQuietly(partsReader);
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/restapi/_spring/restApiContext.xml b/src/main/java/org/olat/restapi/_spring/restApiContext.xml
index 98829b68c3f098da55d349236010496af3e47407..50528f70067c7b515d15f235f3db81e75ad174a4 100644
--- a/src/main/java/org/olat/restapi/_spring/restApiContext.xml
+++ b/src/main/java/org/olat/restapi/_spring/restApiContext.xml
@@ -43,6 +43,8 @@
 				<value>org.olat.course.nodes.co.COWebService</value>
 				<value>org.olat.course.nodes.en.ENWebService</value>
 				<value>org.olat.course.nodes.bc.BCWebService</value>
+				<value>org.olat.course.assessment.restapi.EfficiencyStatementWebService</value>
+				<value>org.olat.course.certificate.restapi.CertificationWebService</value>
 				<value>org.olat.modules.wiki.restapi.WikisWebService</value>
 				<value>org.olat.modules.fo.restapi.ForumImportWebService</value>
 				<value>org.olat.modules.fo.restapi.ForumCourseNodeWebService</value>
diff --git a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
index a27a8048767dd08d0d8c3b12a049edae381f5c17..ea568c87cb08a0089e85e281bed3a5969db3a40e 100644
--- a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
@@ -274,7 +274,6 @@ public class CoursesWebService {
 	 * 
 	 * 
 	 * @param request
-	 * @param access
 	 * @return
 	 */
 	@POST
diff --git a/src/test/java/org/olat/restapi/CertificationTest.java b/src/test/java/org/olat/restapi/CertificationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..af41aef45a2f01d6fb2889b25530fe0848857da6
--- /dev/null
+++ b/src/test/java/org/olat/restapi/CertificationTest.java
@@ -0,0 +1,223 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.restapi;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Calendar;
+import java.util.Date;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.util.EntityUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.core.util.mail.MailerResult;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.course.certificate.Certificate;
+import org.olat.course.certificate.CertificatesManager;
+import org.olat.course.certificate.model.CertificateInfos;
+import org.olat.repository.RepositoryEntry;
+import org.olat.restapi.support.ObjectFactory;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatJerseyTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 17.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CertificationTest extends OlatJerseyTestCase {
+
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private CertificatesManager certificatesManager;
+
+
+	@Test
+	public void getCertificate() throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		Assert.assertTrue(conn.login("administrator", "openolat"));
+
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("cert-1");
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("cert-2");
+		RepositoryEntry entry = JunitTestHelper.deployBasicCourse(author);
+
+		MailerResult result = new MailerResult();
+		CertificateInfos certificateInfos = new CertificateInfos(assessedIdentity, 2.0f, true);
+		Certificate certificate = certificatesManager.generateCertificate(certificateInfos, entry, null, result);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(certificate);
+
+		URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(entry.getOlatResource().getKey().toString())
+				.path("certificates").path(assessedIdentity.getKey().toString()).build();
+		HttpGet method = conn.createGet(uri, "application/pdf", true);
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+
+		EntityUtils.consume(response.getEntity());
+
+		conn.shutdown();
+	}
+	
+	@Test
+	public void generateCertificate() throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		Assert.assertTrue(conn.login("administrator", "openolat"));
+
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("cert-1");
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("cert-2");
+		RepositoryEntry entry = JunitTestHelper.deployBasicCourse(author);
+		dbInstance.commitAndCloseSession();
+
+		Date creationDate = createDate(2014, 9, 9);
+		URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(entry.getOlatResource().getKey().toString())
+				.path("certificates").path(assessedIdentity.getKey().toString())
+				.queryParam("score", "3.2")
+				.queryParam("passed", "true")
+				.queryParam("creationDate", ObjectFactory.formatDate(creationDate)).build();
+
+		HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
+
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+		
+		//check certificate
+		Certificate certificate = certificatesManager.getLastCertificate(assessedIdentity, entry.getOlatResource().getKey());
+		Assert.assertNotNull(certificate);
+		Assert.assertEquals(creationDate, certificate.getCreationDate());
+		//check the certificate file
+		VFSLeaf certificateLeaf = certificatesManager.getCertificateLeaf(certificate);
+		Assert.assertNotNull(certificateLeaf);
+		Assert.assertTrue(certificateLeaf.getSize() > 500);
+	}
+
+	@Test
+	public void uploadCertificate() throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		Assert.assertTrue(conn.login("administrator", "openolat"));
+
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("cert-1");
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("cert-2");
+		RepositoryEntry entry = JunitTestHelper.deployBasicCourse(author);
+		dbInstance.commitAndCloseSession();
+
+		URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(entry.getOlatResource().getKey().toString())
+				.path("certificates").path(assessedIdentity.getKey().toString()).build();
+
+		URL certificateUrl = CertificationTest.class.getResource("certificate.pdf");
+		Assert.assertNotNull(certificateUrl);
+		File certificateFile = new File(certificateUrl.toURI());
+		HttpPost method = conn.createPost(uri, MediaType.APPLICATION_JSON);
+		
+		Date creationDate = createDate(2014, 7, 1);
+		MultipartEntityBuilder builder = MultipartEntityBuilder.create()
+				.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
+				.addTextBody("filename", certificateFile.getName())
+				.addBinaryBody("file", certificateFile, ContentType.APPLICATION_OCTET_STREAM, certificateFile.getName())
+				.addTextBody("creationDate", ObjectFactory.formatDate(creationDate));
+		method.setEntity(builder.build());
+
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+
+		//check certificate
+		Certificate certificate = certificatesManager.getLastCertificate(assessedIdentity, entry.getOlatResource().getKey());
+		Assert.assertNotNull(certificate);
+		Assert.assertEquals(creationDate, certificate.getCreationDate());
+		//check the certificate file
+		VFSLeaf certificateLeaf = certificatesManager.getCertificateLeaf(certificate);
+		Assert.assertNotNull(certificateLeaf);
+		Assert.assertEquals(certificateFile.length(), certificateLeaf.getSize());
+	}
+	
+	@Test
+	public void uploadCertificate_standalone() throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		Assert.assertTrue(conn.login("administrator", "openolat"));
+
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("cert-1");
+		dbInstance.commitAndCloseSession();
+
+		Long resourceKey = 23687468l;
+		URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(resourceKey.toString())
+				.path("certificates").path(assessedIdentity.getKey().toString()).build();
+
+		URL certificateUrl = CertificationTest.class.getResource("certificate.pdf");
+		Assert.assertNotNull(certificateUrl);
+		File certificateFile = new File(certificateUrl.toURI());
+		HttpPost method = conn.createPost(uri, MediaType.APPLICATION_JSON);
+		
+		Date creationDate = createDate(2014, 7, 1);
+		MultipartEntityBuilder builder = MultipartEntityBuilder.create()
+				.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
+				.addTextBody("filename", certificateFile.getName())
+				.addBinaryBody("file", certificateFile, ContentType.APPLICATION_OCTET_STREAM, certificateFile.getName())
+				.addTextBody("creationDate", ObjectFactory.formatDate(creationDate));
+		method.setEntity(builder.build());
+
+		HttpResponse response = conn.execute(method);
+		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+
+		//check certificate
+		Certificate certificate = certificatesManager.getLastCertificate(assessedIdentity, resourceKey);
+		Assert.assertNotNull(certificate);
+		Assert.assertEquals(creationDate, certificate.getCreationDate());
+		//check the certificate file
+		VFSLeaf certificateLeaf = certificatesManager.getCertificateLeaf(certificate);
+		Assert.assertNotNull(certificateLeaf);
+		Assert.assertEquals(certificateFile.length(), certificateLeaf.getSize());
+	}
+	
+	private Date createDate(int year, int month, int day) {
+		Calendar cal = Calendar.getInstance();
+		cal.set(Calendar.YEAR, year);
+		cal.set(Calendar.MONTH, month);
+		cal.set(Calendar.DATE, day);
+		cal.set(Calendar.HOUR_OF_DAY, 0);
+		cal.set(Calendar.MINUTE, 0);
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		return cal.getTime();
+	}
+}
diff --git a/src/test/java/org/olat/restapi/EfficiencyStatementTest.java b/src/test/java/org/olat/restapi/EfficiencyStatementTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff48d91933aa20716eb39f550069f014defc4822
--- /dev/null
+++ b/src/test/java/org/olat/restapi/EfficiencyStatementTest.java
@@ -0,0 +1,133 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.restapi;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Date;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.util.EntityUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.EfficiencyStatementManager;
+import org.olat.course.assessment.UserEfficiencyStatement;
+import org.olat.course.assessment.model.EfficiencyStatementVO;
+import org.olat.repository.RepositoryEntry;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatJerseyTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 17.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class EfficiencyStatementTest extends OlatJerseyTestCase {
+
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private EfficiencyStatementManager efficiencyStatementManager;
+
+	@Test
+	public void putEfficiencyStatement() throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		Assert.assertTrue(conn.login("administrator", "openolat"));
+
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("cert-3");
+		Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("cert-4");
+		RepositoryEntry entry = JunitTestHelper.deployBasicCourse(author);
+		dbInstance.commitAndCloseSession();
+
+		URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(entry.getOlatResource().getKey().toString())
+				.path("statements").path(assessedIdentity.getKey().toString()).build();
+
+		EfficiencyStatementVO statement = new EfficiencyStatementVO();
+		statement.setCreationDate(new Date());
+		statement.setPassed(Boolean.TRUE);
+		statement.setScore(2.5f);
+
+		HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
+		conn.addJsonEntity(method, statement);
+
+		HttpResponse response = conn.execute(method);
+		assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+
+		UserEfficiencyStatement efficiencyStatement = efficiencyStatementManager
+				.getUserEfficiencyStatementFullByResourceKey(entry.getOlatResource().getKey(), assessedIdentity);
+
+		Assert.assertNotNull(efficiencyStatement);
+		Assert.assertNotNull(efficiencyStatement.getCourseRepoKey());
+		Assert.assertEquals(entry.getKey(), efficiencyStatement.getCourseRepoKey());
+		Assert.assertEquals(2.5f, efficiencyStatement.getScore(), 0.001);
+		Assert.assertEquals(Boolean.TRUE, efficiencyStatement.getPassed());
+		Assert.assertEquals(assessedIdentity, efficiencyStatement.getIdentity());
+	}
+	
+	@Test
+	public void putEfficiencyStatement_standalone() throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		Assert.assertTrue(conn.login("administrator", "openolat"));
+
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("cert-3");
+		dbInstance.commitAndCloseSession();
+		
+		Long resourceKey = 3495783497l;
+
+		URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(resourceKey.toString())
+				.path("statements").path(assessedIdentity.getKey().toString()).build();
+
+		EfficiencyStatementVO statement = new EfficiencyStatementVO();
+		statement.setCreationDate(new Date());
+		statement.setPassed(Boolean.TRUE);
+		statement.setScore(8.5f);
+		statement.setCourseTitle("Standalone");
+
+		HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
+		conn.addJsonEntity(method, statement);
+
+		HttpResponse response = conn.execute(method);
+		assertEquals(200, response.getStatusLine().getStatusCode());
+		EntityUtils.consume(response.getEntity());
+
+		//check the efficiency statement
+		UserEfficiencyStatement efficiencyStatement = efficiencyStatementManager
+				.getUserEfficiencyStatementFullByResourceKey(resourceKey, assessedIdentity);
+		Assert.assertNotNull(efficiencyStatement);
+		Assert.assertEquals(8.5f, efficiencyStatement.getScore(), 0.001);
+		Assert.assertEquals(Boolean.TRUE, efficiencyStatement.getPassed());
+		Assert.assertEquals("Standalone", efficiencyStatement.getShortTitle());
+		Assert.assertEquals(assessedIdentity, efficiencyStatement.getIdentity());
+	}
+}
diff --git a/src/test/java/org/olat/restapi/GroupMgmtTest.java b/src/test/java/org/olat/restapi/GroupMgmtTest.java
index 772aff5d1607c3e7878096fec041872a32795515..4fa9475e6b324fb3195dbd3694bd601f25596f2a 100644
--- a/src/test/java/org/olat/restapi/GroupMgmtTest.java
+++ b/src/test/java/org/olat/restapi/GroupMgmtTest.java
@@ -388,11 +388,11 @@ public class GroupMgmtTest extends OlatJerseyTestCase {
 		assertTrue(response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201);
 		EntityUtils.consume(response.getEntity());
 		
-    BusinessGroup bg = businessGroupService.loadBusinessGroup(g1.getKey());
-    assertNotNull(bg);
-    assertEquals(bg.getKey(), vo.getKey());
-    assertEquals(bg.getName(), "rest-g1-mod");
-    assertEquals(bg.getDescription(), "rest-g1 description");
+		BusinessGroup bg = businessGroupService.loadBusinessGroup(g1.getKey());
+		assertNotNull(bg);
+		assertEquals(bg.getKey(), vo.getKey());
+		assertEquals(bg.getName(), "rest-g1-mod");
+		assertEquals(bg.getDescription(), "rest-g1 description");
 	}
 	
 	@Test
@@ -412,13 +412,13 @@ public class GroupMgmtTest extends OlatJerseyTestCase {
 		assertTrue(response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201);
 		
 		GroupVO newGroupVo = conn.parse(response, GroupVO.class); 
-    assertNotNull(newGroupVo);
+		assertNotNull(newGroupVo);
 
-    BusinessGroup bg = businessGroupService.loadBusinessGroup(newGroupVo.getKey());
-    assertNotNull(bg);
-    assertEquals(bg.getKey(), newGroupVo.getKey());
-    assertEquals(bg.getName(), "rest-g5-new");
-    assertEquals(bg.getDescription(), "rest-g5 description");
+		BusinessGroup bg = businessGroupService.loadBusinessGroup(newGroupVo.getKey());
+		assertNotNull(bg);
+		assertEquals(bg.getKey(), newGroupVo.getKey());
+		assertEquals(bg.getName(), "rest-g5-new");
+		assertEquals(bg.getDescription(), "rest-g5 description");
 	}
 	
 	@Test
@@ -484,8 +484,8 @@ public class GroupMgmtTest extends OlatJerseyTestCase {
 		HttpResponse response = conn.execute(method);
 		assertEquals(200, response.getStatusLine().getStatusCode());
 		
-    BusinessGroup bg = businessGroupService.loadBusinessGroup(g1.getKey());
-    assertNull(bg);
+		BusinessGroup bg = businessGroupService.loadBusinessGroup(g1.getKey());
+		assertNull(bg);
 	}
 	
 	@Test
diff --git a/src/test/java/org/olat/restapi/certificate.pdf b/src/test/java/org/olat/restapi/certificate.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..f7edf3914c163ccb8f1b6e5073588efd268f52d5
Binary files /dev/null and b/src/test/java/org/olat/restapi/certificate.pdf differ
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index cbe48c4012190e5b2dce4a3dbabbec815da3aebc..fd37817518dde7ce9048b010e8c207f8aafaa916 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -190,6 +190,7 @@ import org.junit.runners.Suite;
 	org.olat.restapi.AuthenticationTest.class,
 	org.olat.restapi.CatalogTest.class,
 	org.olat.restapi.CalendarTest.class,
+	org.olat.restapi.CertificationTest.class,
 	org.olat.restapi.CourseGroupMgmtTest.class,
 	org.olat.restapi.CourseCalendarTest.class,
 	org.olat.restapi.CourseDBTest.class,
@@ -203,6 +204,7 @@ import org.junit.runners.Suite;
 	org.olat.restapi.CoursePublishTest.class,
 	org.olat.restapi.CoursesInfosTest.class,
 	org.olat.restapi.CourseTest.class,
+	org.olat.restapi.EfficiencyStatementTest.class,
 	org.olat.restapi.FolderTest.class,
 	org.olat.restapi.ForumTest.class,
 	org.olat.restapi.GroupFoldersTest.class,