mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-02 11:20:18 +08:00
feat: support Pricings flow (#2250)
* feat: fix price display * feat: support subscription * feat: fix select-plan-> signup -> buy-plan -> login flow * feat: support paid-user to login and jump to the pricing page * feat: support more subscription state * feat: add payment providers for plan * feat: format code * feat: gofumpt * feat: redirect to buy-plan-result page when user have pending subscription * feat: response err when pricing don't exit * Update PricingListPage.js * Update ProductBuyPage.js * Update LoginPage.js --------- Co-authored-by: hsluoyz <hsluoyz@qq.com>
This commit is contained in:
@ -18,47 +18,108 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/pp"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/xorm-io/core"
|
||||
)
|
||||
|
||||
const defaultStatus = "Pending"
|
||||
type SubscriptionState string
|
||||
|
||||
const (
|
||||
SubStatePending SubscriptionState = "Pending"
|
||||
SubStateError SubscriptionState = "Error"
|
||||
SubStateSuspended SubscriptionState = "Suspended" // suspended by the admin
|
||||
|
||||
SubStateActive SubscriptionState = "Active"
|
||||
SubStateUpcoming SubscriptionState = "Upcoming"
|
||||
SubStateExpired SubscriptionState = "Expired"
|
||||
)
|
||||
|
||||
type Subscription struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
Description string `xorm:"varchar(100)" json:"description"`
|
||||
|
||||
StartDate time.Time `json:"startDate"`
|
||||
EndDate time.Time `json:"endDate"`
|
||||
Duration int `json:"duration"`
|
||||
Description string `xorm:"varchar(100)" json:"description"`
|
||||
User string `xorm:"varchar(100)" json:"user"`
|
||||
Pricing string `xorm:"varchar(100)" json:"pricing"`
|
||||
Plan string `xorm:"varchar(100)" json:"plan"`
|
||||
Payment string `xorm:"varchar(100)" json:"payment"`
|
||||
|
||||
User string `xorm:"mediumtext" json:"user"`
|
||||
Plan string `xorm:"varchar(100)" json:"plan"`
|
||||
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
Submitter string `xorm:"varchar(100)" json:"submitter"`
|
||||
Approver string `xorm:"varchar(100)" json:"approver"`
|
||||
ApproveTime string `xorm:"varchar(100)" json:"approveTime"`
|
||||
|
||||
State string `xorm:"varchar(100)" json:"state"`
|
||||
StartTime time.Time `json:"startTime"`
|
||||
EndTime time.Time `json:"endTime"`
|
||||
Duration int `json:"duration"`
|
||||
State SubscriptionState `xorm:"varchar(100)" json:"state"`
|
||||
}
|
||||
|
||||
func NewSubscription(owner string, user string, plan string, duration int) *Subscription {
|
||||
func (sub *Subscription) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", sub.Owner, sub.Name)
|
||||
}
|
||||
|
||||
func (sub *Subscription) UpdateState() error {
|
||||
preState := sub.State
|
||||
// update subscription state by payment state
|
||||
if sub.State == SubStatePending {
|
||||
if sub.Payment == "" {
|
||||
return nil
|
||||
}
|
||||
payment, err := GetPayment(util.GetId(sub.Owner, sub.Payment))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if payment == nil {
|
||||
sub.Description = fmt.Sprintf("payment: %s does not exist", sub.Payment)
|
||||
sub.State = SubStateError
|
||||
} else {
|
||||
if payment.State == pp.PaymentStatePaid {
|
||||
sub.State = SubStateActive
|
||||
} else if payment.State != pp.PaymentStateCreated {
|
||||
// other states: Canceled, Timeout, Error
|
||||
sub.Description = fmt.Sprintf("payment: %s state is %v", sub.Payment, payment.State)
|
||||
sub.State = SubStateError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if sub.State == SubStateActive || sub.State == SubStateUpcoming || sub.State == SubStateExpired {
|
||||
if sub.EndTime.Before(time.Now()) {
|
||||
sub.State = SubStateExpired
|
||||
} else if sub.StartTime.After(time.Now()) {
|
||||
sub.State = SubStateUpcoming
|
||||
} else {
|
||||
sub.State = SubStateActive
|
||||
}
|
||||
}
|
||||
|
||||
if preState != sub.State {
|
||||
_, err := UpdateSubscription(sub.GetId(), sub)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewSubscription(owner, userName, pricingName, planName, paymentName string) *Subscription {
|
||||
id := util.GenerateId()[:6]
|
||||
return &Subscription{
|
||||
Name: "Subscription_" + id,
|
||||
DisplayName: "New Subscription - " + id,
|
||||
Owner: owner,
|
||||
User: owner + "/" + user,
|
||||
Plan: owner + "/" + plan,
|
||||
Name: "sub_" + id,
|
||||
DisplayName: "New Subscription - " + id,
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
State: defaultStatus,
|
||||
Duration: duration,
|
||||
StartDate: time.Now(),
|
||||
EndDate: time.Now().AddDate(0, 0, duration),
|
||||
|
||||
User: userName,
|
||||
Pricing: pricingName,
|
||||
Plan: planName,
|
||||
Payment: paymentName,
|
||||
|
||||
StartTime: time.Now(),
|
||||
EndTime: time.Now().AddDate(0, 0, 30),
|
||||
Duration: 30, // TODO
|
||||
State: SubStatePending, // waiting for payment complete
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +134,28 @@ func GetSubscriptions(owner string) ([]*Subscription, error) {
|
||||
if err != nil {
|
||||
return subscriptions, err
|
||||
}
|
||||
for _, sub := range subscriptions {
|
||||
err = sub.UpdateState()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return subscriptions, nil
|
||||
}
|
||||
|
||||
func GetSubscriptionsByUser(owner, userName string) ([]*Subscription, error) {
|
||||
subscriptions := []*Subscription{}
|
||||
err := ormer.Engine.Desc("created_time").Find(&subscriptions, &Subscription{Owner: owner, User: userName})
|
||||
if err != nil {
|
||||
return subscriptions, err
|
||||
}
|
||||
// update subscription state
|
||||
for _, sub := range subscriptions {
|
||||
err = sub.UpdateState()
|
||||
if err != nil {
|
||||
return subscriptions, err
|
||||
}
|
||||
}
|
||||
return subscriptions, nil
|
||||
}
|
||||
|
||||
@ -84,7 +166,12 @@ func GetPaginationSubscriptions(owner string, offset, limit int, field, value, s
|
||||
if err != nil {
|
||||
return subscriptions, err
|
||||
}
|
||||
|
||||
for _, sub := range subscriptions {
|
||||
err = sub.UpdateState()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return subscriptions, nil
|
||||
}
|
||||
|
||||
@ -144,7 +231,3 @@ func DeleteSubscription(subscription *Subscription) (bool, error) {
|
||||
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func (subscription *Subscription) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", subscription.Owner, subscription.Name)
|
||||
}
|
||||
|
Reference in New Issue
Block a user