satellite/payments: coupon expiration bug fixed

Change-Id: Icc89e9ee6a1dd91109d34909490ee446b716e2ed
This commit is contained in:
VitaliiShpital 2020-05-13 20:02:51 +03:00 committed by Kaloyan Raev
parent 79a562c3ed
commit ee9bb0d689
4 changed files with 38 additions and 30 deletions

View File

@ -47,15 +47,13 @@ type Coupon struct {
Created time.Time `json:"created"`
}
// IsExpired checks if coupon is not after its rollup period.
func (coupon *Coupon) IsExpired() bool {
expirationDate := time.Date(coupon.Created.Year(), coupon.Created.Month(), 1, 0, 0, 0, 0, coupon.Created.Location())
expirationDate = expirationDate.AddDate(0, coupon.Duration, 0)
now := time.Now().UTC()
now = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, coupon.Created.Location())
return expirationDate.Before(now)
// ExpirationDate returns coupon expiration date.
//
// A coupon is valid for Duration number of full months. The month the user
// signs up is not counted in the duration. The expirated date is at the last
// day of the last valid month.
func (coupon *Coupon) ExpirationDate() time.Time {
return time.Date(coupon.Created.Year(), coupon.Created.Month()+time.Month(coupon.Duration)+1, 0, 0, 0, 0, 0, time.UTC)
}
// CouponType indicates the type of the coupon.

View File

@ -10,28 +10,32 @@ import (
"github.com/stretchr/testify/require"
)
func TestCouponIsExpired(t *testing.T) {
duration := 2
now := time.Now()
testCases := [...]struct {
func TestCoupon_ExpirationDate(t *testing.T) {
for _, tt := range []struct {
created time.Time
expected bool
duration int
expires time.Time
}{
{now.AddDate(0, -duration-1, 0), true},
{now.AddDate(0, -duration-2, 0), true},
{now.AddDate(0, -duration-3, 0), true},
{now.AddDate(0, -1, 0), false},
{now.AddDate(0, 0, 0), false},
{now.AddDate(0, 1, 0), false},
}
for _, tc := range testCases {
{
created: time.Date(2020, 1, 30, 0, 0, 0, 0, time.UTC), // 2020-01-30 00:00:00 +0000 UTC
duration: 0, // sign-up month only
expires: time.Date(2020, 2, 0, 0, 0, 0, 0, time.UTC), // 2020-01-31 00:00:00 +0000 UTC
},
{
created: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC), // 2020-02-01 00:00:00 +0000 UTC
duration: 1, // sign-up month + 1 full month
expires: time.Date(2020, 4, 0, 0, 0, 0, 0, time.UTC), // 2020-03-31 00:00:00 +0000 UTC
},
{
created: time.Date(2020, 2, 5, 8, 0, 0, 0, time.UTC), // 2020-02-05 08:00:00 +0000 UTC
duration: 2, // sign-up month + 2 full months
expires: time.Date(2020, 5, 0, 0, 0, 0, 0, time.UTC), // 2020-04-30 00:00:00 +0000 UTC
},
} {
coupon := Coupon{
Duration: duration,
Created: tc.created,
Duration: tt.duration,
Created: tt.created,
}
require.Equal(t, coupon.IsExpired(), tc.expected)
require.Equal(t, tt.expires, coupon.ExpirationDate())
}
}

View File

@ -432,7 +432,13 @@ func (service *Service) processCustomers(ctx context.Context, customers []Custom
// Apply any promotional credits (a.k.a. coupons) on the remainder.
// TODO: if multiple coupons are available apply them in order of expiration.
for _, coupon := range coupons {
if coupon.IsExpired() {
if coupon.Status == payments.CouponExpired {
// this coupon has already been marked as expired.
continue
}
if end.After(coupon.ExpirationDate()) {
// this coupon is identified as expired for first time, mark it in the database
if _, err = service.db.Coupons().Update(ctx, coupon.ID, payments.CouponExpired); err != nil {
return err
}

View File

@ -296,7 +296,7 @@ func TestService_InvoiceUserWithManyCoupons(t *testing.T) {
var sumUsages int64
for i, coupon := range coupons {
sumCoupons += coupon.Amount
require.False(t, coupon.IsExpired())
require.NotEqual(t, payments.CouponExpired, coupon.Status)
sumUsages += couponsPage.Usages[i].Amount
require.Equal(t, stripecoinpayments.CouponUsageStatusUnapplied, couponsPage.Usages[i].Status)