Files
order_site/apps/frontend/src/services/admin/cost-center.ts
T

522 lines
15 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(params: { scope?: string } = {}) {
return apiGet<CostCenterOverview>('/api/v1/admin/cost-center/overview', {
scope: params.scope && params.scope !== 'all' ? params.scope : undefined,
})
}
export function fetchAdminCostCenterOptions() {
return apiGet<CostCenterOptions>('/api/v1/admin/cost-center/options')
}
export function previewAdminTemplateProductBootstrap(payload?: {
dateFrom?: string
dateTo?: string
}) {
return apiGet<TemplateProductBootstrapPreview>(
'/api/v1/admin/cost-center/template-bootstrap/preview',
payload,
{ timeout: 300_000 },
)
}
export function applyAdminTemplateProductBootstrap(payload?: {
dateFrom?: string
dateTo?: string
includeDisabledTemplates?: boolean
}) {
return apiPost<TemplateProductBootstrapResult>(
'/api/v1/admin/cost-center/template-bootstrap/apply',
{ repair: true, ...payload },
{ timeout: 300_000 },
)
}
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(payload?: {
dateFrom?: string
dateTo?: string
}) {
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', payload || {}, { timeout: 300_000 })
}
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 importAdminAffiliateDashPricesBaseline() {
return apiPost<{
total: number
createdProductCount: number
createdVersionCount: number
updatedVersionCount: number
skippedCount: number
}>('/api/v1/admin/cost-center/affiliate-products/price-baseline')
}
export function setAdminAffiliateProductPrice(
productId: number,
payload: {
amountFen: number
effectiveFrom?: string
retroactive?: boolean
changeReason?: string
},
) {
return apiPost<{
success: boolean
costVersionId: number
amountFen: number
effectiveFrom: string
message: string
}>(`/api/v1/admin/cost-center/affiliate-products/${productId}/price`, payload)
}
export function syncAdminAffiliateDashCostSnapshots() {
return apiPost<{
snapshotResult: {
range: { fromDate: string; toDate: string }
createdCount: number
exceptionCreatedCount: number
resolvedExceptionCount: number
}
factsResult: {
fromDate: string
toDate: string
deletedCount: number
insertedCount: number
batchCount: number
}
}>('/api/v1/admin/cost-center/affiliate-products/sync-snapshots', {}, { timeout: 300_000 })
}
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, { timeout: 300_000 })
}
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, { timeout: 300_000 })
}
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, { timeout: 300_000 })
}
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
orderId?: number
} = {},
) {
return apiGet<ManualFulfillmentPendingListResult>(
'/api/v1/admin/finance/manual-fulfillment/pending',
params,
)
}
export function confirmAdminManualFulfillment(payload: {
orderItemId: number
costFen?: number
payeeName?: string
note?: string
/** 管理员/财务代录:指定客服备用金账户 */
fundAccountId?: number
/** 管理员/财务代录:指定客服积分账户归属人 */
creditOwnerAdminUserId?: number
}) {
return apiPost<ManualFulfillmentConfirmResult>(
'/api/v1/admin/finance/manual-fulfillment/confirm',
payload,
)
}
export function setAdminProductPrice(
productId: number,
payload: {
amountFen: number
effectiveFrom?: string
retroactive?: boolean
changeReason?: string
syncOpenOrders?: boolean
},
) {
return apiPost<{
success: boolean
costVersionId: number
amountFen: number
effectiveFrom: string
syncedOrders?: {
candidateCount: number
updatedCount: number
updatedNormalCount: number
updatedPartialSharingCount: number
}
message?: string
}>(`/api/v1/admin/cost-center/products/${productId}/price`, payload)
}
export function syncAdminProductPrice(productId: number) {
return apiPost<{
success: boolean
type: string
synced?: {
candidateCount: number
updatedCount: number
updatedNormalCount: number
updatedPartialSharingCount: number
}
message: string
}>(`/api/v1/admin/cost-center/products/${productId}/sync-price`, {})
}