odoo-addon-rma 17.0.1.1.1__py3-none-any.whl → 17.0.2.0.0.1__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.
@@ -1,4 +1,5 @@
1
1
  # Copyright 2020 Tecnativa - Ernesto Tejeda
2
+ # Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
2
3
  # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3
4
 
4
5
  from odoo import _, api, fields, models
@@ -23,7 +24,7 @@ class StockMove(models.Model):
23
24
  string="RMA receivers",
24
25
  copy=False,
25
26
  )
26
- # RMA that create the delivery movement to the customer
27
+ # RMA that creates the out move
27
28
  rma_id = fields.Many2one(
28
29
  comodel_name="rma",
29
30
  string="RMA return",
@@ -33,8 +34,8 @@ class StockMove(models.Model):
33
34
  def unlink(self):
34
35
  # A stock user could have no RMA permissions, so the ids wouldn't
35
36
  # be accessible due to record rules.
36
- rma_receiver = self.sudo().mapped("rma_receiver_ids")
37
- rma = self.sudo().mapped("rma_id")
37
+ rma_receiver = self.sudo().rma_receiver_ids
38
+ rma = self.sudo().rma_id
38
39
  res = super().unlink()
39
40
  rma_receiver.filtered(lambda x: x.state != "cancelled").write(
40
41
  {"state": "draft"}
@@ -115,38 +116,22 @@ class StockMove(models.Model):
115
116
  res["rma_id"] = self.sudo().rma_id.id
116
117
  return res
117
118
 
118
- def _prepare_return_rma_vals(self, original_picking):
119
- """hook method for preparing an RMA from the 'return picking wizard'."""
120
- self.ensure_one()
121
- partner = original_picking.partner_id
122
- if hasattr(original_picking, "sale_id") and original_picking.sale_id:
123
- partner_invoice_id = original_picking.sale_id.partner_invoice_id.id
124
- partner_shipping_id = original_picking.sale_id.partner_shipping_id.id
125
- else:
126
- partner_invoice_id = partner.address_get(["invoice"]).get("invoice", False)
127
- partner_shipping_id = partner.address_get(["delivery"]).get(
128
- "delivery", False
129
- )
130
- return {
131
- "user_id": self.env.user.id,
132
- "partner_id": partner.id,
133
- "partner_shipping_id": partner_shipping_id,
134
- "partner_invoice_id": partner_invoice_id,
135
- "origin": original_picking.name,
136
- "picking_id": original_picking.id,
137
- "move_id": self.origin_returned_move_id.id,
138
- "product_id": self.origin_returned_move_id.product_id.id,
139
- "product_uom_qty": self.product_uom_qty,
140
- "product_uom": self.product_uom.id,
141
- "reception_move_id": self.id,
142
- "company_id": self.company_id.id,
143
- "location_id": self.location_dest_id.id,
144
- "state": "confirmed",
145
- }
119
+ def _prepare_procurement_values(self):
120
+ res = super()._prepare_procurement_values()
121
+ if self.rma_id:
122
+ res["rma_id"] = self.rma_id.id
123
+ return res
146
124
 
147
125
 
148
126
  class StockRule(models.Model):
149
127
  _inherit = "stock.rule"
150
128
 
151
129
  def _get_custom_move_fields(self):
152
- return super()._get_custom_move_fields() + ["rma_id"]
130
+ move_fields = super()._get_custom_move_fields()
131
+ move_fields += [
132
+ "rma_id",
133
+ "origin_returned_move_id",
134
+ "move_orig_ids",
135
+ "rma_receiver_ids",
136
+ ]
137
+ return move_fields
@@ -1,7 +1,8 @@
1
1
  # Copyright 2020 Tecnativa - Ernesto Tejeda
2
+ # Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
2
3
  # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3
4
 
4
- from odoo import _, api, fields, models
5
+ from odoo import _, fields, models
5
6
 
6
7
 
7
8
  class StockWarehouse(models.Model):
@@ -27,35 +28,39 @@ class StockWarehouse(models.Model):
27
28
  comodel_name="stock.location",
28
29
  string="RMA Location",
29
30
  )
31
+ rma_in_route_id = fields.Many2one("stock.route", "RMA in Route")
32
+ rma_out_route_id = fields.Many2one("stock.route", "RMA out Route")
30
33
 
31
- @api.model_create_multi
32
- def create(self, vals_list):
33
- """To create an RMA location and link it with a new warehouse,
34
- this method is overridden instead of '_get_locations_values'
35
- method because the locations that are created with the
36
- values ​​returned by that method are forced to be children
37
- of view_location_id, and we don't want that.
38
- """
39
- res = super().create(vals_list)
40
- stock_location = self.env["stock.location"]
41
- for record in res:
42
- rma_location_vals = record._get_rma_location_values()
43
- record.rma_loc_id = stock_location.create(rma_location_vals).id
44
- return res
45
-
46
- def _get_rma_location_values(self):
34
+ def _get_rma_location_values(self, vals, code=False):
47
35
  """this method is intended to be used by 'create' method
48
36
  to create a new RMA location to be linked to a new warehouse.
49
37
  """
38
+ company_id = vals.get(
39
+ "company_id", self.default_get(["company_id"])["company_id"]
40
+ )
41
+ code = vals.get("code") or code or ""
42
+ code = code.replace(" ", "").upper()
43
+ view_location_id = vals.get("view_location_id")
44
+ view_location = (
45
+ view_location_id
46
+ and self.view_location_id.browse(view_location_id)
47
+ or self.view_location_id
48
+ )
50
49
  return {
51
- "name": self.view_location_id.name,
50
+ "name": view_location.name,
52
51
  "active": True,
53
52
  "return_location": True,
54
53
  "usage": "internal",
55
- "company_id": self.company_id.id,
54
+ "company_id": company_id,
56
55
  "location_id": self.env.ref("rma.stock_location_rma").id,
56
+ "barcode": self._valid_barcode(code + "-RMA", company_id),
57
57
  }
58
58
 
59
+ def _get_locations_values(self, vals, code=False):
60
+ res = super()._get_locations_values(vals, code)
61
+ res["rma_loc_id"] = self._get_rma_location_values(vals, code)
62
+ return res
63
+
59
64
  def _get_sequence_values(self, name=False, code=False):
60
65
  values = super()._get_sequence_values(name=name, code=code)
61
66
  values.update(
@@ -77,12 +82,14 @@ class StockWarehouse(models.Model):
77
82
  return values
78
83
 
79
84
  def _update_name_and_code(self, new_name=False, new_code=False):
85
+ res = super()._update_name_and_code(new_name, new_code)
80
86
  for warehouse in self:
81
87
  sequence_data = warehouse._get_sequence_values()
82
88
  warehouse.rma_in_type_id.sequence_id.write(sequence_data["rma_in_type_id"])
83
89
  warehouse.rma_out_type_id.sequence_id.write(
84
90
  sequence_data["rma_out_type_id"]
85
91
  )
92
+ return res
86
93
 
87
94
  def _get_picking_type_create_values(self, max_sequence):
88
95
  data, next_sequence = super()._get_picking_type_create_values(max_sequence)
@@ -116,12 +123,13 @@ class StockWarehouse(models.Model):
116
123
 
117
124
  def _get_picking_type_update_values(self):
118
125
  data = super()._get_picking_type_update_values()
119
- data.update(
120
- {
121
- "rma_in_type_id": {"default_location_dest_id": self.rma_loc_id.id},
122
- "rma_out_type_id": {"default_location_src_id": self.rma_loc_id.id},
123
- }
124
- )
126
+ picking_types = {
127
+ "rma_in_type_id": {"default_location_dest_id": self.rma_loc_id.id},
128
+ "rma_out_type_id": {"default_location_src_id": self.rma_loc_id.id},
129
+ }
130
+ if self.env.context.get("rma_post_init_hook"):
131
+ return picking_types
132
+ data.update(picking_types)
125
133
  return data
126
134
 
127
135
  def _create_or_update_sequences_and_picking_types(self):
@@ -138,3 +146,70 @@ class StockWarehouse(models.Model):
138
146
  {"return_picking_type_id": data.get("rma_out_type_id", False)}
139
147
  )
140
148
  return data
149
+
150
+ def _get_routes_values(self):
151
+ res = super()._get_routes_values()
152
+ rma_routes = {
153
+ "rma_in_route_id": {
154
+ "routing_key": "rma_in",
155
+ "depends": ["active"],
156
+ "route_update_values": {
157
+ "name": self._format_routename("RMA In"),
158
+ "active": self.active,
159
+ },
160
+ "route_create_values": {
161
+ "warehouse_selectable": True,
162
+ "company_id": self.company_id.id,
163
+ "sequence": 100,
164
+ },
165
+ "rules_values": {
166
+ "active": True,
167
+ },
168
+ },
169
+ "rma_out_route_id": {
170
+ "routing_key": "rma_out",
171
+ "depends": ["active"],
172
+ "route_update_values": {
173
+ "name": self._format_routename("RMA Out"),
174
+ "active": self.active,
175
+ },
176
+ "route_create_values": {
177
+ "warehouse_selectable": True,
178
+ "company_id": self.company_id.id,
179
+ "sequence": 110,
180
+ },
181
+ "rules_values": {
182
+ "active": True,
183
+ },
184
+ },
185
+ }
186
+ if self.env.context.get("rma_post_init_hook"):
187
+ return rma_routes
188
+ res.update(rma_routes)
189
+ return res
190
+
191
+ def get_rules_dict(self):
192
+ res = super().get_rules_dict()
193
+ customer_loc, supplier_loc = self._get_partner_locations()
194
+ for warehouse in self:
195
+ res[warehouse.id].update(
196
+ {
197
+ "rma_in": [
198
+ self.Routing(
199
+ customer_loc,
200
+ warehouse.rma_loc_id,
201
+ warehouse.rma_in_type_id,
202
+ "pull",
203
+ )
204
+ ],
205
+ "rma_out": [
206
+ self.Routing(
207
+ warehouse.rma_loc_id,
208
+ customer_loc,
209
+ warehouse.rma_out_type_id,
210
+ "pull",
211
+ )
212
+ ],
213
+ }
214
+ )
215
+ return res
@@ -7,3 +7,4 @@
7
7
  - Giovanni Serra - Ooops \<<giovanni@ooops404.com>\>
8
8
  - [APSL-Nagarro](https://www.apsl.tech):
9
9
  - Antoni Marroig \<<amarroig@apsl.net>\>
10
+ - Michael Tietz (MT Software) <mtietz@mt-software.de>
@@ -1,3 +1,6 @@
1
1
  - As soon as the picking is selected, the user should select the move,
2
2
  but perhaps stock.move \_rec_name could be improved to better show
3
3
  what the product of that move is.
4
+ - Add RMA reception and/or RMA delivery on several steps - 2 or 3 - like
5
+ normal receptions/deliveries. It should be a separate option inside the
6
+ warehouse definition.
@@ -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:ed3081bf9b94660a0e6b35acbc7a874023c57e4bc3a87f3762eabbb1c75ce2f4
369
+ !! source digest: sha256:8f36869aece97a0f6af8aa5d76b446e9cf0bd589d914c1f5e12c628e87317021
370
370
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
371
371
  <p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.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/rma/tree/17.0/rma"><img alt="OCA/rma" src="https://img.shields.io/badge/github-OCA%2Frma-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/rma-17-0/rma-17-0-rma"><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/rma&amp;target_branch=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
372
372
  <p>This module allows you to manage <a class="reference external" href="https://en.wikipedia.org/wiki/Return_merchandise_authorization">Return Merchandise Authorization
@@ -493,6 +493,9 @@ team will be the default one if no team is set.</li>
493
493
  <li>As soon as the picking is selected, the user should select the move,
494
494
  but perhaps stock.move _rec_name could be improved to better show
495
495
  what the product of that move is.</li>
496
+ <li>Add RMA reception and/or RMA delivery on several steps - 2 or 3 -
497
+ like normal receptions/deliveries. It should be a separate option
498
+ inside the warehouse definition.</li>
496
499
  </ul>
497
500
  </div>
498
501
  <div class="section" id="bug-tracker">
@@ -527,6 +530,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
527
530
  <li>Antoni Marroig &lt;<a class="reference external" href="mailto:amarroig&#64;apsl.net">amarroig&#64;apsl.net</a>&gt;</li>
528
531
  </ul>
529
532
  </li>
533
+ <li>Michael Tietz (MT Software) <a class="reference external" href="mailto:mtietz&#64;mt-software.de">mtietz&#64;mt-software.de</a></li>
530
534
  </ul>
531
535
  </div>
532
536
  <div class="section" id="maintainers">
@@ -1,24 +1,20 @@
1
1
  # Copyright 2020 Tecnativa - Ernesto Tejeda
2
+ # Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
2
3
  # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3
4
 
4
5
  from odoo.exceptions import UserError, ValidationError
5
- from odoo.tests import Form, TransactionCase, new_test_user, users
6
+ from odoo.tests import Form, new_test_user, users
7
+ from odoo.tools import mute_logger
6
8
 
9
+ from odoo.addons.base.tests.common import BaseCommon
7
10
 
8
- class TestRma(TransactionCase):
11
+ from .. import hooks
12
+
13
+
14
+ class TestRma(BaseCommon):
9
15
  @classmethod
10
16
  def setUpClass(cls):
11
17
  super().setUpClass()
12
- cls.env = cls.env(
13
- context=dict(
14
- cls.env.context,
15
- mail_create_nolog=True,
16
- mail_create_nosubscribe=True,
17
- mail_notrack=True,
18
- no_reset_password=True,
19
- tracking_disable=True,
20
- )
21
- )
22
18
  cls.user_rma = new_test_user(
23
19
  cls.env,
24
20
  login="user_rma",
@@ -72,6 +68,7 @@ class TestRma(TransactionCase):
72
68
  {"name": "[Test] It's out of warranty. To be scrapped"}
73
69
  )
74
70
  cls.env.ref("rma.group_rma_manual_finalization").users |= cls.env.user
71
+ cls.warehouse = cls.env.ref("stock.warehouse0")
75
72
  # Ensure grouping
76
73
  cls.env.company.rma_return_grouping = True
77
74
 
@@ -95,7 +92,7 @@ class TestRma(TransactionCase):
95
92
  rma = self._create_rma(partner, product, qty, location)
96
93
  rma.action_confirm()
97
94
  rma.reception_move_id.quantity = rma.product_uom_qty
98
- rma.reception_move_id.picking_id._action_done()
95
+ rma.reception_move_id.picking_id.button_validate()
99
96
  return rma
100
97
 
101
98
  def _create_delivery(self):
@@ -132,6 +129,49 @@ class TestRma(TransactionCase):
132
129
 
133
130
 
134
131
  class TestRmaCase(TestRma):
132
+ def test_post_init_hook(self):
133
+ warehouse = self.env["stock.warehouse"].create(
134
+ {
135
+ "name": "Test warehouse",
136
+ "code": "code",
137
+ "company_id": self.env.company.id,
138
+ }
139
+ )
140
+ hooks.post_init_hook(self.env)
141
+ self.assertTrue(warehouse.rma_in_type_id)
142
+ self.assertEqual(
143
+ warehouse.rma_in_type_id.default_location_dest_id, warehouse.rma_loc_id
144
+ )
145
+ self.assertEqual(
146
+ warehouse.rma_out_type_id.default_location_src_id, warehouse.rma_loc_id
147
+ )
148
+ self.assertTrue(warehouse.rma_loc_id)
149
+ self.assertTrue(warehouse.rma_in_route_id)
150
+ self.assertTrue(warehouse.rma_out_route_id)
151
+
152
+ def test_rma_replace_pick_ship(self):
153
+ self.warehouse.write({"delivery_steps": "pick_ship"})
154
+ rma = self._create_rma(self.partner, self.product, 1, self.rma_loc)
155
+ rma.action_confirm()
156
+ rma.reception_move_id.quantity = 1
157
+ rma.reception_move_id.picking_id.button_validate()
158
+ self.assertEqual(rma.reception_move_id.picking_id.state, "done")
159
+ self.assertEqual(rma.state, "received")
160
+ res = rma.action_replace()
161
+ wizard_form = Form(self.env[res["res_model"]].with_context(**res["context"]))
162
+ wizard_form.product_id = self.product
163
+ wizard_form.product_uom_qty = rma.product_uom_qty
164
+ wizard = wizard_form.save()
165
+ wizard.action_deliver()
166
+ self.assertEqual(rma.delivery_picking_count, 2)
167
+ out_pickings = rma.mapped("delivery_move_ids.picking_id")
168
+ self.assertIn(
169
+ self.warehouse.pick_type_id, out_pickings.mapped("picking_type_id")
170
+ )
171
+ self.assertIn(
172
+ self.warehouse.out_type_id, out_pickings.mapped("picking_type_id")
173
+ )
174
+
135
175
  def test_computed(self):
136
176
  # If partner changes, the invoice address is set
137
177
  rma = self.env["rma"].new()
@@ -169,7 +209,7 @@ class TestRmaCase(TestRma):
169
209
  move.product_id = product_2
170
210
  move.product_uom_qty = 15
171
211
  picking = picking_form.save()
172
- picking._action_done()
212
+ picking.button_validate()
173
213
  rma.picking_id = picking
174
214
  rma.move_id = picking.move_ids
175
215
  self.assertEqual(rma.product_id, product_2)
@@ -207,13 +247,18 @@ class TestRmaCase(TestRma):
207
247
  self.assertEqual(rma.state, "confirmed")
208
248
  rma.reception_move_id.quantity = 9
209
249
  with self.assertRaises(ValidationError):
210
- rma.reception_move_id.picking_id._action_done()
250
+ res = rma.reception_move_id.picking_id.button_validate()
251
+ wizard = (
252
+ self.env[res["res_model"]].with_context(**res["context"]).create({})
253
+ )
254
+ wizard.process()
211
255
  rma.reception_move_id.quantity = 10
212
- rma.reception_move_id.picking_id._action_done()
256
+ rma.reception_move_id.picking_id.button_validate()
213
257
  self.assertEqual(rma.reception_move_id.picking_id.state, "done")
214
258
  self.assertEqual(rma.reception_move_id.quantity, 10)
215
259
  self.assertEqual(rma.state, "received")
216
260
 
261
+ @mute_logger("odoo.models.unlink")
217
262
  def test_cancel(self):
218
263
  # cancel a draft RMA
219
264
  rma = self._create_rma(self.partner, self.product)
@@ -333,7 +378,7 @@ class TestRmaCase(TestRma):
333
378
  # line of refund_1
334
379
  self.assertEqual(len(refund_1.invoice_line_ids), 3)
335
380
  self.assertEqual(
336
- refund_1.invoice_line_ids.mapped("rma_id"),
381
+ refund_1.invoice_line_ids.rma_id,
337
382
  (rma_1 | rma_2 | rma_3),
338
383
  )
339
384
  self.assertEqual(
@@ -524,6 +569,13 @@ class TestRmaCase(TestRma):
524
569
  all_rmas = rma_1 | rma_2 | rma_3 | rma_4
525
570
  self.assertEqual(all_rmas.mapped("state"), ["received"] * 4)
526
571
  self.assertEqual(all_rmas.mapped("can_be_returned"), [True] * 4)
572
+ all_in_pickings = all_rmas.mapped("reception_move_id.picking_id")
573
+ self.assertEqual(
574
+ all_in_pickings.mapped("picking_type_id"), self.warehouse.rma_in_type_id
575
+ )
576
+ self.assertEqual(
577
+ all_in_pickings.mapped("location_dest_id"), self.warehouse.rma_loc_id
578
+ )
527
579
  # Mass return of those four RMAs
528
580
  delivery_wizard = (
529
581
  self.env["rma.delivery.wizard"]
@@ -534,6 +586,10 @@ class TestRmaCase(TestRma):
534
586
  # Two pickings were created
535
587
  pick_1 = (rma_1 | rma_2 | rma_3).mapped("delivery_move_ids.picking_id")
536
588
  pick_2 = rma_4.delivery_move_ids.picking_id
589
+ self.assertEqual(pick_1.picking_type_id, self.warehouse.rma_out_type_id)
590
+ self.assertEqual(pick_1.location_id, self.warehouse.rma_loc_id)
591
+ self.assertEqual(pick_2.picking_type_id, self.warehouse.rma_out_type_id)
592
+ self.assertEqual(pick_2.location_id, self.warehouse.rma_loc_id)
537
593
  self.assertEqual(len(pick_1), 1)
538
594
  self.assertEqual(len(pick_2), 1)
539
595
  self.assertNotEqual(pick_1, pick_2)
@@ -549,7 +605,7 @@ class TestRmaCase(TestRma):
549
605
  # line of picking_1
550
606
  self.assertEqual(len(pick_1.move_ids), 3)
551
607
  self.assertEqual(
552
- pick_1.move_ids.mapped("rma_id"),
608
+ pick_1.move_ids.rma_id,
553
609
  (rma_1 | rma_2 | rma_3),
554
610
  )
555
611
  self.assertEqual(
@@ -620,14 +676,14 @@ class TestRmaCase(TestRma):
620
676
  origin_moves = origin_delivery.move_ids
621
677
  self.assertTrue(origin_moves[0].rma_ids)
622
678
  self.assertTrue(origin_moves[1].rma_ids)
623
- rmas = origin_moves.mapped("rma_ids")
679
+ rmas = origin_moves.rma_ids
624
680
  self.assertEqual(rmas.mapped("state"), ["confirmed"] * 2)
625
681
  # Each reception move is linked one of the generated RMAs
626
682
  reception = self.env["stock.picking"].browse(picking_action["res_id"])
627
683
  reception_moves = reception.move_ids
628
684
  self.assertTrue(reception_moves[0].rma_receiver_ids)
629
685
  self.assertTrue(reception_moves[1].rma_receiver_ids)
630
- self.assertEqual(reception_moves.mapped("rma_receiver_ids"), rmas)
686
+ self.assertEqual(reception_moves.rma_receiver_ids, rmas)
631
687
  # Validate the reception picking to set rmas to 'received' state
632
688
  reception_moves[0].quantity = reception_moves[0].product_uom_qty
633
689
  reception_moves[1].quantity = reception_moves[1].product_uom_qty
@@ -645,7 +701,7 @@ class TestRmaCase(TestRma):
645
701
  rma = rma_form.save()
646
702
  rma.action_confirm()
647
703
  rma.reception_move_id.quantity = 10
648
- rma.reception_move_id.picking_id._action_done()
704
+ rma.reception_move_id.picking_id.button_validate()
649
705
  # Return quantity 4 of the same product to the customer
650
706
  delivery_form = Form(
651
707
  self.env["rma.delivery.wizard"].with_context(
@@ -686,6 +742,7 @@ class TestRmaCase(TestRma):
686
742
  self.assertEqual(new_rma.move_id.quantity, 10)
687
743
  self.assertEqual(new_rma.reception_move_id.quantity, 10)
688
744
 
745
+ @mute_logger("odoo.models.unlink")
689
746
  def test_rma_to_receive_on_delete_invoice(self):
690
747
  rma = self._create_confirm_receive(self.partner, self.product, 10, self.rma_loc)
691
748
  rma.action_refund()
@@ -1,8 +1,25 @@
1
1
  # Copyright 2020 Tecnativa - Ernesto Tejeda
2
+ # Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
2
3
  # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
4
+ from copy import deepcopy
3
5
 
4
6
  from odoo import _, api, fields, models
5
7
  from odoo.exceptions import ValidationError
8
+ from odoo.tools import float_compare
9
+
10
+
11
+ class ReturnPickingLine(models.TransientModel):
12
+ _inherit = "stock.return.picking.line"
13
+
14
+ def _prepare_rma_vals(self):
15
+ self.ensure_one()
16
+ return {
17
+ "move_id": self.move_id.id,
18
+ "product_id": self.move_id.product_id.id,
19
+ "product_uom_qty": self.quantity,
20
+ "product_uom": self.product_id.uom_id.id,
21
+ "location_id": self.wizard_id.location_id.id or self.move_id.location_id.id,
22
+ }
6
23
 
7
24
 
8
25
  class ReturnPicking(models.TransientModel):
@@ -48,6 +65,52 @@ class ReturnPicking(models.TransientModel):
48
65
  location_id = return_picking_type.default_location_dest_id.id
49
66
  self.location_id = location_id
50
67
 
68
+ def _prepare_rma_partner_values(self):
69
+ self.ensure_one()
70
+ partner = self.picking_id.partner_id
71
+ partner_address = partner.address_get(["invoice", "delivery"])
72
+ partner_invoice_id = partner_address.get("invoice", False)
73
+ partner_shipping_id = partner_address.get("delivery", False)
74
+ return (
75
+ partner,
76
+ partner_invoice_id and partner.browse(partner_invoice_id) or partner,
77
+ partner_shipping_id and partner.browse(partner_shipping_id) or partner,
78
+ )
79
+
80
+ def _prepare_rma_vals(self):
81
+ partner, partner_invoice, partner_shipping = self._prepare_rma_partner_values()
82
+ origin = self.picking_id.name
83
+ vals = self.env["rma"]._prepare_procurement_group_vals()
84
+ vals["partner_id"] = partner_shipping.id
85
+ vals["name"] = origin
86
+ group = self.env["procurement.group"].create(vals)
87
+ return {
88
+ "user_id": self.env.user.id,
89
+ "partner_id": partner.id,
90
+ "partner_shipping_id": partner_shipping.id,
91
+ "partner_invoice_id": partner_invoice.id,
92
+ "origin": origin,
93
+ "picking_id": self.picking_id.id,
94
+ "company_id": self.company_id.id,
95
+ "procurement_group_id": group.id,
96
+ }
97
+
98
+ def _prepare_rma_vals_list(self):
99
+ vals_list = []
100
+ for return_picking in self:
101
+ global_vals = return_picking._prepare_rma_vals()
102
+ for line in return_picking.product_return_moves:
103
+ if (
104
+ not line.move_id
105
+ or float_compare(line.quantity, 0, line.product_id.uom_id.rounding)
106
+ <= 0
107
+ ):
108
+ continue
109
+ vals = deepcopy(global_vals)
110
+ vals.update(line._prepare_rma_vals())
111
+ vals_list.append(vals)
112
+ return vals_list
113
+
51
114
  def create_returns(self):
52
115
  """Override create_returns method for creating one or more
53
116
  'confirmed' RMAs after return a delivery picking in case
@@ -57,10 +120,6 @@ class ReturnPicking(models.TransientModel):
57
120
  as the 'Receipt'.
58
121
  """
59
122
  if self.create_rma:
60
- # set_rma_picking_type is to override the copy() method of stock
61
- # picking and change the default picking type to rma picking type
62
- self_with_context = self.with_context(set_rma_picking_type=True)
63
- res = super(ReturnPicking, self_with_context).create_returns()
64
123
  if not self.picking_id.partner_id:
65
124
  raise ValidationError(
66
125
  _(
@@ -68,12 +127,30 @@ class ReturnPicking(models.TransientModel):
68
127
  "'Stock Picking' from which RMAs will be created"
69
128
  )
70
129
  )
71
- returned_picking = self.env["stock.picking"].browse(res["res_id"])
72
- vals_list = [
73
- move._prepare_return_rma_vals(self.picking_id)
74
- for move in returned_picking.move_ids
75
- ]
76
- self.env["rma"].create(vals_list)
77
- return res
78
- else:
79
- return super().create_returns()
130
+ vals_list = self._prepare_rma_vals_list()
131
+ rmas = self.env["rma"].create(vals_list)
132
+ rmas.action_confirm()
133
+ picking = rmas.reception_move_id.picking_id
134
+ picking = picking and picking[0] or picking
135
+ ctx = dict(self.env.context)
136
+ ctx.update(
137
+ {
138
+ "default_partner_id": picking.partner_id.id,
139
+ "search_default_picking_type_id": picking.picking_type_id.id,
140
+ "search_default_draft": False,
141
+ "search_default_assigned": False,
142
+ "search_default_confirmed": False,
143
+ "search_default_ready": False,
144
+ "search_default_planning_issues": False,
145
+ "search_default_available": False,
146
+ }
147
+ )
148
+ return {
149
+ "name": _("Returned Picking"),
150
+ "view_mode": "form,tree,calendar",
151
+ "res_model": "stock.picking",
152
+ "res_id": picking.id,
153
+ "type": "ir.actions.act_window",
154
+ "context": ctx,
155
+ }
156
+ return super().create_returns()
@@ -17,6 +17,7 @@
17
17
  <field name="rma_location_ids" invisible="1" />
18
18
  <field name="picking_id" invisible="1" />
19
19
  <field name="picking_type_code" invisible="1" />
20
+ <field name="location_id" invisible="1" />
20
21
  </group>
21
22
  </field>
22
23
  </field>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: odoo-addon-rma
3
- Version: 17.0.1.1.1
3
+ Version: 17.0.2.0.0.1
4
4
  Requires-Python: >=3.10
5
5
  Requires-Dist: odoo>=17.0a,<17.1dev
6
6
  Summary: Return Merchandise Authorization (RMA)
@@ -23,7 +23,7 @@ Return Merchandise Authorization Management
23
23
  !! This file is generated by oca-gen-addon-readme !!
24
24
  !! changes will be overwritten. !!
25
25
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
26
- !! source digest: sha256:ed3081bf9b94660a0e6b35acbc7a874023c57e4bc3a87f3762eabbb1c75ce2f4
26
+ !! source digest: sha256:8f36869aece97a0f6af8aa5d76b446e9cf0bd589d914c1f5e12c628e87317021
27
27
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
28
28
 
29
29
  .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
@@ -156,6 +156,9 @@ Known issues / Roadmap
156
156
  - As soon as the picking is selected, the user should select the move,
157
157
  but perhaps stock.move \_rec_name could be improved to better show
158
158
  what the product of that move is.
159
+ - Add RMA reception and/or RMA delivery on several steps - 2 or 3 -
160
+ like normal receptions/deliveries. It should be a separate option
161
+ inside the warehouse definition.
159
162
 
160
163
  Bug Tracker
161
164
  ===========
@@ -191,6 +194,8 @@ Contributors
191
194
 
192
195
  - Antoni Marroig <amarroig@apsl.net>
193
196
 
197
+ - Michael Tietz (MT Software) mtietz@mt-software.de
198
+
194
199
  Maintainers
195
200
  -----------
196
201