feat: 支持勾选部分档口入库码匹配 (#235)

This commit is contained in:
chengma
2026-08-15 09:41:45 +08:00
parent 05b59974e8
commit 63f8407780
10 changed files with 342 additions and 55 deletions
+65 -12
View File
@@ -30,22 +30,35 @@ type InnerCodePlanResult struct {
Failed int
}
// PlanInnerCodeRecords 对某个业务日期的可重规划记录读取最新远端详情并原子保存计划。
// PlanInnerCodeRecords 对某个业务日期选中的可重规划记录读取最新远端详情并原子保存计划。
// 本函数绝不调用删除或更新顺运宝接口。
func PlanInnerCodeRecords(ctx context.Context, db *sql.DB, reader InnerCodeDetailReader, businessDate string) (*InnerCodePlanResult, error) {
func PlanInnerCodeRecords(ctx context.Context, db *sql.DB, reader InnerCodeDetailReader, businessDate string, selectedIDs []int64) (*InnerCodePlanResult, error) {
if _, err := time.Parse("2006-01-02", businessDate); err != nil {
return nil, fmt.Errorf("业务日期格式应为 YYYY-MM-DD")
}
records, err := repository.ListInnerCodeRecordsForPlanning(db, businessDate)
selectedIDs = uniquePositiveInnerCodeIDs(selectedIDs)
if len(selectedIDs) == 0 {
return nil, fmt.Errorf("没有选中可匹配记录")
}
records, err := repository.ListInnerCodeRecordsForPlanning(db, businessDate, selectedIDs)
if err != nil {
return nil, err
}
result := &InnerCodePlanResult{Total: len(records)}
if len(records) == 0 {
return result, nil
if len(records) != len(selectedIDs) {
return nil, fmt.Errorf("部分选中记录不存在、业务日期不一致或状态已变化,请刷新后重新勾选")
}
result := &InnerCodePlanResult{Total: len(records)}
orders := uniqueInnerCodeOrders(records)
contextRecords, err := repository.ListInnerCodePlanningContext(db, businessDate, orders)
if err != nil {
return nil, err
}
selectedSet := make(map[int64]bool, len(records))
for _, record := range records {
selectedSet[record.ID] = true
}
reservedDetails := innerCodeReservedDetails(contextRecords, selectedSet)
snapshots, err := repository.ListInnerCodeSybSnapshots(db, orders)
if err != nil {
return nil, err
@@ -76,7 +89,7 @@ func PlanInnerCodeRecords(ctx context.Context, db *sql.DB, reader InnerCodeDetai
}
}
plans := planInnerCodeRows(records, stockIDsByOrder, detailsByID)
plans := planInnerCodeRowsWithReserved(records, stockIDsByOrder, detailsByID, reservedDetails)
for _, plan := range plans {
switch plan.Status {
case model.InnerCodeReady:
@@ -156,8 +169,42 @@ func uniqueInnerCodeStockIDs(records []model.InnerCodeRecord, byOrder map[string
return result
}
func innerCodeReservedDetails(records []model.InnerCodeRecord, selected map[int64]bool) map[string]map[int64]bool {
reserved := make(map[string]map[int64]bool)
for _, record := range records {
if selected[record.ID] || record.DetailID <= 0 || !innerCodeStatusReservesDetail(record.Status) {
continue
}
if reserved[record.OrderNumber] == nil {
reserved[record.OrderNumber] = make(map[int64]bool)
}
reserved[record.OrderNumber][record.DetailID] = true
}
return reserved
}
func innerCodeStatusReservesDetail(status model.InnerCodeStatus) bool {
switch status {
case model.InnerCodeReady, model.InnerCodeApplying, model.InnerCodeUpdated,
model.InnerCodeAlreadyFilled, model.InnerCodeNeedsCheck:
return true
default:
return false
}
}
func planInnerCodeRows(records []model.InnerCodeRecord, stockIDsByOrder map[string][]int64, detailsByID map[int64]syb.StockDetail) []model.InnerCodeRecord {
used := make(map[string]map[int64]bool)
return planInnerCodeRowsWithReserved(records, stockIDsByOrder, detailsByID, nil)
}
func planInnerCodeRowsWithReserved(records []model.InnerCodeRecord, stockIDsByOrder map[string][]int64, detailsByID map[int64]syb.StockDetail, reserved map[string]map[int64]bool) []model.InnerCodeRecord {
used := make(map[string]map[int64]bool, len(reserved))
for orderNumber, detailIDs := range reserved {
used[orderNumber] = make(map[int64]bool, len(detailIDs))
for detailID := range detailIDs {
used[orderNumber][detailID] = true
}
}
plans := make([]model.InnerCodeRecord, 0, len(records))
for _, record := range records {
plan := record
@@ -189,16 +236,22 @@ func planInnerCodeRows(records []model.InnerCodeRecord, stockIDsByOrder map[stri
used[record.OrderNumber] = make(map[int64]bool)
}
eligible := make([]syb.DetailItem, 0, len(stock.Details))
availableBeforeReservation := 0
for _, item := range stock.Details {
if used[record.OrderNumber][item.ID] {
continue
}
if innerCodeRawText(item.Raw["purchasePlatform"]) == "" && innerCodeRawText(item.Raw["purchaseCode"]) == "" {
availableBeforeReservation++
if used[record.OrderNumber][item.ID] {
continue
}
eligible = append(eligible, item)
}
}
if len(eligible) == 0 {
plans = append(plans, innerCodeSkippedPlan(plan, "没有采购平台和采购单号都为空的顺运宝商品"))
message := "没有采购平台和采购单号都为空的顺运宝商品"
if availableBeforeReservation > 0 {
message = "符合条件的顺运宝商品已被同订单其他记录占用"
}
plans = append(plans, innerCodeSkippedPlan(plan, message))
continue
}
matches := matchInnerCodeItems(record.SpecRaw, record.Stall, eligible)