Files

307 lines
9.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}