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 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 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 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 } type FulfillmentProfileUpsertInput = { profileKey: string name: string executorKey: string requiresClaim?: boolean autoDispatch?: boolean inventoryStrategy?: string configJson?: string | Record createdAt: string updatedAt: string } export type FulfillmentProfileRequirementInput = { roleKey: string credentialType: string quantityPerUnit?: number | string isRequired?: boolean configJson?: string | Record } type SkuFulfillmentBindingUpsertInput = { skuCode: string provider?: string platform?: string shopId?: string profileId: number | string enabled?: boolean priority?: number | string configJson?: string | Record createdAt: string updatedAt: string } type FulfillmentBindingResolveInput = { skuCode: string provider?: string platform?: string shopId?: string } export async function getFulfillmentProfileByKey(profileKey: string): Promise { const result = await query( '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 { const result = await query( ` 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 { 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 { const result = await query( ` 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 { const existing = await query( ` 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( ` 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( ` 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 { const result = await query( ` 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 }