@marcfargas/odoo-client 0.1.0 → 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.
Files changed (41) hide show
  1. package/dist/client/odoo-client.d.ts +39 -0
  2. package/dist/client/odoo-client.d.ts.map +1 -1
  3. package/dist/client/odoo-client.js +43 -0
  4. package/dist/client/odoo-client.js.map +1 -1
  5. package/dist/services/attendance/attendance-service.d.ts +100 -0
  6. package/dist/services/attendance/attendance-service.d.ts.map +1 -0
  7. package/dist/services/attendance/attendance-service.js +113 -0
  8. package/dist/services/attendance/attendance-service.js.map +1 -0
  9. package/dist/services/attendance/functions.d.ts +72 -0
  10. package/dist/services/attendance/functions.d.ts.map +1 -0
  11. package/dist/services/attendance/functions.js +169 -0
  12. package/dist/services/attendance/functions.js.map +1 -0
  13. package/dist/services/attendance/index.d.ts +4 -0
  14. package/dist/services/attendance/index.d.ts.map +1 -0
  15. package/dist/services/attendance/index.js +12 -0
  16. package/dist/services/attendance/index.js.map +1 -0
  17. package/dist/services/attendance/types.d.ts +53 -0
  18. package/dist/services/attendance/types.d.ts.map +1 -0
  19. package/dist/services/attendance/types.js +8 -0
  20. package/dist/services/attendance/types.js.map +1 -0
  21. package/dist/services/index.d.ts +2 -0
  22. package/dist/services/index.d.ts.map +1 -1
  23. package/dist/services/index.js +2 -0
  24. package/dist/services/index.js.map +1 -1
  25. package/dist/services/timesheets/functions.d.ts +75 -0
  26. package/dist/services/timesheets/functions.d.ts.map +1 -0
  27. package/dist/services/timesheets/functions.js +220 -0
  28. package/dist/services/timesheets/functions.js.map +1 -0
  29. package/dist/services/timesheets/index.d.ts +4 -0
  30. package/dist/services/timesheets/index.d.ts.map +1 -0
  31. package/dist/services/timesheets/index.js +12 -0
  32. package/dist/services/timesheets/index.js.map +1 -0
  33. package/dist/services/timesheets/timesheets-service.d.ts +121 -0
  34. package/dist/services/timesheets/timesheets-service.d.ts.map +1 -0
  35. package/dist/services/timesheets/timesheets-service.js +136 -0
  36. package/dist/services/timesheets/timesheets-service.js.map +1 -0
  37. package/dist/services/timesheets/types.d.ts +81 -0
  38. package/dist/services/timesheets/types.d.ts.map +1 -0
  39. package/dist/services/timesheets/types.js +10 -0
  40. package/dist/services/timesheets/types.js.map +1 -0
  41. package/package.json +1 -1
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Types for hr.attendance service.
3
+ *
4
+ * @see https://github.com/odoo/odoo/blob/17.0/addons/hr_attendance/models/hr_attendance.py
5
+ */
6
+ /**
7
+ * Raw hr.attendance record as returned by Odoo read/search_read.
8
+ *
9
+ * Key fields:
10
+ * - check_in: always set when record exists
11
+ * - check_out: null/false when the employee is still checked in
12
+ * - worked_hours: computed from check_in/check_out (0 when still checked in)
13
+ */
14
+ export interface AttendanceRecord {
15
+ id: number;
16
+ /** Many2one → hr.employee: [id, display_name] */
17
+ employee_id: [number, string] | false;
18
+ /** Datetime string (UTC): when the employee checked in */
19
+ check_in: string;
20
+ /** Datetime string (UTC) or false: when the employee checked out */
21
+ check_out: string | false;
22
+ /** Computed: hours worked (check_out - check_in), 0 if still checked in */
23
+ worked_hours: number;
24
+ }
25
+ /**
26
+ * Options for listing attendance records.
27
+ */
28
+ export interface AttendanceListOptions {
29
+ /** Filter by employee ID */
30
+ employeeId?: number;
31
+ /** Start date (inclusive, YYYY-MM-DD) */
32
+ dateFrom?: string;
33
+ /** End date (inclusive, YYYY-MM-DD) */
34
+ dateTo?: string;
35
+ /** Max records to return */
36
+ limit?: number;
37
+ /** Offset for pagination */
38
+ offset?: number;
39
+ /** Sort order (default: 'check_in desc') */
40
+ order?: string;
41
+ }
42
+ /**
43
+ * Attendance status for an employee.
44
+ */
45
+ export interface AttendanceStatus {
46
+ /** Whether the employee is currently checked in */
47
+ checkedIn: boolean;
48
+ /** The current (open) attendance record, or null if checked out */
49
+ currentAttendance: AttendanceRecord | null;
50
+ /** Employee info: [id, display_name] */
51
+ employee: [number, string];
52
+ }
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/attendance/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;IACtC,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,iBAAiB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC3C,wCAAwC;IACxC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Types for hr.attendance service.
4
+ *
5
+ * @see https://github.com/odoo/odoo/blob/17.0/addons/hr_attendance/models/hr_attendance.py
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/attendance/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG"}
@@ -19,4 +19,6 @@
19
19
  */
