Update submodule references for OCORE, OCORE_Charting, OCORE_web, and OCORE_web_pdf to latest commits
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Stefan
2026-07-10 11:47:12 +02:00
parent 59a2b86c09
commit e53d8962ad
10 changed files with 87 additions and 29 deletions
+27 -6
View File
@@ -131,19 +131,40 @@ public static class FuchsPdf
public static string Currency(object? input, string returnobject = "?")
{
if (input == null || input is DBNull) return returnobject;
if (decimal.TryParse(input.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out var d))
return d.ToString("0.00 \u20ac", DeCulture);
return returnobject;
return ParseDec(input, out var d) ? d.ToString("0.00 \u20ac", DeCulture) : returnobject;
}
public static string TranslatePaymentTerm(string pt) =>
pt.Replace("wd", " Werktagen").Replace("d", " Tagen").Replace("wk", " Wochen").ne("10 Tagen");
/// <summary>
/// Parses a numeric value coming from JSON deserialization (long/double), SQL
/// (decimal), or an already-invariant numeric string. Numeric CLR types are
/// converted directly rather than round-tripped through <c>object.ToString()</c>:
/// that stringifies using the server's <em>current thread culture</em> (e.g.
/// de-DE, where 22.6 becomes "22,6"), which <see cref="NumberStyles.Any"/> +
/// <see cref="CultureInfo.InvariantCulture"/> then misreads \u2014 the comma is taken
/// as a thousands separator, not a decimal point, inflating amounts ~100x
/// (19,00 \u2192 1900) and corrupting sums built from such values.
/// </summary>
public static bool ParseDec(object? input, out decimal val)
{
val = 0;
return input != null && decimal.TryParse(
input.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out val);
switch (input)
{
case null:
val = 0; return false;
case decimal d:
val = d; return true;
case double dbl:
val = (decimal)dbl; return true;
case float flt:
val = (decimal)flt; return true;
case int or long or short or byte or sbyte or uint or ulong or ushort:
val = Convert.ToDecimal(input, CultureInfo.InvariantCulture); return true;
default:
return decimal.TryParse(
input.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out val);
}
}
// ── HTML split helper (for multi-line PDF cells) ──────────────────────────
+10 -3
View File
@@ -875,9 +875,16 @@ $inv.itemToContract = function (rrx) {
ci.desc = rrx.htmltext || ((((rrx.NameOrNumber || '').substr(0, 1) !== '#') ? oHtml($$[0]('p').text(rrx.NameOrNumber || '')) : '') + (rrx.Note || ''));
ci.total_net = '';
} else {
/* normal priced item (incl. set headers, which carry their own set price or 0) */
ci.title = rrx.NameOrNumber || '';
ci.desc = rrx.Note || '';
/* normal priced item (incl. set headers, which carry their own set price or 0).
Mirrors the "itm"/co.t fallback above: when the row only carries pre-built
htmltext (no separate NameOrNumber/Note), use it as desc so the PDF isn't left
without a description for these rows. */
if (rrx.htmltext) {
ci.desc = rrx.htmltext;
} else {
ci.title = rrx.NameOrNumber || '';
ci.desc = rrx.Note || '';
}
ci.qty = rrx.quantity || ((rrx.quantityhours || 0) !== 0 ? (fnum(rrx.quantityhours) + (rrx.UnitString ? ' ' + rrx.UnitString : '')) : '');
ci.price_net = (rrx.net || 0);
ci.total_net = (rrx.net_val || 0);
+22 -7
View File
@@ -1027,14 +1027,22 @@ $inv.cSt = function (data) {
});
};
$inv.eHtml = function (ev) {
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t, flds = [
{ name: 'txt', label: 'Text', type: 'html', value: frmct.html(), tinymce: true, attr: { style: 'height: 300px' } }
];
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t;
/* invoiceemail must stay plain text — using the TinyMCE/html editor here used to wrap the
address in <p> tags, which then got posted and persisted verbatim into SendToEmail. */
let isPlainText = ev.data.nme === 'invoiceemail';
let flds = isPlainText
? [{ name: 'txt', label: 'Text', type: 'text', value: frmct.text() }]
: [{ name: 'txt', label: 'Text', type: 'html', value: frmct.html(), tinymce: true, attr: { style: 'height: 300px' } }];
let change = ev.data.change || null;
let sets = {
title: t.data('dialog') || '',
success: function (response) {
frmct.html(response.txt);
if (isPlainText) {
frmct.text(response.txt || '');
} else {
frmct.html(response.txt);
}
if (typeof change === 'function') {
change(response.txt);
}
@@ -1414,9 +1422,16 @@ $inv.itemToContract = function (rrx) {
ci.desc = rrx.htmltext || ((((rrx.NameOrNumber || '').substr(0, 1) !== '#') ? oHtml($$[0]('p').text(rrx.NameOrNumber || '')) : '') + (rrx.Note || ''));
ci.total_net = '';
} else {
/* normal priced item (incl. set headers, which carry their own set price or 0) */
ci.title = rrx.NameOrNumber || '';
ci.desc = rrx.Note || '';
/* normal priced item (incl. set headers, which carry their own set price or 0).
Mirrors the "itm"/co.t fallback above: when the row only carries pre-built
htmltext (no separate NameOrNumber/Note), use it as desc so the PDF isn't left
without a description for these rows. */
if (rrx.htmltext) {
ci.desc = rrx.htmltext;
} else {
ci.title = rrx.NameOrNumber || '';
ci.desc = rrx.Note || '';
}
ci.qty = rrx.quantity || ((rrx.quantityhours || 0) !== 0 ? (fnum(rrx.quantityhours) + (rrx.UnitString ? ' ' + rrx.UnitString : '')) : '');
ci.price_net = (rrx.net || 0);
ci.total_net = (rrx.net_val || 0);
File diff suppressed because one or more lines are too long
+22 -7
View File
@@ -1008,14 +1008,22 @@ $inv.cSt = function (data) {
});
};
$inv.eHtml = function (ev) {
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t, flds = [
{ name: 'txt', label: 'Text', type: 'html', value: frmct.html(), tinymce: true, attr: { style: 'height: 300px' } }
];
let t = $(this), frmct = ev.data instanceof jQuery ? ev.data : ev.data.t;
/* invoiceemail must stay plain text — using the TinyMCE/html editor here used to wrap the
address in <p> tags, which then got posted and persisted verbatim into SendToEmail. */
let isPlainText = ev.data.nme === 'invoiceemail';
let flds = isPlainText
? [{ name: 'txt', label: 'Text', type: 'text', value: frmct.text() }]
: [{ name: 'txt', label: 'Text', type: 'html', value: frmct.html(), tinymce: true, attr: { style: 'height: 300px' } }];
let change = ev.data.change || null;
let sets = {
title: t.data('dialog') || '',
success: function (response) {
frmct.html(response.txt);
if (isPlainText) {
frmct.text(response.txt || '');
} else {
frmct.html(response.txt);
}
if (typeof change === 'function') {
change(response.txt);
}
@@ -1395,9 +1403,16 @@ $inv.itemToContract = function (rrx) {
ci.desc = rrx.htmltext || ((((rrx.NameOrNumber || '').substr(0, 1) !== '#') ? oHtml($$[0]('p').text(rrx.NameOrNumber || '')) : '') + (rrx.Note || ''));
ci.total_net = '';
} else {
/* normal priced item (incl. set headers, which carry their own set price or 0) */
ci.title = rrx.NameOrNumber || '';
ci.desc = rrx.Note || '';
/* normal priced item (incl. set headers, which carry their own set price or 0).
Mirrors the "itm"/co.t fallback above: when the row only carries pre-built
htmltext (no separate NameOrNumber/Note), use it as desc so the PDF isn't left
without a description for these rows. */
if (rrx.htmltext) {
ci.desc = rrx.htmltext;
} else {
ci.title = rrx.NameOrNumber || '';
ci.desc = rrx.Note || '';
}
ci.qty = rrx.quantity || ((rrx.quantityhours || 0) !== 0 ? (fnum(rrx.quantityhours) + (rrx.UnitString ? ' ' + rrx.UnitString : '')) : '');
ci.price_net = (rrx.net || 0);
ci.total_net = (rrx.net_val || 0);
File diff suppressed because one or more lines are too long
+1 -1
Submodule OCORE updated: d760efc077...973b47439a