...
Validation that affects the result (all failures THROW -> surface as HTTP 500):
commonValidator.ValidateCustomer (via AccountValidator.ValidateAccountGetOutput,
invoked as "BrightInvoiceService.GetByCustomerAsync"):
...
Validation that affects the result (all surface as HTTP 500 with a message):
- 0 customer rows -> "No customer found with Id '{id}'."
...
- 1 customer rows -> "Unique active customer could not be identified. Id: '{id}'."
...
- row has blank CustomerId -> "The customer returned did not have any CustomerId."
...
- returned id != requested -> "Returned customer '{row}' does not match requested '{id}'."
...
- MitId deactivated -> "The customer with Id '{id}' does not have an active MitId
...
- registration." (skipped if Settings.IgnoreMitIdStatus)
InvoicesValidator.ValidateGetInvoicesInput (invoked as "GetInvoices"): -
- blank customerId -> "Missing parameter 'AccountId'."
...
- dateFrom out of SQL range -> "Missing or invalid parameter 'DateFrom'.
...
- Provide a
...
- date between 1753-01-01 and 9999-12-31 (e.g. 2000-01-01)."
...
- dateTo out of SQL range -> "Missing or invalid parameter 'DateTo'.
...
- Provide a date between 1753-01-01 and 9999-12-31 (e.g. 2030-12-31)."
...
- dateFrom > dateTo -> "Parameter outside of allowed range:
...
- 'DateFrom' must
...
- be earlier than or equal to 'DateTo'."
...
- limit < 1 -> "Parameter outside of allowed range
...
- : 'Limit' must be 1 or greater."
(A missing/unparseable date query param binds to DateTime.MinValue, which is below SQL Server's datetime min; the range check catches this up front to avoid a cryptic SQL error.)
'Limit' must be 1 or greater."
(A missing/unparseable date query param binds to DateTime.MinValue, which is below SQL Server's datetime min; the range check catches this up front to avoid a cryptic SQL error.)
NOTE on status codes:
The two domain catches in the controller are commented out ("we make use of the internalerror500 for all errors inside the api"),
so a bad date or an unknown customer returns 500 (not 400/404). The validation messages above are wrapped by ValidationHelper into:
"The operation [{invokingMethodName}] could not be completed due to the following validation errors: \n <message(s)>" and that wrapped text becomes the 500 body.
--------------------------------------------------------------------------------
...
UDSMARK visibility variants are independent and compose. Each active flag appends its appends its own SQL clause; inactive flags add nothing (no runtime OR-gates).
- ExcludeParked = Settings.InvoiceExcludeParked ?? BCHEC VISEJPARKEREDE
...
- -> AND (UDSMARK IS NULL OR UDSMARK <= 25) (hide UDSMARK > 25)
...
- CheckUdsmark = Settings.InvoiceCheckUdsmark ?? BCHEC
...
- CHECKUDSMARK -> AND (UDSMARK IS NULL OR = 0 OR BETWEEN 2 AND 25) (also drops UDSMARK = 1)
...
- ShowOnlyDelivered = Settings.InvoiceShowOnlyDelivered ?? BCHEC VISKUNUDSKREVNE
...
- -> UDSMARK <= 25 + SNEX/DSEND delivery check (DELIVERYSTATE IN (5,9))
...
- ExcludeFutureDated = Settings.InvoiceExcludeFutureDated ?? BCHEC
...
- EJFREMTID -> AND BILAGSDATO <=
...
- @Today
...
- ExcludeAfregnTypes = Settings.InvoiceExcludeAfregnTypes (non-empty) ?? BCHEC W11_
...
- W12EJAFRTYP -> AND AFREGNTYPE NOT IN
...
- @ExcludeAfregnTypes
...
- OnlyRendered = !Settings.InvoiceShowAlsoInvoicesWithoutPdf (default true)
...
- -> AND EXISTS (AKONDDOC -> BDOC, DOCTYPE=1, DATALENGTH(PAYLOAD)>0,
...
- MIMETYPE LIKE @PdfMimeType)
Always-applied (Base query) filters, independent of the toggles above: -
- FIRMANR = @CompanyId, KUNDENR = @CustomerId
...
- TARIFART IN ('A-TOT','A-FAK') (header rows only; S-TOT excluded)
...
- (SWIBASVIS IS NULL OR SWIBASVIS = 1) (exclude SWIB-internal, non-visible)
...
- (SAMLREGNINGNR IS NULL OR SAMLREGNINGNR <= 0) (hide bills folded into a collective invoice)
...
- BILAGSDATO BETWEEN @DateFrom AND @DateTo
...
- ORDER BY BILAGSDATO DESC, REGNINGNR DESC, SWCOUNT DESC
...
- OFFSET 0 ROWS FETCH NEXT @Limit ROWS ONLY (@Limit = limit ?? 100)
--------------------------------------------------------------------------------
...
Field origin detail (top-level BrightInvoice):
- Id <- composite "{InstNr}-{ForbnNr}-{UdebNr}-{Id}" (Id = REGNINGNR)
...
- ServiceId <- ForsyningsartMapper.MapToBrightServiceType(ForsyningsArt, AfregnType)
...
- DueDate <- AKOND.
...
- FORFDATO
...
- InvoiceDate <- AKOND.BILAGSDATO
...
- Period <- MapPeriod(DATOFRA, DATOTIL)
...
- StartDate <- AKOND.DATOFRA
...
- EndDate <- AKOND.DATOTIL
...
- RemainingAmount <- AKOND.KR - PBSI PaidAmount (null unless both present)
...
- TotalAmount <- AKOND.KR
...
- InvoiceStatus <- MapInvoiceStatus(row).GetDisplayName()
...
- InvoiceType <- MapInvoiceType(row) ("pdf" if HasPdf else "missing")
...
- Info <- list assembled in the mapper (see above)
InvoiceStatus derivation (MapInvoiceStatus), in order:
1. KORTSTATUS == 99 -> "cancelled"
2. TotalAmount (KR) < 0 -> "credited"
3. SettlementDate (UDLIGNDATO) set -> "paid" (regardless of PaidAmount)
4. PaidAmount >= TotalAmount -> "paid"
5. DueDate < today (and not fully paid)-> "overdue"
6. PaidAmount > 0 -> "partly_paid"
7. otherwise -> "unpaid"
(collection / reminder / deferred_* / investigation / paid_out are never returned — TODO.)
...