Initial commit

This commit is contained in:
gsinghpal
2026-02-22 01:22:18 -05:00
commit 5200d5baf0
2394 changed files with 386834 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
import { expect, test } from "@odoo/hoot";
import { click, press } from "@odoo/hoot-dom";
import { animationFrame } from "@odoo/hoot-mock";
import { mountWithCleanup, makeMockEnv, defineModels } from "@web/../tests/web_test_helpers";
import { mailModels } from "@mail/../tests/mail_test_helpers";
import { AccountReportLineCellEditable } from "@fusion_accounting/components/account_report/line_cell_editable/line_cell_editable";
// Due to dependency with mail module, we have to define their models for our tests.
defineModels(mailModels);
test("can unformat a value when focus and format when blur", async () => {
const env = await makeMockEnv({
controller: {},
});
await mountWithCleanup(AccountReportLineCellEditable, {
env,
props: {
cell: {
name: "5,702.22",
no_format: 5702.22,
edit_popup_data: {},
},
line: {},
},
});
expect(".o_input").toHaveValue("5,702.22");
await click(".o_input");
await animationFrame();
expect(".o_input").toHaveValue("5702.22");
await press("Enter");
await animationFrame();
expect(".o_input").toHaveValue("5,702.22");
});

View File

@@ -0,0 +1,649 @@
/** @odoo-module **/
import { click, drag, editInput, getFixture } from "@web/../tests/helpers/utils";
import { registerCleanup } from "@web/../tests/helpers/cleanup";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
import { sortableDrag } from "@web/../tests/core/utils/nested_sortable_tests"
let arch;
let serverData;
let target;
QUnit.module("Account Reports Builder", ({ beforeEach }) => {
beforeEach(async () => {
arch = `
<form>
<field class="w-100" name="line_ids" widget="account_report_lines_list_x2many">
<list>
<field name="id" column_invisible="1"/>
<field name="sequence" column_invisible="1"/>
<field name="parent_id" column_invisible="1"/>
<field name="hierarchy_level" column_invisible="1"/>
<field name="name"/>
<field name="code" optional="hide"/>
</list>
</field>
</form>
`;
serverData = {
models: {
report: {
fields: {
id: { string: "ID", type: "integer" },
line_ids: {
string: "Lines",
type: "one2many",
relation: "report_lines",
relation_field: "report_id",
},
},
records: [
{
id: 1,
line_ids: [1, 2, 3, 4, 5],
}
]
},
report_lines: {
fields: {
report_id: { string: "Report ID", type: "many2one", relation: "report" },
id: { string: "ID", type: "integer" },
sequence: { string: "Sequence", type: "integer" },
parent_id: {
string: "Parent Line",
type: "many2one",
relation: "report_lines",
relation_field: "id",
},
hierarchy_level: { string: "Level", type: "integer" },
name: { string: "Name", type: "char" },
code: { string: "Code", type: "char" },
},
records: [
{
id: 1,
sequence: null,
parent_id: false,
hierarchy_level: 1,
name: "Root without children",
code: "RWOC",
},
{
id: 2,
sequence: null,
parent_id: false,
hierarchy_level: 0,
name: "Root with children",
code: "RC",
},
{
id: 3,
sequence: null,
parent_id: 2,
hierarchy_level: 3,
name: "Child #1",
code: "C1",
},
{
id: 4,
sequence: null,
parent_id: 3,
hierarchy_level: 5,
name: "Grandchild",
code: "GC",
},
{
id: 5,
sequence: null,
parent_id: 2,
hierarchy_level: 3,
name: "Child #2",
code: "C2",
},
]
},
},
views: {
"report_lines,false,form": `
<form>
<field name="name"/>
</form>
`,
}
};
target = getFixture();
// Make fixture in visible range, so that document.elementFromPoint work as expected
target.style.position = "absolute";
target.style.top = "0";
target.style.left = "0";
target.style.height = "100%";
target.style.opacity = QUnit.config.debug ? "" : "0";
registerCleanup(async () => {
target.style.position = "";
target.style.top = "";
target.style.left = "";
target.style.height = "";
target.style.opacity = "";
});
setupViewRegistries();
});
//------------------------------------------------------------------------------------------------------------------
// Structure
//------------------------------------------------------------------------------------------------------------------
QUnit.test("have correct descendants count", async (assert) => {
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
});
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='0'] span:contains('Root without children')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='3'] span:contains('Root with children')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='1'] span:contains('Child #1')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='0'] span:contains('Grandchild')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='0'] span:contains('Child #2')");
});
//------------------------------------------------------------------------------------------------------------------
// Create
//------------------------------------------------------------------------------------------------------------------
QUnit.test("can create a line", async (assert) => {
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
});
await click(target.querySelector(".account_report_lines_list_x2many"), "li:last-of-type a");
assert.containsOnce(target, ".o_dialog");
await editInput(target.querySelector("div[name='name'] input"), null, "Created line");
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Created line')");
});
//------------------------------------------------------------------------------------------------------------------
// Edit
//------------------------------------------------------------------------------------------------------------------
QUnit.test("can edit a line", async (assert) => {
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
});
await click(target.querySelector(".account_report_lines_list_x2many"), "li[data-record_id='1'] .column");
assert.containsOnce(target, ".o_dialog");
await editInput(target.querySelector("div[name='name'] input"), null, "Line without children (edited)");
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Line without children (edited)')");
});
//------------------------------------------------------------------------------------------------------------------
// Delete
//------------------------------------------------------------------------------------------------------------------
QUnit.test("can delete a root", async (assert) => {
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
});
await click(target.querySelector(".account_report_lines_list_x2many"), "li[data-record_id='1'] > div > .trash");
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root without children')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root with children')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #1')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Grandchild')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #2')");
});
QUnit.test("can delete a root with children", async (assert) => {
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
});
await click(target.querySelector(".account_report_lines_list_x2many"), "li[data-record_id='2'] > div > .trash");
// Confirmation dialog "This line and all its children will be deleted. Are you sure you want to proceed?"
assert.containsOnce(target, ".o_dialog");
await click(target.querySelector(".o_dialog"), ".btn-primary");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root without children')");
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root with children')");
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #1')");
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Grandchild')");
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #2')");
});
QUnit.test("can delete a last child", async (assert) => {
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
});
await click(target.querySelector(".account_report_lines_list_x2many"), "li[data-record_id='4'] > div > .trash");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root without children')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='2'] span:contains('Root with children')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='0'] span:contains('Child #1')");
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Grandchild')");
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #2')");
});
//------------------------------------------------------------------------------------------------------------------
// Drag and drop
//------------------------------------------------------------------------------------------------------------------
QUnit.test("can move a root down", async (assert) => {
serverData.models.report.records[0].line_ids = [1, 2, 3, 4];
serverData.models.report_lines.records = [
{
id: 1,
sequence: null,
parent_id: false,
hierarchy_level: 1,
name: "dragged",
code: "D",
},
{
id: 2,
sequence: null,
parent_id: false,
hierarchy_level: 1,
name: "noChild",
code: "N",
},
{
id: 3,
sequence: null,
parent_id: false,
hierarchy_level: 0,
name: "parent",
code: "P",
},
{
id: 4,
sequence: null,
parent_id: 3,
hierarchy_level: 3,
name: "child",
code: "C",
},
];
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
mockRPC: (route, args) => {
if (args.method === 'web_save') {
const lineIds = args.args[1].line_ids;
// Parents
assert.equal(lineIds[0][2].parent_id, 3);
// Hierarchy levels
assert.equal(lineIds[0][2].hierarchy_level, 3);
// Sequences
assert.equal(lineIds[0][2].sequence, 4);
assert.equal(lineIds[1][2].sequence, 1);
assert.equal(lineIds[2][2].sequence, 2);
assert.equal(lineIds[3][2].sequence, 3);
}
}
});
const { drop, moveUnder } = await sortableDrag("li[data-record_id='1']");
await moveUnder("li[data-record_id='2']");
await moveUnder("li[data-record_id='4']");
await drop();
await click(target.querySelector(".o_form_button_save"));
});
QUnit.test("can move a root up", async (assert) => {
serverData.models.report.records[0].line_ids = [1, 2, 3, 4];
serverData.models.report_lines.records = [
{
id: 1,
sequence: null,
parent_id: false,
hierarchy_level: 0,
name: "parent",
code: "P",
},
{
id: 2,
sequence: null,
parent_id: 1,
hierarchy_level: 3,
name: "child",
code: "C",
},
{
id: 3,
sequence: null,
parent_id: false,
hierarchy_level: 1,
name: "noChild",
code: "N",
},
{
id: 4,
sequence: null,
parent_id: false,
hierarchy_level: 1,
name: "dragged",
code: "D",
},
];
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
mockRPC: (route, args) => {
if (args.method === 'web_save') {
const lineIds = args.args[1].line_ids;
// Parents
assert.equal(lineIds[0][2].parent_id, 1);
// Hierarchy levels
assert.equal(lineIds[0][2].hierarchy_level, 3);
// Sequences
assert.equal(lineIds[0][2].sequence, 2);
assert.equal(lineIds[1][2].sequence, 1);
assert.equal(lineIds[2][2].sequence, 3);
assert.equal(lineIds[3][2].sequence, 4);
}
}
});
const { drop, moveAbove } = await sortableDrag("li[data-record_id='4']");
await moveAbove("li[data-record_id='3']");
await moveAbove("li[data-record_id='2']");
await drop();
await click(target.querySelector(".o_form_button_save"));
});
QUnit.test("can move a child down", async (assert) => {
serverData.models.report.records[0].line_ids = [1, 2, 3, 4];
serverData.models.report_lines.records = [
{
id: 1,
sequence: null,
parent_id: false,
hierarchy_level: 0,
name: "parent",
code: "P",
},
{
id: 2,
sequence: null,
parent_id: 1,
hierarchy_level: 3,
name: "dragged",
code: "D",
},
{
id: 3,
sequence: null,
parent_id: 1,
hierarchy_level: 3,
name: "child",
code: "C",
},
{
id: 4,
sequence: null,
parent_id: false,
hierarchy_level: 1,
name: "noChild",
code: "N",
},
];
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
mockRPC: (route, args) => {
if (args.method === 'web_save') {
const lineIds = args.args[1].line_ids;
// Parents
assert.equal(lineIds[0][2].parent_id, false);
// Hierarchy levels
assert.equal(lineIds[0][2].hierarchy_level, 1);
// Sequences
assert.equal(lineIds[0][2].sequence, 4);
assert.equal(lineIds[1][2].sequence, 1);
assert.equal(lineIds[2][2].sequence, 2);
assert.equal(lineIds[3][2].sequence, 3);
}
}
});
const { drop, moveUnder } = await sortableDrag("li[data-record_id='2']");
await moveUnder("li[data-record_id='3']");
await moveUnder("li[data-record_id='4']");
await drop();
await click(target.querySelector(".o_form_button_save"));
});
QUnit.test("can move a child up", async (assert) => {
serverData.models.report.records[0].line_ids = [1, 2, 3];
serverData.models.report_lines.records = [
{
id: 1,
sequence: null,
parent_id: false,
hierarchy_level: 0,
name: "parent",
code: "P",
},
{
id: 2,
sequence: null,
parent_id: 1,
hierarchy_level: 3,
name: "child",
code: "C",
},
{
id: 3,
sequence: null,
parent_id: 1,
hierarchy_level: 3,
name: "dragged",
code: "D",
},
];
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
mockRPC: (route, args) => {
if (args.method === 'web_save') {
const lineIds = args.args[1].line_ids;
// Parents
assert.equal(lineIds[0][2].parent_id, false);
// Hierarchy levels
assert.equal(lineIds[0][2].hierarchy_level, 1);
// Sequences
assert.equal(lineIds[0][2].sequence, 1);
assert.equal(lineIds[1][2].sequence, 2);
assert.equal(lineIds[2][2].sequence, 3);
}
}
});
const { drop, moveAbove } = await sortableDrag("li[data-record_id='3']");
await moveAbove("li[data-record_id='2']");
await moveAbove("li[data-record_id='1']");
await drop();
await click(target.querySelector(".o_form_button_save"));
});
QUnit.test("can move a new root into a child", async (assert) => {
serverData.models.report.records[0].line_ids = [1, 2, 3];
serverData.models.report_lines.records = [
{
id: 1,
sequence: null,
parent_id: false,
hierarchy_level: 0,
name: "parent",
code: "P",
},
{
id: 2,
sequence: null,
parent_id: 1,
hierarchy_level: 3,
name: "child",
code: "C",
},
{
id: 3,
sequence: null,
parent_id: false,
hierarchy_level: 1,
name: "noChild",
code: "N",
},
];
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
mockRPC: (route, args) => {
if (args.method === 'web_save' && !target.querySelector(".o_dialog")) {
const lineIds = args.args[1].line_ids;
// Parents
assert.equal(lineIds[0][2].parent_id, 1);
// Hierarchy levels
assert.equal(lineIds[0][2].hierarchy_level, 3);
// Sequences
assert.equal(lineIds[0][2].sequence, 2);
assert.equal(lineIds[1][2].sequence, 1);
assert.equal(lineIds[2][2].sequence, 3);
assert.equal(lineIds[3][2].sequence, 4);
}
}
});
await click(target.querySelector(".account_report_lines_list_x2many"), "li:last-of-type a");
await editInput(target.querySelector("div[name='name'] input"), null, "dragged");
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
const { drop, moveAbove } = await sortableDrag("li[data-record_id='4']");
await moveAbove("li[data-record_id='3']");
await moveAbove("li[data-record_id='2']");
await drop();
await click(target.querySelector(".o_form_button_save"));
});
QUnit.test("can move a child into a new root", async (assert) => {
serverData.models.report.records[0].line_ids = [];
serverData.models.report_lines.records = [];
await makeView({
type: "form",
resId: 1,
resModel: "report",
serverData,
arch,
mockRPC: (route, args) => {
if (args.method === 'web_save' && !target.querySelector(".o_dialog")) {
const lineIds = args.args[1].line_ids;
// Parents
assert.equal(lineIds[0][2].parent_id, 1);
// Hierarchy levels
assert.equal(lineIds[0][2].hierarchy_level, 3);
// Sequences
assert.equal(lineIds[0][2].sequence, 2);
assert.equal(lineIds[1][2].sequence, 1);
}
}
});
await click(target.querySelector(".account_report_lines_list_x2many"), "li:last-of-type a");
await editInput(target.querySelector("div[name='name'] input"), null, "parent");
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
await click(target.querySelector(".account_report_lines_list_x2many"), "li:last-of-type a");
await editInput(target.querySelector("div[name='name'] input"), null, "dragged");
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
const toSelector = target.querySelector("li[data-record_id='2']");
const { drop, moveTo } = await drag(toSelector);
await moveTo(toSelector, { x: 600 });
await drop();
await click(target.querySelector(".o_form_button_save"));
});
});

