package yookassa // Shops is a set of YooKassa merchant shops keyed by channel — the subtype of the trusted X-Platform // signal for the direct rail ("web", "android"; "ios" later). The direct rail routes a payment to the // per-channel shop for separate merchant accounts, accounting and receipts, while every shop still // credits the one direct wallet (docs/PAYMENTS_DECISIONS_ru.md D42). An empty set leaves the direct // order and notification endpoints unregistered. type Shops map[string]Config // Channel constants name the direct-rail X-Platform subtypes a shop is keyed by. ChannelWeb is the // default: an unknown or empty channel routes here on the order side. const ( ChannelWeb = "web" ChannelAndroid = "android" ) // Shop returns the shop that issues an order for channel, falling back to the web shop when channel // is unknown, empty or not configured. The fallback is safe: routing only chooses the merchant // account and receipt, never the credited wallet (always direct, D42), so a mis-attributed channel // costs at most accounting accuracy, not money. The second result is false when neither the channel // nor the web shop is configured. func (s Shops) Shop(channel string) (Config, bool) { if channel != "" { if c, ok := s[channel]; ok && c.Configured() { return c, true } } if c, ok := s[ChannelWeb]; ok && c.Configured() { return c, true } return Config{}, false } // ByShopID returns the shop with the given YooKassa shop id, which is how an incoming notification is // attributed to one of several configured shops (the payment object reports it as // recipient.account_id). Unlike Shop it does not fall back: an unrecognised shop id means the // notification was not meant for us, and the caller must not guess at credentials. func (s Shops) ByShopID(shopID string) (channel string, cfg Config, ok bool) { if shopID == "" { return "", Config{}, false } for ch, c := range s { if c.Configured() && c.ShopID == shopID { return ch, c, true } } return "", Config{}, false } // Configured reports whether at least one shop has credentials (the YooKassa direct rail is live). func (s Shops) Configured() bool { for _, c := range s { if c.Configured() { return true } } return false }