2026-08-03 18:37:42 +08:00
|
|
|
// Package domain 定义采购服务的业务实体与不依赖外部系统的状态规则。
|
|
|
|
|
package domain
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var ErrInvalidTaskTransition = errors.New("invalid task status transition")
|
|
|
|
|
|
|
|
|
|
type TaskStatus string
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
TaskStatusDraft TaskStatus = "DRAFT"
|
|
|
|
|
TaskStatusPending TaskStatus = "PENDING"
|
|
|
|
|
TaskStatusClaimed TaskStatus = "CLAIMED"
|
|
|
|
|
TaskStatusOrdering TaskStatus = "ORDERING"
|
|
|
|
|
TaskStatusWaitingPayment TaskStatus = "WAITING_PAYMENT"
|
|
|
|
|
TaskStatusReconciliationRequired TaskStatus = "RECONCILIATION_REQUIRED"
|
|
|
|
|
TaskStatusNeedsManual TaskStatus = "NEEDS_MANUAL"
|
|
|
|
|
TaskStatusSucceeded TaskStatus = "SUCCEEDED"
|
2026-08-04 17:01:35 +08:00
|
|
|
TaskStatusFailed TaskStatus = "FAILED"
|
2026-08-03 18:37:42 +08:00
|
|
|
TaskStatusCanceled TaskStatus = "CANCELED"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Source string
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
SourceManual Source = "MANUAL"
|
|
|
|
|
SourceExcel Source = "EXCEL"
|
|
|
|
|
SourceERP Source = "ERP"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Task struct {
|
|
|
|
|
ID string
|
|
|
|
|
Source Source
|
|
|
|
|
SourceRef *string
|
|
|
|
|
Title string
|
|
|
|
|
GoodsID string
|
|
|
|
|
SKUColor string
|
|
|
|
|
SKUSize string
|
|
|
|
|
Quantity int
|
|
|
|
|
MaxTotalPrice string
|
|
|
|
|
ReferenceAssetID *string
|
|
|
|
|
Status TaskStatus
|
|
|
|
|
Version int
|
|
|
|
|
CreatedAt time.Time
|
|
|
|
|
UpdatedAt time.Time
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CanTransitionTo 只接受架构已定义的任务状态转移,未知状态或未列出的动作均拒绝。
|
|
|
|
|
func (status TaskStatus) CanTransitionTo(next TaskStatus) bool {
|
|
|
|
|
_, allowed := taskTransitions[status][next]
|
|
|
|
|
return allowed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TransitionTask 返回下一状态;非法转移必须在写库前失败,不能由调用方猜测补救路径。
|
|
|
|
|
func TransitionTask(current, next TaskStatus) (TaskStatus, error) {
|
|
|
|
|
if !current.CanTransitionTo(next) {
|
|
|
|
|
return current, ErrInvalidTaskTransition
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return next, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var taskTransitions = map[TaskStatus]map[TaskStatus]struct{}{
|
|
|
|
|
TaskStatusDraft: {
|
2026-08-04 17:01:35 +08:00
|
|
|
TaskStatusPending: {},
|
|
|
|
|
TaskStatusCanceled: {},
|
2026-08-03 18:37:42 +08:00
|
|
|
},
|
|
|
|
|
TaskStatusPending: {
|
2026-08-04 17:01:35 +08:00
|
|
|
TaskStatusClaimed: {},
|
|
|
|
|
TaskStatusDraft: {},
|
|
|
|
|
TaskStatusCanceled: {},
|
2026-08-03 18:37:42 +08:00
|
|
|
},
|
|
|
|
|
TaskStatusClaimed: {
|
|
|
|
|
TaskStatusOrdering: {},
|
2026-08-04 17:01:35 +08:00
|
|
|
TaskStatusDraft: {},
|
2026-08-03 18:37:42 +08:00
|
|
|
},
|
|
|
|
|
TaskStatusOrdering: {
|
|
|
|
|
TaskStatusNeedsManual: {},
|
|
|
|
|
TaskStatusWaitingPayment: {},
|
|
|
|
|
TaskStatusReconciliationRequired: {},
|
|
|
|
|
},
|
2026-08-04 17:01:35 +08:00
|
|
|
TaskStatusNeedsManual: {
|
|
|
|
|
TaskStatusDraft: {},
|
|
|
|
|
TaskStatusCanceled: {},
|
|
|
|
|
},
|
2026-08-03 18:37:42 +08:00
|
|
|
TaskStatusWaitingPayment: {
|
|
|
|
|
TaskStatusSucceeded: {},
|
|
|
|
|
},
|
2026-08-04 17:01:35 +08:00
|
|
|
TaskStatusReconciliationRequired: {
|
|
|
|
|
TaskStatusWaitingPayment: {},
|
|
|
|
|
TaskStatusFailed: {},
|
|
|
|
|
},
|
2026-08-03 18:37:42 +08:00
|
|
|
}
|