diff options
| author | Tiffany Chang (tic) <tic@odoo.com> | 2020-05-29 14:30:44 +0000 |
|---|---|---|
| committer | svs-odoo <svs@odoo.com> | 2020-08-20 15:06:08 +0000 |
| commit | 71e7f56719622c7fc3b2f6b750121971875e2750 (patch) | |
| tree | 5885f453b82263bf82628293d7a1baf8f8498ec7 /addons | |
| parent | 1bd2594b8390baddcc65cac310a75322f436b15f (diff) | |
[IMP] stock_picking_batch: add "Scheduled Date" field
This commit adds a "Scheduled Date" field to the batch pickings. Logic
behind this date is a bit tricky:
1. If "Scheduled Date" is edited directly in batch then this date will
also be applied to all of its picking's "Schedule Date"s.
2. If "Scheduled Date" is not edited directly in the batch, then this
date will be the earliest date of its assigned pickings and pickings
will maintain their original scheduled date' including if picking
scheduled date is changed.
3. If "Scheduled Date" is not edited directly and all pickings are
removed or there are none then date will default to no date.
First cut of test for scheduled_date logic has also been added. Update
will be needed for testing onchange logic since it is currently not
supported by the tests.Form due to M2M widget used with O2M picking_ids
(M2M widget is used for when doing a "Add a Line" transfer to a batch
in backend).
Additionally this commit adds the 'scheduled_date' and 'operation_type' to
the kanban view.
Part of "1. Improve Batch Pickings" specification of overall barcode app
improvements task.
Task: 1884520
Enterprise PR: odoo/enterprise#12086
Upgrade PR: odoo/upgrade#1569
Closes: odoo/odoo#55096
Diffstat (limited to 'addons')
3 files changed, 113 insertions, 1 deletions
diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py index 7d6cb969d75..696c67eabc5 100644 --- a/addons/stock_picking_batch/models/stock_picking_batch.py +++ b/addons/stock_picking_batch/models/stock_picking_batch.py @@ -47,6 +47,13 @@ class StockPickingBatch(models.Model): picking_type_id = fields.Many2one( 'stock.picking.type', 'Operation Type', check_company=True, copy=False, readonly=True, states={'draft': [('readonly', False)]}) + scheduled_date = fields.Datetime( + 'Scheduled Date', copy=False, store=True, readonly=False, compute="_compute_scheduled_date", + states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, + help="""Scheduled date for the transfers to be processed. + - If manually set then scheduled date for all transfers in batch will automatically update to this date. + - If not manually changed and transfers are added/removed/updated then this will be their earliest scheduled date + but this scheduled date will not be set for all transfers in batch.""") @api.depends('company_id', 'picking_type_id', 'state') def _compute_allowed_picking_ids(self): @@ -95,6 +102,15 @@ class StockPickingBatch(models.Model): elif all(picking.state in ['cancel', 'done'] for picking in batch.picking_ids): batch.state = 'done' + @api.depends('picking_ids', 'picking_ids.scheduled_date') + def _compute_scheduled_date(self): + self.scheduled_date = min(self.picking_ids.filtered('scheduled_date').mapped('scheduled_date'), default=False) + + @api.onchange('scheduled_date') + def onchange_scheduled_date(self): + if self.scheduled_date: + self.picking_ids.scheduled_date = self.scheduled_date + def _set_move_line_ids(self): new_move_lines = self[0].move_line_ids for picking in self.picking_ids: @@ -129,6 +145,17 @@ class StockPickingBatch(models.Model): raise UserError(_("You can only delete draft batch transfers.")) return super().unlink() + def onchange(self, values, field_name, field_onchange): + """Override onchange to NOT to update all scheduled_date on pickings when + scheduled_date on batch is updated by the change of scheduled_date on pickings. + """ + result = super().onchange(values, field_name, field_onchange) + if field_name == 'picking_ids' and 'value' in result: + for line in result['value'].get('picking_ids', []): + if line[0] < 2 and 'scheduled_date' in line[2]: + del line[2]['scheduled_date'] + return result + # ------------------------------------------------------------------------- # Action methods # ------------------------------------------------------------------------- diff --git a/addons/stock_picking_batch/tests/test_batch_picking.py b/addons/stock_picking_batch/tests/test_batch_picking.py index f23270e003c..c7352699439 100644 --- a/addons/stock_picking_batch/tests/test_batch_picking.py +++ b/addons/stock_picking_batch/tests/test_batch_picking.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from datetime import datetime, timedelta + from odoo.tests import Form from odoo.tests.common import TransactionCase @@ -58,12 +60,88 @@ class TestBatchPicking(TransactionCase): 'location_dest_id': self.customer_location.id, }) + self.picking_client_3 = self.env['stock.picking'].create({ + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + 'picking_type_id': self.picking_type_out, + 'company_id': self.env.company.id, + }) + + self.env['stock.move'].create({ + 'name': self.productB.name, + 'product_id': self.productB.id, + 'product_uom_qty': 10, + 'product_uom': self.productA.uom_id.id, + 'picking_id': self.picking_client_3.id, + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + }) + self.batch = self.env['stock.picking.batch'].create({ 'name': 'Batch 1', 'company_id': self.env.company.id, 'picking_ids': [(4, self.picking_client_1.id), (4, self.picking_client_2.id)] }) + def test_batch_scheduled_date(self): + """ Test to make sure the correct scheduled date is set for both a batch and its pickings. + Setting a batch's scheduled date manually has different behavior from when it is automatically + set/updated via compute. + """ + + now = datetime.now().replace(microsecond=0) + self.batch.scheduled_date = now + + # TODO: this test cannot currently handle the onchange scheduled_date logic because of test form + # view not handling the M2M widget assigned to picking_ids (O2M). Hopefully if this changes then + # commented parts of this test can be used later. + + + # manually set batch scheduled date => picking's scheduled dates auto update to match (onchange logic test) + # with Form(self.batch) as batch_form: + # batch_form.scheduled_date = now - timedelta(days=1) + # batch_form.save() + # self.assertEqual(self.batch.scheduled_date, self.picking_client_1.scheduled_date) + # self.assertEqual(self.batch.scheduled_date, self.picking_client_2.scheduled_date) + + picking1_scheduled_date = now - timedelta(days=2) + picking2_scheduled_date = now - timedelta(days=3) + picking3_scheduled_date = now - timedelta(days=4) + + # manually update picking scheduled dates => batch's scheduled date auto update to match lowest value + self.picking_client_1.scheduled_date = picking1_scheduled_date + self.picking_client_2.scheduled_date = picking2_scheduled_date + self.assertEqual(self.batch.scheduled_date, self.picking_client_2.scheduled_date) + # but individual pickings keep original scheduled dates + self.assertEqual(self.picking_client_1.scheduled_date, picking1_scheduled_date) + self.assertEqual(self.picking_client_2.scheduled_date, picking2_scheduled_date) + + # add a new picking with an earlier scheduled date => batch's scheduled date should auto-update + self.picking_client_3.scheduled_date = picking3_scheduled_date + self.batch.write({'picking_ids': [(4, self.picking_client_3.id)]}) + self.assertEqual(self.batch.scheduled_date, self.picking_client_3.scheduled_date) + + # remove that picking and batch scheduled date should auto-update to next min date + self.batch.write({'picking_ids': [(3, self.picking_client_3.id)]}) + self.assertEqual(self.batch.scheduled_date, self.picking_client_2.scheduled_date) + + # directly add new picking with an earlier scheduled date => batch's scheduled date auto updates to match, + # but existing pickings do not (onchange logic test) + # with Form(self.batch) as batch_form: + # batch_form.picking_ids.add(self.picking_client_3) + # batch_form.save() + # # individual pickings keep original scheduled dates + self.assertEqual(self.picking_client_1.scheduled_date, picking1_scheduled_date) + self.assertEqual(self.picking_client_2.scheduled_date, picking2_scheduled_date) + # self.assertEqual(self.batch.scheduled_date, self.picking_client_3.scheduled_date) + # self.batch.write({'picking_ids': [(3, self.picking_client_3.id)]}) + + + # remove all pickings and batch scheduled date should default to none + self.batch.write({'picking_ids': [(3, self.picking_client_1.id)]}) + self.batch.write({'picking_ids': [(3, self.picking_client_2.id)]}) + self.assertEqual(self.batch.scheduled_date, False) + def test_simple_batch_with_manual_qty_done(self): """ Test a simple batch picking with all quantity for picking available. The user set all the quantity_done on picking manually and no wizard are used. diff --git a/addons/stock_picking_batch/views/stock_picking_batch_views.xml b/addons/stock_picking_batch/views/stock_picking_batch_views.xml index a83bf4f5258..016d53cfb87 100644 --- a/addons/stock_picking_batch/views/stock_picking_batch_views.xml +++ b/addons/stock_picking_batch/views/stock_picking_batch_views.xml @@ -102,6 +102,9 @@ <field name="picking_type_id"/> <field name="company_id" groups="base.group_multi_company" attrs="{'readonly': [('picking_ids', '!=', [])]}" force_save="1"/> </group> + <group> + <field name="scheduled_date"/> + </group> </group> <notebook> <page string="Detailed Operations" attrs="{'invisible': [('state', '=', 'draft')]}"> @@ -140,6 +143,7 @@ <field name="arch" type="xml"> <tree string="Stock Batch Transfer" multi_edit="1" sample="1"> <field name="name" decoration-bf="1"/> + <field name="scheduled_date"/> <field name="user_id" widget="many2one_avatar_user"/> <field name="company_id" groups="base.group_multi_company"/> <field name="state" widget="badge" decoration-success="state == 'done'" decoration-info="state in ('draft', 'in_progress')"/> @@ -165,8 +169,11 @@ <field name="state" widget="label_selection"/> </div> <div class="o_kanban_record_bottom"> - <div class="oe_kanban_bottom_left"/> + <div class="oe_kanban_bottom_left"> + <field name="picking_type_id"/> + </div> <div class="oe_kanban_bottom_right"> + <field name="scheduled_date" widget="date"/> <field name="user_id" widget="many2one_avatar_user"/> </div> </div> |
