From 97134694a27763ae019f193d49ef1b11d6545b9a Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Tue, 15 Jul 2025 23:46:01 +0200 Subject: [PATCH] implemented deletion of positions --- .../umbrella/documents/DocumentApi.java | 27 ++++++++++++----- frontend/src/routes/document/Position.svelte | 16 ++++++---- .../src/routes/document/PositionList.svelte | 30 ++++++++++++++----- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java b/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java index b54b300..9037d37 100644 --- a/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java +++ b/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java @@ -63,14 +63,14 @@ public class DocumentApi extends BaseHandler { var user = users.loadUser(token); if (user.isEmpty()) return unauthorized(ex); var head = path.pop(); - return switch (head){ - default -> { - try { - yield deleteDocument(ex,Long.parseLong(head),user.get()); - } catch (NumberFormatException ignored) {} - yield super.doDelete(path,ex); - } + long docId = Long.parseLong(head); + return switch (path.pop()){ + case POSITION -> deletePosition(ex,docId,user.get()); + case null -> deleteDocument(ex,docId,user.get()); + default -> super.doDelete(path,ex); }; + } catch (NumberFormatException ignored) { + return super.doDelete(path,ex); } catch (UmbrellaException e) { return send(ex,e); } @@ -84,6 +84,17 @@ public class DocumentApi extends BaseHandler { return sendContent(ex,db.deleteDoc(docId)); } + private boolean deletePosition(HttpExchange ex, long docId, UmbrellaUser user) 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()); + 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); + db.dropPosition(docId,number.longValue()); + return send(ex,db.loadDoc(docId).positions()); + } + @Override public boolean doGet(Path path, HttpExchange ex) throws IOException { addCors(ex); @@ -301,7 +312,7 @@ public class DocumentApi extends BaseHandler { var pos = new Position(doc.positions().size()+1,itemCode,amount.doubleValue(),unit,title,description,unitPrice.longValue(),tax,timeId,false); doc.positions().add(pos); - return sendContent(ex,db.save(doc).positions()); + return send(ex,db.save(doc).positions()); } private boolean postTemplateList(HttpExchange ex, UmbrellaUser user) throws UmbrellaException, IOException { diff --git a/frontend/src/routes/document/Position.svelte b/frontend/src/routes/document/Position.svelte index 3827493..3dc811c 100644 --- a/frontend/src/routes/document/Position.svelte +++ b/frontend/src/routes/document/Position.svelte @@ -5,7 +5,7 @@ import LineEditor from '../../Components/LineEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import PriceEditor from '../../Components/PriceEditor.svelte'; - var { currency, editable, pos = $bindable(null), submit = (key,newVal) => {}, movePos = (number,step) => {} } = $props(); + var { currency, editable, pos = $bindable(null), submit = (key,newVal) => {}, movePos = (number,step) => {}, drop = (number) => {} } = $props(); let prefix = `pos.${pos.number}` function moveup(){ @@ -21,14 +21,14 @@ .move{ vertical-align: middle; } + + tr > *:nth-child(1){ + text-align: right; + } + {#if pos} - - {#if editable && pos.number>1} - - {/if} - {pos.number} submit(`${prefix}.item`,val)} /> @@ -54,6 +54,10 @@ {#if editable} + {#if pos.number>1} + + {/if} + drop(pos.number)}>❌ {/if} diff --git a/frontend/src/routes/document/PositionList.svelte b/frontend/src/routes/document/PositionList.svelte index 5050208..d2297a9 100644 --- a/frontend/src/routes/document/PositionList.svelte +++ b/frontend/src/routes/document/PositionList.svelte @@ -8,6 +8,13 @@ let editable = $derived(document.state == 1); + async function updatePositions(resp){ + let json = await resp.json(); + document.positions = {}; + setTimeout(() => document.positions = json,100) + error = null; + } + async function movePos(number,step){ const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/document/${document.id}/position`; const resp = await fetch(url,{ @@ -16,10 +23,21 @@ body:JSON.stringify({position:number,move:step}) }); if (resp.ok){ - let json = await resp.json(); - document.positions = {}; - setTimeout(() => document.positions = json,10) - error = null; + updatePositions(resp); + } else { + error = await resp.text(); + } + } + + async function drop(number){ + const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/document/${document.id}/position`; + const resp = await fetch(url,{ + method: 'DELETE', + credentials:'include', + body:JSON.stringify({position:number}) + }); + if (resp.ok){ + updatePositions(resp); } else { error = await resp.text(); } @@ -30,7 +48,6 @@ - @@ -43,10 +60,9 @@ {#each Object.entries(document.positions) as [id,pos]} - + {/each} -
{t('document.pos')} {t('document.code')} {t('document.title_or_desc')}
{t('document.net_sum')} {document.net_sum/100} {document.currency}