riteaid

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 13, 2023 License: MIT Imports: 11 Imported by: 0

README

RiteAid Store Search WebAPI Wrapper

WARNING! This is my VERY first Go project so their maybe defiantly are dragons! 🔥🐉

The test module is still being tweaked to ensure I have accounted for all the dragon eggs 🥚 that may hatch in the future.

What it do? 🔎

This module is a wrapper for the RiteAid Store search API. The date and times are store location / timezone aware and will always be returned with the store locality in mind. This way calculations can traverse timezones accurately

Why I do? ✨

I'm a field tech and I close a lot of repair tickets for RiteAid and the tools I have to managed routing/trip planning are meh 🤷.

🤓 So, I am creating/created tools to streamline my workflow and this module is one of those tools.

Who else would do?

Someone whom wants to query the RiteAid store data would find this useful. It's kinda niche so I don't expect much if any interest in the project.

Example Usage:

// Get a specific store data by entering stores known address with a minimal search radius
storeAddress := "4 Walton St E, Willard, OH 44890"
searchRadius := 0.1
rawJsonResult, err := GetStoreData(storeAddress, searchRadius)
if err != nil {
    panic(err)
}
os.WriteFile("storeData.json", []byte(rawJsonResult), 0644)
storeAddress := "4 Walton St E, Willard, OH 44890"
searchRadius := 0.1

// Get Store Data as a struct
searchResults, err := GetStoreDataStruct(storeAddress, searchRadius)
if err != nil {
    panic(err)
}
storeData := searchResults.Data.Stores[0]

// Get the store hours for today
var storeHours [2]time.Time
var rxHours [2]time.Time
storeHours, rxHours, err := GetStoreHours(time.Now().Format(DateFormat), storeData)
if err != nil {
    panic(err)
}

fmt.Printf("Store Hours: %s\n", storeHours)
fmt.Printf("Rx Hours: %s\n", rxHours)

// Is the store and rx open?
isOpenStore, isOpenRX, err := IsStoreOpen(time.Now(), storeData)
if err != nil {
    panic(err)
}

fmt.Printf("Is Store Open: %t\n", isOpenStore)
fmt.Printf("Is RX Open: %t\n", isOpenRX)

TODO / Known Issues:

  • Initial Alpha release!
  • FIX BUG: GetStoreHours fails to account for Daylight Savings
    • Issue was corrected with inclusion of github.com/zsefvlol/timezonemapper which doesn't appear to be actively maintained. Thus, I'll need to look over the code and see if I need to make changes to it, but at the moment it works well.
    • BUG: Weekday tests are failing, this is due to issues implementing the new external module.
  • Finish Test Routines
  • Code Review
  • Code Review AGAIN!
  • Remove the "DEPRECIATED" functions and put them into their own module or snippets as they are for special use cases that really only apply to a field tech.

Documentation

Index

Constants

View Source
const (
	TimeFormat   = "3:04pm"
	TimeFormat_M = "3:04 PM"

	// DateFormat is the format used by the RiteAid API
	DateFormat = "2006-01-02"

	// DateFormatm is the format used by the RiteAid API for the date with the time
	//  i.e. "2006-01-02 3:04pm"
	DateTimeFormat = DateFormat + " " + TimeFormat

	// DateFormat_M is the format used by the RiteAid API for the date with the time
	//  i.e. "2006-01-02 3:04 PM"
	DateTimeFormat_M = DateFormat + " " + TimeFormat_M
)

Variables

View Source
var ErrRadiusOverMax = errors.New("radius is greater than 25 the API will only return a max of 25 stores")

Error returned when the radius is over the maximum value (This error can be ignored as it will default to 25 when over)

View Source
var ErrRadiusUnderMin = errors.New("radius is less than 0 this MUST be 0 or greater")

Error returned when the radius is under the minimum value

View Source
var ErrRiteAidAPIError = errors.New("RiteAid API returned an error")

Error returned when RiteAid API returns an error

View Source
var ErrTimeParseOrder = errors.New("parsed start time is after parsed end time")

Error returned when a parsed time span is out of expected order.

Expected order is: "8:00am-5:00pm" || "8:00 AM-5:00 PM"

Functions

func GetFedExPickupURL

func GetFedExPickupURL(storeData Store, FedExTracking string) string

Returns a FedEx URL for scheduling in store package pickup

!! DEPRECIATED: Function has a very specific use case.

