307 lines
9.5 KiB
Go
307 lines
9.5 KiB
Go
package repository
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"gorm.io/gorm"
|
||
|
||
"license-manager/internal/models"
|
||
)
|
||
|
||
type customerRepository struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
// NewCustomerRepository 创建客户数据访问实例
|
||
func NewCustomerRepository(db *gorm.DB) CustomerRepository {
|
||
return &customerRepository{
|
||
db: db,
|
||
}
|
||
}
|
||
|
||
// GetCustomerList 查询客户列表
|
||
func (r *customerRepository) GetCustomerList(ctx context.Context, req *models.CustomerListRequest) (*models.CustomerListResponse, error) {
|
||
// 设置默认值
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.PageSize <= 0 {
|
||
req.PageSize = 20
|
||
}
|
||
if req.PageSize > 100 {
|
||
req.PageSize = 100
|
||
}
|
||
if req.Sort == "" {
|
||
req.Sort = "created_at"
|
||
}
|
||
if req.Order == "" {
|
||
req.Order = "desc"
|
||
}
|
||
|
||
// 构建查询
|
||
query := r.db.Model(&models.Customer{})
|
||
|
||
// 搜索关键词筛选
|
||
if req.Search != "" {
|
||
searchTerm := "%" + strings.TrimSpace(req.Search) + "%"
|
||
query = query.Where(
|
||
"customer_code LIKE ? OR customer_name LIKE ? OR contact_person LIKE ? OR email LIKE ?",
|
||
searchTerm, searchTerm, searchTerm, searchTerm,
|
||
)
|
||
}
|
||
|
||
// 客户类型筛选
|
||
if req.CustomerType != "" {
|
||
query = query.Where("customer_type = ?", req.CustomerType)
|
||
}
|
||
|
||
// 客户等级筛选
|
||
if req.CustomerLevel != "" {
|
||
query = query.Where("customer_level = ?", req.CustomerLevel)
|
||
}
|
||
|
||
// 状态筛选
|
||
if req.Status != "" {
|
||
query = query.Where("status = ?", req.Status)
|
||
}
|
||
|
||
// 计算总数
|
||
var total int64
|
||
if err := query.Count(&total).Error; err != nil {
|
||
return nil, fmt.Errorf("failed to count customers: %w", err)
|
||
}
|
||
|
||
// 排序和分页
|
||
offset := (req.Page - 1) * req.PageSize
|
||
orderClause := fmt.Sprintf("%s %s", req.Sort, strings.ToUpper(req.Order))
|
||
query = query.Order(orderClause).Offset(offset).Limit(req.PageSize)
|
||
|
||
// 查询数据
|
||
var customers []models.Customer
|
||
if err := query.Find(&customers).Error; err != nil {
|
||
return nil, fmt.Errorf("failed to query customers: %w", err)
|
||
}
|
||
|
||
// 转换为响应格式
|
||
customerList := make([]models.CustomerListItem, 0, len(customers))
|
||
for _, customer := range customers {
|
||
customerList = append(customerList, models.CustomerListItem{
|
||
ID: customer.ID,
|
||
CustomerCode: customer.CustomerCode,
|
||
CustomerName: customer.CustomerName,
|
||
CustomerType: customer.CustomerType,
|
||
ContactPerson: customer.ContactPerson,
|
||
Email: customer.Email,
|
||
CustomerLevel: customer.CustomerLevel,
|
||
Status: customer.Status,
|
||
CreatedAt: customer.CreatedAt.Format(time.RFC3339),
|
||
})
|
||
}
|
||
|
||
// 计算总页数
|
||
totalPages := int(total) / req.PageSize
|
||
if int(total)%req.PageSize > 0 {
|
||
totalPages++
|
||
}
|
||
|
||
return &models.CustomerListResponse{
|
||
List: customerList,
|
||
Total: total,
|
||
Page: req.Page,
|
||
PageSize: req.PageSize,
|
||
TotalPages: totalPages,
|
||
}, nil
|
||
}
|
||
|
||
// GetCustomerByID 根据ID获取客户信息
|
||
func (r *customerRepository) GetCustomerByID(ctx context.Context, id string) (*models.Customer, error) {
|
||
var customer models.Customer
|
||
|
||
if err := r.db.Where("id = ?", id).First(&customer).Error; err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
return nil, ErrCustomerNotFound
|
||
}
|
||
return nil, fmt.Errorf("failed to get customer by id: %w", err)
|
||
}
|
||
return &customer, nil
|
||
}
|
||
|
||
// CreateCustomer 创建客户
|
||
func (r *customerRepository) CreateCustomer(ctx context.Context, customer *models.Customer) error {
|
||
// 使用事务确保数据一致性
|
||
return r.db.Transaction(func(tx *gorm.DB) error {
|
||
// 生成客户编码
|
||
customerCode, err := r.generateCustomerCode(tx)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to generate customer code: %w", err)
|
||
}
|
||
customer.CustomerCode = customerCode
|
||
|
||
// 创建客户
|
||
if err := tx.Create(customer).Error; err != nil {
|
||
return fmt.Errorf("failed to create customer: %w", err)
|
||
}
|
||
return nil
|
||
})
|
||
}
|
||
|
||
// generateCustomerCode 生成客户编码
|
||
func (r *customerRepository) generateCustomerCode(tx *gorm.DB) (string, error) {
|
||
currentYear := time.Now().Year()
|
||
|
||
// 查询或创建当年的序列号记录
|
||
var sequence models.CustomerCodeSequence
|
||
err := tx.Where("year = ?", currentYear).First(&sequence).Error
|
||
if err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
// 创建新年份的序列号记录
|
||
sequence = models.CustomerCodeSequence{
|
||
Year: currentYear,
|
||
SequenceNumber: 1,
|
||
}
|
||
if err := tx.Create(&sequence).Error; err != nil {
|
||
return "", fmt.Errorf("failed to create sequence: %w", err)
|
||
}
|
||
} else {
|
||
return "", fmt.Errorf("failed to query sequence: %w", err)
|
||
}
|
||
} else {
|
||
// 更新序列号
|
||
sequence.SequenceNumber++
|
||
if err := tx.Save(&sequence).Error; err != nil {
|
||
return "", fmt.Errorf("failed to update sequence: %w", err)
|
||
}
|
||
}
|
||
|
||
// 生成客户编码:CUS-YYYY-NNNN
|
||
customerCode := fmt.Sprintf("CUS-%d-%04d", currentYear, sequence.SequenceNumber)
|
||
return customerCode, nil
|
||
}
|
||
|
||
// UpdateCustomer 更新客户信息
|
||
func (r *customerRepository) UpdateCustomer(ctx context.Context, customer *models.Customer) error {
|
||
if err := r.db.Save(customer).Error; err != nil {
|
||
return fmt.Errorf("failed to update customer: %w", err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// DeleteCustomer 删除客户(物理删除)
|
||
func (r *customerRepository) DeleteCustomer(ctx context.Context, id string) error {
|
||
result := r.db.Unscoped().Where("id = ?", id).Delete(&models.Customer{})
|
||
if result.Error != nil {
|
||
return fmt.Errorf("failed to delete customer: %w", result.Error)
|
||
}
|
||
if result.RowsAffected == 0 {
|
||
return ErrCustomerNotFound
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// CheckCustomerHasAuthorizationCodes 检查客户是否有关联的授权码
|
||
func (r *customerRepository) CheckCustomerHasAuthorizationCodes(ctx context.Context, customerID string) (bool, error) {
|
||
var count int64
|
||
err := r.db.Model(&models.AuthorizationCode{}).Where("customer_id = ?", customerID).Count(&count).Error
|
||
if err != nil {
|
||
return false, fmt.Errorf("failed to check authorization codes: %w", err)
|
||
}
|
||
return count > 0, nil
|
||
}
|
||
|
||
// CheckCustomerHasLicenses 检查客户是否有关联的许可证
|
||
func (r *customerRepository) CheckCustomerHasLicenses(ctx context.Context, customerID string) (bool, error) {
|
||
var count int64
|
||
err := r.db.Model(&models.License{}).Where("customer_id = ?", customerID).Count(&count).Error
|
||
if err != nil {
|
||
return false, fmt.Errorf("failed to check licenses: %w", err)
|
||
}
|
||
return count > 0, nil
|
||
}
|
||
|
||
// GetCustomerCount 获取客户总数(用于统计)
|
||
func (r *customerRepository) GetCustomerCount(ctx context.Context, filters map[string]interface{}) (int64, error) {
|
||
var count int64
|
||
query := r.db.Model(&models.Customer{})
|
||
|
||
// 应用筛选条件
|
||
for key, value := range filters {
|
||
query = query.Where(fmt.Sprintf("%s = ?", key), value)
|
||
}
|
||
|
||
if err := query.Count(&count).Error; err != nil {
|
||
return 0, fmt.Errorf("failed to count customers: %w", err)
|
||
}
|
||
|
||
return count, nil
|
||
}
|
||
|
||
// GetCustomerAuthorizationStats 获取客户授权统计信息
|
||
func (r *customerRepository) GetCustomerAuthorizationStats(ctx context.Context, customerID string) (*models.AuthorizationStats, error) {
|
||
stats := &models.AuthorizationStats{}
|
||
|
||
// 1. 授权码统计
|
||
// 总授权码数量
|
||
var totalAuthCodes int64
|
||
if err := r.db.Model(&models.AuthorizationCode{}).
|
||
Where("customer_id = ?", customerID).
|
||
Count(&totalAuthCodes).Error; err != nil {
|
||
return nil, fmt.Errorf("failed to count total auth codes: %w", err)
|
||
}
|
||
stats.TotalAuthCodes = totalAuthCodes
|
||
|
||
// 已过期授权码数量(end_date < NOW(),不考虑锁定状态)
|
||
var expiredAuthCodes int64
|
||
if err := r.db.Model(&models.AuthorizationCode{}).
|
||
Where("customer_id = ? AND end_date < NOW()", customerID).
|
||
Count(&expiredAuthCodes).Error; err != nil {
|
||
return nil, fmt.Errorf("failed to count expired auth codes: %w", err)
|
||
}
|
||
stats.ExpiredAuthCodes = expiredAuthCodes
|
||
|
||
// 30日内即将到期授权码数量(end_date >= NOW() AND end_date <= DATE_ADD(NOW(), INTERVAL 30 DAY),不考虑锁定状态)
|
||
var expiringSoonAuthCodes int64
|
||
if err := r.db.Model(&models.AuthorizationCode{}).
|
||
Where("customer_id = ? AND end_date >= NOW() AND end_date <= DATE_ADD(NOW(), INTERVAL 30 DAY)", customerID).
|
||
Count(&expiringSoonAuthCodes).Error; err != nil {
|
||
return nil, fmt.Errorf("failed to count expiring soon auth codes: %w", err)
|
||
}
|
||
stats.ExpiringSoonAuthCodes = expiringSoonAuthCodes
|
||
|
||
// 2. 许可证统计
|
||
// 总许可证数量
|
||
var totalLicenses int64
|
||
if err := r.db.Model(&models.License{}).
|
||
Where("customer_id = ? AND deleted_at IS NULL", customerID).
|
||
Count(&totalLicenses).Error; err != nil {
|
||
return nil, fmt.Errorf("failed to count total licenses: %w", err)
|
||
}
|
||
stats.TotalLicenses = totalLicenses
|
||
|
||
// 已激活许可证数量(status = 'active')
|
||
var activeLicenses int64
|
||
if err := r.db.Model(&models.License{}).
|
||
Where("customer_id = ? AND status = 'active' AND deleted_at IS NULL", customerID).
|
||
Count(&activeLicenses).Error; err != nil {
|
||
return nil, fmt.Errorf("failed to count active licenses: %w", err)
|
||
}
|
||
stats.ActiveLicenses = activeLicenses
|
||
|
||
// 未激活许可证数量(total - active)
|
||
stats.InactiveLicenses = totalLicenses - activeLicenses
|
||
|
||
// 已过期许可证数量(关联的授权码已过期)
|
||
// 需要通过JOIN authorization_codes表来判断
|
||
var expiredLicenses int64
|
||
if err := r.db.Model(&models.License{}).
|
||
Joins("INNER JOIN authorization_codes ON licenses.authorization_code_id = authorization_codes.id").
|
||
Where("licenses.customer_id = ? AND authorization_codes.end_date < NOW() AND licenses.deleted_at IS NULL", customerID).
|
||
Count(&expiredLicenses).Error; err != nil {
|
||
return nil, fmt.Errorf("failed to count expired licenses: %w", err)
|
||
}
|
||
stats.ExpiredLicenses = expiredLicenses
|
||
|
||
return stats, nil
|
||
} |