feat: 完成 SKU 图片选择及素材导入后端
This commit is contained in:
@@ -132,6 +132,14 @@ describe('商品编辑 M3.0–M3.3 HTTP 集成测试', () => {
|
||||
'DELETE FROM atlas.collection_asset_transfers WHERE workspace_id = $1',
|
||||
[workspaceId],
|
||||
);
|
||||
await tx.query(
|
||||
'DELETE FROM atlas.product_image_imports WHERE workspace_id = $1',
|
||||
[workspaceId],
|
||||
);
|
||||
await tx.query(
|
||||
'DELETE FROM atlas.media_upload_intents WHERE workspace_id = $1',
|
||||
[workspaceId],
|
||||
);
|
||||
await tx.query(
|
||||
'DELETE FROM atlas.product_variants WHERE workspace_id = $1',
|
||||
[workspaceId],
|
||||
@@ -1900,6 +1908,81 @@ describe('商品编辑 M3.0–M3.3 HTTP 集成测试', () => {
|
||||
after.body.data.variants[0].media.map((item: any) => item.asset_id),
|
||||
[asset],
|
||||
);
|
||||
const additionalAssets = await database.workspaceTransaction(workspaceId, async (tx) => {
|
||||
const ids: string[] = [];
|
||||
for (let index = 0; index < 29; index += 1) {
|
||||
const checksum = randomUUID().replaceAll('-', '').repeat(2);
|
||||
const objectKey = `m36/${randomUUID()}.png`;
|
||||
const created = await tx.query<{ id: string }>(
|
||||
`INSERT INTO atlas.media_assets
|
||||
(workspace_id, storage_provider, bucket, object_key, content_type,
|
||||
byte_size, checksum_sha256, width_px, height_px)
|
||||
VALUES (current_setting('app.workspace_id')::uuid, 'test', 'test', $1,
|
||||
'image/png', 1024, $2, 1200, 900) RETURNING id`,
|
||||
[objectKey, checksum],
|
||||
);
|
||||
const assetId = created.rows[0].id;
|
||||
ids.push(assetId);
|
||||
if (index === 0) {
|
||||
await tx.query(
|
||||
`INSERT INTO atlas.media_upload_intents
|
||||
(workspace_id, purpose, storage_provider, bucket, object_key,
|
||||
expected_content_type, expected_byte_size, expected_checksum_sha256,
|
||||
status, asset_id, expires_at, completed_at)
|
||||
VALUES (current_setting('app.workspace_id')::uuid, 'product_image',
|
||||
'test', 'test', $1, 'image/png', 1024, $2,
|
||||
'ready', $3, now() + interval '1 hour', now())`,
|
||||
[objectKey, checksum, assetId],
|
||||
);
|
||||
} else {
|
||||
await tx.query(
|
||||
`INSERT INTO atlas.product_image_imports
|
||||
(workspace_id, source_url, asset_id)
|
||||
VALUES (current_setting('app.workspace_id')::uuid, $1, $2)`,
|
||||
[`https://example.test/${randomUUID()}.png`, assetId],
|
||||
);
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
});
|
||||
const thirtyImages = {
|
||||
...payload,
|
||||
variants: payload.variants.map((item: any) => ({
|
||||
...item,
|
||||
media_asset_ids: item.id === variant.id ? [asset, ...additionalAssets] : [],
|
||||
})),
|
||||
};
|
||||
const expanded = await request(`/api/products/${first.productId}/editor-draft`, {
|
||||
method: 'PUT',
|
||||
headers: headers({
|
||||
'X-Atlas-Platform-Id': platformId,
|
||||
'Idempotency-Key': randomUUID(),
|
||||
'If-Match': `"${saved.body.data.product_revision}:${saved.body.data.profile_revision}"`,
|
||||
}),
|
||||
body: JSON.stringify(thirtyImages),
|
||||
});
|
||||
assert.equal(expanded.response.status, 200);
|
||||
const expandedSnapshot = await request(`/api/products/${first.productId}/editor`, {
|
||||
headers: headers({ 'X-Atlas-Platform-Id': platformId }),
|
||||
});
|
||||
assert.equal(expandedSnapshot.body.data.variants[0].media.length, 30);
|
||||
const uploaded = await request('/api/media-assets/product-uploads', {
|
||||
headers: headers(),
|
||||
});
|
||||
assert.equal(uploaded.response.status, 200);
|
||||
assert.ok(uploaded.body.data.some((item: any) => item.id === additionalAssets[0]));
|
||||
const imported = await request('/api/media-assets/product-imports', {
|
||||
headers: headers(),
|
||||
});
|
||||
assert.equal(imported.response.status, 200);
|
||||
assert.ok(imported.body.data.some((item: any) => item.id === additionalAssets[1]));
|
||||
const privateImport = await request('/api/media-assets/product-imports', {
|
||||
method: 'POST',
|
||||
headers: headers({ 'Idempotency-Key': randomUUID() }),
|
||||
body: JSON.stringify({ url: 'https://127.0.0.1/private.png' }),
|
||||
});
|
||||
assert.equal(privateImport.response.status, 422);
|
||||
assert.equal(privateImport.body.error.code, 'PRODUCT_IMAGE_IMPORT_INVALID');
|
||||
});
|
||||
|
||||
it('独立保存采集描述会持久化覆盖值并保持幂等', async () => {
|
||||
|
||||
Reference in New Issue
Block a user