feat(t237): import freight orders synchronously

This commit is contained in:
QiuSW
2026-07-29 12:11:56 +08:00
parent 4bce1e162c
commit 8d5b88f4a2
18 changed files with 653 additions and 97 deletions
@@ -13,6 +13,7 @@ import (
"time"
"unicode/utf8"
"cmroubao/backend-api/internal/domain"
"cmroubao/backend-api/internal/transport/authcommon"
"github.com/gin-gonic/gin"
@@ -319,6 +320,7 @@ func (h *Handler) ListFreight(ctx *gin.Context) {
CSRFToken: token,
},
Orders: orders,
Notice: freightNotice(ctx.Query("notice")),
})
}
@@ -443,6 +445,10 @@ func (h *Handler) CreateFreightImport(ctx *gin.Context) {
})
return
}
if mode == domain.FreightSyncOrderNumber && run.Status == "SUCCEEDED" {
ctx.Redirect(http.StatusSeeOther, "/freight?notice=import-succeeded")
return
}
ctx.Redirect(http.StatusSeeOther, "/freight/import?sync="+pathEscape(run.ID))
}
@@ -452,7 +458,7 @@ func (h *Handler) logFreightImportFailure(code string, status int) {
return
}
h.logEvent(
"freight_import_preflight_failed code=" + code +
"freight_import_failed code=" + code +
" status=" + strconv.Itoa(status),
)
}
@@ -463,12 +469,20 @@ func freightImportError(err error) (string, string, string) {
return "OCR_SERVICE_INVALID", "OCR 服务无效", "OCR 服务无效,请检查本机 OCR 服务和 CMROUBAO_OCR_API_URL 后重试。"
case errors.Is(err, ErrERPNotConfigured):
return "ERP_NOT_CONFIGURED", "ERP 凭证未配置", "ERP 账号或密码未配置,请检查 backend-api/.env 后重试。"
case errors.Is(err, ErrERPSessionNeeded):
return "ERP_SESSION_REQUIRED", "ERP 会话已失效", "ERP 会话已失效,请使用相同提交标识重试。"
case errors.Is(err, ErrERPFreightNotFound):
return "ERP_FREIGHT_NOT_FOUND", "未找到货运单", "ERP 中没有找到该完整单号,请检查后重试。"
case errors.Is(err, ErrERPLoginRejected):
return "ERP_LOGIN_REJECTED", "ERP 登录被拒绝", "请检查 ERP 账号密码及 OCR 识别结果后重试。"
case errors.Is(err, ErrERPProtocol):
return "ERP_RESPONSE_INVALID", "ERP 响应无效", "ERP 返回格式无法确认,请稍后重试。"
case errors.Is(err, ErrERPUnavailable):
return "ERP_UNAVAILABLE", "ERP 暂时不可用", "ERP 服务暂时不可用,请稍后使用相同提交标识重试。"
case errors.Is(err, ErrFreightSyncBusy):
return "FREIGHT_SYNC_BUSY", "ERP 正在同步", "已有完整单号正在同步,请等待完成后重试。"
case errors.Is(err, ErrFreightSyncTimeout):
return "FREIGHT_SYNC_TIMEOUT", "ERP 同步超时", "完整单号同步超过 55 秒,请使用相同提交标识重试。"
default:
return "", "", "同步任务创建失败,请稍后使用相同提交标识重试。"
}
@@ -646,6 +660,8 @@ func freightNotice(value string) string {
return "参考图已绑定,可以生成采购任务。"
case "task-conflict":
return "需求状态或来源已变化,当前不能生成任务。"
case "import-succeeded":
return "ERP 货运单已同步,货运信息和商品明细已更新。"
default:
return ""
}
@@ -1270,10 +1286,16 @@ func serviceErrorStatus(err error) int {
return http.StatusServiceUnavailable
case errors.Is(err, ErrERPNotConfigured), errors.Is(err, ErrERPLoginRejected):
return http.StatusUnprocessableEntity
case errors.Is(err, ErrERPFreightNotFound):
return http.StatusNotFound
case errors.Is(err, ErrERPProtocol):
return http.StatusBadGateway
case errors.Is(err, ErrERPUnavailable):
case errors.Is(err, ErrERPSessionNeeded), errors.Is(err, ErrERPUnavailable):
return http.StatusServiceUnavailable
case errors.Is(err, ErrFreightSyncBusy):
return http.StatusConflict
case errors.Is(err, ErrFreightSyncTimeout):
return http.StatusGatewayTimeout
case errors.Is(err, ErrConflict):
return http.StatusConflict
case errors.Is(err, context.DeadlineExceeded):
@@ -1336,6 +1358,7 @@ type pageView struct {
type freightPage struct {
Page pageView
Orders []FreightOrder
Notice string
}
type freightImportPage struct {