You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

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

 BrightLocationsController - Summary & Response Structures

 File: SonWinCommonAPI/Controllers/BrightLocationsController.cs

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


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

 WHAT THE CONTROLLER DOES

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

BrightLocationsController exposes a customer's locations (installations /

"installationer") and the supply-type services attached to them from the

SonWin/Sonlinc system, shaped into the "Bright" location contract. It requires

authorization ([Authorize]) and, on any thrown exception, goes through

CustomBase.HandleError which logs the error and returns HTTP 500 with the

exception message in the body.


IMPORTANT SCOPE LIMITATION:

Only ELECTRICITY supply is currently returned. The service query hard-codes

FORSYNINGSART = 0 (El), so even if an installation has water, heat, gas, etc.,

those services are not included today. (SQL for the other supply types exists

but is commented out / future work.)


Call chain:

    BrightLocationsController.GetLocations

      -> BrightLocationService.GetLocationByCustomerAsync   (validation + mapping)

  1. repository.GetLocationHeaderByCustomerAsync -> location headers
  2. repository.GetSonWinSupplyTypeDataAsync -> electricity services
  3. repository.GetSonWinSupplyRangeAsync -> supply start/end dates

      (SQL lives in LocationSql; sources are Sonlinc.AINSD / AFORD / AUDEBFORS /

       IndividualMPoints + SWMarket.* market tables for the dates.)


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

 METHODS

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


1) GetLocations

   Route:    GET /bright/locations

   Params:   customerId (required), limit (optional)  (+ CancellationToken)

   Returns:  200 OK -> IEnumerable<BrightLocation>

             400 BadRequest    (declared; see note below)

             401 Unauthorized

             404 NotFound      (declared; see note below)

   What it does:

     Returns the list of active locations for a customer, each with its

     electricity service(s). It first validates the customer exists

     (commonValidator.ValidateCustomer) and validates input

     (customerId required; limit, if supplied, must be 1-1000, default 100).

     It then loads location headers, loads the electricity services for those

     installations, attaches each service's current supply start/end dates, and

     maps everything to the BrightLocation response.


   Validation that affects the result (all surface as HTTP 500 with a message):

     - Missing customerId            -> "Missing parameter 'CustomerId'."

     - limit out of range (1-1000)   -> "Parameter outside of allowed range..."

     - No locations found            -> "No locations found for customer {id}"

     - A service with no start date   -> "Location with missing supply start

                                         date found for meteringpointid: {id}..."

       (Every returned service MUST have a supply start date or the whole call

        fails. The start/end dates come from the SWMarket supply-range query,

        which only returns the CURRENTLY active supply: FromDate <= today and

        ToDate is null or in the future.)


   NOTE on status codes: although 400 and 404 are declared via

   ProducesResponseType, the BadRequest branch is commented out in the

   controller. In practice every error (bad input, not found, missing dates,

   DB failure) currently comes back as HTTP 500 with the message in the body.


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

 RESPONSE STRUCTURE (BrightLocation)

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

Returned as a JSON ARRAY (IEnumerable<BrightLocation>), one element per active

installation for the customer.


[

  {

    "Id":        <value>     // Data: SonWin installation number (AINSD.INSTNR), as string

    "Address":   <value>     // Data: street + house number (AINSD.ADRESSE + AINSD.HUSNUMMER)

    "ZipCode":   <value>     // Data: postal code (AINSD.POSTNUM)

    "City":      <value>     // Data: city name (IPOST.NAVN, falling back to AINSD.STED; empty string if both null)

    "Properties": null       // Hardcoded null: BrightLocationProperties is never populated by the mapper

                             //   (PropertyType, NumberOfResidents, Size, HouseAge, Cars[], Heating,

                             //    HeatingSecondary, Gadgets[] are all unused today)

    "PriceZone": <value>     // Derived: from ZipCode -> "DK1" if zip >= 6000, "DK2" if zip < 6000,

                             //   null if the zip code cannot be parsed

    "Services": [            // Data: the electricity service(s) for this installation (empty array if none)

      {

        "Id":                    <value>  // Data: metering point id / EAN (IndividualMPoints.MeteringPointId, aka AftageNr)

        "Type":                  <value>  // Derived: mapped from SonWin forsyningsart. For electricity this is

                                          //   always "consumption_trade". (Other types map to water/heating/

                                          //   cooling/tv/broadband/waste/gas_trade, but only El is queried today.)

        "Status":                "Active" // Hardcoded: BrightServiceStatus.Active.ToString().

                                          //   NOTE: this emits the enum NAME "Active" (capital A), NOT the

                                          //   display value "active". TODO in code: derive real status from SonWin.

        "MeasurementResolution": <value>  // Derived from forsyningsart: electricity => "hour"

                                          //   (broadband => "none"; other types default to "none" - TODO).

        "MeasurementId":         <value>  // Data: metering point id (same value as Service.Id / AftageNr)

        "DeliveryPointId":       null     // Hardcoded null: never set by the mapper

        "CostResolution":        null     // Hardcoded null: never set by the mapper

        "CostId":                null     // Hardcoded null: never set by the mapper

        "Properties":            null     // Hardcoded null: BrightServiceProperties (ShowCost,

                                          //   RealtimeMeasurements) is never populated

        "StartDate":             <value>  // Data: current supply start date (SWMarket MeteringPointRoleOccurrence.FromDate),

                                          //   as DateTimeOffset (UTC/zero offset). Required - null fails validation.

        "EndDate":               <value>  // Data: current supply end date (SWMarket ...ToDate), as DateTimeOffset.

                                          //   OMITTED from the JSON entirely when null (JsonIgnore WhenWritingNull);

                                          //   null/absent means the supply has no scheduled end (still active).

      }

    ],

    "Longitude": null        // Hardcoded null: never set by the mapper

    "Latitude":  null        // Hardcoded null: never set by the mapper

  }

]


Notes:

  - Properties, Longitude and Latitude on the location are always null/absent.

  - On a service, DeliveryPointId, CostResolution, CostId and Properties are

    always null; Id and MeasurementId always carry the same metering point id.

  - Service.Status is the only hardcoded non-null literal and is currently the

    enum NAME "Active" rather than the lowercase display string "active".

  - EndDate is the only field deliberately omitted (not null) when it has no

    value, due to [JsonIgnore(WhenWritingNull)].

  - A location can have an empty Services array, but if a service IS present it

    must have a StartDate or the whole request fails validation.


  • No labels