preparing to render document

This commit is contained in:
2025-07-16 08:55:08 +02:00
parent b372ae45b3
commit 07ef168226
4 changed files with 83 additions and 17 deletions

View File

@@ -0,0 +1,17 @@
package de.srsoftware.umbrella.core;
import de.srsoftware.umbrella.core.model.Company;
public class Tuple<A,B>{
public final A a;
public final B b;
public Tuple(A a, B b){
this.a = a;
this.b = b;
}
public static <A, B> Tuple<A,B> of(A a, B b) {
return new Tuple<>(a,b);
}
}

View File

@@ -3,5 +3,11 @@ description = "Umbrella : Documents"
dependencies{
implementation(project(":company"))
implementation(project(":core"))
implementation("de.srsoftware:document.api:1.0.1")
implementation("de.srsoftware:document.file:1.0.0")
implementation("de.srsoftware:document.processor:1.0.2")
implementation("de.srsoftware:document.zugferd:1.0.3")
implementation("de.srsoftware:tools.mime:1.1.2")
}

View File

@@ -19,10 +19,12 @@ import static java.util.stream.Collectors.toMap;
import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.configuration.Configuration;
import de.srsoftware.document.api.DocumentRegistry;
import de.srsoftware.tools.Pair;
import de.srsoftware.tools.Path;
import de.srsoftware.tools.SessionToken;
import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.Tuple;
import de.srsoftware.umbrella.core.api.CompanyService;
import de.srsoftware.umbrella.core.api.UserService;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
@@ -35,12 +37,14 @@ import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.json.JSONArray;
import org.json.JSONObject;
public class DocumentApi extends BaseHandler {
private static final Predicate<de.srsoftware.document.api.Document> ZUGFERD_FILTER = document -> document.id().equals("Zugferd");
private final DocumentRegistry registry = new DocumentRegistry();
private final CompanyService companies;
private final Configuration config;
@@ -110,18 +114,25 @@ public class DocumentApi extends BaseHandler {
case STATES -> getDocStates(ex);
case null -> super.doGet(path,ex);
default -> {
try {
var docId = Long.parseLong(head);
yield getDocument(ex,docId,user.get());
} catch (NumberFormatException ignored) {}
yield super.doGet(path,ex);
head = path.pop();
yield switch (head){
case null -> getDocument(ex,docId,user.get());
case PATH_PDF -> getRenderedDocument(ex,docId,user.get());
default -> super.doGet(path,ex);
};
}
};
} catch (NumberFormatException ignored) {
return super.doGet(path,ex);
} catch (UmbrellaException e) {
return send(ex,e);
}
}
@Override
public boolean doOptions(Path path, HttpExchange ex) throws IOException {
return sendEmptyResponse(HTTP_OK,addCors(ex));
@@ -197,18 +208,46 @@ public class DocumentApi extends BaseHandler {
return sendContent(ex,map);
}
private boolean getDocument(HttpExchange ex, long docId, UmbrellaUser user) throws IOException, UmbrellaException {
private Tuple<Document,Company> getDocument(long docId, UmbrellaUser user) throws UmbrellaException {
var doc = db.loadDoc(docId);
var companyId = doc.companyId();
var company = companies.get(companyId);
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
return Tuple.of(doc,company);
}
private Document getDocumentWithCompanyData(long docId, UmbrellaUser user) throws UmbrellaException {
var tuple = getDocument(docId,user);
var company = tuple.b;
var sep = company.decimalSeparator();
var doc = tuple.a;
if (sep != null) doc.setDecimalSeparator(sep);
doc.setCompanyName(company.name());
return doc;
}
private boolean getDocument(HttpExchange ex, long docId, UmbrellaUser user) throws IOException, UmbrellaException {
var doc = getDocumentWithCompanyData(docId,user);
return sendContent(ex,doc.renderToMap());
}
private boolean getRenderedDocument(HttpExchange ex, long docId, UmbrellaUser user) throws IOException, UmbrellaException {
var document = getDocumentWithCompanyData(docId,user);
var template = document.template().name();
var templateName = template+".html.pdf";
var type = document.type().name();
var zugferd = "invoice".equals(type);
Predicate<de.srsoftware.document.api.Document> filter = zugferd ? ZUGFERD_FILTER : doc -> doc.name().equals(templateName);
var optDoc = registry.documents()
.filter(filter)
.findAny();
if (optDoc.isEmpty()) throw new UmbrellaException(404,"Cannot render {0} {1}: Missing template \"{2}\"",type,document.number(),template);
return sendContent(ex,document.renderToMap());
}
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);
@@ -234,9 +273,7 @@ public class DocumentApi extends BaseHandler {
}
private boolean patchDocument(long docId, UmbrellaUser user, HttpExchange ex) throws UmbrellaException, IOException {
var doc = db.loadDoc(docId);
var companyId = doc.companyId();
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId());
var doc = getDocument(docId,user).a;
doc.patch(json(ex));
db.save(doc);
return ok(ex);
@@ -247,9 +284,7 @@ public class DocumentApi extends BaseHandler {
}
private boolean patchDocumentPosition(long docId, UmbrellaUser user, HttpExchange ex) throws UmbrellaException, IOException {
var doc = db.loadDoc(docId);
var companyId = doc.companyId();
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId());
var doc = getDocument(docId,user).a;
if (doc.state() != NEW) throw forbidden("Document has already been send and is write-protected!");
var json = json(ex);
var step = json.has(MOVE) && json.get(MOVE) instanceof Number num ? num.intValue() : 0;
@@ -295,10 +330,7 @@ public class DocumentApi extends BaseHandler {
}
private boolean postDocumentPosition(long docId, HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException {
var doc = db.loadDoc(docId);
var companyId = doc.companyId();
var company = companies.get(companyId);
if (!companies.membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
var doc = getDocument(docId,user).a;
var json = json(ex);
if (!(json.has(FIELD_AMOUNT) && json.get(FIELD_AMOUNT) instanceof Number amount)) throw missingFieldException(FIELD_AMOUNT);

View File

@@ -79,6 +79,16 @@
}
}
async function render(){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/document/${doc.id}/pdf`;
const resp = fetch(url,{credentials:'include'});
if (resp.ok){
error = null;
} else {
error = await resp.text();
}
}
onMount(loadDoc);
</script>
@@ -199,6 +209,7 @@
</fieldset>
<fieldset>
<legend>{t('document.actions')}</legend>
<button onclick={render}>{t('document.create_pdf')}</button>
</fieldset>
<fieldset>
<legend>TODO</legend>