View File

@@ -0,0 +1,52 @@
/** @odoo-module **/
import { mockDownload } from "@web/../tests/helpers/utils";
import { createWebClient, doAction } from "@web/../tests/webclient/helpers";
let serverData;
QUnit.module('Account Reports', {}, function () {
QUnit.test('can execute account report download actions', async function (assert) {
assert.expect(5);
const actions = {
1: {
id: 1,
data: {
model: 'some_model',
options: {
someOption: true,
},
output_format: 'pdf',
},
type: 'ir_actions_account_report_download',
},
};
serverData = {actions};
mockDownload((options) => {
assert.step(options.url);
assert.deepEqual(options.data, {
model: 'some_model',
options: {
someOption: true,
},
output_format: 'pdf',
}, "should give the correct data");
return Promise.resolve();
});
const webClient = await createWebClient({
serverData,
mockRPC: function (route, args) {
assert.step(args.method || route);
},
});
await doAction(webClient, 1);
assert.verifySteps([
'/web/webclient/load_menus',
'/web/action/load',
'/fusion_accounting',
]);
});
});

View File

@@ -0,0 +1,340 @@
import { beforeEach, test } from "@odoo/hoot";
import { defineAccountModels } from "@account/../tests/account_test_helpers";
import {
assertSteps,
click,
contains,
onRpcBefore,
openListView,
patchUiSize,
SIZES,
start,
startServer,
step,
} from "@mail/../tests/mail_test_helpers";
import { onRpc, serverState } from "@web/../tests/web_test_helpers";
import { getOrigin } from "@web/core/utils/urls";
const ROUTES_TO_IGNORE = [
"/bus/im_status",
"/web/dataset/call_kw/account.move.line/get_views",
"/web/webclient/load_menus",
"/web/dataset/call_kw/res.users/load_views",
"/hr_attendance/attendance_user_data",
"/web/dataset/call_kw/res.users/has_group",
];
const openPreparedView = async (size) => {
patchUiSize({ size: size });
onRpcBefore((route, args) => {
if (
ROUTES_TO_IGNORE.includes(route) ||
route.includes("/web/static/lib/pdfjs/web/viewer.html")
) {
return;
}
step(`${route} - ${JSON.stringify(args)}`);
});
onRpc(({ method, model, args, kwargs }) => {
const route = `/web/dataset/call_kw/${model}/${method}`;
if (ROUTES_TO_IGNORE.includes(route)) {
return;
}
step(`${route} - {"kwargs":${JSON.stringify(kwargs)}}`);
});
await start();
await assertSteps([
`/mail/data - ${JSON.stringify({
init_messaging: {},
failures: true,
systray_get_activities: true,
context: { lang: "en", tz: "taht", uid: serverState.userId, allowed_company_ids: [1] },
})}`,
]);
await openListView("account.move.line", {
context: { group_by: ["move_id"] },
arch: `
<list editable='bottom' js_class='account_move_line_list'>
<field name='id'/>
<field name='name'/>
<field name='move_id'/>
</list>`,
});
};
defineAccountModels();
beforeEach(async () => {
const pyEnv = await startServer();
const accountMoveLineIds = pyEnv["account.move.line"].create([
{ name: "line0" },
{ name: "line1" },
{ name: "line2" },
{ name: "line3" },
{ name: "line4" },
{ name: "line5" },
]);
const accountMove = pyEnv["account.move"].create([
{ name: "move0", invoice_line_ids: [accountMoveLineIds[0], accountMoveLineIds[1]] },
{ name: "move1", invoice_line_ids: [accountMoveLineIds[2], accountMoveLineIds[3]] },
{ name: "move2", invoice_line_ids: [accountMoveLineIds[4], accountMoveLineIds[5]] },
]);
const attachmentIds = pyEnv["ir.attachment"].create([
{ res_id: accountMove[1], res_model: "account.move", mimetype: "application/pdf" },
{ res_id: accountMove[2], res_model: "account.move", mimetype: "application/pdf" },
]);
pyEnv["account.move"].write([accountMove[1]], { attachment_ids: [attachmentIds[0]] });
pyEnv["account.move.line"].write([accountMoveLineIds[0]], { move_id: accountMove[0] });
pyEnv["account.move.line"].write([accountMoveLineIds[1]], { move_id: accountMove[0] });
pyEnv["account.move.line"].write([accountMoveLineIds[2]], {
move_id: accountMove[1],
move_attachment_ids: [attachmentIds[0]],
});
pyEnv["account.move.line"].write([accountMoveLineIds[3]], {
move_id: accountMove[1],
move_attachment_ids: [attachmentIds[0]],
});
pyEnv["account.move.line"].write([accountMoveLineIds[4]], {
move_id: accountMove[2],
move_attachment_ids: [attachmentIds[1]],
});
pyEnv["account.move.line"].write([accountMoveLineIds[5]], {
move_id: accountMove[2],
move_attachment_ids: [attachmentIds[1]],
});
});
test("No preview on small devices", async () => {
await openPreparedView(SIZES.XL);
await contains(".o_move_line_list_view");
await assertSteps([
`/web/dataset/call_kw/account.move.line/web_read_group - ${JSON.stringify({
kwargs: {
orderby: "",
lazy: true,
offset: 0,
limit: 80,
context: {
lang: "en",
tz: "taht",
uid: serverState.userId,
allowed_company_ids: [1],
group_by: ["move_id"],
},
groupby: ["move_id"],
domain: [],
fields: ["id:sum"],
},
})}`,
]);
// weak test, no guarantee to wait long enough for the potential attachment preview to show
await contains(".o_attachment_preview", { count: 0 }); // The preview component shouldn't be mounted for small screens
await click(":nth-child(1 of .o_group_header)");
await contains(".o_data_row", { count: 2 });
await assertSteps([
`/web/dataset/call_kw/account.move.line/web_search_read - ${JSON.stringify({
kwargs: {
specification: {
id: {},
name: {},
move_id: { fields: { display_name: {} } },
move_attachment_ids: { fields: { mimetype: {} } },
},
offset: 0,
order: "",
limit: 80,
context: {
lang: "en",
tz: "taht",
uid: serverState.userId,
allowed_company_ids: [1],
bin_size: true,
group_by: ["move_id"],
default_move_id: 1,
},
count_limit: 10001,
domain: [["move_id", "=", 1]],
},
})}`,
]);
await click(":nth-child(1 of .o_data_row) :nth-child(2 of .o_data_cell)");
await contains(":nth-child(1 of .o_data_row) :nth-child(2 of .o_data_cell) input");
// weak test, no guarantee to wait long enough for the potential attachment preview to show
await contains(".o_attachment_preview", { count: 0 }); // The preview component shouldn't be mounted for small screens even when clicking on a line without attachment
await click(":nth-child(2 of .o_group_header)");
await contains(".o_data_row", { count: 4 });
await assertSteps([
`/web/dataset/call_kw/account.move.line/web_search_read - ${JSON.stringify({
kwargs: {
specification: {
id: {},
name: {},
move_id: { fields: { display_name: {} } },
move_attachment_ids: { fields: { mimetype: {} } },
},
offset: 0,
order: "",
limit: 80,
context: {
lang: "en",
tz: "taht",
uid: serverState.userId,
allowed_company_ids: [1],
bin_size: true,
group_by: ["move_id"],
default_move_id: 2,
},
count_limit: 10001,
domain: [["move_id", "=", 2]],
},
})}`,
]);
await click(":nth-child(4 of .o_data_row) :nth-child(2 of .o_data_cell)");
await contains(":nth-child(4 of .o_data_row) :nth-child(2 of .o_data_cell) input");
// weak test, no guarantee to wait long enough for the potential attachment preview to show
await contains(".o_attachment_preview", { count: 0 }); // The preview component shouldn't be mounted for small screens even when clicking on a line with attachment
await assertSteps([], "no extra rpc should be done");
});
test("Fetch and preview of attachments on big devices", async () => {
await openPreparedView(SIZES.XXL);
await contains(".o_move_line_list_view");
await assertSteps([
`/web/dataset/call_kw/account.move.line/web_read_group - ${JSON.stringify({
kwargs: {
orderby: "",
lazy: true,
offset: 0,
limit: 80,
context: {
lang: "en",
tz: "taht",
uid: serverState.userId,
allowed_company_ids: [1],
group_by: ["move_id"],
},
groupby: ["move_id"],
domain: [],
fields: ["id:sum"],
},
})}`,
]);
await contains(".o_attachment_preview");
await contains(".o_attachment_preview p", {
text: "Choose a line to preview its attachments.",
});
await contains(".o_attachment_preview iframe", { count: 0 });
await click(":nth-child(1 of .o_group_header)");
await contains(".o_data_row", { count: 2 });
await assertSteps([
`/web/dataset/call_kw/account.move.line/web_search_read - ${JSON.stringify({
kwargs: {
specification: {
id: {},
name: {},
move_id: { fields: { display_name: {} } },
move_attachment_ids: { fields: { mimetype: {} } },
},
offset: 0,
order: "",
limit: 80,
context: {
lang: "en",
tz: "taht",
uid: serverState.userId,
allowed_company_ids: [1],
bin_size: true,
group_by: ["move_id"],
default_move_id: 1,
},
count_limit: 10001,
domain: [["move_id", "=", 1]],
},
})}`,
]);
await click(":nth-child(1 of .o_data_row) :nth-child(2 of .o_data_cell)");
await contains(".o_attachment_preview iframe", { count: 0 });
await contains(".o_attachment_preview p", { text: "No attachments linked." });
await click(":nth-child(2 of .o_group_header)");
await contains(".o_data_row", { count: 4 });
await contains(".o_attachment_preview p", { text: "No attachments linked." });
await assertSteps([
`/web/dataset/call_kw/account.move.line/web_search_read - ${JSON.stringify({
kwargs: {
specification: {
id: {},
name: {},
move_id: { fields: { display_name: {} } },
move_attachment_ids: { fields: { mimetype: {} } },
},
offset: 0,
order: "",
limit: 80,
context: {
lang: "en",
tz: "taht",
uid: serverState.userId,
allowed_company_ids: [1],
bin_size: true,
group_by: ["move_id"],
default_move_id: 2,
},
count_limit: 10001,
domain: [["move_id", "=", 2]],
},
})}`,
]);
await click(":nth-child(4 of .o_data_row) :nth-child(2 of .o_data_cell)");
await contains(".o_attachment_preview p", { count: 0 });
await contains(
`.o_attachment_preview iframe[data-src='/web/static/lib/pdfjs/web/viewer.html?file=${encodeURIComponent(
getOrigin() + "/web/content/1"
)}#pagemode=none']`
);
await assertSteps([], "no extra rpc should be done");
await click(":nth-child(3 of .o_group_header)");
await contains(".o_data_row", { count: 6 });
// weak test, no guarantee to wait long enough for the potential attachment to change
await contains(
`.o_attachment_preview iframe[data-src='/web/static/lib/pdfjs/web/viewer.html?file=${encodeURIComponent(
getOrigin() + "/web/content/1"
)}#pagemode=none']`
); // The previewer content shouldn't change without clicking on another line from another account.move
await assertSteps([
`/web/dataset/call_kw/account.move.line/web_search_read - ${JSON.stringify({
kwargs: {
specification: {
id: {},
name: {},
move_id: { fields: { display_name: {} } },
move_attachment_ids: { fields: { mimetype: {} } },
},
offset: 0,
order: "",
limit: 80,
context: {
lang: "en",
tz: "taht",
uid: serverState.userId,
allowed_company_ids: [1],
bin_size: true,
group_by: ["move_id"],
default_move_id: 3,
},
count_limit: 10001,
domain: [["move_id", "=", 3]],
},
})}`,
]);
await click(":nth-child(5 of .o_data_row) :nth-child(2 of .o_data_cell)");
await contains(":nth-child(5 of .o_data_row) :nth-child(2 of .o_data_cell) input");
await contains(
`.o_attachment_preview iframe[data-src='/web/static/lib/pdfjs/web/viewer.html?file=${encodeURIComponent(
getOrigin() + "/web/content/2"
)}#pagemode=none']`
);
await assertSteps([]);
await click(":nth-child(1 of .o_data_row) :nth-child(2 of .o_data_cell)");
await contains(".o_attachment_preview iframe", { count: 0 });
await contains(".o_attachment_preview p");
await assertSteps([]);
});

