completed company deletion implementation
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -23,52 +23,7 @@ public class Constants {
|
||||
public static final String ERROR_ADDRESS_MISSING = "{0} address does not contain street address / post code / city";
|
||||
|
||||
|
||||
public static final String FIELD_AMOUNT = "amount";
|
||||
public static final String FIELD_CODE = "code";
|
||||
public static final String FIELD_COMPANY = "company";
|
||||
public static final String FIELD_COMPANY_ID = "company_id";
|
||||
public static final String FIELD_CUSTOMER = "customer";
|
||||
public static final String FIELD_CUSTOMER_EMAIL = "customer_email";
|
||||
public static final String FIELD_CUSTOMER_NUMBER = "customer_number";
|
||||
public static final String FIELD_CUSTOMER_TAX_NUMBER = "customer_tax_number";
|
||||
public static final String FIELD_DEFAULT_HEADER = "default_header";
|
||||
public static final String FIELD_DEFAULT_FOOTER = "default_footer";
|
||||
public static final String FIELD_DEFAULT_MAIL = "type_mail_text";
|
||||
public static final String FIELD_DELIVERY = "delivery";
|
||||
public static final String FIELD_DELIVERY_DATE = "delivery_date";
|
||||
public static final String FIELD_DOC = "doc";
|
||||
public static final String FIELD_DOCID = "doc_id";
|
||||
public static final String FIELD_DOCUMENT = "document";
|
||||
public static final String FIELD_DOCUMENT_ID = "document_id";
|
||||
public static final String FIELD_DOC_TYPE_ID = "document_type_id";
|
||||
public static final String FIELD_END_TIME = "end_time";
|
||||
public static final String FIELD_FOOTER = "footer";
|
||||
public static final String FIELD_GROSS_SUM = "gross_sum";
|
||||
public static final String FIELD_HEAD = "head";
|
||||
public static final String FIELD_ITEM = "item";
|
||||
public static final String FIELD_ITEM_CODE = "item_code";
|
||||
public static final String FIELD_NET_PRICE = "net_price";
|
||||
public static final String FIELD_NET_SUM = "net_sum";
|
||||
public static final String FIELD_NEXT_TYPE = "next_type_id";
|
||||
public static final String FIELD_POS = "pos";
|
||||
public static final String FIELD_POSITIONS = "positions";
|
||||
public static final String FIELD_PRICE = "single_price";
|
||||
public static final String FIELD_PRICE_FORMAT = "price_format";
|
||||
public static final String FIELD_PROJECTS = "projects";
|
||||
public static final String FIELD_RECEIVER = "receiver";
|
||||
public static final String FIELD_START_TIME = "start_time";
|
||||
public static final String FIELD_TEMPLATE_ID = "template_id";
|
||||
public static final String FIELD_TASKS = "tasks";
|
||||
public static final String FIELD_TAX = "tax";
|
||||
public static final String FIELD_TAX_ID = "tax_id";
|
||||
public static final String FIELD_TIME_ID = "time_id";
|
||||
public static final String FIELD_TYPE = "type";
|
||||
public static final String FIELD_TYPE_ID = "type_id";
|
||||
public static final String FIELD_TYPE_NUMBER = "type_number";
|
||||
public static final String FIELD_TYPE_PREFIX = "type_prefix";
|
||||
public static final String FIELD_TYPE_SUFFIX = "type_suffix";
|
||||
public static final String FIELD_UNIT = "unit";
|
||||
public static final String FIELD_UNIT_PRICE = "unit_price";
|
||||
|
||||
public static final String MOVE = "move";
|
||||
|
||||
public static final String PATH_ADD_ITEM = "add_item";
|
||||
|
||||
@@ -13,14 +13,23 @@ 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.Constants.FIELD_AMOUNT;
|
||||
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_ITEM_CODE;
|
||||
import static de.srsoftware.umbrella.core.Constants.FIELD_PRICE_FORMAT;
|
||||
import static de.srsoftware.umbrella.core.Constants.FIELD_TIME_ID;
|
||||
import static de.srsoftware.umbrella.core.Constants.FIELD_TYPE;
|
||||
import static de.srsoftware.umbrella.core.Constants.FIELD_UNIT;
|
||||
import static de.srsoftware.umbrella.core.Paths.LIST;
|
||||
import static de.srsoftware.umbrella.core.Paths.STATES;
|
||||
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.*;
|
||||
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.documents.Constants.*;
|
||||
import static de.srsoftware.umbrella.documents.model.Document.State.NEW;
|
||||
import static de.srsoftware.umbrella.documents.model.Document.State.SENT;
|
||||
import static java.lang.System.Logger.Level.DEBUG;
|
||||
import static java.lang.System.Logger.Level.WARNING;
|
||||
import static java.net.HttpURLConnection.*;
|
||||
@@ -46,8 +55,8 @@ import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||
import de.srsoftware.umbrella.core.api.*;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.*;
|
||||
import de.srsoftware.umbrella.core.model.Customer;
|
||||
import de.srsoftware.umbrella.documents.model.*;
|
||||
import de.srsoftware.umbrella.documents.model.Customer;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
@@ -400,6 +409,11 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
return new JSONArray(s);
|
||||
}
|
||||
|
||||
public Map<Long, Document> list(long companyId) throws UmbrellaException{
|
||||
return db.listDocs(companyId);
|
||||
}
|
||||
|
||||
|
||||
private boolean listCompaniesDocuments(HttpExchange ex, UmbrellaUser user, Token token) throws UmbrellaException {
|
||||
try {
|
||||
var json = json(ex);
|
||||
@@ -407,7 +421,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
long companyId = json.getLong(COMPANY);
|
||||
var company = modules.companyService().get(companyId);
|
||||
if (!modules.companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company);
|
||||
var docs = db.listDocs(companyId);
|
||||
var docs = list(companyId);
|
||||
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));
|
||||
@@ -417,6 +431,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean patchDocument(long docId, UmbrellaUser user, HttpExchange ex) throws UmbrellaException, IOException {
|
||||
var doc = getDocument(docId,user).a;
|
||||
doc.patch(json(ex));
|
||||
|
||||
@@ -3,6 +3,9 @@ package de.srsoftware.umbrella.documents;
|
||||
|
||||
import de.srsoftware.tools.Pair;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.Document;
|
||||
import de.srsoftware.umbrella.core.model.Template;
|
||||
import de.srsoftware.umbrella.core.model.Type;
|
||||
import de.srsoftware.umbrella.documents.model.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -7,10 +7,11 @@ 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.Constants.FIELD_COMPANY_ID;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException;
|
||||
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.documents.Constants.*;
|
||||
import static de.srsoftware.umbrella.documents.model.Document.DEFAULT_THOUSANDS_SEPARATOR;
|
||||
import static de.srsoftware.umbrella.documents.model.Document.State;
|
||||
import static java.lang.System.Logger.Level.*;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
@@ -18,8 +19,8 @@ import static java.time.ZoneOffset.UTC;
|
||||
import de.srsoftware.tools.Pair;
|
||||
import de.srsoftware.tools.jdbc.Query;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.*;
|
||||
import de.srsoftware.umbrella.documents.model.*;
|
||||
import de.srsoftware.umbrella.documents.model.Type;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -3,8 +3,8 @@ 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.FIELD_PRICE_FORMAT;
|
||||
import static de.srsoftware.umbrella.core.Constants.USER;
|
||||
import static de.srsoftware.umbrella.documents.Constants.FIELD_PRICE_FORMAT;
|
||||
import static java.lang.System.Logger.Level.TRACE;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.text.MessageFormat.format;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
import static de.srsoftware.tools.Optionals.emptyIfNull;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.documents.Constants.*;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
|
||||
import static de.srsoftware.umbrella.documents.Constants.FIELD_TAX_ID;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public final class Customer implements Mappable {
|
||||
private String id;
|
||||
private String name;
|
||||
private String email;
|
||||
private String taxNumber;
|
||||
private String language;
|
||||
private final Set<String> dirtyFields = new HashSet<>();
|
||||
|
||||
public Customer(String id, String name, String email, String taxNumber, String language) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
this.taxNumber = taxNumber;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
dirtyFields.clear();
|
||||
}
|
||||
|
||||
public String email() {
|
||||
return email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Customer) obj;
|
||||
return Objects.equals(this.id, that.id) &&
|
||||
Objects.equals(this.name, that.name) &&
|
||||
Objects.equals(this.email, that.email) &&
|
||||
Objects.equals(this.taxNumber, that.taxNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name, email, taxNumber);
|
||||
}
|
||||
|
||||
public String id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return !dirtyFields.isEmpty();
|
||||
}
|
||||
|
||||
public String language(){
|
||||
return language;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static Customer of(JSONObject json) throws UmbrellaException {
|
||||
if (!json.has(ID) || !(json.get(ID) instanceof String id)) throw missingFieldException(ID);
|
||||
if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingFieldException(NAME);
|
||||
if (!json.has(EMAIL) || !(json.get(EMAIL) instanceof String email)) throw missingFieldException(EMAIL);
|
||||
if (!json.has(FIELD_TAX_ID) || !(json.get(FIELD_TAX_ID) instanceof String taxId)) throw missingFieldException(FIELD_TAX_ID);
|
||||
var lang = json.has(LANGUAGE) && json.get(LANGUAGE) instanceof String l ? l : FALLBACK_LANG;
|
||||
return new Customer(id,name,email,taxId,lang);
|
||||
}
|
||||
|
||||
public void patch(JSONObject json) {
|
||||
for (var key : json.keySet()){
|
||||
switch (key){
|
||||
case ID: id = json.getString(key); break;
|
||||
case NAME: name = json.getString(key); break;
|
||||
case EMAIL: email = json.getString(key); break;
|
||||
case FIELD_TAX_ID: taxNumber = json.getString(key); break;
|
||||
default: key = null;
|
||||
}
|
||||
if (key != null) dirtyFields.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
public String shortName(){
|
||||
var lines = name.split("\n");
|
||||
var result = lines[0];
|
||||
if (lines.length>1 && !lines[1].matches(".*\\d.*")) result += " "+lines[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
public String taxNumber() {
|
||||
return taxNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
return Map.of(
|
||||
"id", id,
|
||||
"name", name,
|
||||
"email", email,
|
||||
"tax_id", taxNumber
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.documents.Constants.*;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
|
||||
@@ -1,332 +0,0 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE;
|
||||
import static de.srsoftware.umbrella.core.Util.mapMarkdown;
|
||||
import static de.srsoftware.umbrella.documents.Constants.*;
|
||||
import static de.srsoftware.umbrella.documents.Constants.FIELD_CUSTOMER;
|
||||
import static java.util.Optional.empty;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
public final class Document implements Mappable {
|
||||
public static final String DEFAULT_THOUSANDS_SEPARATOR = ".";
|
||||
|
||||
public enum State {
|
||||
|
||||
NEW(1), SENT(2), DELAYED(3), PAYED(4), DECLINED(5), ERROR(99);
|
||||
|
||||
private final int code;
|
||||
|
||||
State(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public int code() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static Map<Integer, Object> names() {
|
||||
return Arrays.stream(values()).collect(Collectors.toMap(state -> state.code, state -> Map.of("name", state.toString(), "display", "<? " + state + " ?>")));
|
||||
}
|
||||
|
||||
public static Optional<State> of(int code) {
|
||||
for (var s : State.values()) {
|
||||
if (s.code == code) return Optional.of(s);
|
||||
}
|
||||
return empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
private final long companyId, id;
|
||||
private String companyName, currency, decimalSeparator, delivery, footer, head, number;
|
||||
|
||||
private final Type type;
|
||||
private LocalDate date;
|
||||
private State state;
|
||||
private Template template;
|
||||
private final Sender sender;
|
||||
private final Customer customer;
|
||||
private final PositionList positions;
|
||||
private final Set<String> dirtyFields = new HashSet<>();
|
||||
|
||||
|
||||
public Document(long id, long companyId, String number, Type type, LocalDate date, State state, Template template, String delivery, String head, String footer, String currency, String thousandsSeparator, Sender sender, Customer customer, PositionList positions) {
|
||||
this.id = id;
|
||||
this.companyId = companyId;
|
||||
this.number = number;
|
||||
this.type = type;
|
||||
this.date = date;
|
||||
this.state = state;
|
||||
this.template = template;
|
||||
this.delivery = delivery;
|
||||
this.head = head;
|
||||
this.footer = footer;
|
||||
this.currency = currency;
|
||||
this.sender = sender;
|
||||
this.customer = customer;
|
||||
this.positions = positions;
|
||||
this.decimalSeparator = thousandsSeparator;
|
||||
positions.setDocId(id);
|
||||
if (id == 0) dirtyFields.add(ID);
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
dirtyFields.clear();
|
||||
}
|
||||
|
||||
public long companyId() {
|
||||
return companyId;
|
||||
}
|
||||
|
||||
public String currency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
public Customer customer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public LocalDate date() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public String decimalSeparator() {
|
||||
return decimalSeparator;
|
||||
}
|
||||
|
||||
public String delivery() {
|
||||
return delivery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Document) obj;
|
||||
return this.id == that.id &&
|
||||
this.companyId == that.companyId &&
|
||||
Objects.equals(this.number, that.number) &&
|
||||
Objects.equals(this.type, that.type) &&
|
||||
Objects.equals(this.date, that.date) &&
|
||||
Objects.equals(this.state, that.state) &&
|
||||
Objects.equals(this.template, that.template) &&
|
||||
Objects.equals(this.delivery, that.delivery) &&
|
||||
Objects.equals(this.head, that.head) &&
|
||||
Objects.equals(this.footer, that.footer) &&
|
||||
Objects.equals(this.currency, that.currency) &&
|
||||
Objects.equals(this.sender, that.sender) &&
|
||||
Objects.equals(this.customer, that.customer) &&
|
||||
Objects.equals(this.positions, that.positions);
|
||||
}
|
||||
|
||||
public String footer() {
|
||||
return footer;
|
||||
}
|
||||
|
||||
public long grossSum() {
|
||||
var taxMap = new HashMap<Integer, Double>();
|
||||
for (var pos : positions.values()) {
|
||||
var taxRate = pos.tax();
|
||||
var sum = taxMap.get(taxRate);
|
||||
if (sum == null) sum = 0d;
|
||||
sum += pos.unitPrice() * pos.amount();
|
||||
taxMap.put(taxRate, sum);
|
||||
}
|
||||
var sum = 0d;
|
||||
for (var entry : taxMap.entrySet()) {
|
||||
var taxRate = entry.getKey();
|
||||
var taxSum = entry.getValue();
|
||||
sum += taxSum * (100 + taxRate) / 100d;
|
||||
}
|
||||
return Math.round(sum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, companyId, number, type, date, state, template, delivery, head, footer, currency, sender, customer, positions);
|
||||
}
|
||||
|
||||
public String head() {
|
||||
return head;
|
||||
}
|
||||
|
||||
public long id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return !dirtyFields.isEmpty() || sender.isDirty() || customer.isDirty();
|
||||
}
|
||||
|
||||
public boolean isNew(){
|
||||
return dirtyFields.contains(ID);
|
||||
}
|
||||
|
||||
public long netSum() {
|
||||
var sum = 0d;
|
||||
for (var pos : positions.values()) sum += pos.unitPrice() * pos.amount();
|
||||
return Math.round(sum);
|
||||
}
|
||||
|
||||
public String number() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void patch(JSONObject json) throws UmbrellaException {
|
||||
for (var key : json.keySet()){
|
||||
switch (key){
|
||||
case FIELD_CUSTOMER: if (json.get(key) instanceof JSONObject nested) customer.patch(nested); break;
|
||||
case FIELD_CURRENCY: currency = json.getString(key); break;
|
||||
case DATE: date = LocalDate.parse(json.getString(key)); break;
|
||||
case FIELD_DELIVERY: delivery = json.getString(key); break;
|
||||
case FIELD_FOOTER: footer = json.getString(key); break;
|
||||
case FIELD_HEAD: head = json.getString(key); break;
|
||||
case NUMBER: number = json.getString(key); break;
|
||||
case SENDER: if (json.get(key) instanceof JSONObject nested) sender.patch(nested); break;
|
||||
case STATE: state = State.of(json.getInt(key)).orElseThrow(() -> new UmbrellaException(HTTP_UNPROCESSABLE,"Invalid state")); break;
|
||||
case FIELD_POS: if (json.get(key) instanceof JSONObject nested) positions.patch(nested); break;
|
||||
case FIELD_TEMPLATE_ID: if (json.get(key) instanceof Number num) template = new Template(num.longValue(),companyId,null,null); break;
|
||||
default: key = null;
|
||||
}
|
||||
if (key != null) dirtyFields.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
public PositionList positions() {
|
||||
return positions;
|
||||
}
|
||||
|
||||
public Map<String, Object> renderToMap() {
|
||||
var map = new HashMap<String, Object>();
|
||||
map.put(ID, id);
|
||||
map.put(FIELD_COMPANY, Map.of(ID,companyId, NAME,companyName));
|
||||
map.put(NUMBER, number);
|
||||
map.put(FIELD_TYPE, type.name());
|
||||
map.put(DATE, date);
|
||||
map.put(STATE, state.code);
|
||||
map.put(FIELD_DELIVERY, delivery == null ? "" : delivery);
|
||||
map.put(FIELD_HEAD, mapMarkdown(head));
|
||||
map.put(FIELD_FOOTER, mapMarkdown(footer));
|
||||
map.put(FIELD_CURRENCY, currency);
|
||||
map.put(SENDER, sender.toMap());
|
||||
map.put(FIELD_CUSTOMER, customer.toMap());
|
||||
map.put(FIELD_POSITIONS, positions.asMap(true));
|
||||
map.put("taxes",positions.taxNetSums(true));
|
||||
map.put(FIELD_NET_SUM, netSum());
|
||||
map.put(FIELD_GROSS_SUM, grossSum());
|
||||
if (template != null) map.put("template", template.toMap());
|
||||
return map;
|
||||
}
|
||||
|
||||
public Sender sender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public Document set(State newState) {
|
||||
state = newState;
|
||||
dirtyFields.add(STATE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* alter the separator for decimals
|
||||
* @param newValue new value for the separator
|
||||
* @return this document instance
|
||||
*/
|
||||
public Document setDecimalSeparator(String newValue) {
|
||||
decimalSeparator = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the company name
|
||||
* @param newValue new value for the company name
|
||||
* @return this document instance
|
||||
*/
|
||||
public Document setCompanyName(String newValue){
|
||||
companyName = newValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
public State state() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public Map<String, Object> summary() {
|
||||
return Map.of(
|
||||
ID, id,
|
||||
NUMBER, number,
|
||||
"type", type.name(),
|
||||
STATE, Map.of(NAME,state.toString(),ID,state.code),
|
||||
DATE, date,
|
||||
FIELD_CURRENCY, currency,
|
||||
FIELD_CUSTOMER, customer.toMap(),
|
||||
"sum", positions.grossSum(true)
|
||||
);
|
||||
}
|
||||
|
||||
public Template template() {
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
var map = new HashMap<String, Object>();
|
||||
map.put(ID, id);
|
||||
map.put(FIELD_COMPANY, companyId);
|
||||
map.put(NUMBER, number);
|
||||
map.put(FIELD_TYPE, type);
|
||||
map.put(DATE, date);
|
||||
map.put(STATE, state.code);
|
||||
map.put(FIELD_DELIVERY, delivery);
|
||||
map.put(FIELD_HEAD, head);
|
||||
map.put(FIELD_FOOTER, footer);
|
||||
map.put(FIELD_CURRENCY, currency);
|
||||
map.put(SENDER, sender.toMap());
|
||||
map.put(FIELD_CUSTOMER, customer.toMap());
|
||||
map.put(FIELD_POSITIONS, positions.asMap(false));
|
||||
map.put("taxes",positions.taxNetSums(true));
|
||||
map.put(FIELD_NET_SUM, netSum());
|
||||
map.put(FIELD_GROSS_SUM, grossSum());
|
||||
if (template != null) map.put("template", template.toMap());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Document[" +
|
||||
"id=" + id + ", " +
|
||||
"company=" + companyId + ", " +
|
||||
"number=" + number + ", " +
|
||||
"type=" + type + ", " +
|
||||
"date=" + date + ", " +
|
||||
"state=" + state + ", " +
|
||||
"template=" + template + ", " +
|
||||
"delivery=" + delivery + ", " +
|
||||
"head=" + head + ", " +
|
||||
"footer=" + footer + ", " +
|
||||
"currency=" + currency + ", " +
|
||||
"sender=" + sender + ", " +
|
||||
"customer=" + customer + ", " +
|
||||
"positions=" + positions + ']';
|
||||
}
|
||||
|
||||
public Type type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.Util.mapMarkdown;
|
||||
import static de.srsoftware.umbrella.documents.Constants.*;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import java.util.*;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public final class Position implements Mappable {
|
||||
public static final System.Logger LOG = System.getLogger(Position.class.getSimpleName());
|
||||
private long docId;
|
||||
private final int num;
|
||||
private String itemCode;
|
||||
private double amount;
|
||||
private String unit;
|
||||
private String title;
|
||||
private String description;
|
||||
private long unitPrice;
|
||||
private int tax;
|
||||
private final Long timeId;
|
||||
private boolean optional;
|
||||
private Set<String> dirtyFields = new HashSet<>();
|
||||
|
||||
public Position(int num, String itemCode, double amount, String unit, String title, String description, long unitPrice, int tax, Long timeId, boolean optional) {
|
||||
this.num = num;
|
||||
this.itemCode = itemCode;
|
||||
this.amount = amount;
|
||||
this.unit = unit;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.unitPrice = unitPrice;
|
||||
this.tax = tax;
|
||||
this.timeId = timeId;
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public double amount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
dirtyFields.clear();
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public long docId() {
|
||||
return docId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Position) obj;
|
||||
return this.docId == that.docId &&
|
||||
this.num == that.num &&
|
||||
Objects.equals(this.itemCode, that.itemCode) &&
|
||||
Double.doubleToLongBits(this.amount) == Double.doubleToLongBits(that.amount) &&
|
||||
Objects.equals(this.unit, that.unit) &&
|
||||
Objects.equals(this.title, that.title) &&
|
||||
Objects.equals(this.description, that.description) &&
|
||||
this.unitPrice == that.unitPrice &&
|
||||
this.tax == that.tax &&
|
||||
this.timeId == that.timeId &&
|
||||
this.optional == that.optional;
|
||||
}
|
||||
|
||||
public long grossPrice() {
|
||||
var taxRate = (100 + tax) / 100d;
|
||||
var sum = unitPrice * amount * taxRate;
|
||||
return Math.round(sum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(docId, num, itemCode, amount, unit, title, description, unitPrice, tax, timeId, optional);
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return !dirtyFields.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isDirty(String field){
|
||||
return dirtyFields.contains(field);
|
||||
}
|
||||
|
||||
public boolean isNew(){
|
||||
return dirtyFields.contains(FIELD_DOCUMENT_ID);
|
||||
}
|
||||
|
||||
public String itemCode() {
|
||||
return itemCode;
|
||||
}
|
||||
|
||||
public long netPrice() {
|
||||
return Math.round(amount * unitPrice);
|
||||
}
|
||||
|
||||
public int num() {
|
||||
return num;
|
||||
}
|
||||
|
||||
public boolean optional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
public void patch(JSONObject json) {
|
||||
for (var key : json.keySet()) {
|
||||
switch (key) {
|
||||
case FIELD_AMOUNT: amount = json.getDouble(key); break;
|
||||
case DESCRIPTION: description = json.getString(key); break;
|
||||
case FIELD_ITEM: itemCode = json.getString(key); break;
|
||||
case OPTIONAL: optional = json.getBoolean(key); break;
|
||||
case FIELD_TAX: tax = json.getInt(key); break;
|
||||
case TITLE: title = json.getString(key); break;
|
||||
case FIELD_UNIT: unit = json.getString(key); break;
|
||||
case FIELD_UNIT_PRICE: unitPrice = json.getLong(key); break;
|
||||
default: key = null;
|
||||
}
|
||||
if (key != null) dirtyFields.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
public Position setDocId(long docId) {
|
||||
this.docId = docId;
|
||||
dirtyFields.add(FIELD_DOCUMENT_ID);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Position setItemCode(String newValue) {
|
||||
this.itemCode = newValue;
|
||||
dirtyFields.add(FIELD_ITEM);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Position setUnit(String newValue) {
|
||||
unit = newValue;
|
||||
dirtyFields.add(FIELD_UNIT);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setUnitPrice(long price) {
|
||||
unitPrice = price;
|
||||
dirtyFields.add(FIELD_UNIT_PRICE);
|
||||
}
|
||||
|
||||
public int tax() {
|
||||
return tax;
|
||||
}
|
||||
|
||||
public long taxAmount() {
|
||||
var taxRate = tax / 100d;
|
||||
var tax = unitPrice * amount * taxRate;
|
||||
return Math.round(tax);
|
||||
}
|
||||
|
||||
public Long timeId() {
|
||||
return timeId;
|
||||
}
|
||||
|
||||
public String title() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
var map = new HashMap<String, Object>();
|
||||
map.put(FIELD_DOCUMENT_ID, docId);
|
||||
map.put(NUMBER, num);
|
||||
map.put(FIELD_ITEM, itemCode);
|
||||
map.put(FIELD_AMOUNT, amount);
|
||||
map.put(FIELD_UNIT, unit);
|
||||
map.put(TITLE, title);
|
||||
map.put(DESCRIPTION, description);
|
||||
map.put(FIELD_UNIT_PRICE, unitPrice);
|
||||
map.put(FIELD_TAX, tax);
|
||||
map.put(FIELD_TIME_ID, timeId);
|
||||
map.put(OPTIONAL, optional);
|
||||
map.put(FIELD_NET_PRICE, netPrice());
|
||||
return map;
|
||||
}
|
||||
|
||||
public Map<String, Object> renderToMap() {
|
||||
var map = new HashMap<String, Object>();
|
||||
map.put(FIELD_DOCUMENT_ID, docId);
|
||||
map.put(NUMBER, num);
|
||||
map.put(FIELD_ITEM, itemCode);
|
||||
map.put(FIELD_AMOUNT, amount);
|
||||
map.put(FIELD_UNIT, unit);
|
||||
map.put(TITLE, title);
|
||||
map.put(DESCRIPTION, mapMarkdown(description));
|
||||
map.put(FIELD_UNIT_PRICE, unitPrice);
|
||||
map.put(FIELD_TAX, tax);
|
||||
map.put(FIELD_TIME_ID, timeId);
|
||||
map.put(OPTIONAL, optional);
|
||||
map.put(FIELD_NET_PRICE, netPrice());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Position[" +
|
||||
"docId=" + docId + ", " +
|
||||
"num=" + num + ", " +
|
||||
"itemCode=" + itemCode + ", " +
|
||||
"amount=" + amount + ", " +
|
||||
"unit=" + unit + ", " +
|
||||
"title=" + title + ", " +
|
||||
"description=" + description + ", " +
|
||||
"unitPrice=" + unitPrice + ", " +
|
||||
"tax=" + tax + ", " +
|
||||
"timeId=" + timeId + ", " +
|
||||
"optional=" + optional + ']';
|
||||
}
|
||||
|
||||
public String unit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public long unitPrice() {
|
||||
return unitPrice;
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.documents.Constants.*;
|
||||
|
||||
import de.srsoftware.tools.Pair;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class PositionList extends HashMap<Integer,Position> {
|
||||
private long docId;
|
||||
|
||||
public PositionList add(Position pos) {
|
||||
put(pos.num(),pos);
|
||||
pos.setDocId(docId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Position addItem(JSONObject item) {
|
||||
var itemCode = item.getString(FIELD_CODE);
|
||||
var unit = item.getString(FIELD_UNIT);
|
||||
var name = item.getString(NAME);
|
||||
var description = item.getString(DESCRIPTION);
|
||||
var unitPrice = item.getLong(FIELD_UNIT_PRICE);
|
||||
var tax = item.getInt(FIELD_TAX);
|
||||
var position = new Position(size()+1,itemCode,1.0,unit,name,description,unitPrice,tax,null,false);
|
||||
add(position);
|
||||
return position;
|
||||
}
|
||||
|
||||
public Position addTask(JSONObject task) {
|
||||
var amount = task.getLong("est_time");
|
||||
var name = task.getString(NAME);
|
||||
var description = task.getString(DESCRIPTION);
|
||||
var unitPrice = 0;
|
||||
var tax = 19; // TODO: make adjustable
|
||||
var position = new Position(size()+1,null,amount,null,name,description,unitPrice,tax,null,false);
|
||||
add(position);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
public Position addTime(JSONObject time) {
|
||||
var id = time.getLong(ID);
|
||||
var start = time.getLong(FIELD_START_TIME);
|
||||
var end = time.getLong(FIELD_END_TIME);
|
||||
var amount = (end - start)/3600d;
|
||||
var name = time.getString(SUBJECT);
|
||||
var desc = time.getString(DESCRIPTION).trim();
|
||||
var description = new StringBuilder();
|
||||
if (!desc.isEmpty()) description.append(desc);
|
||||
if (time.has(FIELD_TASKS)){
|
||||
var tasks = time.getJSONObject(FIELD_TASKS);
|
||||
var taskKeys = tasks.keySet();
|
||||
if (taskKeys.size()>1) { // description normally came from first task
|
||||
if (!desc.isEmpty()) description.append("\n\n");
|
||||
for (var taskId : tasks.keySet()) {
|
||||
var task = tasks.getJSONObject(taskId);
|
||||
description.append("* ").append(task.getString(NAME)).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
var unitPrice = 0;
|
||||
var tax = 19; // TODO: make adjustable
|
||||
var position = new Position(size()+1,null,amount,null,name,description.toString(),unitPrice,tax,id,false);
|
||||
add(position);
|
||||
return position;
|
||||
}
|
||||
|
||||
public Map<Integer,Object> asMap(boolean renderMarkdown) {
|
||||
var map = new HashMap<Integer,Object>();
|
||||
for (var entry : entrySet()) {
|
||||
var pos = entry.getValue();
|
||||
map.put(entry.getKey(),renderMarkdown ? pos.renderToMap() : pos.toMap());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public Pair<Integer> getMoveablePair(JSONObject data) throws UmbrellaException {
|
||||
if (!data.has("pos")) throw new UmbrellaException(400,"Missing nested value move.pos!");
|
||||
if (!data.has("step")) throw new UmbrellaException(400,"Missing nested value move.step!");
|
||||
if (!(data.get("pos") instanceof Number pos)) throw new UmbrellaException(400,"Invalid value for move.pos");
|
||||
if (!(data.get("step") instanceof Number step)) throw new UmbrellaException(400,"Invalid value for move.step");
|
||||
int one = pos.intValue();
|
||||
int other = one + (step.longValue() < 0 ? -1 : 1);
|
||||
if (!containsKey(one) || !containsKey(other)) throw new UmbrellaException(400,"Invalid value for move.pos");
|
||||
return new Pair<>(one,other);
|
||||
}
|
||||
|
||||
public long grossSum(boolean includeOptionals) {
|
||||
var gross = netSum(includeOptionals);
|
||||
for (var taxSum : taxNetSums(includeOptionals).entrySet()) {
|
||||
var percent = taxSum.getKey();
|
||||
var netSum = taxSum.getValue();
|
||||
gross += Math.round(netSum * percent / 100d);
|
||||
}
|
||||
return gross;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return values().stream().anyMatch(Position::isDirty);
|
||||
}
|
||||
|
||||
public long netSum(boolean includeOptionals) {
|
||||
long sum = 0;
|
||||
for (var pos : values()){
|
||||
if (includeOptionals || !pos.optional()) sum += pos.netPrice();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public void patch(JSONObject json) {
|
||||
for (var key : json.keySet()){
|
||||
try {
|
||||
var pos = Integer.parseInt(key);
|
||||
if (get(pos) instanceof Position position && json.get(key) instanceof JSONObject data) position.patch(data);
|
||||
} catch (NumberFormatException ignored){}
|
||||
}
|
||||
}
|
||||
|
||||
public void setDocId(long id) {
|
||||
docId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map from Percent to net sums of relevant positions
|
||||
* @param includeOptionals
|
||||
* @return
|
||||
*/
|
||||
public Map<Integer,Long> taxNetSums(boolean includeOptionals){
|
||||
var netSums = new HashMap<Integer,Long>();
|
||||
for (var pos : values()){
|
||||
if (includeOptionals || !pos.optional()) {
|
||||
var tax = pos.tax();
|
||||
var netSumForTax = netSums.get(tax);
|
||||
if (netSumForTax == null) netSumForTax = 0L;
|
||||
netSumForTax += pos.netPrice();
|
||||
netSums.put(tax, netSumForTax);
|
||||
}
|
||||
}
|
||||
return netSums;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
|
||||
import static de.srsoftware.umbrella.documents.Constants.*;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public final class Sender implements Mappable {
|
||||
private String name;
|
||||
private String bankAccount;
|
||||
private String taxNumber;
|
||||
private String court;
|
||||
private final Set<String> dirtyFields = new HashSet<>();
|
||||
|
||||
public Sender(String name, String bankAccount, String taxNumber, String court) {
|
||||
this.name = name;
|
||||
this.bankAccount = bankAccount;
|
||||
this.taxNumber = taxNumber;
|
||||
this.court = court;
|
||||
}
|
||||
|
||||
public String bankAccount() {
|
||||
return bankAccount;
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
dirtyFields.clear();
|
||||
}
|
||||
|
||||
public String court() {
|
||||
return court;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Sender) obj;
|
||||
return Objects.equals(this.name, that.name) &&
|
||||
Objects.equals(this.bankAccount, that.bankAccount) &&
|
||||
Objects.equals(this.taxNumber, that.taxNumber) &&
|
||||
Objects.equals(this.court, that.court);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, bankAccount, taxNumber, court);
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return !dirtyFields.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static Sender of(JSONObject json) throws UmbrellaException {
|
||||
if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingFieldException(NAME);
|
||||
if (!json.has(FIELD_BANK_ACCOUNT) || !(json.get(FIELD_BANK_ACCOUNT) instanceof String bankAccount)) throw missingFieldException(FIELD_BANK_ACCOUNT);
|
||||
if (!json.has(FIELD_TAX_ID) || !(json.get(FIELD_TAX_ID) instanceof String taxId)) throw missingFieldException(FIELD_TAX_ID);
|
||||
if (!json.has(FIELD_COURT) || !(json.get(FIELD_COURT) instanceof String court)) throw missingFieldException(FIELD_COURT);
|
||||
return new Sender(name,bankAccount,taxId,court);
|
||||
}
|
||||
|
||||
public void patch(JSONObject json) {
|
||||
for (var key : json.keySet()){
|
||||
switch (key){
|
||||
case FIELD_BANK_ACCOUNT: bankAccount = json.getString(key); break;
|
||||
case NAME: name = json.getString(key); break;
|
||||
case FIELD_COURT: court = json.getString(key); break;
|
||||
case FIELD_TAX_ID: taxNumber = json.getString(key); break;
|
||||
default: key = null;
|
||||
}
|
||||
if (key != null) dirtyFields.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
public String taxNumber() {
|
||||
return taxNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
return Map.of(
|
||||
FIELD_BANK_ACCOUNT, bankAccount,
|
||||
FIELD_COURT, court,
|
||||
NAME, name,
|
||||
FIELD_TAX_ID, taxNumber
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Sender[" +
|
||||
"name=" + name + ", " +
|
||||
"bankAccount=" + bankAccount + ", " +
|
||||
"taxNumber=" + taxNumber + ", " +
|
||||
"court=" + court + ']';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
import static de.srsoftware.umbrella.documents.Constants.FIELD_COMPANY;
|
||||
|
||||
import de.srsoftware.tools.Mappable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
public record Template(long id, long company, String name, byte[] data) implements Mappable {
|
||||
|
||||
public static Template of(ResultSet rs) throws SQLException {
|
||||
return new Template(rs.getLong(ID),rs.getLong(COMPANY_ID),rs.getString(NAME),rs.getBytes(TEMPLATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
return Map.of(ID,id,FIELD_COMPANY,company, NAME,name);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
/* © SRSoftware 2025 */
|
||||
package de.srsoftware.umbrella.documents.model;
|
||||
|
||||
|
||||
|
||||
public record Type(int id, int successor, String name) {}
|
||||
Reference in New Issue
Block a user