147 lines
4.3 KiB
Go
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
|
||
|
|
}
|