View File

@@ -0,0 +1,35 @@
import { _t } from "@web/core/l10n/translation";
import { patch } from "@web/core/utils/patch";
import { accountTourSteps } from "@account/js/tours/account";
patch(accountTourSteps, {
onboarding() {
return [
{
trigger: ".o_widget_account_onboarding .fa-circle",
},
{
trigger: "a[data-method=action_open_step_fiscal_year]",
content: _t("Set Periods"),
run: "click",
},
{
trigger: "button[name=action_save_onboarding_fiscal_year]",
content: _t("Save Fiscal Year end"),
run: "click",
},
];
},
newInvoice() {
return [
{
trigger: ".o_widget_account_onboarding .fa-check-circle",
},
{
trigger: "button[name=action_create_new]",
content: _t("Now, we'll create your first invoice (accountant)"),
run: "click",
},
];
},
});

View File

@@ -0,0 +1,61 @@
/** @odoo-module */
import { accountTourSteps } from "@account/js/tours/account";
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("account_merge_wizard_tour", {
url: "/odoo",
steps: () => [
...accountTourSteps.goToAccountMenu("Go to Accounting"),
{
content: "Go to Configuration",
trigger: 'span:contains("Configuration")',
run: "click",
},
{
content: "Go to Chart of Accounts",
trigger: 'a:contains("Chart of Accounts")',
run: "click",
},
{
trigger: '.o_breadcrumb .text-truncate:contains("Chart of Accounts")',
},
{
content: "Select accounts",
trigger: "thead .o_list_record_selector",
run: "click",
},
{
content: "Check that exactly 4 accounts are present and selected",
trigger: ".o_list_selection_box:contains(4):contains(selected)",
},
{
content: "Open Actions menu",
trigger: ".o_cp_action_menus .dropdown-toggle",
run: "click",
},
{
content: "Open Merge accounts wizard",
trigger: 'span:contains("Merge accounts")',
run: "click",
},
{
content: "Group by name",
trigger: 'div[name="is_group_by_name"] input',
run: "click",
},
{
content: "Wait for content to be updated",
trigger: 'td:contains("Current Assets (Current Assets)")',
},
{
content: "Merge accounts",
trigger: 'button:not([disabled]) span:contains("Merge")',
run: "click",
},
{
content: "Check that there are now exactly 2 accounts",
trigger: "tr.o_data_row:contains(2)",
},
],
});

View File

@@ -0,0 +1,262 @@
/** @odoo-module **/
import { Asserts } from "./asserts";
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("account_reports", {
url: "/odoo/action-fusion_accounting.action_account_report_bs",
steps: () => [
//--------------------------------------------------------------------------------------------------------------
// Foldable
//--------------------------------------------------------------------------------------------------------------
{
content: "Initial foldable",
trigger: ".o_content",
run: () => {
Asserts.DOMContainsNumber("tbody > tr:not(.d-none):not(.empty)", 28);
// Since the total line is not displayed (folded), the amount should be on the line
Asserts.isEqual(
document.querySelector("tr:nth-child(4) td:nth-child(2)").textContent,
"75.00"
);
},
},
{
content: "Click to unfold line",
trigger: "tr:nth-child(4) td:first()",
run: "click",
},
{
content: "Line is unfolded",
trigger: "tr:nth-child(5) .name:contains('101401')",
run: () => {
Asserts.DOMContainsNumber("tbody > tr:not(.d-none):not(.empty)", 30);
// Since the total line is displayed (unfolded), the amount should not be on the line
Asserts.isEqual(
document.querySelector("tr:nth-child(4) td:nth-child(2)").textContent,
""
);
},
},
{
content: "Click to fold line",
trigger: "tr:nth-child(4) td:first()",
run: "click",
},
{
content: "Line is folded",
trigger: ".o_content",
run: () => {
Asserts.DOMContainsNumber("tbody > tr:not(.d-none):not(.empty)", 28);
},
},
//--------------------------------------------------------------------------------------------------------------
// Sortable
//--------------------------------------------------------------------------------------------------------------
{
content: "Unfold first line",
trigger: "tr:nth-child(4) td:first()",
run: "click",
},
{
content: "Unfold second line",
trigger: "tr:nth-child(7) td:first()",
run: "click",
},
{
content: "Unfold third line",
trigger: "tr:nth-child(10) td:first()",
run: "click",
},
{
content: "Extra Trigger step",
trigger: "tr:nth-child(12):not(.d-none) .name:contains('101404')",
},
{
content: "Initial sortable",
trigger: ".o_content",
run: () => {
// Bank and Cash Accounts
Asserts.isEqual(
document.querySelector("tr:nth-child(5) td:nth-child(2)").textContent,
"75.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(6) td:nth-child(2)").textContent,
"75.00"
);
// Receivables
Asserts.isEqual(
document.querySelector("tr:nth-child(8) td:nth-child(2)").textContent,
"25.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(9) td:nth-child(2)").textContent,
"25.00"
);
// Current Assets
Asserts.isEqual(
document.querySelector("tr:nth-child(11) td:nth-child(2)").textContent,
"100.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(12) td:nth-child(2)").textContent,
"50.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(13) td:nth-child(2)").textContent,
"150.00"
);
},
},
{
content: "Click sort",
trigger: "th .btn_sortable",
run: "click",
},
{
trigger: "tr:nth-child(11) td:nth-child(2):contains('50.00')",
},
{
content: "Unfold not previously unfolded line",
trigger: "tr:nth-child(22):contains('Current Liabilities') td:first()",
run: "click",
},
{
content: "Line is unfolded",
trigger: "tr:nth-child(23) .name:contains('251000')",
run: "click",
},
{
content: "Sortable (asc)",
trigger: "tr:nth-child(11) td:nth-child(2):contains('50.00')",
run: () => {
// Bank and Cash Accounts
Asserts.isEqual(
document.querySelector("tr:nth-child(5) td:nth-child(2)").textContent,
"75.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(6) td:nth-child(2)").textContent,
"75.00"
);
// Receivables
Asserts.isEqual(
document.querySelector("tr:nth-child(8) td:nth-child(2)").textContent,
"25.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(9) td:nth-child(2)").textContent,
"25.00"
);
// Current Assets
Asserts.isEqual(
document.querySelector("tr:nth-child(11) td:nth-child(2)").textContent,
"50.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(12) td:nth-child(2)").textContent,
"100.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(13) td:nth-child(2)").textContent,
"150.00"
);
},
},
{
content: "Click sort",
trigger: "th .btn_sortable",
run: "click",
},
{
content: "Sortable (desc)",
trigger: "tr:nth-child(11) td:nth-child(2):contains('100.00')",
run: () => {
// Bank and Cash Accounts
Asserts.isEqual(
document.querySelector("tr:nth-child(5) td:nth-child(2)").textContent,
"75.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(6) td:nth-child(2)").textContent,
"75.00"
);
// Receivables
Asserts.isEqual(
document.querySelector("tr:nth-child(8) td:nth-child(2)").textContent,
"25.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(9) td:nth-child(2)").textContent,
"25.00"
);
// Current Assets
Asserts.isEqual(
document.querySelector("tr:nth-child(11) td:nth-child(2)").textContent,
"100.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(12) td:nth-child(2)").textContent,
"50.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(13) td:nth-child(2)").textContent,
"150.00"
);
},
},
{
content: "Click sort",
trigger: "th .btn_sortable",
run: "click",
},
{
content: "Sortable (reset)",
trigger: "tr:nth-child(5) td:nth-child(2):contains('75.00')",
run: () => {
// Bank and Cash Accounts
Asserts.isEqual(
document.querySelector("tr:nth-child(5) td:nth-child(2)").textContent,
"75.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(6) td:nth-child(2)").textContent,
"75.00"
);
// Receivables
Asserts.isEqual(
document.querySelector("tr:nth-child(8) td:nth-child(2)").textContent,
"25.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(9) td:nth-child(2)").textContent,
"25.00"
);
// Current Assets
Asserts.isEqual(
document.querySelector("tr:nth-child(11) td:nth-child(2)").textContent,
"100.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(12) td:nth-child(2)").textContent,
"50.00"
);
Asserts.isEqual(
document.querySelector("tr:nth-child(13) td:nth-child(2)").textContent,
"150.00"
);
},
},
],
});

View File