20
20
  export * from './mail';
21
21
  export * from './modules';
22
+ export * from './attendance';
23
+ export * from './timesheets';
22
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC"}
@@ -35,4 +35,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  __exportStar(require("./mail"), exports);
37
37
  __exportStar(require("./modules"), exports);
38
+ __exportStar(require("./attendance"), exports);
39
+ __exportStar(require("./timesheets"), exports);
38
40
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;;;;;;;;;;;;;;AAEH,yCAAuB;AACvB,4CAA0B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;;;;;;;;;;;;;;AAEH,yCAAuB;AACvB,4CAA0B;AAC1B,+CAA6B;AAC7B,+CAA6B"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Timesheet standalone functions — timer start/stop and time logging.
3
+ *
4
+ * Timer concept in Odoo timesheets is simple:
5
+ * - A running clock = account.analytic.line with unit_amount = 0 (no duration)
6
+ * - A stopped clock = account.analytic.line with unit_amount > 0 (duration filled)
7
+ *
8
+ * This is standard hr_timesheet behavior. The OCA module
9
+ * `project_timesheet_time_control` adds UI buttons for this workflow,
10
+ * but the data model needs nothing beyond the base module.
11
+ *
12
+ * We use create_date to compute elapsed time when stopping a timer.
13
+ *
14
+ * @see https://github.com/odoo/odoo/blob/17.0/addons/hr_timesheet/models/account_analytic_line.py
15
+ * @see https://github.com/OCA/project/tree/17.0/project_timesheet_time_control
16
+ */
17
+ import type { OdooClient } from '../../client/odoo-client';
18
+ import type { TimesheetEntry, TimerStartOptions, LogTimeOptions, TimesheetListOptions } from './types';
19
+ /**
20
+ * Start a timesheet timer — creates a line with no duration.
21
+ *
22
+ * An entry with unit_amount = 0 represents a running clock.
23
+ * Call stopTimer() to compute elapsed time and fill in the duration.
24
+ *
25
+ * @param client - Authenticated OdooClient
26
+ * @param options - Timer options (description, projectId, optional taskId/employeeId)
27
+ * @returns The created timesheet entry (unit_amount = 0)
28
+ *
29
+ * @throws OdooValidationError if description or projectId missing
30
+ */
31
+ export declare function startTimer(client: OdooClient, options: TimerStartOptions): Promise<TimesheetEntry>;
32
+ /**
33
+ * Stop a running timesheet timer.
34
+ *
35
+ * Computes elapsed time from create_date to now and writes unit_amount.
36
+ * After this call, the entry has unit_amount > 0 (closed).
37
+ *
38
+ * @param client - Authenticated OdooClient
39
+ * @param timesheetId - ID of the timesheet entry to stop (must have unit_amount = 0)
40
+ * @returns The updated timesheet entry with duration filled in
41
+ *
42
+ * @throws OdooValidationError if the entry already has a duration
43
+ */
44
+ export declare function stopTimer(client: OdooClient, timesheetId: number): Promise<TimesheetEntry>;
45
+ /**
46
+ * Find running timers for an employee.
47
+ *
48
+ * Running timers are timesheet entries with unit_amount = 0.
49
+ *
50
+ * @param client - Authenticated OdooClient
51
+ * @param employeeId - Employee ID (omit for current user's employee)
52
+ * @returns Array of timesheet entries with unit_amount = 0
53
+ */
54
+ export declare function getRunningTimers(client: OdooClient, employeeId?: number): Promise<TimesheetEntry[]>;
55
+ /**
56
+ * Log a completed timesheet entry (no timer, just hours).
57
+ *
58
+ * Creates an account.analytic.line with unit_amount already set.
59
+ *
60
+ * @param client - Authenticated OdooClient
61
+ * @param options - Time log options
62
+ * @returns The created timesheet entry
63
+ *
64
+ * @throws OdooValidationError if required fields missing or hours <= 0
65
+ */
66
+ export declare function logTime(client: OdooClient, options: LogTimeOptions): Promise<TimesheetEntry>;
67
+ /**
68
+ * List timesheet entries with optional filters.
69
+ *
70
+ * @param client - Authenticated OdooClient
71
+ * @param options - Filter and pagination options
72
+ * @returns Array of timesheet entries
73
+ */
74
+ export declare function listTimesheets(client: OdooClient, options?: TimesheetListOptions): Promise<TimesheetEntry[]>;
75
+ //# sourceMappingURL=functions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/services/timesheets/functions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAG3D,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAsBjB;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,cAAc,CAAC,CAiCzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA2ChG;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,UAAU,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,EAAE,CAAC,CAgB3B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,cAAc,CAAC,CAkCzB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,cAAc,EAAE,CAAC,CAmC3B"}
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ /**
3
+ * Timesheet standalone functions — timer start/stop and time logging.
4
+ *
5
+ * Timer concept in Odoo timesheets is simple:
6
+ * - A running clock = account.analytic.line with unit_amount = 0 (no duration)
7
+ * - A stopped clock = account.analytic.line with unit_amount > 0 (duration filled)
8
+ *
9
+ * This is standard hr_timesheet behavior. The OCA module
10
+ * `project_timesheet_time_control` adds UI buttons for this workflow,
11
+ * but the data model needs nothing beyond the base module.
12
+ *
13
+ * We use create_date to compute elapsed time when stopping a timer.
14
+ *
15
+ * @see https://github.com/odoo/odoo/blob/17.0/addons/hr_timesheet/models/account_analytic_line.py
16
+ * @see https://github.com/OCA/project/tree/17.0/project_timesheet_time_control
17
+ */
18
+ var __importDefault = (this && this.__importDefault) || function (mod) {
19
+ return (mod && mod.__esModule) ? mod : { "default": mod };
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.startTimer = startTimer;
23
+ exports.stopTimer = stopTimer;
24
+ exports.getRunningTimers = getRunningTimers;
25
+ exports.logTime = logTime;
26
+ exports.listTimesheets = listTimesheets;
27
+ const debug_1 = __importDefault(require("debug"));
28
+ const errors_1 = require("../../types/errors");
29
+ const functions_1 = require("../attendance/functions");
30
+ const log = (0, debug_1.default)('odoo-client:timesheets');
31
+ /** Fields we always fetch for timesheet entries. */
32
+ const TIMESHEET_FIELDS = [
33
+ 'name',
34
+ 'date',
35
+ 'unit_amount',
36
+ 'project_id',
37
+ 'task_id',
38
+ 'employee_id',
39
+ 'create_date',
40
+ ];
41
+ /**
42
+ * Get the current date as YYYY-MM-DD.
43
+ */
44
+ function today() {
45
+ return new Date().toISOString().split('T')[0];
46
+ }
47
+ /**
48
+ * Start a timesheet timer — creates a line with no duration.
49
+ *
50
+ * An entry with unit_amount = 0 represents a running clock.
51
+ * Call stopTimer() to compute elapsed time and fill in the duration.
52
+ *
53
+ * @param client - Authenticated OdooClient
54
+ * @param options - Timer options (description, projectId, optional taskId/employeeId)
55
+ * @returns The created timesheet entry (unit_amount = 0)
56
+ *
57
+ * @throws OdooValidationError if description or projectId missing
58
+ */
59
+ async function startTimer(client, options) {
60
+ if (!options.description?.trim()) {
61
+ throw new errors_1.OdooValidationError('Timesheet description is required. Describe the work being done.');
62
+ }
63
+ if (!options.projectId) {
64
+ throw new errors_1.OdooValidationError('Project ID is required for timesheet entries. ' +
65
+ 'The project must have allow_timesheets = true.');
66
+ }
67
+ const empId = await (0, functions_1.resolveEmployeeId)(client, options.employeeId);
68
+ log('Starting timer for employee %d on project %d', empId, options.projectId);
69
+ const values = {
70
+ name: options.description.trim(),
71
+ project_id: options.projectId,
72
+ employee_id: empId,
73
+ unit_amount: 0,
74
+ date: today(),
75
+ };
76
+ if (options.taskId) {
77
+ values.task_id = options.taskId;
78
+ }
79
+ const id = await client.create('account.analytic.line', values);
80
+ log('Created timesheet entry %d with unit_amount=0 (running)', id);
81
+ const [entry] = await client.read('account.analytic.line', id, TIMESHEET_FIELDS);
82
+ return entry;
83
+ }
84
+ /**
85
+ * Stop a running timesheet timer.
86
+ *
87
+ * Computes elapsed time from create_date to now and writes unit_amount.
88
+ * After this call, the entry has unit_amount > 0 (closed).
89
+ *
90
+ * @param client - Authenticated OdooClient
91
+ * @param timesheetId - ID of the timesheet entry to stop (must have unit_amount = 0)
92
+ * @returns The updated timesheet entry with duration filled in
93
+ *
94
+ * @throws OdooValidationError if the entry already has a duration
95
+ */
96
+ async function stopTimer(client, timesheetId) {
97
+ log('Stopping timer on entry %d', timesheetId);
98
+ const [entry] = await client.read('account.analytic.line', timesheetId, TIMESHEET_FIELDS);
99
+ if (entry.unit_amount !== 0) {
100
+ throw new errors_1.OdooValidationError(`Timesheet entry ${timesheetId} is not a running timer ` +
101
+ `(unit_amount = ${entry.unit_amount}). ` +
102
+ 'Only entries with unit_amount = 0 can be stopped.');
103
+ }
104
+ // Compute elapsed time from create_date
105
+ const createDate = entry.create_date;
106
+ if (!createDate) {
107
+ throw new errors_1.OdooValidationError(`Cannot determine start time for entry ${timesheetId}: create_date not available.`);
108
+ }
109
+ const startMs = new Date(createDate.replace(' ', 'T') + 'Z').getTime();
110
+ const nowMs = Date.now();
111
+ const elapsedHours = Math.max(0, (nowMs - startMs) / (1000 * 60 * 60));
112
+ // Round to 2 decimal places, minimum 0.01 (36s) to avoid staying at 0 (= "running")
113
+ const roundedHours = Math.max(0.01, Math.round(elapsedHours * 100) / 100);
114
+ await client.write('account.analytic.line', timesheetId, {
115
+ unit_amount: roundedHours,
116
+ });
117
+ log('Timer stopped on entry %d: %.2f hours (from %s)', timesheetId, roundedHours, createDate);
118
+ const [updated] = await client.read('account.analytic.line', timesheetId, TIMESHEET_FIELDS);
119
+ return updated;
120
+ }
121
+ /**
122
+ * Find running timers for an employee.
123
+ *
124
+ * Running timers are timesheet entries with unit_amount = 0.
125
+ *
126
+ * @param client - Authenticated OdooClient
127
+ * @param employeeId - Employee ID (omit for current user's employee)
128
+ * @returns Array of timesheet entries with unit_amount = 0
129
+ */
130
+ async function getRunningTimers(client, employeeId) {
131
+ const empId = await (0, functions_1.resolveEmployeeId)(client, employeeId);
132
+ log('Looking for running timers for employee %d', empId);
133
+ return client.searchRead('account.analytic.line', [
134
+ ['employee_id', '=', empId],
135
+ ['unit_amount', '=', 0],
136
+ ['project_id', '!=', false],
137
+ ], {
138
+ fields: TIMESHEET_FIELDS,
139
+ order: 'create_date desc',
140
+ });
141
+ }
142
+ /**
143
+ * Log a completed timesheet entry (no timer, just hours).
144
+ *
145
+ * Creates an account.analytic.line with unit_amount already set.
146
+ *
147
+ * @param client - Authenticated OdooClient
148
+ * @param options - Time log options
149
+ * @returns The created timesheet entry
150
+ *
151
+ * @throws OdooValidationError if required fields missing or hours <= 0
152
+ */
153
+ async function logTime(client, options) {
154
+ if (!options.description?.trim()) {
155
+ throw new errors_1.OdooValidationError('Timesheet description is required. Describe the work done.');
156
+ }
157
+ if (!options.projectId) {
158
+ throw new errors_1.OdooValidationError('Project ID is required for timesheet entries.');
159
+ }
160
+ if (!options.hours || options.hours <= 0) {
161
+ throw new errors_1.OdooValidationError(`Hours must be greater than 0 (got: ${options.hours}). ` +
162
+ 'Use startTimer() for entries where duration is unknown.');
163
+ }
164
+ const empId = await (0, functions_1.resolveEmployeeId)(client, options.employeeId);
165
+ log('Logging %f hours for employee %d on project %d', options.hours, empId, options.projectId);
166
+ const values = {
167
+ name: options.description.trim(),
168
+ project_id: options.projectId,
169
+ employee_id: empId,
170
+ unit_amount: options.hours,
171
+ date: options.date ?? today(),
172
+ };
173
+ if (options.taskId) {
174
+ values.task_id = options.taskId;
175
+ }
176
+ const id = await client.create('account.analytic.line', values);
177
+ log('Logged timesheet entry %d: %f hours', id, options.hours);
178
+ const [entry] = await client.read('account.analytic.line', id, TIMESHEET_FIELDS);
179
+ return entry;
180
+ }
181
+ /**
182
+ * List timesheet entries with optional filters.
183
+ *
184
+ * @param client - Authenticated OdooClient
185
+ * @param options - Filter and pagination options
186
+ * @returns Array of timesheet entries
187
+ */
188
+ async function listTimesheets(client, options = {}) {
189
+ const domain = [];
190
+ if (options.employeeId) {
191
+ domain.push(['employee_id', '=', options.employeeId]);
192
+ }
193
+ if (options.projectId) {
194
+ domain.push(['project_id', '=', options.projectId]);
195
+ }
196
+ if (options.taskId) {
197
+ domain.push(['task_id', '=', options.taskId]);
198
+ }
199
+ if (options.dateFrom) {
200
+ domain.push(['date', '>=', options.dateFrom]);
201
+ }
202
+ if (options.dateTo) {
203
+ domain.push(['date', '<=', options.dateTo]);
204
+ }
205
+ if (options.runningOnly) {
206
+ domain.push(['unit_amount', '=', 0]);
207
+ }
208
+ // Ensure we only get timesheet lines (not generic analytic lines)
209
+ if (!options.projectId) {
210
+ domain.push(['project_id', '!=', false]);
211
+ }
212
+ log('Listing timesheets with domain: %o', domain);
213
+ return client.searchRead('account.analytic.line', domain, {
214
+ fields: TIMESHEET_FIELDS,
215
+ limit: options.limit,
216
+ offset: options.offset,
217
+ order: options.order ?? 'date desc, id desc',
218
+ });
219
+ }
220
+ //# sourceMappingURL=functions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.js","sourceRoot":"","sources":["../../../src/services/timesheets/functions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { TimesheetsService } from './timesheets-service';
2
+ export { startTimer, stopTimer, getRunningTimers, logTime, listTimesheets } from './functions';
3
+ export type { TimesheetEntry, TimerStartOptions, LogTimeOptions, TimesheetListOptions, } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/timesheets/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/F,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,oBAAoB,GACrB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listTimesheets = exports.logTime = exports.getRunningTimers = exports.stopTimer = exports.startTimer = exports.TimesheetsService = void 0;
4
+ var timesheets_service_1 = require("./timesheets-service");
5
+ Object.defineProperty(exports, "TimesheetsService", { enumerable: true, get: function () { return timesheets_service_1.TimesheetsService; } });
6
+ var functions_1 = require("./functions");
7
+ Object.defineProperty(exports, "startTimer", { enumerable: true, get: function () { return functions_1.startTimer; } });
8
+ Object.defineProperty(exports, "stopTimer", { enumerable: true, get: function () { return functions_1.stopTimer; } });
9
+ Object.defineProperty(exports, "getRunningTimers", { enumerable: true, get: function () { return functions_1.getRunningTimers; } });
10
+ Object.defineProperty(exports, "logTime", { enumerable: true, get: function () { return functions_1.logTime; } });
11
+ Object.defineProperty(exports, "listTimesheets", { enumerable: true, get: function () { return functions_1.listTimesheets; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/timesheets/index.ts"],"names":[],"mappings":";;;AAAA,2DAAyD;AAAhD,uHAAA,iBAAiB,OAAA;AAC1B,yCAA+F;AAAtF,uGAAA,UAAU,OAAA;AAAE,sGAAA,SAAS,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AAAE,oGAAA,OAAO,OAAA;AAAE,2GAAA,cAAc,OAAA"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Timesheets service — the typed interface exposed via `client.timesheets.*`
3
+ *
4
+ * Delegates to standalone functions in functions.ts.
5
+ *
6
+ * Timer concept: unit_amount = 0 means running, unit_amount > 0 means closed.
7
+ * This is standard hr_timesheet behavior — no extra modules needed.
8
+ *
9
+ * Requires the `hr_timesheet` module to be installed.
10
+ *
11
+ * @see https://github.com/odoo/odoo/blob/17.0/addons/hr_timesheet/models/account_analytic_line.py
12
+ */
13
+ import type { OdooClient } from '../../client/odoo-client';
14
+ import type { TimesheetEntry, TimerStartOptions, LogTimeOptions, TimesheetListOptions } from './types';
15
+ /**
16
+ * Timesheets service for managing time tracking on projects and tasks.
17
+ *
18
+ * Access via `client.timesheets` — never instantiate directly.
19
+ *
20
+ * Two workflows:
21
+ * 1. **Timer-based**: startTimer() → work → stopTimer() (duration auto-computed)
22
+ * 2. **Manual**: logTime() with known hours (e.g., logging past work)
23
+ *
24
+ * All methods accept an optional employeeId. When omitted, the current
25
+ * user's linked hr.employee record is used automatically.
26
+ */
27
+ export declare class TimesheetsService {
28
+ private client;
29
+ /** @internal */
30
+ constructor(client: OdooClient);
31
+ /**
32
+ * Start a timesheet timer.
33
+ *
34
+ * Creates a timesheet entry and starts the clock. Duration is tracked
35
+ * automatically until stopTimer() is called.
36
+ *
37
+ * @param options - Description, projectId, optional taskId/employeeId
38
+ * @returns The created timesheet entry with timer running
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const entry = await client.timesheets.startTimer({
43
+ * description: 'Implementing login feature',
44
+ * projectId: 5,
45
+ * taskId: 42,
46
+ * });
47
+ * console.log(`Timer started: ${entry.id}`);
48
+ * ```
49
+ */
50
+ startTimer(options: TimerStartOptions): Promise<TimesheetEntry>;
51
+ /**
52
+ * Stop a running timesheet timer.
53
+ *
54
+ * Computes the elapsed time and saves it to the entry's unit_amount.
55
+ *
56
+ * @param timesheetId - ID of the timesheet entry with a running timer
57
+ * @returns The updated entry with hours filled in
58
+ * @throws OdooValidationError if no running timer on this entry
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const entry = await client.timesheets.stopTimer(123);
63
+ * console.log(`Logged ${entry.unit_amount.toFixed(2)} hours`);
64
+ * ```
65
+ */
66
+ stopTimer(timesheetId: number): Promise<TimesheetEntry>;
67
+ /**
68
+ * Find all running timers for an employee.
69
+ *
70
+ * @param employeeId - Employee ID (omit for current user's employee)
71
+ * @returns Array of entries with running timers (usually 0 or 1)
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const running = await client.timesheets.getRunningTimers();
76
+ * if (running.length > 0) {
77
+ * console.log(`Timer running since ${running[0].timer_start}`);
78
+ * }
79
+ * ```
80
+ */
81
+ getRunningTimers(employeeId?: number): Promise<TimesheetEntry[]>;
82
+ /**
83
+ * Log a completed timesheet entry with known hours.
84
+ *
85
+ * Use this when you know the duration (no timer needed).
86
+ *
87
+ * @param options - Description, projectId, hours, optional taskId/date/employeeId
88
+ * @returns The created timesheet entry
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const entry = await client.timesheets.logTime({
93
+ * description: 'Code review for PR #42',
94
+ * projectId: 5,
95
+ * taskId: 42,
96
+ * hours: 1.5,
97
+ * });
98
+ * ```
99
+ */
100
+ logTime(options: LogTimeOptions): Promise<TimesheetEntry>;
101
+ /**
102
+ * List timesheet entries with optional filters.
103
+ *
104
+ * @param options - Filter by employee, project, task, date range, etc.
105
+ * @returns Array of timesheet entries
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * // This week's timesheets
110
+ * const entries = await client.timesheets.list({
111
+ * dateFrom: '2026-02-09',
112
+ * dateTo: '2026-02-15',
113
+ * employeeId: 42,
114
+ * });
115
+ * const total = entries.reduce((sum, e) => sum + e.unit_amount, 0);
116
+ * console.log(`Total: ${total.toFixed(2)} hours`);
117
+ * ```
118
+ */
119
+ list(options?: TimesheetListOptions): Promise<TimesheetEntry[]>;
120
+ }
121
+ //# sourceMappingURL=timesheets-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timesheets-service.d.ts","sourceRoot":"","sources":["../../../src/services/timesheets/timesheets-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACrB,MAAM,SAAS,CAAC;AASjB;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAiB;IAEhB,OAAO,CAAC,MAAM;IAD1B,gBAAgB;gBACI,MAAM,EAAE,UAAU;IAEtC;;;;;;;;;;;;;;;;;;OAkBG;IACG,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IAIrE;;;;;;;;;;;;;;OAcG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAI7D;;;;;;;;;;;;;OAaG;IACG,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAItE;;;;;;;;;;;;;;;;;OAiBG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IAI/D;;;;;;;;;;;;;;;;;OAiBG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;CAGtE"}