package repository import ( "errors" "strings" "time" "wails-app/internal/dao" "wails-app/internal/global" "gorm.io/gorm" ) type PaymentRepository struct{} func (r *PaymentRepository) EntryList() ([]dao.PaymentEntryConfig, error) { var entries []dao.PaymentEntryConfig if err := global.GVA_DB.Order("sort ASC, id ASC").Find(&entries).Error; err != nil { return nil, err } for i := range entries { codes, err := r.entryMethodCodes(global.GVA_DB, entries[i].Code) if err != nil { if strings.Contains(strings.ToLower(err.Error()), "no such table") { continue } return nil, err } entries[i].MethodCodes = codes } return entries, nil } func (r *PaymentRepository) entryMethodCodes(db *gorm.DB, entryCode string) ([]string, error) { var codes []string err := db.Model(&dao.PaymentEntryMethod{}).Where("entry_code = ?", entryCode). Order("sort ASC, id ASC").Pluck("method_code", &codes).Error return codes, err } func (r *PaymentRepository) MethodList() ([]dao.PaymentMethodConfig, error) { var methods []dao.PaymentMethodConfig if err := global.GVA_DB.Where("is_legacy = ?", false).Order("sort ASC, id ASC").Find(&methods).Error; err != nil { return nil, err } for i := range methods { codes, err := r.methodEntryCodes(global.GVA_DB, methods[i].Code) if err != nil { if strings.Contains(strings.ToLower(err.Error()), "no such table") { continue } return nil, err } methods[i].EntryCodes = codes } return methods, nil } func (r *PaymentRepository) methodEntryCodes(db *gorm.DB, methodCode string) ([]string, error) { var codes []string err := db.Model(&dao.PaymentEntryMethod{}).Where("method_code = ?", methodCode). Order("sort ASC, id ASC").Pluck("entry_code", &codes).Error return codes, err } func (r *PaymentRepository) EnabledMethodList(db *gorm.DB, entryCode string) ([]dao.PaymentMethodConfig, error) { var methods []dao.PaymentMethodConfig err := db.Table("payment_method_config AS pm"). Select("pm.*"). Joins("INNER JOIN payment_entry_method AS pem ON pem.method_code = pm.code"). Joins("INNER JOIN payment_entry_config AS pec ON pec.code = pem.entry_code"). Where("pem.entry_code = ? AND pem.deleted_at IS NULL AND pec.enabled = ? AND pm.enabled = ? AND pm.is_legacy = ?", entryCode, true, true, false). Order("pem.sort ASC, pm.sort ASC, pm.id ASC").Scan(&methods).Error return methods, err } func (r *PaymentRepository) IsMethodAllowed(db *gorm.DB, entryCode, methodCode string) (bool, error) { if db == nil { db = global.GVA_DB } var count int64 err := db.Table("payment_entry_method AS pem"). Joins("INNER JOIN payment_entry_config AS pec ON pec.code = pem.entry_code"). Where("pem.entry_code = ? AND pem.method_code = ? AND pem.deleted_at IS NULL AND pec.deleted_at IS NULL", entryCode, methodCode). Count(&count).Error return count > 0, err } func (r *PaymentRepository) GetMethodByID(id uint) (*dao.PaymentMethodConfig, error) { var method dao.PaymentMethodConfig err := global.GVA_DB.First(&method, id).Error return &method, err } func (r *PaymentRepository) GetMethodByCode(db *gorm.DB, code string) (*dao.PaymentMethodConfig, error) { if db == nil { db = global.GVA_DB } var method dao.PaymentMethodConfig err := db.Where("code = ?", code).First(&method).Error return &method, err } func (r *PaymentRepository) GetEntryByID(id uint) (*dao.PaymentEntryConfig, error) { var entry dao.PaymentEntryConfig err := global.GVA_DB.First(&entry, id).Error return &entry, err } func (r *PaymentRepository) GetEntryByCode(db *gorm.DB, code string) (*dao.PaymentEntryConfig, error) { if db == nil { db = global.GVA_DB } var entry dao.PaymentEntryConfig err := db.Where("code = ?", code).First(&entry).Error return &entry, err } func (r *PaymentRepository) CreateEntry(entry *dao.PaymentEntryConfig) error { return global.GVA_DB.Create(entry).Error } func (r *PaymentRepository) CreateEntryTx(db *gorm.DB, entry *dao.PaymentEntryConfig) error { return db.Create(entry).Error } func (r *PaymentRepository) UpdateEntry(entry *dao.PaymentEntryConfig) error { return global.GVA_DB.Model(entry).Select("name", "enabled", "sort", "description").Updates(entry).Error } func (r *PaymentRepository) UpdateEntryTx(db *gorm.DB, entry *dao.PaymentEntryConfig) error { return db.Model(entry).Select("name", "enabled", "sort", "description").Updates(entry).Error } func (r *PaymentRepository) SetEntryEnabled(id uint, enabled bool) error { result := global.GVA_DB.Model(&dao.PaymentEntryConfig{}).Where("id = ?", id).Update("enabled", enabled) if result.Error != nil { return result.Error } if result.RowsAffected == 0 { return gorm.ErrRecordNotFound } return nil } func (r *PaymentRepository) CreateMethod(method *dao.PaymentMethodConfig) error { return global.GVA_DB.Create(method).Error } func (r *PaymentRepository) CreateMethodTx(db *gorm.DB, method *dao.PaymentMethodConfig) error { return db.Create(method).Error } func (r *PaymentRepository) UpdateMethod(method *dao.PaymentMethodConfig) error { return global.GVA_DB.Model(method).Select("name", "input_mode", "enabled", "sort", "description").Updates(method).Error } func (r *PaymentRepository) SetMethodEnabled(id uint, enabled bool) error { result := global.GVA_DB.Model(&dao.PaymentMethodConfig{}).Where("id = ?", id).Update("enabled", enabled) if result.Error != nil { return result.Error } if result.RowsAffected == 0 { return gorm.ErrRecordNotFound } return nil } func (r *PaymentRepository) DeleteMethod(method *dao.PaymentMethodConfig) error { return global.GVA_DB.Transaction(func(tx *gorm.DB) error { if err := tx.Unscoped().Where("method_code = ?", method.Code).Delete(&dao.PaymentEntryMethod{}).Error; err != nil { return err } result := tx.Delete(method) if result.Error != nil { return result.Error } if result.RowsAffected == 0 { return errors.New("支付方式不存在") } return nil }) } func (r *PaymentRepository) ReplaceEntryMethods(db *gorm.DB, entryCode string, methodCodes []string) error { if err := db.Unscoped().Where("entry_code = ?", entryCode).Delete(&dao.PaymentEntryMethod{}).Error; err != nil { return err } for i, code := range methodCodes { if err := db.Create(&dao.PaymentEntryMethod{EntryCode: entryCode, MethodCode: code, Sort: i * 10}).Error; err != nil { return err } } return nil } func (r *PaymentRepository) ReplaceMethodEntries(db *gorm.DB, methodCode string, entryCodes []string) error { if err := db.Unscoped().Where("method_code = ?", methodCode).Delete(&dao.PaymentEntryMethod{}).Error; err != nil { return err } for i, code := range entryCodes { if err := db.Create(&dao.PaymentEntryMethod{EntryCode: code, MethodCode: methodCode, Sort: i * 10}).Error; err != nil { return err } } return nil } func (r *PaymentRepository) DeleteEntry(entry *dao.PaymentEntryConfig) error { return global.GVA_DB.Transaction(func(tx *gorm.DB) error { if err := tx.Unscoped().Where("entry_code = ?", entry.Code).Delete(&dao.PaymentEntryMethod{}).Error; err != nil { return err } return tx.Delete(entry).Error }) } func (r *PaymentRepository) Create(record *dao.PaymentRecord) error { return global.GVA_DB.Create(record).Error } // PaymentListQuery 收费记录查询参数 type PaymentListQuery struct { PlateNumber string `form:"plate_number"` PaymentEntry string `form:"payment_entry"` PaymentMethod string `form:"payment_method"` ParkingLotID uint `form:"parking_lot_id"` StartDate string `form:"start_date"` EndDate string `form:"end_date"` Page int `form:"page"` PageSize int `form:"page_size"` } // PaymentListResult 收费记录列表项 type PaymentListResult struct { ID uint `json:"id"` PlateNumber string `json:"plate_number"` VehicleType string `json:"vehicle_type"` PaymentEntry string `json:"payment_entry"` PaymentEntryName string `json:"payment_entry_name"` PaymentMethod string `json:"payment_method"` PaymentMethodName string `json:"payment_method_name"` Amount float64 `json:"amount"` PaidAmount float64 `json:"paid_amount"` ChangeAmount float64 `json:"change_amount"` OperatorID uint `json:"operator_id"` OperatorName string `json:"operator_name"` ParkingLot string `json:"parking_lot"` PaidAt string `json:"paid_at"` EntryTime string `json:"entry_time"` ExitTime string `json:"exit_time"` StayTime int64 `json:"stay_time"` } // List 查询收费记录列表(关联 vehicle_record + vehicle + vehicle_type) func (r *PaymentRepository) List(q PaymentListQuery) ([]PaymentListResult, int64, error) { db := global.GVA_DB.Table("payment_record"). Select(`payment_record.id, vehicle_record.plate_number, vehicle_type.name as vehicle_type, payment_record.payment_entry, COALESCE(payment_entry_config.name, payment_record.payment_entry) as payment_entry_name, payment_record.payment_method, COALESCE(payment_method_config.name, CASE WHEN payment_record.payment_method = 'free' THEN '免密放行' ELSE payment_record.payment_method END) as payment_method_name, payment_record.amount, payment_record.paid_amount, payment_record.change_amount, payment_record.operator_id, sys_users.nick_name as operator_name, vehicle_record.parking_lot_id, parking_lot.lot_name as parking_lot, payment_record.paid_at, vehicle_record.entry_time, vehicle_record.exit_time, vehicle_record.stay_time`). Joins("LEFT JOIN vehicle_record ON vehicle_record.id = payment_record.record_id"). Joins("LEFT JOIN vehicle ON vehicle.plate_number = vehicle_record.plate_number"). Joins("LEFT JOIN vehicle_type ON vehicle_type.id = vehicle.vehicle_type_id"). Joins("LEFT JOIN sys_users ON sys_users.id = payment_record.operator_id"). Joins("LEFT JOIN parking_lot ON parking_lot.id = vehicle_record.parking_lot_id") db = db.Joins("LEFT JOIN payment_entry_config ON payment_entry_config.code = payment_record.payment_entry") db = db.Joins("LEFT JOIN payment_method_config ON payment_method_config.code = payment_record.payment_method") if q.PlateNumber != "" { db = db.Where("vehicle_record.plate_number LIKE ?", "%"+q.PlateNumber+"%") } if q.ParkingLotID > 0 { db = db.Where("vehicle_record.parking_lot_id = ?", q.ParkingLotID) } if q.PaymentMethod != "" { db = db.Where("payment_record.payment_method = ?", q.PaymentMethod) } if q.PaymentEntry != "" { db = db.Where("payment_record.payment_entry = ?", q.PaymentEntry) } if q.StartDate != "" { db = db.Where("payment_record.paid_at >= ?", q.StartDate) } if q.EndDate != "" { db = db.Where("payment_record.paid_at <= ?", q.EndDate+" 23:59:59") } var total int64 db.Count(&total) if q.Page <= 0 { q.Page = 1 } if q.PageSize <= 0 { q.PageSize = 10 } offset := (q.Page - 1) * q.PageSize var results []PaymentListResult err := db.Order("payment_record.paid_at DESC").Offset(offset).Limit(q.PageSize).Scan(&results).Error return results, total, err } // TodaySummary 当日收费汇总 type TodaySummary struct { TotalAmount float64 `json:"total_amount"` CashAmount float64 `json:"cash_amount"` FreeAmount float64 `json:"free_amount"` TotalCount int64 `json:"total_count"` } // GetTodaySummary 获取当日收费汇总 func (r *PaymentRepository) GetTodaySummary() (TodaySummary, error) { var s TodaySummary today := time.Now().Format("2006-01-02") err := global.GVA_DB.Table("payment_record"). Select(`COALESCE(SUM(amount), 0) as total_amount, COALESCE(SUM(CASE WHEN payment_method = 'cash' THEN amount ELSE 0 END), 0) as cash_amount, COALESCE(SUM(CASE WHEN payment_method = 'free' THEN amount ELSE 0 END), 0) as free_amount, COUNT(*) as total_count`). Where("paid_at >= ? AND paid_at < ?", today, today+" 23:59:59"). Scan(&s).Error return s, err }