@@ -0,0 +1,94 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add('account_reports_rounding_unit', {
url: '/odoo/action-fusion_accounting.action_account_report_bs',
steps: () => [
{
content: 'Test the value of `Receivables` line in decimals',
trigger: '.line_name:contains("Receivables") + .line_cell:contains("1,150,000.00")',
run: "click",
},
// Units
{
content: "Open amounts rounding dropdown",
trigger: "#filter_rounding_unit button",
run: 'click',
},
{
content: "Select the units filter",
trigger: ".dropdown-item:contains('In $')",
run: 'click',
},
{
trigger:
'.line_name:contains("Receivables") + .line_cell:not(:contains("1,150,000.00"))',
},
{
content: 'test the value of `Receivables` line in units',
// We wait for the value to change.
// We check the new value.
trigger: '.line_name:contains("Receivables") + .line_cell:contains("1,150,000")',
run: "click",
},
// Thousands
{
content: "Open amounts rounding dropdown",
trigger: "#filter_rounding_unit button",
run: 'click',
},
{
content: "Select the thousands filter",
trigger: ".dropdown-item:contains('In K$')",
run: 'click',
},
{
trigger: '.line_name:contains("Receivables") + .line_cell:not(:contains("1,150,000"))',
},
{
content: 'test the value of `Receivables` line in thousands',
// We wait for the value to change.
// We check the new value.
trigger: '.line_name:contains("Receivables") + .line_cell:contains("1,150")',
run: "click",
},
// Millions
{
content: "Open amounts rounding dropdown",
trigger: "#filter_rounding_unit button",
run: 'click',
},
{
content: "Select the millions filter",
trigger: ".dropdown-item:contains('In M$')",
run: 'click',
},
{
trigger: '.line_name:contains("Receivables") + .line_cell:not(:contains("1,150"))',
},
{
content: 'test the value of `Receivables` line in millions',
// We wait for the value to change.
// We check the new value.
trigger: '.line_name:contains("Receivables") + .line_cell:contains("1")',
run: "click",
},
// Decimals
{
content: "Open amounts rounding dropdown",
trigger: "#filter_rounding_unit button",
run: 'click',
},
{
content: "Select the decimals filter",
trigger: ".dropdown-item:contains('In .$')",
run: 'click',
},
{
content: 'test the value of `Receivables` line in millions',
trigger: '.line_name:contains("Receivables") + .line_cell:contains("1,150,000.00")',
run: () => null,
},
]
});

View File

@@ -0,0 +1,28 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("account_reports_analytic_filters", {
url: "/odoo/action-fusion_accounting.action_account_report_general_ledger",
steps: () => [
{
content: "click analytic filters",
trigger: ".filter_analytic button",
run: "click",
},
{
content: "insert text in the searchbar",
trigger: ".o_multi_record_selector input",
run: "edit Time",
},
{
content: "click on the item",
trigger: '.o-autocomplete--dropdown-item:contains("Time Off")',
run: "click",
},
{
content: "Check the label of the badge",
trigger: '.dropdown-menu .o_tag_badge_text:contains("Time Off")',
},
],
});

View File

@@ -0,0 +1,298 @@
/** @odoo-module **/
import { Asserts } from "./asserts";
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("account_reports_annotations", {
url: "/odoo/action-fusion_accounting.action_account_report_bs",
steps: () => [
//--------------------------------------------------------------------------------------------------------------
// Annotations
//--------------------------------------------------------------------------------------------------------------
// Test the initial status of annotations - There are 2 annotations to display
{
content: "Initial annotations",
trigger: ".o_content",
run: () => {
Asserts.DOMContainsNone(".annotations");
},
},
{
content: "Unfold first line",
trigger: "tr:nth-child(4) td:first()",
run: "click",
},
{
content: "Unfold second line",
trigger: "tr:nth-child(7) td:first()",
run: "click",
},
{
content: "Unfold third line",
trigger: "tr:nth-child(10) td:first()",
run: "click",
},
{
content: "Extra Trigger step",
trigger: "tr:nth-child(12):not(.d-none) .name:contains('101404')",
},
{
content: "Check there are two lines annotated initially",
trigger: ".o_content",
run: () => {
const annotations = document.querySelectorAll(".btn_annotation .fa-commenting");
// Check the number of annotated lines
Asserts.isEqual(annotations.length, 2);
// Check the annotations buttons are on the right lines
Asserts.isTrue(
annotations[0] ===
document.querySelector("tr:nth-child(5)").querySelector(".fa-commenting")
);
Asserts.isTrue(
annotations[1] ===
document.querySelector("tr:nth-child(12)").querySelector(".fa-commenting")
);
},
},
// Test that we can add a new annotation
{
content: "Click to show caret option",
trigger: "tr:nth-child(8) .dropdown-toggle",
run: "click",
},
{
content: "Caret option is displayed",
trigger: "tr:nth-child(8)",
run: () => {
Asserts.hasClass("tr:nth-child(8) .o-dropdown", "show");
},
},
{
content: "Click on annotate",
trigger: ".o-dropdown--menu .dropdown-item:last-of-type:contains('Annotate')",
run: "click",
},
{
content: "Add text to annotate",
trigger: "textarea",
run: "edit Annotation 121000",
},
{
content: "Submit annotation by blurring",
trigger: "textarea",
run: function () {
const annotation = this.anchor;
annotation.dispatchEvent(new InputEvent("input"));
annotation.dispatchEvent(new Event("change"));
},
},
{
content: "Wait for annotation created",
trigger: "tr:nth-child(8) .btn_annotation .fa-commenting",
},
{
content: "Close annotation",
trigger: ".o_content",
run: "click",
},
{
content: "Check there are now three lines annotated",
trigger: ".o_content",
run: () => {
const annotations = document.querySelectorAll(".btn_annotation .fa-commenting");
// Check the number of annotated lines
Asserts.isEqual(annotations.length, 3);
// Check the annotations buttons are on the right lines
Asserts.isTrue(
annotations[0] ===
document.querySelector("tr:nth-child(5)").querySelector(".fa-commenting")
);
Asserts.isTrue(
annotations[1] ===
document.querySelector("tr:nth-child(8)").querySelector(".fa-commenting")
);
Asserts.isTrue(
annotations[2] ===
document.querySelector("tr:nth-child(12)").querySelector(".fa-commenting")
);
},
},
// Test that we can edit an annotation
{
content: "Open second annotated line annotation popover",
trigger: "tr:nth-child(8) .btn_annotation",
run: "click",
},
{
content: "Annotate contains previous text value",
trigger: "textarea",
run: () => {
Asserts.isEqual(document.querySelector("textarea").value, "Annotation 121000");
},
},
{
content: "Add text to annotate",
trigger: "textarea",
run: "edit Annotation 121000 edited",
},
{
content: "Annotation is edited",
trigger: "tr:nth-child(8) .btn_annotation",
run: () => {
Asserts.isEqual(
document.querySelector(".annotation_popover_autoresize_textarea").value,
"Annotation 121000 edited"
);
},
},
// Test that we can delete an annotation by clicking the trash icon
{
content: "Click on trash can",
trigger: ".btn_annotation_delete",
run: "click",
},
{
content: "Check there are now only two lines annotated",
trigger: "tr:nth-child(8):not(:has(.fa-commenting))",
run: () => {
const annotations = document.querySelectorAll(".btn_annotation .fa-commenting");
// Check the number of annotated lines
Asserts.isEqual(annotations.length, 2);
// Check the annotations buttons are on the right lines
Asserts.isTrue(
annotations[0] ===
document.querySelector("tr:nth-child(5)").querySelector(".fa-commenting")
);
Asserts.isTrue(
annotations[1] ===
document.querySelector("tr:nth-child(12)").querySelector(".fa-commenting")
);
},
},
// Test that we can add an annotation by clicking on the "New" button inside the popover
{
content: "Open an annotated line annotation popover",
trigger: "tr:nth-child(12) .btn_annotation",
run: "click",
},
{
content: "Click on the 'New' button",
trigger: ".annotation_popover_line .oe_link",
run: "click",
},
{
content: "Add text to annotate",
trigger: "textarea:last()",
run: "edit Annotation 101404 bis",
},
{
content: "Submit annotation by blurring",
trigger: "textarea:last()",
run: function () {
const annotation = this.anchor;
annotation.dispatchEvent(new InputEvent("input"));
annotation.dispatchEvent(new Event("change"));
},
},
// Check the current state of the annotations
{
content: "Check there are two annotated lines to end the test",
trigger: ".o_content",
run: () => {
const annotations = document.querySelectorAll(".btn_annotation .fa-commenting");
// Check there is only one annotated line
Asserts.isEqual(annotations.length, 2);
// Check the annotation buttons are on the right lines
Asserts.isTrue(
annotations[0] ===
document.querySelector("tr:nth-child(5)").querySelector(".fa-commenting")
);
Asserts.isTrue(
annotations[1] ===
document.querySelector("tr:nth-child(12)").querySelector(".fa-commenting")
);
},
},
//--------------------------------------------------------------------------------------------------------------
// Annotations dates
//--------------------------------------------------------------------------------------------------------------
{
content:
"Remove first annotation to only have one annotation on line 12 (required setup step)",
trigger: ".annotation_popover tr:nth-child(2) .btn_annotation_delete",
run: "click",
},
{
content: "Verify that we still have one element",
trigger: ".annotation_popover tr:nth-child(3):contains('Add a line')",
},
{
content: "Modify the date of an annotation to a further period",
trigger: ".annotation_popover tr:nth-child(2) input",
run: "edit 01/01/2100",
},
{
content: "Modify the date of an annotation to a further period",
trigger: ".annotation_popover tr:nth-child(2) input",
run: function () {
// Since the t-on-change of the input is not triggered by the run: "edit" action,
// we need to dispatch the event manually requiring a function.
const input = this.anchor;
input.dispatchEvent(new InputEvent("input"));
input.dispatchEvent(new Event("change", { bubbles: true }));
},
},
{
content: "Check that there is no annotation anymore on line 12",
trigger: "tr:nth-child(12):not(:has(.fa-commenting))",
},
{
content: "change date filter",
trigger: "#filter_date button",
run: "click",
},
{
content: "Open specific date button",
trigger: ".dropdown-menu div.dropdown-item",
run: "click",
},
{
content: "Go to 15 January 2100",
trigger: ".o_datetime_input",
run: "edit 01/15/2100",
},
{
content: "Apply filter by closing the dropdown",
trigger: "#filter_date .btn:first()",
run: "click",
},
{
content: "wait refresh",
trigger: `#filter_date button:not(:contains(${new Date().getFullYear()}))`,
},
{
content: "Check there is one annotation on line 12",
trigger: "tr:nth-child(12):has(.fa-commenting)",
run: () => {
const annotations = document.querySelectorAll(".btn_annotation .fa-commenting");
// Check there is only one annotated line
Asserts.isEqual(annotations.length, 1);
// Check the annotation buttons are on the right lines
Asserts.isTrue(
annotations[0] ===
document.querySelector("tr:nth-child(12)").querySelector(".fa-commenting")
);
}
},
]
});

View File

@@ -0,0 +1,107 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add('account_reports_hide_0_lines', {
url: '/odoo/action-fusion_accounting.action_account_report_bs',
steps: () => [
{
content: 'test if the Bank and Cash line is present (but the value is 0)',
trigger: '.line_name:contains("Bank and Cash Accounts")',
run: "click",
},
{
content: 'test if the Current Year Unallocated Earnings line is present (but the value is 0)',
trigger: '.line_name:contains("Current Year Unallocated Earnings")',
run: "click",
},
{
content: 'test if the Unallocated Earnings line is present (but value is different from 0 and so should be there after the hide_0_lines',
trigger: '.line_name:contains("Unallocated Earnings")',
run: "click",
},
{
content: "Open options selector",
trigger: "#filter_extra_options button",
run: 'click',
},
{
content: "Select the hide line at 0 option",
trigger: ".dropdown-item:contains('Hide lines at 0')",
run: 'click',
},
{
content: 'test if the Unallocated Earnings line is still present',
trigger: '.line_name:contains("Unallocated Earnings")',
run: "click",
},
{
content: 'test if the Bank and Cash line is not present',
trigger: '.line_name:not(:contains("Bank and Cash Accounts"))',
run: "click",
},
{
content: 'test if the Current Year Unallocated Earnings line is not present',
trigger: '.line_name:not(:contains("Current Year Unallocated Earnings"))',
run: "click",
},
{
content: "Click again to open the options selector",
trigger: "#filter_extra_options button",
run: 'click',
},
{
content: "Select the hide lines at 0 option again",
trigger: ".dropdown-item:contains('Hide lines at 0')",
run: 'click',
},
{
content: 'test again if the Bank and Cash line is present (but the value is 0)',
trigger: '.line_name:contains("Bank and Cash Accounts")',
run: () => null,
},
]
});
registry.category("web_tour.tours").add('account_reports_hide_0_lines_with_string_columns', {
url: '/odoo/action-fusion_accounting.action_account_report_general_ledger',
steps: () => [
{
content: "Check if the 211000 Account Payable line is present (but the value is 0)",
trigger: ".name:contains('211000 Account Payable')",
run: "click",
},
{
content: "Check if the MISC item line is present with string values set up, but all amounts are at 0",
trigger: ".name:contains('Coucou les biloutes')",
},
{
content: "Open options selector",
trigger: "#filter_extra_options button",
run: 'click',
},
{
content: "Select the hide line at 0 option",
trigger: ".dropdown-item:contains('Hide lines at 0')",
run: 'click',
},
{
content: "Check if the MISC item line is hidden",
trigger: ":not(:visible):contains('Coucou les biloutes')",
},
{
content: "Click again to open the options selector",
trigger: "#filter_extra_options button",
run: 'click',
},
{
content: "Select the hide lines at 0 option again",
trigger: ".dropdown-item:contains('Hide lines at 0')",
run: 'click',
},
{
content: "Check again if the MISC item line is present (but the value is 0)",
trigger: ".name:contains('Coucou les biloutes')",
},
]
});

