后端迁移更多仓储模块

This commit is contained in:
yml
2026-05-21 13:50:31 +08:00
parent 6eeb1a49df
commit 79e586387c
4 changed files with 242 additions and 34 deletions
@@ -1,5 +1,43 @@
import { query, withTransaction } from '../db/client.js'
type AdminUserRow = {
id: number
username: string
password_hash: string
role: string
status: string
created_at: string
updated_at: string
inventory_group_codes: string[]
}
type AdminUserCreateInput = {
username: string
passwordHash: string
role: string
status: string
createdAt: string
updatedAt: string
}
type AdminUserPatch = Partial<Pick<
AdminUserRow,
'username' | 'password_hash' | 'role' | 'status' | 'updated_at'
>>
type AdminUserListInput = {
page?: number
pageSize?: number
username?: string
role?: string
status?: string
}
type AdminUserListResult = {
items: AdminUserRow[]
total: number
}
const ADMIN_USER_SELECT = `
SELECT
au.*,
@@ -12,24 +50,24 @@ const ADMIN_USER_SELECT = `
) bindings ON TRUE
`
export async function getAdminUserById(userId) {
const result = await query(
export async function getAdminUserById(userId: number | string): Promise<AdminUserRow | null> {
const result = await query<AdminUserRow>(
`${ADMIN_USER_SELECT} WHERE au.id = $1 LIMIT 1`,
[Number(userId)],
)
return result.rows[0] || null
}
export async function getAdminUserByUsername(username) {
const result = await query(
export async function getAdminUserByUsername(username: string): Promise<AdminUserRow | null> {
const result = await query<AdminUserRow>(
`${ADMIN_USER_SELECT} WHERE au.username = $1 LIMIT 1`,
[String(username || '').trim().toLowerCase()],
)
return result.rows[0] || null
}
export async function createAdminUser(input) {
const result = await query(
export async function createAdminUser(input: AdminUserCreateInput): Promise<AdminUserRow | null> {
const result = await query<{ [column: string]: unknown, id: number }>(
`
INSERT INTO admin_users (
username,
@@ -54,14 +92,17 @@ export async function createAdminUser(input) {
return getAdminUserById(result.rows[0]?.id || 0)
}
export async function updateAdminUser(userId, patch) {
export async function updateAdminUser(
userId: number | string,
patch: AdminUserPatch,
): Promise<AdminUserRow | null> {
const current = await getAdminUserById(userId)
if (!current) {
return null
}
const next = { ...current, ...patch }
const result = await query(
const result = await query<{ [column: string]: unknown, id: number }>(
`
UPDATE admin_users
SET
@@ -86,10 +127,16 @@ export async function updateAdminUser(userId, patch) {
return getAdminUserById(result.rows[0]?.id || 0)
}
export async function listAdminUsers({ page = 1, pageSize = 20, username = '', role = '', status = '' } = {}) {
export async function listAdminUsers({
page = 1,
pageSize = 20,
username = '',
role = '',
status = '',
}: AdminUserListInput = {}): Promise<AdminUserListResult> {
const offset = (page - 1) * pageSize
const filters = []
const params = []
const filters: string[] = []
const params: unknown[] = []
if (username) {
params.push(`%${username}%`)
@@ -107,11 +154,14 @@ export async function listAdminUsers({ page = 1, pageSize = 20, username = '', r
}
const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
const totalResult = await query(`SELECT COUNT(*)::int AS total FROM admin_users ${whereClause}`, params)
const totalResult = await query<{ [column: string]: unknown, total: number }>(
`SELECT COUNT(*)::int AS total FROM admin_users ${whereClause}`,
params,
)
params.push(pageSize)
params.push(offset)
const itemsResult = await query(
const itemsResult = await query<AdminUserRow>(
`
${ADMIN_USER_SELECT}
${whereClause}
@@ -127,14 +177,18 @@ export async function listAdminUsers({ page = 1, pageSize = 20, username = '', r
}
}
export async function countActiveAdminUsers() {
const result = await query(
export async function countActiveAdminUsers(): Promise<number> {
const result = await query<{ [column: string]: unknown, total: number }>(
`SELECT COUNT(*)::int AS total FROM admin_users WHERE role = 'admin' AND status = 'active'`,
)
return Number(result.rows[0]?.total || 0)
}
export async function replaceAdminUserInventoryGroupBindings(userId, inventoryGroupCodes = [], timestamp) {
export async function replaceAdminUserInventoryGroupBindings(
userId: number | string,
inventoryGroupCodes: unknown[] = [],
timestamp: string,
): Promise<AdminUserRow | null> {
const normalizedUserId = Number(userId)
const normalizedCodes = Array.from(new Set((Array.isArray(inventoryGroupCodes) ? inventoryGroupCodes : [])
.map((value) => String(value || '').trim())
@@ -1,15 +1,106 @@
import { query, withTransaction } from '../db/client.js'
export async function getFulfillmentProfileByKey(profileKey) {
const result = await query(
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) {
const result = await query(
export async function upsertFulfillmentProfile(
input: FulfillmentProfileUpsertInput,
): Promise<FulfillmentProfileRow | null> {
const result = await query<FulfillmentProfileRow>(
`
INSERT INTO fulfillment_profiles (
profile_key,
@@ -49,7 +140,11 @@ export async function upsertFulfillmentProfile(input) {
return result.rows[0] || null
}
export async function replaceFulfillmentProfileRequirements(profileId, requirements = [], timestamp) {
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',
@@ -85,8 +180,10 @@ export async function replaceFulfillmentProfileRequirements(profileId, requireme
})
}
export async function listFulfillmentProfileRequirements(profileId) {
const result = await query(
export async function listFulfillmentProfileRequirements(
profileId: number | string,
): Promise<FulfillmentProfileRequirementRow[]> {
const result = await query<FulfillmentProfileRequirementRow>(
`
SELECT *
FROM fulfillment_profile_requirements
@@ -99,8 +196,10 @@ export async function listFulfillmentProfileRequirements(profileId) {
return result.rows
}
export async function upsertSkuFulfillmentBinding(input) {
const existing = await query(
export async function upsertSkuFulfillmentBinding(
input: SkuFulfillmentBindingUpsertInput,
): Promise<SkuFulfillmentBindingRow | null> {
const existing = await query<SkuFulfillmentBindingRow>(
`
SELECT *
FROM sku_fulfillment_bindings
@@ -111,7 +210,7 @@ export async function upsertSkuFulfillmentBinding(input) {
)
if (!existing.rows[0]) {
const inserted = await query(
const inserted = await query<SkuFulfillmentBindingRow>(
`
INSERT INTO sku_fulfillment_bindings (
sku_code,
@@ -144,7 +243,7 @@ export async function upsertSkuFulfillmentBinding(input) {
return inserted.rows[0] || null
}
const updated = await query(
const updated = await query<SkuFulfillmentBindingRow>(
`
UPDATE sku_fulfillment_bindings
SET
@@ -169,8 +268,13 @@ export async function upsertSkuFulfillmentBinding(input) {
return updated.rows[0] || null
}
export async function resolveFulfillmentBinding({ skuCode, provider = '', platform = '', shopId = '' }) {
const result = await query(
export async function resolveFulfillmentBinding({
skuCode,
provider = '',
platform = '',
shopId = '',
}: FulfillmentBindingResolveInput): Promise<SkuFulfillmentBindingRow | null> {
const result = await query<SkuFulfillmentBindingRow>(
`
SELECT
sfb.*,
@@ -1,7 +1,53 @@
import { query } from '../db/client.js'
export async function upsertProductMatchRule(input) {
const result = await query(
type ProductMatchRuleRow = {
id: number
provider: string
platform: string
shop_id: string
external_item_id: string
external_sku_code: string
external_sku_name: string
external_sku_name_normalized: string
resolved_sku_code: string
enabled: boolean
priority: number
config_json: string | Record<string, unknown>
created_at: string
updated_at: string
matched_by?: string
match_score?: number
}
type ProductMatchRuleUpsertInput = {
provider?: string
platform?: string
shopId?: string
externalItemId?: string
externalSkuCode?: string
externalSkuName?: string
externalSkuNameNormalized?: string
resolvedSkuCode: string
enabled?: boolean
priority?: number | string
configJson?: string | Record<string, unknown>
createdAt: string
updatedAt: string
}
type ProductMatchRuleResolveInput = {
provider?: string
platform?: string
shopId?: string
externalItemId?: string
externalSkuCode?: string
externalSkuNameNormalized?: string
}
export async function upsertProductMatchRule(
input: ProductMatchRuleUpsertInput,
): Promise<ProductMatchRuleRow | null> {
const result = await query<ProductMatchRuleRow>(
`
INSERT INTO product_match_rules (
provider,
@@ -64,8 +110,8 @@ export async function resolveProductMatchRule({
externalItemId = '',
externalSkuCode = '',
externalSkuNameNormalized = '',
}) {
const result = await query(
}: ProductMatchRuleResolveInput): Promise<ProductMatchRuleRow | null> {
const result = await query<ProductMatchRuleRow>(
`
SELECT
pmr.*,