Listing_SuggestPrice/backend/app/services/erp_service.ts

156 lines
4.9 KiB
TypeScript

import env from '#start/env'
import logger from '@adonisjs/core/services/logger'
import type Product from '#models/product'
import type { SupplierPricePoint } from '#models/history'
import axios from 'axios'
interface ErpProductListParams {
limit?: number
skip?: number
order?: string
where?: {
sku?: string
warehouse?: string
condition?: string
}
}
export interface ErpProductItem {
sku: string
condition: string
qty: number
price: number
costs?: Array<{ currency: string; price: number }> | null
packageContain?: string | null
type?: string | null
erpId?: string | null
warehouse?: string | null
}
export interface ErpProductPage {
items: ErpProductItem[]
/** Tổng số bản ghi ở ERP (dùng để phân trang vòng lặp sync) */
total: number
skip: number
limit: number
}
/**
* Gọi ERP để lấy lịch sử giá supplier theo SKU/condition.
*/
export default class ErpService {
static async getSupplierPricing(product: Product): Promise<SupplierPricePoint[]> {
const url = env.get('ERP_API_URL')
if (!url) throw new Error('ERP_API_URL chưa cấu hình')
const body = {
urlAPI: '/api/wtbquote-result/get-result-list',
filter: {
limit: 50,
skip: 0,
order: 'updatedAt desc',
where: { _q: product.sku, condition: product.condition },
},
}
const resp = await axios.post(url + "/api/transferGetData", body, {
headers: {
Authorization: `Bearer ${env.get('ERP_API_KEY')}`,
'Content-Type': 'application/json',
},
})
if (!resp.data) throw new Error(`ERP API lỗi: ${resp.status}`)
const data: any = await resp.data
logger.debug({ count: data?.data?.length }, 'ERP supplier pricing fetched')
return (data?.data ?? []).map((r: any) => ({
price: Number(r.price),
date: r.createdAt,
source: 'erp',
}))
}
/**
* Gọi ERP để lấy danh sách sản phẩm tồn kho cho sync.
*/
static async getProductsForSync(params: ErpProductListParams = {}): Promise<ErpProductPage> {
const url = env.get('ERP_API_URL')
if (!url) throw new Error('ERP_API_URL chưa cấu hình')
const limit = params.limit ?? 20
const skip = params.skip ?? 0
try {
const body = {
urlAPI: '/api/products/instock',
filter: {
limit,
skip,
order: params.order ?? '',
where: {
sku: params.where?.sku ?? '',
warehouse: params.where?.warehouse ?? '',
condition: params.where?.condition ?? '',
},
},
}
const resp = await axios.post(url + "/api/transferGetData", body, {
headers: {
Authorization: `Bearer ${env.get('ERP_API_KEY')}`,
},
})
if (!resp.data) throw new Error(`ERP API lỗi: ${resp.status}`)
const data: any = await resp.data
const raw = Array.isArray(data?.data) ? data.data : Array.isArray(data) ? data : []
const total = Number(data?.total ?? raw.length)
logger.debug({ count: raw.length, total, skip }, 'ERP products fetched for sync')
const items: ErpProductItem[] = raw.map((item: any) => {
const sku = String(item?.sku ?? item?.SKU ?? item?.productSku ?? item?.product?.sku ?? '').trim()
const condition = String(
item?.condition ?? item?.Condition ?? item?.conditionName ?? item?.productCondition ?? ''
).trim()
const qty = Number(item?.qty ?? item?.quantity ?? item?.stock ?? item?.availableQty ?? item?.inStockQty ?? 0)
const price = Number(item?.price ?? item?.salePrice ?? item?.listPrice ?? item?.unitPrice ?? 0)
const costs = Array.isArray(item?.costs)
? item.costs.map((entry: any) => ({
currency: String(entry?.currency ?? 'USD').trim(),
price: Number(entry?.price ?? 0),
}))
: item?.cost != null || item?.purchasePrice != null || item?.costPrice != null
? [
{
currency: 'USD',
price: Number(item?.cost ?? item?.purchasePrice ?? item?.costPrice ?? 0),
},
]
: null
const packageContain = item?.packageContain ?? item?.package_contain ?? item?.packageQty ?? null
const erpId = item?.productId ?? null
const warehouse = item?.warehouse ?? 'AU'
return {
sku,
condition,
qty: Number.isFinite(qty) ? qty : 0,
price: Number.isFinite(price) ? price : 0,
costs,
packageContain: packageContain == null ? null : String(packageContain),
type: 'ERP',
erpId: erpId ? String(erpId) : null,
warehouse,
}
})
return { items, total: Number.isFinite(total) ? total : items.length, skip, limit }
}
catch (error) {
logger.error({ err: error }, 'ERP getProductsForSync lỗi')
// throw error
return { items: [], total: 0, skip, limit }
}
}
}