Commit Graph
31 Commits
Author SHA1 Message Date
StefanandClaude Fable 5.1 546648533b fix(drafts): serialize draft session flushes and register reminders via fds__setReminder
Playwright Tests / test (push) Canceled after 0s
Make invoice/reminder live-draft edits concurrency-safe with an explicit
DraftFlushResult, add the fds__setReminder stored procedure, and harden the
date helper functions. Includes concurrency and SQL contract tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-01 13:57:40 +02:00
StefanandClaude Opus 5.5 d0002ccdad fix(invoices): send invoice amounts as exact cent-rounded decimals
Playwright Tests / test (push) Canceled after 0s
Stornorechnung saves still failed: the VAT amount was formatted invariantly
("-615.3757999999999") and re-parsed under the server's de-DE culture as
-6153757999999999, overflowing numeric(10,3) in fds__setInvoice.

- FdsInvoiceData.BuildInvoiceParams: amount params are decimal(10,x) via
  AmountParam/ParseAmount (culture-independent, rounded to cents); amounts
  beyond +/-9,999,999.99 throw InvoiceAmountOutOfRangeException.
- InvoiceService.RegisterInvoiceAsync: refuses such an invoice with a logged
  error (EventId InvoiceAmountRejected) instead of storing a wrong amount.
- Invoice editor: vat_val is cent-rounded decimal, no float noise.
- Tests: InvoiceAmountParamTests replaces the float-based Storno test.
- Bump Azure.Storage.Blobs 12.30.0; OCORE/OCORE_web submodules (AngleSharp
  1.8.3, Azure.Storage.Files.Shares 12.28.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:57:41 +02:00
Stefan c741535aec feat: Implement mfr truncation fix and enhance invoice handling
Playwright Tests / test (push) Canceled after 0s
- Added a new SQL script to address the "String or binary data would be truncated" error in mfr sync by widening the Note fields in service objects and companies to NVARCHAR(MAX).
- Updated the table types and associated stored procedures to accommodate the changes, ensuring compatibility with existing data.
- Queued a re-sync for previously rejected rows due to truncation issues.
- Created application logins for fuchs_fds and fuchs_web with placeholder passwords for initial setup.
- Introduced functions for invoice backdating and invoice date retrieval to streamline invoice processing.
- Developed a password generation function with customizable parameters for length and character types.
- Added a random number generation function to support password creation.
2026-09-30 16:56:08 +02:00
StefanandClaude Sonnet 5 99bf5337f8 fix: invoice/reminder PDF preview 404s and their unlogged root causes
An invoice's finalisation-time PDF render/store (fds__setInvoiceFile) can
fail silently; the row stays finalised with [file] = NULL and inv/rdoc
(the invoice list's preview icon) 404'd forever with no trace in any log.

- inv/rdoc and rem/idoc now regenerate and persist a missing document on
  read, mirroring the legacy VB "idoc" fallback (Fuchs_Database ADR 0025),
  gated to finalised + non-external invoices only — a draft render must
  never be persisted, since fds__setInvoiceFile/fds__setReminderFile only
  write WHERE [file] IS NULL and finalisation would then silently no-op.
- StoreInvoiceDocumentFileAsync/StoreReminderDocumentFileAsync now log
  every distinct failure (render threw, render produced 0 bytes, DB write
  threw, DB write matched 0 rows) instead of collapsing them into a single
  silent empty-array return. The 0-rows case needed switching from
  setSQLValue_async (reports success once the command completes, whatever
  the row count) to setSQLValue_async_result, whose AffectedRows makes a
  no-op UPDATE distinguishable from an actual write for the first time.
- HandleRequestIdoc/HandleReminderIdoc no longer treat
  StoreInvoiceDocumentFileAsync's Array.Empty<byte>() failure signal as
  success (a bare `ct == null` check never caught it), which would have
  served a 0-byte "PDF".
- rdoc/HandleRequestIdoc reject a missing 'id' form field instead of doing
  wasted work with an empty id.
- _BackupAndClearInvoiceFile.sql is annotated as a manual-only maintenance
  utility, never called from app code, so it's clear why running it leaves
  no application log trail.
- Client-side: $inv.pdfPreviewTimeout was 120 (ms) instead of 120000 — the
  preview dialog was timing out client-side after 120ms on every call.
- Fixed a genuine process-wide test flake: PdfPipelineTests and
  ERechnungMapperTests both install PdfSharp's global font resolver, and
  whichever ran first would win, making the other's tests fail
  deterministically once eRechnungLib's SystemFontResolver got there
  first. FuchsPdf.EnsureFontResolver is now also race-safe under
  concurrent first use (a check-then-set without a lock). Also removed
  the InvoiceService.PublishAsync failure logging added mid-session after
  code review found it duplicated every call site's own, more detailed
  logging against ADR 0024's single-write-path rule.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 21:07:24 +02:00
StefanandClaude Sonnet 5 bcf1f2dbb6 feat: migrate DB error logging onto the generic OCORE MultiLogger SQL sink
Playwright Tests / test (push) Canceled after 0s
Retires Fuchs_intranet.debug_log() and every direct EXECUTE [dbo].[fds__admin_logdebug]
call in favor of a single path: ILogger. A new SQL log sink (OCORE.MultiLogger.SqlLoggerProvider,
gated by Fuchs:Logging:SqlSink:Enabled, default on) mirrors every _logger.LogWarning/-Error/
-Critical call into [dbo].[fds__debuglog] via a new fds__admin_logdebug_ext proc, at Warning+.

- Program.cs registers the sink and RequestLogScopeMiddleware (request id/path/authenticated
  user, pushed after UseAuthentication) so every log line in a request — including ones written
  deep inside OCORE's SQL helpers — is attributed automatically.
- FIS_SQLOptions, IntranetController.Do's catch-all, PdfPreviewAsync, and the banking-upload
  handlers now log once, with an explicit EventId preserving the exact CodeReference text the
  retired debug_log() calls used to write, so existing dashboards/queries over fds__debuglog
  keep working unchanged.
- Fuchs_DataService/FdsMfr.cs's FdsSqlOptions had the identical double-write hazard (it's hosted
  in the same process per ADR 0010) — the original 2026-09-16 log review's mfr__getSchema/
  fds__getUpdateableRequests deadlock rows came from exactly this class. Fixed the same way.
- fds__debuglog gains LogLevel/Machine/Category/Account/AuthUser/IsDebug columns; the legacy
  fds__admin_logdebug proc is left in place unused, not dropped.
- FdsDebug.DebugLog (Fuchs_DataService's other ~9 call sites) deliberately left on its direct
  DB-write path — no ILogger call sits alongside it there, so no duplication risk today.

See ADR 0024 (supersedes 0023) and Docs/Concepts/error-logging-pipeline.md.

New tests: ErrorLoggingTests (FIS_SQLOptions), FdsSqlOptionsTests, RequestLogScopeMiddlewareTests.
694/694 pass (the 4 PdfPipelineTests failures seen under full-suite parallel runs are a
pre-existing, unrelated PdfSharp global-font-resolver test-isolation flake — they pass both
individually and in most full-suite runs).

Bumps the OCORE submodule to 3137b56 (SQL sink hardening: redaction matches short fragments
as whole identifier segments, per-entry-tolerant serialization, lazy dataSerialized, opt-in
SqlLoggerOptions.IncludeCategory, LogEntry.Category/AuthUser capture).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 17:20:06 +02:00
Stefan fce83c528f feat: Enhance error logging for PDF preview failures and SQL timeouts
- Implemented a new method `ShapeTableNames` to gather entity and navigation table names, ensuring no blanks or duplicates are included.
- Updated `FdsMfrClient` to handle cases where schema queries return no tables, logging appropriate warnings and preventing misleading errors.
- Introduced `PdfPreviewAsync` in `IntranetController` to manage PDF preview rendering, capturing detailed logs for failures and notifying users with readable error messages.
- Added comprehensive unit tests for error logging and table name shaping to ensure robustness and correctness.
- Documented decision to persist user action failures to the `fds__admin_logdebug` table, enhancing support diagnostics.
2026-09-16 16:35:04 +02:00
StefanandClaude Sonnet 5 52b2811b43 Render invoice-editor <img> elements on their own line
Playwright Tests / test (push) Canceled after 0s
<img> is a nominally inline HTML element, but TinyMCE content places images
between paragraphs of text; without a forced line break before/after, an
image could render packed against adjacent text in the PDF. Insert a line
break ahead of the image (unless one is already there) and always after it.
Also fixes the img handler's early-return path to still apply the inline
size cap (MaxInlineImageWidth/Height) when only one of width/height was
resized, matching the aspect-ratio-locked branch.

Fuchs/wwwroot/web/tools.js: cosmetic gulp rebuild diff (leading blank line),
no behavior change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 22:20:44 +02:00
StefanandClaude Fable 5.1 5fa7a2b50f Key the set-price menu modes on the set instead of the service-request block (ADR 0019)
"Set mit Preis" / "Nur Set mit Preis" collapsed every block into an inserted
"Gesamtumfang pauschal" row, nulled/removed all lines and cleared the user-defined
set structure. Both modes now convert every still-unconverted top-level set:
the set line takes the sum of its subtree, its members render without a price
(setprice) or are removed from itm + items (setonly); lines outside a set stay
individually priced and several sets stay separate lines. Nested sets are priced
once via their top-level set. One conversion primitive (ConvertSetHeader) now
backs all three triggers; item.setprice is a no-op on an already-converted set
(a repeated delta used to reset the set price to 0). The header's price_net is
mirrored too (flat PDF path unit price), and Build treats a null total_net as
"no price" like the flat path. The editor checks for a set before offering the
modes and the menu entry stays available for sets added later.

ADR 0009 is superseded by 0019; INVOICE_SET_PRICING.md rewritten accordingly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 22:19:01 +02:00
Stefan 22d2ef9c1a Refactor code structure for improved readability and maintainability
Playwright Tests / test (push) Canceled after 0s
2026-09-10 21:17:35 +02:00
StefanandClaude Sonnet 5 f407341f5f Parallelize invoice image fetch, add telemetry, generalize HtmlConverter
- InvoiceService.ResolveInlineImagesAsync now fetches an invoice's
  distinct whitelisted images concurrently (SemaphoreSlim-capped at 4)
  instead of one at a time. It ran inline on every invoice render,
  including repeated draft-preview renders, so N sequential mfr-portal
  round-trips could otherwise add N x latency to a user-facing request.
- Add fuchs.invoice.inlineimages.fetches (counter, tagged by outcome:
  success/http_error/bad_content_type/oversized/exception) and
  fuchs.invoice.inlineimages.resolve.duration (histogram) to
  FuchsTelemetry, matching the project's observability convention for
  outbound-HTTP operations.
- MigraDocExtensions.HtmlConverter's pre-resolved-image parameter is
  renamed inlineImages -> resolvedImages with generic docs: the
  converter fetches nothing and knows nothing about invoices — which
  images to resolve, and any whitelist/network policy, is entirely the
  caller's concern (InvoiceService, ADR 0018 today; any future caller
  tomorrow).
- Add tests asserting fetches actually overlap (not just faster) and
  that the new counter/histogram are recorded.
- Update ADR 0018 to describe the concurrent fetch, telemetry, and the
  generalized converter parameter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 21:17:09 +02:00
StefanandClaude Sonnet 5 406c6f2860 Fix invoice-image code-review findings: aspect ratio, whitelist config, stale refs
- MigraDocExtensions: fix a bug where capping an oversized explicit
  width+height image re-derived the other dimension from the image's
  native pixel ratio instead of scaling both sides uniformly, silently
  distorting a deliberately non-native-ratio (e.g. stretched) image.
- InvoiceService: derive the mfr-portal image whitelist prefix from the
  existing Fds:MFR_host config setting (via MFRClientConfig.RestRoot)
  instead of a second hardcoded literal, so it can't drift from the
  actual configured host; parse <img> sources with HtmlAgilityPack
  (already used by the PDF's own HTML converter) instead of a regex, so
  a decoy attribute like data-src can't be picked up in place of the
  real src; dedup fetch URLs with a HashSet instead of O(n^2) List
  scanning; reuse FuchsPdf.MigraDocFilenameFromByteArray instead of
  re-spelling the "base64:" prefix.
- Fix a stale log message and comment left over from the
  GenerateInvoicePdf -> GenerateInvoicePdfAsync rename, and update
  INVOICE_LIFECYCLE.md's references to the old sync method name.
- Add tests for the config-derived whitelist, a decoy-attribute src,
  and the 20-image-per-invoice fetch cap boundary.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 21:03:09 +02:00
StefanandClaude Sonnet 5 071982caec Render invoice-editor images (mfr portal only) into the PDF
The invoice line editor already shows <img> pictures pulled from the mfr
portal, but the PDF pipeline's HTML-to-MigraDoc converter had no <img>
handler, so they never appeared on the actual invoice.

InvoiceService now fetches only https://portal.mobilefieldreport.com/mfr/*
image sources before rendering (size/type/count capped, failures logged and
skipped) and hands the resolved images down through ApplyInvoice into the
HTML converter, which renders them inline at their original HTML position
and size (px converted to cm, capped against layout overflow). See ADR 0018.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 19:36:31 +02:00
StefanandClaude Sonnet 5 d16d168eee Add hierarchical invoice position numbering (ADR 0017)
Adds the InvoiceLineNumbering class that InvoiceDraftCalculator.
RecomputePositions, InvoiceSetPricing.AssignPositionLabels and their
callers already depend on (this dependency was pushed in ecc74cf
without the class itself, breaking the build) — position labels are
now hierarchical ("1", "1.1", "1.2", …) matching a line's ADR 0016
nesting level, computed by one pure, shared algorithm for both the
online editor and the PDF so they can never disagree (ADR 0008).

Also fixes an InvoiceDraftServiceTests assertion that still expected
the old flat integer position field; it is a string label now.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 09:09:43 +02:00
StefanandClaude Sonnet 5 94aa7cbfe4 Add Cc (Zusatzempfänger) recipient support for invoice emails
Lets an invoice carry an additional Cc recipient alongside the primary
SendToEmail, sent via the ProcessWeb mailer API. Honors the
Fuchs:Email:OverrideRecipient dev safety net: when the override is
active, Cc is dropped entirely (only the single override inbox is
ever reached), never leaked to it.

- IComService.SendEmailAsync / ProcessWebComService: new optional
  `cc` parameter, included in the mailer payload only when non-empty.
- FdsInvoiceData.RawInvoiceEmailCc + BuildInvoiceParams: reads
  `new.invoiceemailcc`, posts @SendToEmailCc.
- IntranetController.Requests: reads SendToEmailCc from the loaded
  invoice row and passes it through on send/resend.
- Fuchs_Database: SendToEmailCc column on fds__invoices, threaded
  through fds__createInvoice/fds__setInvoice/fds__getInvoice and the
  fds__tt__invoice_base/_core table types.
- fis.req_txt_de.js: "Zusatzempfänger (CC)" field label.
- Tests: ProcessWebComServiceTests (Cc included/omitted/dropped under
  override); SystemStatusServiceTests mocks updated for the new
  IComService.SendEmailAsync parameter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 09:09:29 +02:00
StefanandClaude Sonnet 5 ecc74cf3c6 Add user-defined invoice set structure dialog (ADR 0016)
Playwright Tests / test (push) Canceled after 0s
Lets a back-office user correct/define which invoice line belongs to
which "set" and how deep it is nested, instead of relying only on the
implicit "everything after a Set header until the next Set" grouping
fds__prepInvoice derives. Sets may contain sets; every change applies
immediately to the cached draft session and is reflected in the editor
and PDF (ADR 0006/0008).

Backend:
- InvoiceSetStructure: pure parent-link forest (assign, change level,
  create, place/move-sibling, depth-first linearise + level recompute).
- InvoiceDraftSetStructureDeltas: new inv/dpatch targets set.assign,
  set.level, set.create, set.move.
- InvoiceSetPricing.Build is now order-preserving and nesting-aware
  (governed by the nearest converted ancestor); the set-item switch
  sums a header's transitive descendants so nested conversions never
  double-count.
- FuchsPdf indents nested set members per level, mirroring the editor.

Frontend:
- New fis.inv_sets.js: "Set-Struktur bearbeiten" dialog — per-block
  table of all lines with drag & drop reorder (before/after/into),
  ▲▼ order and ◀▶ level buttons, fold/unfold per set (view-only), and
  a create bar for new Set/Text lines. Posts one delta per action; the
  dialog is a pure view of the server state (ADR 0006).
- _Layout.cshtml / fis_main.js: cache-bust the dynamically imported
  per-module bundles (web/fis.<mdl>.<locale>.js/.css) with an asset
  version derived from the newest bundle write time, so a gulp rebuild
  is picked up without a stale cached module.

Docs: ADR 0016, live-draft-editing concept, INVOICE_SET_PRICING.md,
USER_GUIDE.md, ARCHITECTURE.md updated. Tests: InvoiceSetStructureTests
(new) + additions to InvoiceDraftServiceTests/InvoiceSetPricingTests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 08:55:05 +02:00
Stefan 628802db19 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.
2026-07-18 18:01:24 +02:00
Stefan 49e3ed2673 Add unit tests for Fuchs_DataService and related components
- 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.
2026-07-16 13:34:23 +02:00
Stefan 5f85b75c22 added improvements on set proces and minor other improvements 2026-07-13 22:40:08 +02:00
Stefan 5c0fdc6c1d Changed Reminder Systematics analogue to invoices 2026-07-10 22:50:26 +02:00
Stefan 83d1c28b29 Refactor code structure and remove redundant sections for improved readability and maintainability 2026-07-10 21:03:55 +02:00
Stefan 42997c4f49 Refactor code structure for improved readability and maintainability 2026-07-10 14:29:51 +02:00
StefanandClaude Opus 4.8 af445c015e Add backend-authoritative invoice draft editing (ADR 0006/0007)
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>
2026-07-10 13:29:35 +02:00
Stefan e53d8962ad Update submodule references for OCORE, OCORE_Charting, OCORE_web, and OCORE_web_pdf to latest commits
Playwright Tests / test (push) Has been cancelled
2026-07-10 11:47:12 +02:00
Stefan 4abf81cd7d Refactor stored procedure and update project structure
Playwright Tests / test (push) Has been cancelled
- 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.
2026-07-06 00:01:35 +02:00
Stefan 882e97509a Enhance logging in FdsSqlOptions and related classes
- 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.
2026-07-03 20:22:05 +02:00
StefanandClaude Opus 4.8 bfc695ed6a Invoice set pricing: wire editor + align editor/backend contract
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>
2026-06-06 10:48:14 +02:00
StefanandClaude Opus 4.8 c358fdbdb2 Invoice set pricing: 3 display modes (backend contract + PDF + tests)
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>
2026-06-05 16:42:44 +02:00
StefanandClaude Opus 4.8 8dee630abb Complete DI migration: wire all business services end-to-end
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>
2026-06-05 12:57:59 +02:00
StefanandClaude Opus 4.8 c81619fa53 Restore legacy parity gaps lost in the VB.NET → C# migration
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>
2026-06-04 16:41:46 +02:00
Stefan b17baca835 Unify email/SMS via ProcessWeb Mailer API, remove legacy
Replaces legacy email/SMS logic with a new IComService abstraction using the ProcessWeb Mailer API for all outbound communication. Removes FuchsFdsEmail, FuchsEmailService, IEmailService, SmtpAccountSettings, and FuchsEmailSettings. Updates controllers to use IComService. Refactors appsettings.json to use a new "Mailer" section. Adds ProcessWebComSettings and a stub for secret management. Removes OCORE.sms.SMS77 and direct SMTP/MailKit usage. Cleans up solution file references to OCORE projects.
2026-05-18 08:11:21 +02:00
Stefan a4284234b2 Initial Commit after switching from SVN to git 2026-05-03 01:43:52 +02:00