View File

@@ -0,0 +1,43 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add('account_reports_search', {
url: '/odoo/action-fusion_accounting.action_account_report_general_ledger',
steps: () => [
{
content: "click search",
trigger: '.o_searchview_input',
run: 'click',
},
{
content: 'insert text in the searchbar',
trigger: '.o_searchview_input',
run: "edit 40",
},
{
content: 'test if the product sale line is present',
trigger: '.line_name:contains("400000 Product Sales")',
run: "click",
},
{
content: "click search",
trigger: '.o_searchview_input',
run: 'click',
},
{
content: 'insert text in the search bar',
trigger: '.o_searchview_input',
run: "edit Account",
},
{
content: 'test if the receivable line is present',
trigger: '.line_name:contains("121000 Account Receivable")',
run: 'click',
},
{
content: 'check that the product sale line is not present',
trigger: '.line_name:not(:contains("400000 Product Sales"))',
},
]
});

View File

@@ -0,0 +1,129 @@
/** @odoo-module **/
const { DateTime } = luxon;
import { Asserts } from "./asserts";
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add('account_reports_sections', {
url: "/odoo/action-fusion_accounting.action_account_report_gt",
steps: () => [
{
content: "Open variant selector",
trigger: "#filter_variant button",
run: 'click',
},
{
content: "Select the test variant using sections",
trigger: ".dropdown-item:contains('Test Sections')",
run: 'click',
},
{
content: "Check the lines of section 1 are displayed",
trigger: ".line_name:contains('Section 1 line')",
},
{
content: "Check the columns of section 1 are displayed",
trigger: "#table_header th:last():contains('Column 1')",
},
{
content: "Check the export buttons belong to the composite report",
trigger: ".btn:contains('composite_report_custom_button')",
},
{
content: "Check the filters displayed belong to section 1 (journals filter is not enabled on section 2, nor the composite report)",
trigger: "#filter_journal",
},
{
content: "Check the date chosen by default",
trigger: "#filter_date",
run: (actionHelper) => {
// Generic tax report opens on the previous period and in this case the period is one month.
// And since we are using the generic tax report, we need to go back one month.
const previousMonth = DateTime.now().minus({months: 1});
Asserts.isTrue(actionHelper.anchor.getElementsByTagName('button')[0].innerText.includes(previousMonth.year));
},
},
{
content: "Switch to section 2",
trigger: "#section_selector .btn:contains('Section 2')",
run: 'click',
},
{
content: "Check the lines of section 2 are displayed",
trigger: ".line_name:contains('Section 2 line')",
},
{
content: "Check the columns of section 2 are displayed",
trigger: "#table_header th:last():contains('Column 2')",
},
{
content: "Check the export buttons belong to the composite report",
trigger: ".btn:contains('composite_report_custom_button')",
},
{
content: "Check the filters displayed belong to section 2 (comparison filter is not enabled on section 1, nor the composite report)",
trigger: "#filter_comparison",
},
{
content: "Open date switcher",
trigger: "#filter_date button",
run: 'click',
},
{
content: "Select another date in the future",
trigger: ".dropdown-menu span.dropdown-item:nth-child(3) .btn_next_date",
run: 'click'
},
{
content: "Apply filter by closing the dropdown for the future date",
trigger: "#filter_date .btn:first()",
run: "click",
},
{
content: "Check that the date has changed",
trigger: `#filter_date button:not(:contains(${ DateTime.now().minus({months: 1}).year }))`, // We need to remove one month for the case where we are in january. It will impact the year.
run: (actionHelper) => {
const nextYear = DateTime.now().plus({years: 1}).year;
Asserts.isTrue(actionHelper.anchor.innerText.includes(nextYear));
},
},
{
content: "Open date switcher",
trigger: "#filter_date button",
run: 'click',
},
{
content: "Select another date first time",
trigger: ".dropdown-menu span.dropdown-item:nth-child(3) .btn_previous_date",
run: 'click'
},
{
trigger: `.dropdown-menu span.dropdown-item:nth-child(3) time:contains(${ DateTime.now().year})`,
},
{
content: "Select another date second time",
trigger: ".dropdown-menu span.dropdown-item:nth-child(3) .btn_previous_date",
run: 'click'
},
{
trigger: `.dropdown-menu span.dropdown-item:nth-child(3) time:contains(${ DateTime.now().minus({years: 1}).year })`,
},
{
content: "Apply filter by closing the dropdown",
trigger: "#filter_date .btn:first()",
run: "click",
},
{
content: "Check that the date has changed",
trigger: `#filter_date button:contains(${ DateTime.now().minus({years: 1}).year })`,
},
{
content: "Switch back to section 1",
trigger: "#section_selector .btn:contains('Section 1')",
run: 'click',
},
]
});

View File

@@ -0,0 +1,82 @@
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("account_reports_widgets", {
url: "/odoo/action-fusion_accounting.action_account_report_pl",
steps: () => [
{
content: "change date filter",
trigger: "#filter_date button",
run: "click",
},
{
content: "Select another date in the future",
trigger: ".dropdown-menu span.dropdown-item:nth-child(3) .btn_next_date",
run: 'click'
},
{
content: "Apply filter by closing the dropdown",
trigger: "#filter_date .btn:first()",
run: "click",
},
{
content: "wait refresh",
trigger: `#filter_date button:not(:contains(${ new Date().getFullYear() }))`,
},
{
content: "change date filter for the second time",
trigger: "#filter_date button",
run: "click",
},
{
content: "Select another date in the past first time",
trigger: ".dropdown-menu span.dropdown-item:nth-child(3) .btn_previous_date",
run: 'click'
},
{
trigger: `.dropdown-menu span.dropdown-item:nth-child(3) time:contains(${new Date().getFullYear()})`,
},
{
content: "Select another date in the past second time",
trigger: ".dropdown-menu span.dropdown-item:nth-child(3) .btn_previous_date",
run: 'click'
},
{
trigger: `.dropdown-menu span.dropdown-item:nth-child(3) time:contains(${
new Date().getFullYear() - 1
})`,
},
{
content: "Apply filter by closing the dropdown",
trigger: "#filter_date .btn:first()",
run: "click",
},
{
content: "wait refresh",
trigger: `#filter_date button:contains(${ new Date().getFullYear() - 1 })`,
},
{
content: "change comparison filter",
trigger: "#filter_comparison .btn:first()",
run: "click",
},
{
content: "change comparison filter",
trigger: ".dropdown-item.period:first()",
run: "click",
},
{
content: "Apply filter by closing the dropdown",
trigger: "#filter_comparison .btn:first()",
run: "click",
},
{
content: "wait refresh, report should have 4 columns",
trigger: "th + th + th + th",
},
{
content: "export xlsx",
trigger: "button:contains('XLSX')",
run: "click",
},
],
});

View File

@@ -0,0 +1,10 @@
/** @odoo-module **/
import { patch } from "@web/core/utils/patch";
import { accountTourSteps } from "@account/js/tours/account";
import { stepUtils } from "@web_tour/tour_service/tour_utils";
patch(accountTourSteps, {
goToAccountMenu(description="Open Accounting Menu") {
return stepUtils.goToAppSteps('fusion_accounting.menu_accounting', description);
}
});

View File

@@ -0,0 +1,115 @@
/** @odoo-module **/
//----------------------------------------------------------------------------------------------------------------------
// This class provides some helpers function to do assertions on tours
//----------------------------------------------------------------------------------------------------------------------
export class Asserts {
//------------------------------------------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------------------------------------------
// Gets the number of 'selector' element inside 'target' element
static getCount(target, selector) {
return document.querySelector(target).querySelectorAll(selector).length;
}
// Gets the number of 'selector' element inside DOM
static getDOMCount(selector) {
return document.querySelectorAll(selector).length;
}
static check(condition, success, error) {
condition ? Asserts.success(success) : Asserts.error(error);
}
static success(message) {
return console.info(`SUCCESS: ${message}`);
}
static error(message) {
throw new Error(`FAIL: ${message}`);
}
//------------------------------------------------------------------------------------------------------------------
// Asserts
//------------------------------------------------------------------------------------------------------------------
static isTrue(actual) {
Asserts.check(actual, `${actual} is true`, `${actual} is not true`);
}
static isFalse(actual) {
Asserts.check(!actual, `${actual} is false`, `${actual} is not false`);
}
// Assert that 'actual' and 'expected' are equal
static isEqual(actual, expected) {
Asserts.check(
(actual == expected),
`${actual} is equal to expected ${expected}`,
`${actual} is not equal to expected ${expected}`
);
}
// Asserts that 'actual' and 'expected' are strictly equal
static isStrictEqual(actual, expected) {
Asserts.check(
(actual === expected),
`${actual} is strictly equal to expected ${expected}`,
`${actual} is not strictly equal to expected ${expected}`
);
}
// Assert that 'target' element contains at least one 'selector' element
static contains(target, selector) {
const count = Asserts.getCount(target, selector);
Asserts.check(
(count > 0),
`There is at least one ${selector} in ${target}`,
`There should be at least one ${selector} in ${target} but there is ${count}`
);
}
// Asserts there is no 'selector' element in 'target' element
static containsNone(target, selector) {
const count = Asserts.getCount(target, selector);
Asserts.check(
(count === 0),
`There is no ${selector} in ${target}`,
`There should be no ${selector} in ${target} but there is ${count}`
);
}
// Asserts that 'target' element contains 'number' of 'selector' elements
static containsNumber(target, selector, number) {
const count = Asserts.getCount(target, selector);
Asserts.check(
(count === number),
`There is the correct number (${number}) of ${selector} in ${target}`,
`There should be at ${number} ${selector} in ${target} but there is ${count}`
);
}
// Asserts that DOM contains at least one 'selector' element
static DOMContains(selector) {
const count = Asserts.getDOMCount(selector);
Asserts.check(
(count > 0),
`There is at least one ${selector} in the DOM`,
`There should be at least one ${selector} in the DOM but there is ${count}`
);
}
// Asserts there is no 'selector' element in the DOM
static DOMContainsNone(selector) {
const count = Asserts.getDOMCount(selector);
Asserts.check(
(count === 0),
`There is no ${selector} in the DOM`,
`There should be 0 ${selector} in the DOM but there is ${count}`
);
}
// Asserts that DOM contains 'number' of 'selector' element
static DOMContainsNumber(selector, number) {
const count = Asserts.getDOMCount(selector);
Asserts.check(
(Asserts.getDOMCount(selector) === number),
`There is the correct number (${number}) of ${selector} in the DOM`,
`There should be ${number} ${selector} in the DOM but there is ${count}`
);
}
// Asserts that 'selector' element has class 'classname'
static hasClass(selector, classname) {
Asserts.check(
document.querySelector(selector).classList.contains(classname),
`${selector} has class ${classname}`,
`${selector} should have class ${classname} but hasn't`
);
}
}

View File

