feat: 统一顺运宝日期同步并记录历史 (#59)

This commit is contained in:
chengma
2026-08-09 18:22:58 +08:00
parent ea7932db63
commit 05a54b044d
18 changed files with 934 additions and 144 deletions
+107
View File
@@ -112,6 +112,113 @@ func SetSybLastSyncedAt(q Execer, at string) error {
return nil
}
// ---------- 同步记录 ----------
// CreateSybSyncRun 在真正启动后台同步前写入一条 running 记录。
func CreateSybSyncRun(q Execer, run model.SybSyncRun) error {
if run.RunID == "" || run.UserID == "" || run.DateFrom == "" || run.DateTo == "" || run.StartedAt == "" {
return fmt.Errorf("同步记录缺少编号、操作人、日期范围或开始时间")
}
_, err := q.Exec(`
INSERT INTO syb_sync_runs
(run_id, user_id, date_from, date_to, status, started_at)
VALUES (?, ?, ?, ?, 'running', ?)`,
run.RunID, run.UserID, run.DateFrom, run.DateTo, run.StartedAt)
if err != nil {
return fmt.Errorf("创建顺运宝同步记录失败: %w", err)
}
return nil
}
// FinishSybSyncRun 把 running 记录更新为最终状态。
func FinishSybSyncRun(q Execer, run model.SybSyncRun) error {
if run.Status != model.SybSyncSucceeded && run.Status != model.SybSyncFailed {
return fmt.Errorf("同步完成状态不合法: %s", run.Status)
}
result, err := q.Exec(`
UPDATE syb_sync_runs
SET status = ?, stock_count = ?, detail_count = ?, created_count = ?,
updated_count = ?, skipped_count = ?, error_message = ?,
cursor_advanced = ?, finished_at = ?
WHERE run_id = ? AND status = 'running'`,
run.Status, run.StockCount, run.DetailCount, run.Created, run.Updated, run.Skipped,
nullableText(run.ErrorMessage), run.CursorAdvanced, run.FinishedAt, run.RunID)
if err != nil {
return fmt.Errorf("完成顺运宝同步记录失败: %w", err)
}
affected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("确认顺运宝同步记录完成结果失败: %w", err)
}
if affected != 1 {
return fmt.Errorf("同步记录 %s 不存在或已经结束", run.RunID)
}
return nil
}
// InterruptRunningSybSyncRuns 在 Admin 启动时收敛上次进程遗留的 running 记录。
func InterruptRunningSybSyncRuns(q Execer, finishedAt string) (int, error) {
result, err := q.Exec(`
UPDATE syb_sync_runs
SET status = 'interrupted', finished_at = ?,
error_message = 'Admin 在同步完成前退出,请重新同步该日期范围'
WHERE status = 'running'`, finishedAt)
if err != nil {
return 0, fmt.Errorf("标记中断的顺运宝同步记录失败: %w", err)
}
affected, err := result.RowsAffected()
if err != nil {
return 0, fmt.Errorf("统计中断的顺运宝同步记录失败: %w", err)
}
return int(affected), nil
}
// ListSybSyncRuns 按开始时间倒序分页查询同步记录。
func ListSybSyncRuns(q Execer, limit, offset int) ([]model.SybSyncRun, error) {
rows, err := q.Query(`
SELECT r.run_id, r.user_id, u.username, r.date_from, r.date_to, r.status,
r.stock_count, r.detail_count, r.created_count, r.updated_count,
r.skipped_count, r.error_message, r.cursor_advanced,
r.started_at, r.finished_at
FROM syb_sync_runs r
JOIN users u ON u.user_id = r.user_id
ORDER BY r.started_at DESC, r.run_id DESC
LIMIT ? OFFSET ?`, limit, offset)
if err != nil {
return nil, fmt.Errorf("查询顺运宝同步记录失败: %w", err)
}
defer rows.Close()
var list []model.SybSyncRun
for rows.Next() {
var run model.SybSyncRun
var errorMessage, finishedAt sql.NullString
var cursorAdvanced int
if err := rows.Scan(&run.RunID, &run.UserID, &run.Username, &run.DateFrom, &run.DateTo,
&run.Status, &run.StockCount, &run.DetailCount, &run.Created, &run.Updated,
&run.Skipped, &errorMessage, &cursorAdvanced, &run.StartedAt, &finishedAt); err != nil {
return nil, fmt.Errorf("读取顺运宝同步记录失败: %w", err)
}
run.ErrorMessage = errorMessage.String
run.CursorAdvanced = cursorAdvanced == 1
run.FinishedAt = finishedAt.String
list = append(list, run)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("读取顺运宝同步记录失败: %w", err)
}
return list, nil
}
// CountSybSyncRuns 返回同步记录总数,供弹窗分页。
func CountSybSyncRuns(q Execer) (int, error) {
var count int
if err := q.QueryRow(`SELECT COUNT(*) FROM syb_sync_runs`).Scan(&count); err != nil {
return 0, fmt.Errorf("统计顺运宝同步记录失败: %w", err)
}
return count, nil
}
// ---------- 货运单明细 ----------
// UpsertSybOrder 写入或更新一条顺运宝货运单明细行。