package pricing import ( "errors" "fmt" "strconv" "time" ) type BillingStrategy int // BAM BAM // should except... on const ( BILL_ONCE BillingStrategy = iota // is a permanent buying ( predictible ) BILL_PER_WEEK BILL_PER_MONTH BILL_PER_YEAR ) func (t BillingStrategy) IsBillingStrategyAllowed(bs int) (BillingStrategy, bool) { switch t { case BILL_ONCE: return BILL_ONCE, bs == 0 case BILL_PER_WEEK: case BILL_PER_MONTH: case BILL_PER_YEAR: return t, bs != 0 } return t, false } func (t BillingStrategy) String() string { return [...]string{"BILL_ONCE", "BILL_PER_WEEK", "BILL_PER_MONTH", "BILL_PER_YEAR"}[t] } func BillingStrategyList() []BillingStrategy { return []BillingStrategy{BILL_ONCE, BILL_PER_WEEK, BILL_PER_MONTH, BILL_PER_YEAR} } type BuyingStrategy int // should except... on const ( PERMANENT BuyingStrategy = iota // is a permanent buying ( predictible ) UNDEFINED_SUBSCRIPTION // a endless subscription ( unpredictible ) SUBSCRIPTION // a defined subscription ( predictible ) // PAY_PER_USE // per request. ( unpredictible ) ) func (t BuyingStrategy) String() string { return [...]string{"PERMANENT", "UNDEFINED_SUBSCRIPTION", "SUBSCRIPTION"}[t] } func (t BuyingStrategy) IsBillingStrategyAllowed(bs BillingStrategy) (BillingStrategy, bool) { switch t { case PERMANENT: return BILL_ONCE, bs == BILL_ONCE case UNDEFINED_SUBSCRIPTION: return BILL_PER_MONTH, bs != BILL_ONCE case SUBSCRIPTION: /*case PAY_PER_USE: return bs, true*/ } return bs, false } func BuyingStrategyList() []BuyingStrategy { return []BuyingStrategy{PERMANENT, UNDEFINED_SUBSCRIPTION, SUBSCRIPTION} } type Strategy interface { GetStrategy() string GetStrategyValue() int } type TimePricingStrategy int const ( ONCE TimePricingStrategy = iota PER_SECOND PER_MINUTE PER_HOUR PER_DAY PER_WEEK PER_MONTH ) func IsTimeStrategy(i int) bool { return len(TimePricingStrategyList()) < i } func (t TimePricingStrategy) String() string { return [...]string{"ONCE", "PER SECOND", "PER MINUTE", "PER HOUR", "PER DAY", "PER WEEK", "PER MONTH"}[t] } func TimePricingStrategyList() []TimePricingStrategy { return []TimePricingStrategy{ONCE, PER_SECOND, PER_MINUTE, PER_HOUR, PER_DAY, PER_WEEK, PER_MONTH} } func (t TimePricingStrategy) GetStrategy() string { return [...]string{"ONCE", "PER_SECOND", "PER_MINUTE", "PER_HOUR", "PER_DAY", "PER_WEEK", "PER_MONTH"}[t] } func (t TimePricingStrategy) GetStrategyValue() int { return int(t) } func getAverageTimeInSecond(averageTimeInSecond float64, start time.Time, end *time.Time) float64 { now := time.Now() after := now.Add(time.Duration(averageTimeInSecond) * time.Second) fromAverageDuration := after.Sub(now).Seconds() var tEnd time.Time if end == nil { tEnd = start.Add(1 * time.Hour) } else { tEnd = *end } fromDateDuration := tEnd.Sub(start).Seconds() if fromAverageDuration > fromDateDuration { return fromAverageDuration } return fromDateDuration } func BookingEstimation(t TimePricingStrategy, price float64, locationDurationInSecond float64, start time.Time, end *time.Time) (float64, error) { locationDurationInSecond = getAverageTimeInSecond(locationDurationInSecond, start, end) priceStr := fmt.Sprintf("%v", price) p, err := strconv.ParseFloat(priceStr, 64) if err != nil { return 0, err } switch t { case ONCE: return p, nil case PER_HOUR: return p * float64(locationDurationInSecond/3600), nil case PER_MINUTE: return p * float64(locationDurationInSecond/60), nil case PER_SECOND: return p * locationDurationInSecond, nil case PER_DAY: return p * float64(locationDurationInSecond/86400), nil case PER_WEEK: return p * float64(locationDurationInSecond/604800), nil case PER_MONTH: return p * float64(locationDurationInSecond/2592000), nil } return 0, errors.New("pricing strategy not found") } // may suppress in pricing strategy -> to set in map type PricingStrategy[T Strategy] struct { Price float64 `json:"price" bson:"price" default:"0"` // Price is the Price of the pricing Currency string `json:"currency" bson:"currency" default:"USD"` // Currency is the currency of the pricing BuyingStrategy BuyingStrategy `json:"buying_strategy" bson:"buying_strategy" default:"0"` // BuyingStrategy is the buying strategy of the pricing TimePricingStrategy TimePricingStrategy `json:"time_pricing_strategy" bson:"time_pricing_strategy" default:"0"` // TimePricingStrategy is the time pricing strategy of the pricing OverrideStrategy T `json:"override_strategy" bson:"override_strategy" default:"-1"` // Modulation is the modulation of the pricing } func (p PricingStrategy[T]) GetPrice(amountOfData float64, bookingTimeDuration float64, start time.Time, end *time.Time) (float64, error) { if p.BuyingStrategy == SUBSCRIPTION { return BookingEstimation(p.GetTimePricingStrategy(), p.Price*float64(amountOfData), bookingTimeDuration, start, end) } else if p.BuyingStrategy == PERMANENT { return p.Price, nil } return p.Price * float64(amountOfData), nil } func (p PricingStrategy[T]) GetBuyingStrategy() BuyingStrategy { return p.BuyingStrategy } func (p PricingStrategy[T]) GetTimePricingStrategy() TimePricingStrategy { return p.TimePricingStrategy } func (p PricingStrategy[T]) GetOverrideStrategy() T { return p.OverrideStrategy }