[MOV] stock: move traceability report from mrp_workorder
This commit is contained in:
committed by
Simon Lejeune
parent
eaca63277e
commit
5fcdb06010
@@ -25,6 +25,7 @@
|
||||
'security/stock_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/stock_menu_views.xml',
|
||||
'data/stock_traceability_report_data.xml',
|
||||
|
||||
'report/report_stock_forecast.xml',
|
||||
'report/stock_report_views.xml',
|
||||
@@ -57,6 +58,9 @@
|
||||
'views/stock_move_views.xml',
|
||||
'views/product_views.xml',
|
||||
'views/stock_config_settings_views.xml',
|
||||
'views/report_stock_traceability.xml',
|
||||
'views/stock_traceability_report_views.xml',
|
||||
'views/stock_template.xml',
|
||||
|
||||
'data/default_barcode_patterns.xml',
|
||||
'data/stock_data.xml',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo.addons.web.controllers.main import _serialize_exception
|
||||
from odoo.tools import html_escape
|
||||
|
||||
import json
|
||||
|
||||
|
||||
class BarcodeController(http.Controller):
|
||||
@@ -11,3 +15,32 @@ class BarcodeController(http.Controller):
|
||||
return http.local_redirect('/web/login?redirect=/stock/barcode/')
|
||||
|
||||
return request.render('stock.barcode_index')
|
||||
|
||||
|
||||
class StockReportController(http.Controller):
|
||||
|
||||
@http.route('/mrp_workorder/<string:output_format>/<string:report_name>/<int:report_id>', type='http', auth='user')
|
||||
def report(self, output_format, report_name, token, report_id=False, **kw):
|
||||
uid = request.session.uid
|
||||
domain = [('create_uid', '=', uid)]
|
||||
stock_traceability = request.env['stock.traceability.report'].sudo(uid).search(domain, limit=1)
|
||||
line_data = json.loads(kw['data'])
|
||||
try:
|
||||
if output_format == 'pdf':
|
||||
response = request.make_response(
|
||||
stock_traceability.with_context(active_id=report_id).get_pdf(line_data),
|
||||
headers=[
|
||||
('Content-Type', 'application/pdf'),
|
||||
('Content-Disposition', 'attachment; filename=' + 'stock_traceability' + '.pdf;')
|
||||
]
|
||||
)
|
||||
response.set_cookie('fileToken', token)
|
||||
return response
|
||||
except Exception as e:
|
||||
se = _serialize_exception(e)
|
||||
error = {
|
||||
'code': 200,
|
||||
'message': 'Odoo Server Error',
|
||||
'data': se
|
||||
}
|
||||
return request.make_response(html_escape(json.dumps(error)))
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="action_stock_report" model="ir.actions.client">
|
||||
<field name="name">Upstream Traceability</field>
|
||||
<field name="tag">stock_report_generic</field>
|
||||
<field name="context" eval="{'url': '/mrp_workorder/output_format/stock/active_id', 'model': 'stock.traceability.report'}" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -16,6 +16,7 @@ from . import stock_pack_operation
|
||||
from . import stock_production_lot
|
||||
from . import stock_picking
|
||||
from . import stock_quant
|
||||
from . import stock_traceability
|
||||
from . import stock_warehouse
|
||||
from . import stock_scrap
|
||||
from . import web_planner
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models, _
|
||||
|
||||
|
||||
rec = 0
|
||||
def autoIncrement():
|
||||
global rec
|
||||
pStart = 1
|
||||
pInterval = 1
|
||||
if rec == 0:
|
||||
rec = pStart
|
||||
else:
|
||||
rec += pInterval
|
||||
return rec
|
||||
|
||||
|
||||
class MrpStockReport(models.TransientModel):
|
||||
_name = 'stock.traceability.report'
|
||||
|
||||
@api.model
|
||||
def get_lines(self, line_id=None, **kw):
|
||||
context = dict(self.env.context)
|
||||
stream = context.get('ttype')
|
||||
model = False
|
||||
model_id = False
|
||||
level = 1
|
||||
parent_quant = False
|
||||
if kw:
|
||||
level = kw['level']
|
||||
model = kw['model_name']
|
||||
model_id = kw['model_id']
|
||||
stream = kw['stream']
|
||||
parent_quant = kw['parent_quant']
|
||||
StockQuant = self.env['stock.quant']
|
||||
context_ids = []
|
||||
if context.get('active_id') and not context.get('model') or context.get('model') == 'stock.production.lot':
|
||||
context_ids = StockQuant.search([['lot_id', '=', context.get('active_id')]])
|
||||
elif context.get('active_id') and context.get('model') == 'mrp.production':
|
||||
context_ids = self.env['mrp.production'].browse(context['active_id']).move_finished_ids.mapped('quant_ids')
|
||||
elif context.get('active_id') and context.get('model') == 'stock.picking':
|
||||
context_ids = self.env['stock.picking'].browse(context['active_id']).move_lines.mapped('quant_ids')
|
||||
context.update({
|
||||
'context_ids': context_ids or context.get('model') == 'stock.quant' and self.env[context.get('model')].browse(context.get('active_id')) or [],
|
||||
'stream': stream
|
||||
})
|
||||
res = self.with_context(context)._lines(line_id, model_id=model_id, model=model, level=level, parent_quant=parent_quant)
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def get_links(self, move):
|
||||
res_model = ''
|
||||
ref = ''
|
||||
res_id = False
|
||||
if move.picking_id:
|
||||
res_model = 'stock.picking'
|
||||
res_id = move.picking_id.id
|
||||
ref = move.picking_id.name
|
||||
elif move.raw_material_production_id or move.production_id:
|
||||
res_model = 'mrp.production'
|
||||
res_id = move.raw_material_production_id.id or move.production_id.id
|
||||
ref = move.raw_material_production_id.name or move.production_id.name
|
||||
elif move.unbuild_id or move.consume_unbuild_id:
|
||||
res_model = 'mrp.unbuild'
|
||||
res_id = move.consume_unbuild_id.id or move.unbuild_id.id
|
||||
ref = move.consume_unbuild_id.name or move.unbuild_id.name
|
||||
return res_model, res_id, ref
|
||||
|
||||
def make_dict_move(self, level, line_id, move, stream=False, final_vals=None):
|
||||
res_model, res_id, ref = self.get_links(move)
|
||||
data = {
|
||||
'level': level,
|
||||
'unfoldable': False,
|
||||
'date': move.date,
|
||||
'parent_id': line_id,
|
||||
'model_id': move.id,
|
||||
'model':'stock.move',
|
||||
'product_id': move.product_id.display_name,
|
||||
'product_qty_uom': False,
|
||||
'location_source': move.location_id.name,
|
||||
'location_destination': move.location_dest_id.name,
|
||||
'reference_id': ref,
|
||||
'res_id': res_id,
|
||||
'stream': stream,
|
||||
'res_model': res_model}
|
||||
final_vals.append(data)
|
||||
return final_vals
|
||||
|
||||
def make_dict_head(self, level, line_id, stream=False, move=False, quant=False, final_vals=None):
|
||||
if move:
|
||||
res_model, res_id, ref = self.get_links(move)
|
||||
final_vals.append({
|
||||
'level': level,
|
||||
'unfoldable': True,
|
||||
'model_id': move.id,
|
||||
'parent_id': line_id,
|
||||
'model': 'stock.move',
|
||||
'parent_quant': quant.id if quant else False,
|
||||
'product_id': move.product_id.display_name,
|
||||
'product_qty_uom': False,
|
||||
'location_source': move.location_id.name,
|
||||
'location_destination': move.location_dest_id.name,
|
||||
'reference_id': ref,
|
||||
'res_id': res_id,
|
||||
'stream': stream,
|
||||
'res_model': res_model})
|
||||
else:
|
||||
final_vals.append({
|
||||
'level': level,
|
||||
'unfoldable': True if quant.history_ids else False,
|
||||
'date': quant.lot_id.name,
|
||||
'model_id': quant.id,
|
||||
'parent_id': line_id,
|
||||
'model':'stock.quant',
|
||||
'product_id': quant.product_id.display_name,
|
||||
'product_qty_uom': str(quant.qty) + ' ' + quant.product_id.uom_id.name,
|
||||
'location_source': False,
|
||||
'location_destination': False,
|
||||
'stream': stream,
|
||||
'reference_id': False})
|
||||
return final_vals
|
||||
|
||||
@api.model
|
||||
def upstream_traceability(self, level, stream=False, line_id=False, model=False, model_id=False, parent_quant=False, final_vals=None):
|
||||
model_obj = self.env[model].browse(model_id)
|
||||
if model == 'stock.quant':
|
||||
for move in model_obj.history_ids.sorted(key=lambda r: r.date, reverse=True):
|
||||
if move.production_id or move.unbuild_id:
|
||||
final_vals = self.make_dict_head(level, stream=stream, line_id=line_id, move=move, quant=model_obj, final_vals=final_vals)
|
||||
else:
|
||||
final_vals = self.make_dict_move(level, stream=stream, line_id=line_id, move=move, final_vals=final_vals)
|
||||
else:
|
||||
if model_obj.production_id or model_obj.unbuild_id:
|
||||
parent_quant = self.env['stock.quant'].browse(parent_quant)
|
||||
for quant in parent_quant.consumed_quant_ids.filtered(lambda x: x.qty > 0):
|
||||
final_vals = self.make_dict_head(level, line_id=line_id, stream=stream, move=False, quant=quant, final_vals=final_vals)
|
||||
|
||||
@api.model
|
||||
def downstream_traceability(self, level, stream=False, line_id=False, model=False, model_id=False, parent_quant=False, final_vals=None):
|
||||
model_obj = self.env[model].browse(model_id)
|
||||
if model == 'stock.quant':
|
||||
for move in model_obj.history_ids.sorted(key=lambda r: r.date):
|
||||
if move.raw_material_production_id or move.consume_unbuild_id:
|
||||
final_vals = self.make_dict_head(level, stream=stream, line_id=line_id, move=move, quant=model_obj, final_vals=final_vals)
|
||||
else:
|
||||
final_vals = self.make_dict_move(level, stream=stream, line_id=line_id, move=move, final_vals=final_vals)
|
||||
else:
|
||||
if model_obj.raw_material_production_id or model_obj.consume_unbuild_id:
|
||||
parent_quant = self.env['stock.quant'].browse(parent_quant)
|
||||
for quant in parent_quant.produced_quant_ids.filtered(lambda x: x.qty > 0):
|
||||
final_vals = self.make_dict_head(level, stream=stream, line_id=line_id, move=False, quant=quant, final_vals=final_vals)
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def _lines(self, line_id=None, model_id=False, model=False, level=0, parent_quant=False, **kw):
|
||||
lines = []
|
||||
context = dict(self.env.context)
|
||||
final_vals = []
|
||||
if model:
|
||||
if context.get('stream') == "downstream" or context.get('stream') == 'downstream':
|
||||
self.downstream_traceability(level, stream='downstream', line_id=line_id, model=model, model_id=model_id, parent_quant=parent_quant, final_vals=final_vals)
|
||||
else:
|
||||
self.upstream_traceability(level, stream='upstream', line_id=line_id, model=model, model_id=model_id, parent_quant=parent_quant, final_vals=final_vals)
|
||||
else:
|
||||
for quant in context['context_ids']:
|
||||
final_vals = self.make_dict_head(level, stream=context.get('stream', False), line_id=line_id, move=False, quant=quant, final_vals=final_vals)
|
||||
for data in final_vals:
|
||||
lines.append({
|
||||
'id': autoIncrement(),
|
||||
'model': data['model'],
|
||||
'model_id': data['model_id'],
|
||||
'stream': data['stream'] or 'upstream',
|
||||
'parent_id': data['parent_id'],
|
||||
'parent_quant': data.get('parent_quant', False),
|
||||
'type': 'line',
|
||||
'reference': data.get('reference_id', False),
|
||||
'res_id': data.get('res_id', False),
|
||||
'res_model': data.get('res_model', False),
|
||||
'name': _(data.get('lot_id', False)),
|
||||
'columns': [data.get('reference_id', False) or data.get('product_id', False),
|
||||
data.get('date', False),
|
||||
data.get('product_qty_uom', 0),
|
||||
data.get('location_source', False),
|
||||
data.get('location_destination', False)],
|
||||
'level': level,
|
||||
'unfoldable': data['unfoldable'],
|
||||
})
|
||||
return lines
|
||||
|
||||
@api.multi
|
||||
def get_pdf_lines(self, line_data=[]):
|
||||
final_vals = []
|
||||
lines = []
|
||||
for line in line_data:
|
||||
model = self.env[line['model_name']].browse(line['model_id'])
|
||||
if line.get('unfoldable'):
|
||||
if line['model_name'] == 'stock.quant':
|
||||
final_vals = self.make_dict_head(line['level'], line_id=line['id'], move=False, quant=model, final_vals=final_vals)
|
||||
else:
|
||||
final_vals = self.make_dict_head(line['level'], line_id=line['id'], move=model, quant=False, final_vals=final_vals)
|
||||
else:
|
||||
if line['model_name'] == 'stock.move':
|
||||
final_vals = self.make_dict_move(line['level'], line_id=line['id'], move=model, final_vals=final_vals)
|
||||
else:
|
||||
final_vals = self.make_dict_head(line['level'], line_id=line['id'], quant=model, final_vals=final_vals)
|
||||
for data in final_vals:
|
||||
lines.append({
|
||||
'id': autoIncrement(),
|
||||
'model': data['model'],
|
||||
'model_id': data['model_id'],
|
||||
'parent_id': data['parent_id'],
|
||||
'stream': "%s" % (data['stream']),
|
||||
'type': 'line',
|
||||
'name': _(data.get('lot_id')),
|
||||
'columns': [data.get('reference_id') or data.get('product_id'),
|
||||
data.get('date'),
|
||||
data.get('product_qty_uom', 0),
|
||||
data.get('location_source'),
|
||||
data.get('location_destination')],
|
||||
'level': data['level'],
|
||||
'unfoldable': data['unfoldable'],
|
||||
})
|
||||
|
||||
return lines
|
||||
|
||||
def get_pdf(self, line_data=[]):
|
||||
lines = self.with_context(print_mode=True).get_pdf_lines(line_data)
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
rcontext = {
|
||||
'mode': 'print',
|
||||
'base_url': base_url,
|
||||
}
|
||||
|
||||
body = self.env['ir.ui.view'].render_template(
|
||||
"mrp_workorder.report_stock_inventory_print",
|
||||
values=dict(rcontext, lines=lines, report=self, context=self),
|
||||
)
|
||||
|
||||
header = self.env['ir.actions.report'].render_template("web.internal_layout", values=rcontext)
|
||||
header = self.env['ir.actions.report'].render_template("web.minimal_layout", values=dict(rcontext, subst=True, body=header))
|
||||
landscape = True
|
||||
|
||||
return self.env['ir.actions.report']._run_wkhtmltopdf(
|
||||
[self.env['ir.actions.report'].create_wkhtmltopdf_obj(header, body, None)],
|
||||
landscape, self.env.user.company_id.paperformat_id,
|
||||
specific_paperformat_args={'data-report-margin-top': 10, 'data-report-header-spacing': 10}
|
||||
)
|
||||
|
||||
def _get_html(self):
|
||||
result = {}
|
||||
rcontext = {}
|
||||
context = dict(self.env.context)
|
||||
rcontext['lines'] = self.with_context(context).get_lines()
|
||||
result['html'] = self.env.ref('mrp_workorder.report_stock_inventory').render(rcontext)
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def get_html(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()
|
||||
@@ -0,0 +1,113 @@
|
||||
odoo.define('mrp_workorder.stock_report_generic', function (require) {
|
||||
'use strict';
|
||||
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
var ControlPanelMixin = require('web.ControlPanelMixin');
|
||||
var session = require('web.session');
|
||||
var ReportWidget = require('mrp_workorder.ReportWidget');
|
||||
var framework = require('web.framework');
|
||||
var crash_manager = require('web.crash_manager');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var stock_report_generic = Widget.extend(ControlPanelMixin, {
|
||||
// Stores all the parameters of the action.
|
||||
init: function(parent, action) {
|
||||
this.actionManager = parent;
|
||||
this.given_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;
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
willStart: function() {
|
||||
return this.get_html();
|
||||
},
|
||||
set_html: function() {
|
||||
var self = this;
|
||||
var def = $.when();
|
||||
if (!this.report_widget) {
|
||||
this.report_widget = new ReportWidget(this, this.given_context);
|
||||
def = this.report_widget.appendTo(this.$el);
|
||||
}
|
||||
def.then(function () {
|
||||
self.report_widget.$el.html(self.html);
|
||||
if(self.given_context['ttype'] == 'downstream'){
|
||||
self.report_widget.$el.find('.o_report_heading').html('<h1>Downstream Traceability</h1>');
|
||||
}
|
||||
});
|
||||
},
|
||||
start: function() {
|
||||
this.set_html();
|
||||
return this._super();
|
||||
},
|
||||
// Fetches the html and is previous report.context if any, else create it
|
||||
get_html: function() {
|
||||
var self = this;
|
||||
var defs = [];
|
||||
return this._rpc({
|
||||
model: 'stock.traceability.report',
|
||||
method: 'get_html',
|
||||
args: [self.given_context],
|
||||
})
|
||||
.then(function (result) {
|
||||
self.html = result.html;
|
||||
self.renderButtons();
|
||||
defs.push(self.update_cp());
|
||||
return $.when.apply($, defs);
|
||||
});
|
||||
},
|
||||
// Updates the control panel and render the elements that have yet to be rendered
|
||||
update_cp: function() {
|
||||
if (!this.$buttons) {
|
||||
this.renderButtons();
|
||||
}
|
||||
var status = {
|
||||
breadcrumbs: this.actionManager.get_breadcrumbs(),
|
||||
cp_content: {$buttons: this.$buttons},
|
||||
};
|
||||
return this.update_control_panel(status);
|
||||
},
|
||||
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']);
|
||||
session.get_file({
|
||||
url: url_data.replace('output_format', 'pdf'),
|
||||
data: {data: JSON.stringify(dict)},
|
||||
complete: framework.unblockUI,
|
||||
error: crash_manager.rpc_error.bind(crash_manager),
|
||||
});
|
||||
});
|
||||
return this.$buttons;
|
||||
},
|
||||
do_show: function() {
|
||||
this._super();
|
||||
this.update_cp();
|
||||
},
|
||||
});
|
||||
|
||||
core.action_registry.add("stock_report_generic", stock_report_generic);
|
||||
return stock_report_generic;
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
odoo.define('mrp_workorder.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',
|
||||
},
|
||||
init: function(parent) {
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
start: function() {
|
||||
QWeb.add_template("/mrp_workorder/static/src/xml/stock_traceability_report_line.xml");
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
boundLink: function(e) {
|
||||
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'
|
||||
});
|
||||
},
|
||||
updownStream: function(e) {
|
||||
var stream = $(e.target).parent().data('stream');
|
||||
var $el = $(e.target).parents('tr');
|
||||
var string = "Upstream Traceability"
|
||||
if (stream == 'downstream') {
|
||||
string = "Downstream Traceability"
|
||||
}
|
||||
this.do_action({
|
||||
type: "ir.actions.client",
|
||||
tag: 'stock_report_generic',
|
||||
name: _t(string),
|
||||
context: {
|
||||
active_id : $el.data('model_id'),
|
||||
active_model : $el.data('model'),
|
||||
ttype: stream || false,
|
||||
url: '/mrp_workorder/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');
|
||||
},
|
||||
unfold: function(e) {
|
||||
var $CurretElement;
|
||||
$CurretElement = $(e.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 stream = $CurretElement.data('stream');
|
||||
var parent_quant = $CurretElement.data('parent_quant');
|
||||
var $cursor = $(e.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,
|
||||
'stream': stream || 'upstream',
|
||||
'parent_quant': parseInt(parent_quant) || false,
|
||||
'level': parseInt(row_level) + 30 || 1
|
||||
},
|
||||
})
|
||||
.then(function (lines) {// After loading the line
|
||||
var line;
|
||||
for (line in lines) { // Render each line
|
||||
$cursor.after(QWeb.render("report_mrp_line", {l: lines[line]}));
|
||||
$cursor = $cursor.next();
|
||||
}
|
||||
});
|
||||
$CurretElement.attr('class', 'o_stock_reports_foldable ' + active_id); // Change the class, and rendering of the unfolded line
|
||||
$(e.target).parents('tr').find('span.o_stock_reports_unfoldable').replaceWith(QWeb.render("foldable", {lineId: active_id}));
|
||||
$(e.target).parents('tr').toggleClass('o_stock_reports_unfolded');
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
return ReportWidget;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
.o_stock_reports_lines(@border-width: 5px, @color: inherit, @font-weight: inherit, @border-top-style: initial, @border-bottom-style: initial) {
|
||||
border-width: @border-width;
|
||||
border-left-style: hidden;
|
||||
border-right-style: hidden;
|
||||
color: @color;
|
||||
font-weight: @font-weight;
|
||||
border-top-style: @border-top-style;
|
||||
border-bottom-style: @border-bottom-style;
|
||||
}
|
||||
.o_stock_reports_body_print {
|
||||
background-color: white;
|
||||
color: black;
|
||||
.o_stock_reports_level0 {
|
||||
.o_stock_reports_lines(@border-width: 1px, @font-weight: bold, @border-top-style: solid, @border-bottom-style: groove);
|
||||
}
|
||||
}
|
||||
|
||||
.o_stock_reports_page {
|
||||
background-color: @odoo-view-background-color;
|
||||
color: @odoo-main-text-color;
|
||||
&.o_stock_reports_no_print {
|
||||
padding-bottom: 125px;
|
||||
margin: @odoo-horizontal-padding auto;
|
||||
.o-webclient-padding(@top: @odoo-sheet-vpadding, @bottom: @odoo-sheet-vpadding);
|
||||
.o_stock_reports_level0 {
|
||||
.o_stock_reports_lines(@border-width: 1px, @color: @odoo-brand-primary, @font-weight: bold, @border-top-style: solid, @border-bottom-style: groove);
|
||||
}
|
||||
.o_stock_reports_table {
|
||||
white-space: nowrap;
|
||||
margin-bottom: 228px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.o_report_line_header {
|
||||
padding-left: 10px;
|
||||
}
|
||||
.o_report_header {
|
||||
border-top-style: solid;
|
||||
border-top-style: groove;
|
||||
border-bottom-style: groove;
|
||||
border-width: 2px;
|
||||
}
|
||||
}
|
||||
.o_stock_reports_unfolded {
|
||||
display: inline-block;
|
||||
}
|
||||
table > tbody > tr > td ~ td > span {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.o_stock_reports_unfolded td + td {
|
||||
visibility: hidden;
|
||||
}
|
||||
div.o_stock_reports_web_action,
|
||||
span.o_stock_reports_web_action, i.fa,
|
||||
span.o_stock_reports_unfoldable, span.o_stock_reports_foldable, a.o_stock_reports_web_action {
|
||||
cursor: pointer;
|
||||
}
|
||||
.o_stock_reports_caret_icon {
|
||||
margin-left: -3px;
|
||||
}
|
||||
th {
|
||||
border-bottom: thin groove;
|
||||
}
|
||||
.o_stock_reports_level1 {
|
||||
.o_stock_reports_lines(@border-width: 2px, @border-top-style: hidden, @border-bottom-style: solid);
|
||||
}
|
||||
.o_stock_reports_level2 {
|
||||
.o_stock_reports_lines(@border-width: 1px, @border-top-style: solid, @border-bottom-style: solid);
|
||||
> td > span:last-child {
|
||||
margin-left: 25px;
|
||||
}
|
||||
}
|
||||
.o_stock_reports_default_style {
|
||||
.o_stock_reports_lines(@border-width: 0px, @border-top-style: solid, @border-bottom-style: solid);
|
||||
> td > span:last-child {
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates>
|
||||
|
||||
<t t-name="stockReports.buttons">
|
||||
<button type="button" class='btn btn-primary btn-sm o_stock-widget-pdf'>PRINT</button>
|
||||
</t>
|
||||
|
||||
<div t-name='stockReports.errorModal' class="modal" id="editable_error" tabindex="-1" data-backdrop="static" role="dialog" aria-hidden="true" style="z-index:9999;">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 class="modal-title">Error</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p id='insert_error' class='text-center'></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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"></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"></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.quant'"><t t-set="trclass" t-value="'o_stock_reports_level0'"/></t>
|
||||
<t t-if="l.model == 'stock.move'"><t t-set="trclass" t-value="'o_stock_reports_level1'"/></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="domainClass" t-value="'o_stock_reports_domain_line_1'"/>
|
||||
</t>
|
||||
|
||||
<tr t-att-data-type="l.type" t-att-data-unfold="l.unfoldable" t-att-data-parent_id="l.parent_id" t-att-data-id="l.id" t-att-data-stream="'l.stream'" t-att-data-model_id="l.model_id" t-att-data-model="l.model" t-att-class="trclass">
|
||||
<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-stream="l.stream" 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-parent_quant="l.parent_quant">
|
||||
<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"></i></span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="l.res_model == 'mrp.production' and l.reference == c">
|
||||
<span t-if="c">
|
||||
<a t-att-data-active-id="l.res_id" t-att-data-res-model="l.res_model" class="o_stock_reports_web_action"><t t-raw="c" /></a>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="l.res_model == 'stock.picking' and l.reference == c">
|
||||
<span t-if="c">
|
||||
<a t-att-data-active-id="l.res_id" t-att-data-res-model="l.res_model" class="o_stock_reports_web_action"><t t-raw="c" /></a>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="l.res_model == 'mrp.unbuild' and l.reference == c">
|
||||
<span t-if="c">
|
||||
<a t-att-data-active-id="l.res_id" t-att-data-res-model="l.res_model" class="o_stock_reports_web_action"><t t-raw="c" /></a>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="l.reference != c">
|
||||
<t t-if="typeof c == 'string' || typeof c == 'number'"><span>
|
||||
<t t-raw="c"/>
|
||||
</span></t>
|
||||
<t t-if="typeof c != 'string' & typeof c != 'number'"><span t-att-style="c[1]">
|
||||
<t t-raw="c[0]"/>
|
||||
</span></t>
|
||||
</t>
|
||||
</td>
|
||||
</t>
|
||||
<td>
|
||||
<t t-if="l.model == 'stock.quant'">
|
||||
<span t-if="l.stream == 'downstream'" class="o_stock_reports_stream text-muted" data-stream="upstream" title="Upstream Traceability"><i class="fa fa-arrow-up"></i></span>
|
||||
<span t-if="l.stream == 'upstream'" class="o_stock_reports_stream" data-stream="downstream" title="Downstream Traceability"><i class="fa fa-arrow-down"></i></span>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,129 @@
|
||||
<?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.quant'"><t t-set="trclass" t-value="'o_stock_reports_level0'"/></t>
|
||||
<t t-if="a.get('model') == 'stock.move'"><t t-set="trclass" t-value="'o_stock_reports_level1'"/></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-type="a['type']" t-att-data-stream="a['stream']" 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-class="trclass">
|
||||
<t t-set="tdclass" t-value="''" />
|
||||
<t t-if="a.get('unfoldable')"><t t-set="tdclass" t-value="'o_stock_reports_unfoldable'" /></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-data-stream="a['stream']" t-att-class="tdclass" t-att-data-level="a['level']" t-att-data-parent_quant="a['parent_quant']">
|
||||
<t t-if="column == 1">
|
||||
<span t-att-data-active-id="a['id']" t-att-class="a['type'] + ' ' + domainClass"></span>
|
||||
<t t-if="a.get('unfoldable')">
|
||||
<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"></i></span>
|
||||
</t>
|
||||
</t>
|
||||
<span>
|
||||
<t t-raw="c" />
|
||||
</span>
|
||||
</td>
|
||||
</t>
|
||||
<td>
|
||||
<t t-if="a.get('model') == 'stock.quant'">
|
||||
<span t-if="a['stream'] == 'downstream'" class="o_stock_reports_stream text-muted" data-stream="upstream" title="Upstream Traceability"><i class="fa fa-arrow-up"></i></span>
|
||||
<span t-if="a['stream'] == 'upstream'" class="o_stock_reports_stream" data-stream="downstream" title="Downstream Traceability"><i class="fa fa-arrow-down"></i></span>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_stock_inventory">
|
||||
<div class="container o_stock_reports_page o_stock_reports_no_print">
|
||||
<span t-if="lines" class="o_report_heading text-left"><h1>Upstream Traceability</h1></span>
|
||||
<span><t t-esc="context"/></span>
|
||||
<div class="o_stock_reports_table">
|
||||
<t t-if="not lines">
|
||||
<span class="text-center"><h1>No operation made on this lot.</h1></span>
|
||||
</t>
|
||||
<t t-if="lines">
|
||||
<table width='100%' class="table-responsive">
|
||||
<thead>
|
||||
<tr class="o_report_header">
|
||||
<th class="o_report_line_header">PRODUCT</th>
|
||||
<th class="o_report_line_header"></th>
|
||||
<th class="o_report_line_header">QUANTITY</th>
|
||||
<th class="o_report_line_header">LOCATION SOURCE</th>
|
||||
<th class="o_report_line_header">LOCATION DESTINATION</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-call="mrp_workorder.report_mrp_line"/>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="assets_stock_print_report" inherit_id="web.assets_common" active="True">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/mrp_workorder/static/src/less/stock_traceability_report.less" />
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="report_stock_inventory_print">
|
||||
<t t-raw="'<base href=%s>' % base_url"/>
|
||||
<t t-call="web.html_container">
|
||||
<t t-call-assets="mrp_workorder.assets_stock_print_report" t-js="False"/>
|
||||
<t t-call='mrp_workorder.report_stock_body_print'/>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="report_stock_body_print">
|
||||
<div class="container o_stock_reports_page o_stock_reports_no_print">
|
||||
<span class="text-left"><h3>Traceability Report</h3></span>
|
||||
<div class="table-responsive">
|
||||
<table width='100%' class="o_stock_reports_table">
|
||||
<thead>
|
||||
<tr class="o_report_header">
|
||||
<th class="o_report_line_header">PRODUCT</th>
|
||||
<th class="o_report_line_header"></th>
|
||||
<th class="o_report_line_header">QUANTITY</th>
|
||||
<th class="o_report_line_header">LOCATION SOURCE</th>
|
||||
<th class="o_report_line_header">LOCATION DESTINATION</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-set="space_td" t-value="'margin-left: 0'"/>
|
||||
<t t-foreach="lines" t-as="a">
|
||||
<t t-set="space_td" t-value="'margin-left: '+ str(a['level']) + 'px;'"/>
|
||||
<t t-set="trclass" t-value="'o_stock_reports_default_style'"/>
|
||||
<t t-if="a.get('model') == 'stock.quant'"><t t-set="trclass" t-value="'o_stock_reports_level0'"/></t>
|
||||
<t t-if="a.get('model') == 'stock.move'"><t t-set="trclass" t-value="'o_stock_reports_level1'"/></t>
|
||||
<t t-set="column" t-value="0" />
|
||||
<tr t-att-data-type="a['type']" t-att-data-stream="a['stream']" t-att-data-id="a['id']" t-att-data-model="a['model']" t-att-class="trclass">
|
||||
<t t-set="tdclass" t-value="''" />
|
||||
<t t-if="a.get('unfoldable')"><t t-set="tdclass" t-value="'o_stock_reports_unfoldable'" /></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 t-if="column == 1">
|
||||
<span t-att-style="space_td"></span>
|
||||
</t>
|
||||
<span>
|
||||
<t t-raw="c" />
|
||||
</span>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="mrp_workorder_assets_backend" name="mrp_workorder assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/mrp_workorder/static/src/js/mrp_workorder.js"></script>
|
||||
<script type="text/javascript" src="/mrp_workorder/static/src/js/stock_traceability_report_backend.js"></script>
|
||||
<script type="text/javascript" src="/mrp_workorder/static/src/js/stock_traceability_report_widgets.js"></script>
|
||||
<link rel="stylesheet" href="/mrp_workorder/static/src/less/stock_traceability_report.less" />
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_production_lot_form_inherit_mrp_workorder" model="ir.ui.view">
|
||||
<field name="name">stock.production.lot.form.inherit.stock</field>
|
||||
<field name="model">stock.production.lot</field>
|
||||
<field name="inherit_id" ref="stock.view_production_lot_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<button name="action_traceability" position="replace">
|
||||
<button name="%(action_stock_report)d" icon="fa-arrow-up" class="oe_stat_button" string="Up/Down Traceability" type="action" attrs="{'invisible': [('quant_ids','=', [])]}"/>
|
||||
</button>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="mrp_production_form_view_inherit_mrp_workorder" model="ir.ui.view">
|
||||
<field name="name">mrp.production.form.view.inherit.mrp.workorder</field>
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="button_box" position="inside">
|
||||
<button name="%(action_stock_report)d" icon="fa-arrow-up" class="oe_stat_button" string="Up/Down Traceability" type="action" attrs="{'invisible': [('state','!=', 'done')]}"/>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_picking_form_inherit_mrp_workorder" model="ir.ui.view">
|
||||
<field name="name">stock.picking.form.view.inherit.mrp.workorder</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="button_box" position="inside">
|
||||
<button name="%(action_stock_report)d" icon="fa-arrow-up" class="oe_stat_button" string="Up/Down Traceability" type="action" attrs="{'invisible': [('state','!=', 'done')]}"/>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user