odoo-addon-shipment-advice 16.0.1.3.1.9__py3-none-any.whl → 16.0.1.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. odoo/addons/shipment_advice/README.rst +1 -1
  2. odoo/addons/shipment_advice/__manifest__.py +5 -1
  3. odoo/addons/shipment_advice/data/queue_job_channel.xml +9 -0
  4. odoo/addons/shipment_advice/data/queue_job_function.xml +26 -0
  5. odoo/addons/shipment_advice/i18n/shipment_advice.pot +68 -0
  6. odoo/addons/shipment_advice/models/res_company.py +6 -0
  7. odoo/addons/shipment_advice/models/res_config_settings.py +3 -0
  8. odoo/addons/shipment_advice/models/shipment_advice.py +119 -52
  9. odoo/addons/shipment_advice/static/description/index.html +1 -1
  10. odoo/addons/shipment_advice/tests/__init__.py +1 -0
  11. odoo/addons/shipment_advice/tests/test_shipment_advice.py +1 -1
  12. odoo/addons/shipment_advice/tests/test_shipment_advice_async.py +299 -0
  13. odoo/addons/shipment_advice/views/res_config_settings.xml +17 -0
  14. odoo/addons/shipment_advice/views/shipment_advice.xml +8 -1
  15. odoo/addons/shipment_advice/wizards/load_shipment.py +1 -1
  16. odoo/addons/shipment_advice/wizards/plan_shipment.py +1 -1
  17. odoo/addons/shipment_advice/wizards/unload_shipment.py +2 -2
  18. {odoo_addon_shipment_advice-16.0.1.3.1.9.dist-info → odoo_addon_shipment_advice-16.0.1.4.0.dist-info}/METADATA +3 -2
  19. {odoo_addon_shipment_advice-16.0.1.3.1.9.dist-info → odoo_addon_shipment_advice-16.0.1.4.0.dist-info}/RECORD +21 -18
  20. {odoo_addon_shipment_advice-16.0.1.3.1.9.dist-info → odoo_addon_shipment_advice-16.0.1.4.0.dist-info}/WHEEL +0 -0
  21. {odoo_addon_shipment_advice-16.0.1.3.1.9.dist-info → odoo_addon_shipment_advice-16.0.1.4.0.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ Shipment Advice
7
7
  !! This file is generated by oca-gen-addon-readme !!
8
8
  !! changes will be overwritten. !!
9
9
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10
- !! source digest: sha256:2ce9096e86385f60cb183efb0745bb01324df6f1dee67604801fd7b364a0a68e
10
+ !! source digest: sha256:d15a08534108c95673383be523fd4d221150eb3270f749dad244c6f2504036b0
11
11
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12
12
 
13
13
  .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -4,19 +4,23 @@
4
4
  {
5
5
  "name": "Shipment Advice",
6
6
  "summary": "Manage your (un)loading process through shipment advices.",
7
- "version": "16.0.1.3.1",
7
+ "version": "16.0.1.4.0",
8
8
  "author": "Camptocamp, Odoo Community Association (OCA)",
9
9
  "website": "https://github.com/OCA/stock-logistics-transport",
10
10
  "category": "Warehouse Management",
11
11
  "depends": [
12
12
  "stock",
13
13
  "delivery",
14
+ # OCA/queue
15
+ "queue_job",
14
16
  # OCA/stock-logistics-transport
15
17
  "stock_dock",
16
18
  ],
17
19
  "data": [
18
20
  "security/ir.model.access.csv",
19
21
  "data/ir_sequence.xml",
22
+ "data/queue_job_channel.xml",
23
+ "data/queue_job_function.xml",
20
24
  "views/res_config_settings.xml",
21
25
  "views/shipment_advice.xml",
22
26
  "views/stock_picking.xml",
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <!-- Copyright 2023 ACSONE SA/NV
3
+ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
4
+ <odoo>
5
+ <record model="queue.job.channel" id="shipment_advice_queue_channel">
6
+ <field name="name">shipment_advice</field>
7
+ <field name="parent_id" ref="queue_job.channel_root" />
8
+ </record>
9
+ </odoo>
@@ -0,0 +1,26 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <!-- Copyright 2022 ACSONE SA/NV
3
+ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
4
+ <odoo>
5
+ <record id="job_function_shipment_advice_validate_picking" model="queue.job.function">
6
+ <field name="model_id" ref="shipment_advice.model_shipment_advice" />
7
+ <field name="method">_validate_picking</field>
8
+ <field name="channel_id" ref="shipment_advice.shipment_advice_queue_channel" />
9
+ </record>
10
+ <record
11
+ id="job_function_shipment_advice_unplan_undone_moves"
12
+ model="queue.job.function"
13
+ >
14
+ <field name="model_id" ref="shipment_advice.model_shipment_advice" />
15
+ <field name="method">_unplan_undone_moves</field>
16
+ <field name="channel_id" ref="shipment_advice.shipment_advice_queue_channel" />
17
+ </record>
18
+ <record
19
+ id="job_function_shipment_advice_postprocess_action_done"
20
+ model="queue.job.function"
21
+ >
22
+ <field name="model_id" ref="shipment_advice.model_shipment_advice" />
23
+ <field name="method">_postprocess_action_done</field>
24
+ <field name="channel_id" ref="shipment_advice.shipment_advice_queue_channel" />
25
+ </record>
26
+ </odoo>
@@ -13,6 +13,13 @@ msgstr ""
13
13
  "Content-Transfer-Encoding: \n"
14
14
  "Plural-Forms: \n"
15
15
 
16
+ #. module: shipment_advice
17
+ #. odoo-python
18
+ #: code:addons/shipment_advice/models/shipment_advice.py:0
19
+ #, python-format
20
+ msgid "%(sa)s: %(pick)s background validation"
21
+ msgstr ""
22
+
16
23
  #. module: shipment_advice
17
24
  #: model:ir.actions.report,print_report_name:shipment_advice.action_report_shipment_advice
18
25
  msgid "'Shipment Advice - %s' % (object.name)"
@@ -63,6 +70,15 @@ msgstr ""
63
70
  msgid "Activity Type Icon"
64
71
  msgstr ""
65
72
 
73
+ #. module: shipment_advice
74
+ #. odoo-python
75
+ #: code:addons/shipment_advice/models/shipment_advice.py:0
76
+ #, python-format
77
+ msgid ""
78
+ "An error occurred while processing:\n"
79
+ "- %(related_object_name)s: %(error)s"
80
+ msgstr ""
81
+
66
82
  #. module: shipment_advice
67
83
  #: model:ir.model.fields,field_description:shipment_advice.field_shipment_advice__arrival_date
68
84
  msgid "Arrival Date"
@@ -236,6 +252,16 @@ msgstr ""
236
252
  msgid "Driver signature"
237
253
  msgstr ""
238
254
 
255
+ #. module: shipment_advice
256
+ #: model:ir.model.fields.selection,name:shipment_advice.selection__shipment_advice__state__error
257
+ msgid "Error"
258
+ msgstr ""
259
+
260
+ #. module: shipment_advice
261
+ #: model:ir.model.fields,field_description:shipment_advice.field_shipment_advice__error_message
262
+ msgid "Error Message"
263
+ msgstr ""
264
+
239
265
  #. module: shipment_advice
240
266
  #: model:ir.model.fields,field_description:shipment_advice.field_shipment_advice__message_follower_ids
241
267
  msgid "Followers"
@@ -309,6 +335,11 @@ msgid ""
309
335
  "If you want to mark deliveries as done only when they are all loaded in a shipment advice choose 'Leave open'. This last option is useful when your deliveries will be shipped by several trucks."
310
336
  msgstr ""
311
337
 
338
+ #. module: shipment_advice
339
+ #: model:ir.model.fields.selection,name:shipment_advice.selection__shipment_advice__state__in_process
340
+ msgid "In process"
341
+ msgstr ""
342
+
312
343
  #. module: shipment_advice
313
344
  #: model:ir.model.fields.selection,name:shipment_advice.selection__shipment_advice__state__in_progress
314
345
  msgid "In progress"
@@ -686,6 +717,13 @@ msgstr ""
686
717
  msgid "Number of messages with delivery error"
687
718
  msgstr ""
688
719
 
720
+ #. module: shipment_advice
721
+ #. odoo-python
722
+ #: code:addons/shipment_advice/models/shipment_advice.py:0
723
+ #, python-format
724
+ msgid "One of the pickings to process failed to validate"
725
+ msgstr ""
726
+
689
727
  #. module: shipment_advice
690
728
  #: model:ir.model.fields,field_description:shipment_advice.field_wizard_load_shipment__open_shipment
691
729
  msgid "Open Shipment"
@@ -913,6 +951,13 @@ msgstr ""
913
951
  msgid "Responsible User"
914
952
  msgstr ""
915
953
 
954
+ #. module: shipment_advice
955
+ #: model:ir.model.fields,field_description:shipment_advice.field_res_company__shipment_advice_run_in_queue_job
956
+ #: model:ir.model.fields,field_description:shipment_advice.field_res_config_settings__shipment_advice_run_in_queue_job
957
+ #: model:ir.model.fields,field_description:shipment_advice.field_shipment_advice__run_in_queue_job
958
+ msgid "Run shipment advice in queue job"
959
+ msgstr ""
960
+
916
961
  #. module: shipment_advice
917
962
  #: model:ir.actions.report,name:shipment_advice.action_report_shipment_advice
918
963
  #: model:ir.model,name:shipment_advice.model_shipment_advice
@@ -1034,6 +1079,24 @@ msgstr ""
1034
1079
  msgid "To plan in Shipment Advice"
1035
1080
  msgstr ""
1036
1081
 
1082
+ #. module: shipment_advice
1083
+ #: model_terms:ir.ui.view,arch_db:shipment_advice.res_config_settings_view_form
1084
+ msgid ""
1085
+ "To prevent timeouts for large shipments, enable this option to execute\n"
1086
+ " shipment advice validation through a queued job. Each picking will be\n"
1087
+ " validated in a separate jobs."
1088
+ msgstr ""
1089
+
1090
+ #. module: shipment_advice
1091
+ #: model:ir.model.fields,help:shipment_advice.field_res_company__shipment_advice_run_in_queue_job
1092
+ #: model:ir.model.fields,help:shipment_advice.field_res_config_settings__shipment_advice_run_in_queue_job
1093
+ #: model:ir.model.fields,help:shipment_advice.field_shipment_advice__run_in_queue_job
1094
+ msgid ""
1095
+ "To prevent timeouts for large shipments, enable this option to execute "
1096
+ "shipment advice validation through a queued jobs. Each picking will be "
1097
+ "validated in a separate job."
1098
+ msgstr ""
1099
+
1037
1100
  #. module: shipment_advice
1038
1101
  #: model_terms:ir.ui.view,arch_db:shipment_advice.shipment_advice_view_search
1039
1102
  msgid "Today"
@@ -1321,3 +1384,8 @@ msgid ""
1321
1384
  "You cannot unload this move line alone, you have to unload the whole package"
1322
1385
  " content."
1323
1386
  msgstr ""
1387
+
1388
+ #. module: shipment_advice
1389
+ #: model_terms:ir.ui.view,arch_db:shipment_advice.res_config_settings_view_form
1390
+ msgid "shipment_advice_run_in_queue_job"
1391
+ msgstr ""
@@ -23,3 +23,9 @@ class ResCompany(models.Model):
23
23
  "deliveries will be shipped by several trucks."
24
24
  ),
25
25
  )
26
+ shipment_advice_run_in_queue_job = fields.Boolean(
27
+ string="Run shipment advice in queue job",
28
+ help="To prevent timeouts for large shipments, enable this option to execute "
29
+ "shipment advice validation through a queued jobs. Each picking will be "
30
+ "validated in a separate job.",
31
+ )
@@ -10,3 +10,6 @@ class ResConfigSettings(models.TransientModel):
10
10
  shipment_advice_outgoing_backorder_policy = fields.Selection(
11
11
  related="company_id.shipment_advice_outgoing_backorder_policy", readonly=False
12
12
  )
13
+ shipment_advice_run_in_queue_job = fields.Boolean(
14
+ related="company_id.shipment_advice_run_in_queue_job", readonly=False
15
+ )
@@ -4,6 +4,9 @@
4
4
  from odoo import _, api, fields, models
5
5
  from odoo.exceptions import UserError
6
6
 
7
+ from odoo.addons.queue_job.delay import chain, group
8
+ from odoo.addons.queue_job.job import identity_exact
9
+
7
10
 
8
11
  class ShipmentAdvice(models.Model):
9
12
  _name = "shipment.advice"
@@ -23,11 +26,14 @@ class ShipmentAdvice(models.Model):
23
26
  ("draft", "Draft"),
24
27
  ("confirmed", "Confirmed"),
25
28
  ("in_progress", "In progress"),
29
+ ("in_process", "In process"),
30
+ ("error", "Error"),
26
31
  ("done", "Done"),
27
32
  ("cancel", "Cancelled"),
28
33
  ],
