diff options
Diffstat (limited to 'cost.go')
| -rw-r--r-- | cost.go | 165 |
1 files changed, 165 insertions, 0 deletions
@@ -0,0 +1,165 @@ +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"` +} + +type printJobCostLineItem struct { + NPages uint `json:"page_count"` + Mfg PkgId `json:"pod_package_id"` + Quantity uint `json:"quantity"` +} + +// PrintJobCost is the response from /print-job-cost-calculations/. +type PrintJobCost struct { + Addr, SuggestedAddr ShippingAddress + AddrWarning ShippingAddressWarning + Currency string + Fees []Fee + FulfillmentCost FulfillmentCost + LineItemCosts []LineItemCost + ShipCost FulfillmentCost + TotalCostExclTax, TotalCostInclTax, TotalDiscount, TotalTax decimal.Decimal +} + +type ShippingAddressWarning struct { + Type string `json:"type"` // eg "validation_warning" + Path string `json:"path"` // eg "external" + Code string `json:"code"` // eg "REPLACED" + Msg string `json:"message"` // eg "street1: Holstenstr. 40 -> Holstenstraße 40" +} + +type Fee struct { + Currency string `json:"currency"` + Type string `json:"fee_type"` + Sku string `json:"sku"` + 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"` +} + +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"` +} + +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"` +} + +type Discount struct { + Amount decimal.Decimal `json:"amount"` + Descr 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"` + Fees []Fee `json:"fees"` + FulfillmentCost FulfillmentCost `json:"fulfillment_cost"` + LineItemCosts []LineItemCost `json:"line_item_costs"` + ShipCost FulfillmentCost `json:"shipping_cost"` + 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"` +} + +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, + } + 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, + } + c.AddrWarning = addr.Warning + + c.Currency = resp.Currency + c.Fees = resp.Fees + c.FulfillmentCost = resp.FulfillmentCost + c.LineItemCosts = resp.LineItemCosts + c.ShipCost = resp.ShipCost + c.TotalCostExclTax = resp.TotalCostExclTax + c.TotalCostInclTax = resp.TotalCostInclTax + c.TotalDiscount = resp.TotalDiscount + c.TotalTax = resp.TotalTax + + return nil +} |