merge: 合并 main 并保留寄卖内部匹配与客户退款

This commit is contained in:
2026-11-05 18:02:47 +08:00
105 changed files with 7248 additions and 665 deletions
@@ -8,15 +8,16 @@
import { Router } from 'express'
import {
assignChannelByInternalSku,
assignChannelBySku,
assignChannelToOrderItems,
assignPendingChannelGroup,
deletePendingChannelGroup,
deleteChannelRule,
deleteChannelRules,
forceDeleteChannelRules,
listChannelRulesPage,
listPendingChannelGroups,
retryPendingCarrierGroup,
switchChannelForOrderItems,
unlockChannel,
upsertChannelRule,
@@ -37,6 +38,15 @@ import {
getFinancePipelineStatus,
isFinancePipelineName,
} from '../../services/scheduler/finance-pipeline-status.js'
import {
getVoucherConsumePolicy,
saveVoucherConsumePolicy,
} from '../../services/fulfillment/voucher-consume-policy-service.js'
import {
listVoucherConsumeJobs,
retryVoucherConsumeJob,
} from '../../services/fulfillment/voucher-consume-queue-service.js'
import { createHttpError } from '../../utils/http.js'
import { bodyOf } from './request-helpers.js'
import { createJsonHandler, requireAdminPermission, requireAdminRoles } from './session.js'
@@ -44,6 +54,78 @@ const router = Router()
router.use('/fulfillment', requireAdminRoles(['admin', 'operator', 'finance', 'support']))
router.get(
'/fulfillment/voucher-consume-policy',
requireAdminPermission('finance.view'),
createJsonHandler(() => getVoucherConsumePolicy(), {
successMessage: 'ok',
errorMessage: '读取核销策略失败',
scope: '[admin/fulfillment/voucher-consume-policy]',
}),
)
router.post(
'/fulfillment/voucher-consume-policy',
requireAdminPermission('finance.config'),
createJsonHandler((req) => saveVoucherConsumePolicy(bodyOf(req)), {
successMessage: '核销策略已保存',
errorMessage: '保存核销策略失败',
scope: '[admin/fulfillment/voucher-consume-policy]',
audit: (_req, data) => ({
action: 'fulfillment.save_voucher_consume_policy',
targetType: 'voucher_consume_policy',
targetId: 'default',
data: data as Record<string, unknown>,
}),
}),
)
router.get(
'/fulfillment/voucher-consume-jobs',
requireAdminPermission('finance.view'),
createJsonHandler(
(req) =>
listVoucherConsumeJobs({
status: String(req.query.status || ''),
page: Number(req.query.page),
pageSize: Number(req.query.pageSize),
}),
{
successMessage: 'ok',
errorMessage: '读取核销任务失败',
scope: '[admin/fulfillment/voucher-consume-jobs]',
},
),
)
router.post(
'/fulfillment/voucher-consume-jobs/:id/retry',
requireAdminPermission('finance.config'),
createJsonHandler(
async (req) => {
const job = await retryVoucherConsumeJob(req.params.id)
if (!job) {
throw createHttpError('该核销任务当前不可重试,或已有更新的任务在队列中', {
statusCode: 409,
errorCode: 'voucher_consume_job_not_retryable',
})
}
return job
},
{
successMessage: '核销任务已重新排队',
errorMessage: '重试核销任务失败',
scope: '[admin/fulfillment/voucher-consume-jobs/retry]',
audit: (req, data) => ({
action: 'fulfillment.retry_voucher_consume_job',
targetType: 'voucher_consume_job',
targetId: String(req.params.id || ''),
data: data as Record<string, unknown>,
}),
},
),
)
router.get(
'/fulfillment/pending',
requireAdminPermission('finance.view'),
@@ -68,17 +150,18 @@ router.post(
createJsonHandler(
(req) =>
deletePendingChannelGroup({
groupKey: String(bodyOf(req).groupKey || ''),
internalSku: String(bodyOf(req).internalSku || ''),
adminUserId: req.adminSession?.userId ?? null,
}),
{
successMessage: '待分类记录已删除',
errorMessage: '删除待分类记录失败',
successMessage: '待分类记录已忽略归档',
errorMessage: '归档待分类记录失败',
scope: '[admin/fulfillment/pending/delete]',
audit: (req, data) => ({
action: 'fulfillment.delete_pending_group',
targetType: 'internal_sku',
targetId: String(bodyOf(req).internalSku || ''),
action: 'fulfillment.archive_pending_group',
targetType: 'pending_group',
targetId: String(bodyOf(req).groupKey || bodyOf(req).internalSku || ''),
data: data as Record<string, unknown>,
}),
},
@@ -110,6 +193,28 @@ router.post(
),
)
router.post(
'/fulfillment/pending/retry-carriers',
requireAdminPermission('finance.config'),
createJsonHandler(
(req) =>
retryPendingCarrierGroup({
internalSku: String(bodyOf(req).internalSku || ''),
}),
{
successMessage: '履约载体重试完成',
errorMessage: '重试履约载体失败',
scope: '[admin/fulfillment/pending/retry-carriers]',
audit: (req, data) => ({
action: 'fulfillment.retry_pending_carriers',
targetType: 'internal_sku',
targetId: String(bodyOf(req).internalSku || ''),
data: data as Record<string, unknown>,
}),
},
),
)
router.get(
'/fulfillment/internal-sku-mappings',
requireAdminPermission('finance.view'),
@@ -203,13 +308,14 @@ router.post(
const adminUserId = req.adminSession?.userId ?? null
const note = String(body.note || '')
if (body.internalSku) {
return assignChannelByInternalSku({
internalSku: String(body.internalSku),
if (body.groupKey || body.internalSku) {
return assignPendingChannelGroup({
groupKey: String(body.groupKey || ''),
internalSku: String(body.internalSku || ''),
mappedInternalSku: String(body.mappedInternalSku || ''),
channel,
adminUserId,
note,
createRule: body.createRule !== false,
})
}
@@ -237,8 +343,14 @@ router.post(
scope: '[admin/fulfillment/assign]',
audit: (req, data) => ({
action: 'fulfillment.assign_channel',
targetType: 'order_item',
targetId: String(bodyOf(req).skuCode || bodyOf(req).orderItemId || ''),
targetType: bodyOf(req).groupKey ? 'pending_group' : 'order_item',
targetId: String(
bodyOf(req).groupKey ||
bodyOf(req).internalSku ||
bodyOf(req).skuCode ||
bodyOf(req).orderItemId ||
'',
),
data: { payload: bodyOf(req), result: data as Record<string, unknown> },
}),
},
@@ -32,6 +32,10 @@ import {
updateAdminWorkOrderPaymentAmount,
updateAdminWorkOrderSharing,
} from '../../../services/worker-platform/index.js'
import {
executeCustomerRefund,
previewCustomerRefund,
} from '../../../services/finance/customer-refund-service.js'
import { buildWorkOrderPaymentAmountAuditData } from '../../../services/worker-platform/work-order-payment-amount.js'
import {
createJsonHandler,
@@ -359,6 +363,40 @@ router.post(
),
)
router.post(
'/worker-platform/orders/:workOrderId/customer-refund/preview',
requireAdminPermission('worker_order.customer_refund'),
createJsonHandler((req) => previewCustomerRefund(String(req.params.workOrderId || '')), {
successMessage: '客户退款预检完成',
errorMessage: '客户退款预检失败',
scope: '[admin/worker-platform/orders/:workOrderId/customer-refund/preview]',
}),
)
router.post(
'/worker-platform/orders/:workOrderId/customer-refund',
requireAdminPermission('worker_order.customer_refund'),
createJsonHandler(
(req) =>
executeCustomerRefund(
String(req.params.workOrderId || ''),
req.body || {},
req.adminSession || null,
),
{
successMessage: '客户退款已完成,订单相关操作已关闭',
errorMessage: '客户退款失败',
scope: '[admin/worker-platform/orders/:workOrderId/customer-refund]',
audit: (req, data) => ({
action: 'customer_refund_completed',
targetType: 'work_order',
targetId: String(req.params.workOrderId || ''),
data: data && typeof data === 'object' ? (data as Record<string, unknown>) : {},
}),
},
),
)
router.delete(
'/worker-platform/orders/:workOrderId',
requireAdminPermission('worker_order.delete'),