diff --git a/apps/backend/src/repositories/inventory-repo.js b/apps/backend/src/repositories/inventory-repo.ts similarity index 79% rename from apps/backend/src/repositories/inventory-repo.js rename to apps/backend/src/repositories/inventory-repo.ts index 6e00781f..8bd30167 100644 --- a/apps/backend/src/repositories/inventory-repo.js +++ b/apps/backend/src/repositories/inventory-repo.ts @@ -1,13 +1,21 @@ -// @ts-check - import { query, withTransaction } from '../db/client.js' +import type { + InventoryCreateItemInput, + InventoryListQueryInput, + InventorySkuSuggestionQueryInput, +} from '../types/repository-inputs.js' +import type { + InventoryItemRow, + InventoryListQueryResult, + InventorySkuSuggestionRow, +} from '../types/repository-rows.js' -/** @typedef {import('../types/repository-inputs.js').InventoryCreateItemInput} InventoryCreateItemInput */ -/** @typedef {import('../types/repository-inputs.js').InventoryListQueryInput} InventoryListQueryInput */ -/** @typedef {import('../types/repository-inputs.js').InventorySkuSuggestionQueryInput} InventorySkuSuggestionQueryInput */ -/** @typedef {import('../types/repository-rows.js').InventoryItemRow} InventoryItemRow */ -/** @typedef {import('../types/repository-rows.js').InventoryListQueryResult} InventoryListQueryResult */ -/** @typedef {import('../types/repository-rows.js').InventorySkuSuggestionRow} InventorySkuSuggestionRow */ +type InventoryGroupCodesInput = string | string[] | null | undefined + +type InventoryGroupListInput = { + keyword?: string + limit?: number | string +} const INVENTORY_ITEM_SELECT = ` SELECT @@ -36,18 +44,17 @@ const INVENTORY_ITEM_SELECT = ` LEFT JOIN fulfillment_tasks ft ON ft.id = tib.task_id ` -/** @returns {Promise} */ export async function findFirstAvailableInventoryItemBySkuCode( - skuCode, + skuCode: string, credentialType = 'tencent_code', - inventoryGroupCodes = null, -) { + inventoryGroupCodes: InventoryGroupCodesInput = null, +): Promise { const normalizedInventoryGroupCodes = normalizeInventoryGroupCodes(inventoryGroupCodes) if (normalizedInventoryGroupCodes && normalizedInventoryGroupCodes.length === 0) { return null } - const params = [skuCode, credentialType] + const params: unknown[] = [skuCode, credentialType] const filters = [ 'ii.sku_code = $1', 'ii.credential_type = $2', @@ -59,7 +66,7 @@ export async function findFirstAvailableInventoryItemBySkuCode( filters.push(`ii.inventory_group_code = ANY($${params.length}::text[])`) } - const result = await query( + const result = await query( `${INVENTORY_ITEM_SELECT} WHERE ${filters.join(' AND ')} ORDER BY ii.id ASC @@ -67,11 +74,15 @@ export async function findFirstAvailableInventoryItemBySkuCode( params, ) - return /** @type {InventoryItemRow | null} */ (result.rows[0] || null) + return result.rows[0] || null } -/** @returns {Promise} */ -export async function assignReservedInventoryItem(inventoryItemId, taskId, updatedAt, roleKey = 'primary_code') { +export async function assignReservedInventoryItem( + inventoryItemId: number | string, + taskId: number | string, + updatedAt: string, + roleKey = 'primary_code', +): Promise { return withTransaction(async (client) => { const inventoryResult = await client.query( ` @@ -109,20 +120,21 @@ export async function assignReservedInventoryItem(inventoryItemId, taskId, updat }) } -/** @returns {Promise} */ -export async function getInventoryItemById(inventoryItemId) { - const result = await query( +export async function getInventoryItemById(inventoryItemId: number | string): Promise { + const result = await query( `${INVENTORY_ITEM_SELECT} WHERE ii.id = $1 LIMIT 1`, [Number(inventoryItemId)], ) - return /** @type {InventoryItemRow | null} */ (result.rows[0] || null) + return result.rows[0] || null } -/** @returns {Promise} */ -export async function markInventoryItemDelivered(inventoryItemId, deliveredAt) { +export async function markInventoryItemDelivered( + inventoryItemId: number | string, + deliveredAt: string, +): Promise { return withTransaction(async (client) => { await client.query( ` @@ -146,8 +158,11 @@ export async function markInventoryItemDelivered(inventoryItemId, deliveredAt) { }) } -/** @returns {Promise} */ -export async function markInventoryItemConsumed(inventoryItemId, reason, consumedAt) { +export async function markInventoryItemConsumed( + inventoryItemId: number | string, + reason: string, + consumedAt: string, +): Promise { return withTransaction(async (client) => { await client.query( ` @@ -175,8 +190,6 @@ export async function markInventoryItemConsumed(inventoryItemId, reason, consume }) } -/** @returns {Promise} */ -/** @param {InventoryListQueryInput} [queryInput] */ export async function listInventoryItems({ page = 1, pageSize = 20, @@ -186,7 +199,7 @@ export async function listInventoryItems({ batchNo = '', inventoryGroupCode = '', allowedInventoryGroupCodes = null, -} = /** @type {InventoryListQueryInput} */ ({})) { +}: InventoryListQueryInput = {}): Promise { const normalizedAllowedInventoryGroupCodes = normalizeInventoryGroupCodes(allowedInventoryGroupCodes) if (normalizedAllowedInventoryGroupCodes && normalizedAllowedInventoryGroupCodes.length === 0) { return { @@ -196,8 +209,8 @@ export async function listInventoryItems({ } const offset = (page - 1) * pageSize - const filters = [] - const params = [] + const filters: string[] = [] + const params: unknown[] = [] if (skuCode) { params.push(skuCode) @@ -230,14 +243,14 @@ export async function listInventoryItems({ } const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '' - const totalResult = await query( + const totalResult = await query<{ [column: string]: unknown, total: number }>( `SELECT COUNT(*)::int AS total FROM inventory_items ii ${whereClause}`, params, ) params.push(pageSize) params.push(offset) - const itemsResult = await query( + const itemsResult = await query( `${INVENTORY_ITEM_SELECT} ${whereClause} ORDER BY ii.id DESC @@ -246,27 +259,25 @@ export async function listInventoryItems({ ) return { - items: /** @type {InventoryItemRow[]} */ (itemsResult.rows), + items: itemsResult.rows, total: Number(totalResult.rows[0]?.total || 0), } } -/** @returns {Promise} */ -/** @param {InventorySkuSuggestionQueryInput} [queryInput] */ export async function listInventorySkuSuggestions({ credentialType = '', keyword = '', limit = 50, inventoryGroupCode = '', allowedInventoryGroupCodes = null, -} = /** @type {InventorySkuSuggestionQueryInput} */ ({})) { +}: InventorySkuSuggestionQueryInput = {}): Promise { const normalizedAllowedInventoryGroupCodes = normalizeInventoryGroupCodes(allowedInventoryGroupCodes) if (normalizedAllowedInventoryGroupCodes && normalizedAllowedInventoryGroupCodes.length === 0) { return [] } - const filters = [] - const params = [] + const filters: string[] = [] + const params: unknown[] = [] if (credentialType) { params.push(credentialType) @@ -294,7 +305,7 @@ export async function listInventorySkuSuggestions({ params.push(normalizedLimit) const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '' - const result = await query( + const result = await query( ` SELECT sku_code, @@ -317,18 +328,17 @@ export async function listInventorySkuSuggestions({ params, ) - return /** @type {InventorySkuSuggestionRow[]} */ (result.rows) + return result.rows } -/** @param {InventoryCreateItemInput[]} rows */ -export async function createInventoryItems(rows) { +export async function createInventoryItems(rows: InventoryCreateItemInput[]): Promise { let created = 0 for (const row of rows) { const payloadJson = JSON.stringify(row.payload || { code: row.displayValue }) const displayValue = String(row.displayValue || '').trim() const inventoryGroupCode = String(row.inventoryGroupCode || '').trim() - const result = await query( + const result = await query<{ [column: string]: unknown, id: number }>( ` INSERT INTO inventory_items ( batch_no, @@ -370,8 +380,8 @@ export async function createInventoryItems(rows) { export async function listInventoryGroupCodes({ keyword = '', limit = 100, -} = {}) { - const params = [] +}: InventoryGroupListInput = {}): Promise { + const params: unknown[] = [] const filters = [`inventory_group_code <> ''`] if (keyword) { @@ -384,7 +394,7 @@ export async function listInventoryGroupCodes({ : 100 params.push(normalizedLimit) - const result = await query( + const result = await query<{ [column: string]: unknown, inventory_group_code: string }>( ` SELECT inventory_group_code FROM inventory_items @@ -399,7 +409,7 @@ export async function listInventoryGroupCodes({ return result.rows.map((row) => String(row.inventory_group_code || '').trim()).filter(Boolean) } -function normalizeInventoryGroupCodes(inventoryGroupCodes) { +function normalizeInventoryGroupCodes(inventoryGroupCodes: InventoryGroupCodesInput): string[] | null { if (inventoryGroupCodes == null) { return null } @@ -409,8 +419,10 @@ function normalizeInventoryGroupCodes(inventoryGroupCodes) { .filter(Boolean))) } -/** @returns {Promise} */ -export async function releaseReservedInventoryItem(inventoryItemId, updatedAt) { +export async function releaseReservedInventoryItem( + inventoryItemId: number | string, + updatedAt: string, +): Promise { return withTransaction(async (client) => { await client.query( ` @@ -434,8 +446,12 @@ export async function releaseReservedInventoryItem(inventoryItemId, updatedAt) { }) } -export async function invalidateInventoryItem(inventoryItemId, invalidReason, updatedAt) { - const result = await query( +export async function invalidateInventoryItem( + inventoryItemId: number | string, + invalidReason: string, + updatedAt: string, +): Promise { + const result = await query<{ [column: string]: unknown, id: number }>( ` UPDATE inventory_items SET status = 'invalid', invalid_reason = $1, updated_at = $2 @@ -452,7 +468,11 @@ export async function invalidateInventoryItem(inventoryItemId, invalidReason, up return getInventoryItemById(inventoryItemId) } -export async function invalidateReservedInventoryItem(inventoryItemId, invalidReason, updatedAt) { +export async function invalidateReservedInventoryItem( + inventoryItemId: number | string, + invalidReason: string, + updatedAt: string, +): Promise { return withTransaction(async (client) => { await client.query( ` diff --git a/docs/backend-typescript-migration-plan.md b/docs/backend-typescript-migration-plan.md index 7657fd55..f56b13aa 100644 --- a/docs/backend-typescript-migration-plan.md +++ b/docs/backend-typescript-migration-plan.md @@ -231,12 +231,14 @@ 15. repository 第四批已迁移到 `.ts`: - `src/repositories/order-repo.ts` - `src/repositories/task-inventory-binding-repo.ts` +16. 核心库存 repository 已迁移到 `.ts`: + - `src/repositories/inventory-repo.ts` ## 下一步建议 第一批继续推进时,建议按这个顺序: -1. 继续迁移剩余核心 repository:`inventory-repo`、`task-repo` +1. 继续迁移剩余核心 repository:`task-repo` 2. 拆分并迁移 `runtime.js`,把 env 解析、默认配置加载、配置合并分开 3. 为 webhook、库存换码、自动发货补测试