Files
2026-05-27 15:50:23 +02:00

147 lines
4.3 KiB
Go

package discount
import (
"time"
"cloud.o-forge.io/core/oc-lib/models/utils"
"cloud.o-forge.io/core/oc-lib/tools"
)
type DiscountType int
const (
PERCENTAGE DiscountType = iota // réduction en pourcentage
FIXED_AMOUNT // réduction montant fixe
)
func (d DiscountType) String() string {
return [...]string{"percentage", "fixed_amount"}[d]
}
func DiscountTypeList() []DiscountType {
return []DiscountType{PERCENTAGE, FIXED_AMOUNT}
}
type DiscountScope int
const (
SCOPE_ALL DiscountScope = iota // applicable à tout
SCOPE_RESOURCE_TYPE // applicable à un type de ressource
SCOPE_RESOURCE // applicable à une ressource spécifique
SCOPE_SUBSCRIPTION // applicable aux souscriptions
)
func (d DiscountScope) String() string {
return [...]string{"all", "resource_type", "resource", "subscription"}[d]
}
// Discount représente une réduction applicable sur les ressources ou abonnements.
type Discount struct {
utils.AbstractObject
Code string `json:"code,omitempty" bson:"code,omitempty"`
DiscountType DiscountType `json:"discount_type" bson:"discount_type"`
Scope DiscountScope `json:"scope" bson:"scope"`
Value float64 `json:"value" bson:"value"` // pourcentage (0-100) ou montant fixe
Currency string `json:"currency,omitempty" bson:"currency,omitempty"` // pour FIXED_AMOUNT
ResourceTypes []tools.DataType `json:"resource_types,omitempty" bson:"resource_types,omitempty"` // si SCOPE_RESOURCE_TYPE
ResourceIDs []string `json:"resource_ids,omitempty" bson:"resource_ids,omitempty"` // si SCOPE_RESOURCE
ValidFrom *time.Time `json:"valid_from,omitempty" bson:"valid_from,omitempty"`
ValidUntil *time.Time `json:"valid_until,omitempty" bson:"valid_until,omitempty"`
MaxUsage int `json:"max_usage,omitempty" bson:"max_usage,omitempty"` // 0 = illimité
CurrentUsage int `json:"current_usage" bson:"current_usage"`
MinAmount float64 `json:"min_amount,omitempty" bson:"min_amount,omitempty"` // montant minimum du bill pour appliquer
Active bool `json:"active" bson:"active" default:"true"`
}
// IsValid vérifie si la réduction est applicable au moment présent.
func (d *Discount) IsValid(billAmount float64) bool {
now := time.Now().UTC()
if !d.Active {
return false
}
if d.MaxUsage > 0 && d.CurrentUsage >= d.MaxUsage {
return false
}
if d.ValidFrom != nil && now.Before(*d.ValidFrom) {
return false
}
if d.ValidUntil != nil && now.After(*d.ValidUntil) {
return false
}
if d.MinAmount > 0 && billAmount < d.MinAmount {
return false
}
return true
}
// Apply applique la réduction sur un prix HT et retourne le prix réduit.
func (d *Discount) Apply(priceHT float64) float64 {
switch d.DiscountType {
case PERCENTAGE:
return priceHT - (priceHT * d.Value / 100)
case FIXED_AMOUNT:
result := priceHT - d.Value
if result < 0 {
return 0
}
return result
}
return priceHT
}
// DiscountAmount retourne le montant de la réduction sans l'appliquer.
func (d *Discount) DiscountAmount(priceHT float64) float64 {
switch d.DiscountType {
case PERCENTAGE:
return priceHT * d.Value / 100
case FIXED_AMOUNT:
if d.Value > priceHT {
return priceHT
}
return d.Value
}
return 0
}
// AppliesToResource vérifie si cette réduction s'applique à une ressource donnée.
func (d *Discount) AppliesToResource(resourceID string, resourceType tools.DataType) bool {
switch d.Scope {
case SCOPE_ALL:
return true
case SCOPE_RESOURCE:
for _, id := range d.ResourceIDs {
if id == resourceID {
return true
}
}
case SCOPE_RESOURCE_TYPE:
for _, t := range d.ResourceTypes {
if t == resourceType {
return true
}
}
}
return false
}
// IncrementUsage incrémente le compteur d'utilisation.
func (d *Discount) IncrementUsage() {
d.CurrentUsage++
}
func (d *Discount) GetAccessor(request *tools.APIRequest) utils.Accessor {
return NewAccessor(request)
}
func (d *Discount) StoreDraftDefault() {
d.IsDraft = true
}
func (d *Discount) CanUpdate(set utils.DBObject) (bool, utils.DBObject) {
return d.IsDraft, set
}
func (d *Discount) CanDelete() bool {
return d.IsDraft || d.CurrentUsage == 0
}