package services import ( "database/sql" "testing" "quyun/v2/app/commands/testx" order_dto "quyun/v2/app/http/v1/dto" "quyun/v2/database" "quyun/v2/database/models" "quyun/v2/pkg/consts" . "github.com/smartystreets/goconvey/convey" "github.com/stretchr/testify/suite" "go.ipao.vip/atom/contracts" "go.uber.org/dig" ) type CouponTestSuiteInjectParams struct { dig.In DB *sql.DB Initials []contracts.Initial `group:"initials"` } type CouponTestSuite struct { suite.Suite CouponTestSuiteInjectParams } func Test_Coupon(t *testing.T) { providers := testx.Default().With(Provide) testx.Serve(providers, t, func(p CouponTestSuiteInjectParams) { suite.Run(t, &CouponTestSuite{CouponTestSuiteInjectParams: p}) }) } func (s *CouponTestSuite) Test_CouponFlow() { Convey("Coupon Flow", s.T(), func() { ctx := s.T().Context() tenantID := int64(1) database.Truncate( ctx, s.DB, models.TableNameCoupon, models.TableNameUserCoupon, models.TableNameOrder, models.TableNameUser, models.TableNameContent, models.TableNameContentPrice, ) user := &models.User{Username: "coupon_user", Phone: "13800000001"} models.UserQuery.WithContext(ctx).Create(user) // 1. Create Coupon (Fixed 5.00 CNY, Min 10.00 CNY) cp := &models.Coupon{ TenantID: tenantID, Title: "Save 5", Type: consts.CouponTypeFixAmount, Value: 500, MinOrderAmount: 1000, } models.CouponQuery.WithContext(ctx).Create(cp) // 2. Give to User uc := &models.UserCoupon{ UserID: user.ID, CouponID: cp.ID, Status: consts.UserCouponStatusUnused, } models.UserCouponQuery.WithContext(ctx).Create(uc) Convey("should validate coupon successfully", func() { discount, err := Coupon.Validate(ctx, tenantID, user.ID, uc.ID, 1500) So(err, ShouldBeNil) So(discount, ShouldEqual, 500) }) Convey("should fail if below min amount", func() { _, err := Coupon.Validate(ctx, tenantID, user.ID, uc.ID, 800) So(err, ShouldNotBeNil) }) Convey("should apply in Order.Create", func() { // Setup Content c := &models.Content{TenantID: tenantID, UserID: 99, Title: "Test", Status: consts.ContentStatusPublished} models.ContentQuery.WithContext(ctx).Create(c) models.ContentPriceQuery.WithContext(ctx).Create(&models.ContentPrice{ TenantID: tenantID, ContentID: c.ID, PriceAmount: 2000, // 20.00 CNY Currency: consts.CurrencyCNY, }) form := &order_dto.OrderCreateForm{ ContentID: c.ID, UserCouponID: uc.ID, } // Simulate Auth context for Order service res, err := Order.Create(ctx, tenantID, user.ID, form) So(err, ShouldBeNil) // Verify Order oid := res.OrderID o, _ := models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.ID.Eq(oid)).First() So(o.AmountOriginal, ShouldEqual, 2000) So(o.AmountDiscount, ShouldEqual, 500) So(o.AmountPaid, ShouldEqual, 1500) So(o.CouponID, ShouldEqual, cp.ID) // Verify Coupon Status ucReload, _ := models.UserCouponQuery.WithContext(ctx).Where(models.UserCouponQuery.ID.Eq(uc.ID)).First() So(ucReload.Status, ShouldEqual, consts.UserCouponStatusUsed) So(ucReload.OrderID, ShouldEqual, oid) }) }) } func (s *CouponTestSuite) Test_Receive() { Convey("Receive", s.T(), func() { ctx := s.T().Context() tenantID := int64(2) database.Truncate( ctx, s.DB, models.TableNameCoupon, models.TableNameUserCoupon, models.TableNameUser, ) user := &models.User{Username: "coupon_receive", Phone: "13800000002"} So(models.UserQuery.WithContext(ctx).Create(user), ShouldBeNil) cp := &models.Coupon{ TenantID: tenantID, Title: "Receive Test", Type: consts.CouponTypeFixAmount, Value: 300, MinOrderAmount: 0, TotalQuantity: 1, } So(models.CouponQuery.WithContext(ctx).Create(cp), ShouldBeNil) item, err := Coupon.Receive(ctx, tenantID, user.ID, cp.ID) So(err, ShouldBeNil) So(item, ShouldNotBeNil) So(item.CouponID, ShouldEqual, cp.ID) // second receive should return existing item2, err := Coupon.Receive(ctx, tenantID, user.ID, cp.ID) So(err, ShouldBeNil) So(item2.CouponID, ShouldEqual, cp.ID) }) } func (s *CouponTestSuite) Test_ListAvailable() { Convey("ListAvailable", s.T(), func() { ctx := s.T().Context() tenantID := int64(3) database.Truncate( ctx, s.DB, models.TableNameCoupon, models.TableNameUserCoupon, models.TableNameUser, ) user := &models.User{Username: "coupon_available", Phone: "13800000003"} So(models.UserQuery.WithContext(ctx).Create(user), ShouldBeNil) cp := &models.Coupon{ TenantID: tenantID, Title: "Available Test", Type: consts.CouponTypeFixAmount, Value: 500, MinOrderAmount: 1000, } So(models.CouponQuery.WithContext(ctx).Create(cp), ShouldBeNil) uc := &models.UserCoupon{ UserID: user.ID, CouponID: cp.ID, Status: consts.UserCouponStatusUnused, } So(models.UserCouponQuery.WithContext(ctx).Create(uc), ShouldBeNil) list, err := Coupon.ListAvailable(ctx, tenantID, user.ID, 500) So(err, ShouldBeNil) So(len(list), ShouldEqual, 0) list, err = Coupon.ListAvailable(ctx, tenantID, user.ID, 1200) So(err, ShouldBeNil) So(len(list), ShouldEqual, 1) So(list[0].CouponID, ShouldEqual, cp.ID) }) }