implemented storing of customer settings when sending document

This commit is contained in:
2025-07-17 23:24:57 +02:00
parent 763e5b447b
commit 67cb0b61b6
6 changed files with 55 additions and 32 deletions

View File

@@ -23,6 +23,7 @@ public class UmbrellaException extends Exception{
this.statusCode = statusCode;
}
public UmbrellaException causedBy(Exception e) {
initCause(e);
return this;
@@ -59,4 +60,8 @@ public class UmbrellaException extends Exception{
public int statusCode(){
return statusCode;
}
public static UmbrellaException unprocessable(String message, Object... fills) {
return new UmbrellaException(HTTP_UNPROCESSABLE,message,fills);
}
}

View File

@@ -8,7 +8,7 @@ dependencies{
implementation("de.srsoftware:document.api:2.0.0")
implementation("de.srsoftware:document.file:1.0.1")
implementation("de.srsoftware:document.processor:1.0.3")
implementation("de.srsoftware:document.zugferd:1.0.4")
implementation("de.srsoftware:document.zugferd:1.0.5")
implementation("de.srsoftware:tools.mime:1.1.2")
}

View File

@@ -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,8 +396,6 @@ 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 rendered = source.render(data);
@@ -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);
};
}

View File

@@ -41,6 +41,8 @@ public interface DocumentDb {
Document save(Document document) throws UmbrellaException;
CustomerSettings save(CustomerSettings settings,Document doc) throws UmbrellaException;
CustomerSettings save(long companyId, Type docType, String customerId, CustomerSettings settings) throws UmbrellaException;
/**

View File

@@ -7,6 +7,7 @@ import static de.srsoftware.tools.jdbc.Condition.in;
import static de.srsoftware.tools.jdbc.Query.*;
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException;
import static de.srsoftware.umbrella.documents.Constants.*;
import static de.srsoftware.umbrella.documents.model.Document.DEFAULT_THOUSANDS_SEPARATOR;
@@ -409,6 +410,21 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
}
}
@Override
public CustomerSettings save(CustomerSettings settings, Document doc) throws UmbrellaException {
var companyId = doc.companyId();
var typeId = doc.type().id();
var customerId = doc.customer().id();
try{
replaceInto(TABLE_CUSTOMER_SETTINGS, FIELD_COMPANY_ID, FIELD_DOC_TYPE_ID, FIELD_CUSTOMER_NUMBER, FIELD_DEFAULT_HEADER, FIELD_DEFAULT_FOOTER, FIELD_DEFAULT_MAIL)
.values(companyId, typeId, customerId, settings.header(), settings.footer(), settings.mailText())
.execute(db);
return settings;
} catch (SQLException e){
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to update customer settings");
}
}
@Override
public Document save(Document doc) throws UmbrellaException {
if (doc.isNew()) try {

View File

@@ -67,5 +67,6 @@
</fieldset>
<fieldset>
<legend>{t('actions')}</legend>
<button onclick={() => router.navigate(`/document/${id}/view`)}>{t('abort')}</button>
<button onclick={doSend}>{t('do_send')}</button>
</fieldset>