Add function to retrieve company address as JSON and update invoice procedures
- Created a new function `fds__getCompanyAddressJson` to return a company's postal address as a structured JSON object. - Modified stored procedures `fds__createInvoice`, `fds__setInvoice`, and `fds__prepInvoice` to include a new parameter `@SendToAddressJson` for handling the address data. - Updated the invoice table and user-defined types to accommodate the new `SendToAddressJson` field. - Ensured that the address data is properly retrieved and stored in the invoice records.
This commit is contained in:
@@ -492,4 +492,22 @@ table.if td.num {
|
||||
padding: 0.2rem;
|
||||
border-top-left-radius: inherit;
|
||||
border-top-right-radius: inherit;
|
||||
}
|
||||
|
||||
/* Conformity hint shown inside the structured recipient-address dialog (EN 16931 / DATEV). */
|
||||
.adr-conformity {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.6rem 0.75rem;
|
||||
background: #f3f7fb;
|
||||
border: 1px solid #cfe0f0;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.adr-conformity .hd {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.adr-conformity .tx {
|
||||
color: #445;
|
||||
}
|
||||
@@ -1523,7 +1523,84 @@ $inv.cSt = function (data) {
|
||||
}
|
||||
});
|
||||
};
|
||||
/* Country choices for the structured recipient-address dialog (ISO 3166-1 alpha-2, BT-55). */
|
||||
$inv.adrCountries = [['DE', 'Deutschland'], ['AT', 'Österreich'], ['CH', 'Schweiz'], ['FR', 'Frankreich'],
|
||||
['NL', 'Niederlande'], ['BE', 'Belgien'], ['LU', 'Luxemburg'], ['IT', 'Italien'], ['ES', 'Spanien'],
|
||||
['PL', 'Polen'], ['DK', 'Dänemark'], ['CZ', 'Tschechien'], ['GB', 'Großbritannien'], ['US', 'USA']];
|
||||
|
||||
/* Compose the free-text postal block (for the inline display) from the structured address —
|
||||
mirrors the backend InvoiceRecipientAddress.Compose (the VAT id is never part of the block). */
|
||||
$inv.composeAddress = function (a) {
|
||||
a = a || {}; let lines = [];
|
||||
let push = (v) => { v = ('' + (v || '')).trim(); if (v !== '') lines.push(v); };
|
||||
push(a.name);
|
||||
if (('' + (a.contact || '')).trim() !== '') push('z.Hd. ' + ('' + a.contact).trim());
|
||||
push(a.line2 || a.addressLine2);
|
||||
push(a.street);
|
||||
push((('' + (a.postalCode || '')) + ' ' + ('' + (a.city || ''))).trim());
|
||||
let cc = ('' + (a.countryCode || '')).toUpperCase();
|
||||
if (cc !== '' && cc !== 'DE') push(cc);
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
/* The structured recipient address currently in effect: the backend keeps it in
|
||||
CustomValues.sendToAddress (survives a draft refresh); new invoices seed it from
|
||||
fds__prepInvoice's invoiceaddressData; otherwise start empty. */
|
||||
$inv.adrCurrent = function (tbl) {
|
||||
let cv = jObj((tbl.data('new') || {}).CustomValues, 'sendToAddress');
|
||||
if (typeof cv === 'string' && cv.trim().charAt(0) === '{') { try { cv = JSON.parse(cv); } catch (e) { cv = null; } }
|
||||
if (cv && typeof cv === 'object') return cv;
|
||||
let ad = (tbl.data('admin') || {}).invoiceaddressData;
|
||||
if (typeof ad === 'string' && ad.trim().charAt(0) === '{') { try { return JSON.parse(ad); } catch (e) { } }
|
||||
else if (ad && typeof ad === 'object') { return ad; }
|
||||
return {};
|
||||
};
|
||||
|
||||
/* Structured recipient-address dialog (EN 16931 / DATEV). Posts the address delta as a JSON
|
||||
object; the backend stores it, composes SendToAddress and keeps the PDF unchanged (ADR 0012).
|
||||
B2C stays effortless: the USt-IdNr. is optional (empty = private person). */
|
||||
$inv.eAddress = function (ev) {
|
||||
let tbl = $inv.d.tbl(), cur = $inv.adrCurrent(tbl);
|
||||
let flds = [
|
||||
{ name: 'name', label: 'Name / Firma', type: 'text', value: cur.name || '', required: true },
|
||||
{ name: 'contact', label: 'z.Hd. (optional)', type: 'text', value: cur.contact || '' },
|
||||
{ name: 'street', label: 'Straße + Nr.', type: 'text', value: cur.street || '' },
|
||||
{ name: 'line2', label: 'Adresszusatz (optional)', type: 'text', value: cur.line2 || cur.addressLine2 || '' },
|
||||
{ name: 'postalCode', label: 'PLZ', type: 'text', value: cur.postalCode || '' },
|
||||
{ name: 'city', label: 'Ort', type: 'text', value: cur.city || '' },
|
||||
{ name: 'countryCode', label: 'Land', type: 'select', url: $inv.adrCountries, value: (cur.countryCode || 'DE') },
|
||||
{ name: 'vatId', label: 'USt-IdNr. (nur bei Firmen)', type: 'text', value: cur.vatId || '' }
|
||||
];
|
||||
let hint = $$.dc('adr-conformity').append([
|
||||
$$.dc('hd').text('Hinweis zur DATEV-/eRechnungs-Konformität'),
|
||||
$$.dc('tx').text('Pflicht: Name, Straße, PLZ, Ort und Land. Die USt-IdNr. nur bei Firmen angeben — '
|
||||
+ 'für eine Rechnung an eine Privatperson einfach leer lassen.')
|
||||
]);
|
||||
$ocms.dlgform(flds, {
|
||||
title: 'Rechnungsempfänger',
|
||||
addcontent: hint,
|
||||
success: function (res) {
|
||||
let a = {
|
||||
name: res.name || '', contact: res.contact || '', line2: res.line2 || '',
|
||||
street: res.street || '', postalCode: res.postalCode || '', city: res.city || '',
|
||||
countryCode: (res.countryCode || 'DE'), vatId: ('' + (res.vatId || '')).trim()
|
||||
};
|
||||
let txt = $inv.composeAddress(a);
|
||||
if (ev.data && ev.data.t) { ev.data.t.rwText(txt); }
|
||||
if (typeof (ev.data || {}).change === 'function') { ev.data.change(txt); }
|
||||
/* Structured delta — the invoice draft backend accepts a JSON object for 'address'. */
|
||||
$inv.d.sync({ Target: 'address', Value: a });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$inv.eHtml = function (ev) {
|
||||
/* The recipient address is edited through the structured dialog whenever an invoice draft is
|
||||
active; reminders (no invoice draft token) keep the plain free-text editor. */
|
||||
if (ev.data && !(ev.data instanceof jQuery) && ev.data.nme === 'invoiceaddress'
|
||||
&& $inv.d && typeof $inv.d.token === 'function' && $inv.d.token() !== '') {
|
||||
return $inv.eAddress.call(this, ev);
|
||||
}
|
||||
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>
|
||||
tags, which used to get posted and persisted verbatim (e.g. <p>18.06.2026</p> in the
|
||||
|
||||
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
@@ -629,4 +629,22 @@ table.if th.keep, table.if td.keep {
|
||||
padding: 0.2rem;
|
||||
border-top-left-radius: inherit;
|
||||
border-top-right-radius: inherit;
|
||||
}
|
||||
|
||||
/* Conformity hint shown inside the structured recipient-address dialog (EN 16931 / DATEV). */
|
||||
.adr-conformity {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.6rem 0.75rem;
|
||||
background: #f3f7fb;
|
||||
border: 1px solid #cfe0f0;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.adr-conformity .hd {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.adr-conformity .tx {
|
||||
color: #445;
|
||||
}
|
||||
@@ -1504,7 +1504,84 @@ $inv.cSt = function (data) {
|
||||
}
|
||||
});
|
||||
};
|
||||
/* Country choices for the structured recipient-address dialog (ISO 3166-1 alpha-2, BT-55). */
|
||||
$inv.adrCountries = [['DE', 'Deutschland'], ['AT', 'Österreich'], ['CH', 'Schweiz'], ['FR', 'Frankreich'],
|
||||
['NL', 'Niederlande'], ['BE', 'Belgien'], ['LU', 'Luxemburg'], ['IT', 'Italien'], ['ES', 'Spanien'],
|
||||
['PL', 'Polen'], ['DK', 'Dänemark'], ['CZ', 'Tschechien'], ['GB', 'Großbritannien'], ['US', 'USA']];
|
||||
|
||||
/* Compose the free-text postal block (for the inline display) from the structured address —
|
||||
mirrors the backend InvoiceRecipientAddress.Compose (the VAT id is never part of the block). */
|
||||
$inv.composeAddress = function (a) {
|
||||
a = a || {}; let lines = [];
|
||||
let push = (v) => { v = ('' + (v || '')).trim(); if (v !== '') lines.push(v); };
|
||||
push(a.name);
|
||||
if (('' + (a.contact || '')).trim() !== '') push('z.Hd. ' + ('' + a.contact).trim());
|
||||
push(a.line2 || a.addressLine2);
|
||||
push(a.street);
|
||||
push((('' + (a.postalCode || '')) + ' ' + ('' + (a.city || ''))).trim());
|
||||
let cc = ('' + (a.countryCode || '')).toUpperCase();
|
||||
if (cc !== '' && cc !== 'DE') push(cc);
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
/* The structured recipient address currently in effect: the backend keeps it in
|
||||
CustomValues.sendToAddress (survives a draft refresh); new invoices seed it from
|
||||
fds__prepInvoice's invoiceaddressData; otherwise start empty. */
|
||||
$inv.adrCurrent = function (tbl) {
|
||||
let cv = jObj((tbl.data('new') || {}).CustomValues, 'sendToAddress');
|
||||
if (typeof cv === 'string' && cv.trim().charAt(0) === '{') { try { cv = JSON.parse(cv); } catch (e) { cv = null; } }
|
||||
if (cv && typeof cv === 'object') return cv;
|
||||
let ad = (tbl.data('admin') || {}).invoiceaddressData;
|
||||
if (typeof ad === 'string' && ad.trim().charAt(0) === '{') { try { return JSON.parse(ad); } catch (e) { } }
|
||||
else if (ad && typeof ad === 'object') { return ad; }
|
||||
return {};
|
||||
};
|
||||
|
||||
/* Structured recipient-address dialog (EN 16931 / DATEV). Posts the address delta as a JSON
|
||||
object; the backend stores it, composes SendToAddress and keeps the PDF unchanged (ADR 0012).
|
||||
B2C stays effortless: the USt-IdNr. is optional (empty = private person). */
|
||||
$inv.eAddress = function (ev) {
|
||||
let tbl = $inv.d.tbl(), cur = $inv.adrCurrent(tbl);
|
||||
let flds = [
|
||||
{ name: 'name', label: 'Name / Firma', type: 'text', value: cur.name || '', required: true },
|
||||
{ name: 'contact', label: 'z.Hd. (optional)', type: 'text', value: cur.contact || '' },
|
||||
{ name: 'street', label: 'Straße + Nr.', type: 'text', value: cur.street || '' },
|
||||
{ name: 'line2', label: 'Adresszusatz (optional)', type: 'text', value: cur.line2 || cur.addressLine2 || '' },
|
||||
{ name: 'postalCode', label: 'PLZ', type: 'text', value: cur.postalCode || '' },
|
||||
{ name: 'city', label: 'Ort', type: 'text', value: cur.city || '' },
|
||||
{ name: 'countryCode', label: 'Land', type: 'select', url: $inv.adrCountries, value: (cur.countryCode || 'DE') },
|
||||
{ name: 'vatId', label: 'USt-IdNr. (nur bei Firmen)', type: 'text', value: cur.vatId || '' }
|
||||
];
|
||||
let hint = $$.dc('adr-conformity').append([
|
||||
$$.dc('hd').text('Hinweis zur DATEV-/eRechnungs-Konformität'),
|
||||
$$.dc('tx').text('Pflicht: Name, Straße, PLZ, Ort und Land. Die USt-IdNr. nur bei Firmen angeben — '
|
||||
+ 'für eine Rechnung an eine Privatperson einfach leer lassen.')
|
||||
]);
|
||||
$ocms.dlgform(flds, {
|
||||
title: 'Rechnungsempfänger',
|
||||
addcontent: hint,
|
||||
success: function (res) {
|
||||
let a = {
|
||||
name: res.name || '', contact: res.contact || '', line2: res.line2 || '',
|
||||
street: res.street || '', postalCode: res.postalCode || '', city: res.city || '',
|
||||
countryCode: (res.countryCode || 'DE'), vatId: ('' + (res.vatId || '')).trim()
|
||||
};
|
||||
let txt = $inv.composeAddress(a);
|
||||
if (ev.data && ev.data.t) { ev.data.t.rwText(txt); }
|
||||
if (typeof (ev.data || {}).change === 'function') { ev.data.change(txt); }
|
||||
/* Structured delta — the invoice draft backend accepts a JSON object for 'address'. */
|
||||
$inv.d.sync({ Target: 'address', Value: a });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$inv.eHtml = function (ev) {
|
||||
/* The recipient address is edited through the structured dialog whenever an invoice draft is
|
||||
active; reminders (no invoice draft token) keep the plain free-text editor. */
|
||||
if (ev.data && !(ev.data instanceof jQuery) && ev.data.nme === 'invoiceaddress'
|
||||
&& $inv.d && typeof $inv.d.token === 'function' && $inv.d.token() !== '') {
|
||||
return $inv.eAddress.call(this, ev);
|
||||
}
|
||||
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>
|
||||
tags, which used to get posted and persisted verbatim (e.g. <p>18.06.2026</p> in the
|
||||
|
||||
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
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user