@marcfargas/odoo-client 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +165 -165
- package/README.md +115 -3
- package/dist/client/config.d.ts +49 -0
- package/dist/client/config.d.ts.map +1 -0
- package/dist/client/config.js +75 -0
- package/dist/client/config.js.map +1 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +10 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/odoo-client.d.ts +227 -0
- package/dist/client/odoo-client.d.ts.map +1 -0
- package/dist/client/odoo-client.js +298 -0
- package/dist/client/odoo-client.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/rpc/index.d.ts +2 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +7 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/rpc/transport.d.ts +77 -0
- package/dist/rpc/transport.d.ts.map +1 -0
- package/dist/rpc/transport.js +207 -0
- package/dist/rpc/transport.js.map +1 -0
- package/dist/rpc/types.d.ts +25 -0
- package/dist/rpc/types.d.ts.map +1 -0
- package/dist/rpc/types.js +6 -0
- package/dist/rpc/types.js.map +1 -0
- package/dist/safety/index.d.ts +68 -0
- package/dist/safety/index.d.ts.map +1 -0
- package/dist/safety/index.js +86 -0
- package/dist/safety/index.js.map +1 -0
- package/dist/services/attendance/attendance-service.d.ts +100 -0
- package/dist/services/attendance/attendance-service.d.ts.map +1 -0
- package/dist/services/attendance/attendance-service.js +113 -0
- package/dist/services/attendance/attendance-service.js.map +1 -0
- package/dist/services/attendance/functions.d.ts +72 -0
- package/dist/services/attendance/functions.d.ts.map +1 -0
- package/dist/services/attendance/functions.js +169 -0
- package/dist/services/attendance/functions.js.map +1 -0
- package/dist/services/attendance/index.d.ts +4 -0
- package/dist/services/attendance/index.d.ts.map +1 -0
- package/dist/services/attendance/index.js +12 -0
- package/dist/services/attendance/index.js.map +1 -0
- package/dist/services/attendance/types.d.ts +53 -0
- package/dist/services/attendance/types.d.ts.map +1 -0
- package/dist/services/attendance/types.js +8 -0
- package/dist/services/attendance/types.js.map +1 -0
- package/dist/services/index.d.ts +24 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +40 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/mail/functions.d.ts +69 -0
- package/dist/services/mail/functions.d.ts.map +1 -0
- package/dist/services/mail/functions.js +124 -0
- package/dist/services/mail/functions.js.map +1 -0
- package/dist/services/mail/index.d.ts +4 -0
- package/dist/services/mail/index.d.ts.map +1 -0
- package/dist/services/mail/index.js +10 -0
- package/dist/services/mail/index.js.map +1 -0
- package/dist/services/mail/mail-service.d.ts +57 -0
- package/dist/services/mail/mail-service.d.ts.map +1 -0
- package/dist/services/mail/mail-service.js +66 -0
- package/dist/services/mail/mail-service.js.map +1 -0
- package/dist/services/mail/types.d.ts +23 -0
- package/dist/services/mail/types.d.ts.map +1 -0
- package/dist/services/mail/types.js +6 -0
- package/dist/services/mail/types.js.map +1 -0
- package/dist/services/modules/index.d.ts +2 -0
- package/dist/services/modules/index.d.ts.map +1 -0
- package/dist/services/modules/index.js +6 -0
- package/dist/services/modules/index.js.map +1 -0
- package/dist/services/modules/module-manager.d.ts +136 -0
- package/dist/services/modules/module-manager.d.ts.map +1 -0
- package/dist/services/modules/module-manager.js +255 -0
- package/dist/services/modules/module-manager.js.map +1 -0
- package/dist/services/timesheets/functions.d.ts +75 -0
- package/dist/services/timesheets/functions.d.ts.map +1 -0
- package/dist/services/timesheets/functions.js +220 -0
- package/dist/services/timesheets/functions.js.map +1 -0
- package/dist/services/timesheets/index.d.ts +4 -0
- package/dist/services/timesheets/index.d.ts.map +1 -0
- package/dist/services/timesheets/index.js +12 -0
- package/dist/services/timesheets/index.js.map +1 -0
- package/dist/services/timesheets/timesheets-service.d.ts +121 -0
- package/dist/services/timesheets/timesheets-service.d.ts.map +1 -0
- package/dist/services/timesheets/timesheets-service.js +136 -0
- package/dist/services/timesheets/timesheets-service.js.map +1 -0
- package/dist/services/timesheets/types.d.ts +81 -0
- package/dist/services/timesheets/types.d.ts.map +1 -0
- package/dist/services/timesheets/types.js +10 -0
- package/dist/services/timesheets/types.js.map +1 -0
- package/dist/types/errors.d.ts +122 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +195 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +31 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/properties.d.ts +246 -0
- package/dist/types/properties.d.ts.map +1 -0
- package/dist/types/properties.js +56 -0
- package/dist/types/properties.js.map +1 -0
- package/package.json +28 -6
- package/index.js +0 -3
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main Odoo client — RPC transport, CRUD, and safety guards.
|
|
3
|
+
*
|
|
4
|
+
* Domain-specific helpers (mail, accounting, etc.) are accessed via lazy
|
|
5
|
+
* service accessors:
|
|
6
|
+
*
|
|
7
|
+
* client.mail.postInternalNote(...)
|
|
8
|
+
* client.modules.isModuleInstalled(...)
|
|
9
|
+
*
|
|
10
|
+
* OdooClient itself is strictly RPC/CRUD/auth/safety. No business logic.
|
|
11
|
+
*
|
|
12
|
+
* ## Adding a new service accessor
|
|
13
|
+
*
|
|
14
|
+
* 1. Create `services/{module}/` directory
|
|
15
|
+
* 2. Add a lazy getter here (3 lines: private field + getter)
|
|
16
|
+
* 3. Export from `services/index.ts`
|
|
17
|
+
* 4. Update skill docs to show `client.{module}.*` pattern
|
|
18
|
+
*/
|
|
19
|
+
import { OdooSessionInfo } from '../rpc/transport';
|
|
20
|
+
import { type SafetyContext, type SafetyLevel } from '../safety';
|
|
21
|
+
import { MailService } from '../services/mail/mail-service';
|
|
22
|
+
import { ModuleManager } from '../services/modules/module-manager';
|
|
23
|
+
import { AttendanceService } from '../services/attendance/attendance-service';
|
|
24
|
+
import { TimesheetsService } from '../services/timesheets/timesheets-service';
|
|
25
|
+
export interface OdooClientConfig {
|
|
26
|
+
url: string;
|
|
27
|
+
database: string;
|
|
28
|
+
username: string;
|
|
29
|
+
password: string;
|
|
30
|
+
/**
|
|
31
|
+
* Opt-in safety context for this client.
|
|
32
|
+
* - undefined: use global default (setDefaultSafetyContext)
|
|
33
|
+
* - null: explicitly disable safety for this client
|
|
34
|
+
* - SafetyContext: custom confirm callback
|
|
35
|
+
*/
|
|
36
|
+
safety?: SafetyContext | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Main client for interacting with Odoo.
|
|
40
|
+
*
|
|
41
|
+
* Core: authentication, CRUD operations, raw RPC calls, safety guards.
|
|
42
|
+
* Services: accessed via lazy getters — `client.mail`, `client.modules`, etc.
|
|
43
|
+
*/
|
|
44
|
+
export declare class OdooClient {
|
|
45
|
+
private config;
|
|
46
|
+
private transport;
|
|
47
|
+
private authenticated;
|
|
48
|
+
private safetyContext;
|
|
49
|
+
constructor(config: OdooClientConfig);
|
|
50
|
+
private _mail?;
|
|
51
|
+
/**
|
|
52
|
+
* Mail / Chatter service — post messages and notes on records.
|
|
53
|
+
*
|
|
54
|
+
* ```typescript
|
|
55
|
+
* await client.mail.postInternalNote('crm.lead', 42, '<p>Called customer.</p>');
|
|
56
|
+
* await client.mail.postOpenMessage('res.partner', 7, '<p>Order shipped.</p>');
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
get mail(): MailService;
|
|
60
|
+
private _modules?;
|
|
61
|
+
/**
|
|
62
|
+
* Module management — install, uninstall, list, and check Odoo modules.
|
|
63
|
+
*
|
|
64
|
+
* ```typescript
|
|
65
|
+
* if (await client.modules.isModuleInstalled('sale')) { ... }
|
|
66
|
+
* await client.modules.installModule('project');
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
get modules(): ModuleManager;
|
|
70
|
+
private _attendance?;
|
|
71
|
+
/**
|
|
72
|
+
* Attendance service — clock in/out and presence tracking.
|
|
73
|
+
*
|
|
74
|
+
* Requires the `hr_attendance` module to be installed.
|
|
75
|
+
*
|
|
76
|
+
* ```typescript
|
|
77
|
+
* await client.attendance.clockIn();
|
|
78
|
+
* const status = await client.attendance.getStatus();
|
|
79
|
+
* await client.attendance.clockOut();
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
get attendance(): AttendanceService;
|
|
83
|
+
private _timesheets?;
|
|
84
|
+
/**
|
|
85
|
+
* Timesheets service — timer-based and manual time tracking on projects.
|
|
86
|
+
*
|
|
87
|
+
* Requires the `hr_timesheet` module to be installed.
|
|
88
|
+
*
|
|
89
|
+
* ```typescript
|
|
90
|
+
* // Timer workflow
|
|
91
|
+
* const entry = await client.timesheets.startTimer({
|
|
92
|
+
* description: 'Feature work',
|
|
93
|
+
* projectId: 5,
|
|
94
|
+
* });
|
|
95
|
+
* // ... later ...
|
|
96
|
+
* await client.timesheets.stopTimer(entry.id);
|
|
97
|
+
*
|
|
98
|
+
* // Manual logging
|
|
99
|
+
* await client.timesheets.logTime({
|
|
100
|
+
* description: 'Code review',
|
|
101
|
+
* projectId: 5,
|
|
102
|
+
* hours: 1.5,
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
get timesheets(): TimesheetsService;
|
|
107
|
+
/**
|
|
108
|
+
* Override safety context for this client instance.
|
|
109
|
+
* Pass null to explicitly disable, undefined to use global default.
|
|
110
|
+
*/
|
|
111
|
+
setSafetyContext(ctx: SafetyContext | null | undefined): void;
|
|
112
|
+
/**
|
|
113
|
+
* Authenticate with Odoo
|
|
114
|
+
*
|
|
115
|
+
* Must be called before making any RPC calls
|
|
116
|
+
*/
|
|
117
|
+
authenticate(): Promise<OdooSessionInfo>;
|
|
118
|
+
/**
|
|
119
|
+
* Check if client is authenticated
|
|
120
|
+
*/
|
|
121
|
+
isAuthenticated(): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Get current session info
|
|
124
|
+
*/
|
|
125
|
+
getSession(): OdooSessionInfo | null;
|
|
126
|
+
/**
|
|
127
|
+
* Check safety guard for an operation.
|
|
128
|
+
* Throws OdooSafetyError if the operation is blocked.
|
|
129
|
+
*/
|
|
130
|
+
private guard;
|
|
131
|
+
/**
|
|
132
|
+
* Make a raw RPC call to a model method
|
|
133
|
+
*
|
|
134
|
+
* Safety level is inferred from the method name:
|
|
135
|
+
* - Known read methods (search, read, fields_get, etc.) → READ (never blocked)
|
|
136
|
+
* - unlink → DELETE
|
|
137
|
+
* - Everything else → WRITE
|
|
138
|
+
*
|
|
139
|
+
* Override with `options.safetyLevel` for methods the inference gets wrong.
|
|
140
|
+
*
|
|
141
|
+
* @param model - Model name (e.g., 'res.partner')
|
|
142
|
+
* @param method - Method name (e.g., 'search', 'read')
|
|
143
|
+
* @param args - Positional arguments
|
|
144
|
+
* @param kwargs - Keyword arguments (context, etc)
|
|
145
|
+
* @param options - Additional options (safetyLevel override)
|
|
146
|
+
* @returns Method result, typed as T
|
|
147
|
+
*/
|
|
148
|
+
call<T = any>(model: string, method: string, args?: any[], kwargs?: Record<string, any>, options?: {
|
|
149
|
+
safetyLevel?: SafetyLevel;
|
|
150
|
+
}): Promise<T>;
|
|
151
|
+
/**
|
|
152
|
+
* Search for records
|
|
153
|
+
*
|
|
154
|
+
* @param model - Model name
|
|
155
|
+
* @param domain - Search domain (e.g., [['active', '=', true]])
|
|
156
|
+
* @param options - Search options (offset, limit, order, etc)
|
|
157
|
+
* @returns Array of record IDs
|
|
158
|
+
*/
|
|
159
|
+
search(model: string, domain?: any[], options?: {
|
|
160
|
+
offset?: number;
|
|
161
|
+
limit?: number;
|
|
162
|
+
order?: string;
|
|
163
|
+
}): Promise<number[]>;
|
|
164
|
+
/**
|
|
165
|
+
* Read records
|
|
166
|
+
*
|
|
167
|
+
* @param model - Model name
|
|
168
|
+
* @param ids - Record IDs to read
|
|
169
|
+
* @param fields - Fields to read (empty = all fields)
|
|
170
|
+
* @returns Array of record objects
|
|
171
|
+
*/
|
|
172
|
+
read<T extends Record<string, any> = Record<string, any>>(model: string, ids: number | number[], fields?: string[]): Promise<T[]>;
|
|
173
|
+
/**
|
|
174
|
+
* Search and read records in one call
|
|
175
|
+
*
|
|
176
|
+
* @param model - Model name
|
|
177
|
+
* @param domain - Search domain
|
|
178
|
+
* @param options - Search and read options
|
|
179
|
+
* @returns Array of record objects
|
|
180
|
+
*/
|
|
181
|
+
searchRead<T extends Record<string, any> = Record<string, any>>(model: string, domain?: any[], options?: {
|
|
182
|
+
fields?: string[];
|
|
183
|
+
offset?: number;
|
|
184
|
+
limit?: number;
|
|
185
|
+
order?: string;
|
|
186
|
+
}): Promise<T[]>;
|
|
187
|
+
/**
|
|
188
|
+
* Create a new record
|
|
189
|
+
*
|
|
190
|
+
* @param model - Model name
|
|
191
|
+
* @param values - Record values
|
|
192
|
+
* @param context - Optional context for creation
|
|
193
|
+
* @returns Created record ID
|
|
194
|
+
*/
|
|
195
|
+
create(model: string, values: Record<string, any>, context?: Record<string, any>): Promise<number>;
|
|
196
|
+
/**
|
|
197
|
+
* Update records
|
|
198
|
+
*
|
|
199
|
+
* @param model - Model name
|
|
200
|
+
* @param ids - Record IDs to update
|
|
201
|
+
* @param values - Values to update
|
|
202
|
+
* @param context - Optional context for update
|
|
203
|
+
* @returns True if successful
|
|
204
|
+
*/
|
|
205
|
+
write(model: string, ids: number | number[], values: Record<string, any>, context?: Record<string, any>): Promise<boolean>;
|
|
206
|
+
/**
|
|
207
|
+
* Delete records
|
|
208
|
+
*
|
|
209
|
+
* @param model - Model name
|
|
210
|
+
* @param ids - Record IDs to delete
|
|
211
|
+
* @returns True if successful
|
|
212
|
+
*/
|
|
213
|
+
unlink(model: string, ids: number | number[]): Promise<boolean>;
|
|
214
|
+
/**
|
|
215
|
+
* Count matching records
|
|
216
|
+
*
|
|
217
|
+
* @param model - Model name
|
|
218
|
+
* @param domain - Search domain
|
|
219
|
+
* @returns Number of matching records
|
|
220
|
+
*/
|
|
221
|
+
searchCount(model: string, domain?: any[]): Promise<number>;
|
|
222
|
+
/**
|
|
223
|
+
* Logout and close connection
|
|
224
|
+
*/
|
|
225
|
+
logout(): void;
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=odoo-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odoo-client.d.ts","sourceRoot":"","sources":["../../src/client/odoo-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Main Odoo client — RPC transport, CRUD, and safety guards.
|
|
4
|
+
*
|
|
5
|
+
* Domain-specific helpers (mail, accounting, etc.) are accessed via lazy
|
|
6
|
+
* service accessors:
|
|
7
|
+
*
|
|
8
|
+
* client.mail.postInternalNote(...)
|
|
9
|
+
* client.modules.isModuleInstalled(...)
|
|
10
|
+
*
|
|
11
|
+
* OdooClient itself is strictly RPC/CRUD/auth/safety. No business logic.
|
|
12
|
+
*
|
|
13
|
+
* ## Adding a new service accessor
|
|
14
|
+
*
|
|
15
|
+
* 1. Create `services/{module}/` directory
|
|
16
|
+
* 2. Add a lazy getter here (3 lines: private field + getter)
|
|
17
|
+
* 3. Export from `services/index.ts`
|
|
18
|
+
* 4. Update skill docs to show `client.{module}.*` pattern
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.OdooClient = void 0;
|
|
22
|
+
const transport_1 = require("../rpc/transport");
|
|
23
|
+
const errors_1 = require("../types/errors");
|
|
24
|
+
const safety_1 = require("../safety");
|
|
25
|
+
const mail_service_1 = require("../services/mail/mail-service");
|
|
26
|
+
const module_manager_1 = require("../services/modules/module-manager");
|
|
27
|
+
const attendance_service_1 = require("../services/attendance/attendance-service");
|
|
28
|
+
const timesheets_service_1 = require("../services/timesheets/timesheets-service");
|
|
29
|
+
/**
|
|
30
|
+
* Main client for interacting with Odoo.
|
|
31
|
+
*
|
|
32
|
+
* Core: authentication, CRUD operations, raw RPC calls, safety guards.
|
|
33
|
+
* Services: accessed via lazy getters — `client.mail`, `client.modules`, etc.
|
|
34
|
+
*/
|
|
35
|
+
class OdooClient {
|
|
36
|
+
config;
|
|
37
|
+
transport;
|
|
38
|
+
authenticated = false;
|
|
39
|
+
safetyContext;
|
|
40
|
+
constructor(config) {
|
|
41
|
+
this.config = config;
|
|
42
|
+
this.transport = new transport_1.JsonRpcTransport(config.url, config.database);
|
|
43
|
+
this.safetyContext = config.safety;
|
|
44
|
+
}
|
|
45
|
+
// ── Service accessors (lazy) ────────────────────────────────────────
|
|
46
|
+
//
|
|
47
|
+
// Each service is created on first access and reused thereafter.
|
|
48
|
+
// Adding a service: private field + getter + import. That's it.
|
|
49
|
+
_mail;
|
|
50
|
+
/**
|
|
51
|
+
* Mail / Chatter service — post messages and notes on records.
|
|
52
|
+
*
|
|
53
|
+
* ```typescript
|
|
54
|
+
* await client.mail.postInternalNote('crm.lead', 42, '<p>Called customer.</p>');
|
|
55
|
+
* await client.mail.postOpenMessage('res.partner', 7, '<p>Order shipped.</p>');
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
get mail() {
|
|
59
|
+
return (this._mail ??= new mail_service_1.MailService(this));
|
|
60
|
+
}
|
|
61
|
+
_modules;
|
|
62
|
+
/**
|
|
63
|
+
* Module management — install, uninstall, list, and check Odoo modules.
|
|
64
|
+
*
|
|
65
|
+
* ```typescript
|
|
66
|
+
* if (await client.modules.isModuleInstalled('sale')) { ... }
|
|
67
|
+
* await client.modules.installModule('project');
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
get modules() {
|
|
71
|
+
return (this._modules ??= new module_manager_1.ModuleManager(this));
|
|
72
|
+
}
|
|
73
|
+
_attendance;
|
|
74
|
+
/**
|
|
75
|
+
* Attendance service — clock in/out and presence tracking.
|
|
76
|
+
*
|
|
77
|
+
* Requires the `hr_attendance` module to be installed.
|
|
78
|
+
*
|
|
79
|
+
* ```typescript
|
|
80
|
+
* await client.attendance.clockIn();
|
|
81
|
+
* const status = await client.attendance.getStatus();
|
|
82
|
+
* await client.attendance.clockOut();
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
get attendance() {
|
|
86
|
+
return (this._attendance ??= new attendance_service_1.AttendanceService(this));
|
|
87
|
+
}
|
|
88
|
+
_timesheets;
|
|
89
|
+
/**
|
|
90
|
+
* Timesheets service — timer-based and manual time tracking on projects.
|
|
91
|
+
*
|
|
92
|
+
* Requires the `hr_timesheet` module to be installed.
|
|
93
|
+
*
|
|
94
|
+
* ```typescript
|
|
95
|
+
* // Timer workflow
|
|
96
|
+
* const entry = await client.timesheets.startTimer({
|
|
97
|
+
* description: 'Feature work',
|
|
98
|
+
* projectId: 5,
|
|
99
|
+
* });
|
|
100
|
+
* // ... later ...
|
|
101
|
+
* await client.timesheets.stopTimer(entry.id);
|
|
102
|
+
*
|
|
103
|
+
* // Manual logging
|
|
104
|
+
* await client.timesheets.logTime({
|
|
105
|
+
* description: 'Code review',
|
|
106
|
+
* projectId: 5,
|
|
107
|
+
* hours: 1.5,
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
get timesheets() {
|
|
112
|
+
return (this._timesheets ??= new timesheets_service_1.TimesheetsService(this));
|
|
113
|
+
}
|
|
114
|
+
// ── Auth ────────────────────────────────────────────────────────────
|
|
115
|
+
/**
|
|
116
|
+
* Override safety context for this client instance.
|
|
117
|
+
* Pass null to explicitly disable, undefined to use global default.
|
|
118
|
+
*/
|
|
119
|
+
setSafetyContext(ctx) {
|
|
120
|
+
this.safetyContext = ctx;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Authenticate with Odoo
|
|
124
|
+
*
|
|
125
|
+
* Must be called before making any RPC calls
|
|
126
|
+
*/
|
|
127
|
+
async authenticate() {
|
|
128
|
+
const session = await this.transport.authenticate(this.config.username, this.config.password);
|
|
129
|
+
this.authenticated = true;
|
|
130
|
+
return session;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Check if client is authenticated
|
|
134
|
+
*/
|
|
135
|
+
isAuthenticated() {
|
|
136
|
+
return this.authenticated;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get current session info
|
|
140
|
+
*/
|
|
141
|
+
getSession() {
|
|
142
|
+
return this.transport.getSession();
|
|
143
|
+
}
|
|
144
|
+
// ── Safety ──────────────────────────────────────────────────────────
|
|
145
|
+
/**
|
|
146
|
+
* Check safety guard for an operation.
|
|
147
|
+
* Throws OdooSafetyError if the operation is blocked.
|
|
148
|
+
*/
|
|
149
|
+
async guard(op) {
|
|
150
|
+
const ctx = (0, safety_1.resolveSafetyContext)(this.safetyContext);
|
|
151
|
+
if (!ctx)
|
|
152
|
+
return;
|
|
153
|
+
if (op.level === 'READ')
|
|
154
|
+
return;
|
|
155
|
+
const confirmed = await ctx.confirm(op);
|
|
156
|
+
if (!confirmed) {
|
|
157
|
+
throw new errors_1.OdooSafetyError(op);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// ── RPC ─────────────────────────────────────────────────────────────
|
|
161
|
+
/**
|
|
162
|
+
* Make a raw RPC call to a model method
|
|
163
|
+
*
|
|
164
|
+
* Safety level is inferred from the method name:
|
|
165
|
+
* - Known read methods (search, read, fields_get, etc.) → READ (never blocked)
|
|
166
|
+
* - unlink → DELETE
|
|
167
|
+
* - Everything else → WRITE
|
|
168
|
+
*
|
|
169
|
+
* Override with `options.safetyLevel` for methods the inference gets wrong.
|
|
170
|
+
*
|
|
171
|
+
* @param model - Model name (e.g., 'res.partner')
|
|
172
|
+
* @param method - Method name (e.g., 'search', 'read')
|
|
173
|
+
* @param args - Positional arguments
|
|
174
|
+
* @param kwargs - Keyword arguments (context, etc)
|
|
175
|
+
* @param options - Additional options (safetyLevel override)
|
|
176
|
+
* @returns Method result, typed as T
|
|
177
|
+
*/
|
|
178
|
+
async call(model, method, args = [], kwargs = {}, options) {
|
|
179
|
+
if (!this.authenticated) {
|
|
180
|
+
throw new errors_1.OdooAuthError('Client not authenticated. Call authenticate() first.');
|
|
181
|
+
}
|
|
182
|
+
const level = options?.safetyLevel ?? (0, safety_1.inferSafetyLevel)(method);
|
|
183
|
+
await this.guard({
|
|
184
|
+
name: `odoo.${method}`,
|
|
185
|
+
level,
|
|
186
|
+
model,
|
|
187
|
+
description: `${model}.${method}()`,
|
|
188
|
+
target: this.config.url,
|
|
189
|
+
});
|
|
190
|
+
return this.transport.call(model, method, args, kwargs);
|
|
191
|
+
}
|
|
192
|
+
// ── CRUD ────────────────────────────────────────────────────────────
|
|
193
|
+
/**
|
|
194
|
+
* Search for records
|
|
195
|
+
*
|
|
196
|
+
* @param model - Model name
|
|
197
|
+
* @param domain - Search domain (e.g., [['active', '=', true]])
|
|
198
|
+
* @param options - Search options (offset, limit, order, etc)
|
|
199
|
+
* @returns Array of record IDs
|
|
200
|
+
*/
|
|
201
|
+
async search(model, domain = [], options = {}) {
|
|
202
|
+
const kwargs = {};
|
|
203
|
+
if (options.offset !== undefined)
|
|
204
|
+
kwargs.offset = options.offset;
|
|
205
|
+
if (options.limit !== undefined)
|
|
206
|
+
kwargs.limit = options.limit;
|
|
207
|
+
if (options.order !== undefined)
|
|
208
|
+
kwargs.order = options.order;
|
|
209
|
+
return this.call(model, 'search', [domain], kwargs);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Read records
|
|
213
|
+
*
|
|
214
|
+
* @param model - Model name
|
|
215
|
+
* @param ids - Record IDs to read
|
|
216
|
+
* @param fields - Fields to read (empty = all fields)
|
|
217
|
+
* @returns Array of record objects
|
|
218
|
+
*/
|
|
219
|
+
async read(model, ids, fields = []) {
|
|
220
|
+
const idArray = Array.isArray(ids) ? ids : [ids];
|
|
221
|
+
return this.call(model, 'read', [idArray, fields]);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Search and read records in one call
|
|
225
|
+
*
|
|
226
|
+
* @param model - Model name
|
|
227
|
+
* @param domain - Search domain
|
|
228
|
+
* @param options - Search and read options
|
|
229
|
+
* @returns Array of record objects
|
|
230
|
+
*/
|
|
231
|
+
async searchRead(model, domain = [], options = {}) {
|
|
232
|
+
const kwargs = {};
|
|
233
|
+
if (options.fields !== undefined && options.fields.length > 0) {
|
|
234
|
+
kwargs.fields = options.fields;
|
|
235
|
+
}
|
|
236
|
+
if (options.offset !== undefined)
|
|
237
|
+
kwargs.offset = options.offset;
|
|
238
|
+
if (options.limit !== undefined)
|
|
239
|
+
kwargs.limit = options.limit;
|
|
240
|
+
if (options.order !== undefined)
|
|
241
|
+
kwargs.order = options.order;
|
|
242
|
+
return this.call(model, 'search_read', [domain], kwargs);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Create a new record
|
|
246
|
+
*
|
|
247
|
+
* @param model - Model name
|
|
248
|
+
* @param values - Record values
|
|
249
|
+
* @param context - Optional context for creation
|
|
250
|
+
* @returns Created record ID
|
|
251
|
+
*/
|
|
252
|
+
async create(model, values, context = {}) {
|
|
253
|
+
return this.call(model, 'create', [values], { context });
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Update records
|
|
257
|
+
*
|
|
258
|
+
* @param model - Model name
|
|
259
|
+
* @param ids - Record IDs to update
|
|
260
|
+
* @param values - Values to update
|
|
261
|
+
* @param context - Optional context for update
|
|
262
|
+
* @returns True if successful
|
|
263
|
+
*/
|
|
264
|
+
async write(model, ids, values, context = {}) {
|
|
265
|
+
const idArray = Array.isArray(ids) ? ids : [ids];
|
|
266
|
+
return this.call(model, 'write', [idArray, values], { context });
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Delete records
|
|
270
|
+
*
|
|
271
|
+
* @param model - Model name
|
|
272
|
+
* @param ids - Record IDs to delete
|
|
273
|
+
* @returns True if successful
|
|
274
|
+
*/
|
|
275
|
+
async unlink(model, ids) {
|
|
276
|
+
const idArray = Array.isArray(ids) ? ids : [ids];
|
|
277
|
+
return this.call(model, 'unlink', [idArray]);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Count matching records
|
|
281
|
+
*
|
|
282
|
+
* @param model - Model name
|
|
283
|
+
* @param domain - Search domain
|
|
284
|
+
* @returns Number of matching records
|
|
285
|
+
*/
|
|
286
|
+
async searchCount(model, domain = []) {
|
|
287
|
+
return this.call(model, 'search_count', [domain]);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Logout and close connection
|
|
291
|
+
*/
|
|
292
|
+
logout() {
|
|
293
|
+
this.transport.logout();
|
|
294
|
+
this.authenticated = false;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
exports.OdooClient = OdooClient;
|
|
298
|
+
//# sourceMappingURL=odoo-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odoo-client.js","sourceRoot":"","sources":["../../src/client/odoo-client.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAEH,gDAAqE;AACrE,4CAAiE;AACjE,sCAMmB;AACnB,gEAA4D;AAC5D,uEAAmE;AACnE,kFAA8E;AAC9E,kFAA8E;AAgB9E;;;;;GAKG;AACH,MAAa,UAAU;IACb,MAAM,CAAmB;IACzB,SAAS,CAAmB;IAC5B,aAAa,GAAG,KAAK,CAAC;IACtB,aAAa,CAAmC;IAExD,YAAY,MAAwB;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,IAAI,4BAAgB,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACnE,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACrC,CAAC;IAED,uEAAuE;IACvE,EAAE;IACF,iEAAiE;IACjE,gEAAgE;IAExD,KAAK,CAAe;IAE5B;;;;;;;OAOG;IACH,IAAI,IAAI;QACN,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,0BAAW,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;IAEO,QAAQ,CAAiB;IAEjC;;;;;;;OAOG;IACH,IAAI,OAAO;QACT,OAAO,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,8BAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,CAAC;IAEO,WAAW,CAAqB;IAExC;;;;;;;;;;OAUG;IACH,IAAI,UAAU;QACZ,OAAO,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,sCAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC;IAEO,WAAW,CAAqB;IAExC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,IAAI,UAAU;QACZ,OAAO,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,sCAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,uEAAuE;IAEvE;;;OAGG;IACH,gBAAgB,CAAC,GAAqC;QACpD,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9F,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;IACrC,CAAC;IAED,uEAAuE;IAEvE;;;OAGG;IACK,KAAK,CAAC,KAAK,CAAC,EAAiB;QACnC,MAAM,GAAG,GAAG,IAAA,6BAAoB,EAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrD,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,EAAE,CAAC,KAAK,KAAK,MAAM;YAAE,OAAO;QAEhC,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,wBAAe,CAAC,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,uEAAuE;IAEvE;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,IAAI,CACR,KAAa,EACb,MAAc,EACd,OAAc,EAAE,EAChB,SAA8B,EAAE,EAChC,OAAuC;QAEvC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,sBAAa,CAAC,sDAAsD,CAAC,CAAC;QAClF,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,EAAE,WAAW,IAAI,IAAA,yBAAgB,EAAC,MAAM,CAAC,CAAC;QAC/D,MAAM,IAAI,CAAC,KAAK,CAAC;YACf,IAAI,EAAE,QAAQ,MAAM,EAAE;YACtB,KAAK;YACL,KAAK;YACL,WAAW,EAAE,GAAG,KAAK,IAAI,MAAM,IAAI;YACnC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG;SACxB,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAI,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7D,CAAC;IAED,uEAAuE;IAEvE;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,CACV,KAAa,EACb,SAAgB,EAAE,EAClB,UAII,EAAE;QAEN,MAAM,MAAM,GAAwB,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QACjE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC9D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAE9D,OAAO,IAAI,CAAC,IAAI,CAAW,KAAK,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI,CACR,KAAa,EACb,GAAsB,EACtB,SAAmB,EAAE;QAErB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,IAAI,CAAM,KAAK,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,UAAU,CACd,KAAa,EACb,SAAgB,EAAE,EAClB,UAKI,EAAE;QAEN,MAAM,MAAM,GAAwB,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9D,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QACjC,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QACjE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC9D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAE9D,OAAO,IAAI,CAAC,IAAI,CAAM,KAAK,EAAE,aAAa,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,CACV,KAAa,EACb,MAA2B,EAC3B,UAA+B,EAAE;QAEjC,OAAO,IAAI,CAAC,IAAI,CAAS,KAAK,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,KAAK,CACT,KAAa,EACb,GAAsB,EACtB,MAA2B,EAC3B,UAA+B,EAAE;QAEjC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,IAAI,CAAU,KAAK,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,GAAsB;QAChD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,IAAI,CAAU,KAAK,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,WAAW,CAAC,KAAa,EAAE,SAAgB,EAAE;QACjD,OAAO,IAAI,CAAC,IAAI,CAAS,KAAK,EAAE,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QACxB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IAC7B,CAAC;CACF;AAlUD,gCAkUC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,UAAU,CAAC;AAGzB,cAAc,YAAY,CAAC;AAG3B,cAAc,OAAO,CAAC;AAGtB,cAAc,SAAS,CAAC;AAGxB,cAAc,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Core client, config, and factory
|
|
18
|
+
__exportStar(require("./client"), exports);
|
|
19
|
+
// Module services (mail, modules, etc.)
|
|
20
|
+
__exportStar(require("./services"), exports);
|
|
21
|
+
// RPC transport
|
|
22
|
+
__exportStar(require("./rpc"), exports);
|
|
23
|
+
// Types and errors
|
|
24
|
+
__exportStar(require("./types"), exports);
|
|
25
|
+
// Safety guards
|
|
26
|
+
__exportStar(require("./safety"), exports);
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mCAAmC;AACnC,2CAAyB;AAEzB,wCAAwC;AACxC,6CAA2B;AAE3B,gBAAgB;AAChB,wCAAsB;AAEtB,mBAAmB;AACnB,0CAAwB;AAExB,gBAAgB;AAChB,2CAAyB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JsonRpcTransport = void 0;
|
|
4
|
+
// RPC transport layer
|
|
5
|
+
var transport_1 = require("./transport");
|
|
6
|
+
Object.defineProperty(exports, "JsonRpcTransport", { enumerable: true, get: function () { return transport_1.JsonRpcTransport; } });
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":";;;AAAA,sBAAsB;AACtB,yCAKqB;AAJnB,6GAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC transport for Odoo
|
|
3
|
+
*
|
|
4
|
+
* Implements the JSON-RPC 2.0 protocol over HTTP for Odoo RPC calls
|
|
5
|
+
* Handles authentication, request/response formatting, and error parsing
|
|
6
|
+
*/
|
|
7
|
+
import { JsonRpcRequest, JsonRpcResponse, OdooSessionInfo } from './types';
|
|
8
|
+
export { JsonRpcRequest, JsonRpcResponse, OdooSessionInfo };
|
|
9
|
+
/**
|
|
10
|
+
* JSON-RPC transport client for Odoo
|
|
11
|
+
*
|
|
12
|
+
* Manages HTTP communication with Odoo using JSON-RPC protocol
|
|
13
|
+
*/
|
|
14
|
+
export declare class JsonRpcTransport {
|
|
15
|
+
private baseUrl;
|
|
16
|
+
private db;
|
|
17
|
+
private requestId;
|
|
18
|
+
private sessionInfo;
|
|
19
|
+
private password;
|
|
20
|
+
constructor(baseUrl: string, db: string);
|
|
21
|
+
/**
|
|
22
|
+
* Get the RPC endpoint URL
|
|
23
|
+
*/
|
|
24
|
+
private getRpcUrl;
|
|
25
|
+
/**
|
|
26
|
+
* Generate a unique request ID
|
|
27
|
+
*/
|
|
28
|
+
private nextRequestId;
|
|
29
|
+
/**
|
|
30
|
+
* Get current session info
|
|
31
|
+
*/
|
|
32
|
+
getSession(): OdooSessionInfo | null;
|
|
33
|
+
/**
|
|
34
|
+
* Authenticate with Odoo using JSON-RPC
|
|
35
|
+
*
|
|
36
|
+
* Calls the common.login RPC method via /jsonrpc endpoint
|
|
37
|
+
* Stores session info (uid, db) for future requests
|
|
38
|
+
*
|
|
39
|
+
* @see https://www.odoo.com/documentation/17.0/developer/howtos/web_services.html#json-rpc-library
|
|
40
|
+
*/
|
|
41
|
+
authenticate(username: string, password: string): Promise<OdooSessionInfo>;
|
|
42
|
+
/**
|
|
43
|
+
* Make an RPC call to Odoo
|
|
44
|
+
*
|
|
45
|
+
* Low-level method that sends JSON-RPC requests and parses responses
|
|
46
|
+
*/
|
|
47
|
+
callRpc<T = any>(method: string, params: Record<string, any>): Promise<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Categorize an Odoo RPC error into a specific error type.
|
|
50
|
+
*
|
|
51
|
+
* Checks exception_type first (more structured, Odoo 17+),
|
|
52
|
+
* then falls back to data.name (Python exception class name).
|
|
53
|
+
*
|
|
54
|
+
* @see https://github.com/odoo/odoo/blob/17.0/odoo/exceptions.py
|
|
55
|
+
*/
|
|
56
|
+
private categorizeError;
|
|
57
|
+
/**
|
|
58
|
+
* Call an Odoo model method via JSON-RPC
|
|
59
|
+
*
|
|
60
|
+
* Uses the object.execute_kw RPC method to call model methods with
|
|
61
|
+
* both positional arguments and keyword arguments (kwargs).
|
|
62
|
+
*
|
|
63
|
+
* @param model - Model name (e.g., 'res.partner')
|
|
64
|
+
* @param method - Method name (e.g., 'search', 'read', 'create')
|
|
65
|
+
* @param args - Positional arguments
|
|
66
|
+
* @param kwargs - Keyword arguments (includes context)
|
|
67
|
+
* @returns Method result
|
|
68
|
+
*
|
|
69
|
+
* @see https://www.odoo.com/documentation/17.0/developer/reference/external_api.html#calling-methods
|
|
70
|
+
*/
|
|
71
|
+
call<T = any>(model: string, method: string, args?: any[], kwargs?: Record<string, any>): Promise<T>;
|
|
72
|
+
/**
|
|
73
|
+
* Logout and clear session
|
|
74
|
+
*/
|
|
75
|
+
logout(): void;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=transport.d.ts.map
|