[REF] stock: convert client action "stock_report_generic"
This commit is to convert the "stock_report_generic" client action into owl. closes odoo/odoo#112064 Taskid: 3175084 Related: odoo/upgrade#4309 Signed-off-by: Steve Van Essche <svs@odoo.com>
This commit is contained in:
@@ -231,17 +231,13 @@ class MrpStockReport(models.TransientModel):
|
||||
specific_paperformat_args={'data-report-margin-top': 17, 'data-report-header-spacing': 12}
|
||||
)
|
||||
|
||||
def _get_html(self):
|
||||
result = {}
|
||||
rcontext = {}
|
||||
def _get_main_lines(self):
|
||||
context = dict(self.env.context)
|
||||
rcontext['lines'] = self.with_context(context).get_lines()
|
||||
result['html'] = self.env['ir.qweb']._render('stock.report_stock_inventory', rcontext)
|
||||
return result
|
||||
return self.with_context(context).get_lines()
|
||||
|
||||
@api.model
|
||||
def get_html(self, given_context=None):
|
||||
def get_main_lines(self, given_context=None):
|
||||
res = self.search([('create_uid', '=', self.env.uid)], limit=1)
|
||||
if not res:
|
||||
return self.create({}).with_context(given_context)._get_html()
|
||||
return res.with_context(given_context)._get_html()
|
||||
return self.create({}).with_context(given_context)._get_main_lines()
|
||||
return res.with_context(given_context)._get_main_lines()
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, onWillStart, useState } from "@odoo/owl";
|
||||
import { download } from "@web/core/network/download";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { Layout } from "@web/search/layout";
|
||||
import { useSetupAction } from "@web/webclient/actions/action_hook";
|
||||
|
||||
function processLine(line) {
|
||||
return { ...line, lines: [], isFolded: true };
|
||||
}
|
||||
|
||||
function extractPrintData(lines) {
|
||||
const data = [];
|
||||
for (const line of lines) {
|
||||
const { id, model_id, model, unfoldable, level } = line;
|
||||
data.push({
|
||||
id: id,
|
||||
model_id: model_id,
|
||||
model_name: model,
|
||||
unfoldable,
|
||||
level: level || 1,
|
||||
});
|
||||
if (!line.isFolded) {
|
||||
data.push(...extractPrintData(line.lines));
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
export class TraceabilityReport extends Component {
|
||||
static template = "stock.TraceabilityReport";
|
||||
static components = { Layout };
|
||||
|
||||
setup() {
|
||||
this.actionService = useService("action");
|
||||
this.orm = useService("orm");
|
||||
this.user = useService("user");
|
||||
|
||||
onWillStart(this.onWillStart);
|
||||
useSetupAction({
|
||||
getLocalState: () => ({
|
||||
lines: [...this.state.lines],
|
||||
}),
|
||||
});
|
||||
|
||||
this.state = useState({
|
||||
lines: this.props.state?.lines || [],
|
||||
});
|
||||
|
||||
const { active_id, active_model, auto_unfold, context, lot_name, ttype, url } =
|
||||
this.props.action.context;
|
||||
this.controllerUrl = url;
|
||||
|
||||
this.context = context || {};
|
||||
Object.assign(this.context, {
|
||||
active_id: active_id || this.props.action.params.active_id,
|
||||
auto_unfold: auto_unfold || false,
|
||||
model: active_model || false,
|
||||
lot_name: lot_name || false,
|
||||
ttype: ttype || false,
|
||||
});
|
||||
|
||||
this.display = {
|
||||
controlPanel: { "top-right": false, "bottom-right": false },
|
||||
searchPanel: false,
|
||||
};
|
||||
}
|
||||
|
||||
async onWillStart() {
|
||||
if (!this.state.lines.length) {
|
||||
const mainLines = await this.orm.call("stock.traceability.report", "get_main_lines", [
|
||||
this.context,
|
||||
]);
|
||||
this.state.lines = mainLines.map(processLine);
|
||||
}
|
||||
}
|
||||
|
||||
onClickBoundLink(line) {
|
||||
this.actionService.doAction({
|
||||
type: "ir.actions.act_window",
|
||||
res_model: line.res_model,
|
||||
res_id: line.res_id,
|
||||
views: [[false, "form"]],
|
||||
target: "current",
|
||||
});
|
||||
}
|
||||
|
||||
onCLickOpenLot(line) {
|
||||
this.actionService.doAction({
|
||||
type: "ir.actions.client",
|
||||
tag: "stock_report_generic",
|
||||
name: line.lot_name !== undefined && line.lot_name.toString(),
|
||||
context: {
|
||||
active_id: line.lot_id,
|
||||
active_model: "stock.lot",
|
||||
url: "/stock/output_format/stock?active_id=:active_id&active_model=:active_model",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onClickUpDownStream(line) {
|
||||
this.actionService.doAction({
|
||||
type: "ir.actions.client",
|
||||
tag: "stock_report_generic",
|
||||
name: this.env._t("Traceability Report"),
|
||||
context: {
|
||||
active_id: line.model_id,
|
||||
active_model: line.model,
|
||||
auto_unfold: true,
|
||||
lot_name: line.lot_name !== undefined && line.lot_name,
|
||||
url: "/stock/output_format/stock/active_id",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onClickPrint() {
|
||||
const data = JSON.stringify(extractPrintData(this.state.lines));
|
||||
const url = this.controllerUrl
|
||||
.replace(":active_id", this.context.active_id)
|
||||
.replace(":active_model", this.context.model)
|
||||
.replace("output_format", "pdf");
|
||||
|
||||
download({
|
||||
data: { data },
|
||||
url,
|
||||
});
|
||||
}
|
||||
|
||||
async toggleLine(line) {
|
||||
line.isFolded = !line.isFolded;
|
||||
if (!line.lines.length) {
|
||||
line.lines = (
|
||||
await this.orm.call("stock.traceability.report", "get_lines", [line.id], {
|
||||
model_id: line.model_id,
|
||||
model_name: line.model,
|
||||
level: line.level + 30 || 1,
|
||||
})
|
||||
).map(processLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registry.category("actions").add("stock_report_generic", TraceabilityReport);
|
||||
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="stock.TraceabilityReport" owl="1">
|
||||
<div class="o_action">
|
||||
<Layout display="display">
|
||||
<t t-set-slot="layout-buttons">
|
||||
<div class="o_cp_buttons" role="toolbar" aria-label="Control panel buttons" t-ref="buttons">
|
||||
<button type="button" class="btn btn-primary" t-on-click="() => this.onClickPrint()">Print</button>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<div class="container-fluid o_stock_reports_page o_stock_reports_no_print">
|
||||
<t t-if="state.lines.length">
|
||||
<h1 class="o_report_heading text-start">Traceability Report</h1>
|
||||
<div class="o_stock_reports_table table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr class="o_report_header">
|
||||
<th class="o_report_line_header">Reference</th>
|
||||
<th class="o_report_line_header">Product</th>
|
||||
<th class="o_report_line_header">Date</th>
|
||||
<th class="o_report_line_header">Lot/Serial #</th>
|
||||
<th class="o_report_line_header">From</th>
|
||||
<th class="o_report_line_header">To</th>
|
||||
<th class="o_report_line_header">Quantity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-call="stock.ReportMRPLines">
|
||||
<t t-set="lines" t-value="state.lines"/>
|
||||
<t t-set="hasUpDown" t-value="true"/>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
<h1 t-else="" class="text-center">No operation made on this lot.</h1>
|
||||
</div>
|
||||
</Layout>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="stock.ReportMRPLines" owl="1">
|
||||
<t t-foreach="lines" t-as="line" t-key="line.id">
|
||||
<t t-set="column" t-value="0" />
|
||||
<tr t-att-class="line.model === 'stock.move.line' ? 'o_stock_reports_level0' : 'o_stock_reports_default_style'">
|
||||
<t t-foreach="line.columns" t-as="col" t-key="col_index">
|
||||
<td t-att-class="line.unfoldable ? 'o_stock_reports_unfoldable' : ''">
|
||||
<t t-if="col_first">
|
||||
<span t-attf-style="margin-left: {{line.level}}px"/>
|
||||
<t t-if="hasUpDown and line.is_used ">
|
||||
<span role="img" title="Traceability Report" aria-label="Traceability Report" t-on-click.prevent="() => this.onClickUpDownStream(line)">
|
||||
<i class="fa fa-fw fa-level-up fa-rotate-270"/>
|
||||
</span>
|
||||
</t>
|
||||
<t t-elif="line.unfoldable">
|
||||
<span class="o_stock_reports_unfoldable o_stock_reports_caret_icon" t-on-click="() => this.toggleLine(line)">
|
||||
<i class="fa fa-fw" t-att-class="line.isFolded ? 'fa-caret-right' : 'fa-caret-down'" role="img" aria-label="Unfold" title="Unfold"/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<span t-if="col and line.reference === col" t-att-class="!line.unfoldable ? 'o_stock_reports_nofoldable' : ''">
|
||||
<a class="o_stock_reports_web_action" href="#" t-on-click.prevent="() => this.onClickBoundLink(line)" t-esc="col"/>
|
||||
</span>
|
||||
<span t-elif="col and line.lot_name === col">
|
||||
<a class="o_stock_report_lot_action" t-on-click.prevent="() => this.onCLickOpenLot(line)" t-esc="col" />
|
||||
</span>
|
||||
<t t-elif="col" t-esc="col"/>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
|
||||
<t t-if="!line.isFolded and line.lines.length" t-call="stock.ReportMRPLines">
|
||||
<t t-set="lines" t-value="line.lines"/>
|
||||
<t t-set="hasUpDown" t-value="false"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -1,111 +0,0 @@
|
||||
odoo.define('stock.stock_report_generic', function (require) {
|
||||
'use strict';
|
||||
|
||||
var AbstractAction = require('web.AbstractAction');
|
||||
var core = require('web.core');
|
||||
var session = require('web.session');
|
||||
var ReportWidget = require('stock.ReportWidget');
|
||||
var framework = require('web.framework');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var stock_report_generic = AbstractAction.extend({
|
||||
hasControlPanel: true,
|
||||
|
||||
// Stores all the parameters of the action.
|
||||
init: function(parent, action) {
|
||||
this._super.apply(this, arguments);
|
||||
this.actionManager = parent;
|
||||
this.given_context = Object.assign({}, session.user_context);
|
||||
this.controller_url = action.context.url;
|
||||
if (action.context.context) {
|
||||
this.given_context = action.context.context;
|
||||
}
|
||||
this.given_context.active_id = action.context.active_id || action.params.active_id;
|
||||
this.given_context.model = action.context.active_model || false;
|
||||
this.given_context.ttype = action.context.ttype || false;
|
||||
this.given_context.auto_unfold = action.context.auto_unfold || false;
|
||||
this.given_context.lot_name = action.context.lot_name || false;
|
||||
},
|
||||
willStart: function() {
|
||||
return Promise.all([this._super.apply(this, arguments), this.get_html()]);
|
||||
},
|
||||
set_html: function() {
|
||||
var self = this;
|
||||
var def = Promise.resolve();
|
||||
if (!this.report_widget) {
|
||||
this.report_widget = new ReportWidget(this, this.given_context);
|
||||
def = this.report_widget.appendTo(this.$('.o_content'));
|
||||
}
|
||||
return def.then(function () {
|
||||
self.report_widget.$el.html(self.html);
|
||||
self.report_widget.$el.find('.o_report_heading').html('<h1>Traceability Report</h1>');
|
||||
if (self.given_context.auto_unfold) {
|
||||
_.each(self.$el.find('.fa-caret-right'), function (line) {
|
||||
self.report_widget.autounfold(line, self.given_context.lot_name);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
start: async function() {
|
||||
const props = this.getControlPanelProps();
|
||||
this.controlPanelProps.cp_content = props;
|
||||
await this._super(...arguments);
|
||||
this.set_html();
|
||||
},
|
||||
getControlPanelProps: function() {
|
||||
return { $buttons: this.$buttons }
|
||||
},
|
||||
// Fetches the html and is previous report.context if any, else create it
|
||||
get_html: async function() {
|
||||
const { html } = await this._rpc({
|
||||
args: [this.given_context],
|
||||
method: 'get_html',
|
||||
model: 'stock.traceability.report',
|
||||
});
|
||||
this.html = html;
|
||||
this.renderButtons();
|
||||
},
|
||||
// Updates the control panel and render the elements that have yet to be rendered
|
||||
update_cp: function() {
|
||||
if (!this.$buttons) {
|
||||
this.renderButtons();
|
||||
}
|
||||
this.controlPanelProps.cp_content = { $buttons: this.$buttons };
|
||||
return this.updateControlPanel();
|
||||
},
|
||||
renderButtons: function() {
|
||||
var self = this;
|
||||
this.$buttons = $(QWeb.render("stockReports.buttons", {}));
|
||||
// pdf output
|
||||
this.$buttons.bind('click', function () {
|
||||
var $element = $(self.$el[0]).find('.o_stock_reports_table tbody tr');
|
||||
var dict = [];
|
||||
|
||||
$element.each(function( index ) {
|
||||
var $el = $($element[index]);
|
||||
dict.push({
|
||||
'id': $el.data('id'),
|
||||
'model_id': $el.data('model_id'),
|
||||
'model_name': $el.data('model'),
|
||||
'unfoldable': $el.data('unfold'),
|
||||
'level': $el.find('td:first').data('level') || 1
|
||||
});
|
||||
});
|
||||
framework.blockUI();
|
||||
var url_data = self.controller_url.replace(':active_id', self.given_context.active_id);
|
||||
url_data = url_data.replace(':active_model', self.given_context.model);
|
||||
session.get_file({
|
||||
url: url_data.replace('output_format', 'pdf'),
|
||||
data: {data: JSON.stringify(dict)},
|
||||
complete: framework.unblockUI,
|
||||
error: (error) => self.call('crash_manager', 'rpc_error', error),
|
||||
});
|
||||
});
|
||||
return this.$buttons;
|
||||
},
|
||||
});
|
||||
|
||||
core.action_registry.add("stock_report_generic", stock_report_generic);
|
||||
return stock_report_generic;
|
||||
});
|
||||
@@ -1,131 +0,0 @@
|
||||
odoo.define('stock.ReportWidget', function (require) {
|
||||
'use strict';
|
||||
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
var ReportWidget = Widget.extend({
|
||||
events: {
|
||||
'click span.o_stock_reports_foldable': 'fold',
|
||||
'click span.o_stock_reports_unfoldable': 'unfold',
|
||||
'click .o_stock_reports_web_action': 'boundLink',
|
||||
'click .o_stock_reports_stream': 'updownStream',
|
||||
'click .o_stock_report_lot_action': 'actionOpenLot'
|
||||
},
|
||||
init: function(parent) {
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
start: function() {
|
||||
QWeb.add_template("/stock/static/src/xml/stock_traceability_report_line.xml");
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
boundLink: function(e) {
|
||||
e.preventDefault();
|
||||
return this.do_action({
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: $(e.target).data('res-model'),
|
||||
res_id: $(e.target).data('active-id'),
|
||||
views: [[false, 'form']],
|
||||
target: 'current'
|
||||
});
|
||||
},
|
||||
actionOpenLot: function(e) {
|
||||
e.preventDefault();
|
||||
var $el = $(e.target).parents('tr');
|
||||
this.do_action({
|
||||
type: 'ir.actions.client',
|
||||
tag: 'stock_report_generic',
|
||||
name: $el.data('lot_name') !== undefined && $el.data('lot_name').toString(),
|
||||
context: {
|
||||
active_id : $el.data('lot_id'),
|
||||
active_model : 'stock.lot',
|
||||
url: '/stock/output_format/stock?active_id=:active_id&active_model=:active_model',
|
||||
},
|
||||
});
|
||||
},
|
||||
updownStream: function(e) {
|
||||
var $el = $(e.target).parents('tr');
|
||||
this.do_action({
|
||||
type: "ir.actions.client",
|
||||
tag: 'stock_report_generic',
|
||||
name: _t("Traceability Report"),
|
||||
context: {
|
||||
active_id : $el.data('model_id'),
|
||||
active_model : $el.data('model'),
|
||||
auto_unfold: true,
|
||||
lot_name: $el.data('lot_name') !== undefined && $el.data('lot_name').toString(),
|
||||
url: '/stock/output_format/stock/active_id'
|
||||
},
|
||||
});
|
||||
},
|
||||
removeLine: function(element) {
|
||||
var self = this;
|
||||
var el, $el;
|
||||
var rec_id = element.data('id');
|
||||
var $stockEl = element.nextAll('tr[data-parent_id=' + rec_id + ']')
|
||||
for (el in $stockEl) {
|
||||
$el = $($stockEl[el]).find(".o_stock_reports_domain_line_0, .o_stock_reports_domain_line_1");
|
||||
if ($el.length === 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
var $nextEls = $($el[0]).parents("tr");
|
||||
self.removeLine($nextEls);
|
||||
$nextEls.remove();
|
||||
}
|
||||
$el.remove();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
fold: function(e) {
|
||||
this.removeLine($(e.target).parents('tr'));
|
||||
var active_id = $(e.target).parents('tr').find('td.o_stock_reports_foldable').data('id');
|
||||
$(e.target).parents('tr').find('td.o_stock_reports_foldable').attr('class', 'o_stock_reports_unfoldable ' + active_id); // Change the class, rendering, and remove line from model
|
||||
$(e.target).parents('tr').find('span.o_stock_reports_foldable').replaceWith(QWeb.render("unfoldable", {lineId: active_id}));
|
||||
$(e.target).parents('tr').toggleClass('o_stock_reports_unfolded');
|
||||
},
|
||||
autounfold: function(target, lot_name) {
|
||||
var self = this;
|
||||
var $CurretElement;
|
||||
$CurretElement = $(target).parents('tr').find('td.o_stock_reports_unfoldable');
|
||||
var active_id = $CurretElement.data('id');
|
||||
var active_model_name = $CurretElement.data('model');
|
||||
var active_model_id = $CurretElement.data('model_id');
|
||||
var row_level = $CurretElement.data('level');
|
||||
var $cursor = $(target).parents('tr');
|
||||
this._rpc({
|
||||
model: 'stock.traceability.report',
|
||||
method: 'get_lines',
|
||||
args: [parseInt(active_id, 10)],
|
||||
kwargs: {
|
||||
'model_id': active_model_id,
|
||||
'model_name': active_model_name,
|
||||
'level': parseInt(row_level) + 30 || 1
|
||||
},
|
||||
})
|
||||
.then(function (lines) {// After loading the line
|
||||
_.each(lines, function (line) { // Render each line
|
||||
$cursor.after(QWeb.render("report_mrp_line", {l: line}));
|
||||
$cursor = $cursor.next();
|
||||
if ($cursor && line.unfoldable && line.lot_name == lot_name) {
|
||||
self.autounfold($cursor.find(".fa-caret-right"), lot_name);
|
||||
}
|
||||
});
|
||||
});
|
||||
$CurretElement.attr('class', 'o_stock_reports_foldable ' + active_id); // Change the class, and rendering of the unfolded line
|
||||
$(target).parents('tr').find('span.o_stock_reports_unfoldable').replaceWith(QWeb.render("foldable", {lineId: active_id}));
|
||||
$(target).parents('tr').toggleClass('o_stock_reports_unfolded');
|
||||
},
|
||||
unfold: function(e) {
|
||||
this.autounfold($(e.target));
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
return ReportWidget;
|
||||
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates>
|
||||
|
||||
<t t-name="stockReports.buttons">
|
||||
<button type="button" class='btn btn-primary o_stock-widget-pdf'>PRINT</button>
|
||||
</t>
|
||||
|
||||
<div role="dialog" t-name='stockReports.errorModal' class="modal" id="editable_error" tabindex="-1" data-bs-backdrop="static" style="z-index:9999;">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<header class="modal-header">
|
||||
<h3 class="modal-title">Error</h3>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</header>
|
||||
<main class="modal-body">
|
||||
<p id='insert_error' class='text-center'></p>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</templates>
|
||||
@@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates>
|
||||
|
||||
<t t-name="foldable">
|
||||
<span t-att-class="'o_stock_reports_foldable ' + lineId + ' o_stock_reports_caret_icon'"><i class="fa fa-fw fa-caret-down" role="img" aria-label="Fold" title="Fold"></i></span>
|
||||
</t>
|
||||
|
||||
<t t-name="unfoldable">
|
||||
<span t-att-class="'o_stock_reports_unfoldable ' + lineId + ' o_stock_reports_caret_icon'"><i class="fa fa-fw fa-caret-right" role="img" aria-label="Unfold" title="Unfold"></i></span>
|
||||
</t>
|
||||
|
||||
<t t-name="report_mrp_line">
|
||||
<t t-set="trclass" t-value="'o_stock_reports_default_style'"/>
|
||||
<t t-if="l.model == 'stock.move.line'"><t t-set="trclass" t-value="'o_stock_reports_level0'"/></t>
|
||||
<t t-set="space_td" t-value="'margin-left: '+ l.level + 'px;'"/>
|
||||
<t t-set="domainClass" t-value="'o_stock_reports_domain_line_0'"/>
|
||||
<t t-if="l.unfoldable == false">
|
||||
<t t-set="spanclass" t-value="'o_stock_reports_nofoldable'" />
|
||||
<t t-set="domainClass" t-value="'o_stock_reports_domain_line_1'"/>
|
||||
</t>
|
||||
|
||||
<tr t-att-data-unfold="l.unfoldable" t-att-data-parent_id="l.parent_id" t-att-data-id="l.id" t-att-data-model_id="l.model_id" t-att-data-model="l.model" t-att-class="trclass" t-att-data-lot_name="l.lot_name" t-att-data-lot_id="l.lot_id">
|
||||
<t t-if="l.unfoldable == true"><t t-set="tdclass" t-value="'o_stock_reports_unfoldable'" /></t>
|
||||
<t t-set="column" t-value="0" />
|
||||
<t t-foreach="l.columns" t-as="c">
|
||||
<t t-set="column" t-value="column + 1" />
|
||||
<td style="white-space: nowrap;" t-att-data-id="l.id" t-att-data-model="l.model" t-att-data-model_id="l.model_id" t-att-class="tdclass" t-att-data-level="l.level" t-att-data-lot_name="l.lot_name">
|
||||
<t t-if="column == 1">
|
||||
<span t-att-style="space_td" t-att-class="domainClass"></span>
|
||||
<t t-if="l.unfoldable">
|
||||
<span class="o_stock_reports_unfoldable o_stock_reports_caret_icon"><i class="fa fa-fw fa-caret-right" role="img" aria-label="Unfold" title="Unfold"></i></span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="l.reference == c">
|
||||
<span t-if="c" t-att-class="spanclass">
|
||||
<a t-att-data-active-id="l.res_id" t-att-data-res-model="l.res_model" class="o_stock_reports_web_action" href="#"><t t-esc="c"/></a>
|
||||
</span>
|
||||
</t><t t-elif="l.lot_name == c and l.lot_name != false">
|
||||
<span>
|
||||
<a class="o_stock_report_lot_action" href="#"><t t-esc="c"/></a>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="l.reference != c and l.lot_name != c">
|
||||
<t t-if="typeof c == 'string' || typeof c == 'number'">
|
||||
<t t-esc="c"/>
|
||||
</t>
|
||||
<t t-if="typeof c != 'string' & typeof c != 'number'"><span t-att-style="c[1]">
|
||||
<t t-esc="c[0]"/>
|
||||
</span></t>
|
||||
</t>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -1,174 +1,47 @@
|
||||
odoo.define('stock.stock_traceability_report_backend_tests', function (require) {
|
||||
"use strict";
|
||||
/** @odoo-module **/
|
||||
|
||||
const LegacyControlPanel = require('web.ControlPanel');
|
||||
const { ControlPanel } = require("@web/search/control_panel/control_panel");
|
||||
const dom = require('web.dom');
|
||||
const StockReportGeneric = require('stock.stock_report_generic');
|
||||
const testUtils = require('web.test_utils');
|
||||
import { getFixture } from "@web/../tests/helpers/utils";
|
||||
import { createWebClient, doAction } from "@web/../tests/webclient/helpers";
|
||||
|
||||
const { dom: domUtils } = testUtils;
|
||||
const {
|
||||
destroy,
|
||||
getFixture,
|
||||
legacyExtraNextTick,
|
||||
patchWithCleanup,
|
||||
} = require("@web/../tests/helpers/utils");
|
||||
const { createWebClient, doAction } = require('@web/../tests/webclient/helpers');
|
||||
let serverData;
|
||||
let target;
|
||||
|
||||
const { onMounted, onWillUnmount } = owl;
|
||||
|
||||
/**
|
||||
* Helper function to instantiate a stock report action.
|
||||
* @param {Object} params
|
||||
* @param {Object} params.action
|
||||
* @param {boolean} [params.debug]
|
||||
* @returns {Promise<StockReportGeneric>}
|
||||
*/
|
||||
async function createStockReportAction(params) {
|
||||
const parent = await testUtils.createParent(params);
|
||||
const report = new StockReportGeneric(parent, params.action);
|
||||
const target = testUtils.prepareTarget(params.debug);
|
||||
|
||||
const _destroy = report.destroy;
|
||||
report.destroy = function () {
|
||||
report.destroy = _destroy;
|
||||
parent.destroy();
|
||||
};
|
||||
const fragment = document.createDocumentFragment();
|
||||
await report.appendTo(fragment);
|
||||
dom.prepend(target, fragment, {
|
||||
callbacks: [{ widget: report }],
|
||||
in_DOM: true,
|
||||
});
|
||||
// Wait for the ReportWidget to be appended
|
||||
await testUtils.nextTick();
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
QUnit.module('Stock', {}, function () {
|
||||
QUnit.module('Traceability report');
|
||||
|
||||
QUnit.test("Rendering with no lines", async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const template = `
|
||||
<div class="container-fluid o_stock_reports_page o_stock_reports_no_print">
|
||||
<div class="o_stock_reports_table table-responsive">
|
||||
<span class="text-center">
|
||||
<h1>No operation made on this lot.</h1>
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
const report = await createStockReportAction({
|
||||
action: {
|
||||
QUnit.module("Stock", {}, function (hooks) {
|
||||
hooks.beforeEach(() => {
|
||||
serverData = {
|
||||
actions: {
|
||||
42: {
|
||||
id: 42,
|
||||
name: "Stock report",
|
||||
tag: "stock_report_generic",
|
||||
type: "ir.actions.client",
|
||||
context: {},
|
||||
params: {},
|
||||
},
|
||||
data: {
|
||||
'stock.traceability.report': {
|
||||
fields: {},
|
||||
get_html: () => ({ html: template }),
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// HTML content is nested in a div inside of the content
|
||||
assert.strictEqual(report.el.querySelector('.o_content > div').innerHTML, template,
|
||||
"Displayed template should match");
|
||||
target = getFixture();
|
||||
});
|
||||
|
||||
report.destroy();
|
||||
QUnit.module("Traceability report");
|
||||
|
||||
QUnit.test("Rendering with no lines", async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const webClient = await createWebClient({
|
||||
serverData,
|
||||
mockRPC: async function (route) {
|
||||
if (route === "/web/dataset/call_kw/stock.traceability.report/get_main_lines") {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("mounted is called once when returning on 'Stock report' from breadcrumb", async assert => {
|
||||
// This test can be removed as soon as we don't mix legacy and owl layers anymore.
|
||||
assert.expect(7);
|
||||
|
||||
let mountCount = 0;
|
||||
|
||||
patchWithCleanup(ControlPanel.prototype, {
|
||||
setup() {
|
||||
this._super();
|
||||
onMounted(() => {
|
||||
mountCount = mountCount + 1;
|
||||
this.__uniqueId = mountCount;
|
||||
assert.step(`mounted ${this.__uniqueId}`);
|
||||
});
|
||||
onWillUnmount(() => {
|
||||
assert.step(`willUnmount ${this.__uniqueId}`);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
patchWithCleanup(LegacyControlPanel.prototype, {
|
||||
setup() {
|
||||
this._super();
|
||||
onMounted(() => {
|
||||
mountCount = mountCount + 1;
|
||||
this.__uniqueId = mountCount;
|
||||
assert.step(`mounted ${this.__uniqueId} (legacy)`);
|
||||
});
|
||||
onWillUnmount(() => {
|
||||
assert.step(`willUnmount ${this.__uniqueId} (legacy)`);
|
||||
});
|
||||
},
|
||||
});
|
||||
const serverData = {
|
||||
models: {
|
||||
partner: {
|
||||
fields: {
|
||||
display_name: { string: "Displayed name", type: "char" },
|
||||
},
|
||||
records: [
|
||||
{id: 1, display_name: "Genda Swami"},
|
||||
],
|
||||
},
|
||||
},
|
||||
views: {
|
||||
'partner,false,form': '<form><field name="display_name"/></form>',
|
||||
'partner,false,search': '<search></search>',
|
||||
},
|
||||
actions: {
|
||||
42: {
|
||||
id: 42,
|
||||
name: "Stock report",
|
||||
tag: 'stock_report_generic',
|
||||
type: 'ir.actions.client',
|
||||
context: {},
|
||||
params: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const target = getFixture();
|
||||
const webClient = await createWebClient({
|
||||
serverData,
|
||||
mockRPC: function (route) {
|
||||
if (route === '/web/dataset/call_kw/stock.traceability.report/get_html') {
|
||||
return Promise.resolve({
|
||||
html: '<a class="o_stock_reports_web_action" href="#" data-active-id="1" data-res-model="partner">Go to form view</a>',
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await doAction(webClient, 42);
|
||||
await domUtils.click(target.querySelector('.o_stock_reports_web_action'));
|
||||
await legacyExtraNextTick();
|
||||
await domUtils.click(target.querySelector('.breadcrumb-item'));
|
||||
await legacyExtraNextTick();
|
||||
|
||||
destroy(webClient);
|
||||
|
||||
assert.verifySteps([
|
||||
'mounted 1 (legacy)',
|
||||
'willUnmount 1 (legacy)',
|
||||
'mounted 2',
|
||||
'willUnmount 2',
|
||||
'mounted 3 (legacy)',
|
||||
'willUnmount 3 (legacy)',
|
||||
]);
|
||||
});
|
||||
await doAction(webClient, 42);
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_stock_reports_page").textContent,
|
||||
"No operation made on this lot."
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,80 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="report_mrp_line">
|
||||
<t t-foreach="lines" t-as="a">
|
||||
<t t-set="trclass" t-value="'o_stock_reports_default_style'"/>
|
||||
<t t-if="a.get('model') == 'stock.move.line'"><t t-set="trclass" t-value="'o_stock_reports_level0'"/></t>
|
||||
<t t-set="domainClass" t-value="'o_stock_reports_domain_line'"/>
|
||||
<t t-if="a['unfoldable'] == false">
|
||||
<t t-set="domainClass" t-value="'o_stock_reports_domain_line_1'"/>
|
||||
</t>
|
||||
<t t-set="column" t-value="0" />
|
||||
<tr t-att-data-unfold="a['unfoldable']" t-att-data-parent_id="a['parent_id']" t-att-data-id="a['id']" t-att-data-model_id="a['model_id']" t-att-data-model="a['model']" t-att-data-lot_name="a['lot_name']" t-att-data-lot_id="a['lot_id']" t-att-class="trclass">
|
||||
<t t-set="tdclass" t-value="''" />
|
||||
<t t-set="spanclass" t-value="''" />
|
||||
<t t-if="a.get('unfoldable')"><t t-set="tdclass" t-value="'o_stock_reports_unfoldable'" /></t>
|
||||
<t t-if="not a.get('unfoldable')"><t t-set="spanclass" t-value="'o_stock_reports_nofoldable'" /></t>
|
||||
<t t-set="column" t-value="0" />
|
||||
<t t-foreach="a['columns']" t-as="c">
|
||||
<t t-set="column" t-value="column + 1" />
|
||||
<td t-att-data-id="a.get('id')" t-att-data-model="a['model']" t-att-data-model_id="a['model_id']" t-att-class="tdclass" t-att-data-level="a['level']">
|
||||
<t t-if="column == 1">
|
||||
<t t-if="a.get('unfoldable') and not a.get('is_used')">
|
||||
<span t-att-data-id="a['id']" class="o_stock_reports_unfoldable o_stock_reports_caret_icon"><i class="fa fa-fw fa-caret-right" role="img" aria-label="Unfold" title="Unfold"></i></span>
|
||||
</t>
|
||||
<t t-if="a.get('is_used')">
|
||||
<span role="img" class="o_stock_reports_stream" title="Traceability Report" aria-label="Traceability Report"><i class="fa fa-fw fa-level-up fa-rotate-270"></i></span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="a['reference'] == c">
|
||||
<span t-if="c" t-att-class="spanclass">
|
||||
<a t-att-data-active-id="a['res_id']" t-att-data-res-model="a['res_model']" class="o_stock_reports_web_action" href="#"><t t-esc="c" /></a>
|
||||
</span>
|
||||
</t>
|
||||
<t t-elif="a['lot_name'] == c">
|
||||
<span>
|
||||
<a class="o_stock_report_lot_action" href="#"><t t-esc="c"/></a>
|
||||
</span>
|
||||
</t><t t-else="">
|
||||
<t t-esc="c"/>
|
||||
</t>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_stock_inventory">
|
||||
<div class="container-fluid o_stock_reports_page o_stock_reports_no_print">
|
||||
<span t-if="lines" class="o_report_heading text-start"><h1>Traceability Report</h1></span>
|
||||
<span><t t-esc="context"/></span>
|
||||
<div class="o_stock_reports_table table-responsive">
|
||||
<t t-if="not lines">
|
||||
<span class="text-center"><h1>No operation made on this lot.</h1></span>
|
||||
</t>
|
||||
<t t-if="lines">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr class="o_report_header">
|
||||
<th class="o_report_line_header">Reference</th>
|
||||
<th class="o_report_line_header">Product</th>
|
||||
<th class="o_report_line_header">Date</th>
|
||||
<th class="o_report_line_header">Lot/Serial #</th>
|
||||
<th class="o_report_line_header">From</th>
|
||||
<th class="o_report_line_header">To</th>
|
||||
<th class="o_report_line_header">Quantity</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-call="stock.report_mrp_line"/>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="report_stock_inventory_print">
|
||||
<t t-call="web.html_container">
|
||||
<t t-set="head_start">
|
||||
|
||||
Reference in New Issue
Block a user