Added excel export
This commit is contained in:
@@ -38,6 +38,18 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- EXCEL report -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- PDF report -->
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
@@ -356,6 +368,14 @@
|
||||
<artifactId>org.jacoco.core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Jakarta JSON Processing implementation for unit tests -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.parsson</groupId>
|
||||
<artifactId>parsson</artifactId>
|
||||
<version>1.1.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
|
||||
@@ -100,10 +100,10 @@ public class QuestionnaireCustomerService extends AbstractService {
|
||||
return QuestionnaireCustomerValue.builder(customer);
|
||||
}
|
||||
|
||||
public byte[] getExport(Long id, Long questionnaireId) {
|
||||
public Optional<byte[]> getExport(Long id, Long questionnaireId) {
|
||||
QuestionnaireCustomer customer = entityManager.find(QuestionnaireCustomer.class, id);
|
||||
if (customer == null) {
|
||||
return new byte[0];
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<Questionnaire> questionnaires = customer.getQuestionnaires().stream().sorted((x, y) -> x.getQuestionnaireDate().compareTo(y.getQuestionnaireDate())).toList();
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.service;
|
||||
|
||||
import static marketing.heyday.hartmann.fotodocumentation.core.model.QuestionnaireCustomer.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.ejb.LocalBean;
|
||||
import jakarta.ejb.Stateless;
|
||||
import marketing.heyday.hartmann.fotodocumentation.rest.vo.QuestionnairePublishValue;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.model.Questionnaire;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.model.QuestionnaireCustomer;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.query.Param;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.utils.QuestionnaireUploadJsonParser;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -19,8 +26,32 @@ import marketing.heyday.hartmann.fotodocumentation.rest.vo.QuestionnairePublishV
|
||||
@PermitAll
|
||||
public class QuestionnairePublishService extends AbstractService {
|
||||
|
||||
public boolean publish(QuestionnairePublishValue value) {
|
||||
// FIXME: implement me
|
||||
public boolean publish(String body) {
|
||||
var parserOpt = QuestionnaireUploadJsonParser.builder(body);
|
||||
if (parserOpt.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
var parser = parserOpt.get();
|
||||
|
||||
Optional<QuestionnaireCustomer> customerOpt = queryService.callNamedQuerySingleResult(FIND_BY_NUMBER, new Param(PARAM_NUMBER, parser.customerNumber()));
|
||||
var customer = customerOpt.orElseGet(() -> new QuestionnaireCustomer.Builder().customerNumber(parser.customerNumber()).name(parser.pharmacyName())
|
||||
.city(parser.city()).zip(parser.zip())
|
||||
.build());
|
||||
customer = entityManager.merge(customer);
|
||||
|
||||
var questionnaire = new Questionnaire.Builder().customer(customer).username(parser.username())
|
||||
.category("")// FIXME: remove category
|
||||
.comment(parser.comment())
|
||||
.customer(customer)
|
||||
.questionnaireDate(parser.date())
|
||||
.questions(parser.questionnair())
|
||||
.username(parser.username())
|
||||
.build();
|
||||
customer.getQuestionnaires().add(questionnaire);
|
||||
|
||||
entityManager.persist(questionnaire);
|
||||
entityManager.flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.CreationHelper;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.model.Questionnaire;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.model.QuestionnaireCustomer;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.utils.QuestionnaireJsonParser.QuestionJsonObj;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -21,9 +31,164 @@ import marketing.heyday.hartmann.fotodocumentation.core.model.QuestionnaireCusto
|
||||
public class ExcelUtils {
|
||||
private static final Log LOG = LogFactory.getLog(ExcelUtils.class);
|
||||
|
||||
public byte[] create(QuestionnaireCustomer customer, List<Questionnaire> questionnaires) {
|
||||
// FIXME: implement excel export
|
||||
return new byte[0];
|
||||
public Optional<byte[]> create(QuestionnaireCustomer customer, List<Questionnaire> questionnaires) {
|
||||
LOG.debug("Create excel file for customer " + customer);
|
||||
// TODO: implement excel export
|
||||
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); XSSFWorkbook workbook = new XSSFWorkbook()) {
|
||||
|
||||
for (var questionnaire : questionnaires) {
|
||||
//TODO: set sheet name
|
||||
writeSheet(workbook, customer, questionnaire);
|
||||
}
|
||||
|
||||
workbook.write(bos);
|
||||
return Optional.of(bos.toByteArray());
|
||||
} catch (IOException e) {
|
||||
LOG.debug("Failed to export countries", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeSheet(XSSFWorkbook workbook, QuestionnaireCustomer customer, Questionnaire questionnaire) throws IOException {
|
||||
XSSFSheet sheet = workbook.createSheet();
|
||||
int rowIndex = writeCustomerData(workbook, sheet, customer, questionnaire);
|
||||
writeQuestionData(sheet, questionnaire, rowIndex);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sheet.autoSizeColumn(i);
|
||||
}
|
||||
}
|
||||
|
||||
private int writeCustomerData(XSSFWorkbook workbook, XSSFSheet sheet, QuestionnaireCustomer customer, Questionnaire questionnaire) {
|
||||
int rowIndex = 0;
|
||||
XSSFRow row = sheet.createRow(rowIndex++);
|
||||
row.createCell(0).setCellValue(customer.getName());
|
||||
|
||||
row = sheet.createRow(rowIndex++);
|
||||
row.createCell(0).setCellValue(customer.getCustomerNumber());
|
||||
row = sheet.createRow(rowIndex++);
|
||||
row.createCell(0).setCellValue(customer.getCity());
|
||||
row = sheet.createRow(rowIndex++);
|
||||
row.createCell(0).setCellValue(customer.getZip());
|
||||
|
||||
row = sheet.createRow(rowIndex++);
|
||||
|
||||
CreationHelper createHelper = workbook.getCreationHelper();
|
||||
short format = createHelper.createDataFormat().getFormat("dd.MM.yyyy h:mm");
|
||||
CellStyle cellStyle = workbook.createCellStyle();
|
||||
cellStyle.setDataFormat(format);
|
||||
|
||||
var dateCell = row.createCell(0);
|
||||
dateCell.setCellStyle(cellStyle);
|
||||
|
||||
dateCell.setCellValue(questionnaire.getQuestionnaireDate());
|
||||
rowIndex++;
|
||||
rowIndex++;
|
||||
return rowIndex;
|
||||
}
|
||||
|
||||
private void writeQuestionData(XSSFSheet sheet, Questionnaire questionnaire, int rowIndex) throws IOException {
|
||||
QuestionnaireJsonParser parser = new QuestionnaireJsonParser();
|
||||
var success = parser.parse(questionnaire.getQuestions());
|
||||
if (!success) {
|
||||
throw new IOException("Failed to parse json");
|
||||
}
|
||||
|
||||
var questions = parser.getQuestions();
|
||||
|
||||
for (var question : questions) {
|
||||
XSSFRow row = sheet.createRow(rowIndex++);
|
||||
row.createCell(0).setCellValue(question.title());
|
||||
|
||||
switch (question.type()) {
|
||||
case "singleChoice":
|
||||
writeSingle(row, question);
|
||||
break;
|
||||
case "multiplChoice":
|
||||
int amount1 = writeMultiple(sheet, row, question);
|
||||
rowIndex = rowIndex + amount1;
|
||||
break;
|
||||
case "number":
|
||||
writeNumber(row, question);
|
||||
break;
|
||||
case "matrix":
|
||||
int amount2 = writeMatrix(sheet, row, question);
|
||||
rowIndex = rowIndex + amount2;
|
||||
break;
|
||||
case "freeText":
|
||||
writeFreeText(row, question);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rowIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeSingle(XSSFRow row, QuestionJsonObj question) {
|
||||
row.createCell(1).setCellValue(question.getSingleAnswer());
|
||||
}
|
||||
|
||||
private int writeMultiple(XSSFSheet sheet, XSSFRow row, QuestionJsonObj question) {
|
||||
var answers = question.getMultiAnswer();
|
||||
int count = 0;
|
||||
for (var answer : answers) {
|
||||
if (count == 0) {
|
||||
row.createCell(1).setCellValue(answer);
|
||||
} else {
|
||||
sheet.createRow(row.getRowNum() + count).createCell(1).setCellValue(answer);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return count - 1;
|
||||
}
|
||||
|
||||
private void writeNumber(XSSFRow row, QuestionJsonObj question) {
|
||||
var cell = row.createCell(1);
|
||||
cell.setCellType(CellType.NUMERIC);
|
||||
cell.setCellValue(question.getNumberAnswer());
|
||||
}
|
||||
|
||||
private void writeFreeText(XSSFRow row, QuestionJsonObj question) {
|
||||
row.createCell(1).setCellValue(question.getFreeText());
|
||||
}
|
||||
|
||||
private int writeMatrix(XSSFSheet sheet, XSSFRow row, QuestionJsonObj question) {
|
||||
var questions = question.getMatrixAnswer();
|
||||
int count = 2;
|
||||
|
||||
var answerOpts = questions.getFirst().answers();
|
||||
answerOpts.sort((i, j) -> i.answer().compareToIgnoreCase(j.answer()));
|
||||
|
||||
var headerRow = sheet.createRow(row.getRowNum() + count);
|
||||
// create header
|
||||
for (int i = 0; i < answerOpts.size(); i++) {
|
||||
var answer = answerOpts.get(i);
|
||||
headerRow.createCell(i + 1).setCellValue(answer.answer());
|
||||
}
|
||||
count++;
|
||||
|
||||
for (var subQuestion : questions) {
|
||||
var questionRow = sheet.createRow(row.getRowNum() + count);
|
||||
questionRow.createCell(0).setCellValue(subQuestion.title());
|
||||
|
||||
for (var answer : subQuestion.answers()) {
|
||||
if (!answer.selected()) {
|
||||
continue;
|
||||
}
|
||||
int index = 0;
|
||||
for (int i = 0; i < answerOpts.size(); i++) {
|
||||
if (answer.answer().equalsIgnoreCase(answerOpts.get(i).answer())) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
var cell = questionRow.createCell(1 + index);
|
||||
cell.setCellType(CellType.BOOLEAN);
|
||||
cell.setCellValue(answer.selected());
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.networknt.schema.JsonSchema;
|
||||
import com.networknt.schema.JsonSchemaFactory;
|
||||
import com.networknt.schema.ValidationMessage;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>Copyright: Copyright (c) 2024</p>
|
||||
* <p>Company: heyday Marketing GmbH</p>
|
||||
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
|
||||
* @version 1.0
|
||||
*
|
||||
* created: 20 Feb 2026
|
||||
*/
|
||||
|
||||
public class JsonSchemaValidator {
|
||||
private static final Log LOG = LogFactory.getLog(JsonSchemaValidator.class);
|
||||
|
||||
|
||||
public ValidationReply validate(String schemaPath, String jsonData) {
|
||||
try {
|
||||
JsonSchema schema = getJsonSchema(schemaPath);
|
||||
JsonNode node = getJsonNode(jsonData);
|
||||
Set<ValidationMessage> errors = schema.validate(node);
|
||||
if (!errors.isEmpty()) {
|
||||
LOG.error("Failed to validate json to schema " + schemaPath);
|
||||
errors.forEach(LOG::error);
|
||||
}
|
||||
return new ValidationReply(errors.isEmpty(), errors);
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
return new ValidationReply(false, new HashSet<>());
|
||||
}
|
||||
}
|
||||
|
||||
protected JsonSchema getJsonSchema(String name) throws IOException {
|
||||
JsonSchemaFactory factory = new JsonSchemaFactory();
|
||||
try (InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(name);) {
|
||||
return factory.getSchema(input);
|
||||
}
|
||||
}
|
||||
|
||||
protected JsonNode getJsonNode(String content) throws IOException {
|
||||
return new ObjectMapper().readTree(content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import jakarta.json.*;
|
||||
import jakarta.json.stream.JsonParsingException;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>Copyright: Copyright (c) 2024</p>
|
||||
* <p>Company: heyday Marketing GmbH</p>
|
||||
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
|
||||
* @version 1.0
|
||||
*
|
||||
* created: 20 Feb 2026
|
||||
*/
|
||||
|
||||
public class QuestionnaireJsonParser {
|
||||
private static final Log LOG = LogFactory.getLog(QuestionnaireJsonParser.class);
|
||||
|
||||
private final List<QuestionJsonObj> questions = new ArrayList<>();
|
||||
|
||||
public List<QuestionJsonObj> getQuestions() {
|
||||
return questions;
|
||||
}
|
||||
|
||||
public boolean parse(String body) {
|
||||
questions.clear();
|
||||
if (body == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try (var stringReader = new StringReader(body); JsonReader reader = Json.createReader(stringReader);) {
|
||||
JsonArray root = reader.readArray();
|
||||
|
||||
for (var object : root) {
|
||||
var question = object.asJsonObject();
|
||||
|
||||
String id = question.getString("id");
|
||||
String title = question.getString("title");
|
||||
int order = question.getInt("order");
|
||||
String type = question.getString("type");
|
||||
String data = toData(question.getJsonObject("data"));
|
||||
|
||||
questions.add(new QuestionJsonObj(id, title, order, type, data));
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (IOException | JsonParsingException | NullPointerException ioe) {
|
||||
LOG.warn("Failed to parse json " + ioe.getMessage(), ioe);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private String toData(JsonObject obj) throws IOException {
|
||||
try (StringWriter writer = new StringWriter(); JsonWriter jsonWriter = Json.createWriter(writer);) {
|
||||
|
||||
jsonWriter.writeObject(obj);
|
||||
jsonWriter.close();
|
||||
|
||||
return writer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public record QuestionJsonObj(String id, String title, int order, String type, String data) {
|
||||
|
||||
public List<MatrixQuestion> getMatrixAnswer() {
|
||||
return getValue("questions", () -> null, (questions) -> {
|
||||
var retVal = new ArrayList<MatrixQuestion>();
|
||||
|
||||
for (var question : questions) {
|
||||
var questionObj = question.asJsonObject();
|
||||
var id = questionObj.getString("id");
|
||||
var title = questionObj.getString("title");
|
||||
var order = questionObj.getInt("order");
|
||||
|
||||
var answerList = new ArrayList<MatrixAnswer>();
|
||||
|
||||
var answers = questionObj.getJsonArray("answers");
|
||||
for (var answer : answers) {
|
||||
var answerObj = answer.asJsonObject();
|
||||
var answerId = answerObj.getString("id");
|
||||
var answerStr = answerObj.getString("answer");
|
||||
var selected = answerObj.getBoolean("selected");
|
||||
|
||||
answerList.add(new MatrixAnswer(answerId, answerStr, selected));
|
||||
}
|
||||
retVal.add(new MatrixQuestion(id, title, order, answerList));
|
||||
}
|
||||
return retVal;
|
||||
});
|
||||
}
|
||||
|
||||
public Integer getNumberAnswer() {
|
||||
return getValue(() -> null, (answers) -> {
|
||||
for (var answer : answers) {
|
||||
var answerObj = answer.asJsonObject();
|
||||
if (answerObj.getBoolean("selected")) {
|
||||
return answerObj.getInt("answer");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public String getSingleAnswer() {
|
||||
return getValue(() -> "", (answers) -> {
|
||||
for (var answer : answers) {
|
||||
var answerObj = answer.asJsonObject();
|
||||
if (answerObj.getBoolean("selected")) {
|
||||
return answerObj.getString("answer");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
public List<String> getMultiAnswer() {
|
||||
return getValue(() -> List.of(), (answers) -> {
|
||||
List<String> retVal = new ArrayList<>();
|
||||
for (var answer : answers) {
|
||||
var answerObj = answer.asJsonObject();
|
||||
if (answerObj.getBoolean("selected")) {
|
||||
retVal.add(answerObj.getString("answer"));
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
});
|
||||
}
|
||||
|
||||
public String getFreeText() {
|
||||
return getValue(() -> "", (answers) -> answers.getFirst().asJsonObject().getString("answer"));
|
||||
}
|
||||
|
||||
private <T> T getValue(Supplier<T> emptyValue, Function<JsonArray, T> function) {
|
||||
return getValue("answers", emptyValue, function);
|
||||
}
|
||||
|
||||
private <T> T getValue(String element, Supplier<T> emptyValue, Function<JsonArray, T> function) {
|
||||
try (var stringReader = new StringReader(data); JsonReader reader = Json.createReader(stringReader);) {
|
||||
JsonObject root = reader.readObject();
|
||||
JsonArray answers = root.getJsonArray(element);
|
||||
if (answers.isEmpty()) {
|
||||
return emptyValue.get();
|
||||
}
|
||||
return function.apply(answers);
|
||||
} catch (JsonParsingException | NullPointerException ioe) {
|
||||
LOG.warn("Failed to parse json " + ioe.getMessage(), ioe);
|
||||
return emptyValue.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record MatrixQuestion(String id, String title, int order, List<MatrixAnswer> answers) {
|
||||
|
||||
}
|
||||
|
||||
public record MatrixAnswer(String id, String answer, boolean selected) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import jakarta.json.*;
|
||||
import jakarta.json.stream.JsonParsingException;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>Copyright: Copyright (c) 2024</p>
|
||||
* <p>Company: heyday Marketing GmbH</p>
|
||||
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
|
||||
* @version 1.0
|
||||
*
|
||||
* created: 20 Feb 2026
|
||||
*/
|
||||
|
||||
public record QuestionnaireUploadJsonParser(
|
||||
String username,
|
||||
String pharmacyName,
|
||||
String customerNumber,
|
||||
Date date,
|
||||
String comment,
|
||||
String city,
|
||||
String zip,
|
||||
String questionnair) {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(QuestionnaireUploadJsonParser.class);
|
||||
|
||||
public static Optional<QuestionnaireUploadJsonParser> builder(String body) {
|
||||
if (body == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try (var stringReader = new StringReader(body); JsonReader reader = Json.createReader(stringReader);) {
|
||||
JsonObject root = reader.readObject();
|
||||
|
||||
String username = root.getString("username");
|
||||
String pharmacyName = root.getString("pharmacyName");
|
||||
String customerNumber = root.getString("customerNumber");
|
||||
String dateStr = root.getString("date");
|
||||
|
||||
var dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
|
||||
Date date = dateFormat.parse(dateStr);
|
||||
|
||||
String comment = root.getString("comment");
|
||||
String city = root.getString("city");
|
||||
String zip = root.getString("zip");
|
||||
|
||||
JsonArray questionnaireArr = root.getJsonArray("questionnaire");
|
||||
|
||||
String questionnaire = "";
|
||||
try (StringWriter writer = new StringWriter(); JsonWriter jsonWriter = Json.createWriter(writer);) {
|
||||
|
||||
jsonWriter.writeArray(questionnaireArr);
|
||||
jsonWriter.close();
|
||||
|
||||
questionnaire = writer.toString();
|
||||
}
|
||||
return Optional.of(new QuestionnaireUploadJsonParser(username, pharmacyName, customerNumber, date, comment, city, zip, questionnaire));
|
||||
} catch (IOException | ParseException | JsonParsingException | NullPointerException ioe) {
|
||||
LOG.warn("Failed to parse json " + ioe.getMessage(), ioe );
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.rest.jackson;
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -3,6 +3,7 @@ package marketing.heyday.hartmann.fotodocumentation.rest;
|
||||
import static marketing.heyday.hartmann.fotodocumentation.rest.jackson.ApplicationConfigApi.JSON_OUT;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -73,15 +74,15 @@ public class QuestionnaireCustomerResource {
|
||||
@ApiResponse(responseCode = "200", description = "Successfully retrieved export")
|
||||
public Response doExport(@PathParam("id") Long id, @QueryParam("questionnaire") Long questionnaireId) {
|
||||
LOG.debug("Create export for customer " + id + " with optional param " + questionnaireId);
|
||||
byte[] pdf = questionnaireCustomerService.getExport(id, questionnaireId);
|
||||
Optional<byte[]> pdfOpt = questionnaireCustomerService.getExport(id, questionnaireId);
|
||||
|
||||
if (pdf.length == 0) {
|
||||
if (pdfOpt.isEmpty()) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
StreamingOutput streamingOutput = (OutputStream output) -> {
|
||||
LOG.debug("Start writing content to OutputStream available bytes");
|
||||
output.write(pdf);
|
||||
output.write(pdfOpt.get());
|
||||
};
|
||||
return Response.status(Status.OK).entity(streamingOutput).build();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.rest;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jboss.resteasy.annotations.GZIP;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import jakarta.ejb.EJB;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
@@ -13,8 +21,7 @@ import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.service.QuestionnairePublishService;
|
||||
import marketing.heyday.hartmann.fotodocumentation.rest.jackson.JsonSchemaValidate;
|
||||
import marketing.heyday.hartmann.fotodocumentation.rest.vo.QuestionnairePublishValue;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.utils.JsonSchemaValidator;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,14 +40,28 @@ public class QuestionnairePublishResource {
|
||||
@EJB
|
||||
private QuestionnairePublishService questionnairePublishService;
|
||||
|
||||
@Inject
|
||||
private JsonSchemaValidator jsonSchemaValidator;
|
||||
|
||||
@GZIP
|
||||
@POST
|
||||
@Path("")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Add questionnaire to database")
|
||||
@ApiResponse(responseCode = "200", description = "Add successfull")
|
||||
public Response doAddQuestionnaire(@JsonSchemaValidate("schema/questionnaire_publish.json") QuestionnairePublishValue value) {
|
||||
boolean success = questionnairePublishService.publish(value);
|
||||
return success ? Response.ok().build() : Response.status(Status.BAD_REQUEST).build();
|
||||
public Response doAddQuestionnaire(InputStream inputStream) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
||||
String body = reader.lines().collect(Collectors.joining("\n"));
|
||||
|
||||
var reply = jsonSchemaValidator.validate("schema/questionnaire_publish.json", body);
|
||||
if (!reply.success()) {
|
||||
return Response.status(Status.BAD_REQUEST).entity(reply.errors()).build();
|
||||
}
|
||||
|
||||
questionnairePublishService.publish(body);
|
||||
return Response.ok().build();
|
||||
} catch (IOException e) {
|
||||
return Response.status(Status.BAD_REQUEST).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,10 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.networknt.schema.JsonSchema;
|
||||
import com.networknt.schema.JsonSchemaFactory;
|
||||
import com.networknt.schema.ValidationMessage;
|
||||
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
@@ -27,6 +18,8 @@ import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import jakarta.ws.rs.ext.MessageBodyReader;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.utils.JsonSchemaValidator;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.utils.ValidationReply;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -44,7 +37,6 @@ import jakarta.ws.rs.ext.Provider;
|
||||
MediaType.APPLICATION_JSON, "application/json; charset=utf-8",
|
||||
})
|
||||
public class ValidatedMessageBodyReader implements MessageBodyReader<SchemaValidated> {
|
||||
private static final Log LOG = LogFactory.getLog(ValidatedMessageBodyReader.class);
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see jakarta.ws.rs.ext.MessageBodyReader#isReadable(java.lang.Class, java.lang.reflect.Type, java.lang.annotation.Annotation[], jakarta.ws.rs.core.MediaType)
|
||||
@@ -85,30 +77,7 @@ public class ValidatedMessageBodyReader implements MessageBodyReader<SchemaValid
|
||||
*/
|
||||
private ValidationReply validate(JsonSchemaValidate jsonSchema, String jsonData) {
|
||||
String schemaPath = jsonSchema.value();
|
||||
try {
|
||||
JsonSchema schema = getJsonSchema(schemaPath);
|
||||
JsonNode node = getJsonNode(jsonData);
|
||||
Set<ValidationMessage> errors = schema.validate(node);
|
||||
if (!errors.isEmpty()) {
|
||||
LOG.error("Failed to validate json to schema " + schemaPath);
|
||||
errors.forEach(LOG::error);
|
||||
}
|
||||
return new ValidationReply(errors.isEmpty(), errors);
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
return new ValidationReply(false, new HashSet<>());
|
||||
}
|
||||
}
|
||||
|
||||
protected JsonSchema getJsonSchema(String name) throws IOException {
|
||||
JsonSchemaFactory factory = new JsonSchemaFactory();
|
||||
try (InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(name);) {
|
||||
return factory.getSchema(input);
|
||||
}
|
||||
}
|
||||
|
||||
protected JsonNode getJsonNode(String content) throws IOException {
|
||||
return new ObjectMapper().readTree(content);
|
||||
return new JsonSchemaValidator().validate(schemaPath, jsonData);
|
||||
}
|
||||
|
||||
private String read(InputStream input) throws IOException {
|
||||
|
||||
@@ -1,40 +1,44 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "Add Customer Picture",
|
||||
"description": "Add a Customer Picture to the system",
|
||||
"title": "Publish Questionnaire",
|
||||
"description": "Publish a completed questionnaire to the system",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {
|
||||
"description": "The username from the user who uploads the picture",
|
||||
"description": "The username from the user who submits the questionnaire",
|
||||
"type": "string"
|
||||
},
|
||||
"pharmacyName": {
|
||||
"description": "The Name from the pharmacy customer ",
|
||||
"description": "The name of the pharmacy customer",
|
||||
"type": "string"
|
||||
},
|
||||
"customerNumber": {
|
||||
"description": "The unique number from the pharmacy customer ",
|
||||
"description": "The unique number of the pharmacy customer",
|
||||
"type": "string"
|
||||
},
|
||||
"date": {
|
||||
"description": "The date when the picture is taken ",
|
||||
"description": "The date when the questionnaire was filled in (ISO 8601)",
|
||||
"type": "string"
|
||||
},
|
||||
"comment": {
|
||||
"description": "A free text comment field ",
|
||||
"type": "string"
|
||||
},
|
||||
"zip": {
|
||||
"description": "The zip from the customer",
|
||||
"description": "A free text comment field",
|
||||
"type": "string"
|
||||
},
|
||||
"city": {
|
||||
"description": "The city from the customer",
|
||||
"description": "The city of the customer",
|
||||
"type": "string"
|
||||
},
|
||||
"base64String": {
|
||||
"description": "The Picture content as base64 ",
|
||||
"zip": {
|
||||
"description": "The zip code of the customer",
|
||||
"type": "string"
|
||||
},
|
||||
"questionnaire": {
|
||||
"description": "The list of questions and answers",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/question"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -42,7 +46,118 @@
|
||||
"pharmacyName",
|
||||
"customerNumber",
|
||||
"date",
|
||||
"comment",
|
||||
"base64String"
|
||||
"questionnaire"
|
||||
],
|
||||
"definitions": {
|
||||
"answer": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The unique identifier of the answer",
|
||||
"type": "string"
|
||||
},
|
||||
"answer": {
|
||||
"description": "The answer text",
|
||||
"type": "string"
|
||||
},
|
||||
"selected": {
|
||||
"description": "Whether this answer is selected",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"answer",
|
||||
"selected"
|
||||
]
|
||||
},
|
||||
"matrixSubQuestion": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The unique identifier of the sub-question",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "The title of the sub-question",
|
||||
"type": "string"
|
||||
},
|
||||
"order": {
|
||||
"description": "The display order of the sub-question",
|
||||
"type": "integer"
|
||||
},
|
||||
"answers": {
|
||||
"description": "The list of answers for the sub-question",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/answer"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"order",
|
||||
"answers"
|
||||
]
|
||||
},
|
||||
"questionData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"answers": {
|
||||
"description": "The list of answers (for singleChoice, multiplChoice, number, freeText)",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/answer"
|
||||
}
|
||||
},
|
||||
"questions": {
|
||||
"description": "The list of sub-questions (for matrix type)",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/matrixSubQuestion"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"question": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The unique identifier of the question",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "The title/text of the question",
|
||||
"type": "string"
|
||||
},
|
||||
"order": {
|
||||
"description": "The display order of the question",
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"description": "The type of question",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"singleChoice",
|
||||
"multiplChoice",
|
||||
"number",
|
||||
"freeText",
|
||||
"matrix"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/questionData"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"order",
|
||||
"type",
|
||||
"data"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.model.Questionnaire;
|
||||
import marketing.heyday.hartmann.fotodocumentation.core.model.QuestionnaireCustomer;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>Copyright: Copyright (c) 2024</p>
|
||||
* <p>Company: heyday Marketing GmbH</p>
|
||||
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
|
||||
* @version 1.0
|
||||
*
|
||||
* created: 19 Feb 2026
|
||||
*/
|
||||
class ExcelUtilsTest {
|
||||
private static final Log LOG = LogFactory.getLog(ExcelUtilsTest.class);
|
||||
|
||||
private ExcelUtils excelUtils;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
excelUtils = new ExcelUtils();
|
||||
}
|
||||
|
||||
// --- create: basic output ---
|
||||
|
||||
@Test
|
||||
void create_singleQuestionnaire_returnsPresent() {
|
||||
QuestionnaireCustomer customer = createCustomer("Müller GmbH", "C-001", "Berlin", "10115");
|
||||
Questionnaire questionnaire = createQuestionnaire(new Date(), "What is your rating?");
|
||||
|
||||
Optional<byte[]> result = excelUtils.create(customer, List.of(questionnaire));
|
||||
|
||||
assertTrue(result.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void create_singleQuestionnaire_returnsValidXlsx() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Müller GmbH", "C-001", "Berlin", "10115");
|
||||
Questionnaire questionnaire = createQuestionnaire(new Date(), "What is your rating?");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(questionnaire)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
assertNotNull(workbook);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void create_emptyQuestionnaires_returnsEmptyWorkbook() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Müller GmbH", "C-001", "Berlin", "10115");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, Collections.emptyList()).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
assertEquals(0, workbook.getNumberOfSheets());
|
||||
}
|
||||
}
|
||||
|
||||
// --- create: sheet count ---
|
||||
|
||||
@Test
|
||||
void create_singleQuestionnaire_createsOneSheet() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Müller GmbH", "C-001", "Berlin", "10115");
|
||||
Questionnaire questionnaire = createQuestionnaire(new Date(), "Q1");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(questionnaire)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
assertEquals(1, workbook.getNumberOfSheets());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void create_multipleQuestionnaires_createsSheetPerQuestionnaire() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Müller GmbH", "C-001", "Berlin", "10115");
|
||||
Questionnaire q1 = createQuestionnaire(new Date(), "Q1");
|
||||
Questionnaire q2 = createQuestionnaire(new Date(), "Q2");
|
||||
Questionnaire q3 = createQuestionnaire(new Date(), "Q3");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(q1, q2, q3)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
assertEquals(3, workbook.getNumberOfSheets());
|
||||
}
|
||||
|
||||
writeToFile(bytes, "create_multipleQuestionnaires_createsSheetPerQuestionnaire.xlsx");
|
||||
}
|
||||
|
||||
// --- create: customer data (each field on its own row) ---
|
||||
|
||||
@Test
|
||||
void create_writesCustomerNameInRow0() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Hartmann AG", "C-100", "München", "80331");
|
||||
Questionnaire questionnaire = createQuestionnaire(new Date(), "Q1");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(questionnaire)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
assertEquals("Hartmann AG", workbook.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void create_writesCustomerNumberInRow1() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Hartmann AG", "C-100", "München", "80331");
|
||||
Questionnaire questionnaire = createQuestionnaire(new Date(), "Q1");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(questionnaire)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
assertEquals("C-100", workbook.getSheetAt(0).getRow(1).getCell(0).getStringCellValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void create_writesCustomerCityInRow2() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Hartmann AG", "C-100", "München", "80331");
|
||||
Questionnaire questionnaire = createQuestionnaire(new Date(), "Q1");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(questionnaire)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
assertEquals("München", workbook.getSheetAt(0).getRow(2).getCell(0).getStringCellValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void create_writesCustomerZipInRow3() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Hartmann AG", "C-100", "München", "80331");
|
||||
Questionnaire questionnaire = createQuestionnaire(new Date(), "Q1");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(questionnaire)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
assertEquals("80331", workbook.getSheetAt(0).getRow(3).getCell(0).getStringCellValue());
|
||||
}
|
||||
}
|
||||
|
||||
// --- create: questionnaire date in row 4 ---
|
||||
|
||||
@Test
|
||||
void create_writesQuestionnaireDateInRow4() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Test", "C-001", "Berlin", "10115");
|
||||
Date date = new Date();
|
||||
Questionnaire questionnaire = createQuestionnaire(date, "Q1");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(questionnaire)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
XSSFRow row = workbook.getSheetAt(0).getRow(4);
|
||||
assertEquals(date, row.getCell(0).getDateCellValue());
|
||||
}
|
||||
}
|
||||
|
||||
// --- create: question data in row 7 (after 5 customer rows + 2 blank rows) ---
|
||||
|
||||
@Test
|
||||
void create_writesFirstQuestionTitleInRow7() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Test", "C-001", "Berlin", "10115");
|
||||
Questionnaire questionnaire = createQuestionnaire(new Date(), null);
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(questionnaire)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
XSSFSheet sheet = workbook.getSheetAt(0);
|
||||
// Row 7 should contain the title of the first question from testJson1
|
||||
XSSFRow row = sheet.getRow(7);
|
||||
assertNotNull(row);
|
||||
assertNotNull(row.getCell(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- create: null handling ---
|
||||
|
||||
@Test
|
||||
void create_nullCustomerFields_writesNullsWithoutError() {
|
||||
QuestionnaireCustomer customer = createCustomer(null, null, null, null);
|
||||
Questionnaire questionnaire = createQuestionnaire(null, null);
|
||||
|
||||
Optional<byte[]> result = excelUtils.create(customer, List.of(questionnaire));
|
||||
|
||||
assertTrue(result.isPresent());
|
||||
}
|
||||
|
||||
// --- create: each sheet gets same customer data ---
|
||||
|
||||
@Test
|
||||
void create_multipleSheets_eachSheetHasCustomerData() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Hartmann AG", "C-100", "München", "80331");
|
||||
Questionnaire q1 = createQuestionnaire(new Date(), "Q1");
|
||||
Questionnaire q2 = createQuestionnaire(new Date(), "Q2");
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(q1, q2)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
|
||||
XSSFSheet sheet = workbook.getSheetAt(i);
|
||||
assertEquals("Hartmann AG", sheet.getRow(0).getCell(0).getStringCellValue());
|
||||
assertEquals("C-100", sheet.getRow(1).getCell(0).getStringCellValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void create_multipleSheets_eachSheetHasQuestionData() throws IOException {
|
||||
QuestionnaireCustomer customer = createCustomer("Test", "C-001", "Berlin", "10115");
|
||||
Questionnaire q1 = createQuestionnaire(new Date(), null);
|
||||
Questionnaire q2 = createQuestionnaire(new Date(), null);
|
||||
|
||||
byte[] bytes = excelUtils.create(customer, List.of(q1, q2)).orElseThrow();
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(bytes))) {
|
||||
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
|
||||
XSSFRow row = workbook.getSheetAt(i).getRow(7);
|
||||
assertNotNull(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- helpers ---
|
||||
|
||||
private QuestionnaireCustomer createCustomer(String name, String number, String city, String zip) {
|
||||
return new QuestionnaireCustomer.Builder()
|
||||
.name(name)
|
||||
.customerNumber(number)
|
||||
.city(city)
|
||||
.zip(zip)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Questionnaire createQuestionnaire(Date date, String questions) {
|
||||
return new Questionnaire.Builder()
|
||||
.questionnaireDate(date)
|
||||
.questions(QuestionnaireJsonParserTest.testJson1)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void writeToFile(final byte[] content, final String fileName) {
|
||||
File file = new File("target/test/output/");
|
||||
file.mkdirs();
|
||||
try (FileOutputStream out = new FileOutputStream(new File(file, fileName))) {
|
||||
|
||||
IOUtils.write(content, out);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error saveing pdf file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,7 +332,7 @@ class ImageUtilTest {
|
||||
|
||||
@Test
|
||||
void getExifOrientation_invalidBytes_returns1() {
|
||||
byte[] garbage = new byte[]{0x00, 0x01, 0x02, 0x03};
|
||||
byte[] garbage = new byte[] { 0x00, 0x01, 0x02, 0x03 };
|
||||
|
||||
int orientation = imageUtil.getExifOrientation(garbage);
|
||||
|
||||
@@ -364,7 +364,7 @@ class ImageUtilTest {
|
||||
// --- EXIF orientation with resize ---
|
||||
|
||||
@Test
|
||||
void getImage_size2_rotatedImage_usesEffectiveWidthForResizeDecision() throws IOException {
|
||||
void getImage_size2_rotatedImage_usesEffectiveWidthForResizeDecision() {
|
||||
// A tall image (600x800) with no EXIF won't be resized since width (600) < 1200
|
||||
String base64 = createTestImageBase64(600, 800);
|
||||
byte[] original = Base64.getDecoder().decode(base64);
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>Copyright: Copyright (c) 2024</p>
|
||||
* <p>Company: heyday Marketing GmbH</p>
|
||||
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
|
||||
* @version 1.0
|
||||
*
|
||||
* created: 20 Feb 2026
|
||||
*/
|
||||
|
||||
public class QuestionnaireJsonParserTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testJson1() {
|
||||
var parser = new QuestionnaireJsonParser();
|
||||
boolean retVal = parser.parse(testJson1);
|
||||
assertTrue(retVal);
|
||||
var questions = parser.getQuestions();
|
||||
assertEquals(10, questions.size());
|
||||
}
|
||||
|
||||
|
||||
public static final String testJson1 = """
|
||||
[
|
||||
{
|
||||
"id": "question1",
|
||||
"title": "",
|
||||
"order": 1,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nicht-kaufender Kunde",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Bestandskunde",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question2",
|
||||
"title": "Haben Sie Rezeptpatienten(GKV) für Inko?",
|
||||
"order": 2,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question3",
|
||||
"title": "Warum nicht?",
|
||||
"order": 3,
|
||||
"type": "multiplChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Lagergründe",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Wirtschaftlichkeitsgründe",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Administrativer Aufwand",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Personeller Aufwand",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question4",
|
||||
"title": "Haben Sie Privatrezeptpatienten für inko?",
|
||||
"order": 4,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question5",
|
||||
"title": "Wie viele Patienten versorgen Sie regelmäßig? (Privat) un GKV",
|
||||
"order": 5,
|
||||
"type": "number",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": 47,
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question6",
|
||||
"title": "Mit welchem Herstellern arbeiten Sie zusammen?",
|
||||
"order": 6,
|
||||
"type": "multiplChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "TZMO",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Ontex",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer5",
|
||||
"answer": "Param",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer6",
|
||||
"answer": "Andere",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question7",
|
||||
"title": "Was sind Ihre Gründe für die Zusammenarbeit?",
|
||||
"order": 7,
|
||||
"type": "matrix",
|
||||
"data":
|
||||
{
|
||||
"questions":
|
||||
[
|
||||
{
|
||||
"id": "subq1",
|
||||
"title": "Preis",
|
||||
"order": 1,
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq2",
|
||||
"title": "Einkaufskondition",
|
||||
"order": 2,
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq3",
|
||||
"title": "Qualität",
|
||||
"order": 3,
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question8",
|
||||
"title": "Beziehen Sie Produkte direkt oder über den Großhandel?",
|
||||
"order": 8,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "primär direkt",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "primär Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "ptimär teils. Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "unterschiedlich",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question9",
|
||||
"title": "Gründe für Bezug?",
|
||||
"order": 10,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Umsatzziel mit Händler",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Warenverfügbarkeit/ Liefergeschwindigkeit und Frequent",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Einkaufskondition",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question10",
|
||||
"title": "Weiter/Kommentare Hinweise?",
|
||||
"order": 11,
|
||||
"type": "freeText",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Kommentar eintragen",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
""";
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
package marketing.heyday.hartmann.fotodocumentation.core.utils;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>Copyright: Copyright (c) 2024</p>
|
||||
* <p>Company: heyday Marketing GmbH</p>
|
||||
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
|
||||
* @version 1.0
|
||||
*
|
||||
* created: 20 Feb 2026
|
||||
*/
|
||||
class QuestionnaireUploadJsonParserTest {
|
||||
|
||||
// --- builder: successful parsing ---
|
||||
|
||||
@Test
|
||||
void builder_validJson_returnsPresent() {
|
||||
String json = createValidJson();
|
||||
|
||||
Optional<QuestionnaireUploadJsonParser> result = QuestionnaireUploadJsonParser.builder(json);
|
||||
|
||||
assertTrue(result.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_parsesUsername() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertEquals("verboomp", parser.username());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_parsesPharmacyName() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertEquals("Müller Apotheke", parser.pharmacyName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_parsesCustomerNumber() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertEquals("1234", parser.customerNumber());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_parsesDate() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertNotNull(parser.date());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_parsesComment() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertEquals("Some long text", parser.comment());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_parsesCity() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertEquals("Hannover", parser.city());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_parsesZip() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertEquals("12345", parser.zip());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_parsesQuestionnaireAsJsonString() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertNotNull(parser.questionnair());
|
||||
assertTrue(parser.questionnair().contains("question1"));
|
||||
assertTrue(parser.questionnair().contains("singleChoice"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_validJson_questionnaireContainsAnswers() {
|
||||
String json = createValidJson();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertTrue(parser.questionnair().contains("answer1"));
|
||||
assertTrue(parser.questionnair().contains("Ja"));
|
||||
}
|
||||
|
||||
// --- builder: multiple questions ---
|
||||
|
||||
@Test
|
||||
void builder_multipleQuestions_allQuestionsInOutput() {
|
||||
String json = createJsonWithMultipleQuestions();
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertTrue(parser.questionnair().contains("question1"));
|
||||
assertTrue(parser.questionnair().contains("question2"));
|
||||
}
|
||||
|
||||
// --- builder: invalid input ---
|
||||
|
||||
@Test
|
||||
void builder_invalidJson_returnsEmpty() {
|
||||
String json = "not valid json";
|
||||
|
||||
Optional<QuestionnaireUploadJsonParser> result = QuestionnaireUploadJsonParser.builder(json);
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_emptyObject_returnsEmpty() {
|
||||
String json = "{}";
|
||||
|
||||
Optional<QuestionnaireUploadJsonParser> result = QuestionnaireUploadJsonParser.builder(json);
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_missingRequiredField_returnsEmpty() {
|
||||
String json = """
|
||||
{
|
||||
"username": "verboomp",
|
||||
"pharmacyName": "Test"
|
||||
}""";
|
||||
|
||||
Optional<QuestionnaireUploadJsonParser> result = QuestionnaireUploadJsonParser.builder(json);
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder_invalidDateFormat_returnsEmpty() {
|
||||
String json = """
|
||||
{
|
||||
"username": "verboomp",
|
||||
"pharmacyName": "Test",
|
||||
"customerNumber": "1234",
|
||||
"date": "not-a-date",
|
||||
"comment": "test",
|
||||
"city": "Berlin",
|
||||
"zip": "10115",
|
||||
"questionnaire": [{"id": "q1", "title": "Q", "order": 1, "type": "freeText", "data": {"answers": []}}]
|
||||
}""";
|
||||
|
||||
Optional<QuestionnaireUploadJsonParser> result = QuestionnaireUploadJsonParser.builder(json);
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
// --- builder: special characters ---
|
||||
|
||||
@Test
|
||||
void builder_unicodeCharacters_parsedCorrectly() {
|
||||
String json = createJsonWithValues("user1", "Löwen Apotheke", "5678", "Köln", "50667");
|
||||
|
||||
QuestionnaireUploadJsonParser parser = QuestionnaireUploadJsonParser.builder(json).orElseThrow();
|
||||
|
||||
assertEquals("Löwen Apotheke", parser.pharmacyName());
|
||||
assertEquals("Köln", parser.city());
|
||||
}
|
||||
|
||||
// --- helpers ---
|
||||
|
||||
private String createValidJson() {
|
||||
return """
|
||||
{
|
||||
"username": "verboomp",
|
||||
"pharmacyName": "Müller Apotheke",
|
||||
"customerNumber": "1234",
|
||||
"date": "2026-01-20T11:06:00+01:00",
|
||||
"comment": "Some long text",
|
||||
"city": "Hannover",
|
||||
"zip": "12345",
|
||||
"questionnaire": [
|
||||
{
|
||||
"id": "question1",
|
||||
"title": "Kundentyp",
|
||||
"order": 1,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{"id": "answer1", "answer": "Ja", "selected": true},
|
||||
{"id": "answer2", "answer": "Nein", "selected": false}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}""";
|
||||
}
|
||||
|
||||
private String createJsonWithMultipleQuestions() {
|
||||
return """
|
||||
{
|
||||
"username": "verboomp",
|
||||
"pharmacyName": "Test Apotheke",
|
||||
"customerNumber": "9999",
|
||||
"date": "2026-01-20T11:06:00+01:00",
|
||||
"comment": "comment",
|
||||
"city": "Berlin",
|
||||
"zip": "10115",
|
||||
"questionnaire": [
|
||||
{
|
||||
"id": "question1",
|
||||
"title": "First",
|
||||
"order": 1,
|
||||
"type": "singleChoice",
|
||||
"data": {"answers": [{"id": "a1", "answer": "Yes", "selected": true}]}
|
||||
},
|
||||
{
|
||||
"id": "question2",
|
||||
"title": "Second",
|
||||
"order": 2,
|
||||
"type": "freeText",
|
||||
"data": {"answers": [{"id": "a1", "answer": "Some text", "selected": true}]}
|
||||
}
|
||||
]
|
||||
}""";
|
||||
}
|
||||
|
||||
private String createJsonWithValues(String username, String pharmacyName, String customerNumber, String city, String zip) {
|
||||
return """
|
||||
{
|
||||
"username": "%s",
|
||||
"pharmacyName": "%s",
|
||||
"customerNumber": "%s",
|
||||
"date": "2026-01-20T11:06:00+01:00",
|
||||
"comment": "test",
|
||||
"city": "%s",
|
||||
"zip": "%s",
|
||||
"questionnaire": [
|
||||
{
|
||||
"id": "q1",
|
||||
"title": "Q",
|
||||
"order": 1,
|
||||
"type": "freeText",
|
||||
"data": {"answers": [{"id": "a1", "answer": "text", "selected": true}]}
|
||||
}
|
||||
]
|
||||
}""".formatted(username, pharmacyName, customerNumber, city, zip);
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ public class QuestionnairePublishResourceTest extends AbstractQuestionnaireTest
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
@Disabled // FIXME: enable when implemented
|
||||
public void doAddCustomerdoAddQuestionniare() throws IOException {
|
||||
LOG.info("doAddCustomerdoAddQuestionniare");
|
||||
|
||||
@@ -43,8 +42,8 @@ public class QuestionnairePublishResourceTest extends AbstractQuestionnaireTest
|
||||
assertEquals(5, questionnaireCount());
|
||||
|
||||
String path = deploymentURL + PATH;
|
||||
Request request = Request.Post(path).addHeader("Accept", "application/json; charset=utf-8")
|
||||
.bodyFile(new File(BASE_UPLOAD + "add.json"), ContentType.APPLICATION_JSON);
|
||||
Request request = Request.Post(path)//.addHeader("Accept", "application/json; charset=utf-8")
|
||||
.bodyFile(new File(BASE_UPLOAD + "questionnaire_add.json"), ContentType.APPLICATION_JSON);
|
||||
|
||||
HttpResponse httpResponse = executeRequest(request);
|
||||
int code = httpResponse.getStatusLine().getStatusCode();
|
||||
@@ -56,7 +55,6 @@ public class QuestionnairePublishResourceTest extends AbstractQuestionnaireTest
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
@Disabled // FIXME: enable when implemented
|
||||
public void doAddCustomerWithQuestionnaire() throws IOException {
|
||||
LOG.info("doAddCustomerWithQuestionnaire");
|
||||
|
||||
@@ -65,7 +63,7 @@ public class QuestionnairePublishResourceTest extends AbstractQuestionnaireTest
|
||||
|
||||
String path = deploymentURL + PATH;
|
||||
Request request = Request.Post(path).addHeader("Accept", "application/json; charset=utf-8")
|
||||
.bodyFile(new File(BASE_UPLOAD + "addNewCustomer.json"), ContentType.APPLICATION_JSON);
|
||||
.bodyFile(new File(BASE_UPLOAD + "questionnaire_addNewCustomer.json"), ContentType.APPLICATION_JSON);
|
||||
|
||||
HttpResponse httpResponse = executeRequest(request);
|
||||
int code = httpResponse.getStatusLine().getStatusCode();
|
||||
@@ -77,13 +75,12 @@ public class QuestionnairePublishResourceTest extends AbstractQuestionnaireTest
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
@Disabled // FIXME: enable when implemented
|
||||
public void doAddCustomerWithQuestionnaireWrongJson() throws IOException {
|
||||
LOG.info("doAddCustomerWithQuestionnaireWrongJson");
|
||||
|
||||
String path = deploymentURL + PATH;
|
||||
Request request = Request.Post(path).addHeader("Accept", "application/json; charset=utf-8")
|
||||
.bodyFile(new File(BASE_UPLOAD + "addWrong.json"), ContentType.APPLICATION_JSON);
|
||||
.bodyFile(new File(BASE_UPLOAD + "questionnaire_addWrong.json"), ContentType.APPLICATION_JSON);
|
||||
|
||||
HttpResponse httpResponse = executeRequest(request);
|
||||
int code = httpResponse.getStatusLine().getStatusCode();
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
{
|
||||
"username": "verboomp",
|
||||
"pharmacyName": "Müller Apotheke",
|
||||
"customerNumber": "1234",
|
||||
"date": "2026-01-20T11:06:00+01:00",
|
||||
"comment": "Some long text for Müller Pharmacy",
|
||||
"city": "Hannover",
|
||||
"zip": "12345",
|
||||
"questionnaire": [
|
||||
{
|
||||
"id": "question1",
|
||||
"title": "",
|
||||
"order": 1,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nicht-kaufender Kunde",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Bestandskunde",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question2",
|
||||
"title": "Haben Sie Rezeptpatienten(GKV) für Inko?",
|
||||
"order": 2,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question3",
|
||||
"title": "Warum nicht?",
|
||||
"order": 3,
|
||||
"type": "multiplChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Lagergründe",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Wirtschaftlichkeitsgründe",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Administrativer Aufwand",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Personeller Aufwand",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question4",
|
||||
"title": "Haben Sie Privatrezeptpatienten für inko?",
|
||||
"order": 4,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question5",
|
||||
"title": "Wie viele Patienten versorgen Sie regelmäßig?\n(Privat) un GKV",
|
||||
"order": 5,
|
||||
"type": "number",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "47",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question6",
|
||||
"title": "Mit welchem Herstellern arbeiten Sie zusammen?",
|
||||
"order": 6,
|
||||
"type": "multiplChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "TZMO",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer5",
|
||||
"answer": "Param",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer6",
|
||||
"answer": "Andere",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question7",
|
||||
"title": "Was sind Ihre Gründe für die Zusammenarbeit?",
|
||||
"order": 7,
|
||||
"type": "matrix",
|
||||
"data": {
|
||||
"questions": [
|
||||
{
|
||||
"id": "subq1",
|
||||
"title": "Preis",
|
||||
"order": 1,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq2",
|
||||
"title": "Einkaufskondition",
|
||||
"order": 2,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq3",
|
||||
"title": "Qualität",
|
||||
"order": 3,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question8",
|
||||
"title": "Beziehen Sie Produkte direkt oder über den Großhandel?",
|
||||
"order": 8,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "primär direkt",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "primär Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "ptimär teils. Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "unterschiedlich",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question9",
|
||||
"title": "Gründe für Bezug?",
|
||||
"order": 10,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Umsatzziel mit Händler",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Warenverfügbarkeit/ Liefergeschwindigkeit und Frequent",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Einkaufskondition",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question10",
|
||||
"title": "Weiter/Kommentare Hinweise?",
|
||||
"order": 11,
|
||||
"type": "freeText",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Kommentar eintragen",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
{
|
||||
"username": "verboomp",
|
||||
"pharmacyName": "New Apotheke",
|
||||
"customerNumber": "new_number",
|
||||
"date": "2026-01-20T11:06:00+01:00",
|
||||
"comment": "Some long text for New Pharmacy",
|
||||
"city": "Hannover",
|
||||
"zip": "12345",
|
||||
"questionnaire": [
|
||||
{
|
||||
"id": "question1",
|
||||
"title": "",
|
||||
"order": 1,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nicht-kaufender Kunde",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Bestandskunde",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question2",
|
||||
"title": "Haben Sie Rezeptpatienten(GKV) für Inko?",
|
||||
"order": 2,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question3",
|
||||
"title": "Warum nicht?",
|
||||
"order": 3,
|
||||
"type": "multiplChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Lagergründe",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Wirtschaftlichkeitsgründe",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Administrativer Aufwand",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Personeller Aufwand",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question4",
|
||||
"title": "Haben Sie Privatrezeptpatienten für inko?",
|
||||
"order": 4,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question5",
|
||||
"title": "Wie viele Patienten versorgen Sie regelmäßig?\n(Privat) un GKV",
|
||||
"order": 5,
|
||||
"type": "number",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "47",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question6",
|
||||
"title": "Mit welchem Herstellern arbeiten Sie zusammen?",
|
||||
"order": 6,
|
||||
"type": "multiplChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "TZMO",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer5",
|
||||
"answer": "Param",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer6",
|
||||
"answer": "Andere",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question7",
|
||||
"title": "Was sind Ihre Gründe für die Zusammenarbeit?",
|
||||
"order": 7,
|
||||
"type": "matrix",
|
||||
"data": {
|
||||
"questions": [
|
||||
{
|
||||
"id": "subq1",
|
||||
"title": "Preis",
|
||||
"order": 1,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq2",
|
||||
"title": "Einkaufskondition",
|
||||
"order": 2,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq3",
|
||||
"title": "Qualität",
|
||||
"order": 3,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question8",
|
||||
"title": "Beziehen Sie Produkte direkt oder über den Großhandel?",
|
||||
"order": 8,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "primär direkt",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "primär Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "ptimär teils. Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "unterschiedlich",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question9",
|
||||
"title": "Gründe für Bezug?",
|
||||
"order": 10,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Umsatzziel mit Händler",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Warenverfügbarkeit/ Liefergeschwindigkeit und Frequent",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Einkaufskondition",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question10",
|
||||
"title": "Weiter/Kommentare Hinweise?",
|
||||
"order": 11,
|
||||
"type": "freeText",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Kommentar eintragen",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
{
|
||||
"username": "verboomp",
|
||||
"date": "2026-01-20T11:06:00+01:00",
|
||||
"comment": "Some long text for Müller Pharmacy",
|
||||
"questionnaire": [
|
||||
{
|
||||
"id": "question1",
|
||||
"title": "",
|
||||
"order": 1,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nicht-kaufender Kunde",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Bestandskunde",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question2",
|
||||
"title": "Haben Sie Rezeptpatienten(GKV) für Inko?",
|
||||
"order": 2,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question3",
|
||||
"title": "Warum nicht?",
|
||||
"order": 3,
|
||||
"type": "multiplChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Lagergründe",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Wirtschaftlichkeitsgründe",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Administrativer Aufwand",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Personeller Aufwand",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question4",
|
||||
"title": "Haben Sie Privatrezeptpatienten für inko?",
|
||||
"order": 4,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question5",
|
||||
"title": "Wie viele Patienten versorgen Sie regelmäßig?\n(Privat) un GKV",
|
||||
"order": 5,
|
||||
"type": "number",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "47",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question6",
|
||||
"title": "Mit welchem Herstellern arbeiten Sie zusammen?",
|
||||
"order": 6,
|
||||
"type": "multiplChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "TZMO",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer5",
|
||||
"answer": "Param",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer6",
|
||||
"answer": "Andere",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question7",
|
||||
"title": "Was sind Ihre Gründe für die Zusammenarbeit?",
|
||||
"order": 7,
|
||||
"type": "matrix",
|
||||
"data": {
|
||||
"questions": [
|
||||
{
|
||||
"id": "subq1",
|
||||
"title": "Preis",
|
||||
"order": 1,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq2",
|
||||
"title": "Einkaufskondition",
|
||||
"order": 2,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq3",
|
||||
"title": "Qualität",
|
||||
"order": 3,
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question8",
|
||||
"title": "Beziehen Sie Produkte direkt oder über den Großhandel?",
|
||||
"order": 8,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "primär direkt",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "primär Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "ptimär teils. Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "unterschiedlich",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question9",
|
||||
"title": "Gründe für Bezug?",
|
||||
"order": 10,
|
||||
"type": "singleChoice",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Umsatzziel mit Händler",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Warenverfügbarkeit/ Liefergeschwindigkeit und Frequent",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Einkaufskondition",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question10",
|
||||
"title": "Weiter/Kommentare Hinweise?",
|
||||
"order": 11,
|
||||
"type": "freeText",
|
||||
"data": {
|
||||
"answers": [
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Kommentar eintragen",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -290,12 +290,13 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.5.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.5.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>dom4j</groupId>
|
||||
|
||||
316
question_answer.json
Normal file
316
question_answer.json
Normal file
@@ -0,0 +1,316 @@
|
||||
[
|
||||
{
|
||||
"id": "question1",
|
||||
"title": "",
|
||||
"order": 1,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nicht-kaufender Kunde",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Bestandskunde",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question2",
|
||||
"title": "Haben Sie Rezeptpatienten(GKV) für Inko?",
|
||||
"order": 2,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question3",
|
||||
"title": "Warum nicht?",
|
||||
"order": 3,
|
||||
"type": "multiplChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Lagergründe",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Wirtschaftlichkeitsgründe",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Administrativer Aufwand",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Personeller Aufwand",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question4",
|
||||
"title": "Haben Sie Privatrezeptpatienten für inko?",
|
||||
"order": 4,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Ja",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Nein",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question5",
|
||||
"title": "Wie viele Patienten versorgen Sie regelmäßig?\n(Privat) un GKV",
|
||||
"order": 5,
|
||||
"type": "number",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "47",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question6",
|
||||
"title": "Mit welchem Herstellern arbeiten Sie zusammen?",
|
||||
"order": 6,
|
||||
"type": "multiplChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "TZMO",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer5",
|
||||
"answer": "Param",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer6",
|
||||
"answer": "Andere",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question7",
|
||||
"title": "Was sind Ihre Gründe für die Zusammenarbeit?",
|
||||
"order": 7,
|
||||
"type": "matrix",
|
||||
"data":
|
||||
{
|
||||
"questions":
|
||||
[
|
||||
{
|
||||
"id": "subq1",
|
||||
"title": "Preis",
|
||||
"order": 1,
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq2",
|
||||
"title": "Einkaufskondition",
|
||||
"order": 2,
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "subq3",
|
||||
"title": "Qualität",
|
||||
"order": 3,
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "HARTMANN",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Essity",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Ontex",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question8",
|
||||
"title": "Beziehen Sie Produkte direkt oder über den Großhandel?",
|
||||
"order": 8,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "primär direkt",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "primär Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "ptimär teils. Großhandel",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer4",
|
||||
"answer": "unterschiedlich",
|
||||
"selected": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question9",
|
||||
"title": "Gründe für Bezug?",
|
||||
"order": 10,
|
||||
"type": "singleChoice",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Umsatzziel mit Händler",
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"id": "answer2",
|
||||
"answer": "Warenverfügbarkeit/ Liefergeschwindigkeit und Frequent",
|
||||
"selected": true
|
||||
},
|
||||
{
|
||||
"id": "answer3",
|
||||
"answer": "Einkaufskondition",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "question10",
|
||||
"title": "Weiter/Kommentare Hinweise?",
|
||||
"order": 11,
|
||||
"type": "freeText",
|
||||
"data":
|
||||
{
|
||||
"answers":
|
||||
[
|
||||
{
|
||||
"id": "answer1",
|
||||
"answer": "Kommentar eintragen",
|
||||
"selected": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user