后端迁移更多仓储模块
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
import { query, withTransaction } from '../db/client.js'
|
||||
|
||||
type FulfillmentProfileRow = {
|
||||
id: number
|
||||
profile_key: string
|
||||
name: string
|
||||
executor_key: string
|
||||
requires_claim: boolean
|
||||
auto_dispatch: boolean
|
||||
inventory_strategy: string
|
||||
config_json: string | Record<string, unknown>
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
type FulfillmentProfileRequirementRow = {
|
||||
id: number
|
||||
profile_id: number
|
||||
role_key: string
|
||||
roleKey?: string
|
||||
credential_type: string
|
||||
credentialType?: string
|
||||
quantity_per_unit: number
|
||||
is_required: boolean
|
||||
config_json: string | Record<string, unknown>
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
type SkuFulfillmentBindingRow = {
|
||||
id: number
|
||||
sku_code: string
|
||||
provider: string
|
||||
platform: string
|
||||
shop_id: string
|
||||
profile_id: number
|
||||
enabled: boolean
|
||||
priority: number
|
||||
config_json: string | Record<string, unknown>
|
||||
created_at: string
|
||||
updated_at: string
|
||||
profile_key?: string
|
||||
name?: string
|
||||
profile_name?: string
|
||||
executor_key?: string
|
||||
requires_claim?: boolean
|
||||
auto_dispatch?: boolean
|
||||
inventory_strategy?: string
|
||||
profile_config_json?: string | Record<string, unknown>
|
||||
}
|
||||
|
||||
type FulfillmentProfileUpsertInput = {
|
||||
profileKey: string
|
||||
name: string
|
||||
executorKey: string
|
||||
requiresClaim?: boolean
|
||||
autoDispatch?: boolean
|
||||
inventoryStrategy?: string
|
||||
configJson?: string | Record<string, unknown>
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
type FulfillmentProfileRequirementInput = {
|
||||
roleKey: string
|
||||
credentialType: string
|
||||
quantityPerUnit?: number | string
|
||||
isRequired?: boolean
|
||||
configJson?: string | Record<string, unknown>
|
||||
}
|
||||
|
||||
type SkuFulfillmentBindingUpsertInput = {
|
||||
skuCode: string
|
||||
provider?: string
|
||||
platform?: string
|
||||
shopId?: string
|
||||
profileId: number | string
|
||||
enabled?: boolean
|
||||
priority?: number | string
|
||||
configJson?: string | Record<string, unknown>
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
type FulfillmentBindingResolveInput = {
|
||||
skuCode: string
|
||||
provider?: string
|
||||
platform?: string
|
||||
shopId?: string
|
||||
}
|
||||
|
||||
export async function getFulfillmentProfileByKey(profileKey: string): Promise<FulfillmentProfileRow | null> {
|
||||
const result = await query<FulfillmentProfileRow>(
|
||||
'SELECT * FROM fulfillment_profiles WHERE profile_key = $1 LIMIT 1',
|
||||
[String(profileKey || '').trim()],
|
||||
)
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
export async function upsertFulfillmentProfile(
|
||||
input: FulfillmentProfileUpsertInput,
|
||||
): Promise<FulfillmentProfileRow | null> {
|
||||
const result = await query<FulfillmentProfileRow>(
|
||||
`
|
||||
INSERT INTO fulfillment_profiles (
|
||||
profile_key,
|
||||
name,
|
||||
executor_key,
|
||||
requires_claim,
|
||||
auto_dispatch,
|
||||
inventory_strategy,
|
||||
config_json,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8, $9)
|
||||
ON CONFLICT (profile_key) DO UPDATE
|
||||
SET
|
||||
name = EXCLUDED.name,
|
||||
executor_key = EXCLUDED.executor_key,
|
||||
requires_claim = EXCLUDED.requires_claim,
|
||||
auto_dispatch = EXCLUDED.auto_dispatch,
|
||||
inventory_strategy = EXCLUDED.inventory_strategy,
|
||||
config_json = EXCLUDED.config_json,
|
||||
updated_at = EXCLUDED.updated_at
|
||||
RETURNING *
|
||||
`,
|
||||
[
|
||||
input.profileKey,
|
||||
input.name,
|
||||
input.executorKey,
|
||||
Boolean(input.requiresClaim),
|
||||
Boolean(input.autoDispatch),
|
||||
input.inventoryStrategy || 'static_pool',
|
||||
input.configJson || '{}',
|
||||
input.createdAt,
|
||||
input.updatedAt,
|
||||
],
|
||||
)
|
||||
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
export async function replaceFulfillmentProfileRequirements(
|
||||
profileId: number | string,
|
||||
requirements: FulfillmentProfileRequirementInput[] = [],
|
||||
timestamp: string,
|
||||
): Promise<void> {
|
||||
await withTransaction(async (client) => {
|
||||
await client.query(
|
||||
'DELETE FROM fulfillment_profile_requirements WHERE profile_id = $1',
|
||||
[Number(profileId)],
|
||||
)
|
||||
|
||||
for (const requirement of requirements) {
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO fulfillment_profile_requirements (
|
||||
profile_id,
|
||||
role_key,
|
||||
credential_type,
|
||||
quantity_per_unit,
|
||||
is_required,
|
||||
config_json,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7, $8)
|
||||
`,
|
||||
[
|
||||
Number(profileId),
|
||||
requirement.roleKey,
|
||||
requirement.credentialType,
|
||||
Number(requirement.quantityPerUnit || 1),
|
||||
requirement.isRequired !== false,
|
||||
requirement.configJson || '{}',
|
||||
timestamp,
|
||||
timestamp,
|
||||
],
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function listFulfillmentProfileRequirements(
|
||||
profileId: number | string,
|
||||
): Promise<FulfillmentProfileRequirementRow[]> {
|
||||
const result = await query<FulfillmentProfileRequirementRow>(
|
||||
`
|
||||
SELECT *
|
||||
FROM fulfillment_profile_requirements
|
||||
WHERE profile_id = $1
|
||||
ORDER BY id ASC
|
||||
`,
|
||||
[Number(profileId)],
|
||||
)
|
||||
|
||||
return result.rows
|
||||
}
|
||||
|
||||
export async function upsertSkuFulfillmentBinding(
|
||||
input: SkuFulfillmentBindingUpsertInput,
|
||||
): Promise<SkuFulfillmentBindingRow | null> {
|
||||
const existing = await query<SkuFulfillmentBindingRow>(
|
||||
`
|
||||
SELECT *
|
||||
FROM sku_fulfillment_bindings
|
||||
WHERE sku_code = $1 AND provider = $2 AND platform = $3 AND shop_id = $4
|
||||
LIMIT 1
|
||||
`,
|
||||
[input.skuCode, input.provider || '', input.platform || '', input.shopId || ''],
|
||||
)
|
||||
|
||||
if (!existing.rows[0]) {
|
||||
const inserted = await query<SkuFulfillmentBindingRow>(
|
||||
`
|
||||
INSERT INTO sku_fulfillment_bindings (
|
||||
sku_code,
|
||||
provider,
|
||||
platform,
|
||||
shop_id,
|
||||
profile_id,
|
||||
enabled,
|
||||
priority,
|
||||
config_json,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10)
|
||||
RETURNING *
|
||||
`,
|
||||
[
|
||||
input.skuCode,
|
||||
input.provider || '',
|
||||
input.platform || '',
|
||||
input.shopId || '',
|
||||
Number(input.profileId),
|
||||
input.enabled !== false,
|
||||
Number(input.priority || 100),
|
||||
input.configJson || '{}',
|
||||
input.createdAt,
|
||||
input.updatedAt,
|
||||
],
|
||||
)
|
||||
|
||||
return inserted.rows[0] || null
|
||||
}
|
||||
|
||||
const updated = await query<SkuFulfillmentBindingRow>(
|
||||
`
|
||||
UPDATE sku_fulfillment_bindings
|
||||
SET
|
||||
profile_id = $1,
|
||||
enabled = $2,
|
||||
priority = $3,
|
||||
config_json = $4::jsonb,
|
||||
updated_at = $5
|
||||
WHERE id = $6
|
||||
RETURNING *
|
||||
`,
|
||||
[
|
||||
Number(input.profileId),
|
||||
input.enabled !== false,
|
||||
Number(input.priority || 100),
|
||||
input.configJson || '{}',
|
||||
input.updatedAt,
|
||||
Number(existing.rows[0].id),
|
||||
],
|
||||
)
|
||||
|
||||
return updated.rows[0] || null
|
||||
}
|
||||
|
||||
export async function resolveFulfillmentBinding({
|
||||
skuCode,
|
||||
provider = '',
|
||||
platform = '',
|
||||
shopId = '',
|
||||
}: FulfillmentBindingResolveInput): Promise<SkuFulfillmentBindingRow | null> {
|
||||
const result = await query<SkuFulfillmentBindingRow>(
|
||||
`
|
||||
SELECT
|
||||
sfb.*,
|
||||
fp.profile_key,
|
||||
fp.name AS profile_name,
|
||||
fp.executor_key,
|
||||
fp.requires_claim,
|
||||
fp.auto_dispatch,
|
||||
fp.inventory_strategy,
|
||||
fp.config_json AS profile_config_json
|
||||
FROM sku_fulfillment_bindings sfb
|
||||
JOIN fulfillment_profiles fp ON fp.id = sfb.profile_id
|
||||
WHERE sfb.enabled = TRUE
|
||||
AND sfb.sku_code = $1
|
||||
AND (sfb.provider = '' OR sfb.provider = $2)
|
||||
AND (sfb.platform = '' OR sfb.platform = $3)
|
||||
AND (sfb.shop_id = '' OR sfb.shop_id = $4)
|
||||
ORDER BY
|
||||
CASE WHEN sfb.shop_id = '' THEN 1 ELSE 0 END,
|
||||
CASE WHEN sfb.platform = '' THEN 1 ELSE 0 END,
|
||||
CASE WHEN sfb.provider = '' THEN 1 ELSE 0 END,
|
||||
sfb.priority ASC,
|
||||
sfb.id ASC
|
||||
LIMIT 1
|
||||
`,
|
||||
[skuCode, provider, platform, shopId],
|
||||
)
|
||||
|
||||
return result.rows[0] || null
|
||||
}
|
||||
Reference in New Issue
Block a user