移除快手小店以及 api

This commit is contained in:
yml2213
2026-07-09 21:03:39 +08:00
parent a075b8acf7
commit ffbc19a9db
38 changed files with 110 additions and 2724 deletions
@@ -1,13 +1,9 @@
import { getOrderById } from "../../../repositories/order-repo.js";
import { createTaskEvent } from "../../../repositories/task-event-repo.js";
import { updateTask } from "../../../repositories/task-repo.js";
import { createHttpError } from "../../../utils/http.js";
import { nowIso } from "../../../utils/time.js";
import { TASK_STATUS, normalizeTaskStatus, type TaskStatus } from "../../../domain/task-status.js";
import {
notifyKuaishouCloudAssetNotEnough,
notifyKuaishouCloudConsumeFailed,
} from "../../notification/domain-notifications.js";
import { notifyKuaishouCloudAssetNotEnough } from "../../notification/domain-notifications.js";
import {
buyCloudtentaclesSku,
getCloudtentaclesAsset,
@@ -16,13 +12,7 @@ import {
} from "../../platforms/cloudtentacles/catalog-service.js";
import { getCloudtentaclesKnapsack } from "../../platforms/cloudtentacles/knapsack-service.js";
import { backCloudtentaclesVirtualNumber } from "../../platforms/cloudtentacles/virtual-number-service.js";
import { consumeKuaishouEticket } from "../../platforms/kuaishou-eticket/consume-service.js";
import { isKuaishouEticketMockTicketCode } from "../../platforms/kuaishou-eticket/mock-ticket-service.js";
import { consumeKuaishouIndustryVouchersForTask } from "../../platforms/kuaishou-industry/voucher-service.js";
import {
getKuaishouEticketSourceConfig,
resolveKuaishouEticketShopConfig,
} from "../../platforms/kuaishou-eticket/source-config-service.js";
import {
isKuaishouCloudTask,
isIndustryEVoucherTask,
@@ -95,10 +85,19 @@ export async function dispatchKuaishouCloudFulfillmentTask(
);
}
const ticketCode = String(options.ticketCode || "").trim();
const persistedTicketCode = String(flow.ticket.code || "").trim();
if (!persistedTicketCode && !ticketCode) {
throw createHttpError("客户还没有提交有效核销码,暂时不能继续兑换", {
const voucherContext = isPlainObject(taskContext.kuaishouIndustryVoucher)
? taskContext.kuaishouIndustryVoucher
: {};
const industryVoucherCode = String(
voucherContext.voucherCode || voucherContext.eticketId || ""
).trim();
const hasIndustryVoucherForDispatch =
Boolean(industryVoucherCode) || isIndustryEVoucherTask(task);
const resolvedTicketCode = persistedTicketCode || industryVoucherCode;
if (!resolvedTicketCode && !hasIndustryVoucherForDispatch) {
throw createHttpError("旧快手小店核销流程已停用,请改用行业电子凭证处理", {
statusCode: 409,
errorCode: "kuaishou_cloud_missing_ticket_code",
});
@@ -173,9 +172,11 @@ export async function dispatchKuaishouCloudFulfillmentTask(
...syncedFlow,
ticket: {
...syncedFlow.ticket,
code: ticketCode || persistedTicketCode,
capturedAt: ticketCode ? now : syncedFlow.ticket.capturedAt,
capturedBy: ticketCode && actor ? actor : syncedFlow.ticket.capturedBy,
code: resolvedTicketCode,
capturedAt: resolvedTicketCode
? syncedFlow.ticket.capturedAt || now
: syncedFlow.ticket.capturedAt,
capturedBy: syncedFlow.ticket.capturedBy,
},
dispatch: {
...syncedFlow.dispatch,
@@ -222,7 +223,7 @@ export async function dispatchKuaishouCloudFulfillmentTask(
"kuaishou_cloud_dispatched",
{
source: String(options.source || "system").trim() || "system",
ticketCodeMasked: maskCode(ticketCode || persistedTicketCode),
ticketCodeMasked: maskCode(resolvedTicketCode),
skuId: syncedFlow.binding.skuId,
vnId: syncedFlow.binding.vnId,
vnPhoneMasked: maskPhone(syncedFlow.binding.vnPhone),
@@ -785,34 +786,25 @@ export async function returnKuaishouCloudFulfillmentTask(
id: flow.binding.vnId,
});
const order = await getOrderById(task.order_id);
const ticketCode = String(flow.ticket.code || "").trim();
const shopId = String(flow.consume.shopId || order?.shop_id || "").trim();
const shopName = String(
flow.consume.shopName || order?.shop_name || ""
).trim();
const mockTicketCode = isKuaishouEticketMockTicketCode(ticketCode);
const eticketSource = getKuaishouEticketSourceConfig();
const shopConfig = resolveKuaishouEticketShopConfig({
shopId,
shopName,
});
let consumeStatus = "pending";
let consumeErrorMessage = "";
let consumedAt = null;
let nextTaskStatus: TaskStatus = TASK_STATUS.COMPLETED;
let nextResultCode = "kuaishou_cloud_completed";
let nextResultMessage = "cloudtentacles 发货、退号并完成快手核销";
const consumeAlreadyCompleted = flow.consume.status === "success";
const hasIndustryVoucher = hasKuaishouIndustryVoucherContext(taskContext);
const isIndustryTask = isIndustryEVoucherTask(task);
const shouldConsumeIndustryVoucher = hasIndustryVoucher || isIndustryTask;
let nextResultMessage = shouldConsumeIndustryVoucher
? "cloudtentacles 发货、退号并完成电子凭证核销"
: "cloudtentacles 发货、退号并收口";
let industryVoucherContextPatch: JsonObject | null = null;
if (consumeAlreadyCompleted) {
consumeStatus = "success";
consumedAt = flow.consume.consumedAt || now;
} else if (hasIndustryVoucher || isIndustryTask) {
} else if (shouldConsumeIndustryVoucher) {
const industryResult = hasIndustryVoucher
? await consumeKuaishouIndustryVouchersForTask(task, {
source: String(options.source || "system_auto_finalize").trim() || "system_auto_finalize",
@@ -844,59 +836,20 @@ export async function returnKuaishouCloudFulfillmentTask(
consumeErrorMessage =
industryResult.failed[0]?.errorMessage || "电子凭证核销回调失败,请人工处理";
}
} else if (!order) {
consumeStatus = "failed";
consumeErrorMessage = "任务关联订单不存在,无法执行快手核销";
} else if (!ticketCode) {
consumeStatus = "failed";
consumeErrorMessage = "客户未提交有效核销码,无法执行快手核销";
} else if (mockTicketCode) {
const consumeResult = await consumeKuaishouEticket({
eTicketId: ticketCode,
oid: String(flow.ticket.oid || "").trim(),
formToken: String(flow.ticket.formToken || "").trim(),
});
consumeStatus = consumeResult.consumed ? "success" : "failed";
consumedAt = consumeResult.consumed ? now : null;
consumeErrorMessage = String(consumeResult.errorMessage || "").trim();
} else if (
!shopConfig ||
shopConfig.enabled === false ||
!String(shopConfig.cookie || "").trim()
) {
consumeStatus = "failed";
consumeErrorMessage = "订单对应快手小店缺少可用 Cookie,无法执行快手核销";
} else {
try {
const consumeResult = await consumeKuaishouEticket({
baseUrl: eticketSource.baseUrl,
cookie: shopConfig.cookie,
eTicketId: ticketCode,
oid: String(flow.ticket.oid || "").trim(),
formToken: String(flow.ticket.formToken || "").trim(),
});
if (consumeResult.consumed) {
consumeStatus = "success";
consumedAt = now;
} else {
consumeStatus = "failed";
consumeErrorMessage = String(
consumeResult.errorMessage || "快手核销失败"
).trim();
}
} catch (error) {
consumeStatus = "failed";
consumeErrorMessage =
error instanceof Error ? error.message : "快手核销失败";
}
consumeStatus = "skipped";
consumeErrorMessage = "";
}
if (consumeStatus !== "success") {
nextTaskStatus = TASK_STATUS.MANUAL_REVIEW;
nextResultCode = "kuaishou_cloud_consume_failed";
nextResultMessage =
consumeErrorMessage || "号码已退还,但快手核销未完成,请人工处理";
if (shouldConsumeIndustryVoucher) {
nextTaskStatus = TASK_STATUS.MANUAL_REVIEW;
nextResultCode = "kuaishou_cloud_consume_failed";
nextResultMessage =
consumeErrorMessage || "号码已退还,但电子凭证核销未完成,请人工处理";
} else {
nextResultCode = "kuaishou_cloud_completed_without_eticket_consume";
}
}
const nextContext = {
@@ -922,8 +875,8 @@ export async function returnKuaishouCloudFulfillmentTask(
consume: {
...flow.consume,
status: consumeStatus,
shopId: shopId || flow.consume.shopId,
shopName,
shopId: flow.consume.shopId,
shopName: flow.consume.shopName,
autoConsumeEnabled: flow.consume.autoConsumeEnabled === true,
consumedAt,
errorMessage: consumeErrorMessage,
@@ -936,7 +889,7 @@ export async function returnKuaishouCloudFulfillmentTask(
delivery_status: "delivered",
result_code: nextResultCode,
result_message: nextResultMessage,
redeemed_at: consumeStatus === "success" ? now : task.redeemed_at,
redeemed_at: consumeStatus === "failed" ? task.redeemed_at : now,
last_error: consumeErrorMessage,
context_json: JSON.stringify(nextContext),
updated_at: now,
@@ -954,36 +907,30 @@ export async function returnKuaishouCloudFulfillmentTask(
now
);
const consumeEventType = consumeAlreadyCompleted
? "kuaishou_cloud_consume_already_completed"
: consumeStatus === "success"
? "kuaishou_cloud_consumed"
: consumeStatus === "skipped"
? "kuaishou_cloud_consume_skipped"
: "kuaishou_cloud_consume_failed";
await createTaskEvent(
task.id,
consumeAlreadyCompleted
? "kuaishou_cloud_consume_already_completed"
: consumeStatus === "success"
? "kuaishou_cloud_consumed"
: "kuaishou_cloud_consume_failed",
consumeEventType,
{
source: String(options.source || "system").trim() || "system",
ticketCodeMasked: maskCode(ticketCode),
shopId,
shopName,
shopId: flow.consume.shopId,
shopName: flow.consume.shopName,
consumeStatus,
consumeMode: shouldConsumeIndustryVoucher ? "industry_voucher" : "legacy_writeoff_disabled",
errorMessage: consumeErrorMessage,
actor,
},
now
);
if (consumeStatus !== "success") {
await notifyKuaishouCloudConsumeFailed({
task: updatedTask,
order,
ticketCodeMasked: maskCode(ticketCode),
shopId,
shopName,
errorMessage: consumeErrorMessage,
});
}
return {
task: updatedTask,
flow: normalizeKuaishouCloudFlow(