// This is a standard tracking number
GetFedExPickupURL(storeData, "123456789012")

// This is a 2D barcode
GetFedExPickupURL(storeData, "9622013140009780845100123456789012")

// This is the OCR from above the 2D barcode.
GetFedExPickupURL(storeData, "9622 0131 4 (000 000 0000) 0 00 1234 5678 9012")

The FedEx Tracking Number can be data directly from the label's barcode.

func GetMapURL

func GetMapURL(storeData Store) string

Ancillary function that returns a Google Maps URL to the store. This function is depreciated and will be removed in the future.

!! DEPRECIATED: Function has a very specific use case.

func GetStoreAddress

func GetStoreAddress(storeData Store) string

Returns the store address for the given store. This is primarily a helper function used internally but may be useful.

storeAddress, err := GetStoreAddress(storeData) ->
  "Rite Aid, 4 East Walton Street, Willard, OH 44890-9419"

func GetStoreDataJSON

func GetStoreDataJSON(address string, radius float64) (string, error)

Function will place call to RiteAid API and return the store location data. It is recommended to keep the radius as small as possible to minimize the data received unless importing multiple stores for caching purposes.

ADDRESS: The address of the store. i.e. "4 Walton St E, Willard, OH 44890" (required)

RADIUS: The radius in miles of the address to search. i.e. 3 (required - must be between 0.01 and 25)

RETURNS: The raw store location data. This is the string value returned from the API call in JSON format

func GetStoreHours

func GetStoreHours(date string, storeData Store) ([2]time.Time, [2]time.Time, error)

Retrieves the store hours for a given date. This takes into account the store's TimeZone and holiday hours.

// First return pair is the store hours.
// Second return pair is the rx hours.
var storeHours [2]time.Time
var rxHours [2]time.Time
storeHours, rxHours, err := GetStoreHours("2022-05-30", storeData)

func GetTZLocation

func GetTZLocation(longitude float64, latitude float64) (*time.Location, error)

func IsStoreOpen

func IsStoreOpen(dateTime time.Time, storeData Store) (bool, bool, error)

Returns true if the store is open at the given date and time.

// First return is the store.
// Second return is the pharmacy.
loc, _ := time.LoadLocation(storeData.TimeZone)
dateTime, _ := time.ParseInLocation("2006-01-02 3:04PM", "2022-05-29 8:00PM", loc)
isOpenStore, isOpenRX, _ := IsStoreOpen(dateTime, storeData)
fmt.Printf("Is Store Open: %t\n", isOpenStore)
fmt.Printf("Is RX Open: %t\n", isOpenRX)

func ParseTimeSpan

func ParseTimeSpan(timeRange string, date string, latitude float64, longitude float64) (time.Time, time.Time, error)

ParseTimeSpan takes a time range string and parses it into a start and end time. The time zone is required to ensure proper calculations based on the locality of the user, the store, and the server.

timeRange i.e. "8:00am-5:00pm" || "8:00 AM-5:00 PM"
     date i.e. "2006-01-02"
 timeZone i.e. "MST"

startTime, endTime, err := ParseTimeSpan("8:00am-5:00pm", "2006-01-02", )

func ParseWeekDayHours

func ParseWeekDayHours(weekday time.Weekday, timeRange string, longitude float64, latitude float64) (time.Time, time.Time, error)

ParseWeekDayHours takes a time range string and parses it into a start and end time for a given weekday

Types

type Data

type Data struct {
	Stores          []Store         `json:"stores"`
	GlobalZipCode   string          `json:"globalZipCode,omitempty"`
	ResolvedAddress ResolvedAddress `json:"resolvedAddress"`
	Warnings        []string        `json:"warnings"` // TODO: This is a guess and needs verified

}

type HolidayHours

type HolidayHours struct {
	HolidayDate   string `json:"holidayDate,omitempty"`
	StoreHours    string `json:"storeHours"`
	PharmacyHours string `json:"pharmacyHours"`
}

type PickupDateAndTimes

type PickupDateAndTimes struct {
	RegularHours []string          `json:"regularHours"`
	DefaultTime  string            `json:"defaultTime"`
	Earliest     string            `json:"earliest"`
	SpecialHours map[string]string `json:"specialHours,omitempty"` // SpecialHours is returned with multiple values. Ex. {"2022-05-28": "1:00 PM-5:00 PM"}
}

SpecialHours is mapped as the key names are dynamic and not known ahead of time

