Files
order_site/apps/frontend/src/services/admin/cost-center.ts
T
yml2213 a78cc1f984 feat(finance): P1 人工商品归一,按内部 SKU 生成 man 商品并回填
- 新服务 manual-product-normalization-service:skuNick → outSkuSn → sku_code 兜底,按内部 SKU 生成 man:<sku> 商品
- 订单项按 id 分批(2 万/批)回填,避免 15s 语句超时;同步补齐人工成本快照的商品维度
- 新增 POST /cost-center/manual-products/normalize(支持 dryRun/日期窗口),成本中心「标准商品」加「归一人工商品」按钮
- 每日 cost_finance_sync 接入最近 N 天的增量归一
- 渠道映射未归一队列增加人工单提示:人工单不能用平台 sku_code 建映射
- 文档同步:P1 标记完成,补充归一接口契约与销售事实重算结果
2026-10-24 16:54:55 +08:00

412 lines
12 KiB
TypeScript

import { apiDelete, apiGet, apiPatch, apiPost } from '@/lib/http'
import type {
ChannelMappingDiagnostics,
ChannelProductMapping,
ChannelProductMappingListResult,
CostCenterOptions,
CostCenterOverview,
CostException,
CostExceptionListResult,
CostExceptionSummary,
CostItem,
CostItemListResult,
CostPreview,
CostVersion,
CostVersionListResult,
ManualFulfillmentConfig,
ManualFulfillmentConfirmResult,
ManualFulfillmentPendingListResult,
ManualPlatformOption,
PlatformCreditAccountListResult,
PlatformCreditEntryListResult,
PlatformCreditOwnerListResult,
ManualRematchResult,
ManualSkuListResult,
ManualSkuOverview,
ManualSkuScanResult,
ProductCatalogItem,
ProductCatalogListResult,
TemplateProductBootstrapPreview,
TemplateProductBootstrapResult,
UnmappedMappingGroupListResult,
} from '@/types/admin'
export function fetchAdminCostCenterOverview() {
return apiGet<CostCenterOverview>('/api/v1/admin/cost-center/overview')
}
export function fetchAdminCostCenterOptions() {
return apiGet<CostCenterOptions>('/api/v1/admin/cost-center/options')
}
export function previewAdminTemplateProductBootstrap() {
return apiGet<TemplateProductBootstrapPreview>(
'/api/v1/admin/cost-center/template-bootstrap/preview',
)
}
export function applyAdminTemplateProductBootstrap() {
return apiPost<TemplateProductBootstrapResult>(
'/api/v1/admin/cost-center/template-bootstrap/apply',
{ repair: true },
)
}
export function syncAdminWorkOrderTemplateCostVersions() {
return apiPost<{
ruleCount: number
unitPriceRuleCount: number
activeVersionCount: number
createdCount: number
retiredCount: number
linkedSnapshotCount: number
}>('/api/v1/admin/cost-center/work-order-template-costs/sync')
}
export function backfillAdminWorkOrderProductSkus() {
return apiPost<{
updatedCount: number
skippedCount: number
remainingCount: number
workOrderItemCount: number
matchedCount: number
ruleMatchedCount: number
tailUpdatedCount: number
tailProductCount: number
tailMappingCount: number
factsRebuild: {
fromDate: string
toDate: string
deletedCount: number
insertedCount: number
batchCount: number
} | null
}>('/api/v1/admin/cost-center/work-order-products/backfill')
}
export function fetchAdminProductCatalog(params?: Record<string, unknown>) {
return apiGet<ProductCatalogListResult>('/api/v1/admin/cost-center/products', params)
}
export function createAdminProductCatalog(payload: Record<string, unknown>) {
return apiPost<{ product: ProductCatalogItem }>('/api/v1/admin/cost-center/products', payload)
}
export function syncAdminAffiliateDashProducts() {
return apiPost<{ createdCount: number; updatedCount: number; productCount: number }>(
'/api/v1/admin/cost-center/affiliate-products/sync',
)
}
export function backfillAdminAffiliateDashSkus() {
return apiPost<{
updatedCount: number
skippedCount: number
remainingCount: number
affiliateItemCount: number
matchedCount: number
factsRebuild: {
fromDate: string
toDate: string
deletedCount: number
insertedCount: number
batchCount: number
} | null
}>('/api/v1/admin/cost-center/affiliate-products/backfill')
}
export function updateAdminProductCatalog(productId: number, payload: Record<string, unknown>) {
return apiPatch<{ product: ProductCatalogItem }>(
`/api/v1/admin/cost-center/products/${productId}`,
payload,
)
}
export function deleteAdminProductCatalog(productId: number) {
return apiDelete<{ deleted: boolean; product: ProductCatalogItem }>(
`/api/v1/admin/cost-center/products/${productId}`,
)
}
export function fetchAdminChannelProductMappings(params?: Record<string, unknown>) {
return apiGet<ChannelProductMappingListResult>('/api/v1/admin/cost-center/mappings', params)
}
export function normalizeAdminManualProducts(payload: Record<string, unknown>) {
return apiPost<{
dryRun: boolean
range: { fromDate: string; toDate: string } | null
distinctSkuCount: number
pendingItemCount: number
createdProductCount: number
updatedItemCount: number
updatedSnapshotCount: number
resolvedExceptionCount: number
remainingItemCount: number
}>('/api/v1/admin/cost-center/manual-products/normalize', payload)
}
export function fetchAdminChannelMappingDiagnostics(params?: Record<string, unknown>) {
return apiGet<ChannelMappingDiagnostics>('/api/v1/admin/cost-center/mappings/diagnostics', params)
}
export function fetchAdminUnmappedMappingGroups(params?: Record<string, unknown>) {
return apiGet<UnmappedMappingGroupListResult>(
'/api/v1/admin/cost-center/mappings/unmapped',
params,
)
}
export function createAdminChannelProductMapping(payload: Record<string, unknown>) {
return apiPost<{ mapping: ChannelProductMapping }>('/api/v1/admin/cost-center/mappings', payload)
}
export function updateAdminChannelProductMapping(
mappingId: number,
payload: Record<string, unknown>,
) {
return apiPatch<{ mapping: ChannelProductMapping }>(
`/api/v1/admin/cost-center/mappings/${mappingId}`,
payload,
)
}
export function deleteAdminChannelProductMapping(mappingId: number) {
return apiDelete<{ deleted: boolean; mappingId: number }>(
`/api/v1/admin/cost-center/mappings/${mappingId}`,
)
}
export function backfillAdminProductMappings(payload: Record<string, unknown>) {
return apiPost<{
updatedCount: number
resolvedExceptionCount: number
limit: number
batches: number
remainingCount: number
}>('/api/v1/admin/cost-center/mappings/backfill', payload)
}
export function backfillAdminNormalizedQuantities(payload: Record<string, unknown>) {
return apiPost<{
updatedCount: number
limit: number
batches: number
remainingCount: number
}>('/api/v1/admin/cost-center/normalized-quantities/backfill', payload)
}
export function fetchAdminCostItems(params?: Record<string, unknown>) {
return apiGet<CostItemListResult>('/api/v1/admin/cost-center/cost-items', params)
}
export function createAdminCostItem(payload: Record<string, unknown>) {
return apiPost<{ costItem: CostItem }>('/api/v1/admin/cost-center/cost-items', payload)
}
export function updateAdminCostItem(costItemId: number, payload: Record<string, unknown>) {
return apiPatch<{ costItem: CostItem }>(
`/api/v1/admin/cost-center/cost-items/${costItemId}`,
payload,
)
}
export function deleteAdminCostItem(costItemId: number) {
return apiDelete<{ deleted: boolean; costItem: CostItem }>(
`/api/v1/admin/cost-center/cost-items/${costItemId}`,
)
}
export function fetchAdminCostVersions(params?: Record<string, unknown>) {
return apiGet<CostVersionListResult>('/api/v1/admin/cost-center/cost-versions', params)
}
export function createAdminCostVersion(payload: Record<string, unknown>) {
return apiPost<{ version: CostVersion }>('/api/v1/admin/cost-center/cost-versions', payload)
}
export function retireAdminCostVersion(versionId: number, payload: Record<string, unknown>) {
return apiPatch<{ version: CostVersion }>(
`/api/v1/admin/cost-center/cost-versions/${versionId}/retire`,
payload,
)
}
export function deleteAdminCostVersion(versionId: number) {
return apiDelete<{ deleted: boolean; version: CostVersion }>(
`/api/v1/admin/cost-center/cost-versions/${versionId}`,
)
}
export function fetchAdminCostExceptions(params?: Record<string, unknown>) {
return apiGet<CostExceptionListResult>('/api/v1/admin/cost-center/exceptions', params)
}
export function fetchAdminCostExceptionSummary(params?: Record<string, unknown>) {
return apiGet<CostExceptionSummary>('/api/v1/admin/cost-center/exceptions/summary', params)
}
export function resolveAdminCostException(exceptionId: number, payload: Record<string, unknown>) {
return apiPatch<{ exception: CostException }>(
`/api/v1/admin/cost-center/exceptions/${exceptionId}`,
payload,
)
}
export function previewAdminCost(payload: Record<string, unknown>) {
return apiPost<CostPreview>('/api/v1/admin/cost-center/preview', payload)
}
export function createAdminCostSnapshot(payload: Record<string, unknown>) {
return apiPost<{
preview: CostPreview
snapshots: Array<Record<string, unknown>>
createdCount: number
exceptionCreatedCount: number
}>('/api/v1/admin/cost-center/snapshots', payload)
}
/**
* 人工履约 SKU 配置:扫描 → 配置 → 重新匹配。
* 配置主键是内部 SKU(快手 skuNick / 拼多多 outSkuSn),同名 SKU 算同一商品。
*/
export function fetchAdminManualSkus(
params: {
page?: number
pageSize?: number
keyword?: string
status?: 'configured' | 'unconfigured' | ''
platformKey?: string
provider?: string
} = {},
) {
return apiGet<ManualSkuListResult>('/api/v1/admin/cost-center/manual-skus', params)
}
export function fetchAdminManualSkuOverview() {
return apiGet<ManualSkuOverview>('/api/v1/admin/cost-center/manual-skus/overview')
}
export function fetchAdminManualPlatforms() {
return apiGet<{ items: ManualPlatformOption[] }>('/api/v1/admin/cost-center/manual-platforms')
}
export function fetchAdminManualConfig(skuKey: string) {
return apiGet<ManualFulfillmentConfig | null>(
`/api/v1/admin/cost-center/manual-configs/${encodeURIComponent(skuKey)}`,
)
}
export function scanAdminManualSkus(payload: { fromDate: string; toDate: string }) {
return apiPost<ManualSkuScanResult>('/api/v1/admin/cost-center/manual-skus/scan', payload)
}
export function saveAdminManualConfig(payload: {
skuKey: string
platformKey: string
creditQuantity: number
canonicalProductId?: number | null
enabled?: boolean
note?: string
}) {
return apiPost<ManualFulfillmentConfig>('/api/v1/admin/cost-center/manual-configs', payload)
}
export function deleteAdminManualConfig(skuKey: string) {
return apiDelete<{ skuKey: string; deleted: number }>(
`/api/v1/admin/cost-center/manual-configs/${encodeURIComponent(skuKey)}`,
)
}
export function rematchAdminManualFulfillments(payload: { skuKey?: string } = {}) {
return apiPost<ManualRematchResult>('/api/v1/admin/cost-center/manual-configs/rematch', payload)
}
/**
* 客服平台积分钱包(南航 / 乐玩 / ROCK)。
* 三平台积分互不通用,每客服每平台一个账户;备用金现金走备用金页。
*/
export function fetchAdminPlatformCreditAccounts() {
return apiGet<PlatformCreditAccountListResult>(
'/api/v1/admin/cost-center/platform-credits/accounts',
)
}
export function fetchAdminPlatformCreditOwners() {
return apiGet<PlatformCreditOwnerListResult>('/api/v1/admin/cost-center/platform-credits/owners')
}
export function fetchAdminPlatformCreditEntries(
params: {
page?: number
pageSize?: number
platformKey?: string
entryType?: string
keyword?: string
} = {},
) {
return apiGet<PlatformCreditEntryListResult>(
'/api/v1/admin/cost-center/platform-credits/entries',
params,
)
}
export function grantAdminPlatformCredit(payload: {
ownerAdminUserId: number
platformKey: string
quantity: number
platformRef?: string
note?: string
}) {
return apiPost<{
accountId: number
platformKey: string
quantity: number
balanceAfter: number
amountFen: number
entryId: number
}>('/api/v1/admin/cost-center/platform-credits/grant', payload)
}
export function adjustAdminPlatformCredit(payload: {
ownerAdminUserId: number
platformKey: string
quantity: number
note?: string
}) {
return apiPost<{
accountId: number
platformKey: string
quantity: number
balanceAfter: number
amountFen: number
entryId: number
}>('/api/v1/admin/cost-center/platform-credits/adjust', payload)
}
/**
* 人工履约待办与确认履约。
* 客服点「确认履约」即扣额度 + 写成本快照;固定成本零输入,
* 成本不固定时只填金额。
*/
export function fetchAdminManualFulfillmentPending(
params: { page?: number; pageSize?: number; keyword?: string; status?: string } = {},
) {
return apiGet<ManualFulfillmentPendingListResult>(
'/api/v1/admin/finance/manual-fulfillment/pending',
params,
)
}
export function confirmAdminManualFulfillment(payload: {
orderItemId: number
costFen?: number
payeeName?: string
note?: string
}) {
return apiPost<ManualFulfillmentConfirmResult>(
'/api/v1/admin/finance/manual-fulfillment/confirm',
payload,
)
}