@@ -0,0 +1,91 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { stepUtils } from "@web_tour/tour_service/tour_utils";
import { accountTourSteps } from "@account/js/tours/account";
registry.category("web_tour.tours").add("fusion_accounting_bank_rec_widget_rainbowman_reset", {
url: "/odoo",
steps: () => [
stepUtils.showAppsMenuItem(),
...accountTourSteps.goToAccountMenu("Open the accounting module"),
// Open the widget. The first line should be selected by default.
{
trigger: ".o_breadcrumb",
},
{
content: "Open the bank reconciliation widget",
trigger: "button.btn-secondary[name='action_open_reconcile']",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line1')",
},
{
content: "'line1' should be selected and form mounted",
trigger: ".o_bank_rec_selected_st_line:contains('line1')",
},
// Rainbowman gets reset
{
content: "Mount invoice 2 for line 1",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table td[name='move_id']:contains('INV/2019/00002')",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00002')",
},
{
content: "Validate line1",
trigger: "button:contains('Validate')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line2')",
},
{
content: "No records brings rainbows",
trigger: "div.o_kanban_view .o_searchview_input",
run: "fill thisShouldNotReturnAnyRecords",
},
{
content: "Select the Journal Entry search option from the dropdown",
trigger: ".o_searchview_autocomplete li:contains(Journal Entry)",
run: "click",
},
{
trigger: ".o_reward_rainbow_man:contains('You reconciled 1 transaction in')",
},
{
content: "Remove the filter while rainbow man is on screen",
trigger: ".o_kanban_view .o_searchview_facet:nth-child(3) .o_facet_remove",
run: "click",
},
{
trigger: ".o_bank_rec_st_line:contains('line2')",
},
{
content: "Search for no results again",
trigger: "div.o_kanban_view .o_searchview_input",
run: "fill thisShouldNotReturnAnyRecords",
},
{
content: "Select the Journal Entry search option from the dropdown",
trigger: ".o_searchview_autocomplete li:contains(Journal Entry)",
run: "click",
},
{
content: "No content helper is displayed instead of rainbowman",
trigger: ".o_view_nocontent_smiling_face",
},
// End
...stepUtils.toggleHomeMenu(),
...accountTourSteps.goToAccountMenu("Reset back to accounting module"),
{
content: "check that we're back on the dashboard",
trigger: 'a:contains("Customer Invoices")',
},
],
});

View File

@@ -0,0 +1,95 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { stepUtils } from "@web_tour/tour_service/tour_utils";
import { accountTourSteps } from "@account/js/tours/account";
registry.category("web_tour.tours").add('fusion_accounting_bank_rec_widget_statements',
{
url: '/odoo',
steps: () => [
stepUtils.showAppsMenuItem(),
...accountTourSteps.goToAccountMenu("Open the accounting module"),
{
trigger: ".o_breadcrumb",
},
{
content: "Open the bank reconciliation widget",
trigger: "button.btn-secondary[name='action_open_reconcile']",
run: "click",
},
{
content: "Statement button",
trigger:
".o_bank_rec_st_line:eq(2) a.oe_kanban_action:contains('Statement'):not(:visible)",
run: "click",
},
{
trigger: ".modal-dialog:contains('Create Statement')",
},
{
content: "Save the statement with proposed values",
trigger: ".o_form_button_save",
run: "click",
},
{
content: "Click the Valid Statement with $ 1,000.00 that is visible in Kanban",
trigger: "span[name='kanban-subline-clickable-amount']:contains('$ 1,000.00')",
run: "click",
},
{
content: "Modify the end balance",
trigger: "input[id='balance_end_real_0']",
run: "edit 100 && click body",
},
{
trigger: ".alert-warning:contains('The running balance')",
},
{
content: "Dialog displays warning, save anyway",
trigger: ".breadcrumb-item.o_back_button:nth-of-type(2)",
run: "click",
},
{
trigger: ".btn-link:contains('$ 2,100.00')",
},
{
content: "Click the red statement, after checking the balance",
trigger: "span[name='kanban-subline-clickable-amount']:contains('$ 100.00')",
run: "click",
},
{
content: "Back in the form view",
trigger: ".alert-warning:contains('The running balance')",
},
{
content: "Click on Action",
trigger: ".o_cp_action_menus button",
run: "click",
},
{
content: "Click on Delete",
trigger: ".o-dropdown--menu span:contains('Delete')",
run: "click",
},
{
content: "Confirm Deletion",
trigger: ".btn-primary:contains('Delete')",
run: "click",
},
{
trigger: ".o_kanban_renderer:not(:has(.kanban-statement))",
},
{
content: "balance displays $3000.00 and no statement",
trigger: ".btn-link:contains('$ 3,000')",
},
// End
...stepUtils.toggleHomeMenu(),
...accountTourSteps.goToAccountMenu("Reset back to accounting module"),
{
content: "check that we're back on the dashboard",
trigger: 'a:contains("Customer Invoices")',
}
]
});

View File

