| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- package service
- import (
- "testing"
- "time"
- "github.com/glebarez/sqlite"
- "github.com/stretchr/testify/require"
- "gorm.io/gorm"
- "wails-app/internal/dao"
- "wails-app/internal/global"
- )
- func setupMonthlyServiceTest(t *testing.T) *MonthlyCardService {
- t.Helper()
- db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
- require.NoError(t, err)
- require.NoError(t, db.AutoMigrate(&dao.Vehicle{}, &dao.MonthlyCard{}, &dao.Shortlist{}, &dao.PaymentRecord{}))
- global.GVA_DB = db
- t.Cleanup(func() { global.GVA_DB = nil })
- return NewMonthlyCardService()
- }
- func createVehicle(t *testing.T, plate string) *dao.Vehicle {
- t.Helper()
- vehicle := dao.Vehicle{PlateNumber: plate, VehicleTypeID: 1}
- require.NoError(t, global.GVA_DB.Create(&vehicle).Error)
- return &vehicle
- }
- func countTable(t *testing.T, model interface{}) int64 {
- t.Helper()
- var count int64
- require.NoError(t, global.GVA_DB.Model(model).Count(&count).Error)
- return count
- }
- func TestCreateWritesCardWhitelistAndPayment(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- vehicle := createVehicle(t, "MC-001")
- card, err := svc.Create(vehicle.ID, "month", 300, 7, "测试办理")
- require.NoError(t, err)
- require.NotZero(t, card.ID)
- require.Equal(t, "paid", card.PaymentStatus)
- require.True(t, card.EndDate.After(time.Now().Add(29*24*time.Hour)))
- // 三张表全部写入
- require.Equal(t, int64(1), countTable(t, &dao.MonthlyCard{}))
- require.Equal(t, int64(1), countTable(t, &dao.Shortlist{}))
- require.Equal(t, int64(1), countTable(t, &dao.PaymentRecord{}))
- // 白名单到期日与月卡一致
- var shortlist dao.Shortlist
- require.NoError(t, global.GVA_DB.First(&shortlist).Error)
- require.Equal(t, "白名单", shortlist.ListType)
- require.NotNil(t, shortlist.ExpirationTime)
- require.True(t, shortlist.ExpirationTime.Equal(card.EndDate))
- // 支付流水
- var pay dao.PaymentRecord
- require.NoError(t, global.GVA_DB.First(&pay).Error)
- require.Equal(t, 300.0, pay.Amount)
- require.Equal(t, uint(7), pay.OperatorID)
- }
- func TestCreateRollsBackWhenWhitelistWriteFails(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- vehicle := createVehicle(t, "MC-002")
- // 模拟白名单写入失败:删除 shortlist 表
- require.NoError(t, global.GVA_DB.Exec("DROP TABLE shortlist").Error)
- _, err := svc.Create(vehicle.ID, "month", 300, 7, "")
- require.Error(t, err)
- require.Contains(t, err.Error(), "白名单")
- // 月卡与流水均回滚
- require.Equal(t, int64(0), countTable(t, &dao.MonthlyCard{}))
- require.Equal(t, int64(0), countTable(t, &dao.PaymentRecord{}))
- }
- func TestCreateRollsBackWhenPaymentWriteFails(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- vehicle := createVehicle(t, "MC-003")
- // 模拟支付流水写入失败:删除 payment_record 表
- require.NoError(t, global.GVA_DB.Exec("DROP TABLE payment_record").Error)
- _, err := svc.Create(vehicle.ID, "month", 300, 7, "")
- require.Error(t, err)
- require.Contains(t, err.Error(), "支付流水")
- // 月卡与白名单均回滚
- require.Equal(t, int64(0), countTable(t, &dao.MonthlyCard{}))
- require.Equal(t, int64(0), countTable(t, &dao.Shortlist{}))
- }
- func TestCreateRejectsDuplicateActiveCard(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- vehicle := createVehicle(t, "MC-004")
- _, err := svc.Create(vehicle.ID, "month", 300, 7, "")
- require.NoError(t, err)
- _, err = svc.Create(vehicle.ID, "month", 300, 7, "")
- require.Error(t, err)
- require.Contains(t, err.Error(), "已有有效月卡")
- require.Equal(t, int64(1), countTable(t, &dao.MonthlyCard{}))
- }
- func TestCreateRejectsUnknownVehicle(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- _, err := svc.Create(99999, "month", 300, 7, "")
- require.Error(t, err)
- require.Contains(t, err.Error(), "车辆不存在")
- }
- func TestRenewExtendsFromEndDateWhenActive(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- vehicle := createVehicle(t, "MC-005")
- now := time.Now()
- card := &dao.MonthlyCard{
- VehicleID: vehicle.ID, CardType: "month",
- StartDate: now.AddDate(0, -1, 0), EndDate: now.AddDate(0, 0, 10),
- Fee: 300, PaymentStatus: "paid",
- }
- require.NoError(t, global.GVA_DB.Create(card).Error)
- originalEnd := card.EndDate
- require.NoError(t, global.GVA_DB.Create(&dao.Shortlist{
- VehicleId: int(vehicle.ID), ListType: "白名单", ExpirationTime: &originalEnd,
- }).Error)
- err := svc.Renew(card.ID, "month", 300, 7)
- require.NoError(t, err)
- var renewed dao.MonthlyCard
- require.NoError(t, global.GVA_DB.First(&renewed, card.ID).Error)
- // 未过期:从原到期日顺延 30 天
- require.True(t, renewed.EndDate.After(now.AddDate(0, 0, 39)), "到期日应约为原到期日+30天")
- require.True(t, renewed.EndDate.Before(now.AddDate(0, 0, 41)))
- require.Equal(t, 600.0, renewed.Fee)
- // 白名单到期日同步
- var shortlist dao.Shortlist
- require.NoError(t, global.GVA_DB.Where("vehicle_id = ?", vehicle.ID).First(&shortlist).Error)
- require.True(t, shortlist.ExpirationTime.Equal(renewed.EndDate))
- }
- func TestRenewStartsFromNowWhenCardExpired(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- vehicle := createVehicle(t, "MC-006")
- now := time.Now()
- card := &dao.MonthlyCard{
- VehicleID: vehicle.ID, CardType: "month",
- StartDate: now.AddDate(0, -3, 0), EndDate: now.AddDate(0, -2, 0), // 已过期 2 个月
- Fee: 300, PaymentStatus: "paid",
- }
- require.NoError(t, global.GVA_DB.Create(card).Error)
- expiredEnd := card.EndDate
- require.NoError(t, global.GVA_DB.Create(&dao.Shortlist{
- VehicleId: int(vehicle.ID), ListType: "白名单", ExpirationTime: &expiredEnd,
- }).Error)
- err := svc.Renew(card.ID, "month", 300, 7)
- require.NoError(t, err)
- var renewed dao.MonthlyCard
- require.NoError(t, global.GVA_DB.First(&renewed, card.ID).Error)
- // 已过期:从今天起算约 30 天,而不是从两个月前的到期日续期
- require.True(t, renewed.EndDate.After(now.AddDate(0, 0, 29)), "过期卡应从今天起算")
- require.True(t, renewed.EndDate.Before(now.AddDate(0, 0, 31)))
- // 白名单到期日同步为新到期日(未过期卡同样适用)
- var shortlist dao.Shortlist
- require.NoError(t, global.GVA_DB.Where("vehicle_id = ?", vehicle.ID).First(&shortlist).Error)
- require.True(t, shortlist.ExpirationTime.Equal(renewed.EndDate))
- }
- func TestRenewRollsBackWhenPaymentWriteFails(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- vehicle := createVehicle(t, "MC-007")
- now := time.Now()
- card := &dao.MonthlyCard{
- VehicleID: vehicle.ID, CardType: "month",
- StartDate: now, EndDate: now.AddDate(0, 0, 10),
- Fee: 300, PaymentStatus: "paid",
- }
- require.NoError(t, global.GVA_DB.Create(card).Error)
- originalEnd := card.EndDate
- require.NoError(t, global.GVA_DB.Exec("DROP TABLE payment_record").Error)
- err := svc.Renew(card.ID, "month", 300, 7)
- require.Error(t, err)
- // 到期日与费用均未变(回滚)
- var after dao.MonthlyCard
- require.NoError(t, global.GVA_DB.First(&after, card.ID).Error)
- require.True(t, after.EndDate.Equal(originalEnd))
- require.Equal(t, 300.0, after.Fee)
- }
- func TestRefundMarksRefundedAndRemovesWhitelist(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- vehicle := createVehicle(t, "MC-008")
- card, err := svc.Create(vehicle.ID, "month", 300, 7, "")
- require.NoError(t, err)
- require.Equal(t, int64(1), countTable(t, &dao.Shortlist{}))
- err = svc.Refund(card.ID)
- require.NoError(t, err)
- var refunded dao.MonthlyCard
- require.NoError(t, global.GVA_DB.First(&refunded, card.ID).Error)
- require.Equal(t, "refunded", refunded.PaymentStatus)
- var whitelistCount int64
- require.NoError(t, global.GVA_DB.Model(&dao.Shortlist{}).
- Where("vehicle_id = ? AND list_type = ?", vehicle.ID, "白名单").Count(&whitelistCount).Error)
- require.Equal(t, int64(0), whitelistCount)
- }
- func TestRefundRejectsUnknownCard(t *testing.T) {
- svc := setupMonthlyServiceTest(t)
- err := svc.Refund(99999)
- require.Error(t, err)
- require.Contains(t, err.Error(), "月卡记录不存在")
- }
|