chore(catalog): order the admin catalog list like the public offer
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 26s
CI / ui (pull_request) Successful in 1m11s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m50s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 26s
CI / ui (pull_request) Successful in 1m11s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m50s
Sales (chip packs) first, ascending by rouble price; then the chip-exchange values, grouped and price-sorted the same way projectOfferPricing lists them, so the /catalog console mirrors what a buyer sees. Internal cosmetics only — no product behaviour change. The value-group order moves to a shared helper (valueGroup) so the offer and the admin list cannot drift.
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package payments
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@@ -147,6 +150,65 @@ func (s *Service) AdminCatalog(ctx context.Context) ([]AdminProduct, error) {
|
||||
return s.store.adminCatalog(ctx)
|
||||
}
|
||||
|
||||
// SortAdminCatalog orders an admin catalog list in place the same way the public offer lists products
|
||||
// ([projectOfferPricing]): chip packs first, ascending by rouble price; then chip-priced values,
|
||||
// grouped (hints only, no-ads only, no-ads + hints, tournament) and ascending by chip price within a
|
||||
// group. It is stable, so equal-keyed products keep their incoming order, and it keys archived
|
||||
// products the same as active ones (the admin list shows both).
|
||||
func SortAdminCatalog(products []AdminProduct) {
|
||||
slices.SortStableFunc(products, func(a, b AdminProduct) int {
|
||||
if pa, pb := adminIsPack(a), adminIsPack(b); pa != pb {
|
||||
if pa {
|
||||
return -1 // packs (sales) before values (chip exchange)
|
||||
}
|
||||
return 1
|
||||
} else if pa {
|
||||
return cmp.Compare(adminPriceAmount(a, string(SourceDirect), CurrencyRUB), adminPriceAmount(b, string(SourceDirect), CurrencyRUB))
|
||||
}
|
||||
if d := cmp.Compare(adminValueGroup(a), adminValueGroup(b)); d != 0 {
|
||||
return d
|
||||
}
|
||||
return cmp.Compare(adminPriceAmount(a, "", CurrencyChip), adminPriceAmount(b, "", CurrencyChip))
|
||||
})
|
||||
}
|
||||
|
||||
// adminIsPack reports whether the product is a chip pack (it carries the chips atom).
|
||||
func adminIsPack(p AdminProduct) bool {
|
||||
for _, a := range p.Atoms {
|
||||
if a.Atom == atomChips {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// adminValueGroup ranks a chip-priced value into the shared listing groups (see [valueGroup]).
|
||||
func adminValueGroup(p AdminProduct) int {
|
||||
hasHints, hasNoAds, hasTournament := false, false, false
|
||||
for _, a := range p.Atoms {
|
||||
switch a.Atom {
|
||||
case "hints":
|
||||
hasHints = true
|
||||
case "noads_days":
|
||||
hasNoAds = true
|
||||
case "tournament":
|
||||
hasTournament = true
|
||||
}
|
||||
}
|
||||
return valueGroup(hasHints, hasNoAds, hasTournament)
|
||||
}
|
||||
|
||||
// adminPriceAmount returns the minor-unit amount of the product's price for the method and currency,
|
||||
// or math.MaxInt64 when it carries no such price (so a misconfigured product sorts last, not first).
|
||||
func adminPriceAmount(p AdminProduct, method string, cur Currency) int64 {
|
||||
for _, pr := range p.Prices {
|
||||
if pr.Method == method && pr.Currency == cur {
|
||||
return pr.Amount
|
||||
}
|
||||
}
|
||||
return math.MaxInt64
|
||||
}
|
||||
|
||||
// CreateProduct validates and inserts a new product with its atoms and prices, returning its id. A
|
||||
// product created active must satisfy the sellable shape.
|
||||
func (s *Service) CreateProduct(ctx context.Context, in ProductInput, active bool) (uuid.UUID, error) {
|
||||
|
||||
Reference in New Issue
Block a user