/**
* Odoo API 客戶端
*/
import { getAppSecrets } from '../../utils/secrets.js'
export interface OdooSearchParams {
model: string
domain?: any[]
fields?: string[]
limit?: number
offset?: number
order?: string
}
export interface OdooReadParams {
model: string
ids: number[]
fields?: string[]
}
export interface OdooCreateParams {
model: string
values: Record<string, any>
}
export interface OdooUpdateParams {
model: string
ids: number[]
values: Record<string, any>
}
export interface OdooDeleteParams {
model: string
ids: number[]
}
export class OdooClient {
private url: string
private db: string
private apiKey: string
private userId: number
constructor(url: string, db: string, apiKey: string, userId: number) {
this.url = url.replace(/\/$/, '')
this.db = db
this.apiKey = apiKey
this.userId = userId
}
/**
* 執行 JSON-RPC 呼叫
*/
private async jsonRpc(endpoint: string, _method: string, params: any): Promise<any> {
const response = await fetch(`${this.url}${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'call',
params: {
service: 'object',
method: 'execute_kw',
args: [this.db, this.userId, this.apiKey, ...params],
},
id: Date.now(),
}),
})
const data = await response.json() as any
if (data.error) {
throw new Error(`Odoo Error: ${data.error.message || JSON.stringify(data.error)}`)
}
return data.result
}
async search(params: OdooSearchParams): Promise<any[]> {
const domain = params.domain || []
const fields = params.fields || []
const limit = params.limit || 20
const offset = params.offset || 0
const kwargs: any = {
fields,
limit,
offset,
}
if (params.order) {
kwargs.order = params.order
}
return this.jsonRpc('/jsonrpc', 'call', [
params.model,
'search_read',
[domain],
kwargs,
])
}
async read(params: OdooReadParams): Promise<any[]> {
const fields = params.fields || []
return this.jsonRpc('/jsonrpc', 'call', [
params.model,
'read',
[params.ids],
{ fields },
])
}
async count(model: string, domain: any[] = []): Promise<number> {
return this.jsonRpc('/jsonrpc', 'call', [
model,
'search_count',
[domain],
])
}
async create(params: OdooCreateParams): Promise<number> {
return this.jsonRpc('/jsonrpc', 'call', [
params.model,
'create',
[params.values],
])
}
async update(params: OdooUpdateParams): Promise<boolean> {
return this.jsonRpc('/jsonrpc', 'call', [
params.model,
'write',
[params.ids, params.values],
])
}
async delete(params: OdooDeleteParams): Promise<boolean> {
return this.jsonRpc('/jsonrpc', 'call', [
params.model,
'unlink',
[params.ids],
])
}
}
let odooClient: OdooClient | null = null
export async function getOdooClient(): Promise<OdooClient> {
if (!odooClient) {
const secrets = await getAppSecrets()
odooClient = new OdooClient(
secrets.odooUrl,
secrets.odooDb,
secrets.odooApiKey,
secrets.odooUserId
)
}
return odooClient
}