后端迁移库存仓储模块
This commit is contained in:
+72
-52
@@ -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<InventoryItemRow | null>} */
|
||||
export async function findFirstAvailableInventoryItemBySkuCode(
|
||||
skuCode,
|
||||
skuCode: string,
|
||||
credentialType = 'tencent_code',
|
||||
inventoryGroupCodes = null,
|
||||
) {
|
||||
inventoryGroupCodes: InventoryGroupCodesInput = null,
|
||||
): Promise<InventoryItemRow | null> {
|
||||
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<InventoryItemRow>(
|
||||
`${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<InventoryItemRow | null>} */
|
||||
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<InventoryItemRow | null> {
|
||||
return withTransaction(async (client) => {
|
||||
const inventoryResult = await client.query(
|
||||
`
|
||||
@@ -109,20 +120,21 @@ export async function assignReservedInventoryItem(inventoryItemId, taskId, updat
|
||||
})
|
||||
}
|
||||
|
||||
/** @returns {Promise<InventoryItemRow | null>} */
|
||||
export async function getInventoryItemById(inventoryItemId) {
|
||||
const result = await query(
|
||||
export async function getInventoryItemById(inventoryItemId: number | string): Promise<InventoryItemRow | null> {
|
||||
const result = await query<InventoryItemRow>(
|
||||
`${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<InventoryItemRow | null>} */
|
||||
export async function markInventoryItemDelivered(inventoryItemId, deliveredAt) {
|
||||
export async function markInventoryItemDelivered(
|
||||
inventoryItemId: number | string,
|
||||
deliveredAt: string,
|
||||
): Promise<InventoryItemRow | null> {
|
||||
return withTransaction(async (client) => {
|
||||
await client.query(
|
||||
`
|
||||
@@ -146,8 +158,11 @@ export async function markInventoryItemDelivered(inventoryItemId, deliveredAt) {
|
||||
})
|
||||
}
|
||||
|
||||
/** @returns {Promise<InventoryItemRow | null>} */
|
||||
export async function markInventoryItemConsumed(inventoryItemId, reason, consumedAt) {
|
||||
export async function markInventoryItemConsumed(
|
||||
inventoryItemId: number | string,
|
||||
reason: string,
|
||||
consumedAt: string,
|
||||
): Promise<InventoryItemRow | null> {
|
||||
return withTransaction(async (client) => {
|
||||
await client.query(
|
||||
`
|
||||
@@ -175,8 +190,6 @@ export async function markInventoryItemConsumed(inventoryItemId, reason, consume
|
||||
})
|
||||
}
|
||||
|
||||
/** @returns {Promise<InventoryListQueryResult>} */
|
||||
/** @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<InventoryListQueryResult> {
|
||||
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<InventoryItemRow>(
|
||||
`${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<InventorySkuSuggestionRow[]>} */
|
||||
/** @param {InventorySkuSuggestionQueryInput} [queryInput] */
|
||||
export async function listInventorySkuSuggestions({
|
||||
credentialType = '',
|
||||
keyword = '',
|
||||
limit = 50,
|
||||
inventoryGroupCode = '',
|
||||
allowedInventoryGroupCodes = null,
|
||||
} = /** @type {InventorySkuSuggestionQueryInput} */ ({})) {
|
||||
}: InventorySkuSuggestionQueryInput = {}): Promise<InventorySkuSuggestionRow[]> {
|
||||
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<InventorySkuSuggestionRow>(
|
||||
`
|
||||
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<number> {
|
||||
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<string[]> {
|
||||
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<InventoryItemRow | null>} */
|
||||
export async function releaseReservedInventoryItem(inventoryItemId, updatedAt) {
|
||||
export async function releaseReservedInventoryItem(
|
||||
inventoryItemId: number | string,
|
||||
updatedAt: string,
|
||||
): Promise<InventoryItemRow | null> {
|
||||
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<InventoryItemRow | null> {
|
||||
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<InventoryItemRow | null> {
|
||||
return withTransaction(async (client) => {
|
||||
await client.query(
|
||||
`
|
||||
Reference in New Issue
Block a user