接入多发货平台与电子凭证
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
import { query } from '../db/client.js'
|
||||
import type {
|
||||
KuaishouIndustryVoucherUpdatePatch,
|
||||
KuaishouIndustryVoucherUpsertInput,
|
||||
} from '../types/repository/inputs.js'
|
||||
import type { KuaishouIndustryVoucherRow } from '../types/repository/rows.js'
|
||||
|
||||
type VoucherPatchColumn = {
|
||||
column: string
|
||||
value: unknown
|
||||
cast?: string
|
||||
}
|
||||
|
||||
export async function upsertKuaishouIndustryVoucher(
|
||||
input: KuaishouIndustryVoucherUpsertInput,
|
||||
): Promise<KuaishouIndustryVoucherRow | null> {
|
||||
const result = await query<KuaishouIndustryVoucherRow>(
|
||||
`
|
||||
WITH next_id AS (
|
||||
SELECT nextval(pg_get_serial_sequence('kuaishou_industry_vouchers', 'id')) AS id
|
||||
)
|
||||
INSERT INTO kuaishou_industry_vouchers (
|
||||
id,
|
||||
voucher_code,
|
||||
oid,
|
||||
order_id,
|
||||
task_id,
|
||||
unit_index,
|
||||
token,
|
||||
status,
|
||||
valid_start_time,
|
||||
valid_end_time,
|
||||
consume_serial_num,
|
||||
consume_details_json,
|
||||
consumed_at,
|
||||
destroyed_at,
|
||||
raw_payload_json,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT
|
||||
next_id.id,
|
||||
next_id.id::text,
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10::jsonb,
|
||||
$11,
|
||||
$12,
|
||||
$13::jsonb,
|
||||
$14,
|
||||
$15
|
||||
FROM next_id
|
||||
ON CONFLICT (oid, unit_index) DO UPDATE
|
||||
SET
|
||||
token = CASE
|
||||
WHEN EXCLUDED.token <> '' THEN EXCLUDED.token
|
||||
ELSE kuaishou_industry_vouchers.token
|
||||
END,
|
||||
order_id = COALESCE(kuaishou_industry_vouchers.order_id, EXCLUDED.order_id),
|
||||
task_id = COALESCE(kuaishou_industry_vouchers.task_id, EXCLUDED.task_id),
|
||||
valid_start_time = EXCLUDED.valid_start_time,
|
||||
valid_end_time = EXCLUDED.valid_end_time,
|
||||
raw_payload_json = EXCLUDED.raw_payload_json,
|
||||
updated_at = EXCLUDED.updated_at
|
||||
RETURNING *
|
||||
`,
|
||||
[
|
||||
input.oid,
|
||||
normalizeNullableId(input.orderId),
|
||||
normalizeNullableId(input.taskId),
|
||||
input.unitIndex,
|
||||
input.token || '',
|
||||
input.status || 'UNUSED',
|
||||
input.validStartTime || 0,
|
||||
input.validEndTime || 0,
|
||||
input.consumeSerialNum || '',
|
||||
stringifyJson(input.consumeDetailsJson ?? []),
|
||||
input.consumedAt || null,
|
||||
input.destroyedAt || null,
|
||||
stringifyJson(input.rawPayloadJson ?? {}),
|
||||
input.createdAt,
|
||||
input.updatedAt,
|
||||
],
|
||||
)
|
||||
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
export async function listKuaishouIndustryVouchersByOid(
|
||||
oid: string,
|
||||
): Promise<KuaishouIndustryVoucherRow[]> {
|
||||
const result = await query<KuaishouIndustryVoucherRow>(
|
||||
`
|
||||
SELECT *
|
||||
FROM kuaishou_industry_vouchers
|
||||
WHERE oid = $1
|
||||
ORDER BY unit_index ASC, id ASC
|
||||
`,
|
||||
[oid],
|
||||
)
|
||||
|
||||
return result.rows
|
||||
}
|
||||
|
||||
export async function listKuaishouIndustryVouchersByTaskId(
|
||||
taskId: number | string,
|
||||
): Promise<KuaishouIndustryVoucherRow[]> {
|
||||
const result = await query<KuaishouIndustryVoucherRow>(
|
||||
`
|
||||
SELECT *
|
||||
FROM kuaishou_industry_vouchers
|
||||
WHERE task_id = $1
|
||||
ORDER BY unit_index ASC, id ASC
|
||||
`,
|
||||
[Number(taskId)],
|
||||
)
|
||||
|
||||
return result.rows
|
||||
}
|
||||
|
||||
export async function findKuaishouIndustryVoucherByCode(
|
||||
voucherCode: string,
|
||||
oid = '',
|
||||
): Promise<KuaishouIndustryVoucherRow | null> {
|
||||
const normalizedCode = String(voucherCode || '').trim()
|
||||
const normalizedOid = String(oid || '').trim()
|
||||
if (!normalizedCode) {
|
||||
return null
|
||||
}
|
||||
|
||||
const params: unknown[] = [normalizedCode]
|
||||
const oidFilter = normalizedOid ? 'AND oid = $2' : ''
|
||||
if (normalizedOid) {
|
||||
params.push(normalizedOid)
|
||||
}
|
||||
|
||||
const result = await query<KuaishouIndustryVoucherRow>(
|
||||
`
|
||||
SELECT *
|
||||
FROM kuaishou_industry_vouchers
|
||||
WHERE voucher_code = $1
|
||||
${oidFilter}
|
||||
LIMIT 1
|
||||
`,
|
||||
params,
|
||||
)
|
||||
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
export async function updateKuaishouIndustryVoucherByCode(
|
||||
voucherCode: string,
|
||||
patch: KuaishouIndustryVoucherUpdatePatch,
|
||||
): Promise<KuaishouIndustryVoucherRow | null> {
|
||||
const normalizedCode = String(voucherCode || '').trim()
|
||||
if (!normalizedCode) {
|
||||
return null
|
||||
}
|
||||
|
||||
const columns = normalizeVoucherPatchColumns(patch)
|
||||
if (columns.length === 0) {
|
||||
return findKuaishouIndustryVoucherByCode(normalizedCode)
|
||||
}
|
||||
|
||||
const assignments = columns
|
||||
.map((item, index) => `${item.column} = $${index + 1}${item.cast || ''}`)
|
||||
.join(', ')
|
||||
const params = columns.map((item) => item.value)
|
||||
params.push(normalizedCode)
|
||||
|
||||
const result = await query<KuaishouIndustryVoucherRow>(
|
||||
`
|
||||
UPDATE kuaishou_industry_vouchers
|
||||
SET ${assignments}
|
||||
WHERE voucher_code = $${params.length}
|
||||
RETURNING *
|
||||
`,
|
||||
params,
|
||||
)
|
||||
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
function normalizeVoucherPatchColumns(
|
||||
patch: KuaishouIndustryVoucherUpdatePatch,
|
||||
): VoucherPatchColumn[] {
|
||||
const columns: VoucherPatchColumn[] = []
|
||||
|
||||
if (patch.orderId !== undefined) {
|
||||
columns.push({ column: 'order_id', value: normalizeNullableId(patch.orderId) })
|
||||
}
|
||||
|
||||
if (patch.taskId !== undefined) {
|
||||
columns.push({ column: 'task_id', value: normalizeNullableId(patch.taskId) })
|
||||
}
|
||||
|
||||
if (patch.token !== undefined) {
|
||||
columns.push({ column: 'token', value: patch.token || '' })
|
||||
}
|
||||
|
||||
if (patch.status !== undefined) {
|
||||
columns.push({ column: 'status', value: patch.status || 'UNUSED' })
|
||||
}
|
||||
|
||||
if (patch.validStartTime !== undefined) {
|
||||
columns.push({ column: 'valid_start_time', value: patch.validStartTime || 0 })
|
||||
}
|
||||
|
||||
if (patch.validEndTime !== undefined) {
|
||||
columns.push({ column: 'valid_end_time', value: patch.validEndTime || 0 })
|
||||
}
|
||||
|
||||
if (patch.consumeSerialNum !== undefined) {
|
||||
columns.push({ column: 'consume_serial_num', value: patch.consumeSerialNum || '' })
|
||||
}
|
||||
|
||||
if (patch.consumeDetailsJson !== undefined) {
|
||||
columns.push({
|
||||
column: 'consume_details_json',
|
||||
value: stringifyJson(patch.consumeDetailsJson ?? []),
|
||||
cast: '::jsonb',
|
||||
})
|
||||
}
|
||||
|
||||
if (patch.consumedAt !== undefined) {
|
||||
columns.push({ column: 'consumed_at', value: patch.consumedAt || null })
|
||||
}
|
||||
|
||||
if (patch.destroyedAt !== undefined) {
|
||||
columns.push({ column: 'destroyed_at', value: patch.destroyedAt || null })
|
||||
}
|
||||
|
||||
if (patch.rawPayloadJson !== undefined) {
|
||||
columns.push({
|
||||
column: 'raw_payload_json',
|
||||
value: stringifyJson(patch.rawPayloadJson ?? {}),
|
||||
cast: '::jsonb',
|
||||
})
|
||||
}
|
||||
|
||||
if (patch.updatedAt !== undefined) {
|
||||
columns.push({ column: 'updated_at', value: patch.updatedAt })
|
||||
}
|
||||
|
||||
return columns
|
||||
}
|
||||
|
||||
function normalizeNullableId(value: unknown): number | null {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return null
|
||||
}
|
||||
|
||||
const parsed = Number(value)
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null
|
||||
}
|
||||
|
||||
function stringifyJson(value: unknown): string {
|
||||
if (typeof value === 'string') {
|
||||
return value
|
||||
}
|
||||
|
||||
return JSON.stringify(value ?? {})
|
||||
}
|
||||
Reference in New Issue
Block a user