584 lines
14 KiB
JavaScript
584 lines
14 KiB
JavaScript
import {
|
|
MockServer,
|
|
defineActions,
|
|
defineModels,
|
|
fields,
|
|
models,
|
|
serverState,
|
|
webModels,
|
|
} from "@web/../tests/web_test_helpers";
|
|
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
|
|
|
/**
|
|
* @typedef {object} ServerData
|
|
* @property {object} [models]
|
|
* @property {object} [views]
|
|
* @property {object} [menus]
|
|
* @property {object} [actions]
|
|
*/
|
|
|
|
/**
|
|
* Get a basic arch for a pivot, which is compatible with the data given by
|
|
* getBasicData().
|
|
*
|
|
* Here is the pivot created:
|
|
* A B C D E F
|
|
* 1 1 2 12 17 Total
|
|
* 2 Proba Proba Proba Proba Proba
|
|
* 3 false 15 15
|
|
* 4 true 11 10 95 116
|
|
* 5 Total 11 15 10 95 131
|
|
*/
|
|
export function getBasicPivotArch() {
|
|
return /* xml */ `
|
|
<pivot string="Partners">
|
|
<field name="foo" type="col"/>
|
|
<field name="bar" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`;
|
|
}
|
|
|
|
/**
|
|
* Get a basic arch for a list, which is compatible with the data given by
|
|
* getBasicData().
|
|
*
|
|
* Here is the list created:
|
|
* A B C D
|
|
* 1 Foo bar Date Product
|
|
* 2 12 True 2016-04-14 xphone
|
|
* 3 1 True 2016-10-26 xpad
|
|
* 4 17 True 2016-12-15 xpad
|
|
* 5 2 False 2016-12-11 xpad
|
|
*/
|
|
export function getBasicListArch() {
|
|
return /* xml */ `
|
|
<list string="Partners">
|
|
<field name="foo"/>
|
|
<field name="bar"/>
|
|
<field name="date"/>
|
|
<field name="product_id"/>
|
|
</list>
|
|
`;
|
|
}
|
|
|
|
export function getBasicGraphArch() {
|
|
return /* xml */ `
|
|
<graph string="PartnerGraph">
|
|
<field name="bar" />
|
|
</graph>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* @returns {ServerData}
|
|
*/
|
|
export function getBasicServerData() {
|
|
return {
|
|
models: getBasicData(),
|
|
views: {},
|
|
};
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {string} model
|
|
* @param {Array<string>} columns
|
|
*
|
|
* @returns { {definition: Object, columns: Array<Object>}}
|
|
*/
|
|
export function generateListDefinition(model, columns) {
|
|
const cols = [];
|
|
for (const name of columns) {
|
|
const PyModel = Object.values(SpreadsheetModels).find((m) => m._name === model);
|
|
cols.push({
|
|
name,
|
|
type: PyModel._fields[name].type,
|
|
});
|
|
}
|
|
return {
|
|
definition: {
|
|
metaData: {
|
|
resModel: model,
|
|
columns,
|
|
},
|
|
searchParams: {
|
|
domain: [],
|
|
context: {},
|
|
orderBy: [],
|
|
},
|
|
name: "List",
|
|
},
|
|
columns: cols,
|
|
};
|
|
}
|
|
|
|
export function getBasicListArchs() {
|
|
return {
|
|
"partner,false,list": getBasicListArch(),
|
|
"partner,false,search": /* xml */ `<search/>`,
|
|
"partner,false,form": /* xml */ `<form/>`,
|
|
};
|
|
}
|
|
|
|
export function defineSpreadsheetModels() {
|
|
defineModels(SpreadsheetModels);
|
|
}
|
|
|
|
export function defineSpreadsheetActions() {
|
|
defineActions([
|
|
{
|
|
id: 1,
|
|
name: "partner Action",
|
|
res_model: "partner",
|
|
xml_id: "spreadsheet.partner_action",
|
|
views: [
|
|
[false, "list"],
|
|
[false, "pivot"],
|
|
[false, "graph"],
|
|
[false, "search"],
|
|
[false, "form"],
|
|
],
|
|
},
|
|
]);
|
|
}
|
|
|
|
export class IrModel extends webModels.IrModel {
|
|
display_name_for(models) {
|
|
const records = this.env["ir.model"].search_read([["model", "in", models]]);
|
|
return records.map((record) => ({
|
|
model: record.model,
|
|
display_name: record.name,
|
|
}));
|
|
}
|
|
|
|
_records = [
|
|
{
|
|
id: 37,
|
|
name: "Product",
|
|
model: "product",
|
|
},
|
|
{
|
|
id: 40,
|
|
name: "Partner",
|
|
model: "partner",
|
|
},
|
|
{
|
|
id: 55,
|
|
name: "Users",
|
|
model: "res.users",
|
|
},
|
|
];
|
|
}
|
|
|
|
export class IrUIMenu extends models.Model {
|
|
_name = "ir.ui.menu";
|
|
|
|
name = fields.Char({ string: "Name" });
|
|
action = fields.Char({ string: "Action" });
|
|
groups_id = fields.Many2many({ string: "Groups", relation: "res.group" });
|
|
}
|
|
|
|
export class IrActions extends models.Model {
|
|
_name = "ir.actions";
|
|
}
|
|
export class ResGroup extends models.Model {
|
|
_name = "res.group";
|
|
name = fields.Char({ string: "Name" });
|
|
}
|
|
|
|
export class ResUsers extends mailModels.ResUsers {
|
|
_name = "res.users";
|
|
|
|
name = fields.Char({ string: "Name" });
|
|
groups_id = fields.Many2many({ string: "Groups", relation: "res.group" });
|
|
}
|
|
|
|
export class SpreadsheetMixin extends models.Model {
|
|
_name = "spreadsheet.mixin";
|
|
|
|
spreadsheet_binary_data = fields.Binary({ string: "Spreadsheet file" });
|
|
spreadsheet_data = fields.Text();
|
|
thumbnail = fields.Binary();
|
|
|
|
get_display_names_for_spreadsheet(args) {
|
|
const result = [];
|
|
for (const { model, id } of args) {
|
|
const record = this.env[model].search_read([["id", "=", id]])[0];
|
|
result.push(record?.display_name ?? null);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
get_selector_spreadsheet_models() {
|
|
return [
|
|
{
|
|
model: "documents.document",
|
|
display_name: "Spreadsheets",
|
|
allow_create: true,
|
|
},
|
|
];
|
|
}
|
|
}
|
|
|
|
export class ResCurrency extends models.Model {
|
|
_name = "res.currency";
|
|
|
|
name = fields.Char({ string: "Code" });
|
|
symbol = fields.Char({ string: "Symbol" });
|
|
position = fields.Selection({
|
|
string: "Position",
|
|
selection: [
|
|
["after", "A"],
|
|
["before", "B"],
|
|
],
|
|
});
|
|
decimal_places = fields.Integer({ string: "decimal" });
|
|
|
|
get_company_currency_for_spreadsheet() {
|
|
return {
|
|
code: "EUR",
|
|
symbol: "€",
|
|
position: "after",
|
|
decimalPlaces: 2,
|
|
};
|
|
}
|
|
|
|
_records = [
|
|
{
|
|
id: 1,
|
|
name: "EUR",
|
|
symbol: "€",
|
|
position: "after",
|
|
decimal_places: 2,
|
|
},
|
|
{
|
|
id: 2,
|
|
name: "USD",
|
|
symbol: "$",
|
|
position: "before",
|
|
decimal_places: 2,
|
|
},
|
|
];
|
|
}
|
|
|
|
export class Partner extends models.Model {
|
|
_name = "partner";
|
|
|
|
foo = fields.Integer({
|
|
string: "Foo",
|
|
store: true,
|
|
searchable: true,
|
|
aggregator: "sum",
|
|
groupable: false,
|
|
});
|
|
bar = fields.Boolean({
|
|
string: "Bar",
|
|
store: true,
|
|
sortable: true,
|
|
groupable: true,
|
|
searchable: true,
|
|
});
|
|
name = fields.Char({
|
|
string: "name",
|
|
store: true,
|
|
sortable: true,
|
|
groupable: true,
|
|
searchable: true,
|
|
});
|
|
date = fields.Date({
|
|
string: "Date",
|
|
store: true,
|
|
sortable: true,
|
|
groupable: true,
|
|
searchable: true,
|
|
});
|
|
create_date = fields.Datetime({
|
|
string: "Creation Date",
|
|
store: true,
|
|
sortable: true,
|
|
groupable: true,
|
|
});
|
|
active = fields.Boolean({
|
|
string: "Active",
|
|
default: true,
|
|
searchable: true,
|
|
groupable: false,
|
|
});
|
|
product_id = fields.Many2one({
|
|
string: "Product",
|
|
relation: "product",
|
|
store: true,
|
|
sortable: true,
|
|
groupable: true,
|
|
searchable: true,
|
|
});
|
|
tag_ids = fields.Many2many({
|
|
string: "Tags",
|
|
relation: "tag",
|
|
store: true,
|
|
sortable: true,
|
|
groupable: true,
|
|
searchable: true,
|
|
});
|
|
probability = fields.Float({
|
|
string: "Probability",
|
|
searchable: true,
|
|
store: true,
|
|
aggregator: "avg",
|
|
groupable: false,
|
|
});
|
|
field_with_array_agg = fields.Integer({
|
|
string: "field_with_array_agg",
|
|
searchable: true,
|
|
groupable: false,
|
|
aggregator: "array_agg",
|
|
});
|
|
currency_id = fields.Many2one({
|
|
string: "Currency",
|
|
relation: "res.currency",
|
|
store: true,
|
|
sortable: true,
|
|
groupable: true,
|
|
searchable: true,
|
|
});
|
|
pognon = fields.Monetary({
|
|
string: "Money!",
|
|
currency_field: "currency_id",
|
|
store: true,
|
|
sortable: true,
|
|
aggregator: "avg",
|
|
groupable: true,
|
|
searchable: true,
|
|
});
|
|
partner_properties = fields.Properties({
|
|
string: "Properties",
|
|
store: true,
|
|
sortable: true,
|
|
groupable: true,
|
|
searchable: true,
|
|
definition_record: "product_id",
|
|
definition_record_field: "properties_definitions",
|
|
});
|
|
jsonField = fields.Json({ string: "Json Field", store: true, groupable: false });
|
|
user_ids = fields.Many2many({
|
|
relation: "res.users",
|
|
string: "Users",
|
|
searchable: true,
|
|
groupable: false,
|
|
});
|
|
|
|
_records = [
|
|
{
|
|
id: 1,
|
|
foo: 12,
|
|
bar: true,
|
|
date: "2016-04-14",
|
|
create_date: "2016-04-03 00:00:00",
|
|
product_id: 37,
|
|
probability: 10,
|
|
field_with_array_agg: 1,
|
|
tag_ids: [42, 67],
|
|
currency_id: 1,
|
|
pognon: 74.4,
|
|
},
|
|
{
|
|
id: 2,
|
|
foo: 1,
|
|
bar: true,
|
|
date: "2016-10-26",
|
|
create_date: "2014-04-03 00:05:32",
|
|
product_id: 41,
|
|
probability: 11,
|
|
field_with_array_agg: 2,
|
|
tag_ids: [42, 67],
|
|
currency_id: 2,
|
|
pognon: 74.8,
|
|
},
|
|
{
|
|
id: 3,
|
|
foo: 17,
|
|
bar: true,
|
|
date: "2016-12-15",
|
|
create_date: "2006-01-03 11:30:50",
|
|
product_id: 41,
|
|
probability: 95,
|
|
field_with_array_agg: 3,
|
|
tag_ids: [],
|
|
currency_id: 1,
|
|
pognon: 4,
|
|
},
|
|
{
|
|
id: 4,
|
|
foo: 2,
|
|
bar: false,
|
|
date: "2016-12-11",
|
|
create_date: "2016-12-10 21:59:59",
|
|
product_id: 41,
|
|
probability: 15,
|
|
field_with_array_agg: 4,
|
|
tag_ids: [42],
|
|
currency_id: 2,
|
|
pognon: 1000,
|
|
},
|
|
];
|
|
|
|
// TODO: check which views are actually needed in the tests
|
|
_views = {
|
|
list: getBasicListArch(),
|
|
pivot: getBasicPivotArch(),
|
|
graph: getBasicGraphArch(),
|
|
form: /* xml */ `<Form/>`,
|
|
search: /* xml */ `<search/>`,
|
|
};
|
|
}
|
|
|
|
export class Product extends models.Model {
|
|
_name = "product";
|
|
|
|
name = fields.Char({ string: "Product Name" });
|
|
display_name = fields.Char({ string: "Product Name" });
|
|
active = fields.Boolean({ string: "Active", default: true });
|
|
properties_definitions = fields.PropertiesDefinition();
|
|
|
|
_records = [
|
|
{
|
|
id: 37,
|
|
display_name: "xphone",
|
|
name: "xphone",
|
|
},
|
|
{
|
|
id: 41,
|
|
display_name: "xpad",
|
|
name: "xpad",
|
|
},
|
|
];
|
|
}
|
|
|
|
export class Tag extends models.Model {
|
|
_name = "tag";
|
|
|
|
name = fields.Char({ string: "Tag Name" });
|
|
|
|
_records = [
|
|
{
|
|
id: 42,
|
|
name: "isCool",
|
|
},
|
|
{
|
|
id: 67,
|
|
name: "Growing",
|
|
},
|
|
];
|
|
}
|
|
|
|
export function getBasicData() {
|
|
return {
|
|
"documents.document": {},
|
|
"ir.model": {},
|
|
"ir.embedded.actions": {},
|
|
"documents.tag": {},
|
|
"spreadsheet.template": {},
|
|
"res.currency": {},
|
|
"res.users": {},
|
|
partner: {},
|
|
product: {},
|
|
tag: {},
|
|
};
|
|
}
|
|
|
|
export const SpreadsheetModels = {
|
|
...webModels,
|
|
...mailModels,
|
|
IrModel,
|
|
IrUIMenu,
|
|
IrActions,
|
|
ResGroup,
|
|
ResUsers,
|
|
SpreadsheetMixin,
|
|
ResCurrency,
|
|
Partner,
|
|
Product,
|
|
Tag,
|
|
};
|
|
|
|
/**
|
|
* Add the records inside serverData in the MockServer
|
|
*
|
|
* @param {ServerData} serverData
|
|
*/
|
|
export function addRecordsFromServerData(serverData) {
|
|
for (const modelName of Object.keys(serverData.models)) {
|
|
const records = serverData.models[modelName].records;
|
|
if (!records) {
|
|
continue;
|
|
}
|
|
const PyModel = getSpreadsheetModel(modelName);
|
|
if (!PyModel) {
|
|
throw new Error(`Model ${modelName} not found inside SpreadsheetModels`);
|
|
}
|
|
checkRecordsValidity(modelName, records);
|
|
PyModel._records = records;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add the views inside serverData in the MockServer
|
|
*
|
|
* @param {ServerData} serverData
|
|
*
|
|
* @example
|
|
* addViewsFromServerData({ "partner,false,search": "<search/>" });
|
|
* Will set the default search view for the partner model
|
|
*/
|
|
export function addViewsFromServerData(serverData) {
|
|
for (const fullViewKey of Object.keys(serverData.views)) {
|
|
const viewArch = serverData.views[fullViewKey];
|
|
const splitted = fullViewKey.split(",");
|
|
const modelName = splitted[0];
|
|
const viewType = splitted[2];
|
|
const recordId = splitted[1];
|
|
const PyModel = getSpreadsheetModel(modelName);
|
|
if (!PyModel) {
|
|
throw new Error(`Model ${modelName} not found inside SpreadsheetModels`);
|
|
}
|
|
const viewKey = viewType + "," + recordId;
|
|
PyModel._views[viewKey] = viewArch;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the records are valid.
|
|
* This is mainly to avoid the mail's service crashing if the res.users are not correctly set.
|
|
*/
|
|
function checkRecordsValidity(modelName, records) {
|
|
if (modelName === "res.users") {
|
|
const serverUserId = serverState.userId;
|
|
const currentUser = records.find((record) => record.id === serverUserId);
|
|
if (!currentUser) {
|
|
throw new Error(
|
|
`The current user (${serverUserId}) is not in the records. did you forget to set serverState.userId ?`
|
|
);
|
|
}
|
|
if (!currentUser.active) {
|
|
throw new Error(`The current user (${serverUserId}) is not active`);
|
|
}
|
|
if (!currentUser.partner_id) {
|
|
throw new Error(
|
|
`The current user (${serverUserId}) has no partner_id. It should be set to serverState.partnerId`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function getPyEnv() {
|
|
const mockServer = MockServer.current;
|
|
if (!mockServer) {
|
|
throw new Error("No mock server found");
|
|
}
|
|
return mockServer.env;
|
|
}
|
|
|
|
export function getSpreadsheetModel(modelName) {
|
|
return Object.values(SpreadsheetModels).find((model) => model._name === modelName);
|
|
}
|