added improvements on set proces and minor other improvements
This commit is contained in:
@@ -82,6 +82,11 @@ $inv.iMn = (ix) => {
|
||||
}
|
||||
return $('#topbar').ocmsmenu(m);
|
||||
}
|
||||
/* Menu option CSV builder: 'setm' (Set-Preisanzeige) is only offered while the invoice has not
|
||||
yet been explicitly switched to a set-display mode (admin.setmode empty/undefined) — once set,
|
||||
changing it again is not supported (the user edits the line items directly instead); it
|
||||
reappears only if 'Änderungen verwerfen' reverts to a DB state that was never switched. */
|
||||
$inv.emOpt = (admin) => 'iss,p13b,ctp' + (((admin || {}).setmode || '') === '' ? ',setm' : '');
|
||||
$inv.eM = (r, re, opt) => {
|
||||
let m = [];
|
||||
if (booln(r, false) === true || booln(re, false) === true) {
|
||||
@@ -154,8 +159,24 @@ $inv.d = {
|
||||
let tbl = $inv.d.tbl(); if (tbl.length < 1) { return; }
|
||||
tbl.data('dver', state.version).data('serverSums', state.sums);
|
||||
$inv.d.footer(tbl, state.sums || {}, state.admin || {});
|
||||
$inv.d.notes(state.notes || []);
|
||||
$inv.d.validation(state.validation || []);
|
||||
$inv.d.applyPositions(tbl, state.req || []);
|
||||
$inv.d.applySetDisplay(tbl, state.setDisplay || {});
|
||||
/* Keep the menu's "Set-Preisanzeige" entry in sync with the authoritative admin.setmode:
|
||||
hides it right after a mode switch, and restores it if a discard reverted the draft to
|
||||
a DB state that was never switched (ADR 0006 backend-authoritative refresh). */
|
||||
$inv.eM(false, true, $inv.emOpt(state.admin || {}));
|
||||
},
|
||||
/* Renders the backend-authoritative notice paragraphs (ADR: notice texts are
|
||||
backend-authoritative) exactly as FuchsPdf.BuildInvoiceNotes emits them for the PDF,
|
||||
so the online editor always shows precisely what will be printed. */
|
||||
notes: function (notes) {
|
||||
let frm = $inv.d.layout(); if (frm.length < 1) { return; }
|
||||
let box = frm.children('.dnotes');
|
||||
if (box.length < 1) { box = $$.dc('dnotes'); frm.append(box); }
|
||||
box.empty();
|
||||
(notes || []).forEach((n) => $$.dc('dnote').aC(n.style || 'InvoiceNotes').text(n.text));
|
||||
},
|
||||
/* Push the server's authoritative position numbers back onto the rendered rows so the online
|
||||
editor and the PDF preview always agree (the server numbers priced lines continuously; the
|
||||
@@ -167,6 +188,23 @@ $inv.d = {
|
||||
if (cell.length) { cell.text(co.p != null ? co.p : ''); }
|
||||
}));
|
||||
},
|
||||
/* Applies the backend-authoritative set-pricing display flags (see BuildSetDisplay /
|
||||
InvoiceSetPricing) onto the rendered rows: blanks the price/total cells for lines the
|
||||
server says should show no price (set members in SetPrice mode, the set header in
|
||||
ItemPrices mode), and emphasises the set header line — so the online editor always
|
||||
shows exactly what the PDF will print, without duplicating the pricing rules client-side.
|
||||
Rows not present in the map (no set in that block, or standalone items) are left untouched. */
|
||||
applySetDisplay: function (tbl, setDisplay) {
|
||||
tbl.find('tr.itm').each((i, tr) => {
|
||||
let rw = $(tr), dta = rw.data() || {}, id = (dta.Id || '').toString();
|
||||
if (id === '' || !Object.prototype.hasOwnProperty.call(setDisplay, id)) { return; }
|
||||
let flags = setDisplay[id] || {};
|
||||
rw.tC('sethdr', bool(flags.h, false));
|
||||
if (bool(flags.p, true) === false) {
|
||||
rw.find('td.currency').text('');
|
||||
}
|
||||
});
|
||||
},
|
||||
/* Send one change to the server; the draftReady signal and this success both refresh. */
|
||||
sync: function (delta) {
|
||||
let t = $inv.d.token(); if (t === '') { return; }
|
||||
@@ -354,8 +392,23 @@ $inv.rd = {
|
||||
let tbl = $inv.rd.tbl(); if (tbl.length < 1) { return; }
|
||||
tbl.data('rdver', state.version).data('serverSums', state.sums).data('remid', state.remid || '');
|
||||
$inv.rd.footer(tbl, state.sums || {});
|
||||
$inv.rd.notes(state.notes || {});
|
||||
$inv.rd.validation(state.validation || []);
|
||||
},
|
||||
/* Renders the backend-authoritative intro/closing notice paragraphs (ADR: notice texts
|
||||
are backend-authoritative) exactly as FuchsPdf.BuildReminderNotes emits them for the
|
||||
PDF, so the online editor always shows precisely what will be printed. */
|
||||
notes: function (notes) {
|
||||
let frm = $inv.rd.layout(); if (frm.length < 1) { return; }
|
||||
let rq = frm.find('.srq'); if (rq.length < 1) { return; }
|
||||
rq.children('.dnote').remove();
|
||||
let intro = (notes || {}).intro || [], first = rq.children().first();
|
||||
intro.slice().reverse().forEach((t) => {
|
||||
let p = $$[0]('p').aC('dnote intro').rwText(t);
|
||||
if (first.length) { p.insertBefore(first); } else { p.appendTo(rq); }
|
||||
});
|
||||
((notes || {}).closing || []).forEach((t) => $$[0]('p').aC('dnote closing').rwText(t).appendTo(rq));
|
||||
},
|
||||
/* Send one change to the server; the draftReady signal and this success both refresh. */
|
||||
sync: function (delta) {
|
||||
let t = $inv.rd.token(); if (t === '') { return; }
|
||||
@@ -379,10 +432,13 @@ $inv.rd = {
|
||||
$inv.rd.sync({ Target: 'amount', Value: (amount != null ? amount : 0).toString() });
|
||||
$inv.rd.sync({ Target: 'amount_payed', Value: (amount_payed != null ? amount_payed : 0).toString() });
|
||||
},
|
||||
/* Render the open-amount footer from the server sums. */
|
||||
/* Render the open-amount footer from the server sums. Detail rows ($inv.rRemRw) have
|
||||
6 columns (aux, invoiceid, date, amount, amount_payed, open); span the label over the
|
||||
4 columns between aux and the open-amount column so the total lands in the same last
|
||||
column as the per-invoice open amounts. */
|
||||
footer: function (tbl, sums) {
|
||||
let ft = tbl.children('tfoot').empty();
|
||||
let tr = $$.tr(ft, { class: 'tsum' }).append([$$.tdc('aux'), $$.td({ colspan: 3 }).text('Offener Betrag')]);
|
||||
let tr = $$.tr(ft, { class: 'tsum' }).append([$$.tdc('aux'), $$.td({ colspan: 4 }).text('Offener Betrag')]);
|
||||
$$.tdc('currency', tr, fnum(sums.amount_open || 0, $rct.cst));
|
||||
},
|
||||
validation: function (msgs) {
|
||||
@@ -625,7 +681,7 @@ $inv.ccInv = function (ev) { //normale rechnung
|
||||
rif.tbl.children('tbody').each($inv.bdysort);
|
||||
rif.tbl.trigger('fds.inv'); /* trigger calculations */
|
||||
|
||||
$inv.eM(false, true, 'iss,p13b,setm,ctp');
|
||||
$inv.eM(false, true, $inv.emOpt(admin));
|
||||
}, complete: () => {
|
||||
o.c.trigger('modal_close');
|
||||
}
|
||||
@@ -770,7 +826,7 @@ $inv.cntInv = function (data) { //invoice continuation
|
||||
|
||||
rif.tbl.children('tbody').each($inv.bdysort);
|
||||
rif.tbl.trigger('fds.inv'); /* trigger calculations */
|
||||
$inv.eM(false, true, 'iss,p13b,setm,ctp');
|
||||
$inv.eM(false, true, $inv.emOpt(response.admin));
|
||||
}, complete: () => {
|
||||
o.c.trigger('modal_close');
|
||||
}
|
||||
@@ -970,6 +1026,14 @@ $inv.rrw = function () {
|
||||
if (ph === false) {
|
||||
bc.unshift($$.dc('ibtn edit', { title: $rct.cP }).append(gi('pencil')).click(rw, $inv.eRow));
|
||||
bc.push($$.dc('ibtn del', { title: $rct.dR }).append(gi('trash')).click(function (e) { if (confirm($rct.cD)) { rw.remove(); $inv.t_fds_inv(); } }));
|
||||
/* "Auf Setpreis umstellen": only offered on a Set header item that is not yet
|
||||
priced from its members (fds__prepInvoice's [SetItmId] is null exactly for a
|
||||
Set header — either already set-priced, or not yet converted). Irreversible:
|
||||
sets this row's price to the sum of its members (rows whose [SetItmId] equals
|
||||
this row's id) and clears each member's price. */
|
||||
if ((dta.Type || '').toLowerCase() === 'set' && (dta.SetItmId || '') === '') {
|
||||
bc.push($$.dc('ibtn tosetp', { title: $rct.toSetP }).append(gi('scale')).click(rw, $inv.toSetPrice));
|
||||
}
|
||||
}
|
||||
let axf = $$.dc('axf').append(bc);
|
||||
if (ph === true) {
|
||||
@@ -1015,6 +1079,36 @@ $inv.rrw = function () {
|
||||
rw.empty().attr('class', ph ? 'placeholder' : 'itm').aC(co.Typ).tC('hidenote', hn).append(tda);
|
||||
dta.co = co;
|
||||
};
|
||||
/* "Auf Setpreis umstellen" (see $inv.rrw): sets this Set-header row's price to the sum of
|
||||
its member rows' totals (rows in the same block whose [SetItmId] equals this row's id,
|
||||
the authoritative grouping from fds__prepInvoice), then clears each member's price so the
|
||||
member items show without a price — matching the SetPrice presentation, but as an actual,
|
||||
irreversible data change instead of a display-mode toggle (INVOICE_SET_PRICING.md's
|
||||
setmode remains display-only and is unaffected by this). */
|
||||
$inv.toSetPrice = function (ev) {
|
||||
let rw = ev.data, dta = rw.data(), id = (dta.Id || '').toString();
|
||||
if (id === '') { return; }
|
||||
if (confirm($rct.toSetPc) === false) { return; }
|
||||
let bdy = rw.closest('tbody'), members = bdy.find('tr.itm').filter(function () {
|
||||
return (($(this).data('SetItmId') || '').toString()) === id;
|
||||
});
|
||||
let sum_net_val = 0, sum_vat_val = 0, sum_svcnet_val = 0, sum_svcvat_val = 0;
|
||||
members.each(function () {
|
||||
let m = $(this).data();
|
||||
sum_net_val += (m.net_val || 0);
|
||||
sum_vat_val += (m.vat_val || 0);
|
||||
sum_svcnet_val += (m.svcnet_val || 0);
|
||||
sum_svcvat_val += (m.svcvat_val || 0);
|
||||
$.extend(m, { net: 0, net_val: 0, vat_val: 0, svcnet_val: 0, svcvat_val: 0, Discount: 0 });
|
||||
$inv.rrw.call($(this));
|
||||
});
|
||||
$.extend(dta, {
|
||||
net: sum_net_val, quantityhours: 1, Discount: 0,
|
||||
net_val: sum_net_val, vat_val: sum_vat_val, svcnet_val: sum_svcnet_val, svcvat_val: sum_svcvat_val
|
||||
});
|
||||
$inv.rrw.call(rw);
|
||||
$inv.t_fds_inv();
|
||||
};
|
||||
$inv.invSumUpdate = function () {
|
||||
let tbl = $(this), ft = tbl.children('tfoot').empty(), p13b = bool((tbl.data().admin || {}).p13b || '', false);
|
||||
tbl.nextAll('.fnote').remove();
|
||||
@@ -1541,7 +1635,10 @@ $inv.ccRem_s2 = function (id, sets) { //reminder creation
|
||||
//console.debug(response);
|
||||
let rem = response.rm || {};
|
||||
let rq = $$.dc('srq', frm);
|
||||
$ict.remt[rem.type].forEach(r => $$[0]('p').rwText(r).appendTo(rq));
|
||||
/* Intro/closing notice paragraphs are backend-authoritative (see $inv.rd.notes,
|
||||
populated from FuchsPdf.BuildReminderNotes via rem/dstate after seeding below) —
|
||||
they are appended/prepended into this same .srq container once the draft session
|
||||
is open, so no client-side wording is constructed here. */
|
||||
let rif = $$.tblset({ class: 'invi' }, rq);
|
||||
rif.ft = $$[0]('tfoot');
|
||||
rif.tbl.data($.extend({ invid: rem.invid, new: {} }, response));
|
||||
@@ -1549,7 +1646,6 @@ $inv.ccRem_s2 = function (id, sets) { //reminder creation
|
||||
$ict.remHR.forEach(h => $$.th(thr, h));
|
||||
$inv.rRemRw.call($$.tr(rif.bdy), rif.tbl.data());
|
||||
rif.ft.appendTo(rif.tbl);
|
||||
$ict.remt2[rem.type].forEach(r => $$[0]('p').rwText(r).appendTo(rq));
|
||||
|
||||
let fm = (cls, txt, nme, hd, dta) => {
|
||||
let fr = $$.dc('inpfrm', frm).aC(cls).append(typeof hd === 'string' ? $$.dc('ahd', hd) : (hd > 0 ? $$.dc('ahd', $rct.frm[nme]) : null)), fc = $$.dc('content', fr).rwText(txt);
|
||||
|
||||
Reference in New Issue
Block a user