|
|
|
|
@@ -6,6 +6,7 @@ import static de.srsoftware.document.mustang.Constants.KEY_DATA;
|
|
|
|
|
import static de.srsoftware.document.mustang.Constants.KEY_PDF;
|
|
|
|
|
import static de.srsoftware.document.mustang.Constants.KEY_PRODUCER;
|
|
|
|
|
import static de.srsoftware.document.mustang.Constants.KEY_TEMPLATE;
|
|
|
|
|
import static de.srsoftware.document.zugferd.data.UnitCode.*;
|
|
|
|
|
import static de.srsoftware.tools.MimeType.MIME_FORM_URL;
|
|
|
|
|
import static de.srsoftware.tools.MimeType.MIME_PDF;
|
|
|
|
|
import static de.srsoftware.tools.Optionals.isSet;
|
|
|
|
|
@@ -15,8 +16,7 @@ import static de.srsoftware.umbrella.core.Constants.*;
|
|
|
|
|
import static de.srsoftware.umbrella.core.Paths.LIST;
|
|
|
|
|
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE;
|
|
|
|
|
import static de.srsoftware.umbrella.core.Util.request;
|
|
|
|
|
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden;
|
|
|
|
|
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
|
|
|
|
|
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
|
|
|
|
|
import static de.srsoftware.umbrella.documents.Constants.*;
|
|
|
|
|
import static de.srsoftware.umbrella.documents.model.Document.State.NEW;
|
|
|
|
|
import static de.srsoftware.umbrella.documents.model.Document.State.SENT;
|
|
|
|
|
@@ -202,14 +202,7 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
case LIST -> listCompaniesDocuments(ex,user.get(),token.orElse(null));
|
|
|
|
|
case TEMPLATES -> postTemplateList(ex,user.get());
|
|
|
|
|
case null -> postDocument(ex,user.get());
|
|
|
|
|
default -> {
|
|
|
|
|
var docId = Long.parseLong(head);
|
|
|
|
|
yield switch (path.pop()){
|
|
|
|
|
case null -> postToDocument(ex,path,user.get(),docId);
|
|
|
|
|
case PATH_SEND -> sendDocument(ex,path,user.get(),docId);
|
|
|
|
|
default -> super.doPost(path,ex);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
default -> postToDocument(ex,path,user.get(),Long.parseLong(head));
|
|
|
|
|
};
|
|
|
|
|
} catch (NumberFormatException ignored) {
|
|
|
|
|
return super.doPost(path,ex);
|
|
|
|
|
@@ -225,6 +218,12 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
if (!(json.has(EMAIL) && json.get(EMAIL) instanceof String email)) throw missingFieldException(EMAIL);
|
|
|
|
|
if (!(json.has(SUBJECT) && json.get(SUBJECT) instanceof String subject)) throw missingFieldException(SUBJECT);
|
|
|
|
|
if (!(json.has(CONTENT) && json.get(CONTENT) instanceof String content)) throw missingFieldException(CONTENT);
|
|
|
|
|
var settings = new CustomerSettings(doc.head(),doc.footer(),content);
|
|
|
|
|
try {
|
|
|
|
|
db.save(settings,doc);
|
|
|
|
|
} catch (UmbrellaException e) {
|
|
|
|
|
LOG.log(WARNING,e);
|
|
|
|
|
}
|
|
|
|
|
LOG.log(WARNING,"Updating settings of company-customer-document combination not implemented!");
|
|
|
|
|
var attachment = new Attachment(doc.number()+".pdf",rendered.mimeType(),rendered.bytes());
|
|
|
|
|
var message = new Message(user,subject,content,null,List.of(attachment));
|
|
|
|
|
@@ -297,32 +296,32 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
return val -> message.format(new Object[]{val/100d});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DocumentData convert(Document document) throws Converter.ConversionError {
|
|
|
|
|
private DocumentData convert(Document document) throws UmbrellaException {
|
|
|
|
|
var currency = switch (document.currency()){
|
|
|
|
|
case "€" -> Currency.EUR;
|
|
|
|
|
case "$" -> Currency.USD;
|
|
|
|
|
default -> throw new Converter.ConversionError("Unsupported currency: ",document.currency());
|
|
|
|
|
default -> throw unprocessable("Unsupported currency: ",document.currency());
|
|
|
|
|
};
|
|
|
|
|
var typeCode = switch (document.type().name()){
|
|
|
|
|
case "invoice" -> TypeCode.HANDELSRECHNUNG;
|
|
|
|
|
default -> throw new Converter.ConversionError("Unsupported document type: ",document.type().name());
|
|
|
|
|
default -> throw unprocessable("Unsupported document type: ",document.type().name());
|
|
|
|
|
};
|
|
|
|
|
var countryID = CountryCode.DE;
|
|
|
|
|
LOG.log(WARNING,"countryID is hardcoded to be \"DE\", should be field of company!");
|
|
|
|
|
var sender = document.sender();
|
|
|
|
|
|
|
|
|
|
var match = POST_CODE.matcher(sender.name());
|
|
|
|
|
if (!match.find()) throw new Converter.ConversionError(ERROR_ADDRESS_MISSING, SENDER);
|
|
|
|
|
if (!match.find()) throw unprocessable(ERROR_ADDRESS_MISSING, SENDER);
|
|
|
|
|
var name = match.group(1).trim();
|
|
|
|
|
var streetAddress = match.group(2).trim();
|
|
|
|
|
var postCode = match.group(3);
|
|
|
|
|
var city = match.group(4).trim();
|
|
|
|
|
var taxNumber = sender.taxNumber();
|
|
|
|
|
if (!taxNumber.startsWith("DE")) throw new Converter.ConversionError("Invalid sender tax number ({0})!",taxNumber);
|
|
|
|
|
if (!taxNumber.startsWith("DE")) throw unprocessable("Invalid sender tax number ({0})!",taxNumber);
|
|
|
|
|
var author = new Author(name,countryID,postCode,city,streetAddress,taxNumber);
|
|
|
|
|
|
|
|
|
|
match = POST_CODE.matcher(document.customer().name());
|
|
|
|
|
if (!match.find()) throw new Converter.ConversionError(ERROR_ADDRESS_MISSING,FIELD_CUSTOMER);
|
|
|
|
|
if (!match.find()) throw unprocessable(ERROR_ADDRESS_MISSING,FIELD_CUSTOMER);
|
|
|
|
|
name = escapeHtmlEntities(match.group(1).trim());
|
|
|
|
|
streetAddress = escapeHtmlEntities(match.group(2).trim());
|
|
|
|
|
postCode = match.group(3);
|
|
|
|
|
@@ -338,7 +337,7 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
try {
|
|
|
|
|
deliveryDate = LocalDate.parse(document.delivery());
|
|
|
|
|
} catch (RuntimeException ex) {
|
|
|
|
|
throw new Converter.ConversionError("\"{0}\" is not a valid delivery date (cannot be parsed)!",document.delivery());
|
|
|
|
|
throw unprocessable("\"{0}\" is not a valid delivery date (cannot be parsed)!",document.delivery());
|
|
|
|
|
}
|
|
|
|
|
var lineItems = new ArrayList<LineItem>();
|
|
|
|
|
for (var entry : document.positions().entrySet()){
|
|
|
|
|
@@ -346,11 +345,12 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
var pos = entry.getValue();
|
|
|
|
|
|
|
|
|
|
UnitCode unit = switch (pos.unit()){
|
|
|
|
|
case "jährlich" -> UnitCode.per_year;
|
|
|
|
|
case "pauschal" -> UnitCode.fixed;
|
|
|
|
|
case "h", "Stunden" -> UnitCode.hours;
|
|
|
|
|
case "Stück" -> UnitCode.pieces;
|
|
|
|
|
default -> throw new Converter.ConversionError("No unit code defined for {0}",pos.unit());
|
|
|
|
|
case "d" -> per_day;
|
|
|
|
|
case "h", "Stunden" -> hours;
|
|
|
|
|
case "jährlich" -> per_year;
|
|
|
|
|
case "pauschal" -> fixed;
|
|
|
|
|
case "Stück" -> pieces;
|
|
|
|
|
default -> throw unprocessable("No unit code defined for {0}",pos.unit());
|
|
|
|
|
};
|
|
|
|
|
var percent = pos.tax();
|
|
|
|
|
var taxType = percent == 0 ? TaxType.Z : TaxType.S;
|
|
|
|
|
@@ -384,7 +384,7 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
pdfData.put(USER,user);
|
|
|
|
|
pdfData.put(FIELD_PRICE_FORMAT, priceFormat(document.currency(),user.language()));
|
|
|
|
|
Map<String,Object> data = pdfData;
|
|
|
|
|
if (zugferd) try { // create additional data
|
|
|
|
|
if (zugferd) {// create additional data
|
|
|
|
|
data = Map.of(
|
|
|
|
|
KEY_XML,Map.of(
|
|
|
|
|
KEY_PROFILE,"EN16931",
|
|
|
|
|
@@ -396,10 +396,8 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
),
|
|
|
|
|
KEY_PRODUCER,"SRSoftware Umbrella"
|
|
|
|
|
);
|
|
|
|
|
} catch (Converter.ConversionError e){
|
|
|
|
|
throw new UmbrellaException(500,"Failed to convert data: {0}",e.getMessage()).causedBy(e);
|
|
|
|
|
}
|
|
|
|
|
var source = optDoc.get();
|
|
|
|
|
var source = optDoc.get();
|
|
|
|
|
var rendered = source.render(data);
|
|
|
|
|
if (rendered instanceof RenderError err) throw new UmbrellaException(500,"Failed to render {0}: {1}",source.name(),err.toString());
|
|
|
|
|
if (!(rendered instanceof Content content)) throw new UmbrellaException(500,"Unknown result type ({0}) returned from render process!",rendered.getClass().getSimpleName());
|
|
|
|
|
@@ -409,8 +407,8 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
}
|
|
|
|
|
private boolean getRenderedDocument(HttpExchange ex, long docId, UmbrellaUser user) throws IOException, UmbrellaException {
|
|
|
|
|
var document = getDocumentWithCompanyData(docId,user);
|
|
|
|
|
var content = renderDocument(document,user);
|
|
|
|
|
var headers = ex.getResponseHeaders();
|
|
|
|
|
var content = renderDocument(document,user);
|
|
|
|
|
var headers = ex.getResponseHeaders();
|
|
|
|
|
headers.add(CONTENT_TYPE, MIME_PDF);
|
|
|
|
|
headers.add(CONTENT_DISPOSITION,"attachment; filename=\""+document.number()+".pdf\"");
|
|
|
|
|
return sendContent(ex,content.bytes());
|
|
|
|
|
@@ -418,7 +416,7 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
|
|
|
|
|
private JSONArray getLegacyContacts(HttpExchange ex, UmbrellaUser umbrellaUser, Token token) throws IOException, UmbrellaException {
|
|
|
|
|
var location = config.get("umbrella.modules.contact.baseUrl").map(s -> s+"/json").orElseThrow(() -> new UmbrellaException(500,"umbrella.modules.contact.baseUrl not configured!"));
|
|
|
|
|
var resp = request(location, token.asMap(),MIME_FORM_URL,null);
|
|
|
|
|
var resp = request(location, token.asMap(),MIME_FORM_URL,null);
|
|
|
|
|
if (!(resp instanceof String s && s.startsWith("["))) throw new UmbrellaException(500,"{0} did not return JSON Array!",location);
|
|
|
|
|
return new JSONArray(s);
|
|
|
|
|
}
|
|
|
|
|
@@ -428,10 +426,10 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
var json = json(ex);
|
|
|
|
|
if (!json.has(COMPANY)) throw missingFieldException(COMPANY);
|
|
|
|
|
long companyId = json.getLong(COMPANY);
|
|
|
|
|
var company = companies.get(companyId);
|
|
|
|
|
var company = companies.get(companyId);
|
|
|
|
|
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company);
|
|
|
|
|
var docs = db.listDocs(companyId);
|
|
|
|
|
var map = new HashMap<Long,Object>();
|
|
|
|
|
var map = new HashMap<Long,Object>();
|
|
|
|
|
for (var entry : docs.entrySet()) map.put(entry.getKey(),entry.getValue().summary());
|
|
|
|
|
return sendContent(ex,new JSONObject(map).toString(2));
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
@@ -529,6 +527,7 @@ public class DocumentApi extends BaseHandler {
|
|
|
|
|
var head = path.pop();
|
|
|
|
|
return switch (head){
|
|
|
|
|
case POSITION -> postDocumentPosition(docId,ex,user);
|
|
|
|
|
case PATH_SEND -> sendDocument(ex,path,user,docId);
|
|
|
|
|
case null, default -> super.doPost(path,ex);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|