@@ -0,0 +1,983 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { stepUtils } from "@web_tour/tour_service/tour_utils";
import { patch } from "@web/core/utils/patch";
import { accountTourSteps } from "@account/js/tours/account";
patch(accountTourSteps, {
bankRecUiReportSteps() {
return [
{
trigger: ".o_bank_rec_selected_st_line:contains('line1')",
},
{
content: "balance is 2100",
trigger: ".btn-link:contains('$ 2,100.00')",
},
];
},
});
patch(accountTourSteps, {
bankRecUiReportSteps() {
return [
{
trigger: ".o_bank_rec_selected_st_line:contains('line1')",
},
{
content: "balance is 2100",
trigger: ".btn-link:contains('$ 2,100.00')",
run: "click",
},
{
trigger: "span:contains('General Ledger')",
},
{
content: "Breadcrumb back to Bank Reconciliation from the report",
trigger: ".breadcrumb-item a:contains('Bank Reconciliation')",
run: "click",
},
];
},
});
registry.category("web_tour.tours").add("fusion_accounting_bank_rec_widget_ui", {
url: "/odoo",
steps: () => [
stepUtils.showAppsMenuItem(),
...accountTourSteps.goToAccountMenu("Open the accounting module"),
// Open the widget. The first line should be selected by default.
{
trigger: ".o_breadcrumb",
},
{
content: "Open the bank reconciliation widget",
trigger: "button.btn-secondary[name='action_open_reconcile']",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line1')",
},
{
content: "'line1' should be selected and form mounted",
trigger: ".o_bank_rec_selected_st_line:contains('line1')",
},
// Select line2. It should remain selected when returning using the breadcrumbs.
{
trigger: ".o_bank_rec_st_line:contains('line3')",
},
{
content: "select 'line2'",
trigger: ".o_bank_rec_st_line:contains('line2')",
run: "click",
},
{
content: "'line2' should be selected",
trigger: ".o_bank_rec_selected_st_line:contains('line2')",
},
{
content: "View an invoice",
trigger: "button.btn-secondary[name='action_open_business_doc']:eq(1)",
run: "click",
},
{
trigger: ".o_breadcrumb .active:contains('INV/2019/00001')",
},
{
content: "Breadcrumb back to Bank Reconciliation from INV/2019/00001",
trigger: ".breadcrumb-item:contains('Bank Reconciliation')",
run: "click",
},
{
trigger: ".o_bank_rec_st_line:contains('line1')",
},
{
content: "'line2' should be selected after returning",
trigger: ".o_bank_rec_selected_st_line:contains('line2')",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line2')",
},
{
content: "'line2' form mounted",
trigger: ".o_bank_rec_selected_st_line:contains('line2')",
run: "click",
},
// Keep AML search, and prepared entry (line_ids) when changing tabs, using breadcrumbs, and view switcher
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr:nth-child(2) td[name='move_id']:contains('INV/2019/00001')",
},
{
content: "AMLs list has both invoices",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr:nth-child(1) td[name='move_id']:contains('INV/2019/00002')",
},
{
trigger: "a.active[name='amls_tab']",
},
{
content: "Search for INV/2019/00001",
trigger: "div.bank_rec_widget_form_amls_list_anchor .o_searchview_input",
run: "edit INV/2019/00001",
},
{
content: "Select the Journal Entry search option from the dropdown",
trigger: ".o_searchview_autocomplete li:contains(Journal Entry)",
run: "click",
},
{
content: "AMLs list only displays one invoice",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr:nth-child(1) td[name='move_id']:contains('INV/2019/00001')",
},
{
content: "Liquidity line displays debit '$ 1,000.00'",
trigger:
"div[name='line_ids'] table.o_list_table tr.o_bank_rec_liquidity_line td[field='debit']:contains('$ 1,000.00')",
},
{
content: "Select the liquidity line",
trigger: "tr.o_bank_rec_liquidity_line td[field='debit']",
run: "click",
},
{
content: "Modify the liquidity line amount",
trigger: "div[name='amount_currency'] input",
run: "edit 100.00 && click body",
},
{
content: "Liquidity line displays debit '$ 100.00'",
trigger:
"div[name='line_ids'] table.o_list_table tr.o_bank_rec_liquidity_line td[field='debit']:contains('$ 100.00')",
},
{
trigger: "div[name='partner_id'] input",
},
{
content: "Select 'amls_tab'",
trigger: "a[name='amls_tab']",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor .o_searchview_facet:nth-child(1) .o_facet_value:contains('INV/2019/00001')",
},
{
content: "AMLs list contains the search facet, and one invoice - select it",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr:nth-child(1) td[name='move_id']:contains('INV/2019/00001')",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00001')",
},
{
content: "Check INV/2019/00001 is well marked as selected",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00001')",
},
{
content: "View an invoice",
trigger: "button.btn-secondary[name='action_open_business_doc']:nth-child(1)",
run: "click",
},
{
trigger: ".o_breadcrumb .active:contains('INV/2019/00001')",
},
{
content: "Breadcrumb back to Bank Reconciliation from INV/2019/00001",
trigger: ".breadcrumb-item:contains('Bank Reconciliation')",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor .o_searchview_facet:nth-child(1) .o_facet_value:contains('INV/2019/00001')",
},
{
content: "Check INV/2019/00001 is selected and still contains the search facet",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00001')",
},
// Search should remove some lines, select the first unmatched record, and persist when returning with breadcrumbs
{
trigger: "a.active[name='amls_tab']",
},
{
content: "Search for line2",
trigger: "div.o_kanban_view .o_searchview_input",
run: "fill line2",
},
{
content: "Select the Transaction search option from the dropdown",
trigger: ".o_searchview_autocomplete li:contains(Transaction)",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line2')",
},
{
content: "'line2' should be selected",
trigger: ".o_bank_rec_st_line:last():contains('line2')",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor .o_searchview_facet:nth-child(1) .o_facet_value:contains('INV/2019/00001')",
},
{
content:
"Nothing has changed: INV/2019/00001 is selected and still contains the search facet",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00001')",
},
{
trigger: ".o_switch_view.o_kanban.active",
},
{
content: "Switch to list view",
trigger: ".o_switch_view.o_list",
run: "click",
},
{
trigger: ".o_switch_view.o_list.active",
},
{
content: "Switch back to kanban",
trigger: ".o_switch_view.o_kanban",
run: "click",
},
{
content: "Remove the kanban filter for line2",
trigger: ".o_kanban_view .o_searchview_facet:nth-child(3) .o_facet_remove",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor .o_searchview_facet:nth-child(1) .o_facet_value:contains('INV/2019/00001')",
},
{
content:
"Nothing has changed: INV/2019/00001 is still selected and contains the search facet",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00001')",
},
// AML Search Facet is removed, and line_ids reset when changing line
{
trigger: ".o_bank_rec_st_line:contains('line3')",
},
{
content: "selecting 'line1' should reset the AML search filter ",
trigger: ".o_bank_rec_st_line:contains('line1')",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line1')",
},
{
content: "select 'line2' again",
trigger: ".o_bank_rec_st_line:contains('line2')",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line2')",
},
{
content: "Bank Suspense Account is back",
trigger: "div[name='line_ids'] .o_bank_rec_auto_balance_line",
},
{
content: "AML Search Filter has been reset",
trigger: ".o_list_view .o_searchview_input_container:not(:has(.o_searchview_facet))",
},
// Test statement line selection when using the pager
{
content: "Click Pager",
trigger: ".o_pager_value:first()",
run: "click",
},
{
content: "Change pager to display lines 1-2",
trigger: "input.o_pager_value",
run: "edit 1-2 && click body",
},
{
trigger: ".o_pager_value:contains('1-2')",
},
{
content: "Last St Line is line2",
trigger: ".o_bank_rec_st_line:last():contains('line2')",
},
{
content: "Page Next",
trigger: ".o_pager_next:first():not(:disabled)",
run: "click",
},
{
trigger: ".o_pager_value:contains('3-3')",
},
{
content: "Statement line3 is selected",
trigger: ".o_bank_rec_selected_st_line:contains('line3')",
},
{
content: "Page to beginning",
trigger: ".o_pager_next:first()",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line1')",
},
{
content: "Statement line1 is selected",
trigger: ".o_bank_rec_selected_st_line:contains('line1')",
},
// HTML buttons
{
content: "Mount an invoice",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table td[name='move_id']:contains('INV/2019/00003')",
run: "click",
},
{
trigger:
"div[name='line_ids']:has(.text-decoration-line-through:contains('$ 2,000.00'))",
},
{
content: "Select the mounted invoice line and check the strikethrough value",
trigger:
"div[name='line_ids'] tr.o_data_row:last() td[field='name']:contains('INV/2019/00003')",
run: "click",
},
{
trigger: "a.active[name='manual_operations_tab']",
},
{
content: "Fully Paid button",
trigger: "button[name='action_apply_line_suggestion']:contains('fully paid')",
run: "click",
},
{
content: "Check the remainder",
trigger:
"div[name='line_ids'] tr.o_data_row:contains('Suspense') td[field='debit']:contains('$ 1,000.00')",
},
{
content: "Partial Payment",
trigger: "button[name='action_apply_line_suggestion']:contains('partial payment')",
run: "click",
},
{
trigger: "button[name='action_apply_line_suggestion']:contains('fully paid')",
},
{
content: "View Invoice 0003",
trigger: "button[name='action_redirect_to_move']",
run: "click",
},
{
trigger: ".o_breadcrumb .active:contains('INV/2019/00003')",
},
{
content: "Breadcrumb back to Bank Reconciliation from INV/2019/00003",
trigger: ".breadcrumb-item:contains('Bank Reconciliation')",
run: "click",
},
{
content: "Select the mounted invoice line INV/2019/00003",
trigger:
"div[name='line_ids'] tr.o_data_row:last() td[field='name']:contains('INV/2019/00003')",
run: "click",
},
// Match Existing entries tab is activated when line is removed
{
trigger: "a.active[name='manual_operations_tab']",
},
{
content: "Remove the invoice",
trigger: ".o_list_record_remove .fa-trash-o",
run: "click",
},
{
content: "amls_tab is activated",
trigger: "a.active[name='amls_tab']",
},
{
content: "Activate Manual Operations to add manual entries",
trigger: "a[name='manual_operations_tab']",
run: "click",
},
{
content: "add manual entry 1",
trigger: "div[name='amount_currency'] input",
run: "edit -600.0 && click body",
},
{
content: "mount the remaining opening balance line",
trigger:
"div[name='line_ids'] tr.o_data_row:contains('Suspense') td[field='credit']:contains('$ 400.00')",
run: "click",
},
{
trigger: "div[name='amount_currency'] input:value('-400.00'):focus-within",
},
{
content: "Remove the manual entry",
trigger: ".o_list_record_remove .fa-trash-o",
run: "click",
},
{
trigger:
"div[name='line_ids'] tr.o_data_row:contains('Suspense') td[field='credit']:contains('$ 1,000.00')",
},
{
content: "amls_tab is activated and auto balancing line is 1000",
trigger: "a.active[name='amls_tab']",
},
{
content: "Mount another invoice",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table td[name='move_id']:contains('INV/2019/00001')",
run: "click",
},
// After validating, line1 should disappear & line2 should be selected (due to filters)
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00001')",
},
{
content: "Validate line1",
trigger: "button:contains('Validate')",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line2')",
},
{
content: "The 'line2' is the first kanban record and is selected",
trigger: ".o_bank_rec_st_line:first():contains('line2')",
},
// Test Reset, "Matched" badge and double-click
{
content: "Remove the kanban filter for 'Not Matched'",
trigger: ".o_kanban_view .o_searchview_facet:nth-child(2) .o_facet_remove",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line2')",
},
{
content: "The 'line1' is the first kanban record with line2 selected",
trigger: ".o_bank_rec_st_line:first():contains('line1')",
},
{
content: "Mount invoice 2 for line 2",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table td[name='move_id']:contains('INV/2019/00002')",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00002')",
},
{
content: "Validate line2 with double click",
trigger: "button:contains('Validate')",
run: "dblclick",
},
{
trigger: ".o_bank_rec_st_line:contains('line2') .badge.text-bg-success",
},
{
content: "Click Pager again after line2 is matched",
trigger: ".o_pager_value:first()",
run: "click",
},
{
content: "Change pager to display lines 1-3",
trigger: "input.o_pager_value",
run: "edit 1-3 && click body",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line3')",
},
{
content: "manually select line2 again by clicking it's matched icon",
trigger: ".badge.text-bg-success:last()",
run: "click",
},
{
trigger:
"div[name='line_ids']:not(:has(.fa-trash-o)) td[field='name']:contains('line2')",
},
{
content: "Reset line2",
trigger: "button:contains('Reset')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line2'):not(:has(div.badge))",
},
{
content: "amls_tab is activated while still on line2 which doesn't contain a badge",
trigger: ".o_notebook a.active[name='amls_tab']",
},
// Test view_switcher
{
trigger: ".o_switch_view.o_kanban.active",
},
{
content: "Switch to list view",
trigger: ".o_switch_view.o_list",
run: "click",
},
{
trigger: ".btn-secondary:contains('View')",
},
{
content: "Select the first Match Button (line2)",
trigger: ".btn-secondary:contains('Match')",
run: "click",
},
{
trigger: ".o_bank_rec_st_line:last():contains('line2')",
},
{
content: "Last St Line is line2",
trigger: ".o_bank_rec_selected_st_line:contains('line2')",
run: "click",
},
{
content: "Button To Check will reconcile since partner is saved on line2",
trigger: ".btn-secondary:contains('To Check')",
run: "click",
},
{
trigger:
".o_bank_rec_selected_st_line:contains('line2'):has(div.badge[title='Matched'] i):has(span.badge:contains('To check'))",
},
{
content: "both badges are visible, trash icon is not, manual operation tab is active",
trigger:
"div[name='line_ids']:not(:has(.fa-trash-o))+.o_notebook a.active[name='manual_operations_tab']",
},
{
trigger: ".o_switch_view.o_kanban.active",
},
{
content: "Switch to list view",
trigger: ".o_switch_view.o_list",
run: "click",
},
{
trigger: ".o_switch_view.o_list.active",
},
{
content: "Remove the line filter",
trigger: ".o_searchview_facet:contains('0002') .o_facet_remove",
run: "click",
},
{
trigger: ".o_data_row:contains('line2'):has(.btn-secondary:contains('View'))",
},
{
content: "Select the first Match Button (line3)",
trigger: ".btn-secondary:contains('Match')",
run: "click",
},
{
trigger: ".o_bank_rec_stats_buttons",
},
{
content: "Open search bar menu",
trigger: ".o_searchview_dropdown_toggler:eq(0)",
run: "click",
},
// Test Reco Model
{
trigger: ".o-dropdown--menu.o_search_bar_menu",
},
{
content: "Choose a filter",
trigger: ".o_search_bar_menu .dropdown-item:first()",
run: "click",
},
{
trigger: ".o-dropdown--menu",
},
{
content: "Not Matched Filter",
trigger: ".dropdown-item:contains('Not Matched')",
run: "click",
},
{
trigger: ".o_switch_view.o_kanban.active",
},
{
content: "reco model dropdown",
trigger: ".bank_rec_reco_model_dropdown i",
run: "click",
},
{
trigger: ".o-dropdown--menu",
},
{
content: "create model",
trigger: ".dropdown-item:contains('Create model')",
run: "click",
},
{
content: "model name",
trigger: "input#name_0",
run: "edit Bank Fees",
},
{
content: "add an account",
trigger: "a:contains('Add a line')",
run: "click",
},
{
content: "search for bank fees account",
trigger: "[name='account_id'] input",
run: "edit Bank Fees",
},
{
trigger: ".o-autocomplete--dropdown-menu",
},
{
content: "select the bank fees account",
trigger: ".o-autocomplete--dropdown-item:contains('Bank Fees')",
run: "click",
},
{
trigger: ".o_breadcrumb .active > span:contains('New')",
},
{
content: "Breadcrumb back to Bank Reconciliation from the model",
trigger: ".breadcrumb-item:contains('Bank Reconciliation')",
run: "click",
},
{
content: "Choose Bank Fees Model",
trigger: ".recon_model_button:contains('Bank Fees')",
run: "click",
},
{
content: "Validate line3",
trigger: "button:contains('Validate').btn-primary",
run: "dblclick",
},
{
trigger: ".o_reward_rainbow_man",
},
{
content:
"Remove the kanbans 'not matched' filter to reset all lines - use the rainbow man button",
trigger: "p.btn-primary:contains('All Transactions')",
run: "click",
},
{
trigger:
".o_kanban_view .o_searchview:first() .o_searchview_facet:last():contains('Bank')",
},
{
content: "Wait for search model change and line3 to appear",
trigger: ".o_bank_rec_st_line:last():contains('line3')",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line2')",
},
{
content: "'line2' should be selected, reset it",
trigger: "button:contains('Reset')",
run: "click",
},
{
trigger: ".o_bank_rec_st_line:contains('line2'):not(:has(div.badge))",
},
{
content: "select matched 'line3'",
trigger: ".o_bank_rec_st_line:contains('line3')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line3')",
},
{
content: "'line3' should be selected, reset it",
trigger: "button:contains('Reset')",
run: "click",
},
{
trigger: ".o_bank_rec_st_line:contains('line3'):not(:has(div.badge))",
},
{
content: "select matched 'line1'",
trigger: ".o_bank_rec_st_line:contains('line1')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line1')",
},
{
content: "'line1' should be selected, reset it",
trigger: "button:contains('Reset')",
run: "click",
},
{
trigger: ".o_bank_rec_stats_buttons",
},
{
content: "Open search bar menu",
trigger: ".o_searchview_dropdown_toggler:eq(0)",
run: "click",
},
{
trigger: "button:contains('Validate')",
},
{
content: "Filter Menu",
trigger: ".o_search_bar_menu .dropdown-item:first()",
run: "click",
},
{
trigger: ".o-dropdown--menu",
},
{
content: "Activate the Not Matched filter",
trigger: ".dropdown-item:contains('Not Matched')",
run: "click",
},
{
trigger: ".o_searchview_facet:contains('Not Matched')",
},
{
content: "Close the Filter Menu",
trigger: ".o_searchview_dropdown_toggler:eq(0)",
run: "click",
},
{
trigger: ".o_searchview_facet:contains('Not Matched')",
},
{
content: "select 'line2'",
trigger: ".o_bank_rec_st_line:contains('line2')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line2')",
},
{
content: "Validate 'line2' again",
trigger: "button:contains('Validate')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line3')",
},
{
content: "'line3' should be selected now",
trigger: ".o_bank_rec_selected_st_line:contains('line3')",
},
// Test the Balance when changing journal and liquidity line
...stepUtils.toggleHomeMenu(),
...accountTourSteps.goToAccountMenu("Reset back to accounting module"),
{
trigger: ".o_breadcrumb",
},
{
content: "Open the bank reconciliation widget for Bank2",
trigger: "button.btn-secondary[name='action_open_reconcile']:last()",
run: "click",
},
{
content: "Remove the kanbans 'not matched' filter",
trigger: ".o_kanban_view .o_searchview_facet:nth-child(2) .o_facet_remove",
run: "click",
},
{
content: "Remove the kanban 'journal' filter",
trigger: ".o_kanban_view .o_searchview_facet:nth-child(1) .o_facet_remove",
run: "click",
},
{
content: "select 'line1' from another journal",
trigger: ".o_bank_rec_st_line:contains('line1')",
run: "click",
},
...accountTourSteps.bankRecUiReportSteps(),
{
content: "select 'line4' from this journal",
trigger: ".o_bank_rec_st_line:contains('line4')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line4')",
},
{
content: "balance is $222.22",
trigger: ".btn-link:contains('$ 222.22')",
},
{
content: "Select the liquidity line",
trigger: "tr.o_bank_rec_liquidity_line td[field='debit']",
run: "click",
},
{
trigger: "div[name='amount_currency'] input:focus-within",
},
{
content: "Modify the liquidity line amount",
trigger: "div[name='amount_currency'] input",
run: "edit -333.33 && click body",
},
{
trigger: ".btn-link:contains('$ -333.33')",
},
{
content: "balance displays $-333.33",
trigger: ".btn-link:contains('$ -333.33')",
},
{
content: "Modify the label",
trigger: "div[name='name'] input",
run: "edit Spontaneous Combustion && click body",
},
{
content: "statement line displays combustion and $-333.33",
trigger: ".o_bank_rec_selected_st_line:contains('Combustion'):contains('$ -333.33')",
},
// Test that changing the balance in the list view updates the right side of the kanban view
// (including reapplying matching rules)
{
content: "select matched 'line2'",
trigger: ".o_bank_rec_st_line:contains('line2')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line2')",
},
{
content: "'line2' should be selected, reset it",
trigger: "button:contains('Reset')",
run: "click",
},
{
trigger: ".o_bank_rec_selected_st_line:contains('line2'):not(:has(div.badge))",
},
{
content: "Liquidity line displays debit '$ 100.00'",
trigger:
"div[name='line_ids'] table.o_list_table tr.o_bank_rec_liquidity_line td[field='debit']:contains('$ 100.00')",
},
{
trigger: ".o_switch_view.o_kanban.active",
},
{
content: "Switch to list view",
trigger: ".o_switch_view.o_list",
run: "click",
},
{
content: "Click amount field of 'line2'; Selects the row",
trigger: "table.o_list_table tr.o_data_row:contains('line2') td[name='amount']",
run: "click",
},
{
content: "Set balance of 'line2' (selected row) to 500.00",
trigger: "table.o_list_table tr.o_data_row.o_selected_row td[name='amount'] input",
run: "edit 500.00 && click body",
},
{
trigger: ".o_switch_view.o_list.active",
},
{
content: "Switch back to kanban",
trigger: ".o_switch_view.o_kanban",
run: "click",
},
{
content: "'line2' is still selected",
trigger: ".o_bank_rec_st_line:contains('line2')",
},
{
content: "Liquidity line displays debit '$ 500.00'",
trigger:
"div[name='line_ids'] table.o_list_table tr.o_bank_rec_liquidity_line td[field='debit']:contains('$ 500.00')",
},
{
content:
"'INV/2019/00001' has been selected as matching existing entry by matching rules",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='name']:contains('INV/2019/00001')",
},
// End
...stepUtils.toggleHomeMenu(),
...accountTourSteps.goToAccountMenu("Reset back to accounting module"),
{
content: "check that we're back on the dashboard",
trigger: 'a:contains("Customer Invoices")',
},
],
});
registry.category("web_tour.tours").add('fusion_accounting_bank_rec_widget_reconciliation_button',
{
url: '/odoo',
steps: () => [
stepUtils.showAppsMenuItem(),
...accountTourSteps.goToAccountMenu("Open the accounting module"),
{
content: "Open the bank reconciliation widget",
trigger: "button.btn-secondary[name='action_open_reconcile']",
run: "click",
},
{
content: "Remove suggested line, if present",
trigger: ".o_list_record_remove",
run() {
const button = document.querySelector('.fa-trash-o');
if(button) {
button.click();
}
}
},
{
content: "Wait for deletion",
trigger: ".o_data_row:contains('Open balance')",
},
{
content: "Select reconciliation model creating a new move",
trigger: ".recon_model_button:contains('test reconcile')",
run: "click",
},
{
content: "Confirm move created through reconciliation model writeoff button",
trigger: "button[name=action_post]",
run: "click",
},
{
trigger: ".o_breadcrumb",
},
{
content: "Breadcrumb back to Bank Reconciliation from created move",
trigger: ".breadcrumb-item:contains('Bank Reconciliation')",
run: "click",
},
{
content: "Validate created move added as a line in reco widget",
trigger: "button:contains('Validate')",
run: "click",
},
// End
...stepUtils.toggleHomeMenu(),
...accountTourSteps.goToAccountMenu("Reset back to accounting module"),
{
content: "check that we're back on the dashboard",
trigger: 'a:contains("Customer Invoices")',
},
],
});

