|
@@ -75,8 +75,11 @@ type element struct {
|
|
|
} `json:"seller"`
|
|
} `json:"seller"`
|
|
|
Price struct {
|
|
Price struct {
|
|
|
TotalPrice struct {
|
|
TotalPrice struct {
|
|
|
- FmtPrice struct {
|
|
|
|
|
|
|
+ DiscountPrice int `json:"discountPrice"` // current price in cents; 0 = free
|
|
|
|
|
+ OriginalPrice int `json:"originalPrice"` // list price in cents
|
|
|
|
|
+ FmtPrice struct {
|
|
|
OriginalPrice string `json:"originalPrice"`
|
|
OriginalPrice string `json:"originalPrice"`
|
|
|
|
|
+ DiscountPrice string `json:"discountPrice"` // formatted current price
|
|
|
} `json:"fmtPrice"`
|
|
} `json:"fmtPrice"`
|
|
|
} `json:"totalPrice"`
|
|
} `json:"totalPrice"`
|
|
|
} `json:"price"`
|
|
} `json:"price"`
|
|
@@ -150,13 +153,17 @@ func buildGames(el element, kind string, windows []offer, keep func(offer) bool,
|
|
|
slug = el.CatalogNs.Mappings[0].PageSlug
|
|
slug = el.CatalogNs.Mappings[0].PageSlug
|
|
|
}
|
|
}
|
|
|
for _, o := range windows {
|
|
for _, o := range windows {
|
|
|
- if !keep(o) {
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
- if freeOnly && (o.Discount.DiscountPrice != 0 || o.Discount.DiscountPercentage != 100) {
|
|
|
|
|
- // DiscountPrice alone is not enough: some offers omit the price
|
|
|
|
|
- // field (null → 0) while discountPercentage reveals them as
|
|
|
|
|
- // partial discounts (e.g. Castlevania, Oct 2026).
|
|
|
|
|
|
|
+ // Semantics verified against the live API (Oct 2026): the ONLY
|
|
|
|
|
+ // reliable free indicator is el.price.totalPrice.discountPrice == 0
|
|
|
|
|
+ // (the element's current price). The offer's discountSetting fields
|
|
|
|
|
+ // are unreliable: discountPrice is null (=0 in Go) even for
|
|
|
|
|
+ // non-free offers, and discountPercentage carries inconsistent
|
|
|
|
|
+ // values (e.g. Castlevania 40 while the store shows −60 %).
|
|
|
|
|
+ // - freeOnly: element current price must be 0.
|
|
|
|
|
+ // - deals: current price > 0; discount display from
|
|
|
|
|
+ // fmtPrice (original → current).
|
|
|
|
|
+ currentlyFree := el.Price.TotalPrice.DiscountPrice == 0
|
|
|
|
|
+ if freeOnly != currentlyFree {
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
g := game.Game{
|
|
g := game.Game{
|
|
@@ -172,13 +179,16 @@ func buildGames(el element, kind string, windows []offer, keep func(offer) bool,
|
|
|
EndDate: o.EndDate,
|
|
EndDate: o.EndDate,
|
|
|
PriceFmt: el.Price.TotalPrice.FmtPrice.OriginalPrice,
|
|
PriceFmt: el.Price.TotalPrice.FmtPrice.OriginalPrice,
|
|
|
}
|
|
}
|
|
|
- if o.Discount.DiscountPercentage > 0 && o.Discount.DiscountPercentage < 100 {
|
|
|
|
|
- g.DiscountPct = o.Discount.DiscountPercentage
|
|
|
|
|
- // discountPercentage here is the *discount* (e.g. 40 = −40 %),
|
|
|
|
|
- // not the remaining share. discountPrice (cents) may be absent
|
|
|
|
|
- // (null → 0) on such offers; then show percent only.
|
|
|
|
|
- if o.Discount.DiscountPrice > 0 {
|
|
|
|
|
- g.FinalPriceFmt = fmt.Sprintf("%d.%02d €", o.Discount.DiscountPrice/100, o.Discount.DiscountPrice%100)
|
|
|
|
|
|
|
+ if !currentlyFree {
|
|
|
|
|
+ g.Kind = "deal"
|
|
|
|
|
+ g.FinalPriceFmt = el.Price.TotalPrice.FmtPrice.DiscountPrice
|
|
|
|
|
+ if orig := el.Price.TotalPrice.FmtPrice.OriginalPrice; orig != "" {
|
|
|
|
|
+ g.PriceFmt = orig
|
|
|
|
|
+ }
|
|
|
|
|
+ // Compute the discount percent from the prices (cents).
|
|
|
|
|
+ if cur := el.Price.TotalPrice.DiscountPrice; cur > 0 && cur < el.Price.TotalPrice.OriginalPrice {
|
|
|
|
|
+ orig := el.Price.TotalPrice.OriginalPrice
|
|
|
|
|
+ g.DiscountPct = (orig - cur) * 100 / orig
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if i := indexOfID(games, g.ID); i >= 0 {
|
|
if i := indexOfID(games, g.ID); i >= 0 {
|