overhauling constants, working on translations

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2026-01-15 13:58:50 +01:00
parent 669853352e
commit 0d1cdd35d1
103 changed files with 2161 additions and 1207 deletions

View File

@@ -18,7 +18,6 @@ public class Constants {
public static final String CONTACTS = "contacts";
public static final String CUSTOMERS = "customers";
public static final String ERROR_ADDRESS_MISSING = "{0} address does not contain street address / post code / city";
public static final String MOVE = "move";

View File

@@ -11,19 +11,26 @@ import static de.srsoftware.tools.MimeType.MIME_PDF;
import static de.srsoftware.tools.Optionals.isSet;
import static de.srsoftware.tools.Strings.escapeHtmlEntities;
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Field.*;
import static de.srsoftware.umbrella.core.Field.COMPANY;
import static de.srsoftware.umbrella.core.Field.TAX;
import static de.srsoftware.umbrella.core.Field.TYPE;
import static de.srsoftware.umbrella.core.Field.UNIT;
import static de.srsoftware.umbrella.core.Errors.ADDRESS_MISSING;
import static de.srsoftware.umbrella.core.ModuleRegistry.*;
import static de.srsoftware.umbrella.core.Paths.*;
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE;
import static de.srsoftware.umbrella.core.Util.mapValues;
import static de.srsoftware.umbrella.core.constants.Field.*;
import static de.srsoftware.umbrella.core.constants.Field.COMPANY;
import static de.srsoftware.umbrella.core.constants.Field.CUSTOMER;
import static de.srsoftware.umbrella.core.constants.Field.DOCUMENT;
import static de.srsoftware.umbrella.core.constants.Field.NUMBER;
import static de.srsoftware.umbrella.core.constants.Field.SENDER;
import static de.srsoftware.umbrella.core.constants.Field.STATE;
import static de.srsoftware.umbrella.core.constants.Field.TYPE;
import static de.srsoftware.umbrella.core.constants.Field.UNIT;
import static de.srsoftware.umbrella.core.constants.Field.USER;
import static de.srsoftware.umbrella.core.constants.Path.*;
import static de.srsoftware.umbrella.core.constants.Text.*;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static de.srsoftware.umbrella.core.model.Document.State.NEW;
import static de.srsoftware.umbrella.core.model.Document.State.SENT;
import static de.srsoftware.umbrella.core.model.Translatable.t;
import static de.srsoftware.umbrella.documents.Constants.*;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.WARNING;
@@ -45,8 +52,9 @@ import de.srsoftware.document.zugferd.data.Currency;
import de.srsoftware.tools.*;
import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.ModuleRegistry;
import de.srsoftware.umbrella.core.Paths;
import de.srsoftware.umbrella.core.api.*;
import de.srsoftware.umbrella.core.constants.Path;
import de.srsoftware.umbrella.core.constants.Text;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.*;
import de.srsoftware.umbrella.core.model.Customer;
@@ -71,12 +79,12 @@ public class DocumentApi extends BaseHandler implements DocumentService {
public DocumentApi(Configuration config) throws UmbrellaException {
super();
this.config = config;
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE));
db = new SqliteDb(connect(dbFile));
ModuleRegistry.add(this);
Optional<String> templates = config.get(CONFIG_TEMPLATES);
if (templates.isEmpty()) throw missingFieldException(CONFIG_TEMPLATES);
if (templates.isEmpty()) throw missingField(CONFIG_TEMPLATES);
this.registry.add(new DocumentDirectory(new File(templates.get())));
this.registry.add(new TemplateProcessor(), new LatexFactory(), new WeasyFactory(), new ZugferdFactory());
@@ -87,28 +95,28 @@ public class DocumentApi extends BaseHandler implements DocumentService {
var currency = switch (document.currency()){
case "" -> Currency.EUR;
case "$" -> Currency.USD;
default -> throw unprocessable("Unsupported currency: ",document.currency());
default -> throw unprocessable("Unsupported currency: {currency}",CURRENCY,document.currency());
};
var typeCode = switch (document.type().name()){
case "invoice" -> TypeCode.HANDELSRECHNUNG;
default -> throw unprocessable("Unsupported document type: ",document.type().name());
default -> throw unprocessable("Unsupported document type: {type}",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 unprocessable(ERROR_ADDRESS_MISSING, SENDER);
if (!match.find()) throw unprocessable(ADDRESS_MISSING, OBJECT, t(Text.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 unprocessable("Invalid sender tax number ({0})!",taxNumber);
if (!taxNumber.startsWith("DE")) throw unprocessable("Invalid sender tax number ({number})!", NUMBER,taxNumber);
var author = new Author(name,countryID,postCode,city,streetAddress,taxNumber);
match = POST_CODE.matcher(document.customer().name());
if (!match.find()) throw unprocessable(ERROR_ADDRESS_MISSING,CUSTOMER);
if (!match.find()) throw unprocessable(ADDRESS_MISSING, OBJECT,t(Text.CUSTOMER));
name = escapeHtmlEntities(match.group(1).trim());
streetAddress = escapeHtmlEntities(match.group(2).trim());
postCode = match.group(3);
@@ -124,7 +132,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
try {
deliveryDate = LocalDate.parse(document.delivery());
} catch (RuntimeException ex) {
throw unprocessable("\"{0}\" is not a valid delivery date (cannot be parsed)!",document.delivery());
throw unprocessable("\"{date}\" is not a valid delivery date (cannot be parsed)!", DATE,document.delivery());
}
var lineItems = new ArrayList<LineItem>();
for (var entry : document.positions().entrySet()){
@@ -137,7 +145,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
case "jährlich" -> per_year;
case "pauschal" -> fixed;
case "Stück" -> pieces;
default -> throw unprocessable("No unit code defined for {0}",pos.unit());
default -> throw unprocessable("No unit code defined for {unit}",UNIT,pos.unit());
};
var percent = pos.tax();
var taxType = percent == 0 ? TaxType.Z : TaxType.S;
@@ -157,7 +165,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
private boolean deleteDocument(HttpExchange ex, long docId, UmbrellaUser user) throws IOException, UmbrellaException {
var doc = db.loadDoc(docId);
var companyId = doc.companyId();
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId());
if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID, ID,doc.companyId()));
if (doc.state() != NEW) throw new UmbrellaException(HTTP_BAD_REQUEST,"This document has already been sent");
return sendContent(ex,db.deleteDoc(docId));
}
@@ -165,10 +173,10 @@ public class DocumentApi extends BaseHandler implements DocumentService {
private boolean deletePosition(HttpExchange ex, long docId, UmbrellaUser user) throws UmbrellaException, IOException {
var doc = db.loadDoc(docId);
var companyId = doc.companyId();
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId());
if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID, ID,doc.companyId()));
if (doc.state() != NEW) throw new UmbrellaException(HTTP_BAD_REQUEST,"This document has already been sent");
var json = json(ex);
if (!(json.has(POSITION) && json.get(POSITION) instanceof Number number)) throw missingFieldException(POSITION);
if (!(json.has(POSITION) && json.get(POSITION) instanceof Number number)) throw missingField(POSITION);
db.dropPosition(docId,number.longValue());
return send(ex,db.loadDoc(docId).positions());
}
@@ -179,7 +187,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
}
@Override
public boolean doDelete(Path path, HttpExchange ex) throws IOException {
public boolean doDelete(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
@@ -200,7 +208,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
}
@Override
public boolean doGet(Path path, HttpExchange ex) throws IOException {
public boolean doGet(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
@@ -217,7 +225,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
yield switch (head){
case null -> getDocument(ex,docId,user.get());
case PATH_PDF -> getRenderedDocument(ex,docId,user.get());
case Paths.SETTINGS -> getDocumentSettings(ex,docId,user.get());
case Path.SETTINGS -> getDocumentSettings(ex,docId,user.get());
default -> super.doGet(path,ex);
};
}
@@ -230,7 +238,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
}
@Override
public boolean doPatch(Path path, HttpExchange ex) throws IOException {
public boolean doPatch(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
@@ -252,7 +260,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
}
@Override
public boolean doPost(Path path, HttpExchange ex) throws IOException {
public boolean doPost(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
@@ -293,7 +301,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
var doc = db.loadDoc(docId);
var companyId = doc.companyId();
var company = companyService().get(companyId);
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID,ID,company.name()));
return Tuple.of(doc,company);
}
@@ -333,10 +341,10 @@ public class DocumentApi extends BaseHandler implements DocumentService {
private boolean listCompaniesDocuments(HttpExchange ex, UmbrellaUser user) throws UmbrellaException {
try {
var json = json(ex);
if (!json.has(COMPANY)) throw missingFieldException(COMPANY);
if (!json.has(COMPANY)) throw missingField(COMPANY);
long companyId = json.getLong(COMPANY);
var company = companyService().get(companyId);
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company);
if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID,ID,company.name()));
var docs = list(companyId);
var map = new HashMap<Long,Object>();
for (var entry : docs.entrySet()) map.put(entry.getKey(),entry.getValue().summary());
@@ -371,7 +379,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
var optDoc = registry.documents()
.filter(filter)
.findAny();
if (optDoc.isEmpty()) throw UmbrellaException.notFound("Cannot render {0} {1}: Missing template \"{2}\"",type,document.number(),template);
if (optDoc.isEmpty()) throw UmbrellaException.notFound("Cannot render {type} {id}: Missing template \"{template}\"",TYPE,type, ID,document.number(),TEMPLATE,template);
Function<String,String> translate = text -> translator().translate(user.language(),text);
var pdfData = new HashMap<String,Object>();
pdfData.put(DOCUMENT,document.renderToMap());
@@ -427,7 +435,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
try {
docType = db.getType(Integer.parseInt(body(ex)));
} catch (NumberFormatException nfe){
throw UmbrellaException.invalidFieldException(BODY,"document type id");
throw invalidField(BODY,DOCUMENT_TYPE_ID);
}
Document doc = getDocument(docId, user).a;
@@ -458,14 +466,14 @@ public class DocumentApi extends BaseHandler implements DocumentService {
private boolean postDocument(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException {
var json = json(ex);
if (!(json.has(SENDER) && json.get(SENDER) instanceof JSONObject senderData)) throw missingFieldException(SENDER);
if (!senderData.has(COMPANY) || !(senderData.get(COMPANY) instanceof Number rawCompId)) throw missingFieldException(COMPANY);
if (!(json.has(SENDER) && json.get(SENDER) instanceof JSONObject senderData)) throw missingField(SENDER);
if (!senderData.has(COMPANY) || !(senderData.get(COMPANY) instanceof Number rawCompId)) throw missingField(COMPANY);
var companyId = rawCompId.longValue();
var company = companyService().get(companyId);
if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company);
if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID,ID,company.name()));
if (!json.has(CUSTOMER) || !(json.get(CUSTOMER) instanceof JSONObject customerData)) throw missingFieldException(CUSTOMER);
if (!json.has(TYPE) || !(json.get(TYPE) instanceof Number docTypeId)) throw missingFieldException(TYPE);
if (!json.has(CUSTOMER) || !(json.get(CUSTOMER) instanceof JSONObject customerData)) throw missingField(CUSTOMER);
if (!json.has(TYPE) || !(json.get(TYPE) instanceof Number docTypeId)) throw missingField(TYPE);
var type = db.getType(docTypeId.intValue());
var customer = Customer.of(customerData);
String currency = company.currency();
@@ -495,11 +503,11 @@ public class DocumentApi extends BaseHandler implements DocumentService {
var doc = getDocument(docId,user).a;
var json = json(ex);
if (!(json.has(AMOUNT) && json.get(AMOUNT) instanceof Number amount)) throw missingFieldException(AMOUNT);
if (!(json.has(DESCRIPTION) && json.get(DESCRIPTION) instanceof String description)) throw missingFieldException(DESCRIPTION);
if (!(json.has(ITEM_CODE) && json.get(ITEM_CODE) instanceof String itemCode)) throw missingFieldException(ITEM_CODE);
if (!(json.has(TITLE) && json.get(TITLE) instanceof String title)) throw missingFieldException(TITLE);
if (!(json.has(UNIT) && json.get(UNIT) instanceof String unit)) throw missingFieldException(UNIT);
if (!(json.has(AMOUNT) && json.get(AMOUNT) instanceof Number amount)) throw missingField(AMOUNT);
if (!(json.has(DESCRIPTION) && json.get(DESCRIPTION) instanceof String description)) throw missingField(DESCRIPTION);
if (!(json.has(ITEM_CODE) && json.get(ITEM_CODE) instanceof String itemCode)) throw missingField(ITEM_CODE);
if (!(json.has(TITLE) && json.get(TITLE) instanceof String title)) throw missingField(TITLE);
if (!(json.has(UNIT) && json.get(UNIT) instanceof String unit)) throw missingField(UNIT);
var unitPrice = json.has(UNIT_PRICE) && json.get(UNIT_PRICE) instanceof Number num ? num : 0L;
try {
unitPrice = db.getCustomerPrice(doc.companyId(),doc.customer().id(),itemCode);
@@ -514,9 +522,9 @@ public class DocumentApi extends BaseHandler implements DocumentService {
private boolean postTemplateList(HttpExchange ex, UmbrellaUser user) throws UmbrellaException, IOException {
var json = json(ex);
if (!(json.has(COMPANY) && json.get(COMPANY) instanceof Number companyId)) throw missingFieldException(COMPANY);
if (!(json.has(COMPANY) && json.get(COMPANY) instanceof Number companyId)) throw missingField(COMPANY);
var company = companyService().get(companyId.longValue());
if (!companyService().membership(companyId.longValue(),user.id())) throw forbidden("You are not a member of {0}",company.name());
if (!companyService().membership(companyId.longValue(),user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID,ID,company.name()));
var templates = registry.documents()
.filter(d -> d.name().endsWith(".template"))
.map(d -> d.name().replaceAll("(\\.[^.]+)?\\.template$",""));
@@ -525,7 +533,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
private boolean postSearch(HttpExchange ex, UmbrellaUser user) throws IOException {
var json = json(ex);
if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY);
if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingField(KEY);
var keys = Arrays.asList(key.split(" "));
var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val;
@@ -535,7 +543,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
return sendContent(ex,mapValues(documents));
}
private boolean postToDocument(HttpExchange ex, Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException {
private boolean postToDocument(HttpExchange ex, de.srsoftware.tools.Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException {
var head = path.pop();
return switch (head){
case CLONE -> postCloneDoc(docId,ex,user);
@@ -554,13 +562,13 @@ public class DocumentApi extends BaseHandler implements DocumentService {
return val -> message.format(new Object[]{val/100d});
}
private boolean sendDocument(HttpExchange ex, Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException {
private boolean sendDocument(HttpExchange ex, de.srsoftware.tools.Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException {
var doc = getDocumentWithCompanyData(docId,user);
var rendered = renderDocument(doc,user);
var json = json(ex);
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);
if (!(json.has(EMAIL) && json.get(EMAIL) instanceof String email)) throw missingField(EMAIL);
if (!(json.has(SUBJECT) && json.get(SUBJECT) instanceof String subject)) throw missingField(SUBJECT);
if (!(json.has(CONTENT) && json.get(CONTENT) instanceof String content)) throw missingField(CONTENT);
var settings = new CustomerSettings(doc.head(),doc.footer(),content);
try {
db.save(settings,doc);

View File

@@ -5,25 +5,29 @@ package de.srsoftware.umbrella.documents;
import static de.srsoftware.tools.jdbc.Condition.*;
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.Errors.*;
import static de.srsoftware.umbrella.core.Field.*;
import static de.srsoftware.umbrella.core.Field.COMPANY_ID;
import static de.srsoftware.umbrella.core.Field.TAX;
import static de.srsoftware.umbrella.core.Field.UNIT;
import static de.srsoftware.umbrella.core.ModuleRegistry.translator;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.notFound;
import static de.srsoftware.umbrella.core.constants.Constants.FALLBACK_LANG;
import static de.srsoftware.umbrella.core.constants.Field.*;
import static de.srsoftware.umbrella.core.constants.Field.COMPANY;
import static de.srsoftware.umbrella.core.constants.Field.CUSTOMER;
import static de.srsoftware.umbrella.core.constants.Field.NUMBER;
import static de.srsoftware.umbrella.core.constants.Field.SENDER;
import static de.srsoftware.umbrella.core.constants.Field.TYPE;
import static de.srsoftware.umbrella.core.constants.Field.UNIT;
import static de.srsoftware.umbrella.core.constants.Text.*;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static de.srsoftware.umbrella.core.model.Document.DEFAULT_THOUSANDS_SEPARATOR;
import static de.srsoftware.umbrella.core.model.Document.State;
import static de.srsoftware.umbrella.core.model.Translatable.t;
import static de.srsoftware.umbrella.documents.Constants.*;
import static java.lang.System.Logger.Level.*;
import static java.text.MessageFormat.format;
import static java.time.ZoneOffset.UTC;
import de.srsoftware.tools.Pair;
import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.BaseDb;
import de.srsoftware.umbrella.core.constants.Text;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.*;
import de.srsoftware.umbrella.documents.model.*;
@@ -49,7 +53,7 @@ public class SqliteDb extends BaseDb implements DocumentDb{
var sql = format("ALTER TABLE {0} ADD COLUMN {1} VARCHAR(255)",TABLE_DOCUMENTS,TEMPLATE);
db.prepareStatement(sql).execute();
} catch (SQLException e) {
throw databaseException(FAILED_TO_UPDATE_COLUMN,TEMPLATE_ID,TEMPLATE,TABLE_DOCUMENTS).causedBy(e);
throw databaseException(FAILED_TO_UPDATE_COLUMN,"old",TEMPLATE_ID,"new",TEMPLATE, TABLE,TABLE_DOCUMENTS).causedBy(e);
}
}
@@ -79,7 +83,7 @@ public class SqliteDb extends BaseDb implements DocumentDb{
stmt.execute();
stmt.close();
} catch (SQLException e) {
throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_PRICES).causedBy(e);
throw failedToCreateTable(TABLE_PRICES).causedBy(e);
}
}
@@ -90,7 +94,7 @@ public class SqliteDb extends BaseDb implements DocumentDb{
stmt.execute();
stmt.close();
} catch (SQLException e) {
throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_CUSTOMER_SETTINGS).causedBy(e);
throw failedToCreateTable(TABLE_CUSTOMER_SETTINGS).causedBy(e);
}
}
@@ -118,13 +122,13 @@ CREATE TABLE IF NOT EXISTS {0} (
{18} VARCHAR(255),
{19} VARCHAR(255)
)""";
createTable = format(createTable,TABLE_DOCUMENTS, ID, TYPE_ID, COMPANY_ID, NUMBER, DATE, STATE, TEMPLATE_ID, DELIVERY_DATE,HEAD,FOOTER,CURRENCY, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,CUSTOMER_EMAIL);
createTable = format(createTable,TABLE_DOCUMENTS, ID, TYPE_ID, COMPANY_ID, NUMBER, DATE, STATE, TEMPLATE_ID, DELIVERY_DATE,HEAD,FOOTER,CURRENCY, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT, CUSTOMER,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,CUSTOMER_EMAIL);
try {
var stmt = db.prepareStatement(createTable);
stmt.execute();
stmt.close();
} catch (SQLException e) {
throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_DOCUMENTS).causedBy(e);
throw failedToCreateTable(TABLE_DOCUMENTS).causedBy(e);
}
}
@@ -134,14 +138,14 @@ CREATE TABLE IF NOT EXISTS {0} (
var stmt = db.prepareStatement(format(createTable,TABLE_DOCUMENT_TYPES, ID,NEXT_TYPE, NAME));
stmt.execute();
stmt.close();
insertInto(TABLE_DOCUMENT_TYPES,ID,NEXT_TYPE,NAME)
insertInto(TABLE_DOCUMENT_TYPES, ID,NEXT_TYPE, NAME)
.values(1,2,TYPE_OFFER)
.values(2,3,TYPE_CONFIRMATION)
.values(3,4,TYPE_INVOICE)
.values(4,4,TYPE_REMINDER)
.execute(db);
} catch (SQLException e) {
throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_DOCUMENT_TYPES).causedBy(e);
throw failedToCreateTable(TABLE_DOCUMENT_TYPES).causedBy(e);
}
}
@@ -167,7 +171,7 @@ CREATE TABLE IF NOT EXISTS {0} (
stmt.execute();
stmt.close();
} catch (SQLException e) {
throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_POSITIONS).causedBy(e);
throw failedToCreateTable(TABLE_POSITIONS).causedBy(e);
}
}
@@ -178,7 +182,7 @@ CREATE TABLE IF NOT EXISTS {0} (
stmt.execute();
stmt.close();
} catch (SQLException e) {
throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_TEMPLATES).causedBy(e);
throw failedToCreateTable(TABLE_TEMPLATES).causedBy(e);
}
}
@@ -194,9 +198,9 @@ CREATE TABLE IF NOT EXISTS {0} (
delete().from(TABLE_DOCUMENTS).where(ID,equal(docId)).execute(db);
db.setAutoCommit(true);
if (number != null) return number;
throw databaseException(FAILED_TO_DROP_ENTITY,"document",docId);
throw failedToDropObject(t(DOCUMENT_WITH_ID, ID,docId));
} catch (SQLException e){
throw databaseException(FAILED_TO_DROP_ENTITY,"document",docId).causedBy(e);
throw failedToDropObject(t(DOCUMENT_WITH_ID, ID,docId)).causedBy(e);
}
}
@@ -214,7 +218,7 @@ CREATE TABLE IF NOT EXISTS {0} (
db.setAutoCommit(true);
return pos;
} catch (SQLException e) {
throw databaseException(FAILED_TO_DROP_ENTITY_OF_ENTITY,"position",pos,"document",docId).causedBy(e);
throw failedToDropObjectFromObject(POSITION,pos,t(Text.DOCUMENT),docId).causedBy(e);
}
}
@@ -224,7 +228,7 @@ CREATE TABLE IF NOT EXISTS {0} (
var sql = format("ALTER TABLE {0} DROP COLUMN {1}",TABLE_DOCUMENTS,TEMPLATE_ID);
db.prepareStatement(sql).execute();
} catch (SQLException e) {
throw databaseException(FAILED_TO_UPDATE_COLUMN,TEMPLATE_ID,TEMPLATE,TABLE_DOCUMENTS).causedBy(e);
throw databaseException(FAILED_TO_UPDATE_COLUMN,"old",TEMPLATE_ID,"new",TEMPLATE, TABLE,TABLE_DOCUMENTS).causedBy(e);
}
}
@@ -233,7 +237,7 @@ CREATE TABLE IF NOT EXISTS {0} (
var sql = format("DROP TABLE IF EXISTS {0};",TABLE_TEMPLATES);
db.prepareStatement(sql).execute();
} catch (SQLException e) {
throw databaseException(FAILED_TO_DROP_ENTITY,"table",TABLE_TEMPLATES).causedBy(e);
throw failedToDropObject(t(TABLE_WITH_NAME,NAME,TABLE_TEMPLATES)).causedBy(e);
}
}
@@ -245,9 +249,9 @@ CREATE TABLE IF NOT EXISTS {0} (
if (rs.next()) price = rs.getLong(PRICE);
rs.close();
if (price != null) return price;
throw notFound(FAILED_TO_LOAD_CUSTOMER_PRICE,company,customer,itemCode);
throw notFound(FAILED_TO_LOAD_CUSTOMER_PRICE,COMPANY,company, CUSTOMER,customer,t(Text.ITEM),itemCode);
} catch (SQLException e) {
throw databaseException(FAILED_TO_LOAD_CUSTOMER_PRICE,company,customer,itemCode).causedBy(e);
throw databaseException(FAILED_TO_LOAD_CUSTOMER_PRICE,COMPANY,company, CUSTOMER,customer,t(Text.ITEM),itemCode).causedBy(e);
}
}
@@ -260,7 +264,7 @@ CREATE TABLE IF NOT EXISTS {0} (
rs.close();
return settings;
} catch (SQLException e) {
throw databaseException(FAILED_TO_LOAD_CUSTOMER_SETTINGS,companyId, docType.name()).causedBy(e);
throw databaseException(FAILED_TO_LOAD_CUSTOMER_SETTINGS,COMPANY,companyId,TYPE, docType.name()).causedBy(e);
}
}
@@ -272,9 +276,9 @@ CREATE TABLE IF NOT EXISTS {0} (
if (rs.next()) type = toType(rs);
rs.close();
if (type != null) return type;
throw notFound(FAILED_TO_LOAD_ENTITY_BY_ID,"type",typeId);
throw notFound(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT, Text.TYPE, ID,typeId);
} catch (SQLException e) {
throw databaseException(FAILED_TO_LOAD_ENTITY_BY_ID,"type",typeId).causedBy(e);
throw databaseException(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT, Text.TYPE, ID,typeId).causedBy(e);
}
}
@@ -283,7 +287,7 @@ CREATE TABLE IF NOT EXISTS {0} (
public Map<Long, Map<Long, String>> docReferencedByTimes(Set<Long> timeIds) throws UmbrellaException {
try {
var map = new HashMap<Long, Map<Long, String>>(); // Map ( timeId → Map ( docId → name ))
var rs = select(TIME_ID,DOCUMENT_ID,NUMBER).from(TABLE_POSITIONS).leftJoin(DOCUMENT_ID,TABLE_DOCUMENTS,ID).where(TIME_ID,in(timeIds.toArray())).exec(db);
var rs = select(TIME_ID,DOCUMENT_ID, NUMBER).from(TABLE_POSITIONS).leftJoin(DOCUMENT_ID,TABLE_DOCUMENTS, ID).where(TIME_ID,in(timeIds.toArray())).exec(db);
while (rs.next()) {
var timeId = rs.getLong(TIME_ID);
var docId = rs.getLong(DOCUMENT_ID);
@@ -293,7 +297,7 @@ CREATE TABLE IF NOT EXISTS {0} (
rs.close();
return map;
} catch (SQLException e) {
throw databaseException(FAILED_TO_LIST_ENTITIES,"documents").causedBy(e);
throw databaseException(FAILED_TO_LIST_ENTITIES,TYPE, t(Text.DOCUMENTS)).causedBy(e);
}
}
@@ -307,9 +311,9 @@ CREATE TABLE IF NOT EXISTS {0} (
var query = Query.select(ALL).from(TABLE_DOCUMENTS).where(COMPANY_ID,in(companyIds.toArray()));
if (fulltext) {
for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4},\" \",{5},\" \",{6},\" \",{7},\" \",{8},\" \",{9})",NUMBER,HEAD,FOOTER,SENDER,TAX_NUMBER,BANK_ACCOUNT,CUSTOMER,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,CUSTOMER_EMAIL),like("%"+key+"%"));
for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4},\" \",{5},\" \",{6},\" \",{7},\" \",{8},\" \",{9})", NUMBER,HEAD,FOOTER, SENDER,TAX_NUMBER,BANK_ACCOUNT, CUSTOMER,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,CUSTOMER_EMAIL),like("%"+key+"%"));
} else {
for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4})",NUMBER,HEAD,FOOTER,SENDER,CUSTOMER),like("%"+key+"%"));
for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4})", NUMBER,HEAD,FOOTER, SENDER, CUSTOMER),like("%"+key+"%"));
}
rs = query.exec(db);
var map = new HashMap<Long,Document>();
@@ -318,8 +322,8 @@ CREATE TABLE IF NOT EXISTS {0} (
if (fulltext){
var additionalDocIds = new HashSet<Long>();
query = select(DOCUMENT_ID).from(TABLE_POSITIONS).leftJoin(DOCUMENT_ID,TABLE_DOCUMENTS,ID).where(COMPANY_ID,in(companyIds.toArray()));
for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3})",ITEM_CODE,UNIT,TITLE,DESCRIPTION),like("%"+key+"%"));
query = select(DOCUMENT_ID).from(TABLE_POSITIONS).leftJoin(DOCUMENT_ID,TABLE_DOCUMENTS, ID).where(COMPANY_ID,in(companyIds.toArray()));
for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3})",ITEM_CODE,UNIT,TITLE, DESCRIPTION),like("%"+key+"%"));
rs = query.exec(db);
while (rs.next()) additionalDocIds.add(rs.getLong(DOCUMENT_ID));
rs.close();
@@ -342,7 +346,7 @@ CREATE TABLE IF NOT EXISTS {0} (
rs.close();
return map;
} catch (SQLException e) {
throw databaseException(FAILED_TO_SEARCH_DB,"documents").causedBy(e);
throw failedToSearchDb(t(Text.DOCUMENTS)).causedBy(e);
}
}
@@ -369,7 +373,7 @@ CREATE TABLE IF NOT EXISTS {0} (
rs.close();
return map;
} catch (SQLException e) {
throw databaseException(FAILED_TO_LIST_ENTITIES,"documents").causedBy(e);
throw databaseException(FAILED_TO_LIST_ENTITIES,TYPE,t(Text.DOCUMENTS)).causedBy(e);
}
}
@@ -382,7 +386,7 @@ CREATE TABLE IF NOT EXISTS {0} (
rs.close();
return types;
} catch (SQLException e) {
throw databaseException(FAILED_TO_LIST_ENTITIES,"document types").causedBy(e);
throw databaseException(FAILED_TO_LIST_ENTITIES,TYPE,"document types").causedBy(e);
}
}
@@ -410,9 +414,9 @@ CREATE TABLE IF NOT EXISTS {0} (
rs.close();
return doc;
}
throw notFound(FAILED_TO_LOAD_ENTITY_BY_ID,"document",docId);
throw notFound(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT,t(Text.DOCUMENT), ID,docId);
} catch (SQLException e) {
throw databaseException(FAILED_TO_LOAD_ENTITY_BY_ID,"document",docId).causedBy(e);
throw failedToLoadObject(t(Text.DOCUMENT),docId).causedBy(e);
}
}
@@ -422,14 +426,14 @@ CREATE TABLE IF NOT EXISTS {0} (
var sql = format("UPDATE {0} SET template = (SELECT name FROM templates WHERE templates.id = documents.template_id);",TABLE_DOCUMENTS);
db.prepareStatement(sql).execute();
} catch (SQLException e) {
throw databaseException(FAILED_TO_MOVE,"template.names","document.templates").causedBy(e);
throw databaseException(FAILED_TO_MOVE,"old","template.names","new","document.templates").causedBy(e);
}
}
@Override
public String nextDocId(String language, long companyId, Type type) {
try {
var rs = select(NUMBER).from(TABLE_DOCUMENTS).where(COMPANY_ID,equal(companyId)).where(TYPE_ID,equal(type.id())).sort(ID+" DESC").limit(1).exec(db);
var rs = select(NUMBER).from(TABLE_DOCUMENTS).where(COMPANY_ID,equal(companyId)).where(TYPE_ID,equal(type.id())).sort(ID +" DESC").limit(1).exec(db);
String lastId = null;
if (rs.next()) lastId = rs.getString(1);
rs.close();
@@ -463,7 +467,7 @@ CREATE TABLE IF NOT EXISTS {0} (
.execute(db);
return settings;
} catch (SQLException e){
throw databaseException(FAILED_TO_UPDATE_ENTITY,"customer settings").causedBy(e);
throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT,t(CUSTOMER_SETTINGS)).causedBy(e);
}
}
@@ -473,7 +477,7 @@ CREATE TABLE IF NOT EXISTS {0} (
var timestamp = doc.date().atStartOfDay(UTC).toInstant().getEpochSecond();
var sender = doc.sender();
var custom = doc.customer();
var stmt = insertInto(TABLE_DOCUMENTS,TYPE_ID,COMPANY_ID, DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE,CURRENCY)
var stmt = insertInto(TABLE_DOCUMENTS,TYPE_ID,COMPANY_ID, DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT, CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE,CURRENCY)
.values(doc.type().id(),doc.companyId(),timestamp,doc.delivery(),doc.footer(),doc.head(),doc.number(),doc.state().code(),sender.name(),sender.taxNumber(),sender.bankAccount(),sender.court(),custom.name(),custom.email(),custom.id(),custom.taxNumber(),doc.template(), doc.currency())
.execute(db);
var rs = stmt.getGeneratedKeys();
@@ -485,10 +489,10 @@ CREATE TABLE IF NOT EXISTS {0} (
sender.clean();
custom.clean();
doc.clean();
if (newId == null) throw databaseException(FAILED_TO_STORE_ENTITY,"document");
if (newId == null) throw failedToStoreObject(doc);
return loadDoc(newId);
} catch (Exception e) {
throw databaseException(FAILED_TO_UPDATE_ENTITY,"document",doc.number()).causedBy(e);
throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT, t(DOCUMENT_WITH_ID,ID,doc.number())).causedBy(e);
}
if (doc.isDirty()) try {
@@ -496,7 +500,7 @@ CREATE TABLE IF NOT EXISTS {0} (
var sender = doc.sender();
var custom = doc.customer();
update(TABLE_DOCUMENTS)
.set(DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE)
.set(DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT, CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE)
.where(ID,equal(doc.id()))
.prepare(db)
.apply(timestamp,doc.delivery(),doc.footer(),doc.head(),doc.number(),doc.state().code(),sender.name(),sender.taxNumber(),sender.bankAccount(),sender.court(),custom.name(),custom.email(),custom.id(),custom.taxNumber(),doc.template())
@@ -505,7 +509,7 @@ CREATE TABLE IF NOT EXISTS {0} (
custom.clean();
doc.clean();
} catch (Exception e) {
throw databaseException(FAILED_TO_UPDATE_ENTITY,"document").causedBy(e);
throw databaseException(FAILED_TO_UPDATE_OBJECT,doc).causedBy(e);
}
if (doc.positions().isDirty()) try {
@@ -532,7 +536,7 @@ CREATE TABLE IF NOT EXISTS {0} (
}
}
} catch (Exception e) {
throw databaseException(FAILED_TO_STORE_ENTITY,"positions of document").causedBy(e);
throw failedToStoreObject(t("positions of document")).causedBy(e);
}
return doc;
}
@@ -547,7 +551,7 @@ CREATE TABLE IF NOT EXISTS {0} (
.close();
return settings;
} catch (SQLException e){
throw databaseException(FAILED_TO_UPDATE_ENTITY,"customer settings").causedBy(e);
throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT, t(CUSTOMER_SETTINGS)).causedBy(e);
}
}
@@ -565,7 +569,7 @@ CREATE TABLE IF NOT EXISTS {0} (
.set(PRICE).prepare(db).apply(price).close();
}
} catch (SQLException e) {
throw databaseException(FAILED_TO_STORE_ENTITY,"customer_price").causedBy(e);
throw failedToStoreObject(t("customer price")).causedBy(e);
}
}
@@ -578,7 +582,7 @@ CREATE TABLE IF NOT EXISTS {0} (
update(TABLE_POSITIONS).set(POS).where(DOCUMENT_ID,equal(docId)).where(POS,equal(-pair.right())).prepare(db).apply(pair.right()).close();
db.setAutoCommit(true);
} catch (SQLException e) {
throw databaseException(FAILED_TO_SWITCH_POSITIONS,pair.left(),pair.right(),docId).causedBy(e);
throw databaseException(FAILED_TO_SWITCH_POSITIONS,"a",pair.left(),"b",pair.right(),docId).causedBy(e);
}
return pair;
}
@@ -605,7 +609,7 @@ CREATE TABLE IF NOT EXISTS {0} (
var customerId = rs.getString(CUSTOMER_NUMBER);
var customerTaxNumber = rs.getString(CUSTOMER_TAX_NUMBER);
var customerEmail = rs.getString(CUSTOMER_EMAIL);
var customer = new Customer(customerId, customerName, customerEmail, customerTaxNumber,FALLBACK_LANG);
var customer = new Customer(customerId, customerName, customerEmail, customerTaxNumber, FALLBACK_LANG);
var sender = new Sender(senderName,bankAccount,taxNumber,court);
var template = rs.getString(TEMPLATE);
return new Document(id,company,number,type,date, Document.State.of(state).orElse(State.ERROR),template,delivery,head,footer,currency, DEFAULT_THOUSANDS_SEPARATOR,sender,customer,new PositionList());

View File

@@ -2,9 +2,9 @@
package de.srsoftware.umbrella.documents;
import static de.srsoftware.tools.MimeType.*;
import static de.srsoftware.umbrella.core.Constants.ERROR_MISSING_FIELD;
import static de.srsoftware.umbrella.core.Constants.USER;
import static de.srsoftware.umbrella.core.Field.PRICE_FORMAT;
import static de.srsoftware.umbrella.core.Errors.MISSING_FIELD;
import static de.srsoftware.umbrella.core.constants.Field.PRICE_FORMAT;
import static de.srsoftware.umbrella.core.constants.Field.USER;
import static java.lang.System.Logger.Level.TRACE;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.text.MessageFormat.format;
@@ -55,7 +55,7 @@ public abstract class TemplateDoc implements Document {
@Override
public RenderResult render(Map<String, Object> data) {
data = new HashMap<>(data);
if (!(data.get(PRICE_FORMAT) instanceof PriceFormat price)) return RenderError.of(ERROR_MISSING_FIELD,PRICE_FORMAT);
if (!(data.get(PRICE_FORMAT) instanceof PriceFormat price)) return RenderError.of(MISSING_FIELD,PRICE_FORMAT);
if (data.get(USER) instanceof UmbrellaUser user) data.put(USER,user.toMap());
var precursor = source().render(data);
if (precursor instanceof Content content){

View File

@@ -2,8 +2,7 @@
package de.srsoftware.umbrella.documents.model;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Field.*;
import static de.srsoftware.umbrella.core.constants.Field.*;
import de.srsoftware.tools.Mappable;
import java.sql.ResultSet;
@@ -56,7 +55,7 @@ public class CustomerSettings implements Mappable {
@Override
public Map<String, Object> toMap() {
return Map.of(FOOTER,footer,HEAD,header,CONTENT,mailText);
return Map.of(FOOTER,footer,HEAD,header, CONTENT,mailText);
}
public CustomerSettings patch(JSONObject json) {