================================================================================

 BrightProductsController - Summary & Response Structures

 File: SonWinCommonAPI/Controllers/BrightProductsController.cs

================================================================================


--------------------------------------------------------------------------------

 WHAT THE CONTROLLER DOES

--------------------------------------------------------------------------------

Exposes a single read endpoint that returns the price products / tariffs tied to

one customer + one service (metering point / EAN number) within a date range.

The data is read from the SonWin (Sonlinc) contract tables;

The query selects the contract "lines" for the requested EAN number.

--------------------------------------------------------------------------------

 METHODS

--------------------------------------------------------------------------------

1) GetProducts

   Route:    GET bright/products

   Auth:     [Authorize] (controller-level)

   Params:  

   Body:     none

   Returns: 

   What it does:

   Validation that affects the result (ALL failures surface as HTTP 500:

     Customer validation (AccountValidator.ValidateAccountGetOutput):

     Input validation (ProductsValidator.ValidateGetProductsAsyncInput):       

Output validation (ProductsValidator.ValidateGetProductsAsyncOutput):

--------------------------------------------------------------------------------

 RESPONSE STRUCTURE (IEnumerable<BrightProduct>)

--------------------------------------------------------------------------------

Top level is a JSON array of BrightProduct. One element per distinct AftageNr

(EAN). Because the query filters on a single @EanNumber, in practice there is

one group, and each contract row becomes one entry in that group's Prices list.

[
  {
    "ValidFrom": null,             // Hardcoded null 
    "ValidTo": null,               // Hardcoded null 
    "ServiceId": "<serviceId>",    // Echo of request serviceId param (MeteringPointId)
    "Prices": [
      {
        "Value": 0,                // Hardcoded 0 
        "Type": "kWh",             // Hardcoded "kWh" 
        "Note": null,              // Hardcoded null 
        "Name": "kWhPrice",        // Hardcoded "kWhPrice" 
        "ValidFrom": "<datetime>", // Data: AFORBKONTR.FRADATO (DbProduct.ContractActiveFrom)
        "ValidTo": "<datetime>",   // Data: AFORBKONTR.TILDATO (DbProduct.ContractActiveTo); null = open-ended
        "ValidHours": [],          // Not mapped 
        "ValidMonth": [],          // Not mapped 
        "ValidPart": null,         // Not mapped 
        "ValidFraction": null,     // Not mapped 
        "SubtractMeasurement": null// Not mapped 
      }
    ]
  }
]




Notes:

  - Property names above are the C# names; no [JsonPropertyName] attributes are

    present, so serialization uses the configured default casing.

  - Only TWO fields carry real data: Price.ValidFrom and Price.ValidTo (the

    contract's FRADATO/TILDATO). Everything else is hard-coded, null, or unmapped.

  - Product.ServiceId is the request input, so the output ServiceId always equals

    the requested serviceId by construction.

  - Grouping is by DbProduct.AftageNr (EANNR). Since the WHERE clause pins a

    single @EanNumber, expect a single product group in normal use.

  - The output validator rejects rows whose AftageNr differs from the requested

    serviceId; given the SQL filter (kontr.EANNR = @EanNumber, AftageNr = EANNR)

    this should not normally trigger.


--------------------------------------------------------------------------------

 DATA SOURCE (SQL: ProductSql.GetActiveProducts)

--------------------------------------------------------------------------------

Bound parameters (BrightProductRepository.GetActiveProductsAsync):

    @CompanyId  = Settings.CompanyId

    @CustomerId = customerId (request)

    @EanNumber  = serviceId  (request, "edielNumber")

    @StartDate  = DateFrom   (request)

    @EndDate    = DateTo     (request)


Tables / joins:

    FROM Sonlinc.AFORD ford                              (consumer)

    LEFT JOIN Sonlinc.AFORBKONTR kontr                   (contract link)

        ON ford.FIRMANR = kontr.FIRMANR AND ford.FORBNR = kontr.FORBNR

    INNER JOIN Sonlinc.BAKONTRAKT bKontr                 (actual contracts)

        ON bKontr.FIRMANR = ford.FIRMANR AND bKontr.KONTRAKT = kontr.KONTRAKT

    INNER JOIN Sonlinc.AUDEBFORS fors                    (supply type)

        ON fors.FIRMANR/INSTNR/FORBNR = ford.*

    INNER JOIN Sonlinc.audeb deb                         (debtor; electrical only)

        ON deb.* = ford.* AND deb.UDEBNR = fors.UDEBNR

    (A commented-out DGF/energikilde LEFT JOIN block is left in place for future use.)


WHERE:

    ford.FIRMANR = @CompanyId

    AND ford.KUNDENR = @CustomerId

    AND kontr.EANNR = @EanNumber

    AND ISNULL(ford.STATUS2N,0) < 1            (active consumer)

    AND ISNULL(fors.FORSYNINGSART,0) = 0       (electrical supply)

    AND (kontr.TILDATO IS NULL OR kontr.TILDATO >= @StartDate)

    AND kontr.FRADATO <= @EndDate

    ORDER BY ContractName


Selected columns -> DbProduct:

    ford.KUNDENR              -> CustomerId         (unused by mapper)

    ISNULL(kontr.kontrakt,'') -> ContractName       (unused by mapper)

    kontr.FRADATO             -> ContractActiveFrom -> Price.ValidFrom

    kontr.TILDATO             -> ContractActiveTo   -> Price.ValidTo

    ISNULL(bkontr.TYP,'')     -> ContractType       (unused by mapper)

    ISNULL(bkontr.LINTYPE,'') -> LineType           (unused by mapper)

    kontr.EANNR               -> AftageNr           (grouping key + output validation)


DbProduct columns NOT selected by the SQL (always null/default):

    Value, Type, Name, Note, PriceValidFrom, PriceValidTo

================================================================================