i.e. "2006-01-02" -> "3:04pm-5:00pm"

type ResolvedAddress

type ResolvedAddress struct {
	AddressLine       string  `json:"addressLine"`
	AdminDistrict     string  `json:"adminDistrict"`
	Altitude          float64 `json:"altitude"`
	Confidence        string  `json:"confidence"`
	CalculationMethod string  `json:"calculationMethod"`
	CountryRegion     string  `json:"countryRegion"`
	DisplayName       string  `json:"displayName"`
	District          string  `json:"district"`
	FormattedAddress  string  `json:"formattedAddress"`
	GeocodeBestView   struct {
		NorthEastElements struct {
			Altitude  float64 `json:"altitude"`
			Latitude  float64 `json:"latitude"`
			Longitude float64 `json:"longitude"`
		}
		SouthWestElements struct {
			Altitude  float64 `json:"altitude"`
			Latitude  float64 `json:"latitude"`
			Longitude float64 `json:"longitude"`
		}
	}
	Latitude   float64 `json:"latitude"`
	Locality   string  `json:"locality"`
	Longitude  float64 `json:"longitude"`
	PostalCode string  `json:"postalCode,omitempty"`
	PostalTown string  `json:"postalTown,omitempty"`
}

type Result

type Result struct {
	Data      Data   `json:"data,omitempty"`
	Status    string `json:"Status"`
	ErrCde    string `json:"ErrCde,omitempty"`
	ErrMsg    string `json:"ErrMsg,omitempty"`
	ErrMsgDtl string `json:"ErrMsgDtl,omitempty"`
}

RiteAid store api returned a defined JSON structure. As of 5/29/2022 the structure is accurate but is subject to change as the API evolves.

Known issues:

  • The API returns are not fully mapped and some are being omitted from the struct
  • Warnings is not verified
  • AmbiguousAddresses is being omitted from import

func GetStoreData

func GetStoreData(address string, radius float64) (Result, error)

Function will place call to API and return the store location data as a struct. It is recommended to keep the radius as small as possible to minimize the data received unless importing multiple stores for caching purposes.

ADDRESS: The address of the store. i.e. "4 Walton St E, Willard, OH 44890" (required)

RADIUS: The radius in miles of the address to search. i.e. 3 (required - must be between 0.01 and 25)

RETURNS: The store location data as a struct. In addition, if the API call fails, a ErrRiteAidAPIError will be raised

type Store

type Store struct {
	StoreNumber         uint32   `json:"storeNumber"`
	Address             string   `json:"address"`
	City                string   `json:"city"`
	State               string   `json:"state"`
	Zipcode             string   `json:"zipcode"`
	TimeZone            string   `json:"timeZone"`
	FullZipCode         string   `json:"fullZipCode"`
	FullPhone           string   `json:"fullPhone"`
	LocationDescription string   `json:"locationDescription"`
	StoreHoursMonday    string   `json:"storeHoursMonday"`
	StoreHoursTuesday   string   `json:"storeHoursTuesday"`
	StoreHoursWednesday string   `json:"storeHoursWednesday"`
	StoreHoursThursday  string   `json:"storeHoursThursday"`
	StoreHoursFriday    string   `json:"storeHoursFriday"`
	StoreHoursSaturday  string   `json:"storeHoursSaturday"`
	StoreHoursSunday    string   `json:"storeHoursSunday"`
	RXHrsMon            string   `json:"rxHrsMon"`
	RXHrsTue            string   `json:"rxHrsTue"`
	RXHrsWed            string   `json:"rxHrsWed"`
	RXHrsThu            string   `json:"rxHrsThu"`
	RXHrsFri            string   `json:"rxHrsFri"`
	RXHrsSat            string   `json:"rxHrsSat"`
	RXHrsSun            string   `json:"rxHrsSun"`
	StoreType           string   `json:"storeType"`
	Latitude            float64  `json:"latitude"`
	Longitude           float64  `json:"longitude"`
	Name                string   `json:"name"`
	MilesFromCenter     float64  `json:"milesFromCenter"`
	SpecialServicesKeys []string `json:"specialServicesKeys,omitempty"`
	// Event string `json:"event"` // TODO - Not sure what this is.
	HolidayHours       []HolidayHours     `json:"holidayHours,omitempty"`
	PickupDateAndTimes PickupDateAndTimes `json:"pickupDateAndTimes"`
}

Event is not imported as the format is now known as of 2022/05/29

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL