/** @odoo-module */
import { registry } from "@web/core/registry";
import { fillTemporalService } from "@crm/views/fill_temporal_service";
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
import {
click,
dragAndDrop,
getFixture,
patchDate,
} from '@web/../tests/helpers/utils';
const serviceRegistry = registry.category("services");
let target;
QUnit.module('Crm Forecast Model Extension', {
beforeEach: async function () {
serviceRegistry.add("fillTemporalService", fillTemporalService);
this.testKanbanView = {
arch: `
`,
searchViewArch: `
`,
serverData: {
models: {
'crm.lead': {
fields: {
name: {string: 'Name', type: 'char'},
date_deadline: {string: "Expected closing", type: 'date'},
date_closed: {string: "Closed Date", type: 'datetime'},
},
records: [
{id: 1, name: 'Lead 1', date_deadline: '2021-01-01', date_closed: '2021-01-01 00:00:00'},
{id: 2, name: 'Lead 2', date_deadline: '2021-01-20', date_closed: '2021-01-20 00:00:00'},
{id: 3, name: 'Lead 3', date_deadline: '2021-02-01', date_closed: '2021-02-01 00:00:00'},
{id: 4, name: 'Lead 4', date_deadline: '2021-02-20', date_closed: '2021-02-20 00:00:00'},
{id: 5, name: 'Lead 5', date_deadline: '2021-03-01', date_closed: '2021-03-01 00:00:00'},
{id: 6, name: 'Lead 6', date_deadline: '2021-03-20', date_closed: '2021-03-20 00:00:00'},
],
},
},
views: {},
},
resModel: 'crm.lead',
type: "kanban",
context: {
search_default_forecast: true,
search_default_groupby_date_deadline: true,
forecast_field: 'date_deadline',
},
groupBy: ['date_deadline'],
};
target = getFixture();
setupViewRegistries();
patchDate(2021, 1, 10, 0, 0, 0);
},
}, function () {
QUnit.test("filter out every records before the start of the current month with forecast_filter for a date field", async function (assert) {
// the filter is used by the forecast model extension, and applies the forecast_filter context key,
// which adds a domain constraint on the field marked in the other context key forecast_field
assert.expect(7);
await makeView(this.testKanbanView);
// the filter is active
assert.containsN(target, '.o_kanban_group', 2, "There should be 2 columns");
assert.containsN(target, '.o_kanban_group:nth-child(1) .o_kanban_record', 2,
"1st column February should contain 2 record");
assert.containsN(target, '.o_kanban_group:nth-child(2) .o_kanban_record', 2,
"2nd column March should contain 2 records");
// remove the filter
await click($(target).find(".o_searchview_facet:contains(Forecast)")[0], ".o_facet_remove");
assert.containsN(target, '.o_kanban_group', 3, "There should be 3 columns");
assert.containsN(target, '.o_kanban_group:nth-child(1) .o_kanban_record', 2,
"1st column January should contain 2 record");
assert.containsN(target, '.o_kanban_group:nth-child(2) .o_kanban_record', 2,
"2nd column February should contain 2 records");
assert.containsN(target, '.o_kanban_group:nth-child(3) .o_kanban_record', 2,
"3nd column March should contain 2 records");
});
QUnit.test("filter out every records before the start of the current month with forecast_filter for a datetime field", async function (assert) {
// same tests as for the date field
assert.expect(7);
await makeView({
...this.testKanbanView,
context: {
search_default_forecast: true,
search_default_groupby_date_closed: true,
forecast_field: 'date_closed',
},
groupBy: ['date_closed'],
});
// with the filter
assert.containsN(target, '.o_kanban_group', 2, "There should be 2 columns");
assert.containsN(target, '.o_kanban_group:nth-child(1) .o_kanban_record', 2,
"1st column February should contain 2 record");
assert.containsN(target, '.o_kanban_group:nth-child(2) .o_kanban_record', 2,
"2nd column March should contain 2 records");
// remove the filter
await click($(target).find(".o_searchview_facet:contains(Forecast)")[0], ".o_facet_remove");
assert.containsN(target, '.o_kanban_group', 3, "There should be 3 columns");
assert.containsN(target, '.o_kanban_group:nth-child(1) .o_kanban_record', 2,
"1st column January should contain 2 record");
assert.containsN(target, '.o_kanban_group:nth-child(2) .o_kanban_record', 2,
"2nd column February should contain 2 records");
assert.containsN(target, '.o_kanban_group:nth-child(3) .o_kanban_record', 2,
"3nd column March should contain 2 records");
});
});
QUnit.module('Crm Fill Temporal Service', {
/**
* Remark: -> the filter with the groupBy is needed for the model_extension to access the groupby
* when created with makeView. Not needed in production.
* -> testKanbanView.groupBy is still needed to apply the groupby on the view
*/
beforeEach: async function () {
serviceRegistry.add("fillTemporalService", fillTemporalService);
this.testKanbanView = {
arch: `
`,
searchViewArch: `
`
,
serverData: {
models: {
'crm.lead': {
fields: {
name: {string: 'Name', type: 'char'},
date_deadline: {string: "Expected Closing", type: 'date'},
},
},
},
views: {},
},
resModel: 'crm.lead',
type: "kanban",
context: {
search_default_forecast: true,
search_default_groupby_date_deadline: true,
forecast_field: 'date_deadline',
},
groupBy: ['date_deadline'],
};
target = getFixture();
setupViewRegistries();
patchDate(2021, 9, 10, 0, 0, 0);
},
}, function () {
/**
* Since mock_server does not support fill_temporal,
* we only check the domain and the context sent to the read_group, as well
* as the end value of the FillTemporal Service after the read_group (which should have been updated in the model)
*/
QUnit.test("Forecast on months, until the end of the year of the latest data", async function (assert) {
assert.expect(3);
this.testKanbanView.serverData.models['crm.lead'].records = [
{id: 1, name: 'Lead 1', date_deadline: '2021-01-01'},
{id: 2, name: 'Lead 2', date_deadline: '2021-02-01'},
{id: 3, name: 'Lead 3', date_deadline: '2021-11-01'},
{id: 4, name: 'Lead 4', date_deadline: '2022-01-01'},
];
const kanban = await makeView({
...this.testKanbanView,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/crm.lead/web_read_group') {
assert.deepEqual(args.kwargs.context.fill_temporal, {
fill_from: "2021-10-01",
min_groups: 4,
});
assert.deepEqual(args.kwargs.domain, [
"&", "|",
["date_deadline", "=", false], ["date_deadline", ">=", "2021-10-01"],
"|",
["date_deadline", "=", false], ["date_deadline", "<", "2023-01-01"],
]);
}
},
});
assert.strictEqual(kanban.env.services.fillTemporalService.getFillTemporalPeriod({
modelName: 'crm.lead',
field: {
name: 'date_deadline',
type: 'date',
},
granularity: 'month',
}).end.toFormat('yyyy-MM-dd'), '2022-02-01');
});
/**
* Since mock_server does not support fill_temporal,
* we only check the domain and the context sent to the read_group, as well
* as the end value of the FillTemporal Service after the read_group (which should have been updated in the model)
*/
QUnit.test("Forecast on years, until the end of the year of the latest data", async function (assert) {
assert.expect(3);
this.testKanbanView.serverData.models['crm.lead'].records = [
{id: 1, name: 'Lead 1', date_deadline: '2021-01-01'},
{id: 2, name: 'Lead 2', date_deadline: '2022-02-01'},
{id: 3, name: 'Lead 3', date_deadline: '2027-11-01'},
];
const kanban = await makeView({
...this.testKanbanView,
groupBy: ['date_deadline:year'],
searchViewArch: this.testKanbanView.searchViewArch.replace("'date_deadline'", "'date_deadline:year'"),
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/crm.lead/web_read_group') {
assert.deepEqual(args.kwargs.context.fill_temporal, {
fill_from: "2021-01-01",
min_groups: 4,
});
assert.deepEqual(args.kwargs.domain, [
"&", "|",
["date_deadline", "=", false], ["date_deadline", ">=", "2021-01-01"],
"|",
["date_deadline", "=", false], ["date_deadline", "<", "2025-01-01"],
]);
}
},
});
assert.strictEqual(kanban.env.services.fillTemporalService.getFillTemporalPeriod({
modelName: 'crm.lead',
field: {
name: 'date_deadline',
type: 'date',
},
granularity: 'year',
}).end.toFormat('yyyy-MM-dd'), '2023-01-01');
});
});
QUnit.module('Crm Forecast main flow with progressBars', (hooks) => {
function getCounters() {
return [...target.querySelectorAll(".o_animated_number")].map((counter) => counter.innerText);
}
function getProgressBarsColors() {
return [...target.querySelectorAll(".o_column_progress")].map(columnProgressEl => {
return [...columnProgressEl.querySelectorAll(".progress-bar")].map(progressBarEl => {
return [...progressBarEl.classList.values()].filter(htmlClass => {
return htmlClass.startsWith('bg-');
})[0];
})
});
}
hooks.beforeEach(() => {
serviceRegistry.add("fillTemporalService", fillTemporalService);
this.testKanbanView = {
arch: `
`,
searchViewArch: `
`
,
serverData: {
models: {
'crm.lead': {
fields: {
color: {string: 'Color', type: 'string'},
date_deadline: {string: 'Expected Closing', type: 'date'},
int_field: {string: 'Value', type: 'integer', sortable: true},
name: {string: 'Name', type: 'char'},
},
},
},
views: {},
},
resModel: 'crm.lead',
type: "kanban",
context: {
search_default_forecast: true,
search_default_groupby_date_deadline: true,
forecast_field: 'date_deadline',
},
groupBy: ['date_deadline'],
};
target = getFixture();
setupViewRegistries();
// first september 2023
patchDate(2023, 8, 1, 0, 0, 0);
});
QUnit.test("Forecast drag&drop and add column", async (assert) => {
this.testKanbanView.serverData.models['crm.lead'].records = [
{id: 1, int_field: 7, color: 'd', name: 'Lead 1', date_deadline: '2023-09-03'},
{id: 2, int_field: 20, color: 'w', name: 'Lead 2', date_deadline: '2023-09-05'},
{id: 3, int_field: 300, color: 's', name: 'Lead 3', date_deadline: '2023-10-10'},
];
await makeView({
...this.testKanbanView,
async mockRPC(route, args) {
assert.step(args.method || route);
},
});
assert.deepEqual(getCounters(), ["27", "300"]);
assert.deepEqual(getProgressBarsColors(), [["bg-warning", "bg-danger"], ["bg-success"]]);
await dragAndDrop(
".o_kanban_group:first-child .o_kanban_record",
".o_kanban_group:nth-child(2)"
);
assert.deepEqual(getCounters(), ["20", "307"]);
assert.deepEqual(getProgressBarsColors(), [["bg-warning"], ["bg-success", "bg-danger"]]);
await click(target, ".o_kanban_add_column");
// Counters and progressbars should be unchanged after adding a column.
assert.deepEqual(getCounters(), ["20", "307"]);
assert.deepEqual(getProgressBarsColors(), [["bg-warning"], ["bg-success", "bg-danger"]]);
assert.verifySteps([
// makeView
"get_views",
"read_progress_bar",
"web_read_group",
"web_search_read",
"web_search_read",
// drag&drop
"web_save",
"read_progress_bar",
"web_read_group",
// add column
"read_progress_bar",
"web_read_group",
"web_search_read",
"web_search_read",
]);
});
});