feat: update aftersales service types and serial format
This commit is contained in:
+2
-2
@@ -272,7 +272,7 @@ type CreateAftersalesOrderDTO struct {
|
|||||||
CompanyAddress string `json:"companyAddress" validate:"required"`
|
CompanyAddress string `json:"companyAddress" validate:"required"`
|
||||||
ContactName string `json:"contactName" validate:"required"`
|
ContactName string `json:"contactName" validate:"required"`
|
||||||
ContactPhone string `json:"contactPhone" validate:"required,len=11"`
|
ContactPhone string `json:"contactPhone" validate:"required,len=11"`
|
||||||
ServiceType string `json:"serviceType" validate:"required,oneof=software hardware other"`
|
ServiceType string `json:"serviceType" validate:"required,oneof=software hardware maintenance"`
|
||||||
IssueDescription string `json:"issueDescription" validate:"required"`
|
IssueDescription string `json:"issueDescription" validate:"required"`
|
||||||
TechnicianID *uint `json:"technicianId,omitempty"`
|
TechnicianID *uint `json:"technicianId,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -282,7 +282,7 @@ type UpdateAftersalesOrderDTO struct {
|
|||||||
CompanyAddress string `json:"companyAddress,omitempty"`
|
CompanyAddress string `json:"companyAddress,omitempty"`
|
||||||
ContactName string `json:"contactName,omitempty"`
|
ContactName string `json:"contactName,omitempty"`
|
||||||
ContactPhone string `json:"contactPhone,omitempty" validate:"omitempty,len=11"`
|
ContactPhone string `json:"contactPhone,omitempty" validate:"omitempty,len=11"`
|
||||||
ServiceType string `json:"serviceType,omitempty" validate:"omitempty,oneof=software hardware other"`
|
ServiceType string `json:"serviceType,omitempty" validate:"omitempty,oneof=software hardware maintenance"`
|
||||||
IssueDescription string `json:"issueDescription,omitempty"`
|
IssueDescription string `json:"issueDescription,omitempty"`
|
||||||
ResolutionNote string `json:"resolutionNote,omitempty"`
|
ResolutionNote string `json:"resolutionNote,omitempty"`
|
||||||
TechnicianID *uint `json:"technicianId,omitempty"`
|
TechnicianID *uint `json:"technicianId,omitempty"`
|
||||||
|
|||||||
@@ -108,26 +108,27 @@ func normalizeAftersalesSerial(sn string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generateUniqueSerial 生成唯一的售后工单序列号
|
// generateUniqueSerial 生成唯一的售后工单序列号
|
||||||
// 格式:zjbf-sh-YYMMNN,YY=年份后两位,MM=月份,NN=当月第几单(至少 2 位,溢出自然加宽)
|
// 格式:zjbf-sh-YYMMDDNN,YY=年份后两位,MM=月份,DD=日期,NN=当天第几单(至少 2 位,溢出自然加宽)
|
||||||
func (s *AftersalesService) generateUniqueSerial() (string, error) {
|
func (s *AftersalesService) generateUniqueSerial() (string, error) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
yy := now.Year() % 100
|
yy := now.Year() % 100
|
||||||
mm := int(now.Month())
|
mm := int(now.Month())
|
||||||
|
dd := now.Day()
|
||||||
|
|
||||||
monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
dayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||||
nextMonth := monthStart.AddDate(0, 1, 0)
|
nextDay := dayStart.AddDate(0, 0, 1)
|
||||||
|
|
||||||
// 统计本月已创建工单数(含软删除,避免编号回收)
|
// 统计当天已创建工单数(含软删除,避免编号回收)
|
||||||
var count int64
|
var count int64
|
||||||
if err := database.DB.Unscoped().Model(&models.AftersalesOrder{}).
|
if err := database.DB.Unscoped().Model(&models.AftersalesOrder{}).
|
||||||
Where("created_at >= ? AND created_at < ?", monthStart, nextMonth).
|
Where("created_at >= ? AND created_at < ?", dayStart, nextDay).
|
||||||
Count(&count).Error; err != nil {
|
Count(&count).Error; err != nil {
|
||||||
return "", fmt.Errorf("统计当月工单数失败: %w", err)
|
return "", fmt.Errorf("统计当日工单数失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
seq := int(count) + 1
|
seq := int(count) + 1
|
||||||
for attempt := 0; attempt < 100; attempt++ {
|
for attempt := 0; attempt < 100; attempt++ {
|
||||||
candidate := fmt.Sprintf("%s%02d%02d%02d", aftersalesSerialPrefix, yy, mm, seq)
|
candidate := fmt.Sprintf("%s%02d%02d%02d%02d", aftersalesSerialPrefix, yy, mm, dd, seq)
|
||||||
|
|
||||||
var existing models.AftersalesOrder
|
var existing models.AftersalesOrder
|
||||||
result := database.DB.Unscoped().Where("serial_number = ?", candidate).First(&existing)
|
result := database.DB.Unscoped().Where("serial_number = ?", candidate).First(&existing)
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func createOrderFor(t *testing.T, user models.User, phone string) *models.Afters
|
|||||||
return order
|
return order
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAftersalesService_Create_GeneratesYYMMNNSerial(t *testing.T) {
|
func TestAftersalesService_Create_GeneratesYYMMDDNNSerial(t *testing.T) {
|
||||||
user := seedTechnician(t, "aftersales_create_tech")
|
user := seedTechnician(t, "aftersales_create_tech")
|
||||||
defer database.DB.Unscoped().Delete(&user)
|
defer database.DB.Unscoped().Delete(&user)
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ func TestAftersalesService_Create_GeneratesYYMMNNSerial(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, order)
|
assert.NotNil(t, order)
|
||||||
assert.True(t, strings.HasPrefix(order.SerialNumber, "zjbf-sh-"))
|
assert.True(t, strings.HasPrefix(order.SerialNumber, "zjbf-sh-"))
|
||||||
assert.Len(t, order.SerialNumber, len("zjbf-sh-")+6, "default serial should be 6 digits (YYMMNN)")
|
assert.Len(t, order.SerialNumber, len("zjbf-sh-")+8, "default serial should be 8 digits (YYMMDDNN)")
|
||||||
assert.Equal(t, WorkOrderStatusCreated, order.WorkOrderStatus)
|
assert.Equal(t, WorkOrderStatusCreated, order.WorkOrderStatus)
|
||||||
assert.Equal(t, AuthorizationStatusPending, order.AuthorizationStatus)
|
assert.Equal(t, AuthorizationStatusPending, order.AuthorizationStatus)
|
||||||
assert.NotNil(t, order.TechnicianID)
|
assert.NotNil(t, order.TechnicianID)
|
||||||
@@ -82,25 +82,25 @@ func TestAftersalesService_Create_GeneratesYYMMNNSerial(t *testing.T) {
|
|||||||
database.DB.Unscoped().Where("company_name = ?", "AftersalesSerialCo").Delete(&models.Company{})
|
database.DB.Unscoped().Where("company_name = ?", "AftersalesSerialCo").Delete(&models.Company{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAftersalesService_Create_SerialIncrementsWithinMonth(t *testing.T) {
|
func TestAftersalesService_Create_SerialIncrementsWithinDay(t *testing.T) {
|
||||||
user := seedTechnician(t, "aftersales_seq_tech")
|
user := seedTechnician(t, "aftersales_seq_tech")
|
||||||
defer database.DB.Unscoped().Delete(&user)
|
defer database.DB.Unscoped().Delete(&user)
|
||||||
|
|
||||||
svc := AftersalesService{}
|
svc := AftersalesService{}
|
||||||
first, err := svc.Create(models.CreateAftersalesOrderDTO{
|
first, err := svc.Create(models.CreateAftersalesOrderDTO{
|
||||||
CompanyName: "SeqCo", CompanyAddress: "addr", ContactName: "A", ContactPhone: "13800002000",
|
CompanyName: "SeqCo", CompanyAddress: "addr", ContactName: "A", ContactPhone: "13800002000",
|
||||||
ServiceType: "other", IssueDescription: "issue 1",
|
ServiceType: "maintenance", IssueDescription: "issue 1",
|
||||||
}, user.ID)
|
}, user.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
second, err := svc.Create(models.CreateAftersalesOrderDTO{
|
second, err := svc.Create(models.CreateAftersalesOrderDTO{
|
||||||
CompanyName: "SeqCo", CompanyAddress: "addr", ContactName: "A", ContactPhone: "13800002000",
|
CompanyName: "SeqCo", CompanyAddress: "addr", ContactName: "A", ContactPhone: "13800002000",
|
||||||
ServiceType: "other", IssueDescription: "issue 2",
|
ServiceType: "maintenance", IssueDescription: "issue 2",
|
||||||
}, user.ID)
|
}, user.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.NotEqual(t, first.SerialNumber, second.SerialNumber)
|
assert.NotEqual(t, first.SerialNumber, second.SerialNumber)
|
||||||
// 第二单的序号应大于第一单(按月递增)
|
// 第二单的序号应大于第一单(按天递增)
|
||||||
assert.True(t, second.SerialNumber > first.SerialNumber)
|
assert.True(t, second.SerialNumber > first.SerialNumber)
|
||||||
|
|
||||||
database.DB.Unscoped().Delete(first)
|
database.DB.Unscoped().Delete(first)
|
||||||
|
|||||||
Reference in New Issue
Block a user