View File

@@ -0,0 +1,236 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { stepUtils } from "@web_tour/tour_service/tour_utils";
import { accountTourSteps } from "@account/js/tours/account";
registry.category("web_tour.tours").add("fusion_accounting_bank_rec_widget", {
url: "/odoo",
steps: () => [
stepUtils.showAppsMenuItem(),
...accountTourSteps.goToAccountMenu("Open the accounting module"),
// Open the widget. The first line should be selected by default.
{
trigger: ".o_breadcrumb",
},
{
content: "Open the bank reconciliation widget",
trigger: "button.btn-secondary[name='action_open_reconcile']",
run: "click",
},
{
trigger: "div[name='line_ids']",
},
{
content: "The 'line1' should be selected by default",
trigger: "div[name='line_ids'] td[field='name']:contains('line1')",
},
// Test 1: Check the loading of lazy notebook tabs.
// Check 'amls_tab' (active by default).
{
trigger: "div.bank_rec_widget_form_amls_list_anchor table.o_list_table",
},
{
content: "The 'amls_tab' should be active and the inner list view loaded",
trigger: "a.active[name='amls_tab']",
},
// Check 'discuss_tab'.
{
trigger: "a.active[name='amls_tab']",
},
{
content: "Click on the 'discuss_tab'",
trigger: "a[name='discuss_tab']",
run: "click",
},
{
trigger: "a.active[name='discuss_tab']",
},
{
content: "The 'discuss_tab' should be active and the chatter loaded",
trigger: "div.bank_rec_widget_form_discuss_anchor div.o-mail-Chatter",
},
// Check 'manual_operations_tab'.
{
trigger: "tr.o_bank_rec_auto_balance_line",
},
{
content: "Click on the 'auto_balance' to make the 'manual_operations_tab' visible",
trigger: "tr.o_bank_rec_auto_balance_line td[field='name']",
run: "click",
},
{
content: "The 'manual_operations_tab' should be active",
trigger: "a.active[name='manual_operations_tab']",
},
{
content: "The 'name' field should be focus automatically",
trigger: "div.o_notebook div[name='name'] input:focus",
},
{
trigger: "tr.o_bank_rec_auto_balance_line",
},
{
content: "Click on the 'credit' field to change the focus from 'name' to 'amount_currency'",
trigger: "tr.o_bank_rec_auto_balance_line td[field='credit']",
run: "click",
},
{
content: "Wait to avoid non-deterministic errors on the next step",
trigger: "tr.o_bank_rec_auto_balance_line td[field='credit']",
},
{
content: "The 'balance' field should be focus now",
trigger: "div.o_notebook div[name='amount_currency'] input:focus",
},
// Test 2: Test validation + auto select the next line.
{
trigger: "a.active[name='manual_operations_tab']",
},
{
content: "Click on the 'amls_tab'",
trigger: "a[name='amls_tab']",
run: "click",
},
{
trigger: "a.active[name='amls_tab']",
},
{
content: "Mount INV/2019/00002",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table td[name='move_id']:contains('INV/2019/00002')",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00002')",
},
{
content: "Check INV/2019/00002 is well marked as selected",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00002')",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00002')",
},
{
content: "Remove INV/2019/00002",
trigger: "tr td.o_list_record_remove button",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr:not(.o_rec_widget_list_selected_item) td[name='move_id']:contains('INV/2019/00002')",
},
{
content: "Mount INV/2019/00001",
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table td[name='move_id']:contains('INV/2019/00001')",
run: "click",
},
{
trigger:
"div.bank_rec_widget_form_amls_list_anchor table.o_list_table tr.o_rec_widget_list_selected_item td[name='move_id']:contains('INV/2019/00001')",
},
{
content: "Validate",
trigger: "button:contains('Validate')",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line2')",
},
{
content: "The 'line2' is the next not already reconciled line",
trigger: "div[name='line_ids'] td[field='name']:contains('line2')",
},
// Test 3: Test manual operations tab.
{
content: "Click on 'credit'",
trigger: "div[name='line_ids'] td[field='credit']:last",
run: "click",
},
{
content:
"The 'manual_operations_tab' should be active now and the auto_balance line mounted in edit",
trigger: "a.active[name='manual_operations_tab']",
},
{
content: "The last line should be selected",
trigger: "div[name='line_ids'] tr.o_bank_rec_selected_line",
},
{
content: "Search for 'partner_a'",
trigger: "div[name='partner_id'] input",
run: "edit partner_a",
},
{
trigger: ".ui-autocomplete .o_m2o_dropdown_option a:contains('Create')",
},
{
content: "Select 'partner_a'",
trigger: ".ui-autocomplete:visible li:contains('partner_a')",
run: "click",
},
{
trigger:
"tr:not(.o_bank_rec_auto_balance_line) td[field='partner_id']:contains('partner_a')",
},
{
content: "Select the payable account",
trigger: "button:contains('Payable')",
run: "click",
},
{
trigger:
"tr:not(.o_bank_rec_auto_balance_line) td[field='account_id']:contains('Payable')",
},
{
content: "Enter a tax",
trigger: "div[name='tax_ids'] input",
run: "edit 15",
},
{
trigger: ".ui-autocomplete",
},
{
content: "Select 'Tax 15% (Sales)'",
trigger: ".ui-autocomplete:visible li:contains('Sales')",
run: "click",
},
{
content: "Tax column appears in list of lines",
trigger: "div[name='line_ids'] td[field='tax_ids']",
},
{
content: "Wait to avoid non-deterministic errors on the next step",
trigger: "div[name='line_ids'] td:contains('Tax Received')",
},
{
trigger: "button.btn-primary:contains('Validate')",
},
{
content: "Validate",
trigger: "button:contains('Validate')",
run: "click",
},
{
trigger: "div[name='line_ids'] td[field='name']:contains('line3')",
},
{
content: "The 'line3' is the next not already reconciled line",
trigger: "div[name='line_ids'] td[field='name']:contains('line3')",
},
...stepUtils.toggleHomeMenu(),
...accountTourSteps.goToAccountMenu("Reset back to accounting module"),
{
content: "check that we're back on the dashboard",
trigger: 'a:contains("Customer Invoices")',
},
],
});

View File

@@ -0,0 +1,56 @@
import { expect, test } from "@odoo/hoot";
import { buildLineId, parseLineId, removeTaxGroupingFromLineId } from "@fusion_accounting/js/util";
test("can build a line id from a list of [markup, res_model, res_id]", () => {
const values = [
[false, "account.account", 72],
[null, "account.move", "10"],
[undefined, "account.move.line", "22"],
["name", false, null],
['{"groupby": "account"}', false, null],
];
expect(buildLineId(values)).toBe(
'~account.account~72|~account.move~10|~account.move.line~22|name~~|{"groupby": "account"}~~'
);
});
test("can parse a line id from a generic id with a markup as object", () => {
const genericId =
'~account.account~72|~account.move~10|~account.move.line~22|name~~|{"groupby": "account"}~~';
expect(parseLineId(genericId)).toEqual([
[null, "account.account", 72],
[null, "account.move", 10],
[null, "account.move.line", 22],
["name", null, null],
[{ groupby: "account" }, null, null],
]);
});
test("can parse a line id from a generic id with a markup as string", () => {
const genericId =
'~account.account~72|~account.move~10|~account.move.line~22|name~~|{"groupby": "account"}~~';
expect(parseLineId(genericId, true)).toEqual([
[null, "account.account", 72],
[null, "account.move", 10],
[null, "account.move.line", 22],
["name", null, null],
['{"groupby": "account"}', null, null],
]);
});
test("can parse and rebuild a line id to have the same one", () => {
const genericId =
'~account.account~72|~account.move~10|~account.move.line~22|name~~|{"groupby": "account"}~~';
const parsedLineId = parseLineId(genericId);
const buildedGenericId = buildLineId(parsedLineId);
expect(buildedGenericId).toBe(genericId);
});
test("can remove tax grouping by account group", () => {
const genericId =
'{"groupby": "account_group_id"}~account.group~22|~account.account~21|~account.move.line~20';
expect(removeTaxGroupingFromLineId(genericId)).toBe(
"~account.account~21|~account.move.line~20"
);
});