Add aftersales work order feature
- AftersalesOrder model with state machine (created/pending_confirmation/closed/rejected)
- Public scan-to-confirm flow with phone last-4 verification and rate limiting
- Technician role and middleware for ownership-scoped operations
- QR code generation pointing to /aftersales/{serialNumber}
- Admin overrides: reassign, force-close, delete
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -209,3 +209,88 @@ type UpdateEmployeeSerialDTO struct {
|
||||
EmployeeName string `json:"employeeName,omitempty" validate:"omitempty"`
|
||||
IsActive *bool `json:"isActive,omitempty"`
|
||||
}
|
||||
|
||||
// AftersalesOrder 售后工单模型
|
||||
type AftersalesOrder struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
SerialNumber string `gorm:"uniqueIndex;size:64" json:"serialNumber"`
|
||||
CompanyName string `gorm:"index;size:255" json:"companyName"`
|
||||
CompanyAddress string `gorm:"size:500" json:"companyAddress"`
|
||||
ContactName string `gorm:"size:100" json:"contactName"`
|
||||
ContactPhone string `gorm:"size:32" json:"contactPhone"`
|
||||
ServiceType string `gorm:"size:32" json:"serviceType"`
|
||||
IssueDescription string `gorm:"type:text" json:"issueDescription"`
|
||||
ResolutionNote string `gorm:"type:text" json:"resolutionNote"`
|
||||
|
||||
WorkOrderStatus string `gorm:"size:32;default:'created'" json:"workOrderStatus"`
|
||||
AuthorizationStatus string `gorm:"size:32;default:'pending'" json:"authorizationStatus"`
|
||||
|
||||
TechnicianID *uint `json:"technicianId"`
|
||||
CreatedBy *uint `json:"createdBy"`
|
||||
ScannedAt *time.Time `json:"scannedAt"`
|
||||
ConfirmedAt *time.Time `json:"confirmedAt"`
|
||||
RejectCount int `gorm:"default:0" json:"rejectCount"`
|
||||
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
Technician *User `gorm:"foreignKey:TechnicianID" json:"technician,omitempty"`
|
||||
Creator *User `gorm:"foreignKey:CreatedBy" json:"creator,omitempty"`
|
||||
Company *Company `gorm:"foreignKey:CompanyName;references:CompanyName" json:"company,omitempty"`
|
||||
}
|
||||
|
||||
// CreateAftersalesOrderDTO 创建售后工单请求数据
|
||||
type CreateAftersalesOrderDTO struct {
|
||||
CompanyName string `json:"companyName" validate:"required"`
|
||||
CompanyAddress string `json:"companyAddress" validate:"required"`
|
||||
ContactName string `json:"contactName" validate:"required"`
|
||||
ContactPhone string `json:"contactPhone" validate:"required,len=11"`
|
||||
ServiceType string `json:"serviceType" validate:"required,oneof=software hardware other"`
|
||||
IssueDescription string `json:"issueDescription" validate:"required"`
|
||||
TechnicianID *uint `json:"technicianId,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateAftersalesOrderDTO 更新售后工单请求数据
|
||||
type UpdateAftersalesOrderDTO struct {
|
||||
CompanyAddress string `json:"companyAddress,omitempty"`
|
||||
ContactName string `json:"contactName,omitempty"`
|
||||
ContactPhone string `json:"contactPhone,omitempty" validate:"omitempty,len=11"`
|
||||
ServiceType string `json:"serviceType,omitempty" validate:"omitempty,oneof=software hardware other"`
|
||||
IssueDescription string `json:"issueDescription,omitempty"`
|
||||
ResolutionNote string `json:"resolutionNote,omitempty"`
|
||||
TechnicianID *uint `json:"technicianId,omitempty"`
|
||||
}
|
||||
|
||||
// SubmitForConfirmationDTO 提交客户确认请求
|
||||
type SubmitForConfirmationDTO struct {
|
||||
ResolutionNote string `json:"resolutionNote" validate:"required"`
|
||||
}
|
||||
|
||||
// CustomerConfirmDTO 客户确认请求
|
||||
type CustomerConfirmDTO struct {
|
||||
PhoneLast4 string `json:"phoneLast4" validate:"required,len=4,numeric"`
|
||||
Action string `json:"action" validate:"required,oneof=authorize reject"`
|
||||
RejectReason string `json:"rejectReason,omitempty"`
|
||||
}
|
||||
|
||||
// ReassignAftersalesDTO 重新分配技术员请求
|
||||
type ReassignAftersalesDTO struct {
|
||||
TechnicianID uint `json:"technicianId" validate:"required"`
|
||||
}
|
||||
|
||||
// AftersalesPublicView 公开查询返回视图(脱敏)
|
||||
type AftersalesPublicView struct {
|
||||
SerialNumber string `json:"serialNumber"`
|
||||
CompanyName string `json:"companyName"`
|
||||
CompanyAddress string `json:"companyAddress"`
|
||||
ContactName string `json:"contactName"`
|
||||
ServiceType string `json:"serviceType"`
|
||||
IssueDescription string `json:"issueDescription"`
|
||||
ResolutionNote string `json:"resolutionNote"`
|
||||
WorkOrderStatus string `json:"workOrderStatus"`
|
||||
AuthorizationStatus string `json:"authorizationStatus"`
|
||||
TechnicianName string `json:"technicianName"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
ConfirmedAt *time.Time `json:"confirmedAt"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user