29
34
  string="Status",
30
35
  default="draft",
36
+ tracking=True,
31
37
  )
32
38
  warehouse_id = fields.Many2one(
33
39
  comodel_name="stock.warehouse",
@@ -168,6 +174,10 @@ class ShipmentAdvice(models.Model):
168
174
  "(e.g. through the shopfloor application)."
169
175
  ),
170
176
  )
177
+ run_in_queue_job = fields.Boolean(
178
+ related="company_id.shipment_advice_run_in_queue_job"
179
+ )
180
+ error_message = fields.Text(tracking=True)
171
181
 
172
182
  _sql_constraints = [
173
183
  (
@@ -295,64 +305,121 @@ class ShipmentAdvice(models.Model):
295
305
  self.env.cr.execute(sql, (tuple(records.ids),), log_exceptions=False)
296
306
 
297
307
  def action_done(self):
298
- wiz_model = self.env["stock.backorder.confirmation"]
308
+ self._check_action_done_allowed()
309
+ for shipment in self:
310
+ shipment._action_done()
311
+ return True
312
+
313
+ def _get_picking_to_process(self):
314
+ self.ensure_one()
315
+ if self.shipment_type == "incoming":
316
+ return self.planned_picking_ids
317
+ return self.loaded_picking_ids
318
+
319
+ def _action_done(self):
320
+ # Validate transfers (create backorders for unprocessed lines)
321
+ self.ensure_one()
322
+ self.write({"state": "in_process", "error_message": False})
323
+
324
+ if self.shipment_type == "incoming":
325
+ backorder_policy = "create_backorder"
326
+ else:
327
+ backorder_policy = self.company_id.shipment_advice_outgoing_backorder_policy
328
+ pickings = self._get_picking_to_process().filtered(
329
+ lambda p: p.state not in ("cancel", "done")
330
+ )
331
+ if self.run_in_queue_job:
332
+ chain(
333
+ group(
334
+ *[
335
+ self.delayable(
336
+ identity_key=identity_exact,
337
+ description=_(
338
+ "%(sa)s: %(pick)s background validation",
339
+ sa=self.name,
340
+ pick=picking.name,
341
+ ),
342
+ )._validate_picking(picking, backorder_policy)
343
+ for picking in pickings
344
+ ]
345
+ ),
346
+ group(self.delayable(description=self.name)._unplan_undone_moves()),
347
+ group(self.delayable(description=self.name)._postprocess_action_done()),
348
+ ).delay()
349
+ return
350
+ for picking in pickings:
351
+ self._validate_picking(picking, backorder_policy)
352
+ self._unplan_undone_moves()
353
+ self._postprocess_action_done()
354
+
355
+ def _check_action_done_allowed(self):
299
356
  for shipment in self:
300
- if shipment.state != "in_progress":
357
+ if shipment.state not in ("in_progress", "error"):
301
358
  raise UserError(
302
359
  _("Shipment {} is not started, operation aborted.").format(
303
360
  shipment.name
304
361
  )
305
362
  )
306
- # Validate transfers (create backorders for unprocessed lines)
307
- if shipment.shipment_type == "incoming":
308
- self._lock_records(self.planned_picking_ids)
309
- for picking in self.planned_picking_ids:
310
- if picking.state in ("cancel", "done"):
311
- continue
312
- if picking._check_backorder():
313
- wiz = wiz_model.create({})
314
- wiz.pick_ids = picking
315
- wiz.with_context(
316
- button_validate_picking_ids=picking.ids
317
- ).process()
318
- else:
319
- picking._action_done()
320
- else:
321
- backorder_policy = (
322
- shipment.company_id.shipment_advice_outgoing_backorder_policy
323
- )
324
- self._lock_records(self.loaded_picking_ids)
325
- if backorder_policy == "create_backorder":
326
- for picking in self.loaded_picking_ids:
327
- if picking.state in ("cancel", "done"):
328
- continue
329
- if picking._check_backorder():
330
- wiz = wiz_model.create({})
331
- wiz.pick_ids = picking
332
- wiz.with_context(
333
- button_validate_picking_ids=picking.ids
334
- ).process()
335
- else:
336
- picking._action_done()
337
- else:
338
- for picking in self.loaded_picking_ids:
339
- if picking.state in ("cancel", "done"):
340
- continue
341
- if not picking._check_backorder():
342
- # no backorder needed means that all qty_done are
343
- # set to fullfill the need => validate
344
- picking._action_done()
345
- # Unplan moves that were not loaded and validated
346
- moves_to_unplan = (
347
- self.loaded_move_line_ids.move_id | self.planned_move_ids
348
- ).filtered(
349
- lambda m: m.state not in ("cancel", "done") and not m.quantity_done
350
- )
351
- moves_to_unplan.shipment_advice_id = False
352
- if not shipment.departure_date:
353
- shipment.departure_date = fields.Datetime.now()
354
- shipment.state = "done"
355
- return True
363
+
364
+ def _validate_picking(self, picking, backorder_policy="create_backorder"):
365
+ self.ensure_one()
366
+ self._lock_records(picking)
367
+ try:
368
+ with self.env.cr.savepoint():
369
+ if (
370
+ picking._check_backorder()
371
+ and backorder_policy == "create_backorder"
372
+ ):
373
+ wiz = self.env["stock.backorder.confirmation"].create({})
374
+ wiz.pick_ids = picking
375
+ wiz.with_context(button_validate_picking_ids=picking.ids).process()
376
+ elif not picking._check_backorder():
377
+ picking._action_done()
378
+ except UserError as error:
379
+ self.write(
380
+ {
381
+ "state": "error",
382
+ "error_message": self._get_error_message(error, picking),
383
+ }
384
+ )
385
+
386
+ def _unplan_undone_moves(self):
387
+ """Unplan moves that were not loaded and validated"""
388
+ self.ensure_one()
389
+ if self.state != "in_process" or self.shipment_type != "outgoing":
390
+ return
391
+ moves_to_unplan = (
392
+ self.loaded_move_line_ids.move_id | self.planned_move_ids
393
+ ).filtered(lambda m: m.state not in ("cancel", "done") and not m.quantity_done)
394
+ moves_to_unplan.shipment_advice_id = False
395
+
396
+ def _postprocess_action_done(self):
397
+ self.ensure_one()
398
+ if self.state != "in_process":
399
+ return
400
+ if self._get_picking_to_process().filtered(
401
+ lambda p: p.state not in ("done", "cancel")
402
+ ):
403
+ self.write(
404
+ {
405
+ "state": "error",
406
+ "error_message": _(
407
+ "One of the pickings to process failed to validate"
408
+ ),
409
+ }
410
+ )
411
+ return
412
+ if not self.departure_date:
413
+ self.departure_date = fields.Datetime.now()
414
+ self.write({"state": "done", "error_message": False})
415
+
416
+ @api.model
417
+ def _get_error_message(self, error, related_object):
418
+ return _(
419
+ "An error occurred while processing:\n- %(related_object_name)s: %(error)s",
420
+ related_object_name=related_object.display_name,
421
+ error=str(error),
422
+ )
356
423
 
357
424
  def action_cancel(self):
358
425
  for shipment in self:
@@ -366,7 +366,7 @@ ul.auto-toc {
366
366
  !! This file is generated by oca-gen-addon-readme !!
367
367
  !! changes will be overwritten. !!
368
368
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
369
- !! source digest: sha256:2ce9096e86385f60cb183efb0745bb01324df6f1dee67604801fd7b364a0a68e
369
+ !! source digest: sha256:d15a08534108c95673383be523fd4d221150eb3270f749dad244c6f2504036b0
370
370
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
371
371
  <p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/stock-logistics-transport/tree/16.0/shipment_advice"><img alt="OCA/stock-logistics-transport" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--transport-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/stock-logistics-transport-16-0/stock-logistics-transport-16-0-shipment_advice"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-transport&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
372
372
  <p>Manage your (un)loading process through shipment advices.</p>
@@ -1,4 +1,5 @@
1
1
  from . import test_shipment_advice
2
+ from . import test_shipment_advice_async
2
3
  from . import test_shipment_advice_plan
3
4
  from . import test_shipment_advice_load
4
5
  from . import test_shipment_advice_unload
@@ -108,7 +108,7 @@ class TestShipmentAdvice(Common):
108
108
  # Validate the shipment => the transfer is still open
109
109
  self.shipment_advice_out.action_done()
110
110
  picking = package_level.picking_id
111
- self.assertEqual(self.shipment_advice_out.state, "done")
111
+ self.assertEqual(self.shipment_advice_out.state, "error")
112
112
  # Check the transfer
113
113
  self.assertTrue(
114
114
  all(
@@ -0,0 +1,299 @@
1
+ # Copyright 2021 Camptocamp SA
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
3
+
4
+
5
+ from odoo.addons.queue_job.tests.common import trap_jobs
6
+
7
+ from .common import Common
8
+
9
+
10
+ class TestShipmentAdvice(Common):
11
+ @classmethod
12
+ def setUpClass(cls):
13
+ super().setUpClass()
14
+ cls.env.user.company_id.shipment_advice_run_in_queue_job = True
15
+ cls.product_out4 = cls.env["product.product"].create(
16
+ {"name": "product_out4", "type": "product"}
17
+ )
18
+ cls.group1 = cls.env["procurement.group"].create({})
19
+ cls.group2 = cls.env["procurement.group"].create({})
20
+ cls.group3 = cls.env["procurement.group"].create({})
21
+ cls._update_qty_in_location(
22
+ cls.picking_type_out.default_location_src_id,
23
+ cls.product_out4,
24
+ 3,
25
+ )
26
+ cls.move1 = cls._create_move(
27
+ cls.picking_type_out, cls.product_out4, 1, cls.group1
28
+ )
29
+ cls.move2 = cls._create_move(
30
+ cls.picking_type_out, cls.product_out4, 1, cls.group2
31
+ )
32
+ cls.move3 = cls._create_move(
33
+ cls.picking_type_out, cls.product_out4, 1, cls.group3
34
+ )
35
+
36
+ def _filter_jobs(self, jobs, method_name):
37
+ return list(filter(lambda job: job.method_name == method_name, jobs))
38
+
39
+ def _asset_jobs_dependency(self, jobs):
40
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
41
+ unplan_job = self._filter_jobs(jobs, "_unplan_undone_moves")
42
+ postprocess_job = self._filter_jobs(jobs, "_postprocess_action_done")
43
+ self.assertSetEqual(postprocess_job[0].depends_on, set(unplan_job))
44
+ self.assertSetEqual(unplan_job[0].depends_on, set(picking_jobs))
45
+
46
+ def test_shipment_advice_incoming_done_full(self):
47
+ """Validating an incoming shipment validates automatically planned
48
+ transfers. Here the planned transfers have been fully received.
49
+ """
50
+ picking = self.move_product_in1.picking_id
51
+ self._plan_records_in_shipment(self.shipment_advice_in, picking)
52
+ self._in_progress_shipment_advice(self.shipment_advice_in)
53
+ for ml in picking.move_line_ids:
54
+ ml.qty_done = ml.reserved_uom_qty
55
+ picking._action_done()
56
+ with trap_jobs() as trap:
57
+ self.shipment_advice_in.action_done()
58
+ self.assertEqual(self.shipment_advice_in.state, "in_process")
59
+ trap.assert_jobs_count(2) # 0 picking + 1 for unplan + 1 for postprocess
60
+ jobs = trap.enqueued_jobs
61
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
62
+ self.assertEqual(len(picking_jobs), 0)
63
+ self._asset_jobs_dependency(jobs)
64
+ trap.perform_enqueued_jobs()
65
+ self.assertEqual(self.shipment_advice_in.state, "done")
66
+ self.assertTrue(
67
+ all(
68
+ move.state == "done"
69
+ for move in self.shipment_advice_in.planned_move_ids
70
+ )
71
+ )
72
+ self.assertEqual(picking.state, "done")
73
+
74
+ def test_shipment_advice_incoming_done_partial(self):
75
+ """Validating an incoming shipment validates automatically planned
76
+ transfers. Here the planned transfers have been partially received.
77
+ """
78
+ picking = self.move_product_in1.picking_id
79
+ # Plan a move
80
+ self._plan_records_in_shipment(self.shipment_advice_in, self.move_product_in1)
81
+ self._in_progress_shipment_advice(self.shipment_advice_in)
82
+ # Receive it (making its related transfer partially received)
83
+ for ml in self.move_product_in1.move_line_ids:
84
+ ml.qty_done = ml.reserved_uom_qty
85
+ self.assertEqual(picking, self.move_product_in2.picking_id)
86
+ # When validating the shipment, a backorder is created for unprocessed moves
87
+ with trap_jobs() as trap:
88
+ self.shipment_advice_in.action_done()
89
+ self.assertEqual(self.shipment_advice_in.state, "in_process")
90
+ trap.assert_jobs_count(3) # 1 picking + 1 for unplan + 1 for postprocess
91
+ jobs = trap.enqueued_jobs
92
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
93
+ self.assertEqual(len(picking_jobs), 1)
94
+ self._asset_jobs_dependency(jobs)
95
+ trap.perform_enqueued_jobs()
96
+ backorder = self.move_product_in2.picking_id
97
+ self.assertNotEqual(picking, backorder)
98
+ self.assertEqual(self.shipment_advice_in.state, "done")
99
+ self.assertEqual(self.move_product_in1.state, "done")
100
+ self.assertEqual(picking.state, "done")
101
+ self.assertEqual(backorder.state, "assigned")
102
+
103
+ def test_shipment_advice_done_full(self):
104
+ """Validating a shipment (whatever the backorder policy is) should
105
+ validate all fully loaded transfers.
106
+ """
107
+ pickings = self.move1.picking_id | self.move2.picking_id | self.move3.picking_id
108
+ self._in_progress_shipment_advice(self.shipment_advice_out)
109
+ self._load_records_in_shipment(self.shipment_advice_out, pickings)
110
+ with trap_jobs() as trap:
111
+ self.shipment_advice_out.action_done()
112
+ trap.assert_jobs_count(5) # 3 pickings + 1 for unplan + 1 for postprocess
113
+ jobs = trap.enqueued_jobs
114
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
115
+ self.assertEqual(len(picking_jobs), 3)
116
+ self._asset_jobs_dependency(jobs)
117
+ trap.perform_enqueued_jobs()
118
+ self.assertEqual(self.shipment_advice_out.state, "done")
119
+ self.assertTrue(
120
+ all(
121
+ move.state == "done"
122
+ for move in self.shipment_advice_out.loaded_move_line_ids
123
+ )
124
+ )
125
+ self.assertEqual(pickings.mapped("state"), ["done", "done", "done"])
126
+
127
+ def test_shipment_advice_done_backorder_policy_disabled(self):
128
+ """Validating a shipment with no backorder policy should let partial
129
+ transfers open.
130
+ """
131
+ # Disable the backorder policy
132
+ company = self.shipment_advice_out.company_id
133
+ company.shipment_advice_outgoing_backorder_policy = "leave_open"
134
+ # Load a transfer partially (here a package)
135
+ package_level = self.move_product_out2.move_line_ids.package_level_id
136
+ self._in_progress_shipment_advice(self.shipment_advice_out)
137
+ self._load_records_in_shipment(self.shipment_advice_out, package_level)
138
+ # Validate the shipment => the transfer is still open
139
+ with trap_jobs() as trap:
140
+ self.shipment_advice_out.action_done()
141
+ self.assertEqual(self.shipment_advice_out.state, "in_process")
142
+ trap.assert_jobs_count(3) # 1 picking + 1 for unplan + 1 for postprocess
143
+ jobs = trap.enqueued_jobs
144
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
145
+ self.assertEqual(len(picking_jobs), 1)
146
+ self._asset_jobs_dependency(jobs)
147
+ trap.perform_enqueued_jobs()
148
+ picking = package_level.picking_id
149
+ self.assertEqual(self.shipment_advice_out.state, "error")
150
+ # Check the transfer
151
+ self.assertTrue(
152
+ all(
153
+ move_line.state == "assigned"
154
+ for move_line in package_level.move_line_ids
155
+ )
156
+ )
157
+ self.assertEqual(picking.state, "assigned")
158
+
159
+ def test_shipment_advice_done_backorder_policy_enabled(self):
160
+ """Validating a shipment with the backorder policy enabled should
161
+ validate partial transfers and create a backorder.
162
+ """
163
+ # Enable the backorder policy
164
+ company = self.shipment_advice_out.company_id
165
+ company.shipment_advice_outgoing_backorder_policy = "create_backorder"
166
+ # Load a transfer partially (here a package)
167
+ package_level = self.move_product_out2.move_line_ids.package_level_id
168
+ self._in_progress_shipment_advice(self.shipment_advice_out)
169
+ self._load_records_in_shipment(self.shipment_advice_out, package_level)
170
+ self.assertEqual(package_level.picking_id, self.move_product_out1.picking_id)
171
+ # Validate the shipment => the transfer is validated, creating a backorder
172
+ with trap_jobs() as trap:
173
+ self.shipment_advice_out.action_done()
174
+ self.assertEqual(self.shipment_advice_out.state, "in_process")
175
+ trap.assert_jobs_count(3) # 1 picking + 1 for unplan + 1 for postprocess
176
+ jobs = trap.enqueued_jobs
177
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
178
+ self.assertEqual(len(picking_jobs), 1)
179
+ self._asset_jobs_dependency(jobs)
180
+ trap.perform_enqueued_jobs()
181
+ self.assertEqual(self.shipment_advice_out.state, "done")
182
+ # Check the transfer validated
183
+ picking = package_level.picking_id
184
+ self.assertTrue(
185
+ all(move_line.state == "done" for move_line in package_level.move_line_ids)
186
+ )
187
+ self.assertEqual(picking.state, "done")
188
+ # Check the backorder
189
+ picking2 = self.move_product_out1.picking_id
190
+ self.assertNotEqual(picking, picking2)
191
+ self.assertTrue(
192
+ all(move_line.state == "assigned" for move_line in picking2.move_line_ids)
193
+ )
194
+ self.assertEqual(picking2.state, "assigned")
195
+
196
+ def test_shipment_advice_error(self):
197
+ """
198
+ provoke and error in one picking during validation, expected:
199
+ - only the picking with the error remains assigned
200
+ - the shipment advice moves to the "error" state
201
+ """
202
+ pickings = self.move1.picking_id | self.move2.picking_id | self.move3.picking_id
203
+ self._in_progress_shipment_advice(self.shipment_advice_out)
204
+ self._load_records_in_shipment(self.shipment_advice_out, pickings)
205
+ # provoke validation error by setting internal package as destination
206
+ pickings[0].move_line_ids.result_package_id = self.package
207
+ with trap_jobs() as trap:
208
+ self.shipment_advice_out.action_done()
209
+ self.assertEqual(self.shipment_advice_out.state, "in_process")
210
+ trap.assert_jobs_count(5) # 3 pickings + 1 for unplan + 1 for postprocess
211
+ jobs = trap.enqueued_jobs
212
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
213
+ self.assertEqual(len(picking_jobs), 3)
214
+ self._asset_jobs_dependency(jobs)
215
+ trap.perform_enqueued_jobs()
216
+ self.assertEqual(self.shipment_advice_out.state, "error")
217
+ self.assertIn(
218
+ "You cannot move the same package content more than once",
219
+ self.shipment_advice_out.error_message,
220
+ )
221
+ self.assertEqual(pickings[0].state, "assigned")
222
+ self.assertEqual(pickings[1].state, "done")
223
+ self.assertEqual(pickings[2].state, "done")
224
+ return pickings[0]
225
+
226
+ def test_shipment_advice_error_fix_and_retry(self):
227
+ """
228
+ fix the picking error and retry
229
+ - picking state = done
230
+ - SA state = done
231
+ """
232
+ picking = self.test_shipment_advice_error()
233
+ picking.move_line_ids.result_package_id = False
234
+ with trap_jobs() as trap:
235
+ self.shipment_advice_out.action_done()
236
+ self.assertEqual(self.shipment_advice_out.state, "in_process")
237
+ trap.assert_jobs_count(
238
+ 3
239
+ ) # 1 picking remaining + 1 for unplan + 1 for postprocess
240
+ jobs = trap.enqueued_jobs
241
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
242
+ self.assertEqual(len(picking_jobs), 1)
243
+ self._asset_jobs_dependency(jobs)
244
+ trap.perform_enqueued_jobs()
245
+ self.assertEqual(self.shipment_advice_out.state, "done")
246
+ self.assertFalse(self.shipment_advice_out.error_message)
247
+ self.assertEqual(picking.state, "done")
248
+
249
+ def test_shipment_advice_error_unload_and_retry(self):
250
+ """
251
+ unload the picking and retry
252
+ - picking state = assigned
253
+ - SA state = done
254
+ """
255
+ picking = self.test_shipment_advice_error()
256
+ picking._unload_from_shipment()
257
+ with trap_jobs() as trap:
258
+ self.shipment_advice_out.action_done()
259
+ self.assertEqual(self.shipment_advice_out.state, "in_process")
260
+ trap.assert_jobs_count(
261
+ 2
262
+ ) # 0 picking remaining + 1 for unplan + 1 for postprocess
263
+ jobs = trap.enqueued_jobs
264
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
265
+ self.assertEqual(len(picking_jobs), 0)
266
+ self._asset_jobs_dependency(jobs)
267
+ trap.perform_enqueued_jobs()
268
+ self.assertEqual(self.shipment_advice_out.state, "done")
269
+ self.assertFalse(self.shipment_advice_out.error_message)
270
+ self.assertEqual(picking.state, "assigned")
271
+
272
+ def test_shipment_advice_done_unplan_undone(self):
273
+ """check that undone move are unplaned after validation"""
274
+ # Enable the backorder policy
275
+ company = self.shipment_advice_out.company_id
276
+ company.shipment_advice_outgoing_backorder_policy = "create_backorder"
277
+ # Load a transfer partially (here a package)
278
+ package_level = self.move_product_out2.move_line_ids.package_level_id
279
+ picking = package_level.picking_id
280
+ self._in_progress_shipment_advice(self.shipment_advice_out)
281
+ self._plan_records_in_shipment(self.shipment_advice_out, picking)
282
+ self.assertEqual(len(self.shipment_advice_out.planned_move_ids), 3)
283
+ self._load_records_in_shipment(self.shipment_advice_out, package_level)
284
+ self.assertEqual(len(package_level.move_line_ids.move_id), 2)
285
+ # Validate the shipment => the transfer is validated, creating a backorder
286
+ with trap_jobs() as trap:
287
+ self.shipment_advice_out.action_done()
288
+ self.assertEqual(self.shipment_advice_out.state, "in_process")
289
+ trap.assert_jobs_count(3) # 1 picking + 1 for unplan + 1 for postprocess
290
+ jobs = trap.enqueued_jobs
291
+ picking_jobs = self._filter_jobs(jobs, "_validate_picking")
292
+ self.assertEqual(len(picking_jobs), 1)
293
+ self._asset_jobs_dependency(jobs)
294
+ trap.perform_enqueued_jobs()
295
+ self.assertEqual(self.shipment_advice_out.state, "done")
296
+ self.assertEqual(picking.state, "done")
297
+ self.assertEqual(len(self.shipment_advice_out.planned_move_ids), 2)
298
+ self.assertTrue(picking.backorder_ids)
299
+ self.assertFalse(picking.backorder_ids.move_ids.shipment_advice_id)
@@ -27,6 +27,23 @@
27
27
  <field name="shipment_advice_outgoing_backorder_policy" />
28
28
  </div>
29
29
  </div>
30
+ <div
31
+ class="col-12 col-lg-6 o_setting_box"
32
+ id="shipment_advice_run_in_queue_job"
33
+ title="shipment_advice_run_in_queue_job"
34
+ >
35
+ <div class="o_setting_left_pane">
36
+ <field name="shipment_advice_run_in_queue_job" />
37
+ </div>
38
+ <div class="o_setting_right_pane">
39
+ <label for="shipment_advice_run_in_queue_job" />
40
+ <div class="text-muted">
41
+ To prevent timeouts for large shipments, enable this option to execute
42
+ shipment advice validation through a queued job. Each picking will be
43
+ validated in a separate jobs.
44
+ </div>
45
+ </div>
46
+ </div>
30
47
  </xpath>
31
48
  </field>
32
49
  </record>
@@ -44,7 +44,7 @@
44
44
  type="object"
45
45
  string="Mark as done"
46
46
  class="btn-primary"
47
- states="in_progress"
47
+ states="in_progress,error"
48
48
  />
49
49
  <button
50
50
  name="action_cancel"
@@ -66,6 +66,13 @@
66
66
  statusbar_visible="draft,confirmed,in_progress,done"
67
67
  />
68
68
  </header>
69
+ <div
70
+ class="alert alert-danger mb-0"
71
+ role="alert"
72
+ attrs="{'invisible': [('state', '!=', 'error')]}"
73
+ >
74
+ <field name="error_message" />
75
+ </div>
69
76
  <sheet>
70
77
  <div class="oe_button_box" name="button_box">
71
78
  <button
@@ -23,7 +23,7 @@ class WizardLoadInShipment(models.TransientModel):
23
23
  comodel_name="shipment.advice",
24
24
  string="Shipment Advice",
25
25
  required=True,
26
- domain=[("state", "in", ("confirm", "in_progress"))],
26
+ domain=[("state", "in", ("confirm", "in_progress", "error"))],
27
27
  )
28
28
  warning = fields.Char(readonly=True)
29
29
  open_shipment = fields.Boolean(default=True)
@@ -21,7 +21,7 @@ class WizardPlanShipment(models.TransientModel):
21
21
  comodel_name="shipment.advice",
22
22
  string="Shipment Advice",
23
23
  required=True,
24
- domain=[("state", "in", ("draft", "confirmed"))],
24
+ domain=[("state", "in", ("draft", "confirmed", "error"))],
25
25
  )
26
26
  warning = fields.Char(readonly=True)
27
27
 
@@ -43,7 +43,7 @@ class WizardUnloadShipment(models.TransientModel):
43
43
  o.state not in ["cancel", "done"]
44
44
  and o.move_line_ids.shipment_advice_id
45
45
  and all(
46
- state == "in_progress"
46
+ state in ("in_progress", "error")
47
47
  for state in o.move_line_ids.shipment_advice_id.mapped("state")
48
48
  )
49
49
  and o.picking_type_code == "outgoing"
@@ -71,7 +71,7 @@ class WizardUnloadShipment(models.TransientModel):
71
71
  o.state not in ["cancel", "done"]
72
72
  and o.shipment_advice_id
73
73
  and all(
74
- state == "in_progress"
74
+ state in ("in_progress", "error")
75
75
  for state in o.shipment_advice_id.mapped("state")
76
76
  )
77
77
  and o.picking_code == "outgoing"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: odoo-addon-shipment-advice
3
- Version: 16.0.1.3.1.9
3
+ Version: 16.0.1.4.0
4
4
  Summary: Manage your (un)loading process through shipment advices.
5
5
  Home-page: https://github.com/OCA/stock-logistics-transport
6
6
  Author: Camptocamp, Odoo Community Association (OCA)
@@ -12,6 +12,7 @@ Classifier: Framework :: Odoo
12
12
  Classifier: Framework :: Odoo :: 16.0
13
13
  Classifier: License :: OSI Approved :: GNU Affero General Public License v3
14
14
  Requires-Python: >=3.10
15
+ Requires-Dist: odoo-addon-queue-job <16.1dev,>=16.0dev
15
16
  Requires-Dist: odoo-addon-stock-dock <16.1dev,>=16.0dev
16
17
  Requires-Dist: odoo <16.1dev,>=16.0a
17
18
 
@@ -24,7 +25,7 @@ Shipment Advice
24
25
  !! This file is generated by oca-gen-addon-readme !!
25
26
  !! changes will be overwritten. !!
26
27
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
27
- !! source digest: sha256:2ce9096e86385f60cb183efb0745bb01324df6f1dee67604801fd7b364a0a68e
28
+ !! source digest: sha256:d15a08534108c95673383be523fd4d221150eb3270f749dad244c6f2504036b0
28
29
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
29
30
 
30
31
  .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -1,16 +1,18 @@
1
- odoo/addons/shipment_advice/README.rst,sha256=BrmiZd-cCFddOPb2CurV6RMctjn4cfc3opLt6Ywwme0,3389
1
+ odoo/addons/shipment_advice/README.rst,sha256=SrNDE5dixKCsVxGc7K7879jdgNLd4IyD69BRGDQqO48,3389
2
2
  odoo/addons/shipment_advice/__init__.py,sha256=0XNpxETgFdVxFDEw03O8oL3NtTSk3we-HEZW2sPKzIU,43
3
- odoo/addons/shipment_advice/__manifest__.py,sha256=YGEV67iBKPIFQSlS55KjNfA63lRh8dR_P9-MgznLn58,1183
3
+ odoo/addons/shipment_advice/__manifest__.py,sha256=cgkG4DQ-rPU7rE8Y5MxuGV9kGm2zLWHfqtcLBqaV3Ls,1301
4
4
  odoo/addons/shipment_advice/data/ir_sequence.xml,sha256=7y13W1xPr3o_deB6s5a_UHSJGMpFGCA8JTc7xI5L0-c,1066
5
+ odoo/addons/shipment_advice/data/queue_job_channel.xml,sha256=wZSQNo7aAknlMpTC-mxXRvYf0rXSF53B3hI7NXwKciA,350
6
+ odoo/addons/shipment_advice/data/queue_job_function.xml,sha256=cEy-z8znwYUB8GDNjouWgwS-Rbfn1zl7nbpLvdXRD_U,1151
5
7
  odoo/addons/shipment_advice/demo/stock_dock.xml,sha256=hhwcQa6JGbN-oQYrkrrgPmH1hbH1p7YEGuKZY9NGMT0,267
6
8
  odoo/addons/shipment_advice/i18n/es.po,sha256=L9-rSMTZU4I6lIYNZprstkKj9OMEPkLkWwLWwH5JXZk,53968
7
9
  odoo/addons/shipment_advice/i18n/fr.po,sha256=5DWTGpIE9t7WO6UmJDhqB5B0UYGc_JIbkyTtIoDWyts,51769
8
10
  odoo/addons/shipment_advice/i18n/it.po,sha256=jmudGd9YB1IosMPPdtJSmkMlkkk57RYEdP2z9Etn01U,54007
9
- odoo/addons/shipment_advice/i18n/shipment_advice.pot,sha256=i-nNFo79lMrJoc0w-sndUTXMvckQOJ21ILGXTWzFsKM,44388
11
+ odoo/addons/shipment_advice/i18n/shipment_advice.pot,sha256=Ma-3-gawjjh351lMLluIVm8fgPlkiTPlr4lEeV2bsiE,46879
10
12
  odoo/addons/shipment_advice/models/__init__.py,sha256=kvmDs7RDo8Tnvv0w_2GcxgVcw9nATFSixZ1tFlVNNz8,207
11
- odoo/addons/shipment_advice/models/res_company.py,sha256=EmsRYcCMQmKH4lFp1TN2jjyEubDjgubz5nVDCURA4CU,955
12
- odoo/addons/shipment_advice/models/res_config_settings.py,sha256=UIQqSIOH8CsbkLNdciKBusy21pDLVMIakK0E5oZ4euE,374
13
- odoo/addons/shipment_advice/models/shipment_advice.py,sha256=qoEN2LHyNK3o0SH9eLFVaEzzkT0BleKUD3822LcQTH8,18101
13
+ odoo/addons/shipment_advice/models/res_company.py,sha256=fXtG4UK67RJNoRRXsdL3el5hxsGBLx_lqUKaylg6LEs,1276
14
+ odoo/addons/shipment_advice/models/res_config_settings.py,sha256=XsOdwRyr3_L07kEoabJN2InBQ6aVXSq0qHtTn-OG8r8,513
15
+ odoo/addons/shipment_advice/models/shipment_advice.py,sha256=hBWF8yUSlvuXjnDcf6raoe1a0ah--ICisBWowLI5FV4,20049
14
16
  odoo/addons/shipment_advice/models/stock_move.py,sha256=76z93nLjxFO3et79ogYALXsZadBBz-wqnpwENyDPtbY,543
15
17
  odoo/addons/shipment_advice/models/stock_move_line.py,sha256=gkGBrDFJ1BZC8uY9wwwFSuk_xw__HdRTW2DTGk2WdxI,5378
16
18
  odoo/addons/shipment_advice/models/stock_package_level.py,sha256=0_S4KRBy02kkmBu5Pbcw6g-etJtATveTZh42Srz1R_o,1431
@@ -22,30 +24,31 @@ odoo/addons/shipment_advice/report/report_shipment_advice.xml,sha256=hKMUP7iuRLp
22
24
  odoo/addons/shipment_advice/report/reports.xml,sha256=8LeKVB1M0a4gsLyrwd68RMnxoUw0xCYIn2KN4jlCuLA,1523
23
25
  odoo/addons/shipment_advice/security/ir.model.access.csv,sha256=FeiNV6yP6OOOwJw2MHyo1B3TQQ-umOz75A7QAlCTPZs,657
24
26
  odoo/addons/shipment_advice/static/description/icon.png,sha256=6xBPJauaFOF0KDHfHgQopSc28kKvxMaeoQFQWZtfZDo,9455
25
- odoo/addons/shipment_advice/static/description/index.html,sha256=o2LRPs-5TFsVTXbumE4RTvY8FWZVL5Yi3FuUBmgZjlQ,13567
26
- odoo/addons/shipment_advice/tests/__init__.py,sha256=vME_yg018HaqWuRVwvoMrhS_9DzgRw6uMtIXr3_E8sA,203
27
+ odoo/addons/shipment_advice/static/description/index.html,sha256=jIoAIcM9GXjdIpAuxf5Pe8bbZbmstGXSxKWW2e_qXbM,13567
28
+ odoo/addons/shipment_advice/tests/__init__.py,sha256=NAs_27I19CYFy1t_xuuUDGuuyd0hoa7q1uHRydzdgRY,244
27
29
  odoo/addons/shipment_advice/tests/common.py,sha256=ry1jywQT7E5Rim0l732BRyEIfxBm0fvNH5XKQGFkVNg,7132
28
- odoo/addons/shipment_advice/tests/test_shipment_advice.py,sha256=DdR5zjKXT-USFJHoyOUrBzsfoDo-popPPYd2NVELkts,7539
30
+ odoo/addons/shipment_advice/tests/test_shipment_advice.py,sha256=GO7AV4O2Js8cZ9a7EmZY5-4n1uMWF6zhQwORZxsj5YY,7540
31
+ odoo/addons/shipment_advice/tests/test_shipment_advice_async.py,sha256=Ulc9fH4PfKV_uuvjGiHSZ5Bg2z9ph6TsewyAD4zViLA,14506
29
32
  odoo/addons/shipment_advice/tests/test_shipment_advice_load.py,sha256=DUvZ_yBJRj75XPaLecibA1vp-k7TPaUFYMF4XxXM1wc,8093
30
33
  odoo/addons/shipment_advice/tests/test_shipment_advice_plan.py,sha256=7hUY4RRYi8-6_ovmYFA7DH85KP_kfy1J3O14beKG0hk,1550
31
34
  odoo/addons/shipment_advice/tests/test_shipment_advice_stock_user.py,sha256=7fd0AqX-OrCQH2zGB4L2SO4UUzjcSgzxHOdhmsWgDLw,4334
32
35
  odoo/addons/shipment_advice/tests/test_shipment_advice_unload.py,sha256=2BEJUEVSsh1MW_ke8-LK4vLsi7Sb3Ijs0T794yQdwdE,2727
33
- odoo/addons/shipment_advice/views/res_config_settings.xml,sha256=yiDEGsmNwzIplFaQZbl_tO3msN1yq_DGzFrZwozZfzI,1617
34
- odoo/addons/shipment_advice/views/shipment_advice.xml,sha256=UmgsjBZuD6a4pYbfdZMokI_DehGivOrGsbaK7YzzvLI,16445
36
+ odoo/addons/shipment_advice/views/res_config_settings.xml,sha256=KTNRG9hBnkeJGTjVpF3Bs4ScU512TaPwTSFh6yQjFmU,2501
37
+ odoo/addons/shipment_advice/views/shipment_advice.xml,sha256=ME_BnA3sIgpbxKSHDDI_-tO8NFLgUHyd-nvMCBtyZjE,16723
35
38
  odoo/addons/shipment_advice/views/stock_move.xml,sha256=sQNoEgFOYNT4lUc4GRhDO9xWznjk-pPJqPVfzKoClnI,2275
36
39
  odoo/addons/shipment_advice/views/stock_move_line.xml,sha256=RJ-MCrapTt2uRhxHnEm7KFJmgz_ecQtsaHk_ah9RMos,3250
37
40
  odoo/addons/shipment_advice/views/stock_package_level.xml,sha256=0smz8ZWu9p6GsFn5Px3fSmFUZJgPif8wUJQBR1GFJoc,2171
38
41
  odoo/addons/shipment_advice/views/stock_picking.xml,sha256=R0TLnr9SE3s9-cN6KgIllvJSAMxFOGdeVQo3m5Vkgg4,8005
39
42
  odoo/addons/shipment_advice/wizards/__init__.py,sha256=PWEljvfDbqYr3SrKAVpmaE25XvKFjuW2NCACSkyQzao,116
40
- odoo/addons/shipment_advice/wizards/load_shipment.py,sha256=X8OR4OwUA7L3OVGRyk5LRAbQsCFlMCtKHzGx7EbXz70,8532
43
+ odoo/addons/shipment_advice/wizards/load_shipment.py,sha256=eeoDAaYBDE94ZFb1NGcJhwAiW73zizUHbS5jvd7WK6w,8541
41
44
  odoo/addons/shipment_advice/wizards/load_shipment.xml,sha256=1kb49KAO08qWmYYGyskFojDvuUO11EuLMCK-XRpMx54,2734
42
- odoo/addons/shipment_advice/wizards/plan_shipment.py,sha256=H8TTNJwD9cUYy94XyiTrhBFqZ107ma7RRvlFwcIhop0,5748
45
+ odoo/addons/shipment_advice/wizards/plan_shipment.py,sha256=0POoULPKe8tkxvgsOUvR8Z5EwF3JpkU3veK3aPt7j9c,5757
43
46
  odoo/addons/shipment_advice/wizards/plan_shipment.xml,sha256=OrTpEZmSr8fqDppzTarkIJrWtBDNDmckpJiHtbzYVHo,2276
44
- odoo/addons/shipment_advice/wizards/unload_shipment.py,sha256=pYtnfooSzLsbaEhkb353hpoGFEvfYK3-QmWarW6TGGI,3712
47
+ odoo/addons/shipment_advice/wizards/unload_shipment.py,sha256=J0GtSHeykr5YsJH48at1CqOdBoyoZPdxfhtezY28g7g,3734
45
48
  odoo/addons/shipment_advice/wizards/unload_shipment.xml,sha256=xYL7hKrlH11PfRPOV9uTGDeafSA7KlmZbm5AZ8icqyQ,1562
46
49
  odoo/addons/shipment_advice/wizards/unplan_shipment.py,sha256=zdzK3vRbZW0eY3iw9eOGxXhs5YDTjZhT9JBSyRoqqoM,4163
47
50
  odoo/addons/shipment_advice/wizards/unplan_shipment.xml,sha256=KX4lF5O-HOwcylK3odlqfQd-TDvQLTYtfsxptinIsIQ,1832
48
- odoo_addon_shipment_advice-16.0.1.3.1.9.dist-info/METADATA,sha256=yPpKocf4Ldcq1YtqLms1tHId1FtrqorqcX2zhX7cELI,4028
49
- odoo_addon_shipment_advice-16.0.1.3.1.9.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
50
- odoo_addon_shipment_advice-16.0.1.3.1.9.dist-info/top_level.txt,sha256=qBj40grFkGOfDZ2WDSw3y1RnDlgG0u8rP8pvGNdbz4w,5
51
- odoo_addon_shipment_advice-16.0.1.3.1.9.dist-info/RECORD,,
51
+ odoo_addon_shipment_advice-16.0.1.4.0.dist-info/METADATA,sha256=RnqJGnXd0f1ZHUgUMAUd-DWaXAh3cFcilx6s5bhHC5E,4081
52
+ odoo_addon_shipment_advice-16.0.1.4.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
53
+ odoo_addon_shipment_advice-16.0.1.4.0.dist-info/top_level.txt,sha256=qBj40grFkGOfDZ2WDSw3y1RnDlgG0u8rP8pvGNdbz4w,5
54
+ odoo_addon_shipment_advice-16.0.1.4.0.dist-info/RECORD,,