按平台拆分后台平台配置服务
This commit is contained in:
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user