Add Azure Blob Storage archive & email safety net
- Add AzureBlobStorageService, DocumentArchiveSyncService, and related config for secondary PDF archiving of invoices/reminders - Add SQL procs and schema changes for archive backfill - Update invoice/reminder services to upload PDFs to blob storage - Add telemetry counters and unit tests for blob storage/archive logic - Add Fuchs:Email:OverrideRecipient config and enforce dev/test email redirect in ProcessWebComService, with tests - Improve JS date parsing (German formats), stricter JSON date detection - Increase widget SQL timeouts, update dependencies, docs, and project files
This commit is contained in:
@@ -168,21 +168,34 @@ function ne(inp, alt) {
|
||||
return (inp || '') === '' ? (alt || '') : inp;
|
||||
}
|
||||
function pad(i, n) { return (i || '').toString().padStart(n, '0').substr(-1 * n); }
|
||||
function twoDigitYear(y) { var n = parseInt(y, 10); return n + (n < 70 ? 2000 : 1900); }
|
||||
/* Parses dot-separated German short dates (dd.MM.yyyy / dd.MM.yy, optionally with a time part).
|
||||
Returns null if the string does not match, so callers can fall back to other parsing. */
|
||||
function parseGermanDate(si) {
|
||||
var g = si.match(/^(\d{1,2})\.(\d{1,2})\.(\d{2}|\d{4})(?:[\sT](\d{1,2}):(\d{2})(?::(\d{2}))?)?$/);
|
||||
if (g === null) { return null; }
|
||||
var yr = g[3].length === 2 ? twoDigitYear(g[3]) : parseInt(g[3], 10);
|
||||
return new Date(yr, parseInt(g[2], 10) - 1, parseInt(g[1], 10), parseInt(g[4] || '0', 10), parseInt(g[5] || '0', 10), parseInt(g[6] || '0', 10));
|
||||
}
|
||||
function parseISO(s) {
|
||||
let si = s || '';
|
||||
if (si === '') { return null };
|
||||
if (/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/.test(si) === true) {
|
||||
return new Date(si);
|
||||
} else {
|
||||
var b = s.split(/\D/);
|
||||
return new Date(b[0], b[1] - 1, b[2], b[3], b[4], b[5]);
|
||||
var gd = parseGermanDate(si);
|
||||
if (gd !== null) { return gd; }
|
||||
var b = si.split(/\D/);
|
||||
return new Date(b[0], b[1] - 1, b[2], b[3] || 0, b[4] || 0, b[5] || 0);
|
||||
}
|
||||
}
|
||||
function parseISOLocal(s) {
|
||||
let si = s || '';
|
||||
if (si === '') { return null };
|
||||
var b = s.split(/\D/);
|
||||
return new Date(b[0], b[1] - 1, b[2], b[3], b[4], b[5]);
|
||||
var gd = parseGermanDate(si);
|
||||
if (gd !== null) { return gd; }
|
||||
var b = si.split(/\D/);
|
||||
return new Date(b[0], b[1] - 1, b[2], b[3] || 0, b[4] || 0, b[5] || 0);
|
||||
}
|
||||
function fnum(i, style) {
|
||||
/* { style: 'decimal/currency/percent', currency: 'USD/EUR', currencyDisplay: 'symbol/code/name', minimumIntegerDigits: 1, minimumFractionDigits: 2, maximumFractionDigits: 3, useGrouping: true } */
|
||||
|
||||
Reference in New Issue
Block a user