| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- package service
- import (
- "errors"
- "sync"
- "testing"
- "github.com/stretchr/testify/require"
- "gorm.io/gorm"
- "wails-app/internal/dao"
- "wails-app/internal/global"
- )
- func TestPaymentRejectsNegativeAndInsufficientAmounts(t *testing.T) {
- svc := setupPaymentServiceTest(t)
- for _, amounts := range [][2]float64{{-1, 0}, {1, -1}, {-1, -1}} {
- _, _, err := svc.ValidatePayment(nil, PaymentCash, EntryCounter, amounts[0], amounts[1])
- require.Error(t, err)
- }
- _, _, err := svc.ValidatePayment(nil, PaymentCash, EntryCounter, 10, 0)
- require.Error(t, err)
- record := &dao.VehicleRecord{PaymentStatus: "unpaid"}
- require.NoError(t, global.GVA_DB.Create(record).Error)
- _, err = svc.ProcessPayment(record.ID, PaymentCash, -1, 0, 1)
- require.Error(t, err)
- var paymentCount int64
- require.NoError(t, global.GVA_DB.Model(&dao.PaymentRecord{}).Where("record_id = ?", record.ID).Count(&paymentCount).Error)
- require.Zero(t, paymentCount)
- }
- func TestZeroAmountPaymentIsAllowedForZeroFeeSettlement(t *testing.T) {
- svc := setupPaymentServiceTest(t)
- _, paidAmount, err := svc.ValidatePayment(nil, PaymentPOS, EntryCounter, 0, 999)
- require.NoError(t, err)
- require.Zero(t, paidAmount)
- record := &dao.VehicleRecord{PaymentStatus: "unpaid"}
- require.NoError(t, global.GVA_DB.Create(record).Error)
- payment, err := svc.ProcessPayment(record.ID, PaymentCash, 0, 0, 1)
- require.NoError(t, err)
- require.NotNil(t, payment)
- require.Zero(t, payment.Amount)
- require.Zero(t, payment.PaidAmount)
- require.Zero(t, payment.ChangeAmount)
- var persisted dao.VehicleRecord
- require.NoError(t, global.GVA_DB.First(&persisted, record.ID).Error)
- require.Equal(t, "paid", persisted.PaymentStatus)
- }
- func TestPaymentRejectsDuplicateSettlement(t *testing.T) {
- svc := setupPaymentServiceTest(t)
- record := &dao.VehicleRecord{PaymentStatus: "unpaid"}
- require.NoError(t, global.GVA_DB.Create(record).Error)
- _, err := svc.ProcessPayment(record.ID, PaymentCash, 10, 10, 1)
- require.NoError(t, err)
- _, err = svc.ProcessPayment(record.ID, PaymentCash, 10, 10, 1)
- require.ErrorIs(t, err, ErrPaymentAlreadyProcessed)
- var paymentCount int64
- require.NoError(t, global.GVA_DB.Model(&dao.PaymentRecord{}).Where("record_id = ?", record.ID).Count(&paymentCount).Error)
- require.EqualValues(t, 1, paymentCount)
- }
- func TestPaymentConcurrentSettlementHasSingleWinner(t *testing.T) {
- svc := setupPaymentServiceTest(t)
- record := &dao.VehicleRecord{PaymentStatus: "unpaid"}
- require.NoError(t, global.GVA_DB.Create(record).Error)
- const attempts = 8
- start := make(chan struct{})
- results := make(chan error, attempts)
- var wg sync.WaitGroup
- for i := 0; i < attempts; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- <-start
- _, err := svc.ProcessPayment(record.ID, PaymentCash, 0, 0, 1)
- results <- err
- }()
- }
- close(start)
- wg.Wait()
- close(results)
- successes := 0
- for err := range results {
- if err == nil {
- successes++
- }
- }
- require.Equal(t, 1, successes)
- var paymentCount int64
- require.NoError(t, global.GVA_DB.Model(&dao.PaymentRecord{}).Where("record_id = ?", record.ID).Count(&paymentCount).Error)
- require.EqualValues(t, 1, paymentCount)
- }
- func TestPaymentTransactionRollbackLeavesNoPartialState(t *testing.T) {
- svc := setupPaymentServiceTest(t)
- record := &dao.VehicleRecord{PaymentStatus: "unpaid"}
- require.NoError(t, global.GVA_DB.Create(record).Error)
- rollbackErr := errors.New("force rollback")
- err := global.GVA_DB.Transaction(func(tx *gorm.DB) error {
- if _, err := svc.ProcessPaymentTxAtEntry(tx, record.ID, EntryCounter, PaymentCash, 10, 10, 1); err != nil {
- return err
- }
- return rollbackErr
- })
- require.ErrorIs(t, err, rollbackErr)
- var persisted dao.VehicleRecord
- require.NoError(t, global.GVA_DB.First(&persisted, record.ID).Error)
- require.Equal(t, "unpaid", persisted.PaymentStatus)
- var paymentCount int64
- require.NoError(t, global.GVA_DB.Model(&dao.PaymentRecord{}).Where("record_id = ?", record.ID).Count(&paymentCount).Error)
- require.Zero(t, paymentCount)
- }
- func TestPaymentMissingVehicleRollsBackCreatedRecord(t *testing.T) {
- svc := setupPaymentServiceTest(t)
- _, err := svc.ProcessPayment(999999, PaymentCash, 0, 0, 1)
- require.ErrorIs(t, err, ErrVehicleRecordNotFound)
- var paymentCount int64
- require.NoError(t, global.GVA_DB.Model(&dao.PaymentRecord{}).Count(&paymentCount).Error)
- require.Zero(t, paymentCount)
- }
|