From 5277672f1ed7b57c3edbc363f17c1b668a6b8436 Mon Sep 17 00:00:00 2001 From: Matthieu 'JP' DERASSE Date: Sun, 13 Aug 2023 12:09:47 +0000 Subject: [PATCH] feat(inventory): Be able to handle both type of tesla response --- .drone.yml | 1 - inventory.go | 33 ++++++++++++++++++++ inventory_struct.go | 74 ++++++++++++++++++++++++++++----------------- 3 files changed, 79 insertions(+), 29 deletions(-) diff --git a/.drone.yml b/.drone.yml index 02192b9..628e76a 100644 --- a/.drone.yml +++ b/.drone.yml @@ -80,7 +80,6 @@ steps: ``` {{commit.message}} ``` 🌐 {{ build.link }} - format: markdown when: status: - failure diff --git a/inventory.go b/inventory.go index 21fab46..9e6f72e 100644 --- a/inventory.go +++ b/inventory.go @@ -5,8 +5,41 @@ import ( "encoding/json" "fmt" "net/url" + "strconv" + "strings" ) +// UnmarshalJSON come overide default unmarshal on availabilitiesReponse to handle both type of response sent by Tesla Inventory API. +func (a *AvailabilitiesResponse) UnmarshalJSON(data []byte) error { + if !strings.Contains(string(data), "\"total_matches_found\":\"") { + type TmpJson AvailabilitiesResponse + var tmpJson TmpJson + + err := json.Unmarshal(data, &tmpJson) + if err != nil { + return err + } + + *a = AvailabilitiesResponse(tmpJson) + return nil + } + + var exactAvailabilities AvailabilitiesExactResponse + err := json.Unmarshal(data, &exactAvailabilities) + if err != nil { + return err + } + + amount, err := strconv.Atoi(exactAvailabilities.TotalMatchesFound) + if err != nil { + return err + } + a.TotalMatchesFound = amount + a.Results.Exact = exactAvailabilities.Results + + return nil +} + // GetAvailabilities return the car availabilities matching with the provided characteristics. func (c *Client) GetAvailabilities(ctx context.Context, params AvailabilityParams, headers map[string]string) (*AvailabilitiesResponse, error) { b, err := json.Marshal(params) diff --git a/inventory_struct.go b/inventory_struct.go index aae33f6..3c473e9 100644 --- a/inventory_struct.go +++ b/inventory_struct.go @@ -131,40 +131,40 @@ const ( // AvailabilityParams is the params accepted by the API. type AvailabilityParams struct { Query AvailabilityQueryParams `json:"query"` - Offset int `json:"offset"` - Count int `json:"count"` - OutsideOffset int `json:"outsideOffset"` - OutsideSearch bool `json:"outsideSearch"` + Offset *int `json:"offset,omitempty"` + Count *int `json:"count,omitempty"` + OutsideOffset *int `json:"outsideOffset,omitempty"` + OutsideSearch *bool `json:"outsideSearch,omitempty"` } // AvailabilityQueryParams are the params to filter results. type AvailabilityQueryParams struct { - Arrangeby arrangeByEnum `json:"arrangeby"` - Condition conditionEnum `json:"condition"` - Language string `json:"language"` - Lat float64 `json:"lat"` - Lng float64 `json:"lng"` - Market string `json:"market"` - Model modelEnum `json:"model"` - Options OptionsParams `json:"options"` - Order orderByEnum `json:"order"` - Range int `json:"range"` - Region string `json:"region"` - SuperRegion string `json:"super_region"` - Zip string `json:"zip"` + Arrangeby *arrangeByEnum `json:"arrangeby,omitempty"` + Condition *conditionEnum `json:"condition,omitempty"` + Language *string `json:"language,omitempty"` + Lat *float64 `json:"lat,omitempty"` + Lng *float64 `json:"lng,omitempty"` + Market *string `json:"market,omitempty"` + Model *modelEnum `json:"model,omitempty"` + Options *OptionsParams `json:"options,omitempty"` + Order *orderByEnum `json:"order,omitempty"` + Range *int `json:"range,omitempty"` + Region *string `json:"region,omitempty"` + SuperRegion *string `json:"super_region,omitempty"` + Zip *string `json:"zip,omitempty"` } // OptionsParams contain the car option. type OptionsParams struct { - AdditionalOptions []string `json:"ADL_OPTS"` - Autopilot []autopilotEnum `json:"AUTOPILOT"` - CabinConfig []cabinConfigEnum `json:"CABIN_CONFIG"` - Interior []interiorEnum `json:"INTERIOR"` - Paint []paintEnum `json:"PAINT"` - SteeringWheel []steeringWheelEnum `json:"STEERING_WHEEL"` - Trim []trimEnum `json:"TRIM"` - Wheels []wheelsEnum `json:"WHEELS"` - Year []string `json:"Year"` + AdditionalOptions []string `json:"ADL_OPTS,omitempty"` + Autopilot []autopilotEnum `json:"AUTOPILOT,omitempty"` + CabinConfig []cabinConfigEnum `json:"CABIN_CONFIG,omitempty"` + Interior []interiorEnum `json:"INTERIOR,omitempty"` + Paint []paintEnum `json:"PAINT,omitempty"` + SteeringWheel []steeringWheelEnum `json:"STEERING_WHEEL,omitempty"` + Trim []trimEnum `json:"TRIM,omitempty"` + Wheels []wheelsEnum `json:"WHEELS,omitempty"` + Year []string `json:"Year,omitempty"` } /** @@ -438,8 +438,26 @@ type Availability struct { FirstRegistrationDate any `json:"FirstRegistrationDate,omitempty"` } +/** +* Tesla inventory API have to kind of response by on the result. +* Either you have a exact response (most of the case) +* Either you have a multiple availability based on the level of match with your filters +* +* I have decided to use the 2nd format in the inventory SDK as it can handle both cases +**/ + +// AvailabilitiesExactResponse contain the a list of car availability. +type AvailabilitiesExactResponse struct { + Results []Availability `json:"results"` + TotalMatchesFound string `json:"total_matches_found"` +} + // AvailabilitiesResponse contain the a list of car availability. type AvailabilitiesResponse struct { - Results []Availability `json:"results,omitempty"` - TotalMatchesFound string `json:"total_matches_found,omitempty"` + Results struct { + Approximate []Availability `json:"approximate"` + ApproximateOutside []Availability `json:"approximateOutside"` + Exact []Availability `json:"exact"` + } `json:"results"` + TotalMatchesFound int `json:"total_matches_found"` }