package models type PostalZone struct { Name string `json:"name"` MinAmount float64 `json:"min_amount"` Codes []string `json:"codes"` } // PointsTier représente un palier du barème de points // Si Max == 0, il n'y a pas de borne supérieure (illimité) type PointsTier struct { Min float64 `json:"min"` Max float64 `json:"max"` // 0 = illimité Points int `json:"points"` } // RewardProductQuantity associe un produit à sa propre quantité offerte / à // -50%, pour le cas où une catégorie n'est pas configurée en "tous les // produits" — ex: produit A à 2g offerts, produit B à 1g offert, tous deux // dans la même catégorie et le même type de récompense. type RewardProductQuantity struct { ProductID int `json:"product_id"` Quantity float64 `json:"quantity"` } // RewardCategoryConfig définit les produits éligibles dans une catégorie pour une récompense, // le type de récompense appliqué pour cette catégorie précise, et la quantité // concernée (ex: 1g offert, ou 2g à -50%) — la quantité correspond au palier // de prix catalogue du produit (voir GetActiveProductPrice), pas une valeur // libre : ex. "30€ offert = 1g" si le produit a un palier quantity=1 à 30€. // // Si AllProducts = true, Quantity s'applique uniformément à tous les produits // de la catégorie. Si AllProducts = false, chaque produit sélectionné dans // Products a sa propre quantité (Quantity au niveau catégorie est alors ignoré). type RewardCategoryConfig struct { Category string `json:"category"` // nom de la catégorie Type string `json:"type"` // "free_product" (défaut) | "half_price_product" AllProducts bool `json:"all_products"` // true = tous les produits de la catégorie Quantity float64 `json:"quantity"` // quantité uniforme si AllProducts = true Products []RewardProductQuantity `json:"products"` // produits + quantité individuelle si AllProducts = false } // RewardItem représente un produit résolu à ajouter au panier lors d'un // claim (ProductID + Quantity + Price effectif) — construit dynamiquement à // partir des CategoryConfigs au moment du claim, plus une liste saisie à part. type RewardItem struct { ProductID int `json:"product_id"` // ID du produit ajouté au panier Quantity float64 `json:"quantity"` // quantité offerte Price float64 `json:"price"` // prix effectif facturé (0 si offert, 50% du prix catalogue si -50%) } // PointsReward représente la récompense débloquée à partir d'un seuil de points cumulés. // Le type de récompense (gratuit ou -50%) et la quantité concernée sont // définis par catégorie dans CategoryConfigs (voir RewardCategoryConfig) — // les produits éligibles et leur quantité ne sont plus saisis à part. type PointsReward struct { Threshold int `json:"threshold"` // points cumulés nécessaires (ex: 20) Description string `json:"description"` // description libre affichée au client CategoryConfigs []RewardCategoryConfig `json:"category_configs"` // catégories + produits éligibles + type + quantité par catégorie } // PromotionProductQuantity associe un produit à sa propre quantité en promo, // pour le cas où une catégorie n'est pas configurée en "tous les produits" — // même logique que RewardProductQuantity mais pour les promotions. type PromotionProductQuantity struct { ProductID int `json:"product_id"` Quantity float64 `json:"quantity"` } // CategoryPromotionConfig définit une promotion (réduction en %) appliquée // automatiquement au prix catalogue d'un produit pour une quantité donnée — // contrairement à RewardCategoryConfig, ça ne dépend d'aucun seuil de points : // le prix réduit s'applique à tout client qui commande ce produit à cette // quantité, affiché directement sur le produit. La quantité correspond au // palier de prix catalogue existant (voir GetActiveProductPrice), pas une // valeur libre. // // Si AllProducts = true, Quantity s'applique uniformément à tous les produits // de la catégorie. Si AllProducts = false, chaque produit sélectionné dans // Products a sa propre quantité (Quantity au niveau catégorie est alors ignoré). type CategoryPromotionConfig struct { Category string `json:"category"` // nom de la catégorie DiscountPercent float64 `json:"discount_percent"` // pourcentage de réduction libre (ex: 10, 20, 33.5) AllProducts bool `json:"all_products"` // true = tous les produits de la catégorie Quantity float64 `json:"quantity"` // quantité uniforme si AllProducts = true Products []PromotionProductQuantity `json:"products"` // produits + quantité individuelle si AllProducts = false } // DaySchedule représente les horaires de livraison pour un jour de la semaine type DaySchedule struct { Enabled bool `json:"enabled"` OpenTime string `json:"open_time"` // ex: "09:00" CloseTime string `json:"close_time"` // ex: "20:00" } // DeliverySchedule représente les horaires de livraison pour chaque jour type DeliverySchedule struct { Monday DaySchedule `json:"monday"` Tuesday DaySchedule `json:"tuesday"` Wednesday DaySchedule `json:"wednesday"` Thursday DaySchedule `json:"thursday"` Friday DaySchedule `json:"friday"` Saturday DaySchedule `json:"saturday"` Sunday DaySchedule `json:"sunday"` } type PointsPool struct { Key string `json:"key"` // identifiant interne (ex: "pool_0") Name string `json:"name"` // nom affiché (ex: "Cannabis", "Accessoires") Categories []string `json:"categories"` // catégories de produits assignées à ce pool Tiers []PointsTier `json:"tiers"` // barème de points } // PenaltyTier représente un palier d'amende : à partir de MinCancel annulations, Amount est appliqué type PenaltyTier struct { MinCancel int `json:"min_cancel"` // nombre d'annulations à partir duquel ce palier s'applique Amount int `json:"amount"` // montant de l'amende } // CategoryRoute associe un livreur à une ou plusieurs catégories de produits type CategoryRoute struct { DeliverymanUsername string `json:"deliveryman_username"` Categories []string `json:"categories"` } // DeliveryModeConfig configure le mode d'assignation des livreurs // Mode "single" → un seul livreur, toutes catégories confondues // Mode "category_based" → chaque livreur gère ses catégories dédiées type DeliveryModeConfig struct { Mode string `json:"mode"` // "single" | "category_based" CategoryRoutes []CategoryRoute `json:"category_routes"` // utilisé uniquement en mode category_based } // AppSettings contient les paramètres globaux de l'application type AppSettings struct { PenaltiesEnabled bool `json:"penalties_enabled"` ShowAmendeScore bool `json:"show_amende_score"` // afficher le score d'amendes aux clients/cabine PenaltyTiers []PenaltyTier `json:"penalty_tiers"` // barème des amendes (liste configurable) PointsEnabled bool `json:"points_enabled"` // afficher/activer le système de points PointsPools []PointsPool `json:"points_pools"` // types de points personnalisés PointsReward *PointsReward `json:"points_reward"` // récompense globale par palier de points PromotionsEnabled bool `json:"promotions_enabled"` // activer/désactiver les promotions Promotions []CategoryPromotionConfig `json:"promotions"` // promotions (% de réduction) par catégorie ReferralEnabled bool `json:"referral_enabled"` // activer/désactiver le système de parrainage ReferralAmount float64 `json:"referral_amount"` // montant crédité par parrainage CryptoPaymentEnabled bool `json:"crypto_payment_enabled"` // activer/désactiver le paiement crypto CryptoOnly bool `json:"crypto_only"` // forcer le paiement crypto uniquement (pas d'espèces) NowPaymentsAPIKey string `json:"nowpayments_api_key"` // clé API NowPayments NowPaymentsIPNSecret string `json:"nowpayments_ipn_secret"` // secret IPN NowPayments NowPaymentsCurrencies []string `json:"nowpayments_currencies"` // cryptos acceptées (ex: ["btc","eth","ltc"]) DeliverySchedule DeliverySchedule `json:"delivery_schedule"` // horaires de livraison par jour PostalZones []PostalZone `json:"postal_zones"` // zones de livraison avec minimum de commande TelegramBotToken string `json:"telegram_bot_token"` // token du bot Telegram (BotFather) — pour le webhook de liaison TelegramBotUsername string `json:"telegram_bot_username"` // username du bot (sans @) TelegramNotificationsEnabled bool `json:"telegram_notifications_enabled"` // activer/désactiver les notifications Telegram DeliveryMode DeliveryModeConfig `json:"delivery_mode"` // mode d'assignation des livreurs ShopName string `json:"shop_name"` // nom affiché dans la sidebar du site client Telegram2FAEnabled bool `json:"telegram_2fa_enabled"` // activer/désactiver l'authentification à deux facteurs ContactTelegram string `json:"contact_telegram"` // numéro de téléphone Telegram du contact // Palette de couleurs — espace admin AdminColorPrimary string `json:"admin_color_primary"` AdminColorSecondary string `json:"admin_color_secondary"` AdminColorSuccess string `json:"admin_color_success"` AdminColorDanger string `json:"admin_color_danger"` AdminColorWarning string `json:"admin_color_warning"` // Palette de couleurs — app client + site web ClientColorPrimary string `json:"client_color_primary"` ClientColorSecondary string `json:"client_color_secondary"` ClientColorSuccess string `json:"client_color_success"` ClientColorDanger string `json:"client_color_danger"` ClientColorWarning string `json:"client_color_warning"` // Dégradé du titre boutique sur le site web client ClientTitleGradientFrom string `json:"client_title_gradient_from"` ClientTitleGradientTo string `json:"client_title_gradient_to"` }