Completes the eRechnung output path: finalized invoices are emitted as a
ZUGFeRD/Factur-X EN 16931 hybrid (DATEV) or, when a Leitweg-ID is present, as
XRechnung 3.0 for B2G. Both are externally validated as ACCEPTED (0 errors) and
PDF/A-3B COMPLIANT against the ProcessWeb eInvoice service.
- ERechnungMapper: FdsInvoiceData -> EN 16931 model. Seller master data now from
Fuchs:ERechnung:Seller config (VAT id BT-31, Steuernummer BT-32, optional
Handelsregister BT-30, IBAN/BIC, contact). Adds payment terms BT-20/BT-9
(BR-CO-25), buyer VAT id, §13b reverse charge, and the service date/period
(BT-72 / BG-14) parsed from ProvisionPeriod (BR-DE-TMP-32). B2G -> XRechnung
profile with the required electronic addresses/contact.
- ERechnungValidator: client for POST /validatepdf (EN 16931 XML + PDF/A-3 in
one call). A pure "scenario not matched" with zero errors is not treated as a
hard failure; real errors optionally withhold the hybrid (FailOnError).
- ERechnungSettings: seller + validation config; wired in Program.cs; ServiceUrl
in appsettings.
- Online editor: structured German-only dialogs for the recipient address
(incl. Leitweg-ID) and the service date/period (single date or range).
- Bumps the eRechnungLib submodule to the CII rsm-namespace / PDF-A subtype fix.
Fuchs.Tests 514/514, eRechnungLib 97/97.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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.
- Ensure all email/SMS send attempts are audit-logged, including API errors, exceptions, invalid addresses, and disabled service cases; logs now include raw API responses or exception details for better diagnostics.
- Fix audit log parameter builder to never pass NULL for NOT NULL columns (`config`, `DateSent`).
- Add unit tests covering all send paths and audit log correctness.
- Percent-encode non-ASCII/control chars in `DocumentMetadataBuilder` for safe HTTP header metadata; add tests.
- Simplify admin test mail dialog JS and improve success handler robustness.
- Set `charset=utf-8` in admin controller JSON responses for OCORE consistency.
- Update minified JS to match new admin dialog logic.
- Introduced new JavaScript file `fis.admin_txt_de.js` for German translations of administration-related terms and messages.
- Created `fis.admin.css` for styling the administration interface, including layout, cards, and buttons.
- Added `fis.admin.de.js` for the main functionality of the administration module, implementing features such as system status checks and email testing.
- Minified version of the German JavaScript file created as `fis.admin.de.min.js`.
- Minified CSS file created as `fis.admin.min.css` for optimized loading.
- Introduced comprehensive unit tests for the Fuchs_DataService library, covering DATEV header formatting, CSV/XML generation, and FdsMfrClient construction.
- Implemented tests for FdsMfr.UpdateNeed parsing and FdsShared utility helpers, ensuring correct functionality and stability.
- Added tests for FdsConfig and FdsMfrClient to validate configuration resolution and client construction.
Document decisions on backend-authoritative invoice and reminder handling
- Created ADR 0008 to clarify that all invoice types and reminder stages are backend-authoritative during drafting and previewing.
- Established that all calculations and settings must be processed server-side, ensuring consistency between online editor and PDF outputs.
Define irreversible mutations for set-price modes in invoices
- Documented ADR 0009 to specify that the "Set mit Preis" and "Nur Set mit Preis" operations are irreversible mutations affecting service request blocks.
- Clarified that these operations are not display toggles but actual data changes, ensuring clear expectations for invoice handling.
Transition MFR ERP sync to in-process execution within the web app
- Created ADR 0010 to outline the migration of Fuchs_DataService from a standalone service to an in-process library within the Fuchs web application.
- Updated configuration and logging management to be handled by the host application, streamlining the sync process.
Add publish profile and periodic hosted service for job scheduling
- Introduced a publish profile for deployment to a specified folder.
- Implemented PeriodicHostedService to manage multiple independent jobs, including the MFR ERP sync, with configurable execution intervals.
Add dotnet-tools.json for EF Core CLI tools
- Included dotnet-tools.json to manage the version of dotnet-ef for Entity Framework Core migrations and commands.
Move the invoice draft editor to a backend single source of truth: an
in-memory InvoiceDraftSession (per-token, cached) holds the editable payload,
server-computed sums/VAT and validation, plus an automatic change history. The
browser posts single edits; the server recomputes and signals the editing
session over a dedicated SignalR hub (DraftPreviewHub) to re-fetch.
This reverses the previously-documented stateless editor (EVAL_live_invoice_editing,
INVOICE_LIFECYCLE §10), by explicit product decision — captured in ADR 0006 and 0007
plus the live-draft-editing concept doc.
Backend (this milestone):
- InvoiceDraftSession + ChangeHistoryEntry data holders
- InvoiceDraftCalculator: pure port of quantChange/invSumUpdate (§13b, VAT-by-rate)
and consistency checks — fully unit-tested
- IInvoiceDraftCache/InvoiceDraftCache: in-memory store with idle sliding TTL
- IInvoiceDraftService/InvoiceDraftEditService: open (payload or DB reload), patch,
build state, flush via existing RegisterInvoiceAsync (no new persistence), preview
from cache, discard (DB reload), history
- InvoiceDraftExpiryService: pre-expiry warning + eviction-with-reason
- DraftPreviewHub + IDraftNotifier/DraftNotifier: targeted draftReady/draftExpiring/
draftClosed signals per draft token
- inv/dopen|dstate|dpatch|dpreview|dsave|dhistory|ddiscard|dclose endpoints; save
reports success/failure via the existing EventService
- DI + hub mapping in Program.cs
Frontend (additive foundation): $fis.draft SignalR client for /draftpreview.
The editor DOM inversion (routing deltas, rendering from server state) is the
next, separately-verified step; existing endpoints are unaffected.
Tests: 30 new (calculator, cache, expiry, patch/history, flush); 306 total passing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Modified the stored procedure `fds__admin_getReportCatalog.sql` to use the correct schema for `all_objects`.
- Added new folders and projects for `eRechnungLib` in the solution file `Fuchs_Intranet.slnx`, including validation and test projects.
- Updated submodule reference for `OCORE`.
- Added new submodule `eRechnungLib` with initial commit.
- Increased the length of the NameOfPayer field from NVARCHAR(60) to NVARCHAR(140) in the banking transactions function, table, temporary table, and user-defined type to accommodate longer names.
- Expanded the SepaRemittanceInformation field from VARCHAR(150) to VARCHAR(200) in the banking transactions function for more detailed remittance information.
- Modified the stored procedure fds__setBankingtransaction_done to return additional transaction data (ValueDate and Amount) along with the success flag for improved notification messaging.
- Added validation in MFRClientConfig constructor to ensure the provided URL is not null or empty, enhancing error handling for configuration settings.
- Updated FdsSqlOptions to accept an optional ILogger parameter for improved error logging.
- Modified FdsMfr and FdsMfrClient classes to pass the logger instance to FdsSqlOptions.
- Added detailed error logging in various methods to capture SQL execution issues and file handling errors.
- Improved documentation for FdsSqlOptions to clarify logging behavior.
- Updated Archive class to log compression errors, enhancing traceability of failures.
- Adjusted project configuration to suppress specific warnings related to transitive dependencies.
- Added NuGet.config to define package sources for dependency management.
- Updated submodule references for OCORE and related projects.
- 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
- Support parsing camt.052 ZIP archives in CamtParser and BankingService
- Add CamtZipParserTests for ZIP parsing (single/multi/malformed/empty cases)
- Add CamtRealFileTests: integration tests for real bank exports (ZIP, XML, CAMT, MT940, STA) in git-ignored test data dir
- Update .gitignore and add README.md for test data usage
- Copy test data files in Fuchs.Tests.csproj; add .gitkeep
- Refactor BankingService CAMT mapping logic
- Overhaul connection string config: use {username}/{password} tokens, resolve from secrets at runtime, update appsettings and Key Vault keys
Front-end (fis.inv_shared.js / fis.inv_txt_de.js, rebuilt bundles):
- 3-way set display switch (setprice/itemprices/setonly) via admin.setmode,
emitted into InvoiceOptions by FdsInvoiceData.BuildInvoiceOptions.
- Each request block now posts items[] in the backend contract shape
(title/desc/qty/price_net/total_net + set type/setId tags) via itemToContract.
- invcPayload normalises the editor model to the field names BuildInvoiceParams
reads (sms totals -> new.total_net/total_gross, invoicetitle->title,
loc->provisionlocation, admin.paymentterms->new.paymentterm, CustomerId->customerid).
Back-end:
- BuildInvoiceOptions adds the setmode token alongside §13b.
- VAT rate+amount now taken from sms.vat (HighestVat) instead of the broken
items 'is List<object>' detection that pinned the rate to 19.
- InvoiceSetPricing blanks price/total cells for text/title heading lines.
Tests: set-pricing text-line blanking, HighestVat selection/parsing, updated
the VAT param test to the sms.vat contract. 180 passing.
Note: the second VAT slot (InvoiceVAT_2) stays unused by design; mixed-rate
invoices store only the highest rate (pre-existing, accepted).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sets (mfr__items Type='set') can be shown three ways on the invoice:
- SetPrice (default): set line priced, member items shown without price
- ItemPrices: member items priced, set line as a heading without price
- SetOnly: only the set line (priced), members removed
- InvoiceSetPricing (new): the authoritative, unit-tested transformation
(SetDisplayMode + Build) that both sides agree on; set price always equals the
sum of members. Mode is read from InvoiceOptions ("setmode:<mode>").
- FuchsPdf.ApplyInvoice renders through it: lines flagged ShowPrice=false print
blank price/total cells; set headers are emphasised. Invoices without sets are
unchanged. Totals come from the registration balance, so modes are purely
presentational and never change the sum.
- InvoiceSetPricingTests (+14): all three modes, set-price = member sum, header
total fallback, no-set pass-through, option parsing.
- Docs/INVOICE_SET_PRICING.md documents the front-end contract (the editor sets
the mode token + tags set header/member items); the back-end does the rest.
Front-end editor wiring is specified in the doc but intentionally not shipped
blind (cannot validate the running editor here).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New CAMTParser project: namespace-agnostic parser for camt.052/053/054
producing a statement/entry model aligned with the banking columns
(account, amount, debit/credit, dates, counterparty, references, remittance).
- BankingService now auto-detects the upload format (XML→CAMT, else MT940)
and maps either into the same fds__tt__bankingtransactions DataTable, so the
bam/up handler transparently accepts both.
- Frontend (fis.bam.de.js) upload field now advertises accept for both
MT940 (.sta/.mt940/.txt) and CAMT (.xml/.camt).
- Tests (+14, 151 total): CamtParserTests cover parsing (credit/debit,
namespace-version agnostic, reversals), detection, and failure/edge inputs
(empty, invalid XML, non-CAMT); BankingDualFormatTests verify CAMT and MT940
both land in the same DataTable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the intranet off the static-helper / Active-Record pattern onto
constructor-injected services, removing controller coupling and the
sync-over-async (Task.Run().Wait()) hot spots in the data classes.
Services now registered and consumed via DI:
- IBankingService, IPdfService, IMfrClientFactory (singletons)
- IWidgetService, IReportService, IInvoiceService, IReminderService (scoped)
Key changes:
- FuchsWidgetService: real widget logic (sql_table/indicator/html +
rendering_options) ported from the static class, which is deleted.
- FuchsReportService + FuchsVisualization: report engine decoupled from
IntranetController (takes connStr/dbSec/userAccountId); static
FuchsReports deleted.
- InvoiceService / ReminderService: implement load/register/render/store
(previously NotImplementedException stubs). FdsInvoiceData /
FdsReminderData are now pure data holders — all DB + PDF work moved into
the services, async throughout (no Task.Run().Wait()).
- Controllers inject and call the services; all `new FdsMfrClient()` calls
go through IMfrClientFactory.
- Deleted dead code: static Banking, FuchsWidgets, FuchsReports, and the
unused IDbConnectionFactory.
- InternalsVisibleTo("Fuchs.Tests") for testing internal mapping logic.
Tests: 127 passing (Banking tests moved to the service; added data-holder
tests for FdsInvoiceData/FdsReminderData). Full solution builds clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Close functional regressions found by comparing the legacy applications
(Intranet_Legacy/) against their C# counterparts:
- ProcessWebComService: send attachments inline (base64) with the
push_com POST so invoice/reminder PDFs are attached again.
- FuchsPdf: wire GetPaycode into ApplyInvoice/ApplyReminder to restore
the SEPA giro-code payment QR, and restore the full standard invoice
text block (§35a labor-cost note, Akonto text, §14/§48 notes, AGB,
Steuernummer, Verrechnungssätze, etc.).
- IntranetController: restore changepassword validation (password
strength, confirmation match, current-password verification) and the
mfr empty-id OData $metadata response.
- Reports: port the ocms_visualization engine to C# (FuchsVisualization)
and wire FuchsReports.ProcessFdsRequest to render generic/
generic_content/chart reports instead of returning an empty OK stub.
Adds smoke tests for the giro QR generator and report page builder.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bump Microsoft.IdentityModel.* packages to 8.19.1 in MFR_RESTClient and OCORE. Update Microsoft.NET.Test.Sdk and coverlet.collector in Fuchs.Tests. Refresh OCORE submodule reference. No functional changes; dependency updates only.
Upgraded multiple NuGet packages to latest versions across all projects, including test and core dependencies. Updated OCORE, OCORE_web, and OCORE_web_pdf project references to use local paths. Added OCORE-related projects to the solution file with environment-specific build configs. Fixed package.json structure for valid JSON.