feat: 增加档口入库码独立页面 (#233)
This commit is contained in:
@@ -15,6 +15,20 @@ type InnerCodeSybSnapshot struct {
|
||||
SybData string
|
||||
}
|
||||
|
||||
// InnerCodeListFilter 是独立页面可组合的查询条件。
|
||||
type InnerCodeListFilter struct {
|
||||
BusinessDate string
|
||||
Status string
|
||||
Keyword string
|
||||
}
|
||||
|
||||
// InnerCodeStatusCounts 是当前业务日期的底栏摘要。
|
||||
type InnerCodeStatusCounts struct {
|
||||
Total int
|
||||
Ready int
|
||||
NeedsCheck int
|
||||
}
|
||||
|
||||
// InnerCodeImportOutcome 说明幂等导入是新增还是更新。
|
||||
type InnerCodeImportOutcome string
|
||||
|
||||
@@ -169,6 +183,97 @@ func SaveInnerCodePlans(db *sql.DB, plans []model.InnerCodeRecord, plannedAt str
|
||||
return nil
|
||||
}
|
||||
|
||||
const innerCodeListColumns = `id,business_date,source_row,COALESCE(print_sequence,0),order_number,
|
||||
COALESCE(shop_name,''),stall,spec_raw,spec_key,inner_code,source_duplicate_count,
|
||||
COALESCE(stock_id,0),COALESCE(detail_id,0),COALESCE(syb_spec,''),COALESCE(syb_sku,''),
|
||||
COALESCE(syb_variation_sku,''),COALESCE(purchase_platform,''),COALESCE(purchase_code,''),
|
||||
COALESCE(remote_inner_code,''),status,COALESCE(result_message,''),created_by_user_id,
|
||||
COALESCE(applied_by_user_id,''),COALESCE(planned_at,''),COALESCE(apply_started_at,''),
|
||||
COALESCE(applied_at,''),created_at,updated_at`
|
||||
|
||||
func innerCodeFilterClause(filter InnerCodeListFilter) (string, []any) {
|
||||
clauses := []string{"business_date=?"}
|
||||
args := []any{filter.BusinessDate}
|
||||
if filter.Status != "" {
|
||||
clauses = append(clauses, "status=?")
|
||||
args = append(args, filter.Status)
|
||||
}
|
||||
if filter.Keyword != "" {
|
||||
like := "%" + escapeLike(filter.Keyword) + "%"
|
||||
clauses = append(clauses, `(order_number LIKE ? ESCAPE '!' OR stall LIKE ? ESCAPE '!'
|
||||
OR spec_raw LIKE ? ESCAPE '!' OR inner_code LIKE ? ESCAPE '!')`)
|
||||
args = append(args, like, like, like, like)
|
||||
}
|
||||
return " WHERE " + strings.Join(clauses, " AND "), args
|
||||
}
|
||||
|
||||
// ListInnerCodeRecords 分页读取独立页面记录。
|
||||
func ListInnerCodeRecords(q Execer, filter InnerCodeListFilter, limit, offset int) ([]model.InnerCodeRecord, error) {
|
||||
where, args := innerCodeFilterClause(filter)
|
||||
query := `SELECT ` + innerCodeListColumns + ` FROM syb_inner_code_records` + where +
|
||||
` ORDER BY source_row,id LIMIT ? OFFSET ?`
|
||||
args = append(args, limit, offset)
|
||||
rows, err := q.Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询档口入库码列表失败: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
result := make([]model.InnerCodeRecord, 0)
|
||||
for rows.Next() {
|
||||
row, err := scanInnerCodeRecord(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, row)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("遍历档口入库码列表失败: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CountInnerCodeRecords 统计与列表完全相同的筛选结果。
|
||||
func CountInnerCodeRecords(q Execer, filter InnerCodeListFilter) (int, error) {
|
||||
where, args := innerCodeFilterClause(filter)
|
||||
var count int
|
||||
if err := q.QueryRow(`SELECT COUNT(*) FROM syb_inner_code_records`+where, args...).Scan(&count); err != nil {
|
||||
return 0, fmt.Errorf("统计档口入库码列表失败: %w", err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// CountInnerCodeStatuses 统计当前业务日期总量、可回写和需核对数量。
|
||||
func CountInnerCodeStatuses(q Execer, businessDate string) (InnerCodeStatusCounts, error) {
|
||||
var result InnerCodeStatusCounts
|
||||
err := q.QueryRow(`SELECT COUNT(*),
|
||||
COALESCE(SUM(status='ready'),0),COALESCE(SUM(status='needs_check'),0)
|
||||
FROM syb_inner_code_records WHERE business_date=?`, businessDate).
|
||||
Scan(&result.Total, &result.Ready, &result.NeedsCheck)
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("统计档口入库码状态失败: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type innerCodeRowScanner interface {
|
||||
Scan(...any) error
|
||||
}
|
||||
|
||||
func scanInnerCodeRecord(scanner innerCodeRowScanner) (model.InnerCodeRecord, error) {
|
||||
var row model.InnerCodeRecord
|
||||
err := scanner.Scan(&row.ID, &row.BusinessDate, &row.SourceRow, &row.PrintSequence,
|
||||
&row.OrderNumber, &row.ShopName, &row.Stall, &row.SpecRaw, &row.SpecKey,
|
||||
&row.InnerCode, &row.SourceDuplicateCount, &row.StockID, &row.DetailID,
|
||||
&row.SybSpec, &row.SybSKU, &row.SybVariationSKU, &row.PurchasePlatform,
|
||||
&row.PurchaseCode, &row.RemoteInnerCode, &row.Status, &row.ResultMessage,
|
||||
&row.CreatedByUserID, &row.AppliedByUserID, &row.PlannedAt, &row.ApplyStartedAt,
|
||||
&row.AppliedAt, &row.CreatedAt, &row.UpdatedAt)
|
||||
if err != nil {
|
||||
return row, fmt.Errorf("读取档口入库码记录失败: %w", err)
|
||||
}
|
||||
return row, nil
|
||||
}
|
||||
|
||||
func nullablePositiveInt(value int) any {
|
||||
if value <= 0 {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user