[IMP] mrp,stock: allow auto-printing + chained (report) actions
This commit adds two linked features: 1- the ability to chain (report) actions 2- the ability to auto-print delivery report at picking validation Because feature 2 results in the possibility of 2 actions to be returned at picking validation (due to pre-existing auto-open reception report at validation option), feature 1 is required to support it. It is expected that chaining will primarily occur with report actions since chaining of the other action types does not currently have an applicable use case. Since this feature is only needed within stock for now, it is encapsulated within a custom client_action for now that is a lot of copy paste of action_service.js This is the first commit to support a series of potential auto-printable reports. Part of task: 3046178 - Operation Type ENT PR: odoo/enterprise#43362 Part-of: odoo/odoo#126791
This commit is contained in:
@@ -10,6 +10,7 @@ from markupsafe import escape
|
||||
|
||||
from odoo import SUPERUSER_ID, _, api, fields, models
|
||||
from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
|
||||
from odoo.addons.web.controllers.utils import clean_action
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, format_datetime, format_date, groupby
|
||||
@@ -84,6 +85,9 @@ class PickingType(models.Model):
|
||||
auto_show_reception_report = fields.Boolean(
|
||||
"Show Reception Report at Validation",
|
||||
help="If this checkbox is ticked, Odoo will automatically show the reception report (if there are moves to allocate to) when validating.")
|
||||
auto_print_delivery_slip = fields.Boolean(
|
||||
"Auto Print Delivery Slip",
|
||||
help="If this checkbox is ticked, Odoo will automatically print the delivery slip of a picking when it is validated.")
|
||||
|
||||
count_picking_draft = fields.Integer(compute='_compute_picking_count')
|
||||
count_picking_ready = fields.Integer(compute='_compute_picking_count')
|
||||
@@ -1150,7 +1154,8 @@ class Picking(models.Model):
|
||||
pickings_to_backorder = self - pickings_not_to_backorder
|
||||
pickings_not_to_backorder.with_context(cancel_backorder=True)._action_done()
|
||||
pickings_to_backorder.with_context(cancel_backorder=False)._action_done()
|
||||
|
||||
report_actions = self._get_autoprint_report_actions()
|
||||
another_action = False
|
||||
if self.user_has_groups('stock.group_reception_report'):
|
||||
pickings_show_report = self.filtered(lambda p: p.picking_type_id.auto_show_reception_report)
|
||||
lines = pickings_show_report.move_ids.filtered(lambda m: m.product_id.type == 'product' and m.state != 'cancel' and m.quantity_done and not m.move_dest_ids)
|
||||
@@ -1166,7 +1171,18 @@ class Picking(models.Model):
|
||||
('product_id', 'in', lines.product_id.ids)], limit=1):
|
||||
action = pickings_show_report.action_view_reception_report()
|
||||
action['context'] = {'default_picking_ids': pickings_show_report.ids}
|
||||
return action
|
||||
if not report_actions:
|
||||
return action
|
||||
another_action = action
|
||||
if report_actions:
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'do_multi_print',
|
||||
'params': {
|
||||
'reports': report_actions,
|
||||
'anotherAction': another_action,
|
||||
}
|
||||
}
|
||||
return True
|
||||
|
||||
def action_set_quantities_to_reservation(self):
|
||||
@@ -1690,3 +1706,12 @@ class Picking(models.Model):
|
||||
|
||||
def _get_report_lang(self):
|
||||
return self.move_ids and self.move_ids[0].partner_id.lang or self.partner_id.lang or self.env.lang
|
||||
|
||||
def _get_autoprint_report_actions(self):
|
||||
report_actions = []
|
||||
pickings_to_print = self.filtered(lambda p: p.picking_type_id.auto_print_delivery_slip)
|
||||
if pickings_to_print:
|
||||
action = self.env.ref("stock.action_report_delivery").report_action(pickings_to_print.ids, config=False)
|
||||
clean_action(action, self.env)
|
||||
report_actions.append(action)
|
||||
return report_actions
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { sprintf } from "@web/core/utils/strings";
|
||||
|
||||
async function doMultiPrint(env, action) {
|
||||
for (const report of action.params.reports) {
|
||||
if (report.type != "ir.actions.report") {
|
||||
env.services.notification.add(_t("Incorrect type of action submitted as a report, skipping action"), {
|
||||
title: _t("Report Printing Error"),
|
||||
});
|
||||
continue
|
||||
} else if (report.report_type === "qweb-html") {
|
||||
env.services.notification.add(
|
||||
sprintf(
|
||||
_t("HTML reports cannot be auto-printed, skipping report: %s"),
|
||||
report.name)
|
||||
, {
|
||||
title: _t("Report Printing Error"),
|
||||
});
|
||||
continue
|
||||
}
|
||||
// WARNING: potential issue if pdf generation fails, then action_service defaults
|
||||
// to HTML and rest of the action chain will break w/potentially never resolving promise
|
||||
await env.services.action.doAction({ type: "ir.actions.report", ...report });
|
||||
}
|
||||
if (action.params.anotherAction) {
|
||||
return env.services.action.doAction(action.params.anotherAction);
|
||||
} else if (action.params.on_close) {
|
||||
// handle special cases such as barcode
|
||||
action.params.on_close()
|
||||
} else {
|
||||
return env.services.action.doAction("reload_context");
|
||||
}
|
||||
}
|
||||
|
||||
registry.category("actions").add("do_multi_print", doMultiPrint);
|
||||
@@ -78,49 +78,71 @@
|
||||
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
|
||||
<label for="name"/>
|
||||
<h1><field name="name" placeholder="e.g. Receptions"/></h1>
|
||||
<group name="first">
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="hide_reservation_method" invisible="1"/>
|
||||
<field name="show_picking_type" invisible="1"/>
|
||||
<field name="sequence_id" groups="base.group_no_one"/>
|
||||
<field name="sequence_code"/>
|
||||
<field name="warehouse_id" groups="stock.group_stock_multi_warehouses" force_save="1"/>
|
||||
<field name="reservation_method" invisible="hide_reservation_method" widget="radio"/>
|
||||
<label for="reservation_days_before" string="Reserve before scheduled date" invisible="code == 'incoming' or reservation_method != 'by_date'"/>
|
||||
<div class="o_row" invisible="code == 'incoming' or reservation_method != 'by_date'">
|
||||
<span><field name="reservation_days_before" style="width: 23px;"/> days before/</span>
|
||||
<span><field name="reservation_days_before_priority" style="width: 23px;"/> days before when starred</span>
|
||||
</div>
|
||||
<field name="auto_show_reception_report" invisible="code not in ['incoming', 'internal']" groups="stock.group_reception_report"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
<field invisible="code not in ['incoming', 'outgoing', 'internal']" name="return_picking_type_id" string="Returns Type"/>
|
||||
<field name="default_location_return_id" invisible="code not in ['incoming', 'outgoing', 'internal']" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="create_backorder"/>
|
||||
<field name="show_operations" invisible="not show_picking_type"/>
|
||||
<field name="show_reserved" invisible="code != 'incoming'"/>
|
||||
</group>
|
||||
</group>
|
||||
<group name="second">
|
||||
<group invisible="code not in ['incoming', 'outgoing', 'internal']" string="Lots/Serial Numbers" groups="stock.group_production_lot" name="stock_picking_type_lot">
|
||||
<field name="use_create_lots" string="Create New"/>
|
||||
<field name="use_existing_lots" string="Use Existing ones"/>
|
||||
</group>
|
||||
<group invisible="code not in ['incoming', 'outgoing', 'internal']" string="Packages" groups="stock.group_tracking_lot">
|
||||
<field name="show_entire_packs"/>
|
||||
</group>
|
||||
<!-- As this group will be hidden without multi_loccation, you will not be able to create a
|
||||
picking type with the code 'Internal', which make sense, but as the field 'code' on picking
|
||||
types can't be partially hidden, you can still select the code internal in the form view -->
|
||||
<group string="Locations" groups="stock.group_stock_multi_locations" name="locations">
|
||||
<field name="default_location_src_id" options="{'no_create': True}" required="code in ('internal', 'outgoing')"/>
|
||||
<field name="default_location_dest_id" options="{'no_create': True}" required="code in ('internal', 'incoming')"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page name="general" string="General">
|
||||
<group name="first">
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="hide_reservation_method" invisible="1"/>
|
||||
<field name="show_picking_type" invisible="1"/>
|
||||
<field name="sequence_id" groups="base.group_no_one"/>
|
||||
<field name="sequence_code"/>
|
||||
<field name="warehouse_id" groups="stock.group_stock_multi_warehouses" force_save="1"/>
|
||||
<field name="reservation_method" invisible="hide_reservation_method" widget="radio"/>
|
||||
<label for="reservation_days_before" string="Reserve before scheduled date" invisible="code == 'incoming' or reservation_method != 'by_date'"/>
|
||||
<div class="o_row" invisible="code == 'incoming' or reservation_method != 'by_date'">
|
||||
<span><field name="reservation_days_before" style="width: 23px;"/> days before/</span>
|
||||
<span><field name="reservation_days_before_priority" style="width: 23px;"/> days before when starred</span>
|
||||
</div>
|
||||
<field name="auto_show_reception_report" invisible="code not in ['incoming', 'internal']" groups="stock.group_reception_report"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
<field invisible="code not in ['incoming', 'outgoing', 'internal']" name="return_picking_type_id" string="Returns Type"/>
|
||||
<field name="default_location_return_id" invisible="code not in ['incoming', 'outgoing', 'internal']" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="create_backorder"/>
|
||||
<field name="show_operations" invisible="not show_picking_type"/>
|
||||
<field name="show_reserved" invisible="code != 'incoming'"/>
|
||||
</group>
|
||||
</group>
|
||||
<group name="second">
|
||||
<group invisible="code not in ['incoming', 'outgoing', 'internal']" string="Lots/Serial Numbers" groups="stock.group_production_lot" name="stock_picking_type_lot">
|
||||
<field name="use_create_lots" string="Create New"/>
|
||||
<field name="use_existing_lots" string="Use Existing ones"/>
|
||||
</group>
|
||||
<group invisible="code not in ['incoming', 'outgoing', 'internal']" string="Packages" groups="stock.group_tracking_lot">
|
||||
<field name="show_entire_packs"/>
|
||||
</group>
|
||||
<!-- As this group will be hidden without multi_loccation, you will not be able to create a
|
||||
picking type with the code 'Internal', which make sense, but as the field 'code' on picking
|
||||
types can't be partially hidden, you can still select the code internal in the form view -->
|
||||
<group string="Locations" groups="stock.group_stock_multi_locations" name="locations">
|
||||
<field name="default_location_src_id" options="{'no_create': True}" required="code in ('internal', 'outgoing')"/>
|
||||
<field name="default_location_dest_id" options="{'no_create': True}" required="code in ('internal', 'incoming')"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page name="hardware" string="Hardware" invisible="code not in ['incoming', 'outgoing', 'internal']" >
|
||||
<group name="auto_print">
|
||||
<group string="Print on Validation">
|
||||
<field name="auto_print_delivery_slip" string="Delivery Slip"/>
|
||||
</group>
|
||||
<group string="">
|
||||
<div colspan="2">
|
||||
Odoo opens a PDF preview by default. If you (Enterprise users only) want to print instantly,
|
||||
install the IoT App on a computer that is on the same local network as the
|
||||
barcode operator and configure the routing of the reports.
|
||||
<a href="https://www.odoo.com/documentation/master/applications/productivity/iot/devices/printer.html"
|
||||
target="_blank" class="fa fa-arrow-right">
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
Reference in New Issue
Block a user