@bergetai/odoo-cli 0.6.1 → 0.7.1
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/README.md +2 -1
- package/dist/cli.js +6 -2
- package/dist/commands/notes.js +27 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,7 @@ odoo crm teams delete 5 --dry-run
|
|
|
57
57
|
# Internal notes (NEVER sends email to customer)
|
|
58
58
|
odoo helpdesk tickets add-note 398 --body "Internal note text"
|
|
59
59
|
odoo helpdesk tickets add-note 398 --body-file note.md
|
|
60
|
+
odoo crm records add-note 338 --body "Customer replied: ..." --author 40
|
|
60
61
|
|
|
61
62
|
# Log note correction (message-update / message-delete; comment-type only)
|
|
62
63
|
odoo crm records message-update 270799 --body-file fixed.html --dry-run
|
|
@@ -80,7 +81,7 @@ Note: `odoo --version` prints the CLI's own version; `odoo version` queries the
|
|
|
80
81
|
- Documents surface (`documents`) — `tree` (hierarchical folder listing with `--count`/`--depth`/`--folder`), `records list/show` (folders excluded by default, `--type folder|binary|url|all`, `--folder`/`--owner`/`--partner`/`--tag`), `folders list`, `records create` (folder via `--folder-type folder`, link via `--link <url>`), `records update` (move via `--folder`), `records delete`, and `upload` (local file → base64 `datas`, MIME guessed from extension, `--dry-run` previews without sending bytes). Folders are `documents.document` rows with `type='folder'`; the hierarchy is `folder_id`. Module-not-installed error (exit 4)
|
|
81
82
|
- Writes (`create`, `update`, `delete`) — single-call atomic batch `write`, client-side no-op diffing, delete convergence with `skipped` ids, post-failure "record may have been created" hint on `create`
|
|
82
83
|
- `--dry-run` for all mutations — full validation, resolution, and before/after diffs without mutating
|
|
83
|
-
- Internal notes (`add-note`) — creates internal Log Notes only (subtype_id=2, message_type=comment), **NEVER sends email to customer**, by design prevents accidental customer communication
|
|
84
|
+
- Internal notes (`add-note`) — creates internal Log Notes only (subtype_id=2, message_type=comment), **NEVER sends email to customer**, by design prevents accidental customer communication. Optional `--author <email|name|id>` attributes the note to the partner who actually sent the logged message (resolved via `res.partner`; ambiguous matches list candidates and never guess)
|
|
84
85
|
- Log note correction (`message-update`, `message-delete`) — repair formatting or remove duplicate log notes; strictly limited to comment-type messages (emails/notifications refused by design), full `--dry-run` support, unknown delete ids skipped
|
|
85
86
|
- Config sources and precedence with atomic `0600` config writes, XML-RPC transport with timeouts and HTTPS enforcement, and an auth failure taxonomy (db missing / bad credentials / unreachable)
|
|
86
87
|
|
package/dist/cli.js
CHANGED
|
@@ -139,6 +139,7 @@ Examples:
|
|
|
139
139
|
.argument("<id>", "record id")
|
|
140
140
|
.option("--body <text>", "note body (HTML allowed)")
|
|
141
141
|
.option("--body-file <path>", "read note body from file ('-' for stdin)")
|
|
142
|
+
.option("--author <email|name|id>", "note author (res.partner; default: your own partner)")
|
|
142
143
|
.addHelpText("after", `
|
|
143
144
|
IMPORTANT: This command creates INTERNAL notes only. These notes:
|
|
144
145
|
• Are NEVER sent to the customer via email
|
|
@@ -151,7 +152,8 @@ This is by design to prevent accidental customer emails.
|
|
|
151
152
|
Examples:
|
|
152
153
|
$ odoo crm records add-note 338 --body "Internal note text"
|
|
153
154
|
$ odoo crm records add-note 338 --body-file note.md
|
|
154
|
-
$ cat note.md | odoo crm records add-note 338 --body-file
|
|
155
|
+
$ cat note.md | odoo crm records add-note 338 --body-file -
|
|
156
|
+
$ odoo crm records add-note 338 --body "Kundens svar: ..." --author andreas@berget.ai`)
|
|
155
157
|
.action(async (id, opts) => {
|
|
156
158
|
await run((g) => addNoteCommand(id, opts, g, "crm.lead"), program);
|
|
157
159
|
});
|
|
@@ -391,6 +393,7 @@ the raw form.`)
|
|
|
391
393
|
.argument("<id>", "ticket id")
|
|
392
394
|
.option("--body <text>", "note body (HTML allowed)")
|
|
393
395
|
.option("--body-file <path>", "read note body from file ('-' for stdin)")
|
|
396
|
+
.option("--author <email|name|id>", "note author (res.partner; default: your own partner)")
|
|
394
397
|
.addHelpText("after", `
|
|
395
398
|
IMPORTANT: This command creates INTERNAL notes only. These notes:
|
|
396
399
|
• Are NEVER sent to the customer via email
|
|
@@ -403,7 +406,8 @@ This is by design to prevent accidental customer emails.
|
|
|
403
406
|
Examples:
|
|
404
407
|
$ odoo helpdesk tickets add-note 398 --body "Internal note text"
|
|
405
408
|
$ odoo helpdesk tickets add-note 398 --body-file note.md
|
|
406
|
-
$ cat note.md | odoo helpdesk tickets add-note 398 --body-file
|
|
409
|
+
$ cat note.md | odoo helpdesk tickets add-note 398 --body-file -
|
|
410
|
+
$ odoo helpdesk tickets add-note 398 --body "Kundens svar: ..." --author kund@example.com`)
|
|
407
411
|
.action(async (id, opts) => {
|
|
408
412
|
await run((g) => addNoteCommand(id, opts, g, "helpdesk.ticket"), program);
|
|
409
413
|
});
|
package/dist/commands/notes.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { OdooClient } from "../client.js";
|
|
2
2
|
import { resolveConfig } from "../config.js";
|
|
3
3
|
import { notFoundError, usageError } from "../errors.js";
|
|
4
|
+
import { resolveReference } from "../model.js";
|
|
4
5
|
import { printJson, verbose as logVerbose } from "../output.js";
|
|
5
6
|
import { formatTable } from "../table.js";
|
|
6
7
|
const THREAD_MODELS = {
|
|
@@ -55,6 +56,21 @@ export async function addNoteCommand(recordId, opts, globals, model) {
|
|
|
55
56
|
if (!rows || rows.length === 0) {
|
|
56
57
|
throw notFoundError("record_not_found", `${spec.model} #${id} does not exist`, `check the ${spec.label} id`);
|
|
57
58
|
}
|
|
59
|
+
// Optional: attribute the note to the person who actually sent the
|
|
60
|
+
// logged message (e.g. a forwarded customer email). author_id is a
|
|
61
|
+
// res.partner — resolve by exact email, name, or numeric id. Without
|
|
62
|
+
// --author Odoo defaults to the authenticated user's partner.
|
|
63
|
+
let author;
|
|
64
|
+
if (opts.author) {
|
|
65
|
+
author = await resolveReference(client, "res.partner", opts.author, {
|
|
66
|
+
label: "author",
|
|
67
|
+
searchFields: ["name"],
|
|
68
|
+
exactFields: ["email"],
|
|
69
|
+
});
|
|
70
|
+
if (globals.verbose) {
|
|
71
|
+
logVerbose(`resolved --author "${opts.author}" -> [${author.id}, "${author.name}"]`, globals.verbose);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
58
74
|
// Create internal Log Note
|
|
59
75
|
// CRITICAL: These parameters ensure the note is INTERNAL ONLY
|
|
60
76
|
// - subtype_id=2: "Note" subtype (internal, not sent to customer)
|
|
@@ -66,6 +82,9 @@ export async function addNoteCommand(recordId, opts, globals, model) {
|
|
|
66
82
|
message_type: "comment",
|
|
67
83
|
subtype_id: 2, // Note subtype = internal only, NEVER sends email
|
|
68
84
|
};
|
|
85
|
+
if (author) {
|
|
86
|
+
noteParams.author_id = author.id;
|
|
87
|
+
}
|
|
69
88
|
if (globals.verbose) {
|
|
70
89
|
logVerbose(`Creating internal note for ${spec.model} #${id} (${rows[0].name})`, globals.verbose);
|
|
71
90
|
logVerbose(`Note parameters: ${JSON.stringify(noteParams, null, 2)}`, globals.verbose);
|
|
@@ -78,6 +97,7 @@ export async function addNoteCommand(recordId, opts, globals, model) {
|
|
|
78
97
|
record_name: rows[0].name,
|
|
79
98
|
note_type: "internal_log_note",
|
|
80
99
|
will_send_email: false,
|
|
100
|
+
author: author ? { id: author.id, name: author.name } : null,
|
|
81
101
|
body_preview: body.substring(0, 100) + (body.length > 100 ? "..." : ""),
|
|
82
102
|
body_length: body.length,
|
|
83
103
|
};
|
|
@@ -88,6 +108,9 @@ export async function addNoteCommand(recordId, opts, globals, model) {
|
|
|
88
108
|
console.log(`[DRY RUN] Would create internal Log Note:`);
|
|
89
109
|
console.log(` Record: ${spec.model} #${id} — ${rows[0].name}`);
|
|
90
110
|
console.log(` Type: Internal note (never sent to customer)`);
|
|
111
|
+
if (author) {
|
|
112
|
+
console.log(` Author: ${author.name} (${author.id})`);
|
|
113
|
+
}
|
|
91
114
|
console.log(` Body length: ${body.length} characters`);
|
|
92
115
|
console.log(` Body preview: ${result.body_preview}`);
|
|
93
116
|
}
|
|
@@ -103,6 +126,7 @@ export async function addNoteCommand(recordId, opts, globals, model) {
|
|
|
103
126
|
record_name: rows[0].name,
|
|
104
127
|
note_type: "internal_log_note",
|
|
105
128
|
email_sent: false,
|
|
129
|
+
author: author ? { id: author.id, name: author.name } : null,
|
|
106
130
|
};
|
|
107
131
|
if (globals.json) {
|
|
108
132
|
printJson(result);
|
|
@@ -111,6 +135,9 @@ export async function addNoteCommand(recordId, opts, globals, model) {
|
|
|
111
135
|
console.log(`✓ Internal Log Note created (ID: ${noteId})`);
|
|
112
136
|
console.log(` Record: ${spec.model} #${id} — ${rows[0].name}`);
|
|
113
137
|
console.log(` Type: Internal note (not sent to customer)`);
|
|
138
|
+
if (author) {
|
|
139
|
+
console.log(` Author: ${author.name} (${author.id})`);
|
|
140
|
+
}
|
|
114
141
|
}
|
|
115
142
|
}
|
|
116
143
|
/**
|