feat: 支持勾选部分档口入库码匹配 (#235)
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user