diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2026-05-11 16:16:24 -0400 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2026-05-11 16:16:24 -0400 |
| commit | af2de318402df1fd8d33192d71613c21c4ee96bf (patch) | |
| tree | 473c33981032bc73f5a5f4282ef8b1292333ce28 /cost.go | |
| parent | fcfe73600c8548d45820176d58f1c8cfc2327810 (diff) | |
| download | lulu-af2de318402df1fd8d33192d71613c21c4ee96bf.zip | |
implement POST /print-job-cost-calculations
Diffstat (limited to 'cost.go')
| -rw-r--r-- | cost.go | 134 |
1 files changed, 46 insertions, 88 deletions
@@ -1,38 +1,42 @@ package lulu -// TODO: should we remove the redundant tax/subtotal fields or remain -// true to their retarded api? - import ( "encoding/json" - "fmt" "github.com/shopspring/decimal" ) -// printJobCostReq is the json body of a /print-job-cost-calculations/ request. type printJobCostReq struct { - LineItems []printJobCostLineItem `json:"line_items"` - ShipAddr ShippingAddress `json:"shipping_address"` - ShipOpt ShippingLevel `json:"shipping_option"` + LineItems []PrintJobCostLineItem `json:"line_items"` + ShipAddr printJobCostReqShipAddr `json:"shipping_address"` + ShipOpt ShippingLevel `json:"shipping_option"` } -type printJobCostLineItem struct { +type PrintJobCostLineItem struct { NPages uint `json:"page_count"` Mfg PkgId `json:"pod_package_id"` Quantity uint `json:"quantity"` } +type printJobCostReqShipAddr struct { + City string `json:"city"` + Country string `json:"country_code"` + PostCode string `json:"postcode"` + State string `json:"state_code"` + Street1 string `json:"street1"` + Phone string `json:"phone_number"` +} + // PrintJobCost is the response from /print-job-cost-calculations/. type PrintJobCost struct { Addr, SuggestedAddr ShippingAddress - AddrWarning ShippingAddressWarning - Currency string + AddrWarnings []ShippingAddressWarning Fees []Fee - FulfillmentCost FulfillmentCost LineItemCosts []LineItemCost ShipCost FulfillmentCost - TotalCostExclTax, TotalCostInclTax, TotalDiscount, TotalTax decimal.Decimal + FulfillmentCost FulfillmentCost + TotalTax, TotalCostExclTax, TotalCostInclTax, TotalDiscount decimal.Decimal + Currency string } type ShippingAddressWarning struct { @@ -53,113 +57,67 @@ type Fee struct { } type FulfillmentCost struct { - TaxRate decimal.Decimal `json:"tax_rate"` TotalCostExclTax decimal.Decimal `json:"total_cost_excl_tax"` TotalCostInclTax decimal.Decimal `json:"total_cost_incl_tax"` TotalTax decimal.Decimal `json:"total_tax"` + TaxRate decimal.Decimal `json:"tax_rate"` } type LineItemCost struct { - CostExclDiscounts decimal.Decimal `json:"cost_excl_discounts"` - Discounts []Discount `json:"discounts"` - Quantity uint `json:"quantity"` - TaxRate decimal.Decimal `json:"tax_rate"` - TotalCostExclDiscounts decimal.Decimal `json:"total_cost_excl_discounts"` - TotalCostExclTax decimal.Decimal `json:"total_cost_excl_tax"` - TotalCostInclTax decimal.Decimal `json:"total_cost_incl_tax"` - TotalTax decimal.Decimal `json:"total_tax"` - UnitTierCost *decimal.Decimal `json:"unit_tier_cost"` + CostExclDiscounts decimal.Decimal `json:"cost_excl_discounts"` + TotalTax decimal.Decimal `json:"total_tax"` + TaxRate decimal.Decimal `json:"tax_rate"` + Quantity uint `json:"quantity"` + TotalCostExclTax decimal.Decimal `json:"total_cost_excl_tax"` + TotalCostExclDiscounts decimal.Decimal `json:"total_cost_excl_discounts"` + TotalCostInclTax decimal.Decimal `json:"total_cost_incl_tax"` + Discounts []Discount `json:"discounts"` + UnitTierCost decimal.Decimal `json:"unit_tier_cost"` } type Discount struct { - Amount decimal.Decimal `json:"amount"` - Descr string `json:"description"` + Amount decimal.Decimal `json:"amount"` + Description string `json:"description"` } -// printJobCostResp is the json body of a /print-job-cost-calculations/ response. type printJobCostResp struct { - Addr struct { - City string `json:"city"` - CountryCode string `json:"country_code"` - IsBusiness bool `json:"is_business"` - Name string `json:"name"` - Phone string `json:"phone_number"` - PostCode string `json:"postcode"` - StateCode string `json:"state_code"` - Street1 string `json:"street1"` - Street2 string `json:"street2"` - Warning ShippingAddressWarning `json:"warnings"` - Suggested suggestedShippingAddress `json:"suggested_address"` - } `json:"shipping_address"` - Currency string `json:"currency"` + Addr json.RawMessage `json:"shipping_address"` Fees []Fee `json:"fees"` - FulfillmentCost FulfillmentCost `json:"fulfillment_cost"` LineItemCosts []LineItemCost `json:"line_item_costs"` ShipCost FulfillmentCost `json:"shipping_cost"` + FulfillmentCost FulfillmentCost `json:"fulfillment_cost"` + TotalTax decimal.Decimal `json:"total_tax"` TotalCostExclTax decimal.Decimal `json:"total_cost_excl_tax"` TotalCostInclTax decimal.Decimal `json:"total_cost_incl_tax"` TotalDiscount decimal.Decimal `json:"total_discount_amount"` - TotalTax decimal.Decimal `json:"total_tax"` -} - -// Some blockhead that Lulu hired thought it would be a good idea to use -// a string in one place and a number in another for the postal code. -// That's why this special struct is needed. -type suggestedShippingAddress struct { - CountryCode string `json:"country_code"` - StateCode string `json:"state_code"` - PostCode uint `json:"postcode"` - City string `json:"city"` - Street1 string `json:"street1"` - Street2 string `json:"street2"` + Currency string `json:"currency"` } func (c *PrintJobCost) UnmarshalJSON(data []byte) error { - // Lulu decided to put warnings and suggested_address INSIDE - // shipping_address in the response. So we unmarshal into an - // alias struct and then map onto our own structs. The - // alternative is to add everything to our ShippingAddress - // struct, but that would be confusing to users of this library: - // ShippingAddress would have semantics because some fields would - // be "optional". - var resp printJobCostResp if err := json.Unmarshal(data, &resp); err != nil { return err } - - addr := resp.Addr - c.Addr = ShippingAddress{ - City: addr.City, - CountryCode: addr.CountryCode, - IsBusiness: addr.IsBusiness, - Name: addr.Name, - Phone: addr.Phone, - PostCode: addr.PostCode, - StateCode: addr.StateCode, - Street1: addr.Street1, - Street2: addr.Street2, + if err := json.Unmarshal(resp.Addr, &c.Addr); err != nil { + return err } - sugad := addr.Suggested - c.SuggestedAddr = ShippingAddress{ - CountryCode: sugad.CountryCode, - StateCode: sugad.StateCode, - PostCode: fmt.Sprint(sugad.PostCode), // idiot - City: sugad.City, - Street1: sugad.Street1, - Street2: sugad.Street2, + var warnsAndSugg struct { + Warnings []ShippingAddressWarning `json:"warnings"` + Suggested ShippingAddress `json:"suggested_address"` } - c.AddrWarning = addr.Warning - - c.Currency = resp.Currency + if err := json.Unmarshal(resp.Addr, &warnsAndSugg); err != nil { + return err + } + c.SuggestedAddr = warnsAndSugg.Suggested + c.AddrWarnings = warnsAndSugg.Warnings c.Fees = resp.Fees - c.FulfillmentCost = resp.FulfillmentCost c.LineItemCosts = resp.LineItemCosts c.ShipCost = resp.ShipCost + c.FulfillmentCost = resp.FulfillmentCost + c.TotalTax = resp.TotalTax c.TotalCostExclTax = resp.TotalCostExclTax c.TotalCostInclTax = resp.TotalCostInclTax c.TotalDiscount = resp.TotalDiscount - c.TotalTax = resp.TotalTax - + c.Currency = resp.Currency return nil } |