aboutsummaryrefslogtreecommitdiffstats
path: root/cost.go
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2026-05-11 16:16:24 -0400
committerSam Anthony <sam@samanthony.xyz>2026-05-11 16:16:24 -0400
commitaf2de318402df1fd8d33192d71613c21c4ee96bf (patch)
tree473c33981032bc73f5a5f4282ef8b1292333ce28 /cost.go
parentfcfe73600c8548d45820176d58f1c8cfc2327810 (diff)
downloadlulu-af2de318402df1fd8d33192d71613c21c4ee96bf.zip
implement POST /print-job-cost-calculations
Diffstat (limited to 'cost.go')
-rw-r--r--cost.go134
1 files changed, 46 insertions, 88 deletions
diff --git a/cost.go b/cost.go
index 202fcde..ab605ce 100644
--- a/cost.go
+++ b/cost.go
@@ -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
}