Add row context menus, fix glyphicon copy corruption, combine CC email editing
- Fuchs/gulpfile.js: pass encoding:false to gulp.src() in the copy task — vinyl-fs otherwise UTF-8-decodes binary files by default, which was silently corrupting the glyphicons webfont (and any other binary asset copyconfig.json matches) on every `gulp copy`/`gulp all` run. - Invoice/reminder editor: replace the row's flat action icons (edit/ delete/insert/set-price) with a single context button opening a dropdown menu, reusing the existing $ocms.menu toolbar mechanism. - Fix "-1" leaking into the Pos. column for Text/Title rows: $inv.rrw's `dta.position || dta.SortOrder` fallback treated the numbering's intentional empty string as unset and fell back to SortOrder (-1 for such rows); now only a genuinely uncomputed position falls back. - Zusatzempfänger (CC) is now edited together with the main invoice email in one combined dialog ($inv.emailFrm/$inv.eEmail), wired into all three entry points (create, continue, storno) instead of a separate hover-revealed row with its own edit target. - Add tooltips to every row/header edit control, including several that had none before (header field pencils, the request/section title edit button), phrased as object+verb ($rct.frmTT). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+5
-1
@@ -147,7 +147,11 @@ gulp.task("copy", async () => {
|
|||||||
const jobs = [];
|
const jobs = [];
|
||||||
for (const cpy of copyconfig) {
|
for (const cpy of copyconfig) {
|
||||||
jobs.push(
|
jobs.push(
|
||||||
pipeline(gulp.src(cpy.src, { allowEmpty: true }), gulp.dest(cpy.dest), preservetimeSafe(), logSink("Copied: "))
|
/* encoding:false is required — vinyl-fs otherwise UTF-8-decodes every file by default,
|
||||||
|
which corrupts binary assets (fonts, etc.) by replacing invalid byte sequences with
|
||||||
|
U+FFFD. This is what silently mangled the glyphicons webfont before (see "Fix
|
||||||
|
corrupted glyphicons webfont files causing decode failures"). */
|
||||||
|
pipeline(gulp.src(cpy.src, { allowEmpty: true, encoding: false }), gulp.dest(cpy.dest), preservetimeSafe(), logSink("Copied: "))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await Promise.all(jobs);
|
await Promise.all(jobs);
|
||||||
|
|||||||
@@ -746,13 +746,13 @@ $inv.ccInv = function (ev) { //normale rechnung
|
|||||||
|
|
||||||
let admin = response.admin || {}, fm = (cls, txt, nme, hd, dta) => {
|
let admin = response.admin || {}, 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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', '', 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
fm('locfrm', '', 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
||||||
fm('emailfrm', admin.invoiceemail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, admin.invoiceemail, admin.invoiceemailcc);
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
||||||
|
|
||||||
let admtxt, admlbl;
|
let admtxt, admlbl;
|
||||||
@@ -821,13 +821,13 @@ $inv.ccStInv = function (ev) { // Stornorechnung
|
|||||||
|
|
||||||
let admin = response.admin || {}, fm = (cls, txt, nme, hd, dta) => {
|
let admin = response.admin || {}, 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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', admin.provisionlocation, 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
fm('locfrm', admin.provisionlocation, 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
||||||
fm('emailfrm', admin.invoiceemail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, admin.invoiceemail, admin.invoiceemailcc);
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
||||||
|
|
||||||
let admtxt, admlbl;
|
let admtxt, admlbl;
|
||||||
@@ -897,14 +897,13 @@ $inv.cntInv = function (data) { //invoice continuation
|
|||||||
|
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
||||||
fm('emailfrm', inv.SendToEmail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, inv.SendToEmail, inv.SendToEmailCc);
|
||||||
fm('emailccfrm', inv.SendToEmailCc, 'invoiceemailcc', 0, null);
|
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
||||||
|
|
||||||
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
||||||
@@ -960,14 +959,13 @@ $inv.cSt = function (data) {
|
|||||||
|
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
||||||
fm('emailfrm', inv.SendToEmail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, inv.SendToEmail, inv.SendToEmailCc);
|
||||||
fm('emailccfrm', inv.SendToEmailCc, 'invoiceemailcc', 0, null);
|
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
||||||
|
|
||||||
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
||||||
@@ -1095,6 +1093,45 @@ $inv.eProvisionPeriod = function (ev) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Main recipient + CC ("Zusatzempfänger") edited together in one dialog — there is no separate
|
||||||
|
pencil on the CC row, only on the email row (see $inv.emailFrm), which passes both content
|
||||||
|
spans through ev.data.t / ev.data.ccT. */
|
||||||
|
$inv.eEmail = function (ev) {
|
||||||
|
let flds = [
|
||||||
|
{ name: 'email', label: $rct.frm.invoiceemail, type: 'text', value: (ev.data.t || $$.s()).text() },
|
||||||
|
{ name: 'emailcc', label: $rct.frm.invoiceemailcc, type: 'text', value: (ev.data.ccT || $$.s()).text() }
|
||||||
|
];
|
||||||
|
$ocms.dlgform(flds, {
|
||||||
|
title: $rct.frm.invoiceemail,
|
||||||
|
success: function (res) {
|
||||||
|
let email = ('' + (res.email || '')).trim(), cc = ('' + (res.emailcc || '')).trim();
|
||||||
|
if (ev.data && ev.data.t) { ev.data.t.text(email); }
|
||||||
|
if (ev.data && ev.data.ccT) { ev.data.ccT.text(cc); }
|
||||||
|
if (typeof (ev.data || {}).change === 'function') { ev.data.change(email); }
|
||||||
|
if (typeof (ev.data || {}).changeCc === 'function') { ev.data.changeCc(cc); }
|
||||||
|
/* backend-authoritative: mirror both fields to the server session (see $inv.eHtml's
|
||||||
|
generic path, which this mirrors for a single field). */
|
||||||
|
$inv.d.syncField('invoiceemail', email);
|
||||||
|
$inv.rd.syncField('invoiceemail', email);
|
||||||
|
$inv.d.syncField('invoiceemailcc', cc);
|
||||||
|
$inv.rd.syncField('invoiceemailcc', cc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/* Builds the email + CC ("Zusatzempfänger") header rows together: only the email row gets a
|
||||||
|
pencil, opening the combined $inv.eEmail dialog for both fields (see there). */
|
||||||
|
$inv.emailFrm = function (frm, rif, email, emailcc) {
|
||||||
|
let ccfr = $$.dc('inpfrm emailccfrm', frm), ccfc = $$.dc('content', ccfr).rwText(emailcc);
|
||||||
|
let efr = $$.dc('inpfrm emailfrm', frm), efc = $$.dc('content', efr).rwText(email);
|
||||||
|
$$.dc('axf', efr).append($$.dc('ibtn edit', { title: $rct.frmTT.invoiceemail }).append(gi('pencil')).click({
|
||||||
|
t: efc, ccT: ccfc, nme: 'invoiceemail',
|
||||||
|
change: (nv) => { rif.tbl.data('new').invoiceemail = nv; },
|
||||||
|
changeCc: (nv) => { rif.tbl.data('new').invoiceemailcc = nv; }
|
||||||
|
}, $inv.eHtml));
|
||||||
|
rif.tbl.data('new').invoiceemail = email;
|
||||||
|
rif.tbl.data('new').invoiceemailcc = emailcc;
|
||||||
|
};
|
||||||
|
|
||||||
$inv.eHtml = function (ev) {
|
$inv.eHtml = function (ev) {
|
||||||
/* The recipient address and the service date/period are edited through structured dialogs
|
/* The recipient address and the service date/period are edited through structured dialogs
|
||||||
whenever an invoice draft is active; reminders (no invoice draft token) keep the plain
|
whenever an invoice draft is active; reminders (no invoice draft token) keep the plain
|
||||||
@@ -1103,6 +1140,9 @@ $inv.eHtml = function (ev) {
|
|||||||
if (ev.data.nme === 'invoiceaddress') { return $inv.eAddress.call(this, ev); }
|
if (ev.data.nme === 'invoiceaddress') { return $inv.eAddress.call(this, ev); }
|
||||||
if (ev.data.nme === 'provisionperiod') { return $inv.eProvisionPeriod.call(this, ev); }
|
if (ev.data.nme === 'provisionperiod') { return $inv.eProvisionPeriod.call(this, ev); }
|
||||||
}
|
}
|
||||||
|
/* The CC/Zusatzempfänger recipient is edited together with the main email, in one dialog —
|
||||||
|
there is no separate pencil on the CC row (see $inv.emailFrm). */
|
||||||
|
if (ev.data && !(ev.data instanceof jQuery) && ev.data.nme === 'invoiceemail' && ev.data.ccT) { return $inv.eEmail.call(this, ev); }
|
||||||
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t;
|
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t;
|
||||||
/* Single-line fields must stay plain text — the TinyMCE/html editor wraps the value in <p>
|
/* Single-line fields must stay plain text — the TinyMCE/html editor wraps the value in <p>
|
||||||
tags, which used to get posted and persisted verbatim (e.g. <p>18.06.2026</p> in the
|
tags, which used to get posted and persisted verbatim (e.g. <p>18.06.2026</p> in the
|
||||||
@@ -1216,15 +1256,29 @@ $inv.eRw = function(row, dta, flds) {
|
|||||||
changed block(s) to the backend session (t_fds_inv -> syncChanged). Committing on drop (rather
|
changed block(s) to the backend session (t_fds_inv -> syncChanged). Committing on drop (rather
|
||||||
than on every mid-drag hover-swap) avoids rebuilding the row that is currently being dragged. */
|
than on every mid-drag hover-swap) avoids rebuilding the row that is currently being dragged. */
|
||||||
$inv.bdysort = (i, e) => { $(e).Sortable({ dragItem: false, dragHandleClass: 'ico', parentident: 'tr', onend: () => { $inv.t_fds_inv(); } }) }
|
$inv.bdysort = (i, e) => { $(e).Sortable({ dragItem: false, dragHandleClass: 'ico', parentident: 'tr', onend: () => { $inv.t_fds_inv(); } }) }
|
||||||
|
/* Single "Kontext-Button" per row/field, opening a dropdown of the row's edit actions
|
||||||
|
(reuses $ocms.menu, the same mechanism that already drives the toolbar menus — see
|
||||||
|
$inv.eM/$inv.iMn). Calling .ocmsmenu() directly on a <nav> we built ourselves (rather than
|
||||||
|
letting $ocms.menu create one inside a bar) keeps our own sizing class instead of being
|
||||||
|
replaced. Every entry carries both its label and a matching `title` tooltip. */
|
||||||
|
$inv.rowCtxMenu = function (items) {
|
||||||
|
let nav = $$[0]('nav').aC('rowctx');
|
||||||
|
nav.ocmsmenu([{ glyph: 'glyphicon-option-vertical', aclass: 'ctxbtn', attr: { title: $rct.ctxM }, itm: items }]);
|
||||||
|
/* $ocms.menu puts `attr` (incl. our title tooltip) on the <li>, not the <a> a viewer actually
|
||||||
|
hovers — mirror it onto the <a> too so the native tooltip is guaranteed to fire regardless
|
||||||
|
of how the browser resolves title on a non-interactive ancestor. */
|
||||||
|
nav.find('li[title]').each(function () { let li = $(this); li.children('a').attr('title', li.attr('title')); });
|
||||||
|
return nav;
|
||||||
|
};
|
||||||
$inv.rrw = function () {
|
$inv.rrw = function () {
|
||||||
let rw = $(this), dta = rw.data(), co = {}, ph = rw.is('.placeholder'), hn = rw.is('.hidenote');
|
let rw = $(this), dta = rw.data(), co = {}, ph = rw.is('.placeholder'), hn = rw.is('.hidenote');
|
||||||
let oHtml = (e) => $$.d().append(e).html();
|
let oHtml = (e) => $$.d().append(e).html();
|
||||||
let bc = [
|
let mi = [
|
||||||
$$.dc('ibtn insb', { title: $rct.iRb }).append(gi('indent-left')).click(rw, $inv.inRow)
|
{ lbl: $rct.iRb, attr: { title: $rct.iRb }, data: rw, fnc: $inv.inRow }
|
||||||
];
|
];
|
||||||
if (ph === false) {
|
if (ph === false) {
|
||||||
bc.unshift($$.dc('ibtn edit', { title: $rct.cP }).append(gi('pencil')).click(rw, $inv.eRow));
|
mi.unshift({ lbl: $rct.cP, attr: { title: $rct.cP }, data: rw, fnc: $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(); } }));
|
mi.push({ lbl: $rct.dR, attr: { title: $rct.dR }, fnc: function (e) { if (confirm($rct.cD)) { rw.remove(); $inv.t_fds_inv(); } } });
|
||||||
/* "Auf Setpreis umstellen": offered on a Set header item that does not yet carry a
|
/* "Auf Setpreis umstellen": offered on a Set header item that does not yet carry a
|
||||||
price. fds__prepInvoice's [SetItmId] now anchors on the still-unconverted (price 0)
|
price. fds__prepInvoice's [SetItmId] now anchors on the still-unconverted (price 0)
|
||||||
header, so the header row's own SetItmId self-references its own id rather than being
|
header, so the header row's own SetItmId self-references its own id rather than being
|
||||||
@@ -1233,10 +1287,10 @@ $inv.rrw = function () {
|
|||||||
Irreversible: the actual sum/clear mutation happens server-side (backend-authoritative,
|
Irreversible: the actual sum/clear mutation happens server-side (backend-authoritative,
|
||||||
see InvoiceDraftEditService.ApplyItemSetPrice) via the "item.setprice" patch target. */
|
see InvoiceDraftEditService.ApplyItemSetPrice) via the "item.setprice" patch target. */
|
||||||
if ((dta.Type || '').toLowerCase() === 'set' && (dta.net_val || 0) === 0) {
|
if ((dta.Type || '').toLowerCase() === 'set' && (dta.net_val || 0) === 0) {
|
||||||
bc.push($$.dc('ibtn tosetp', { title: $rct.toSetP }).append(gi('scale')).click(rw, $inv.toSetPrice));
|
mi.push({ lbl: $rct.toSetP, attr: { title: $rct.toSetP }, data: rw, fnc: $inv.toSetPrice });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let axf = $$.dc('axf').append(bc);
|
let axf = $$.dc('axf').append($inv.rowCtxMenu(mi));
|
||||||
if (ph === true) {
|
if (ph === true) {
|
||||||
co = { id: '', typ: 'placeholder' };
|
co = { id: '', typ: 'placeholder' };
|
||||||
} else if (rw.is('.itm.osum') === true) {
|
} else if (rw.is('.itm.osum') === true) {
|
||||||
@@ -1245,7 +1299,12 @@ $inv.rrw = function () {
|
|||||||
co = { invrqid: dta.InvRqId, id: dta.Id || '', typ: dta.Type || 'other', p: '', q: null, t: '', tt: null, v: null, vt: dta.net_val, vs: dta.svcnet_val, vat: dta.vat, vv: dta.vat_val, vsv: dta.svcvat_val, det: (dta.Note || '') !== '' && hn === false, SetItmId: dta.SetItmId || null, lvl: (dta.lvl || 0) };
|
co = { invrqid: dta.InvRqId, id: dta.Id || '', typ: dta.Type || 'other', p: '', q: null, t: '', tt: null, v: null, vt: dta.net_val, vs: dta.svcnet_val, vat: dta.vat, vv: dta.vat_val, vsv: dta.svcvat_val, det: (dta.Note || '') !== '' && hn === false, SetItmId: dta.SetItmId || null, lvl: (dta.lvl || 0) };
|
||||||
$$.dc('ibtn ico move', axf, { title: $rct.mR }); /* should be the last added */
|
$$.dc('ibtn ico move', axf, { title: $rct.mR }); /* should be the last added */
|
||||||
|
|
||||||
co.p = dta.position || (dta.SortOrder || '');
|
/* dta.position is '' (not unset) for a Text/Title row once invSumUpdate has numbered the
|
||||||
|
invoice (ADR 0017) — an intentional "no number", not a missing value, so it must NOT
|
||||||
|
fall through to SortOrder (which is -1 for such rows and would leak "-1" into Pos.).
|
||||||
|
Only an as-yet-uncomputed row (freshly inserted, before the next invSumUpdate pass)
|
||||||
|
has position === undefined and should still fall back to SortOrder as a placeholder. */
|
||||||
|
co.p = dta.position != null ? dta.position : (dta.SortOrder || '');
|
||||||
if (co.id === '') {
|
if (co.id === '') {
|
||||||
co.t = '';
|
co.t = '';
|
||||||
} else if (['Text', 'Title'].includes(co.typ) && (dta.net_val || 0) === 0) {
|
} else if (['Text', 'Title'].includes(co.typ) && (dta.net_val || 0) === 0) {
|
||||||
@@ -1259,7 +1318,7 @@ $inv.rrw = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((dta.Note || '') !== '') {
|
if ((dta.Note || '') !== '') {
|
||||||
$$.dc('ibtn add', axf).append(gi('object-align-left')).click(function (e) {
|
$$.dc('ibtn add', axf, { title: $rct.noteToggle }).append(gi('object-align-left')).click(function (e) {
|
||||||
$inv.rrw.call(rw.tC('hidenote'));
|
$inv.rrw.call(rw.tC('hidenote'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1404,7 +1463,7 @@ $inv.rendersrq = function () {
|
|||||||
$$.dc('ibtn insb', aux, { title: $rct.iRb }).append(gi('indent-left')).click(rtr, $inv.inRow);
|
$$.dc('ibtn insb', aux, { title: $rct.iRb }).append(gi('indent-left')).click(rtr, $inv.inRow);
|
||||||
let stxt = $$.sc('text', rx.text);
|
let stxt = $$.sc('text', rx.text);
|
||||||
let nme = $$.td(rtr, { colspan: onesum ? 4 : 5 }).append(stxt), oidta, numkeys = ['net_val', 'vat_val', 'svcnet_val', 'svcvat_val', 'net'];
|
let nme = $$.td(rtr, { colspan: onesum ? 4 : 5 }).append(stxt), oidta, numkeys = ['net_val', 'vat_val', 'svcnet_val', 'svcvat_val', 'net'];
|
||||||
$$.dc('ibtn edit', aux).data('dialog', $rcol.req.lbl().Name).append(gi('pencil')).click({ t: stxt, change: (nv) => { rx.text = nv; $inv.t_fds_inv(); } }, $inv.eHtml)
|
$$.dc('ibtn edit', aux, { title: $rct.sectionTitleEditTT }).data('dialog', $rcol.req.lbl().Name).append(gi('pencil')).click({ t: stxt, change: (nv) => { rx.text = nv; $inv.t_fds_inv(); } }, $inv.eHtml)
|
||||||
if (onesum) {
|
if (onesum) {
|
||||||
$$.tdc('currency isumval', rtr);
|
$$.tdc('currency isumval', rtr);
|
||||||
oidta = { Id: rx.Id.toString() + '_osum', net_val: 0, vat_val: 0, svcnet_val: 0, svcvat_val: 0, net: 0 };
|
oidta = { Id: rx.Id.toString() + '_osum', net_val: 0, vat_val: 0, svcnet_val: 0, svcvat_val: 0, net: 0 };
|
||||||
@@ -1781,7 +1840,8 @@ $inv.ccRem = function (id, InvoiceId) { //reminder creation
|
|||||||
$inv.rRemRw = function (dta) {
|
$inv.rRemRw = function (dta) {
|
||||||
let tr = $(this), rem = dta.rm || {};
|
let tr = $(this), rem = dta.rm || {};
|
||||||
tr.empty().data({ invoiceid: rem.invoiceid, invoicedate: rem.invoicedate, amount: rem.amount, amount_payed: rem.amount_payed });
|
tr.empty().data({ invoiceid: rem.invoiceid, invoicedate: rem.invoicedate, amount: rem.amount, amount_payed: rem.amount_payed });
|
||||||
let axf = $$.dc('axf').append($$.dc('ibtn edit', { title: $rct.cP }).append(gi('pencil')).click(tr, $inv.eRowR));
|
let mi = [{ lbl: $rct.cP, attr: { title: $rct.cP }, data: tr, fnc: $inv.eRowR }];
|
||||||
|
let axf = $$.dc('axf').append($inv.rowCtxMenu(mi));
|
||||||
tr.append([$$.tdc('aux').append(axf), $$.tdc('keep', rem.invoiceid), $$.tdc('keep', fdt(rem.invoicedate, 'dd.MM.yy')), $$.tdc('currency', fnum(rem.amount, $rct.cst)), $$.tdc('currency', fnum(rem.amount_payed, $rct.cst)), $$.tdc('currency', fnum(rem.amount - rem.amount_payed, $rct.cst))]);
|
tr.append([$$.tdc('aux').append(axf), $$.tdc('keep', rem.invoiceid), $$.tdc('keep', fdt(rem.invoicedate, 'dd.MM.yy')), $$.tdc('currency', fnum(rem.amount, $rct.cst)), $$.tdc('currency', fnum(rem.amount_payed, $rct.cst)), $$.tdc('currency', fnum(rem.amount - rem.amount_payed, $rct.cst))]);
|
||||||
};
|
};
|
||||||
$inv.eRowR = function (ev) {
|
$inv.eRowR = function (ev) {
|
||||||
@@ -1822,9 +1882,12 @@ $inv.ccRem_s2 = function (id, sets) { //reminder creation
|
|||||||
$inv.rRemRw.call($$.tr(rif.bdy), rif.tbl.data());
|
$inv.rRemRw.call($$.tr(rif.bdy), rif.tbl.data());
|
||||||
rif.ft.appendTo(rif.tbl);
|
rif.ft.appendTo(rif.tbl);
|
||||||
|
|
||||||
|
/* Reminders have no CC/Zusatzempfänger field (see $inv.emailFrm, invoice-only), so the
|
||||||
|
email pencil here keeps a plain tooltip instead of $rct.frmTT.invoiceemail. */
|
||||||
|
let remTT = { invoiceemail: 'Email-Adresse ändern', subject: 'Betreff ändern' };
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: remTT[nme] || $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', rem.subject, 'subject', 0, null);
|
fm('tfrm', rem.subject, 'subject', 0, null);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
max-height: 1.5rem;
|
max-height: 1.5rem;
|
||||||
overflow: hidden;
|
overflow: visible; /* the .rowctx dropdown popout must escape this pill-shaped bar */
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
|
|
||||||
> .ibtn {
|
> .ibtn {
|
||||||
@@ -40,6 +40,51 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Single row "Kontext-Button" opening a dropdown of edit actions (see $inv.rowCtxMenu).
|
||||||
|
Resets the generic full-bar <nav> styling (meant for #topbar/#sidebar) down to a
|
||||||
|
small inline trigger; the dropdown popout itself keeps the shared nav/dropdown-menu
|
||||||
|
look (background, shadow, open/close via $nuf) so it matches every other menu in the app. */
|
||||||
|
nav.rowctx {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
max-height: none;
|
||||||
|
background: transparent;
|
||||||
|
z-index: auto;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
|
> ul {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
height: 100%;
|
||||||
|
float: none;
|
||||||
|
|
||||||
|
> a.ctxbtn {
|
||||||
|
padding: 0;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.3rem;
|
||||||
|
|
||||||
|
> .caret {
|
||||||
|
display: none; /* single kebab trigger, no caret needed */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dropdown > ul.dropdown-menu {
|
||||||
|
top: 100%;
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sndfrm {
|
.sndfrm {
|
||||||
@@ -71,7 +116,6 @@
|
|||||||
min-width: 5rem;
|
min-width: 5rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@@ -81,6 +125,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read-only display: edited together with the email above, via that row's pencil
|
||||||
|
(see $inv.emailFrm / $inv.eEmail) — no pencil/hover-reveal of its own. */
|
||||||
.emailccfrm {
|
.emailccfrm {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
@@ -88,28 +134,10 @@
|
|||||||
left: 0.5rem;
|
left: 0.5rem;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlike the other optional fields (plain "-" placeholder), this one names the action —
|
|
||||||
there is no default "Zusatzempfänger" from MFR, so an empty state must read as an
|
|
||||||
offer to add one, not as missing data. */
|
|
||||||
.content:empty::before {
|
|
||||||
content: 'Zusatzempfänger hinzufügen';
|
|
||||||
min-width: 5rem;
|
|
||||||
height: 1rem;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
div.axf {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.admfrm {
|
.admfrm {
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
sV: 'USt festlegen',
|
sV: 'USt festlegen',
|
||||||
cD: 'Löschen?',
|
cD: 'Löschen?',
|
||||||
mR: 'Zeile verschieben',
|
mR: 'Zeile verschieben',
|
||||||
|
ctxM: 'Weitere Aktionen',
|
||||||
|
noteToggle: 'Notiz ein-/ausblenden',
|
||||||
|
sectionTitleEditTT: 'Auftragsbezeichnung ändern',
|
||||||
svcPart: 'Service-Anteil',
|
svcPart: 'Service-Anteil',
|
||||||
vat: 'Umsatzsteuer',
|
vat: 'Umsatzsteuer',
|
||||||
combP: 'Positionen zusammenfassen',
|
combP: 'Positionen zusammenfassen',
|
||||||
@@ -62,11 +65,21 @@
|
|||||||
, '-': '-'
|
, '-': '-'
|
||||||
}, invHR: ['Pos.', 'Menge', 'Artikelbezeichnung', 'VK', 'Summe']
|
}, invHR: ['Pos.', 'Menge', 'Artikelbezeichnung', 'VK', 'Summe']
|
||||||
, frm: {
|
, frm: {
|
||||||
invoiceaddress: 'Adresse'
|
invoicetitle: 'Titel'
|
||||||
|
, invoiceaddress: 'Adresse'
|
||||||
, loc: 'Leistungsort / Lieferadresse'
|
, loc: 'Leistungsort / Lieferadresse'
|
||||||
, invoiceemail: 'Email'
|
, invoiceemail: 'Email'
|
||||||
, invoiceemailcc: 'Zusatzempfänger (CC)'
|
, invoiceemailcc: 'Zusatzempfänger (CC)'
|
||||||
|
, provisionperiod: 'Leistungsdatum / -zeitraum'
|
||||||
|
}
|
||||||
|
/* Tooltip text for each header-field pencil — object+verb phrasing ("<was> <tun>"),
|
||||||
|
distinct from frm[] above (used for dialog titles / field labels, which stay short nouns). */
|
||||||
|
, frmTT: {
|
||||||
|
invoicetitle: 'Rechnungstitel ändern'
|
||||||
|
, invoiceaddress: 'Rechnungsempfänger-Adresse ändern'
|
||||||
|
, loc: 'Leistungsort oder Lieferadresse ändern'
|
||||||
|
, invoiceemail: 'Email-Adresse ändern und zusätzliche Email-Empfänger festlegen'
|
||||||
|
, provisionperiod: 'Leistungsdatum oder -zeitraum ändern'
|
||||||
}
|
}
|
||||||
}, $rcol = {
|
}, $rcol = {
|
||||||
req: new fields_definition('Auftrag', 'Aufträge', [
|
req: new fields_definition('Auftrag', 'Aufträge', [
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ table.if td.num {
|
|||||||
top: 0;
|
top: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
max-height: 1.5rem;
|
max-height: 1.5rem;
|
||||||
overflow: hidden;
|
overflow: visible; /* the .rowctx dropdown popout must escape this pill-shaped bar */
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
}
|
}
|
||||||
.edit_frm .invoice_layout .axf > .ibtn {
|
.edit_frm .invoice_layout .axf > .ibtn {
|
||||||
@@ -138,6 +138,47 @@ table.if td.num {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.edit_frm .invoice_layout .axf {
|
||||||
|
/* Single row "Kontext-Button" opening a dropdown of edit actions (see $inv.rowCtxMenu).
|
||||||
|
Resets the generic full-bar <nav> styling (meant for #topbar/#sidebar) down to a
|
||||||
|
small inline trigger; the dropdown popout itself keeps the shared nav/dropdown-menu
|
||||||
|
look (background, shadow, open/close via $nuf) so it matches every other menu in the app. */
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
max-height: none;
|
||||||
|
background: transparent;
|
||||||
|
z-index: auto;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul > li {
|
||||||
|
height: 100%;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul > li > a.ctxbtn {
|
||||||
|
padding: 0;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.3rem;
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul > li > a.ctxbtn > .caret {
|
||||||
|
display: none; /* single kebab trigger, no caret needed */
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul > li.dropdown > ul.dropdown-menu {
|
||||||
|
top: 100%;
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
.edit_frm .invoice_layout .sndfrm {
|
.edit_frm .invoice_layout .sndfrm {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
@@ -165,11 +206,14 @@ table.if td.num {
|
|||||||
min-width: 5rem;
|
min-width: 5rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
|
||||||
}
|
}
|
||||||
.edit_frm .invoice_layout .emailfrm:hover div.axf {
|
.edit_frm .invoice_layout .emailfrm:hover div.axf {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.edit_frm .invoice_layout {
|
||||||
|
/* Read-only display: edited together with the email above, via that row's pencil
|
||||||
|
(see $inv.emailFrm / $inv.eEmail) — no pencil/hover-reveal of its own. */
|
||||||
|
}
|
||||||
.edit_frm .invoice_layout .emailccfrm {
|
.edit_frm .invoice_layout .emailccfrm {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
@@ -177,26 +221,10 @@ table.if td.num {
|
|||||||
left: 0.5rem;
|
left: 0.5rem;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
.edit_frm .invoice_layout .emailccfrm .content {
|
.edit_frm .invoice_layout .emailccfrm .content {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.edit_frm .invoice_layout .emailccfrm {
|
|
||||||
/* Unlike the other optional fields (plain "-" placeholder), this one names the action —
|
|
||||||
there is no default "Zusatzempfänger" from MFR, so an empty state must read as an
|
|
||||||
offer to add one, not as missing data. */
|
|
||||||
}
|
|
||||||
.edit_frm .invoice_layout .emailccfrm .content:empty::before {
|
|
||||||
content: "Zusatzempfänger hinzufügen";
|
|
||||||
min-width: 5rem;
|
|
||||||
height: 1rem;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.edit_frm .invoice_layout .emailccfrm:hover div.axf {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.edit_frm .invoice_layout .admfrm {
|
.edit_frm .invoice_layout .admfrm {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 3rem;
|
right: 3rem;
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ let $rct = {
|
|||||||
sV: 'USt festlegen',
|
sV: 'USt festlegen',
|
||||||
cD: 'Löschen?',
|
cD: 'Löschen?',
|
||||||
mR: 'Zeile verschieben',
|
mR: 'Zeile verschieben',
|
||||||
|
ctxM: 'Weitere Aktionen',
|
||||||
|
noteToggle: 'Notiz ein-/ausblenden',
|
||||||
|
sectionTitleEditTT: 'Auftragsbezeichnung ändern',
|
||||||
svcPart: 'Service-Anteil',
|
svcPart: 'Service-Anteil',
|
||||||
vat: 'Umsatzsteuer',
|
vat: 'Umsatzsteuer',
|
||||||
combP: 'Positionen zusammenfassen',
|
combP: 'Positionen zusammenfassen',
|
||||||
@@ -62,11 +65,21 @@ let $rct = {
|
|||||||
, '-': '-'
|
, '-': '-'
|
||||||
}, invHR: ['Pos.', 'Menge', 'Artikelbezeichnung', 'VK', 'Summe']
|
}, invHR: ['Pos.', 'Menge', 'Artikelbezeichnung', 'VK', 'Summe']
|
||||||
, frm: {
|
, frm: {
|
||||||
invoiceaddress: 'Adresse'
|
invoicetitle: 'Titel'
|
||||||
|
, invoiceaddress: 'Adresse'
|
||||||
, loc: 'Leistungsort / Lieferadresse'
|
, loc: 'Leistungsort / Lieferadresse'
|
||||||
, invoiceemail: 'Email'
|
, invoiceemail: 'Email'
|
||||||
, invoiceemailcc: 'Zusatzempfänger (CC)'
|
, invoiceemailcc: 'Zusatzempfänger (CC)'
|
||||||
|
, provisionperiod: 'Leistungsdatum / -zeitraum'
|
||||||
|
}
|
||||||
|
/* Tooltip text for each header-field pencil — object+verb phrasing ("<was> <tun>"),
|
||||||
|
distinct from frm[] above (used for dialog titles / field labels, which stay short nouns). */
|
||||||
|
, frmTT: {
|
||||||
|
invoicetitle: 'Rechnungstitel ändern'
|
||||||
|
, invoiceaddress: 'Rechnungsempfänger-Adresse ändern'
|
||||||
|
, loc: 'Leistungsort oder Lieferadresse ändern'
|
||||||
|
, invoiceemail: 'Email-Adresse ändern und zusätzliche Email-Empfänger festlegen'
|
||||||
|
, provisionperiod: 'Leistungsdatum oder -zeitraum ändern'
|
||||||
}
|
}
|
||||||
}, $rcol = {
|
}, $rcol = {
|
||||||
req: new fields_definition('Auftrag', 'Aufträge', [
|
req: new fields_definition('Auftrag', 'Aufträge', [
|
||||||
@@ -1308,13 +1321,13 @@ $inv.ccInv = function (ev) { //normale rechnung
|
|||||||
|
|
||||||
let admin = response.admin || {}, fm = (cls, txt, nme, hd, dta) => {
|
let admin = response.admin || {}, 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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', '', 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
fm('locfrm', '', 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
||||||
fm('emailfrm', admin.invoiceemail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, admin.invoiceemail, admin.invoiceemailcc);
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
||||||
|
|
||||||
let admtxt, admlbl;
|
let admtxt, admlbl;
|
||||||
@@ -1383,13 +1396,13 @@ $inv.ccStInv = function (ev) { // Stornorechnung
|
|||||||
|
|
||||||
let admin = response.admin || {}, fm = (cls, txt, nme, hd, dta) => {
|
let admin = response.admin || {}, 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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', admin.provisionlocation, 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
fm('locfrm', admin.provisionlocation, 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
||||||
fm('emailfrm', admin.invoiceemail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, admin.invoiceemail, admin.invoiceemailcc);
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
||||||
|
|
||||||
let admtxt, admlbl;
|
let admtxt, admlbl;
|
||||||
@@ -1459,14 +1472,13 @@ $inv.cntInv = function (data) { //invoice continuation
|
|||||||
|
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
||||||
fm('emailfrm', inv.SendToEmail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, inv.SendToEmail, inv.SendToEmailCc);
|
||||||
fm('emailccfrm', inv.SendToEmailCc, 'invoiceemailcc', 0, null);
|
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
||||||
|
|
||||||
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
||||||
@@ -1522,14 +1534,13 @@ $inv.cSt = function (data) {
|
|||||||
|
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
||||||
fm('emailfrm', inv.SendToEmail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, inv.SendToEmail, inv.SendToEmailCc);
|
||||||
fm('emailccfrm', inv.SendToEmailCc, 'invoiceemailcc', 0, null);
|
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
||||||
|
|
||||||
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
||||||
@@ -1657,6 +1668,45 @@ $inv.eProvisionPeriod = function (ev) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Main recipient + CC ("Zusatzempfänger") edited together in one dialog — there is no separate
|
||||||
|
pencil on the CC row, only on the email row (see $inv.emailFrm), which passes both content
|
||||||
|
spans through ev.data.t / ev.data.ccT. */
|
||||||
|
$inv.eEmail = function (ev) {
|
||||||
|
let flds = [
|
||||||
|
{ name: 'email', label: $rct.frm.invoiceemail, type: 'text', value: (ev.data.t || $$.s()).text() },
|
||||||
|
{ name: 'emailcc', label: $rct.frm.invoiceemailcc, type: 'text', value: (ev.data.ccT || $$.s()).text() }
|
||||||
|
];
|
||||||
|
$ocms.dlgform(flds, {
|
||||||
|
title: $rct.frm.invoiceemail,
|
||||||
|
success: function (res) {
|
||||||
|
let email = ('' + (res.email || '')).trim(), cc = ('' + (res.emailcc || '')).trim();
|
||||||
|
if (ev.data && ev.data.t) { ev.data.t.text(email); }
|
||||||
|
if (ev.data && ev.data.ccT) { ev.data.ccT.text(cc); }
|
||||||
|
if (typeof (ev.data || {}).change === 'function') { ev.data.change(email); }
|
||||||
|
if (typeof (ev.data || {}).changeCc === 'function') { ev.data.changeCc(cc); }
|
||||||
|
/* backend-authoritative: mirror both fields to the server session (see $inv.eHtml's
|
||||||
|
generic path, which this mirrors for a single field). */
|
||||||
|
$inv.d.syncField('invoiceemail', email);
|
||||||
|
$inv.rd.syncField('invoiceemail', email);
|
||||||
|
$inv.d.syncField('invoiceemailcc', cc);
|
||||||
|
$inv.rd.syncField('invoiceemailcc', cc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/* Builds the email + CC ("Zusatzempfänger") header rows together: only the email row gets a
|
||||||
|
pencil, opening the combined $inv.eEmail dialog for both fields (see there). */
|
||||||
|
$inv.emailFrm = function (frm, rif, email, emailcc) {
|
||||||
|
let ccfr = $$.dc('inpfrm emailccfrm', frm), ccfc = $$.dc('content', ccfr).rwText(emailcc);
|
||||||
|
let efr = $$.dc('inpfrm emailfrm', frm), efc = $$.dc('content', efr).rwText(email);
|
||||||
|
$$.dc('axf', efr).append($$.dc('ibtn edit', { title: $rct.frmTT.invoiceemail }).append(gi('pencil')).click({
|
||||||
|
t: efc, ccT: ccfc, nme: 'invoiceemail',
|
||||||
|
change: (nv) => { rif.tbl.data('new').invoiceemail = nv; },
|
||||||
|
changeCc: (nv) => { rif.tbl.data('new').invoiceemailcc = nv; }
|
||||||
|
}, $inv.eHtml));
|
||||||
|
rif.tbl.data('new').invoiceemail = email;
|
||||||
|
rif.tbl.data('new').invoiceemailcc = emailcc;
|
||||||
|
};
|
||||||
|
|
||||||
$inv.eHtml = function (ev) {
|
$inv.eHtml = function (ev) {
|
||||||
/* The recipient address and the service date/period are edited through structured dialogs
|
/* The recipient address and the service date/period are edited through structured dialogs
|
||||||
whenever an invoice draft is active; reminders (no invoice draft token) keep the plain
|
whenever an invoice draft is active; reminders (no invoice draft token) keep the plain
|
||||||
@@ -1665,6 +1715,9 @@ $inv.eHtml = function (ev) {
|
|||||||
if (ev.data.nme === 'invoiceaddress') { return $inv.eAddress.call(this, ev); }
|
if (ev.data.nme === 'invoiceaddress') { return $inv.eAddress.call(this, ev); }
|
||||||
if (ev.data.nme === 'provisionperiod') { return $inv.eProvisionPeriod.call(this, ev); }
|
if (ev.data.nme === 'provisionperiod') { return $inv.eProvisionPeriod.call(this, ev); }
|
||||||
}
|
}
|
||||||
|
/* The CC/Zusatzempfänger recipient is edited together with the main email, in one dialog —
|
||||||
|
there is no separate pencil on the CC row (see $inv.emailFrm). */
|
||||||
|
if (ev.data && !(ev.data instanceof jQuery) && ev.data.nme === 'invoiceemail' && ev.data.ccT) { return $inv.eEmail.call(this, ev); }
|
||||||
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t;
|
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t;
|
||||||
/* Single-line fields must stay plain text — the TinyMCE/html editor wraps the value in <p>
|
/* Single-line fields must stay plain text — the TinyMCE/html editor wraps the value in <p>
|
||||||
tags, which used to get posted and persisted verbatim (e.g. <p>18.06.2026</p> in the
|
tags, which used to get posted and persisted verbatim (e.g. <p>18.06.2026</p> in the
|
||||||
@@ -1778,15 +1831,29 @@ $inv.eRw = function(row, dta, flds) {
|
|||||||
changed block(s) to the backend session (t_fds_inv -> syncChanged). Committing on drop (rather
|
changed block(s) to the backend session (t_fds_inv -> syncChanged). Committing on drop (rather
|
||||||
than on every mid-drag hover-swap) avoids rebuilding the row that is currently being dragged. */
|
than on every mid-drag hover-swap) avoids rebuilding the row that is currently being dragged. */
|
||||||
$inv.bdysort = (i, e) => { $(e).Sortable({ dragItem: false, dragHandleClass: 'ico', parentident: 'tr', onend: () => { $inv.t_fds_inv(); } }) }
|
$inv.bdysort = (i, e) => { $(e).Sortable({ dragItem: false, dragHandleClass: 'ico', parentident: 'tr', onend: () => { $inv.t_fds_inv(); } }) }
|
||||||
|
/* Single "Kontext-Button" per row/field, opening a dropdown of the row's edit actions
|
||||||
|
(reuses $ocms.menu, the same mechanism that already drives the toolbar menus — see
|
||||||
|
$inv.eM/$inv.iMn). Calling .ocmsmenu() directly on a <nav> we built ourselves (rather than
|
||||||
|
letting $ocms.menu create one inside a bar) keeps our own sizing class instead of being
|
||||||
|
replaced. Every entry carries both its label and a matching `title` tooltip. */
|
||||||
|
$inv.rowCtxMenu = function (items) {
|
||||||
|
let nav = $$[0]('nav').aC('rowctx');
|
||||||
|
nav.ocmsmenu([{ glyph: 'glyphicon-option-vertical', aclass: 'ctxbtn', attr: { title: $rct.ctxM }, itm: items }]);
|
||||||
|
/* $ocms.menu puts `attr` (incl. our title tooltip) on the <li>, not the <a> a viewer actually
|
||||||
|
hovers — mirror it onto the <a> too so the native tooltip is guaranteed to fire regardless
|
||||||
|
of how the browser resolves title on a non-interactive ancestor. */
|
||||||
|
nav.find('li[title]').each(function () { let li = $(this); li.children('a').attr('title', li.attr('title')); });
|
||||||
|
return nav;
|
||||||
|
};
|
||||||
$inv.rrw = function () {
|
$inv.rrw = function () {
|
||||||
let rw = $(this), dta = rw.data(), co = {}, ph = rw.is('.placeholder'), hn = rw.is('.hidenote');
|
let rw = $(this), dta = rw.data(), co = {}, ph = rw.is('.placeholder'), hn = rw.is('.hidenote');
|
||||||
let oHtml = (e) => $$.d().append(e).html();
|
let oHtml = (e) => $$.d().append(e).html();
|
||||||
let bc = [
|
let mi = [
|
||||||
$$.dc('ibtn insb', { title: $rct.iRb }).append(gi('indent-left')).click(rw, $inv.inRow)
|
{ lbl: $rct.iRb, attr: { title: $rct.iRb }, data: rw, fnc: $inv.inRow }
|
||||||
];
|
];
|
||||||
if (ph === false) {
|
if (ph === false) {
|
||||||
bc.unshift($$.dc('ibtn edit', { title: $rct.cP }).append(gi('pencil')).click(rw, $inv.eRow));
|
mi.unshift({ lbl: $rct.cP, attr: { title: $rct.cP }, data: rw, fnc: $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(); } }));
|
mi.push({ lbl: $rct.dR, attr: { title: $rct.dR }, fnc: function (e) { if (confirm($rct.cD)) { rw.remove(); $inv.t_fds_inv(); } } });
|
||||||
/* "Auf Setpreis umstellen": offered on a Set header item that does not yet carry a
|
/* "Auf Setpreis umstellen": offered on a Set header item that does not yet carry a
|
||||||
price. fds__prepInvoice's [SetItmId] now anchors on the still-unconverted (price 0)
|
price. fds__prepInvoice's [SetItmId] now anchors on the still-unconverted (price 0)
|
||||||
header, so the header row's own SetItmId self-references its own id rather than being
|
header, so the header row's own SetItmId self-references its own id rather than being
|
||||||
@@ -1795,10 +1862,10 @@ $inv.rrw = function () {
|
|||||||
Irreversible: the actual sum/clear mutation happens server-side (backend-authoritative,
|
Irreversible: the actual sum/clear mutation happens server-side (backend-authoritative,
|
||||||
see InvoiceDraftEditService.ApplyItemSetPrice) via the "item.setprice" patch target. */
|
see InvoiceDraftEditService.ApplyItemSetPrice) via the "item.setprice" patch target. */
|
||||||
if ((dta.Type || '').toLowerCase() === 'set' && (dta.net_val || 0) === 0) {
|
if ((dta.Type || '').toLowerCase() === 'set' && (dta.net_val || 0) === 0) {
|
||||||
bc.push($$.dc('ibtn tosetp', { title: $rct.toSetP }).append(gi('scale')).click(rw, $inv.toSetPrice));
|
mi.push({ lbl: $rct.toSetP, attr: { title: $rct.toSetP }, data: rw, fnc: $inv.toSetPrice });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let axf = $$.dc('axf').append(bc);
|
let axf = $$.dc('axf').append($inv.rowCtxMenu(mi));
|
||||||
if (ph === true) {
|
if (ph === true) {
|
||||||
co = { id: '', typ: 'placeholder' };
|
co = { id: '', typ: 'placeholder' };
|
||||||
} else if (rw.is('.itm.osum') === true) {
|
} else if (rw.is('.itm.osum') === true) {
|
||||||
@@ -1807,7 +1874,12 @@ $inv.rrw = function () {
|
|||||||
co = { invrqid: dta.InvRqId, id: dta.Id || '', typ: dta.Type || 'other', p: '', q: null, t: '', tt: null, v: null, vt: dta.net_val, vs: dta.svcnet_val, vat: dta.vat, vv: dta.vat_val, vsv: dta.svcvat_val, det: (dta.Note || '') !== '' && hn === false, SetItmId: dta.SetItmId || null, lvl: (dta.lvl || 0) };
|
co = { invrqid: dta.InvRqId, id: dta.Id || '', typ: dta.Type || 'other', p: '', q: null, t: '', tt: null, v: null, vt: dta.net_val, vs: dta.svcnet_val, vat: dta.vat, vv: dta.vat_val, vsv: dta.svcvat_val, det: (dta.Note || '') !== '' && hn === false, SetItmId: dta.SetItmId || null, lvl: (dta.lvl || 0) };
|
||||||
$$.dc('ibtn ico move', axf, { title: $rct.mR }); /* should be the last added */
|
$$.dc('ibtn ico move', axf, { title: $rct.mR }); /* should be the last added */
|
||||||
|
|
||||||
co.p = dta.position || (dta.SortOrder || '');
|
/* dta.position is '' (not unset) for a Text/Title row once invSumUpdate has numbered the
|
||||||
|
invoice (ADR 0017) — an intentional "no number", not a missing value, so it must NOT
|
||||||
|
fall through to SortOrder (which is -1 for such rows and would leak "-1" into Pos.).
|
||||||
|
Only an as-yet-uncomputed row (freshly inserted, before the next invSumUpdate pass)
|
||||||
|
has position === undefined and should still fall back to SortOrder as a placeholder. */
|
||||||
|
co.p = dta.position != null ? dta.position : (dta.SortOrder || '');
|
||||||
if (co.id === '') {
|
if (co.id === '') {
|
||||||
co.t = '';
|
co.t = '';
|
||||||
} else if (['Text', 'Title'].includes(co.typ) && (dta.net_val || 0) === 0) {
|
} else if (['Text', 'Title'].includes(co.typ) && (dta.net_val || 0) === 0) {
|
||||||
@@ -1821,7 +1893,7 @@ $inv.rrw = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((dta.Note || '') !== '') {
|
if ((dta.Note || '') !== '') {
|
||||||
$$.dc('ibtn add', axf).append(gi('object-align-left')).click(function (e) {
|
$$.dc('ibtn add', axf, { title: $rct.noteToggle }).append(gi('object-align-left')).click(function (e) {
|
||||||
$inv.rrw.call(rw.tC('hidenote'));
|
$inv.rrw.call(rw.tC('hidenote'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1966,7 +2038,7 @@ $inv.rendersrq = function () {
|
|||||||
$$.dc('ibtn insb', aux, { title: $rct.iRb }).append(gi('indent-left')).click(rtr, $inv.inRow);
|
$$.dc('ibtn insb', aux, { title: $rct.iRb }).append(gi('indent-left')).click(rtr, $inv.inRow);
|
||||||
let stxt = $$.sc('text', rx.text);
|
let stxt = $$.sc('text', rx.text);
|
||||||
let nme = $$.td(rtr, { colspan: onesum ? 4 : 5 }).append(stxt), oidta, numkeys = ['net_val', 'vat_val', 'svcnet_val', 'svcvat_val', 'net'];
|
let nme = $$.td(rtr, { colspan: onesum ? 4 : 5 }).append(stxt), oidta, numkeys = ['net_val', 'vat_val', 'svcnet_val', 'svcvat_val', 'net'];
|
||||||
$$.dc('ibtn edit', aux).data('dialog', $rcol.req.lbl().Name).append(gi('pencil')).click({ t: stxt, change: (nv) => { rx.text = nv; $inv.t_fds_inv(); } }, $inv.eHtml)
|
$$.dc('ibtn edit', aux, { title: $rct.sectionTitleEditTT }).data('dialog', $rcol.req.lbl().Name).append(gi('pencil')).click({ t: stxt, change: (nv) => { rx.text = nv; $inv.t_fds_inv(); } }, $inv.eHtml)
|
||||||
if (onesum) {
|
if (onesum) {
|
||||||
$$.tdc('currency isumval', rtr);
|
$$.tdc('currency isumval', rtr);
|
||||||
oidta = { Id: rx.Id.toString() + '_osum', net_val: 0, vat_val: 0, svcnet_val: 0, svcvat_val: 0, net: 0 };
|
oidta = { Id: rx.Id.toString() + '_osum', net_val: 0, vat_val: 0, svcnet_val: 0, svcvat_val: 0, net: 0 };
|
||||||
@@ -2343,7 +2415,8 @@ $inv.ccRem = function (id, InvoiceId) { //reminder creation
|
|||||||
$inv.rRemRw = function (dta) {
|
$inv.rRemRw = function (dta) {
|
||||||
let tr = $(this), rem = dta.rm || {};
|
let tr = $(this), rem = dta.rm || {};
|
||||||
tr.empty().data({ invoiceid: rem.invoiceid, invoicedate: rem.invoicedate, amount: rem.amount, amount_payed: rem.amount_payed });
|
tr.empty().data({ invoiceid: rem.invoiceid, invoicedate: rem.invoicedate, amount: rem.amount, amount_payed: rem.amount_payed });
|
||||||
let axf = $$.dc('axf').append($$.dc('ibtn edit', { title: $rct.cP }).append(gi('pencil')).click(tr, $inv.eRowR));
|
let mi = [{ lbl: $rct.cP, attr: { title: $rct.cP }, data: tr, fnc: $inv.eRowR }];
|
||||||
|
let axf = $$.dc('axf').append($inv.rowCtxMenu(mi));
|
||||||
tr.append([$$.tdc('aux').append(axf), $$.tdc('keep', rem.invoiceid), $$.tdc('keep', fdt(rem.invoicedate, 'dd.MM.yy')), $$.tdc('currency', fnum(rem.amount, $rct.cst)), $$.tdc('currency', fnum(rem.amount_payed, $rct.cst)), $$.tdc('currency', fnum(rem.amount - rem.amount_payed, $rct.cst))]);
|
tr.append([$$.tdc('aux').append(axf), $$.tdc('keep', rem.invoiceid), $$.tdc('keep', fdt(rem.invoicedate, 'dd.MM.yy')), $$.tdc('currency', fnum(rem.amount, $rct.cst)), $$.tdc('currency', fnum(rem.amount_payed, $rct.cst)), $$.tdc('currency', fnum(rem.amount - rem.amount_payed, $rct.cst))]);
|
||||||
};
|
};
|
||||||
$inv.eRowR = function (ev) {
|
$inv.eRowR = function (ev) {
|
||||||
@@ -2384,9 +2457,12 @@ $inv.ccRem_s2 = function (id, sets) { //reminder creation
|
|||||||
$inv.rRemRw.call($$.tr(rif.bdy), rif.tbl.data());
|
$inv.rRemRw.call($$.tr(rif.bdy), rif.tbl.data());
|
||||||
rif.ft.appendTo(rif.tbl);
|
rif.ft.appendTo(rif.tbl);
|
||||||
|
|
||||||
|
/* Reminders have no CC/Zusatzempfänger field (see $inv.emailFrm, invoice-only), so the
|
||||||
|
email pencil here keeps a plain tooltip instead of $rct.frmTT.invoiceemail. */
|
||||||
|
let remTT = { invoiceemail: 'Email-Adresse ändern', subject: 'Betreff ändern' };
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: remTT[nme] || $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', rem.subject, 'subject', 0, null);
|
fm('tfrm', rem.subject, 'subject', 0, null);
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -265,7 +265,7 @@ table.if th.keep, table.if td.keep {
|
|||||||
top: 0;
|
top: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
max-height: 1.5rem;
|
max-height: 1.5rem;
|
||||||
overflow: hidden;
|
overflow: visible; /* the .rowctx dropdown popout must escape this pill-shaped bar */
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
}
|
}
|
||||||
.edit_frm .invoice_layout .axf > .ibtn {
|
.edit_frm .invoice_layout .axf > .ibtn {
|
||||||
@@ -275,6 +275,47 @@ table.if th.keep, table.if td.keep {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.edit_frm .invoice_layout .axf {
|
||||||
|
/* Single row "Kontext-Button" opening a dropdown of edit actions (see $inv.rowCtxMenu).
|
||||||
|
Resets the generic full-bar <nav> styling (meant for #topbar/#sidebar) down to a
|
||||||
|
small inline trigger; the dropdown popout itself keeps the shared nav/dropdown-menu
|
||||||
|
look (background, shadow, open/close via $nuf) so it matches every other menu in the app. */
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
max-height: none;
|
||||||
|
background: transparent;
|
||||||
|
z-index: auto;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul > li {
|
||||||
|
height: 100%;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul > li > a.ctxbtn {
|
||||||
|
padding: 0;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.3rem;
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul > li > a.ctxbtn > .caret {
|
||||||
|
display: none; /* single kebab trigger, no caret needed */
|
||||||
|
}
|
||||||
|
.edit_frm .invoice_layout .axf nav.rowctx > ul > li.dropdown > ul.dropdown-menu {
|
||||||
|
top: 100%;
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
.edit_frm .invoice_layout .sndfrm {
|
.edit_frm .invoice_layout .sndfrm {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
@@ -302,11 +343,14 @@ table.if th.keep, table.if td.keep {
|
|||||||
min-width: 5rem;
|
min-width: 5rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
|
||||||
}
|
}
|
||||||
.edit_frm .invoice_layout .emailfrm:hover div.axf {
|
.edit_frm .invoice_layout .emailfrm:hover div.axf {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.edit_frm .invoice_layout {
|
||||||
|
/* Read-only display: edited together with the email above, via that row's pencil
|
||||||
|
(see $inv.emailFrm / $inv.eEmail) — no pencil/hover-reveal of its own. */
|
||||||
|
}
|
||||||
.edit_frm .invoice_layout .emailccfrm {
|
.edit_frm .invoice_layout .emailccfrm {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
@@ -314,26 +358,10 @@ table.if th.keep, table.if td.keep {
|
|||||||
left: 0.5rem;
|
left: 0.5rem;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
.edit_frm .invoice_layout .emailccfrm .content {
|
.edit_frm .invoice_layout .emailccfrm .content {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
.edit_frm .invoice_layout .emailccfrm {
|
|
||||||
/* Unlike the other optional fields (plain "-" placeholder), this one names the action —
|
|
||||||
there is no default "Zusatzempfänger" from MFR, so an empty state must read as an
|
|
||||||
offer to add one, not as missing data. */
|
|
||||||
}
|
|
||||||
.edit_frm .invoice_layout .emailccfrm .content:empty::before {
|
|
||||||
content: "Zusatzempfänger hinzufügen";
|
|
||||||
min-width: 5rem;
|
|
||||||
height: 1rem;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.edit_frm .invoice_layout .emailccfrm:hover div.axf {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.edit_frm .invoice_layout .admfrm {
|
.edit_frm .invoice_layout .admfrm {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 3rem;
|
right: 3rem;
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ let $rct = {
|
|||||||
sV: 'USt festlegen',
|
sV: 'USt festlegen',
|
||||||
cD: 'Löschen?',
|
cD: 'Löschen?',
|
||||||
mR: 'Zeile verschieben',
|
mR: 'Zeile verschieben',
|
||||||
|
ctxM: 'Weitere Aktionen',
|
||||||
|
noteToggle: 'Notiz ein-/ausblenden',
|
||||||
|
sectionTitleEditTT: 'Auftragsbezeichnung ändern',
|
||||||
svcPart: 'Service-Anteil',
|
svcPart: 'Service-Anteil',
|
||||||
vat: 'Umsatzsteuer',
|
vat: 'Umsatzsteuer',
|
||||||
combP: 'Positionen zusammenfassen',
|
combP: 'Positionen zusammenfassen',
|
||||||
@@ -62,11 +65,21 @@ let $rct = {
|
|||||||
, '-': '-'
|
, '-': '-'
|
||||||
}, invHR: ['Pos.', 'Menge', 'Artikelbezeichnung', 'VK', 'Summe']
|
}, invHR: ['Pos.', 'Menge', 'Artikelbezeichnung', 'VK', 'Summe']
|
||||||
, frm: {
|
, frm: {
|
||||||
invoiceaddress: 'Adresse'
|
invoicetitle: 'Titel'
|
||||||
|
, invoiceaddress: 'Adresse'
|
||||||
, loc: 'Leistungsort / Lieferadresse'
|
, loc: 'Leistungsort / Lieferadresse'
|
||||||
, invoiceemail: 'Email'
|
, invoiceemail: 'Email'
|
||||||
, invoiceemailcc: 'Zusatzempfänger (CC)'
|
, invoiceemailcc: 'Zusatzempfänger (CC)'
|
||||||
|
, provisionperiod: 'Leistungsdatum / -zeitraum'
|
||||||
|
}
|
||||||
|
/* Tooltip text for each header-field pencil — object+verb phrasing ("<was> <tun>"),
|
||||||
|
distinct from frm[] above (used for dialog titles / field labels, which stay short nouns). */
|
||||||
|
, frmTT: {
|
||||||
|
invoicetitle: 'Rechnungstitel ändern'
|
||||||
|
, invoiceaddress: 'Rechnungsempfänger-Adresse ändern'
|
||||||
|
, loc: 'Leistungsort oder Lieferadresse ändern'
|
||||||
|
, invoiceemail: 'Email-Adresse ändern und zusätzliche Email-Empfänger festlegen'
|
||||||
|
, provisionperiod: 'Leistungsdatum oder -zeitraum ändern'
|
||||||
}
|
}
|
||||||
}, $rcol = {
|
}, $rcol = {
|
||||||
req: new fields_definition('Auftrag', 'Aufträge', [
|
req: new fields_definition('Auftrag', 'Aufträge', [
|
||||||
@@ -1289,13 +1302,13 @@ $inv.ccInv = function (ev) { //normale rechnung
|
|||||||
|
|
||||||
let admin = response.admin || {}, fm = (cls, txt, nme, hd, dta) => {
|
let admin = response.admin || {}, 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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', '', 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
fm('locfrm', '', 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
||||||
fm('emailfrm', admin.invoiceemail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, admin.invoiceemail, admin.invoiceemailcc);
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
||||||
|
|
||||||
let admtxt, admlbl;
|
let admtxt, admlbl;
|
||||||
@@ -1364,13 +1377,13 @@ $inv.ccStInv = function (ev) { // Stornorechnung
|
|||||||
|
|
||||||
let admin = response.admin || {}, fm = (cls, txt, nme, hd, dta) => {
|
let admin = response.admin || {}, 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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
fm('tfrm', admin.invoicetitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', admin.invoiceaddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', admin.provisionlocation, 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
fm('locfrm', admin.provisionlocation, 'loc', 1, { list: deepCopy(response.locations), lbl: 'ref', property: 'address' });
|
||||||
fm('emailfrm', admin.invoiceemail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, admin.invoiceemail, admin.invoiceemailcc);
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(admin.sender));
|
||||||
|
|
||||||
let admtxt, admlbl;
|
let admtxt, admlbl;
|
||||||
@@ -1440,14 +1453,13 @@ $inv.cntInv = function (data) { //invoice continuation
|
|||||||
|
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
||||||
fm('emailfrm', inv.SendToEmail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, inv.SendToEmail, inv.SendToEmailCc);
|
||||||
fm('emailccfrm', inv.SendToEmailCc, 'invoiceemailcc', 0, null);
|
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
||||||
|
|
||||||
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
||||||
@@ -1503,14 +1515,13 @@ $inv.cSt = function (data) {
|
|||||||
|
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
fm('tfrm', inv.InvoiceTitle, 'invoicetitle', 0, null);
|
||||||
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
fm('adrfrm', inv.SendToAddress, 'invoiceaddress', 0, null);
|
||||||
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
fm('locfrm', inv.ProvisionLocation, 'loc', 1, null);
|
||||||
fm('emailfrm', inv.SendToEmail, 'invoiceemail', 0, null);
|
$inv.emailFrm(frm, rif, inv.SendToEmail, inv.SendToEmailCc);
|
||||||
fm('emailccfrm', inv.SendToEmailCc, 'invoiceemailcc', 0, null);
|
|
||||||
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
$$.dc('sndfrm', frm).append($$.dc('content').text(response.admin.sender));
|
||||||
|
|
||||||
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
fm('admfrm', inv.ProvisionPeriod, 'provisionperiod', ((inv.ProvisionPeriod || '').includes('-') === true ? $rct.provP : $rct.provD), 1, null);
|
||||||
@@ -1638,6 +1649,45 @@ $inv.eProvisionPeriod = function (ev) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Main recipient + CC ("Zusatzempfänger") edited together in one dialog — there is no separate
|
||||||
|
pencil on the CC row, only on the email row (see $inv.emailFrm), which passes both content
|
||||||
|
spans through ev.data.t / ev.data.ccT. */
|
||||||
|
$inv.eEmail = function (ev) {
|
||||||
|
let flds = [
|
||||||
|
{ name: 'email', label: $rct.frm.invoiceemail, type: 'text', value: (ev.data.t || $$.s()).text() },
|
||||||
|
{ name: 'emailcc', label: $rct.frm.invoiceemailcc, type: 'text', value: (ev.data.ccT || $$.s()).text() }
|
||||||
|
];
|
||||||
|
$ocms.dlgform(flds, {
|
||||||
|
title: $rct.frm.invoiceemail,
|
||||||
|
success: function (res) {
|
||||||
|
let email = ('' + (res.email || '')).trim(), cc = ('' + (res.emailcc || '')).trim();
|
||||||
|
if (ev.data && ev.data.t) { ev.data.t.text(email); }
|
||||||
|
if (ev.data && ev.data.ccT) { ev.data.ccT.text(cc); }
|
||||||
|
if (typeof (ev.data || {}).change === 'function') { ev.data.change(email); }
|
||||||
|
if (typeof (ev.data || {}).changeCc === 'function') { ev.data.changeCc(cc); }
|
||||||
|
/* backend-authoritative: mirror both fields to the server session (see $inv.eHtml's
|
||||||
|
generic path, which this mirrors for a single field). */
|
||||||
|
$inv.d.syncField('invoiceemail', email);
|
||||||
|
$inv.rd.syncField('invoiceemail', email);
|
||||||
|
$inv.d.syncField('invoiceemailcc', cc);
|
||||||
|
$inv.rd.syncField('invoiceemailcc', cc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/* Builds the email + CC ("Zusatzempfänger") header rows together: only the email row gets a
|
||||||
|
pencil, opening the combined $inv.eEmail dialog for both fields (see there). */
|
||||||
|
$inv.emailFrm = function (frm, rif, email, emailcc) {
|
||||||
|
let ccfr = $$.dc('inpfrm emailccfrm', frm), ccfc = $$.dc('content', ccfr).rwText(emailcc);
|
||||||
|
let efr = $$.dc('inpfrm emailfrm', frm), efc = $$.dc('content', efr).rwText(email);
|
||||||
|
$$.dc('axf', efr).append($$.dc('ibtn edit', { title: $rct.frmTT.invoiceemail }).append(gi('pencil')).click({
|
||||||
|
t: efc, ccT: ccfc, nme: 'invoiceemail',
|
||||||
|
change: (nv) => { rif.tbl.data('new').invoiceemail = nv; },
|
||||||
|
changeCc: (nv) => { rif.tbl.data('new').invoiceemailcc = nv; }
|
||||||
|
}, $inv.eHtml));
|
||||||
|
rif.tbl.data('new').invoiceemail = email;
|
||||||
|
rif.tbl.data('new').invoiceemailcc = emailcc;
|
||||||
|
};
|
||||||
|
|
||||||
$inv.eHtml = function (ev) {
|
$inv.eHtml = function (ev) {
|
||||||
/* The recipient address and the service date/period are edited through structured dialogs
|
/* The recipient address and the service date/period are edited through structured dialogs
|
||||||
whenever an invoice draft is active; reminders (no invoice draft token) keep the plain
|
whenever an invoice draft is active; reminders (no invoice draft token) keep the plain
|
||||||
@@ -1646,6 +1696,9 @@ $inv.eHtml = function (ev) {
|
|||||||
if (ev.data.nme === 'invoiceaddress') { return $inv.eAddress.call(this, ev); }
|
if (ev.data.nme === 'invoiceaddress') { return $inv.eAddress.call(this, ev); }
|
||||||
if (ev.data.nme === 'provisionperiod') { return $inv.eProvisionPeriod.call(this, ev); }
|
if (ev.data.nme === 'provisionperiod') { return $inv.eProvisionPeriod.call(this, ev); }
|
||||||
}
|
}
|
||||||
|
/* The CC/Zusatzempfänger recipient is edited together with the main email, in one dialog —
|
||||||
|
there is no separate pencil on the CC row (see $inv.emailFrm). */
|
||||||
|
if (ev.data && !(ev.data instanceof jQuery) && ev.data.nme === 'invoiceemail' && ev.data.ccT) { return $inv.eEmail.call(this, ev); }
|
||||||
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t;
|
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t;
|
||||||
/* Single-line fields must stay plain text — the TinyMCE/html editor wraps the value in <p>
|
/* Single-line fields must stay plain text — the TinyMCE/html editor wraps the value in <p>
|
||||||
tags, which used to get posted and persisted verbatim (e.g. <p>18.06.2026</p> in the
|
tags, which used to get posted and persisted verbatim (e.g. <p>18.06.2026</p> in the
|
||||||
@@ -1759,15 +1812,29 @@ $inv.eRw = function(row, dta, flds) {
|
|||||||
changed block(s) to the backend session (t_fds_inv -> syncChanged). Committing on drop (rather
|
changed block(s) to the backend session (t_fds_inv -> syncChanged). Committing on drop (rather
|
||||||
than on every mid-drag hover-swap) avoids rebuilding the row that is currently being dragged. */
|
than on every mid-drag hover-swap) avoids rebuilding the row that is currently being dragged. */
|
||||||
$inv.bdysort = (i, e) => { $(e).Sortable({ dragItem: false, dragHandleClass: 'ico', parentident: 'tr', onend: () => { $inv.t_fds_inv(); } }) }
|
$inv.bdysort = (i, e) => { $(e).Sortable({ dragItem: false, dragHandleClass: 'ico', parentident: 'tr', onend: () => { $inv.t_fds_inv(); } }) }
|
||||||
|
/* Single "Kontext-Button" per row/field, opening a dropdown of the row's edit actions
|
||||||
|
(reuses $ocms.menu, the same mechanism that already drives the toolbar menus — see
|
||||||
|
$inv.eM/$inv.iMn). Calling .ocmsmenu() directly on a <nav> we built ourselves (rather than
|
||||||
|
letting $ocms.menu create one inside a bar) keeps our own sizing class instead of being
|
||||||
|
replaced. Every entry carries both its label and a matching `title` tooltip. */
|
||||||
|
$inv.rowCtxMenu = function (items) {
|
||||||
|
let nav = $$[0]('nav').aC('rowctx');
|
||||||
|
nav.ocmsmenu([{ glyph: 'glyphicon-option-vertical', aclass: 'ctxbtn', attr: { title: $rct.ctxM }, itm: items }]);
|
||||||
|
/* $ocms.menu puts `attr` (incl. our title tooltip) on the <li>, not the <a> a viewer actually
|
||||||
|
hovers — mirror it onto the <a> too so the native tooltip is guaranteed to fire regardless
|
||||||
|
of how the browser resolves title on a non-interactive ancestor. */
|
||||||
|
nav.find('li[title]').each(function () { let li = $(this); li.children('a').attr('title', li.attr('title')); });
|
||||||
|
return nav;
|
||||||
|
};
|
||||||
$inv.rrw = function () {
|
$inv.rrw = function () {
|
||||||
let rw = $(this), dta = rw.data(), co = {}, ph = rw.is('.placeholder'), hn = rw.is('.hidenote');
|
let rw = $(this), dta = rw.data(), co = {}, ph = rw.is('.placeholder'), hn = rw.is('.hidenote');
|
||||||
let oHtml = (e) => $$.d().append(e).html();
|
let oHtml = (e) => $$.d().append(e).html();
|
||||||
let bc = [
|
let mi = [
|
||||||
$$.dc('ibtn insb', { title: $rct.iRb }).append(gi('indent-left')).click(rw, $inv.inRow)
|
{ lbl: $rct.iRb, attr: { title: $rct.iRb }, data: rw, fnc: $inv.inRow }
|
||||||
];
|
];
|
||||||
if (ph === false) {
|
if (ph === false) {
|
||||||
bc.unshift($$.dc('ibtn edit', { title: $rct.cP }).append(gi('pencil')).click(rw, $inv.eRow));
|
mi.unshift({ lbl: $rct.cP, attr: { title: $rct.cP }, data: rw, fnc: $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(); } }));
|
mi.push({ lbl: $rct.dR, attr: { title: $rct.dR }, fnc: function (e) { if (confirm($rct.cD)) { rw.remove(); $inv.t_fds_inv(); } } });
|
||||||
/* "Auf Setpreis umstellen": offered on a Set header item that does not yet carry a
|
/* "Auf Setpreis umstellen": offered on a Set header item that does not yet carry a
|
||||||
price. fds__prepInvoice's [SetItmId] now anchors on the still-unconverted (price 0)
|
price. fds__prepInvoice's [SetItmId] now anchors on the still-unconverted (price 0)
|
||||||
header, so the header row's own SetItmId self-references its own id rather than being
|
header, so the header row's own SetItmId self-references its own id rather than being
|
||||||
@@ -1776,10 +1843,10 @@ $inv.rrw = function () {
|
|||||||
Irreversible: the actual sum/clear mutation happens server-side (backend-authoritative,
|
Irreversible: the actual sum/clear mutation happens server-side (backend-authoritative,
|
||||||
see InvoiceDraftEditService.ApplyItemSetPrice) via the "item.setprice" patch target. */
|
see InvoiceDraftEditService.ApplyItemSetPrice) via the "item.setprice" patch target. */
|
||||||
if ((dta.Type || '').toLowerCase() === 'set' && (dta.net_val || 0) === 0) {
|
if ((dta.Type || '').toLowerCase() === 'set' && (dta.net_val || 0) === 0) {
|
||||||
bc.push($$.dc('ibtn tosetp', { title: $rct.toSetP }).append(gi('scale')).click(rw, $inv.toSetPrice));
|
mi.push({ lbl: $rct.toSetP, attr: { title: $rct.toSetP }, data: rw, fnc: $inv.toSetPrice });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let axf = $$.dc('axf').append(bc);
|
let axf = $$.dc('axf').append($inv.rowCtxMenu(mi));
|
||||||
if (ph === true) {
|
if (ph === true) {
|
||||||
co = { id: '', typ: 'placeholder' };
|
co = { id: '', typ: 'placeholder' };
|
||||||
} else if (rw.is('.itm.osum') === true) {
|
} else if (rw.is('.itm.osum') === true) {
|
||||||
@@ -1788,7 +1855,12 @@ $inv.rrw = function () {
|
|||||||
co = { invrqid: dta.InvRqId, id: dta.Id || '', typ: dta.Type || 'other', p: '', q: null, t: '', tt: null, v: null, vt: dta.net_val, vs: dta.svcnet_val, vat: dta.vat, vv: dta.vat_val, vsv: dta.svcvat_val, det: (dta.Note || '') !== '' && hn === false, SetItmId: dta.SetItmId || null, lvl: (dta.lvl || 0) };
|
co = { invrqid: dta.InvRqId, id: dta.Id || '', typ: dta.Type || 'other', p: '', q: null, t: '', tt: null, v: null, vt: dta.net_val, vs: dta.svcnet_val, vat: dta.vat, vv: dta.vat_val, vsv: dta.svcvat_val, det: (dta.Note || '') !== '' && hn === false, SetItmId: dta.SetItmId || null, lvl: (dta.lvl || 0) };
|
||||||
$$.dc('ibtn ico move', axf, { title: $rct.mR }); /* should be the last added */
|
$$.dc('ibtn ico move', axf, { title: $rct.mR }); /* should be the last added */
|
||||||
|
|
||||||
co.p = dta.position || (dta.SortOrder || '');
|
/* dta.position is '' (not unset) for a Text/Title row once invSumUpdate has numbered the
|
||||||
|
invoice (ADR 0017) — an intentional "no number", not a missing value, so it must NOT
|
||||||
|
fall through to SortOrder (which is -1 for such rows and would leak "-1" into Pos.).
|
||||||
|
Only an as-yet-uncomputed row (freshly inserted, before the next invSumUpdate pass)
|
||||||
|
has position === undefined and should still fall back to SortOrder as a placeholder. */
|
||||||
|
co.p = dta.position != null ? dta.position : (dta.SortOrder || '');
|
||||||
if (co.id === '') {
|
if (co.id === '') {
|
||||||
co.t = '';
|
co.t = '';
|
||||||
} else if (['Text', 'Title'].includes(co.typ) && (dta.net_val || 0) === 0) {
|
} else if (['Text', 'Title'].includes(co.typ) && (dta.net_val || 0) === 0) {
|
||||||
@@ -1802,7 +1874,7 @@ $inv.rrw = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((dta.Note || '') !== '') {
|
if ((dta.Note || '') !== '') {
|
||||||
$$.dc('ibtn add', axf).append(gi('object-align-left')).click(function (e) {
|
$$.dc('ibtn add', axf, { title: $rct.noteToggle }).append(gi('object-align-left')).click(function (e) {
|
||||||
$inv.rrw.call(rw.tC('hidenote'));
|
$inv.rrw.call(rw.tC('hidenote'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1947,7 +2019,7 @@ $inv.rendersrq = function () {
|
|||||||
$$.dc('ibtn insb', aux, { title: $rct.iRb }).append(gi('indent-left')).click(rtr, $inv.inRow);
|
$$.dc('ibtn insb', aux, { title: $rct.iRb }).append(gi('indent-left')).click(rtr, $inv.inRow);
|
||||||
let stxt = $$.sc('text', rx.text);
|
let stxt = $$.sc('text', rx.text);
|
||||||
let nme = $$.td(rtr, { colspan: onesum ? 4 : 5 }).append(stxt), oidta, numkeys = ['net_val', 'vat_val', 'svcnet_val', 'svcvat_val', 'net'];
|
let nme = $$.td(rtr, { colspan: onesum ? 4 : 5 }).append(stxt), oidta, numkeys = ['net_val', 'vat_val', 'svcnet_val', 'svcvat_val', 'net'];
|
||||||
$$.dc('ibtn edit', aux).data('dialog', $rcol.req.lbl().Name).append(gi('pencil')).click({ t: stxt, change: (nv) => { rx.text = nv; $inv.t_fds_inv(); } }, $inv.eHtml)
|
$$.dc('ibtn edit', aux, { title: $rct.sectionTitleEditTT }).data('dialog', $rcol.req.lbl().Name).append(gi('pencil')).click({ t: stxt, change: (nv) => { rx.text = nv; $inv.t_fds_inv(); } }, $inv.eHtml)
|
||||||
if (onesum) {
|
if (onesum) {
|
||||||
$$.tdc('currency isumval', rtr);
|
$$.tdc('currency isumval', rtr);
|
||||||
oidta = { Id: rx.Id.toString() + '_osum', net_val: 0, vat_val: 0, svcnet_val: 0, svcvat_val: 0, net: 0 };
|
oidta = { Id: rx.Id.toString() + '_osum', net_val: 0, vat_val: 0, svcnet_val: 0, svcvat_val: 0, net: 0 };
|
||||||
@@ -2324,7 +2396,8 @@ $inv.ccRem = function (id, InvoiceId) { //reminder creation
|
|||||||
$inv.rRemRw = function (dta) {
|
$inv.rRemRw = function (dta) {
|
||||||
let tr = $(this), rem = dta.rm || {};
|
let tr = $(this), rem = dta.rm || {};
|
||||||
tr.empty().data({ invoiceid: rem.invoiceid, invoicedate: rem.invoicedate, amount: rem.amount, amount_payed: rem.amount_payed });
|
tr.empty().data({ invoiceid: rem.invoiceid, invoicedate: rem.invoicedate, amount: rem.amount, amount_payed: rem.amount_payed });
|
||||||
let axf = $$.dc('axf').append($$.dc('ibtn edit', { title: $rct.cP }).append(gi('pencil')).click(tr, $inv.eRowR));
|
let mi = [{ lbl: $rct.cP, attr: { title: $rct.cP }, data: tr, fnc: $inv.eRowR }];
|
||||||
|
let axf = $$.dc('axf').append($inv.rowCtxMenu(mi));
|
||||||
tr.append([$$.tdc('aux').append(axf), $$.tdc('keep', rem.invoiceid), $$.tdc('keep', fdt(rem.invoicedate, 'dd.MM.yy')), $$.tdc('currency', fnum(rem.amount, $rct.cst)), $$.tdc('currency', fnum(rem.amount_payed, $rct.cst)), $$.tdc('currency', fnum(rem.amount - rem.amount_payed, $rct.cst))]);
|
tr.append([$$.tdc('aux').append(axf), $$.tdc('keep', rem.invoiceid), $$.tdc('keep', fdt(rem.invoicedate, 'dd.MM.yy')), $$.tdc('currency', fnum(rem.amount, $rct.cst)), $$.tdc('currency', fnum(rem.amount_payed, $rct.cst)), $$.tdc('currency', fnum(rem.amount - rem.amount_payed, $rct.cst))]);
|
||||||
};
|
};
|
||||||
$inv.eRowR = function (ev) {
|
$inv.eRowR = function (ev) {
|
||||||
@@ -2365,9 +2438,12 @@ $inv.ccRem_s2 = function (id, sets) { //reminder creation
|
|||||||
$inv.rRemRw.call($$.tr(rif.bdy), rif.tbl.data());
|
$inv.rRemRw.call($$.tr(rif.bdy), rif.tbl.data());
|
||||||
rif.ft.appendTo(rif.tbl);
|
rif.ft.appendTo(rif.tbl);
|
||||||
|
|
||||||
|
/* Reminders have no CC/Zusatzempfänger field (see $inv.emailFrm, invoice-only), so the
|
||||||
|
email pencil here keeps a plain tooltip instead of $rct.frmTT.invoiceemail. */
|
||||||
|
let remTT = { invoiceemail: 'Email-Adresse ändern', subject: 'Betreff ändern' };
|
||||||
let fm = (cls, txt, nme, hd, dta) => {
|
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);
|
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);
|
||||||
$$.dc('axf', fr).append($$.dc('ibtn edit').data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
$$.dc('axf', fr).append($$.dc('ibtn edit', { title: remTT[nme] || $rct.frmTT[nme] || $rct.frm[nme] }).data('dialog', $rct.frm[nme]).append(gi('pencil')).click($.extend({ t: fc, nme: nme, change: (nv) => { rif.tbl.data('new')[nme] = nv; } }, dta), $inv.eHtml));
|
||||||
rif.tbl.data('new')[nme] = txt;
|
rif.tbl.data('new')[nme] = txt;
|
||||||
};
|
};
|
||||||
fm('tfrm', rem.subject, 'subject', 0, null);
|
fm('tfrm', rem.subject, 'subject', 0, null);
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user