领取/发货链路优化

This commit is contained in:
yml2213
2026-05-29 22:17:51 +08:00
parent 18123ffecb
commit e5ad6f4918
4 changed files with 317 additions and 101 deletions
@@ -2,8 +2,6 @@ import { createTaskEvent } from "../../../repositories/task-event-repo.js";
import { updateTask } from "../../../repositories/task-repo.js";
import { buildClaimUrl, createTaskClaimToken } from "../../claim/claim-service.js";
import {
buyCloudtentaclesSku,
getCloudtentaclesAsset,
listCloudtentaclesSku,
} from "../../platforms/cloudtentacles/catalog-service.js";
import { getCloudtentaclesKnapsack } from "../../platforms/cloudtentacles/knapsack-service.js";
@@ -14,7 +12,6 @@ import {
} from "../../platforms/cloudtentacles/virtual-number-service.js";
import { resolveCloudtentaclesConfig } from "../../platforms/cloudtentacles/helpers.js";
import {
notifyKuaishouCloudAssetNotEnough,
notifyKuaishouCloudBindUrlRefreshFailed,
} from "../../notification/domain-notifications.js";
import { createHttpError } from "../../../utils/http.js";
@@ -189,78 +186,28 @@ export async function prepareKuaishouCloudFulfillmentTask(
});
}
let usedKnapsack = deliveryPlan.items.every((item) => item.missingCount <= 0);
let purchaseTriggered = false;
let assetBefore = 0;
let assetAfter = 0;
if (!usedKnapsack) {
if (!flowWithResolvedBinding.purchase.autoBuyEnabled) {
throw createHttpError("背包中没有现成库存,且当前配置未开启自动购买", {
statusCode: 409,
errorCode: "kuaishou_cloud_auto_buy_disabled",
});
}
const asset = await getCloudtentaclesAsset(cloudContext);
const missingSku = deliveryPlan.items.find(
(item) => item.missingCount > 0 && !item.skuItem
);
if (missingSku) {
throw createHttpError(
`cloudtentacles 未找到 SKU ${missingSku.cloudSkuId}`,
{
statusCode: 404,
errorCode: "kuaishou_cloud_sku_not_found",
}
);
}
assetBefore = Number(asset.asset || 0) || 0;
const targetPrice = deliveryPlan.items.reduce(
(sum, item) =>
sum + Math.max(0, item.missingCount) * Number(item.skuItem?.price || 0),
0
);
const requiredAsset =
targetPrice + flowWithResolvedBinding.purchase.minAssetReserve;
if (assetBefore < requiredAsset) {
await notifyKuaishouCloudAssetNotEnough({
task,
flow: flowWithResolvedBinding,
assetBefore,
requiredAsset,
skuName: deliveryPlan.items
.filter((item) => item.missingCount > 0)
.map((item) => item.cloudSkuName || `SKU ${item.cloudSkuId}`)
.join("、"),
});
throw createHttpError(
`余额不足,当前 ${assetBefore},至少需要 ${requiredAsset}`,
{
statusCode: 409,
errorCode: "kuaishou_cloud_asset_not_enough",
}
);
}
for (const item of deliveryPlan.items) {
if (item.missingCount <= 0) {
continue;
}
await buyCloudtentaclesSku({
...cloudContext,
id: item.cloudSkuId,
count: item.missingCount,
});
}
purchaseTriggered = true;
const assetResult = await getCloudtentaclesAsset(cloudContext);
assetAfter = Number(assetResult.asset || 0) || 0;
const usedKnapsack = deliveryPlan.items.every((item) => item.missingCount <= 0);
if (!usedKnapsack && !flowWithResolvedBinding.purchase.autoBuyEnabled) {
throw createHttpError("背包中没有现成库存,且当前配置未开启自动购买", {
statusCode: 409,
errorCode: "kuaishou_cloud_auto_buy_disabled",
});
}
const missingSku = deliveryPlan.items.find(
(item) => item.missingCount > 0 && !item.skuItem
);
if (missingSku) {
throw createHttpError(`cloudtentacles 未找到 SKU ${missingSku.cloudSkuId}`, {
statusCode: 404,
errorCode: "kuaishou_cloud_sku_not_found",
});
}
const purchaseTriggered = false;
const assetBefore = 0;
const assetAfter = 0;
const preparedBinding = await prepareKuaishouCloudBindResourceWithFallback({
cloudContext,
vnKeyCandidates,
@@ -305,11 +252,9 @@ export async function prepareKuaishouCloudFulfillmentTask(
cloudSkuName: item.cloudSkuName,
requiredCount: item.quantity,
knapsackCount: item.knapsackCount,
purchasedCount: Math.max(0, item.missingCount),
purchasedCount: 0,
})),
purchaseAt: purchaseTriggered
? now
: flowWithResolvedBinding.purchase.purchaseAt,
purchaseAt: flowWithResolvedBinding.purchase.purchaseAt,
},
},
};
@@ -343,7 +288,7 @@ export async function prepareKuaishouCloudFulfillmentTask(
cloudSkuName: item.cloudSkuName,
quantity: item.quantity,
knapsackCount: item.knapsackCount,
purchasedCount: Math.max(0, item.missingCount),
purchasedCount: 0,
})),
resolvedByName: resolvedBinding.resolvedByName,
actor,