按平台拆分后台平台配置服务

This commit is contained in:
yml
2026-05-04 16:07:23 +08:00
parent 60b84b23b4
commit 3a7c311c09
7 changed files with 658 additions and 598 deletions
@@ -0,0 +1,68 @@
// @ts-check
import { query } from '../../../db/client.js'
import {
getAgisoMessagingDefaults,
getAgisoShopConfigMap,
getAgisoShopsFilePath,
saveAgisoMessagingConfig,
} from '../../platforms/agiso/shop-config-service.js'
import { resolveDisplayShopName } from '../admin-read-shared-helpers.js'
import {
mapAdminAgisoMessagingDefaults,
mapAdminAgisoShopConfigItem,
} from './domain.js'
import { buildAdminAgisoMessagingSavePayload } from './writes.js'
/** @typedef {import('../../../types/admin-write-inputs.js').AdminAgisoShopConfigSaveInput} AdminAgisoShopConfigSaveInput */
export async function getAdminAgisoShopConfigs() {
const configMap = getAgisoShopConfigMap()
const defaults = getAgisoMessagingDefaults()
const rowsResult = await query(
`
SELECT
shop_id,
MAX(CASE WHEN trim(shop_name) != '' THEN shop_name ELSE '' END) AS detected_shop_name,
MAX(created_at) AS latest_seen_at,
COUNT(*)::int AS webhook_event_count
FROM webhook_events
WHERE provider = 'agiso' AND trim(shop_id) != ''
GROUP BY shop_id
ORDER BY latest_seen_at DESC, shop_id DESC
`,
)
const rows = rowsResult.rows
return {
filePath: getAgisoShopsFilePath(),
defaults: mapAdminAgisoMessagingDefaults(defaults),
shops: Object.entries(configMap)
.sort(([left], [right]) => left.localeCompare(right))
.map(([shopId, config]) => mapAdminAgisoShopConfigItem(shopId, config)),
observedShops: rows.map((row) => ({
shopId: String(row.shop_id || '').trim(),
detectedShopName: String(row.detected_shop_name || '').trim(),
displayShopName: resolveDisplayShopName('agiso', row.shop_id, row.detected_shop_name),
latestSeenAt: row.latest_seen_at || null,
webhookEventCount: Number(row.webhook_event_count || 0),
configured: Boolean(configMap[String(row.shop_id || '').trim()]),
})),
}
}
/** @param {AdminAgisoShopConfigSaveInput} [payload] */
export function updateAdminAgisoShopConfigs(payload = /** @type {AdminAgisoShopConfigSaveInput} */ ({})) {
const saved = saveAgisoMessagingConfig(buildAdminAgisoMessagingSavePayload(payload, {
currentDefaults: getAgisoMessagingDefaults(),
currentMap: getAgisoShopConfigMap(),
}))
return {
filePath: getAgisoShopsFilePath(),
defaults: mapAdminAgisoMessagingDefaults(saved.defaults),
shops: Object.entries(saved.shops)
.sort(([left], [right]) => left.localeCompare(right))
.map(([shopId, config]) => mapAdminAgisoShopConfigItem(shopId, config)),
}
}
@@ -0,0 +1,250 @@
// @ts-check
import {
getCloudtentaclesSourceConfig,
getCloudtentaclesSourcesFilePath,
saveCloudtentaclesSourceConfig,
} from '../../platforms/cloudtentacles/source-config-service.js'
import {
clearCloudtentaclesSessionState,
getCloudtentaclesSessionFilePath,
getCloudtentaclesSessionState,
saveCloudtentaclesSessionState,
} from '../../platforms/cloudtentacles/session-state-service.js'
import {
loginCloudtentaclesSession,
sendCloudtentaclesSmsCode,
validateCloudtentaclesSession,
} from '../../platforms/cloudtentacles/session-service.js'
import {
buyCloudtentaclesSku,
getCloudtentaclesAsset,
getCloudtentaclesCategories,
listCloudtentaclesSku,
useCloudtentaclesSku,
} from '../../platforms/cloudtentacles/catalog-service.js'
import { getCloudtentaclesKnapsack } from '../../platforms/cloudtentacles/knapsack-service.js'
import {
appointCloudtentaclesVirtualNumber,
backCloudtentaclesVirtualNumber,
fetchCloudtentaclesVirtualNumberCode,
generateCloudtentaclesLoginCode,
getCloudtentaclesBindUrl,
listCloudtentaclesVirtualNumbers,
verifyCloudtentaclesLoginCode,
} from '../../platforms/cloudtentacles/virtual-number-service.js'
import { runCloudtentaclesFullDebugFlow } from '../../platforms/cloudtentacles/debug-flow-service.js'
import { hasCloudtentaclesCredentialContextChanged, pickFirstNonEmpty } from './context.js'
import {
buildAdminCloudtentaclesLoginResult,
buildAdminCloudtentaclesPersistedSessionPayload,
buildAdminCloudtentaclesValidateResult,
resolveAdminCloudtentaclesCredentialPayload,
resolveAdminCloudtentaclesSessionPayload,
} from './cloudtentacles.js'
import { normalizeAdminCloudtentaclesSourceConfigPayload } from './writes.js'
import {
mapAdminCloudtentaclesSession,
mapAdminCloudtentaclesSourceConfig,
maskPhone,
} from './mappers.js'
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesSourceConfigInput} AdminCloudtentaclesSourceConfigInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesSendSmsCodeInput} AdminCloudtentaclesSendSmsCodeInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesTestLoginInput} AdminCloudtentaclesTestLoginInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesValidateSessionInput} AdminCloudtentaclesValidateSessionInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesCatalogQueryInput} AdminCloudtentaclesCatalogQueryInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesSkuBuyInput} AdminCloudtentaclesSkuBuyInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesSkuUseInput} AdminCloudtentaclesSkuUseInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesVirtualNumberInput} AdminCloudtentaclesVirtualNumberInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesFullFlowInput} AdminCloudtentaclesFullFlowInput */
export function getAdminCloudtentaclesSourceConfig() {
const config = getCloudtentaclesSourceConfig()
const session = getCloudtentaclesSessionState()
return {
filePath: getCloudtentaclesSourcesFilePath(),
sessionFilePath: getCloudtentaclesSessionFilePath(),
source: mapAdminCloudtentaclesSourceConfig(config),
session: mapAdminCloudtentaclesSession(session),
}
}
/** @param {AdminCloudtentaclesSourceConfigInput} [payload] */
export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {AdminCloudtentaclesSourceConfigInput} */ ({})) {
const current = getCloudtentaclesSourceConfig()
const saved = saveCloudtentaclesSourceConfig(normalizeAdminCloudtentaclesSourceConfigPayload(payload))
const shouldClearSession = hasCloudtentaclesCredentialContextChanged(current, saved)
const session = shouldClearSession ? clearCloudtentaclesSessionState() : getCloudtentaclesSessionState()
return {
filePath: getCloudtentaclesSourcesFilePath(),
sessionFilePath: getCloudtentaclesSessionFilePath(),
source: mapAdminCloudtentaclesSourceConfig(saved),
session: mapAdminCloudtentaclesSession(session),
}
}
/** @param {AdminCloudtentaclesSendSmsCodeInput} [payload] */
export async function sendAdminCloudtentaclesSmsCode(payload = /** @type {AdminCloudtentaclesSendSmsCodeInput} */ ({})) {
const result = await sendCloudtentaclesSmsCode(resolveAdminCloudtentaclesCredentialPayload(payload))
return {
...result,
phoneMasked: maskPhone(result.phone),
}
}
/** @param {AdminCloudtentaclesTestLoginInput} [payload] */
export async function testAdminCloudtentaclesLogin(payload = /** @type {AdminCloudtentaclesTestLoginInput} */ ({})) {
const savedSource = getCloudtentaclesSourceConfig()
const credentialContext = resolveAdminCloudtentaclesCredentialPayload(payload, { savedSource })
const session = await loginCloudtentaclesSession({
...credentialContext,
code: String(payload.code || '').trim(),
})
const savedSession = saveCloudtentaclesSessionState(buildAdminCloudtentaclesPersistedSessionPayload(session, {
deviceId: credentialContext.deviceId,
deviceType: credentialContext.deviceType,
}))
return buildAdminCloudtentaclesLoginResult(session, savedSession)
}
/** @param {AdminCloudtentaclesValidateSessionInput} [payload] */
export async function validateAdminCloudtentaclesSession(payload = /** @type {AdminCloudtentaclesValidateSessionInput} */ ({})) {
const savedSource = getCloudtentaclesSourceConfig()
const persistedSession = getCloudtentaclesSessionState()
const sessionContext = resolveAdminCloudtentaclesSessionPayload(payload, { savedSource, persistedSession })
const session = await validateCloudtentaclesSession(sessionContext)
const savedSession = saveCloudtentaclesSessionState(buildAdminCloudtentaclesPersistedSessionPayload(session, {
username: pickFirstNonEmpty([persistedSession.username, savedSource.username]),
phone: pickFirstNonEmpty([persistedSession.phone, savedSource.phone]),
deviceId: sessionContext.deviceId,
deviceType: sessionContext.deviceType,
}))
return buildAdminCloudtentaclesValidateResult(session, savedSession)
}
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
export async function getAdminCloudtentaclesAsset(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
return getCloudtentaclesAsset(resolveAdminCloudtentaclesSessionPayload(payload))
}
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
export async function getAdminCloudtentaclesCategories(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
return getCloudtentaclesCategories(resolveAdminCloudtentaclesSessionPayload(payload))
}
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
export async function getAdminCloudtentaclesSkuList(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
return listCloudtentaclesSku(resolveAdminCloudtentaclesSessionPayload(payload))
}
/** @param {AdminCloudtentaclesSkuBuyInput} [payload] */
export async function buyAdminCloudtentaclesSku(payload = /** @type {AdminCloudtentaclesSkuBuyInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return buyCloudtentaclesSku({
...context,
id: payload.id,
count: payload.count,
})
}
/** @param {AdminCloudtentaclesSkuUseInput} [payload] */
export async function useAdminCloudtentaclesSku(payload = /** @type {AdminCloudtentaclesSkuUseInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return useCloudtentaclesSku({
...context,
id: payload.id,
virtualNumberId: payload.virtualNumberId,
phone: payload.phone,
})
}
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
export async function getAdminCloudtentaclesKnapsack(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
return getCloudtentaclesKnapsack(resolveAdminCloudtentaclesSessionPayload(payload))
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function listAdminCloudtentaclesVirtualNumbers(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return listCloudtentaclesVirtualNumbers({
...context,
key: payload.key,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function appointAdminCloudtentaclesVirtualNumber(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return appointCloudtentaclesVirtualNumber({
...context,
key: payload.key,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function generateAdminCloudtentaclesLoginCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return generateCloudtentaclesLoginCode({
...context,
key: payload.key,
id: payload.id,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function fetchAdminCloudtentaclesVirtualNumberCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return fetchCloudtentaclesVirtualNumberCode({
...context,
key: payload.key,
phone: payload.phone,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function verifyAdminCloudtentaclesLoginCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return verifyCloudtentaclesLoginCode({
...context,
key: payload.key,
id: payload.id,
code: payload.code,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function getAdminCloudtentaclesBindUrl(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return getCloudtentaclesBindUrl({
...context,
key: payload.key,
id: payload.id,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function backAdminCloudtentaclesVirtualNumber(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return backCloudtentaclesVirtualNumber({
...context,
key: payload.key,
id: payload.id,
})
}
/** @param {AdminCloudtentaclesFullFlowInput} [payload] */
export async function runAdminCloudtentaclesFullFlow(payload = /** @type {AdminCloudtentaclesFullFlowInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return runCloudtentaclesFullDebugFlow({
...context,
skuId: payload.skuId,
skuCount: payload.skuCount,
vnKey: payload.vnKey,
})
}
@@ -0,0 +1,90 @@
// @ts-check
import { getAgisoShopConfig } from '../../platforms/agiso/shop-config-service.js'
import {
getOrderFulfillmentBindingConfigs,
getOrderFulfillmentBindingsFilePath,
saveOrderFulfillmentBindingConfigs,
} from '../../order/fulfillment-binding-config-service.js'
import { enrichAgisoXianyuTradeOrder } from '../../platforms/agiso/xianyu/order-detail-service.js'
import { getKuaishouEticketSourceConfig, resolveKuaishouEticketShopConfig } from '../../platforms/kuaishou-eticket/source-config-service.js'
import { syncConfiguredFulfillmentBindings } from '../../bootstrap/fulfillment-bootstrap-service.js'
import { getFulfillmentProfileByKey } from '../../../repositories/fulfillment-profile-repo.js'
import {
buildFulfillmentLookupResult,
normalizeFulfillmentLookupPayload,
resolveFulfillmentLookupDetail,
} from './fulfillment.js'
import { listAdminObservedProducts } from './observed-products.js'
import { validateAdminFulfillmentBindingConfigs } from './validation.js'
import { mapAdminFulfillmentBindingConfigItem } from './domain.js'
/** @typedef {import('../../../types/admin-write-inputs.js').AdminFulfillmentBindingConfigSaveInput} AdminFulfillmentBindingConfigSaveInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminFulfillmentBindingLookupInput} AdminFulfillmentBindingLookupInput */
export async function getAdminFulfillmentBindingConfigs() {
const bindings = getOrderFulfillmentBindingConfigs()
return {
filePath: getOrderFulfillmentBindingsFilePath(),
bindings: bindings.map(mapAdminFulfillmentBindingConfigItem),
observedProducts: await listAdminObservedProducts(bindings),
}
}
/** @param {AdminFulfillmentBindingLookupInput} [payload] */
export async function lookupAdminFulfillmentBindingOrder(payload = /** @type {AdminFulfillmentBindingLookupInput} */ ({})) {
const { provider, platform, shopId, platformOrderId } = normalizeFulfillmentLookupPayload(payload)
const detailResult = await enrichAgisoXianyuTradeOrder({
provider,
platform,
shopId,
shopName: '',
platformOrderId,
orderStatus: 'created',
payStatus: 'unpaid',
buyerId: '',
buyerName: '',
receiverContact: '',
totalAmount: 0,
currency: 'CNY',
paidAt: null,
rawPayload: {},
items: [],
}, {
requestId: `admin-fulfillment-lookup:${shopId}:${platformOrderId}`,
})
const { detail } = resolveFulfillmentLookupDetail(detailResult, platformOrderId)
const bindings = getOrderFulfillmentBindingConfigs()
return buildFulfillmentLookupResult({
provider,
platform,
shopId,
platformOrderId,
detail,
detailResult,
bindings,
fallbackShopName: getAgisoShopConfig(shopId)?.shopName,
})
}
/** @param {AdminFulfillmentBindingConfigSaveInput} [payload] */
export async function updateAdminFulfillmentBindingConfigs(
payload = /** @type {AdminFulfillmentBindingConfigSaveInput} */ ({}),
) {
const bindingsInput = Array.isArray(payload.bindings) ? payload.bindings : []
const normalizedBindings = await validateAdminFulfillmentBindingConfigs(bindingsInput, {
kuaishouEticketSource: getKuaishouEticketSourceConfig(),
resolveKuaishouEticketShopConfig,
getFulfillmentProfileByKey,
})
const saved = saveOrderFulfillmentBindingConfigs(normalizedBindings)
await syncConfiguredFulfillmentBindings()
return {
filePath: getOrderFulfillmentBindingsFilePath(),
bindings: saved.map(mapAdminFulfillmentBindingConfigItem),
}
}
@@ -0,0 +1,76 @@
// @ts-check
import { queryKhhaoOrderList } from '../../platforms/khhao/order-query-service.js'
import { syncKhhaoOrders } from '../../platforms/khhao/order-sync-service.js'
import { getKhhaoSourceConfig, getKhhaoSourcesFilePath, saveKhhaoSourceConfig } from '../../platforms/khhao/source-config-service.js'
import { ensureKhhaoSyncBaseline, getKhhaoSyncState, getKhhaoSyncStateFilePath } from '../../platforms/khhao/sync-state-service.js'
import { loginKhhaoSession } from '../../platforms/khhao/session-service.js'
import {
buildAdminKhhaoLoginPayload,
buildAdminKhhaoLoginResult,
buildAdminKhhaoOrderQueryResult,
buildAdminKhhaoSyncPayload,
resolveAdminKhhaoCredentialPayload,
} from './khhao.js'
import { normalizeAdminKhhaoSourceConfigPayload } from './writes.js'
import {
mapAdminKhhaoSourceConfig,
mapAdminKhhaoSyncState,
} from './mappers.js'
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoSourceConfigInput} AdminKhhaoSourceConfigInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoOrderQueryInput} AdminKhhaoOrderQueryInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoTestLoginInput} AdminKhhaoTestLoginInput */
export function getAdminKhhaoSourceConfig() {
const config = getKhhaoSourceConfig()
const syncState = getKhhaoSyncState()
return {
filePath: getKhhaoSourcesFilePath(),
stateFilePath: getKhhaoSyncStateFilePath(),
source: mapAdminKhhaoSourceConfig(config),
syncState: mapAdminKhhaoSyncState(syncState),
}
}
/** @param {AdminKhhaoSourceConfigInput} [payload] */
export function updateAdminKhhaoSourceConfig(payload = /** @type {AdminKhhaoSourceConfigInput} */ ({})) {
const saved = saveKhhaoSourceConfig(normalizeAdminKhhaoSourceConfigPayload(payload))
const syncState = saved.autoSync?.enabled ? ensureKhhaoSyncBaseline() : getKhhaoSyncState()
return {
filePath: getKhhaoSourcesFilePath(),
stateFilePath: getKhhaoSyncStateFilePath(),
source: mapAdminKhhaoSourceConfig(saved),
syncState: mapAdminKhhaoSyncState(syncState),
}
}
/** @param {AdminKhhaoTestLoginInput} [payload] */
export async function testAdminKhhaoLogin(payload = /** @type {AdminKhhaoTestLoginInput} */ ({})) {
const session = await loginKhhaoSession(buildAdminKhhaoLoginPayload(payload))
return buildAdminKhhaoLoginResult(session)
}
/** @param {AdminKhhaoOrderQueryInput} [payload] */
export async function queryAdminKhhaoOrders(payload = /** @type {AdminKhhaoOrderQueryInput} */ ({})) {
const credential = resolveAdminKhhaoCredentialPayload(payload)
const session = await loginKhhaoSession(buildAdminKhhaoLoginPayload(payload, {
requestIdScope: 'query-orders',
}))
const result = await queryKhhaoOrderList({
baseUrl: credential.baseUrl,
page: payload.page,
limit: payload.limit,
session,
})
return buildAdminKhhaoOrderQueryResult(session, result)
}
/** @param {AdminKhhaoOrderQueryInput} [payload] */
export async function syncAdminKhhaoOrders(payload = /** @type {AdminKhhaoOrderQueryInput} */ ({})) {
return syncKhhaoOrders(buildAdminKhhaoSyncPayload(payload))
}
@@ -0,0 +1,37 @@
// @ts-check
import {
getKuaishouCloudFulfillmentConfig,
getKuaishouCloudFulfillmentFilePath,
saveKuaishouCloudFulfillmentConfig,
} from '../../order/kuaishou-cloud-fulfillment-config-service.js'
import { syncConfiguredFulfillmentBindings } from '../../bootstrap/fulfillment-bootstrap-service.js'
import { mapAdminKuaishouCloudFulfillmentSource } from './mappers.js'
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouCloudFulfillmentConfigInput} AdminKuaishouCloudFulfillmentConfigInput */
export function getAdminKuaishouCloudFulfillmentConfig() {
const config = getKuaishouCloudFulfillmentConfig()
return {
filePath: getKuaishouCloudFulfillmentFilePath(),
source: mapAdminKuaishouCloudFulfillmentSource(config),
}
}
/** @param {AdminKuaishouCloudFulfillmentConfigInput} [payload] */
export async function updateAdminKuaishouCloudFulfillmentConfig(
payload = /** @type {AdminKuaishouCloudFulfillmentConfigInput} */ ({}),
) {
const saved = saveKuaishouCloudFulfillmentConfig({
enabled: payload.enabled !== false,
items: Array.isArray(payload.items) ? payload.items : [],
})
await syncConfiguredFulfillmentBindings()
return {
filePath: getKuaishouCloudFulfillmentFilePath(),
source: mapAdminKuaishouCloudFulfillmentSource(saved),
}
}
@@ -0,0 +1,89 @@
// @ts-check
import {
consumeKuaishouEticket,
queryKuaishouEticketConsumeDetail,
} from '../../platforms/kuaishou-eticket/consume-service.js'
import {
findKuaishouEticketShopConfig,
getFirstAvailableKuaishouEticketShop,
getKuaishouEticketSourceConfig,
getKuaishouEticketSourceFilePath,
listKuaishouEticketShopConfigs,
saveKuaishouEticketSourceConfig,
} from '../../platforms/kuaishou-eticket/source-config-service.js'
import { queryKuaishouEticketStableInfo } from '../../platforms/kuaishou-eticket/info-service.js'
import { resolveKuaishouEticketAdminContext } from './context.js'
import { mapAdminKuaishouEticketSourceConfig } from './mappers.js'
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouEticketSourceConfigInput} AdminKuaishouEticketSourceConfigInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouEticketShopInfoInput} AdminKuaishouEticketShopInfoInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouEticketDetailQueryInput} AdminKuaishouEticketDetailQueryInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouEticketConsumeInput} AdminKuaishouEticketConsumeInput */
function resolveAdminKuaishouEticketContext(payload = {}) {
return resolveKuaishouEticketAdminContext(payload, {
savedSource: getKuaishouEticketSourceConfig(),
findShopConfig: findKuaishouEticketShopConfig,
getFirstAvailableShop: getFirstAvailableKuaishouEticketShop,
})
}
export function getAdminKuaishouEticketSourceConfig() {
const config = getKuaishouEticketSourceConfig()
return {
filePath: getKuaishouEticketSourceFilePath(),
source: mapAdminKuaishouEticketSourceConfig(config, listKuaishouEticketShopConfigs(config)),
}
}
/** @param {AdminKuaishouEticketSourceConfigInput} [payload] */
export function updateAdminKuaishouEticketSourceConfig(payload = /** @type {AdminKuaishouEticketSourceConfigInput} */ ({})) {
const saved = saveKuaishouEticketSourceConfig({
enabled: payload.enabled !== false,
baseUrl: String(payload.baseUrl || '').trim() || 'https://s.kwaixiaodian.com',
shops: Array.isArray(payload.shops) ? payload.shops : [],
})
return {
filePath: getKuaishouEticketSourceFilePath(),
source: mapAdminKuaishouEticketSourceConfig(saved, listKuaishouEticketShopConfigs(saved)),
}
}
/** @param {AdminKuaishouEticketDetailQueryInput} [payload] */
export async function queryAdminKuaishouEticketDetail(payload = /** @type {AdminKuaishouEticketDetailQueryInput} */ ({})) {
const context = resolveAdminKuaishouEticketContext(payload)
return queryKuaishouEticketConsumeDetail({
baseUrl: context.baseUrl,
cookie: context.cookie,
eTicketId: String(payload.eTicketId || '').trim(),
})
}
/** @param {AdminKuaishouEticketShopInfoInput} [payload] */
export async function queryAdminKuaishouEticketShopInfo(payload = /** @type {AdminKuaishouEticketShopInfoInput} */ ({})) {
const context = resolveAdminKuaishouEticketContext(payload)
return queryKuaishouEticketStableInfo({
baseUrl: context.baseUrl,
cookie: context.cookie,
})
}
/** @param {AdminKuaishouEticketConsumeInput} [payload] */
export async function consumeAdminKuaishouEticket(payload = /** @type {AdminKuaishouEticketConsumeInput} */ ({})) {
const context = resolveAdminKuaishouEticketContext(payload)
return consumeKuaishouEticket({
baseUrl: context.baseUrl,
cookie: context.cookie,
eTicketId: String(payload.eTicketId || '').trim(),
oid: String(payload.oid || '').trim(),
formToken: String(payload.formToken || '').trim(),
num: payload.num,
storeId: String(payload.storeId || '').trim(),
})
}
@@ -1,603 +1,53 @@
// @ts-check
export {
getAdminAgisoShopConfigs,
updateAdminAgisoShopConfigs,
} from './agiso-service.js'
import { query } from '../../../db/client.js'
import {
getAgisoMessagingDefaults,
getAgisoShopConfig,
getAgisoShopConfigMap,
getAgisoShopsFilePath,
saveAgisoMessagingConfig,
} from '../../platforms/agiso/shop-config-service.js'
import { enrichAgisoXianyuTradeOrder } from '../../platforms/agiso/xianyu/order-detail-service.js'
import { queryKhhaoOrderList } from '../../platforms/khhao/order-query-service.js'
import { syncKhhaoOrders } from '../../platforms/khhao/order-sync-service.js'
import { getKhhaoSourceConfig, getKhhaoSourcesFilePath, saveKhhaoSourceConfig } from '../../platforms/khhao/source-config-service.js'
import { ensureKhhaoSyncBaseline, getKhhaoSyncState, getKhhaoSyncStateFilePath } from '../../platforms/khhao/sync-state-service.js'
import { loginKhhaoSession } from '../../platforms/khhao/session-service.js'
import {
consumeKuaishouEticket,
queryKuaishouEticketConsumeDetail,
} from '../../platforms/kuaishou-eticket/consume-service.js'
import {
findKuaishouEticketShopConfig,
getFirstAvailableKuaishouEticketShop,
getKuaishouEticketSourceConfig,
getKuaishouEticketSourceFilePath,
listKuaishouEticketShopConfigs,
resolveKuaishouEticketShopConfig,
saveKuaishouEticketSourceConfig,
} from '../../platforms/kuaishou-eticket/source-config-service.js'
import { queryKuaishouEticketStableInfo } from '../../platforms/kuaishou-eticket/info-service.js'
import {
getCloudtentaclesSourceConfig,
getCloudtentaclesSourcesFilePath,
saveCloudtentaclesSourceConfig,
} from '../../platforms/cloudtentacles/source-config-service.js'
import {
clearCloudtentaclesSessionState,
getCloudtentaclesSessionFilePath,
getCloudtentaclesSessionState,
saveCloudtentaclesSessionState,
} from '../../platforms/cloudtentacles/session-state-service.js'
import {
loginCloudtentaclesSession,
sendCloudtentaclesSmsCode,
validateCloudtentaclesSession,
} from '../../platforms/cloudtentacles/session-service.js'
import {
buyCloudtentaclesSku,
getCloudtentaclesAsset,
getCloudtentaclesCategories,
listCloudtentaclesSku,
useCloudtentaclesSku,
} from '../../platforms/cloudtentacles/catalog-service.js'
import { getCloudtentaclesKnapsack } from '../../platforms/cloudtentacles/knapsack-service.js'
import {
appointCloudtentaclesVirtualNumber,
backCloudtentaclesVirtualNumber,
fetchCloudtentaclesVirtualNumberCode,
generateCloudtentaclesLoginCode,
getCloudtentaclesBindUrl,
listCloudtentaclesVirtualNumbers,
verifyCloudtentaclesLoginCode,
} from '../../platforms/cloudtentacles/virtual-number-service.js'
import { runCloudtentaclesFullDebugFlow } from '../../platforms/cloudtentacles/debug-flow-service.js'
import {
getOrderFulfillmentBindingConfigs,
getOrderFulfillmentBindingsFilePath,
saveOrderFulfillmentBindingConfigs,
} from '../../order/fulfillment-binding-config-service.js'
import {
getKuaishouCloudFulfillmentConfig,
getKuaishouCloudFulfillmentFilePath,
saveKuaishouCloudFulfillmentConfig,
} from '../../order/kuaishou-cloud-fulfillment-config-service.js'
import { getFulfillmentProfileByKey } from '../../../repositories/fulfillment-profile-repo.js'
import { syncConfiguredFulfillmentBindings } from '../../bootstrap/fulfillment-bootstrap-service.js'
import { resolveDisplayShopName } from '../admin-read-shared-helpers.js'
import {
hasCloudtentaclesCredentialContextChanged,
isPlainObject,
pickFirstNonEmpty,
resolveKuaishouEticketAdminContext,
} from './context.js'
import {
buildFulfillmentLookupResult,
normalizeFulfillmentLookupPayload,
resolveFulfillmentLookupDetail,
} from './fulfillment.js'
import {
buildAdminKhhaoLoginPayload,
buildAdminKhhaoLoginResult,
buildAdminKhhaoOrderQueryResult,
buildAdminKhhaoSyncPayload,
resolveAdminKhhaoCredentialPayload,
} from './khhao.js'
import {
buildAdminCloudtentaclesLoginResult,
buildAdminCloudtentaclesPersistedSessionPayload,
buildAdminCloudtentaclesValidateResult,
resolveAdminCloudtentaclesCredentialPayload,
resolveAdminCloudtentaclesSessionPayload,
} from './cloudtentacles.js'
import { listAdminObservedProducts } from './observed-products.js'
import {
validateAdminFulfillmentBindingConfigs,
} from './validation.js'
import {
buildAdminAgisoMessagingSavePayload,
normalizeAdminCloudtentaclesSourceConfigPayload,
normalizeAdminKhhaoSourceConfigPayload,
} from './writes.js'
import {
mapAdminAgisoMessagingDefaults,
mapAdminAgisoShopConfigItem,
mapAdminFulfillmentBindingConfigItem,
} from './domain.js'
import {
mapAdminCloudtentaclesSession,
mapAdminCloudtentaclesSourceConfig,
mapAdminKhhaoSourceConfig,
mapAdminKhhaoSyncState,
mapAdminKuaishouCloudFulfillmentSource,
mapAdminKuaishouEticketSourceConfig,
maskPhone,
} from './mappers.js'
export {
getAdminKhhaoSourceConfig,
updateAdminKhhaoSourceConfig,
testAdminKhhaoLogin,
queryAdminKhhaoOrders,
syncAdminKhhaoOrders,
} from './khhao-service.js'
/** @typedef {import('../../../types/admin-write-inputs.js').AdminAgisoShopConfigSaveInput} AdminAgisoShopConfigSaveInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoSourceConfigInput} AdminKhhaoSourceConfigInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouEticketSourceConfigInput} AdminKuaishouEticketSourceConfigInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouEticketShopInfoInput} AdminKuaishouEticketShopInfoInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouEticketDetailQueryInput} AdminKuaishouEticketDetailQueryInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouEticketConsumeInput} AdminKuaishouEticketConsumeInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoOrderQueryInput} AdminKhhaoOrderQueryInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKhhaoTestLoginInput} AdminKhhaoTestLoginInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesSourceConfigInput} AdminCloudtentaclesSourceConfigInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminKuaishouCloudFulfillmentConfigInput} AdminKuaishouCloudFulfillmentConfigInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesSendSmsCodeInput} AdminCloudtentaclesSendSmsCodeInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesTestLoginInput} AdminCloudtentaclesTestLoginInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesValidateSessionInput} AdminCloudtentaclesValidateSessionInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesCatalogQueryInput} AdminCloudtentaclesCatalogQueryInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesSkuBuyInput} AdminCloudtentaclesSkuBuyInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesSkuUseInput} AdminCloudtentaclesSkuUseInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesVirtualNumberInput} AdminCloudtentaclesVirtualNumberInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminCloudtentaclesFullFlowInput} AdminCloudtentaclesFullFlowInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminFulfillmentBindingConfigSaveInput} AdminFulfillmentBindingConfigSaveInput */
/** @typedef {import('../../../types/admin-write-inputs.js').AdminFulfillmentBindingLookupInput} AdminFulfillmentBindingLookupInput */
export {
getAdminKuaishouEticketSourceConfig,
updateAdminKuaishouEticketSourceConfig,
queryAdminKuaishouEticketDetail,
queryAdminKuaishouEticketShopInfo,
consumeAdminKuaishouEticket,
} from './kuaishou-eticket-service.js'
export async function getAdminAgisoShopConfigs() {
const configMap = getAgisoShopConfigMap()
const defaults = getAgisoMessagingDefaults()
const rowsResult = await query(
`
SELECT
shop_id,
MAX(CASE WHEN trim(shop_name) != '' THEN shop_name ELSE '' END) AS detected_shop_name,
MAX(created_at) AS latest_seen_at,
COUNT(*)::int AS webhook_event_count
FROM webhook_events
WHERE provider = 'agiso' AND trim(shop_id) != ''
GROUP BY shop_id
ORDER BY latest_seen_at DESC, shop_id DESC
`,
)
const rows = rowsResult.rows
export {
getAdminCloudtentaclesSourceConfig,
updateAdminCloudtentaclesSourceConfig,
sendAdminCloudtentaclesSmsCode,
testAdminCloudtentaclesLogin,
validateAdminCloudtentaclesSession,
getAdminCloudtentaclesAsset,
getAdminCloudtentaclesCategories,
getAdminCloudtentaclesSkuList,
buyAdminCloudtentaclesSku,
useAdminCloudtentaclesSku,
getAdminCloudtentaclesKnapsack,
listAdminCloudtentaclesVirtualNumbers,
appointAdminCloudtentaclesVirtualNumber,
generateAdminCloudtentaclesLoginCode,
fetchAdminCloudtentaclesVirtualNumberCode,
verifyAdminCloudtentaclesLoginCode,
getAdminCloudtentaclesBindUrl,
backAdminCloudtentaclesVirtualNumber,
runAdminCloudtentaclesFullFlow,
} from './cloudtentacles-service.js'
return {
filePath: getAgisoShopsFilePath(),
defaults: mapAdminAgisoMessagingDefaults(defaults),
shops: Object.entries(configMap)
.sort(([left], [right]) => left.localeCompare(right))
.map(([shopId, config]) => mapAdminAgisoShopConfigItem(shopId, config)),
observedShops: rows.map((row) => ({
shopId: String(row.shop_id || '').trim(),
detectedShopName: String(row.detected_shop_name || '').trim(),
displayShopName: resolveDisplayShopName('agiso', row.shop_id, row.detected_shop_name),
latestSeenAt: row.latest_seen_at || null,
webhookEventCount: Number(row.webhook_event_count || 0),
configured: Boolean(configMap[String(row.shop_id || '').trim()]),
})),
}
}
export {
getAdminFulfillmentBindingConfigs,
lookupAdminFulfillmentBindingOrder,
updateAdminFulfillmentBindingConfigs,
} from './fulfillment-bindings-service.js'
/** @param {AdminAgisoShopConfigSaveInput} [payload] */
export function updateAdminAgisoShopConfigs(payload = /** @type {AdminAgisoShopConfigSaveInput} */ ({})) {
const saved = saveAgisoMessagingConfig(buildAdminAgisoMessagingSavePayload(payload, {
currentDefaults: getAgisoMessagingDefaults(),
currentMap: getAgisoShopConfigMap(),
}))
return {
filePath: getAgisoShopsFilePath(),
defaults: mapAdminAgisoMessagingDefaults(saved.defaults),
shops: Object.entries(saved.shops)
.sort(([left], [right]) => left.localeCompare(right))
.map(([shopId, config]) => mapAdminAgisoShopConfigItem(shopId, config)),
}
}
export function getAdminKhhaoSourceConfig() {
const config = getKhhaoSourceConfig()
const syncState = getKhhaoSyncState()
return {
filePath: getKhhaoSourcesFilePath(),
stateFilePath: getKhhaoSyncStateFilePath(),
source: mapAdminKhhaoSourceConfig(config),
syncState: mapAdminKhhaoSyncState(syncState),
}
}
export function getAdminKuaishouEticketSourceConfig() {
const config = getKuaishouEticketSourceConfig()
return {
filePath: getKuaishouEticketSourceFilePath(),
source: mapAdminKuaishouEticketSourceConfig(config, listKuaishouEticketShopConfigs(config)),
}
}
/** @param {AdminKuaishouEticketSourceConfigInput} [payload] */
export function updateAdminKuaishouEticketSourceConfig(payload = /** @type {AdminKuaishouEticketSourceConfigInput} */ ({})) {
const saved = saveKuaishouEticketSourceConfig({
enabled: payload.enabled !== false,
baseUrl: String(payload.baseUrl || '').trim() || 'https://s.kwaixiaodian.com',
shops: Array.isArray(payload.shops) ? payload.shops : [],
})
return {
filePath: getKuaishouEticketSourceFilePath(),
source: mapAdminKuaishouEticketSourceConfig(saved, listKuaishouEticketShopConfigs(saved)),
}
}
/** @param {AdminKhhaoSourceConfigInput} [payload] */
export function updateAdminKhhaoSourceConfig(payload = /** @type {AdminKhhaoSourceConfigInput} */ ({})) {
const saved = saveKhhaoSourceConfig(normalizeAdminKhhaoSourceConfigPayload(payload))
const syncState = saved.autoSync?.enabled ? ensureKhhaoSyncBaseline() : getKhhaoSyncState()
return {
filePath: getKhhaoSourcesFilePath(),
stateFilePath: getKhhaoSyncStateFilePath(),
source: mapAdminKhhaoSourceConfig(saved),
syncState: mapAdminKhhaoSyncState(syncState),
}
}
/** @param {AdminKhhaoTestLoginInput} [payload] */
export async function testAdminKhhaoLogin(payload = /** @type {AdminKhhaoTestLoginInput} */ ({})) {
const session = await loginKhhaoSession(buildAdminKhhaoLoginPayload(payload))
return buildAdminKhhaoLoginResult(session)
}
/** @param {AdminKhhaoOrderQueryInput} [payload] */
export async function queryAdminKhhaoOrders(payload = /** @type {AdminKhhaoOrderQueryInput} */ ({})) {
const credential = resolveAdminKhhaoCredentialPayload(payload)
const session = await loginKhhaoSession(buildAdminKhhaoLoginPayload(payload, {
requestIdScope: 'query-orders',
}))
const result = await queryKhhaoOrderList({
baseUrl: credential.baseUrl,
page: payload.page,
limit: payload.limit,
session,
})
return buildAdminKhhaoOrderQueryResult(session, result)
}
/** @param {AdminKhhaoOrderQueryInput} [payload] */
export async function syncAdminKhhaoOrders(payload = /** @type {AdminKhhaoOrderQueryInput} */ ({})) {
return syncKhhaoOrders(buildAdminKhhaoSyncPayload(payload))
}
/** @param {AdminKuaishouEticketDetailQueryInput} [payload] */
export async function queryAdminKuaishouEticketDetail(payload = /** @type {AdminKuaishouEticketDetailQueryInput} */ ({})) {
const context = resolveKuaishouEticketAdminContext(payload, {
savedSource: getKuaishouEticketSourceConfig(),
findShopConfig: findKuaishouEticketShopConfig,
getFirstAvailableShop: getFirstAvailableKuaishouEticketShop,
})
return queryKuaishouEticketConsumeDetail({
baseUrl: context.baseUrl,
cookie: context.cookie,
eTicketId: String(payload.eTicketId || '').trim(),
})
}
/** @param {AdminKuaishouEticketShopInfoInput} [payload] */
export async function queryAdminKuaishouEticketShopInfo(payload = /** @type {AdminKuaishouEticketShopInfoInput} */ ({})) {
const context = resolveKuaishouEticketAdminContext(payload, {
savedSource: getKuaishouEticketSourceConfig(),
findShopConfig: findKuaishouEticketShopConfig,
getFirstAvailableShop: getFirstAvailableKuaishouEticketShop,
})
return queryKuaishouEticketStableInfo({
baseUrl: context.baseUrl,
cookie: context.cookie,
})
}
/** @param {AdminKuaishouEticketConsumeInput} [payload] */
export async function consumeAdminKuaishouEticket(payload = /** @type {AdminKuaishouEticketConsumeInput} */ ({})) {
const context = resolveKuaishouEticketAdminContext(payload, {
savedSource: getKuaishouEticketSourceConfig(),
findShopConfig: findKuaishouEticketShopConfig,
getFirstAvailableShop: getFirstAvailableKuaishouEticketShop,
})
return consumeKuaishouEticket({
baseUrl: context.baseUrl,
cookie: context.cookie,
eTicketId: String(payload.eTicketId || '').trim(),
oid: String(payload.oid || '').trim(),
formToken: String(payload.formToken || '').trim(),
num: payload.num,
storeId: String(payload.storeId || '').trim(),
})
}
export function getAdminCloudtentaclesSourceConfig() {
const config = getCloudtentaclesSourceConfig()
const session = getCloudtentaclesSessionState()
return {
filePath: getCloudtentaclesSourcesFilePath(),
sessionFilePath: getCloudtentaclesSessionFilePath(),
source: mapAdminCloudtentaclesSourceConfig(config),
session: mapAdminCloudtentaclesSession(session),
}
}
/** @param {AdminCloudtentaclesSourceConfigInput} [payload] */
export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {AdminCloudtentaclesSourceConfigInput} */ ({})) {
const current = getCloudtentaclesSourceConfig()
const saved = saveCloudtentaclesSourceConfig(normalizeAdminCloudtentaclesSourceConfigPayload(payload))
const shouldClearSession = hasCloudtentaclesCredentialContextChanged(current, saved)
const session = shouldClearSession ? clearCloudtentaclesSessionState() : getCloudtentaclesSessionState()
return {
filePath: getCloudtentaclesSourcesFilePath(),
sessionFilePath: getCloudtentaclesSessionFilePath(),
source: mapAdminCloudtentaclesSourceConfig(saved),
session: mapAdminCloudtentaclesSession(session),
}
}
/** @param {AdminCloudtentaclesSendSmsCodeInput} [payload] */
export async function sendAdminCloudtentaclesSmsCode(payload = /** @type {AdminCloudtentaclesSendSmsCodeInput} */ ({})) {
const result = await sendCloudtentaclesSmsCode(resolveAdminCloudtentaclesCredentialPayload(payload))
return {
...result,
phoneMasked: maskPhone(result.phone),
}
}
/** @param {AdminCloudtentaclesTestLoginInput} [payload] */
export async function testAdminCloudtentaclesLogin(payload = /** @type {AdminCloudtentaclesTestLoginInput} */ ({})) {
const savedSource = getCloudtentaclesSourceConfig()
const credentialContext = resolveAdminCloudtentaclesCredentialPayload(payload, { savedSource })
const session = await loginCloudtentaclesSession({
...credentialContext,
code: String(payload.code || '').trim(),
})
const savedSession = saveCloudtentaclesSessionState(buildAdminCloudtentaclesPersistedSessionPayload(session, {
deviceId: credentialContext.deviceId,
deviceType: credentialContext.deviceType,
}))
return buildAdminCloudtentaclesLoginResult(session, savedSession)
}
/** @param {AdminCloudtentaclesValidateSessionInput} [payload] */
export async function validateAdminCloudtentaclesSession(payload = /** @type {AdminCloudtentaclesValidateSessionInput} */ ({})) {
const savedSource = getCloudtentaclesSourceConfig()
const persistedSession = getCloudtentaclesSessionState()
const sessionContext = resolveAdminCloudtentaclesSessionPayload(payload, { savedSource, persistedSession })
const session = await validateCloudtentaclesSession(sessionContext)
const savedSession = saveCloudtentaclesSessionState(buildAdminCloudtentaclesPersistedSessionPayload(session, {
username: pickFirstNonEmpty([persistedSession.username, savedSource.username]),
phone: pickFirstNonEmpty([persistedSession.phone, savedSource.phone]),
deviceId: sessionContext.deviceId,
deviceType: sessionContext.deviceType,
}))
return buildAdminCloudtentaclesValidateResult(session, savedSession)
}
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
export async function getAdminCloudtentaclesAsset(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
return getCloudtentaclesAsset(resolveAdminCloudtentaclesSessionPayload(payload))
}
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
export async function getAdminCloudtentaclesCategories(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
return getCloudtentaclesCategories(resolveAdminCloudtentaclesSessionPayload(payload))
}
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
export async function getAdminCloudtentaclesSkuList(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
return listCloudtentaclesSku(resolveAdminCloudtentaclesSessionPayload(payload))
}
/** @param {AdminCloudtentaclesSkuBuyInput} [payload] */
export async function buyAdminCloudtentaclesSku(payload = /** @type {AdminCloudtentaclesSkuBuyInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return buyCloudtentaclesSku({
...context,
id: payload.id,
count: payload.count,
})
}
/** @param {AdminCloudtentaclesSkuUseInput} [payload] */
export async function useAdminCloudtentaclesSku(payload = /** @type {AdminCloudtentaclesSkuUseInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return useCloudtentaclesSku({
...context,
id: payload.id,
virtualNumberId: payload.virtualNumberId,
phone: payload.phone,
})
}
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
export async function getAdminCloudtentaclesKnapsack(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
return getCloudtentaclesKnapsack(resolveAdminCloudtentaclesSessionPayload(payload))
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function listAdminCloudtentaclesVirtualNumbers(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return listCloudtentaclesVirtualNumbers({
...context,
key: payload.key,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function appointAdminCloudtentaclesVirtualNumber(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return appointCloudtentaclesVirtualNumber({
...context,
key: payload.key,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function generateAdminCloudtentaclesLoginCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return generateCloudtentaclesLoginCode({
...context,
key: payload.key,
id: payload.id,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function fetchAdminCloudtentaclesVirtualNumberCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return fetchCloudtentaclesVirtualNumberCode({
...context,
key: payload.key,
phone: payload.phone,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function verifyAdminCloudtentaclesLoginCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return verifyCloudtentaclesLoginCode({
...context,
key: payload.key,
id: payload.id,
code: payload.code,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function getAdminCloudtentaclesBindUrl(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return getCloudtentaclesBindUrl({
...context,
key: payload.key,
id: payload.id,
})
}
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
export async function backAdminCloudtentaclesVirtualNumber(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return backCloudtentaclesVirtualNumber({
...context,
key: payload.key,
id: payload.id,
})
}
/** @param {AdminCloudtentaclesFullFlowInput} [payload] */
export async function runAdminCloudtentaclesFullFlow(payload = /** @type {AdminCloudtentaclesFullFlowInput} */ ({})) {
const context = resolveAdminCloudtentaclesSessionPayload(payload)
return runCloudtentaclesFullDebugFlow({
...context,
skuId: payload.skuId,
skuCount: payload.skuCount,
vnKey: payload.vnKey,
})
}
export async function getAdminFulfillmentBindingConfigs() {
const bindings = getOrderFulfillmentBindingConfigs()
return {
filePath: getOrderFulfillmentBindingsFilePath(),
bindings: bindings.map(mapAdminFulfillmentBindingConfigItem),
observedProducts: await listAdminObservedProducts(bindings),
}
}
export function getAdminKuaishouCloudFulfillmentConfig() {
const config = getKuaishouCloudFulfillmentConfig()
return {
filePath: getKuaishouCloudFulfillmentFilePath(),
source: mapAdminKuaishouCloudFulfillmentSource(config),
}
}
/** @param {AdminKuaishouCloudFulfillmentConfigInput} [payload] */
export async function updateAdminKuaishouCloudFulfillmentConfig(
payload = /** @type {AdminKuaishouCloudFulfillmentConfigInput} */ ({}),
) {
const saved = saveKuaishouCloudFulfillmentConfig({
enabled: payload.enabled !== false,
items: Array.isArray(payload.items) ? payload.items : [],
})
await syncConfiguredFulfillmentBindings()
return {
filePath: getKuaishouCloudFulfillmentFilePath(),
source: mapAdminKuaishouCloudFulfillmentSource(saved),
}
}
/** @param {AdminFulfillmentBindingLookupInput} [payload] */
export async function lookupAdminFulfillmentBindingOrder(payload = /** @type {AdminFulfillmentBindingLookupInput} */ ({})) {
const { provider, platform, shopId, platformOrderId } = normalizeFulfillmentLookupPayload(payload)
const detailResult = await enrichAgisoXianyuTradeOrder({
provider,
platform,
shopId,
shopName: '',
platformOrderId,
orderStatus: 'created',
payStatus: 'unpaid',
buyerId: '',
buyerName: '',
receiverContact: '',
totalAmount: 0,
currency: 'CNY',
paidAt: null,
rawPayload: {},
items: [],
}, {
requestId: `admin-fulfillment-lookup:${shopId}:${platformOrderId}`,
})
const { detail } = resolveFulfillmentLookupDetail(detailResult, platformOrderId)
const bindings = getOrderFulfillmentBindingConfigs()
return buildFulfillmentLookupResult({
provider,
platform,
shopId,
platformOrderId,
detail,
detailResult,
bindings,
fallbackShopName: getAgisoShopConfig(shopId)?.shopName,
})
}
/** @param {AdminFulfillmentBindingConfigSaveInput} [payload] */
export async function updateAdminFulfillmentBindingConfigs(
payload = /** @type {AdminFulfillmentBindingConfigSaveInput} */ ({}),
) {
const bindingsInput = Array.isArray(payload.bindings) ? payload.bindings : []
const normalizedBindings = await validateAdminFulfillmentBindingConfigs(bindingsInput, {
kuaishouEticketSource: getKuaishouEticketSourceConfig(),
resolveKuaishouEticketShopConfig,
getFulfillmentProfileByKey,
})
const saved = saveOrderFulfillmentBindingConfigs(normalizedBindings)
await syncConfiguredFulfillmentBindings()
return {
filePath: getOrderFulfillmentBindingsFilePath(),
bindings: saved.map(mapAdminFulfillmentBindingConfigItem),
}
}
export {
getAdminKuaishouCloudFulfillmentConfig,
updateAdminKuaishouCloudFulfillmentConfig,
} from './kuaishou-cloud-fulfillment-service.js'