Skip to content

Commit

Permalink
imp: command exportfile: xml + fix: search, read: --read-binary
Browse files Browse the repository at this point in the history
  • Loading branch information
Tardo committed Nov 24, 2024
1 parent 7d56409 commit fe7d6b2
Show file tree
Hide file tree
Showing 16 changed files with 236 additions and 69 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

```
IMP: Command 'exportfile': Add CSV format [RFC-4180] (issue #138)
IMP: Command 'exportfile': Add XML odoo format
IMP: Interpreter: Add unknown lexer type (issue $139)
FIX: Command 'search', 'read': --read-binary
```

**11.6.0**
Expand Down
2 changes: 2 additions & 0 deletions _locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,15 @@
},
"cmdExportFile": {
"args": {
"delimiter": "The delimiter",
"filename": "The filename",
"format": "The format to use for exporting",
"noHeader": "Don't use header",
"value": "The value to export"
},
"definition": "Exports the command result to a text/json file",
"detail": "Exports the command result to a text/json file.",
"invalidValue": "Invalid value: need a recordset with csv and xml",
"resultExported": "Command result exported to '{{filename}}' file"
},
"cmdExportVar": {
Expand Down
2 changes: 2 additions & 0 deletions _locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,15 @@
},
"cmdExportFile": {
"args": {
"delimiter": "The delimiter",
"filename": "El nombre del archivo",
"format": "El formato a utilizar",
"noHeader": "No usar cabecera",
"value": "El valor a exportar"
},
"definition": "Exporta el resultado del comando a un archivo de texto/json",
"detail": "Exporta el resultado del comando a un archivo de texto/json.",
"invalidValue": "Valor inválido: se requiere un 'recordset' con csv y xml",
"resultExported": "Resultado del comando exportado al archivo '{{filename}}'"
},
"cmdExportVar": {
Expand Down
13 changes: 13 additions & 0 deletions src/js/flow-typed/odoo.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ declare type OdooSession = {
};
declare type OdooSessionInfo = Object;
declare type OdooSessionInfoUserContext = Object;
declare type OdooLongpollingData = Object;
declare type OdooLongpollingItem = [string, string] | {...};
declare type OdooSearchResponse = Object;

Expand All @@ -26,3 +27,15 @@ declare type OdooService = Object;
declare type BusService = OdooService;
declare type BarcodeService = OdooService;
declare type UserService = OdooService;

declare type OdooQueryRPCParams = Object;

declare type OdooMetadataInfo = {
id: number,
create_uid: number,
create_date: string,
write_uid: number,
write_date: string,
noupdate: boolean,
xmlid: string,
};
5 changes: 2 additions & 3 deletions src/js/page/odoo/commands/backoffice/view.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import {ARG} from '@trash/constants';
import type {CMDCallbackArgs, CMDDef} from '@trash/interpreter';
import type Terminal from '@terminal/terminal';

// $FlowFixMe
export type CMDViewOnSelectedCallback = (records: $ReadOnlyArray<Object>) => mixed;
export type CMDViewOnSelectedCallback = (records: $ReadOnlyArray<OdooSearchRecord>) => mixed;

function openSelectCreateDialog(
model: string,
Expand Down Expand Up @@ -77,7 +76,7 @@ async function cmdViewModelRecord(this: Terminal, kwargs: CMDCallbackArgs): Prom
type: 'ir.actions.act_window',
name: i18n.t('cmdView.result.viewRecord', 'View Record'),
res_model: kwargs.model,
res_id: records[0].id || records[0],
res_id: records[0]?.id !== 'undefined' ? records[0]?.id : records[0],
views: [[false, 'form']],
target: 'current',
context: context,
Expand Down
2 changes: 2 additions & 0 deletions src/js/page/odoo/commands/common/__all__.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import cmdWS from './ws';
import cmdURL from './url';
import cmdInfo from './info';
import cmdNotify from './notify';
import cmdExportFile from './exportfile';
import type VMachine from '@trash/vmachine';

export default function (vm: VMachine) {
Expand Down Expand Up @@ -91,4 +92,5 @@ export default function (vm: VMachine) {
vm.registerCommand('url', cmdURL());
vm.registerCommand('info', cmdInfo());
vm.registerCommand('notify', cmdNotify());
vm.registerCommand('exportfile', cmdExportFile());
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
// $FlowIgnore
import i18n from 'i18next';
import save2file from '@terminal/utils/save2file';
import {stringify} from '@terminal/utils/csv';
import Recordset from '@terminal/core/recordset';
import csvStringify from '@terminal/utils/csv';
import xmlStringify from '@odoo/net_utils/xml';
import uniqueId from '@trash/utils/unique_id';
import {ARG} from '@trash/constants';
import type {CMDCallbackArgs, CMDCallbackContext, CMDDef} from '@trash/interpreter';
Expand All @@ -18,9 +20,17 @@ async function cmdExportFile(this: Terminal, kwargs: CMDCallbackArgs, ctx: CMDCa
if (kwargs.format === 'json') {
mime = 'text/json';
data = JSON.stringify(kwargs.value, null, 4);
} else if (kwargs.format === 'csv') {
mime = 'text/csv';
data = stringify(kwargs.value, !kwargs.no_header);
} else if (kwargs.format === 'csv' || kwargs.format === 'xml') {
if (!(kwargs.value instanceof Recordset)) {
throw new Error(i18n.t('cmdExportFile.invalidValue', 'Invalid value: must be a recordset with csv and xml'));
}
if (kwargs.format === 'csv') {
mime = 'text/csv';
data = csvStringify(kwargs.value, !kwargs.no_header, kwargs.delimiter);
} else if (kwargs.format === 'xml') {
mime = 'text/xml';
data = await xmlStringify(kwargs.value, await this.getContext());
}
}
save2file(filename, mime, data);
ctx.screen.print(
Expand All @@ -36,8 +46,9 @@ export default function (): Partial<CMDDef> {
detail: i18n.t('cmdExportFile.detail', 'Exports the command result to a text/json file.'),
args: [
[ARG.Flag, ['no-header', 'no-header'], false, i18n.t('cmdExportFile.args.noHeader', "Don't use header"), false],
[ARG.String, ['f', 'format'], false, i18n.t('cmdExportFile.args.format', 'The format to use for exporting'), 'json', ['json', 'csv']],
[ARG.String, ['f', 'format'], false, i18n.t('cmdExportFile.args.format', 'The format to use for exporting'), 'json', ['json', 'csv', 'xml']],
[ARG.String, ['fn', 'filename'], false, i18n.t('cmdExportFile.args.filename', 'The filename')],
[ARG.String, ['d', 'delimiter'], false, i18n.t('cmdExportFile.args.delimiter', 'The delimiter'), ','],
[ARG.Any, ['v', 'value'], true, i18n.t('cmdExportFile.args.value', 'The value to export')],
],
example: "-c 'search res.partner'",
Expand Down
10 changes: 1 addition & 9 deletions src/js/page/odoo/commands/common/metadata.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,10 @@ import {ARG} from '@trash/constants';
import type {CMDCallbackArgs, CMDCallbackContext, CMDDef} from '@trash/interpreter';
import type Terminal from '@odoo/terminal';

type MetadataInfo = {
create_uid: number,
create_date: string,
write_uid: number,
write_date: string,
noupdate: boolean,
xmlid: string,
};

async function cmdMetadata(this: Terminal, kwargs: CMDCallbackArgs, ctx: CMDCallbackContext) {
const metadata = (
await callModelMulti<$ReadOnlyArray<MetadataInfo>>(
await callModelMulti<$ReadOnlyArray<OdooMetadataInfo>>(
kwargs.model,
[kwargs.id],
'get_metadata',
Expand Down
40 changes: 22 additions & 18 deletions src/js/page/odoo/commands/common/read.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,29 @@ async function cmdSearchModelRecordId(this: Terminal, kwargs: CMDCallbackArgs, c
const bin_fields = [];

// Due to possible problems with binary fields it is necessary to filter them out
if (search_all_fields && !kwargs.read_binary) {
// $FlowFixMe
const fieldDefs = await callModel<{[string]: Object}>(
kwargs.model,
'fields_get',
[fields],
null,
await this.getContext(),
kwargs.options,
);
if (search_all_fields) {
if (!kwargs.read_binary) {
// $FlowFixMe
const fieldDefs = await callModel<{[string]: Object}>(
kwargs.model,
'fields_get',
[fields],
null,
await this.getContext(),
kwargs.options,
);

fields = [];
Object.entries(fieldDefs).forEach(item => {
if (item[1].type === 'binary') {
bin_fields.push(item[0]);
} else {
fields.push(item[0]);
}
});
fields = [];
Object.entries(fieldDefs).forEach(item => {
if (item[1].type === 'binary') {
bin_fields.push(item[0]);
} else {
fields.push(item[0]);
}
});
} else {
fields = false;
}
}

const result = await searchRead(kwargs.model, [['id', 'in', kwargs.id]], fields, await this.getContext());
Expand Down
24 changes: 14 additions & 10 deletions src/js/page/odoo/commands/common/search.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,21 @@ async function cmdSearchModelRecord(this: Terminal, kwargs: CMDCallbackArgs, ctx

// Due to possible problems with binary fields it is necessary to filter them out
const bin_fields = [];
if (search_all_fields && !kwargs.read_binary) {
const fieldDefs = await getFieldsInfo(kwargs.model, false, await this.getContext(), kwargs.options);
if (search_all_fields) {
if (!kwargs.read_binary) {
const fieldDefs = await getFieldsInfo(kwargs.model, false, await this.getContext(), kwargs.options);

fields = [];
Object.entries(fieldDefs).forEach(item => {
if (item[1].type === 'binary') {
bin_fields.push(item[0]);
} else {
fields.push(item[0]);
}
});
fields = [];
Object.entries(fieldDefs).forEach(item => {
if (item[1].type === 'binary') {
bin_fields.push(item[0]);
} else {
fields.push(item[0]);
}
});
} else {
fields = false;
}
}

const result = await searchRead(kwargs.model, kwargs.domain, fields, await this.getContext(), Object.assign({}, kwargs.options, {
Expand Down
13 changes: 5 additions & 8 deletions src/js/page/odoo/longpolling.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,16 @@ export default class Longpolling {
let has_listener = false;
if (typeof OdooVerMajor === 'number') {
if (OdooVerMajor <= 11) {
// $FlowFixMe
this.#getBusService().on('notification', this, this.#onBusNotification.bind(this));
this.#getBusService().on('notification', this, this.onBusNotification);
has_listener = true;
} else if (OdooVerMajor >= 16) {
// $FlowFixMe
this.#busServ('addEventListener', 'notification', this.#onBusNotification.bind(this));
this.#busServ('addEventListener', 'notification', this.onBusNotification);
has_listener = true;
}
}
if (!has_listener) {
this.#busServ('onNotification', this, (data: $ReadOnlyArray<OdooLongpollingItem>) =>
this.#onBusNotification(data),
this.onBusNotification(data),
);
}
}
Expand Down Expand Up @@ -104,15 +102,14 @@ export default class Longpolling {
return getStorageItem('terminal_longpolling_mode') === 'verbose';
}

// $FlowFixMe
#getNotificationsData(data: Object): $ReadOnlyArray<OdooLongpollingItem> {
#getNotificationsData(data: OdooLongpollingData): $ReadOnlyArray<OdooLongpollingItem> {
const OdooVerMajor = getOdooVersion('major');
if (typeof OdooVerMajor === 'number' && OdooVerMajor >= 16) {
return data.detail;
}
return data;
}
#onBusNotification(data: $ReadOnlyArray<OdooLongpollingItem>) {
onBusNotification(data: $ReadOnlyArray<OdooLongpollingItem>) {
if (this.isVerbose()) {
this.#terminal.onBusNotification(this.#getNotificationsData(data));
}
Expand Down
Loading

0 comments on commit fe7d6b2

Please sign in to comment.