odoo-addon-rma 16.0.1.2.0.1__py3-none-any.whl → 17.0.1.0.0.2__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.
- odoo/addons/rma/README.rst +87 -78
- odoo/addons/rma/__manifest__.py +1 -1
- odoo/addons/rma/controllers/main.py +2 -1
- odoo/addons/rma/data/mail_data.xml +3 -6
- odoo/addons/rma/hooks.py +1 -5
- odoo/addons/rma/i18n/it.po +2 -2
- odoo/addons/rma/i18n/rma.pot +49 -81
- odoo/addons/rma/models/rma.py +51 -112
- odoo/addons/rma/models/stock_move.py +1 -1
- odoo/addons/rma/readme/CONFIGURE.md +22 -0
- odoo/addons/rma/readme/CONTRIBUTORS.md +9 -0
- odoo/addons/rma/readme/{DESCRIPTION.rst → DESCRIPTION.md} +4 -4
- odoo/addons/rma/readme/ROADMAP.md +3 -0
- odoo/addons/rma/readme/USAGE.md +59 -0
- odoo/addons/rma/static/description/index.html +55 -46
- odoo/addons/rma/tests/test_rma.py +21 -37
- odoo/addons/rma/views/res_config_settings_views.xml +55 -124
- odoo/addons/rma/views/res_partner_views.xml +1 -1
- odoo/addons/rma/views/rma_finalization_views.xml +1 -1
- odoo/addons/rma/views/rma_team_views.xml +2 -6
- odoo/addons/rma/views/rma_views.xml +71 -39
- odoo/addons/rma/views/stock_picking_views.xml +1 -1
- odoo/addons/rma/wizard/rma_delivery_views.xml +8 -19
- odoo/addons/rma/wizard/stock_picking_return_views.xml +1 -1
- odoo_addon_rma-17.0.1.0.0.2.dist-info/METADATA +220 -0
- {odoo_addon_rma-16.0.1.2.0.1.dist-info → odoo_addon_rma-17.0.1.0.0.2.dist-info}/RECORD +28 -28
- {odoo_addon_rma-16.0.1.2.0.1.dist-info → odoo_addon_rma-17.0.1.0.0.2.dist-info}/WHEEL +1 -1
- odoo_addon_rma-17.0.1.0.0.2.dist-info/top_level.txt +1 -0
- odoo/addons/rma/readme/CONFIGURE.rst +0 -21
- odoo/addons/rma/readme/CONTRIBUTORS.rst +0 -9
- odoo/addons/rma/readme/ROADMAP.rst +0 -3
- odoo/addons/rma/readme/USAGE.rst +0 -57
- odoo_addon_rma-16.0.1.2.0.1.dist-info/METADATA +0 -214
- odoo_addon_rma-16.0.1.2.0.1.dist-info/top_level.txt +0 -1
odoo/addons/rma/models/rma.py
CHANGED
@@ -35,60 +35,37 @@ class Rma(models.Model):
|
|
35
35
|
sent = fields.Boolean()
|
36
36
|
name = fields.Char(
|
37
37
|
index=True,
|
38
|
-
readonly=True,
|
39
|
-
states={"draft": [("readonly", False)]},
|
40
38
|
copy=False,
|
41
39
|
default=lambda self: _("New"),
|
42
40
|
)
|
43
41
|
origin = fields.Char(
|
44
42
|
string="Source Document",
|
45
|
-
states={
|
46
|
-
"locked": [("readonly", True)],
|
47
|
-
"cancelled": [("readonly", True)],
|
48
|
-
},
|
49
43
|
help="Reference of the document that generated this RMA.",
|
50
44
|
)
|
51
45
|
date = fields.Datetime(
|
52
46
|
default=fields.Datetime.now,
|
53
47
|
index=True,
|
54
48
|
required=True,
|
55
|
-
readonly=True,
|
56
|
-
states={"draft": [("readonly", False)]},
|
57
|
-
)
|
58
|
-
deadline = fields.Date(
|
59
|
-
states={
|
60
|
-
"locked": [("readonly", True)],
|
61
|
-
"cancelled": [("readonly", True)],
|
62
|
-
},
|
63
49
|
)
|
50
|
+
deadline = fields.Date()
|
64
51
|
user_id = fields.Many2one(
|
65
52
|
comodel_name="res.users",
|
66
53
|
string="Responsible",
|
67
54
|
index=True,
|
68
55
|
tracking=True,
|
69
|
-
states={
|
70
|
-
"locked": [("readonly", True)],
|
71
|
-
"cancelled": [("readonly", True)],
|
72
|
-
},
|
73
56
|
)
|
74
57
|
team_id = fields.Many2one(
|
75
58
|
comodel_name="rma.team",
|
76
59
|
string="RMA team",
|
77
60
|
index=True,
|
78
|
-
states={
|
79
|
-
"locked": [("readonly", True)],
|
80
|
-
"cancelled": [("readonly", True)],
|
81
|
-
},
|
82
61
|
compute="_compute_team_id",
|
83
62
|
store=True,
|
84
|
-
readonly=False,
|
85
63
|
)
|
86
64
|
tag_ids = fields.Many2many(comodel_name="rma.tag", string="Tags")
|
87
65
|
finalization_id = fields.Many2one(
|
88
66
|
string="Finalization Reason",
|
89
67
|
comodel_name="rma.finalization",
|
90
68
|
copy=False,
|
91
|
-
readonly=True,
|
92
69
|
domain=(
|
93
70
|
"['|', ('company_id', '=', False), ('company_id', '='," " company_id)]"
|
94
71
|
),
|
@@ -97,16 +74,10 @@ class Rma(models.Model):
|
|
97
74
|
company_id = fields.Many2one(
|
98
75
|
comodel_name="res.company",
|
99
76
|
default=lambda self: self.env.company,
|
100
|
-
states={
|
101
|
-
"locked": [("readonly", True)],
|
102
|
-
"cancelled": [("readonly", True)],
|
103
|
-
},
|
104
77
|
)
|
105
78
|
partner_id = fields.Many2one(
|
106
79
|
string="Customer",
|
107
80
|
comodel_name="res.partner",
|
108
|
-
readonly=True,
|
109
|
-
states={"draft": [("readonly", False)]},
|
110
81
|
index=True,
|
111
82
|
tracking=True,
|
112
83
|
)
|
@@ -143,8 +114,6 @@ class Rma(models.Model):
|
|
143
114
|
" ('partner_id', 'child_of', commercial_partner_id),"
|
144
115
|
"]"
|
145
116
|
),
|
146
|
-
readonly=True,
|
147
|
-
states={"draft": [("readonly", False)]},
|
148
117
|
)
|
149
118
|
move_id = fields.Many2one(
|
150
119
|
comodel_name="stock.move",
|
@@ -187,18 +156,10 @@ class Rma(models.Model):
|
|
187
156
|
procurement_group_id = fields.Many2one(
|
188
157
|
comodel_name="procurement.group",
|
189
158
|
string="Procurement group",
|
190
|
-
readonly=True,
|
191
|
-
states={
|
192
|
-
"draft": [("readonly", False)],
|
193
|
-
"confirmed": [("readonly", False)],
|
194
|
-
"received": [("readonly", False)],
|
195
|
-
},
|
196
159
|
)
|
197
160
|
priority = fields.Selection(
|
198
161
|
selection=PROCUREMENT_PRIORITIES,
|
199
162
|
default="1",
|
200
|
-
readonly=True,
|
201
|
-
states={"draft": [("readonly", False)]},
|
202
163
|
)
|
203
164
|
operation_id = fields.Many2one(
|
204
165
|
comodel_name="rma.operation",
|
@@ -222,12 +183,7 @@ class Rma(models.Model):
|
|
222
183
|
copy=False,
|
223
184
|
tracking=True,
|
224
185
|
)
|
225
|
-
description = fields.Html(
|
226
|
-
states={
|
227
|
-
"locked": [("readonly", True)],
|
228
|
-
"cancelled": [("readonly", True)],
|
229
|
-
},
|
230
|
-
)
|
186
|
+
description = fields.Html()
|
231
187
|
# Reception fields
|
232
188
|
location_id = fields.Many2one(
|
233
189
|
comodel_name="stock.location",
|
@@ -249,12 +205,10 @@ class Rma(models.Model):
|
|
249
205
|
# Refund fields
|
250
206
|
refund_id = fields.Many2one(
|
251
207
|
comodel_name="account.move",
|
252
|
-
readonly=True,
|
253
208
|
copy=False,
|
254
209
|
)
|
255
210
|
refund_line_id = fields.Many2one(
|
256
211
|
comodel_name="account.move.line",
|
257
|
-
readonly=True,
|
258
212
|
copy=False,
|
259
213
|
)
|
260
214
|
can_be_refunded = fields.Boolean(compute="_compute_can_be_refunded")
|
@@ -263,7 +217,6 @@ class Rma(models.Model):
|
|
263
217
|
comodel_name="stock.move",
|
264
218
|
inverse_name="rma_id",
|
265
219
|
string="Delivery reservation",
|
266
|
-
readonly=True,
|
267
220
|
copy=False,
|
268
221
|
)
|
269
222
|
delivery_picking_count = fields.Integer(
|
@@ -275,11 +228,6 @@ class Rma(models.Model):
|
|
275
228
|
compute="_compute_delivered_qty",
|
276
229
|
store=True,
|
277
230
|
)
|
278
|
-
delivered_qty_done = fields.Float(
|
279
|
-
digits="Product Unit of Measure",
|
280
|
-
compute="_compute_delivered_qty",
|
281
|
-
compute_sudo=True,
|
282
|
-
)
|
283
231
|
can_be_returned = fields.Boolean(
|
284
232
|
compute="_compute_can_be_returned",
|
285
233
|
)
|
@@ -297,11 +245,6 @@ class Rma(models.Model):
|
|
297
245
|
digits="Product Unit of Measure",
|
298
246
|
compute="_compute_remaining_qty",
|
299
247
|
)
|
300
|
-
remaining_qty_to_done = fields.Float(
|
301
|
-
string="Remaining delivered qty to done",
|
302
|
-
digits="Product Unit of Measure",
|
303
|
-
compute="_compute_remaining_qty",
|
304
|
-
)
|
305
248
|
uom_category_id = fields.Many2one(
|
306
249
|
related="product_id.uom_id.category_id", string="Category UoM"
|
307
250
|
)
|
@@ -312,7 +255,6 @@ class Rma(models.Model):
|
|
312
255
|
origin_split_rma_id = fields.Many2one(
|
313
256
|
comodel_name="rma",
|
314
257
|
string="Extracted from",
|
315
|
-
readonly=True,
|
316
258
|
copy=False,
|
317
259
|
)
|
318
260
|
|
@@ -335,8 +277,7 @@ class Rma(models.Model):
|
|
335
277
|
"delivery_move_ids.state",
|
336
278
|
"delivery_move_ids.scrapped",
|
337
279
|
"delivery_move_ids.product_uom_qty",
|
338
|
-
"delivery_move_ids.
|
339
|
-
"delivery_move_ids.quantity_done",
|
280
|
+
"delivery_move_ids.quantity",
|
340
281
|
"delivery_move_ids.product_uom",
|
341
282
|
"product_uom",
|
342
283
|
)
|
@@ -355,29 +296,21 @@ class Rma(models.Model):
|
|
355
296
|
"""
|
356
297
|
for record in self:
|
357
298
|
delivered_qty = 0.0
|
358
|
-
delivered_qty_done = 0.0
|
359
299
|
for move in record.delivery_move_ids.filtered(
|
360
300
|
lambda r: r.state != "cancel" and not r.scrapped
|
361
301
|
):
|
362
|
-
if move.
|
363
|
-
|
364
|
-
move.
|
365
|
-
)
|
366
|
-
if move.state == "done":
|
367
|
-
delivered_qty_done += quantity_done
|
368
|
-
delivered_qty += quantity_done
|
369
|
-
elif move.reserved_availability:
|
370
|
-
delivered_qty += move.product_uom._compute_quantity(
|
371
|
-
move.reserved_availability, record.product_uom
|
302
|
+
if move.quantity:
|
303
|
+
quantity = move.product_uom._compute_quantity(
|
304
|
+
move.quantity, record.product_uom
|
372
305
|
)
|
306
|
+
delivered_qty += quantity
|
373
307
|
elif move.product_uom_qty:
|
374
308
|
delivered_qty += move.product_uom._compute_quantity(
|
375
309
|
move.product_uom_qty, record.product_uom
|
376
310
|
)
|
377
311
|
record.delivered_qty = delivered_qty
|
378
|
-
record.delivered_qty_done = delivered_qty_done
|
379
312
|
|
380
|
-
@api.depends("product_uom_qty", "delivered_qty"
|
313
|
+
@api.depends("product_uom_qty", "delivered_qty")
|
381
314
|
def _compute_remaining_qty(self):
|
382
315
|
"""Compute 'remaining_qty' and 'remaining_qty_to_done' fields.
|
383
316
|
|
@@ -392,7 +325,6 @@ class Rma(models.Model):
|
|
392
325
|
"""
|
393
326
|
for r in self:
|
394
327
|
r.remaining_qty = r.product_uom_qty - r.delivered_qty
|
395
|
-
r.remaining_qty_to_done = r.product_uom_qty - r.delivered_qty_done
|
396
328
|
|
397
329
|
@api.depends(
|
398
330
|
"state",
|
@@ -443,7 +375,7 @@ class Rma(models.Model):
|
|
443
375
|
and rma.remaining_qty > 0
|
444
376
|
)
|
445
377
|
|
446
|
-
@api.depends("product_uom_qty", "state", "remaining_qty"
|
378
|
+
@api.depends("product_uom_qty", "state", "remaining_qty")
|
447
379
|
def _compute_can_be_split(self):
|
448
380
|
"""Compute 'can_be_split'. This field controls the
|
449
381
|
visibility of 'Split' button in the rma form view and
|
@@ -460,10 +392,10 @@ class Rma(models.Model):
|
|
460
392
|
else:
|
461
393
|
r.can_be_split = False
|
462
394
|
|
463
|
-
@api.depends("
|
395
|
+
@api.depends("state")
|
464
396
|
def _compute_can_be_locked(self):
|
465
397
|
for r in self:
|
466
|
-
r.can_be_locked = r.
|
398
|
+
r.can_be_locked = r.remaining_qty > 0 and r.state in [
|
467
399
|
"received",
|
468
400
|
"waiting_return",
|
469
401
|
"waiting_replacement",
|
@@ -555,7 +487,7 @@ class Rma(models.Model):
|
|
555
487
|
|
556
488
|
def _compute_access_url(self):
|
557
489
|
for record in self:
|
558
|
-
record.access_url = "/my/rmas/{
|
490
|
+
record.access_url = f"/my/rmas/{record.id}"
|
559
491
|
|
560
492
|
# Constrains methods (@api.constrains)
|
561
493
|
@api.constrains(
|
@@ -612,34 +544,41 @@ class Rma(models.Model):
|
|
612
544
|
def _send_draft_email(self):
|
613
545
|
"""Send customer notifications they place the RMA from the portal"""
|
614
546
|
for rma in self.filtered("company_id.send_rma_draft_confirmation"):
|
615
|
-
rma_template_id = rma.company_id.rma_mail_draft_confirmation_template_id.id
|
616
547
|
rma.with_context(
|
617
548
|
force_send=True,
|
618
549
|
mark_rma_as_sent=True,
|
619
|
-
|
620
|
-
|
550
|
+
).message_post_with_source(
|
551
|
+
rma.company_id.rma_mail_draft_confirmation_template_id.get_external_id()[
|
552
|
+
rma.company_id.rma_mail_draft_confirmation_template_id.id
|
553
|
+
],
|
554
|
+
subtype_xmlid="rma.mt_rma_notification",
|
555
|
+
)
|
621
556
|
|
622
557
|
def _send_confirmation_email(self):
|
623
558
|
"""Auto send notifications"""
|
624
559
|
for rma in self.filtered(lambda p: p.company_id.send_rma_confirmation):
|
625
|
-
rma_template_id = rma.company_id.rma_mail_confirmation_template_id.id
|
626
560
|
rma.with_context(
|
627
561
|
force_send=True,
|
628
562
|
mark_rma_as_sent=True,
|
629
|
-
|
630
|
-
|
563
|
+
).message_post_with_source(
|
564
|
+
rma.company_id.rma_mail_confirmation_template_id.get_external_id()[
|
565
|
+
rma.company_id.rma_mail_confirmation_template_id.id
|
566
|
+
],
|
567
|
+
subtype_xmlid="rma.mt_rma_notification",
|
568
|
+
)
|
631
569
|
|
632
570
|
def _send_receipt_confirmation_email(self):
|
633
571
|
"""Send customer notifications when the products are received"""
|
634
572
|
for rma in self.filtered("company_id.send_rma_receipt_confirmation"):
|
635
|
-
rma_template_id = (
|
636
|
-
rma.company_id.rma_mail_receipt_confirmation_template_id.id
|
637
|
-
)
|
638
573
|
rma.with_context(
|
639
574
|
force_send=True,
|
640
575
|
mark_rma_as_sent=True,
|
641
|
-
|
642
|
-
|
576
|
+
).message_post_with_source(
|
577
|
+
rma.company_id.rma_mail_receipt_confirmation_template_id.get_external_id()[
|
578
|
+
rma.company_id.rma_mail_receipt_confirmation_template_id.id
|
579
|
+
],
|
580
|
+
subtype_xmlid="rma.mt_rma_notification",
|
581
|
+
)
|
643
582
|
|
644
583
|
# Action methods
|
645
584
|
def action_rma_send(self):
|
@@ -682,6 +621,7 @@ class Rma(models.Model):
|
|
682
621
|
reception_move = self._create_receptions_from_picking()
|
683
622
|
else:
|
684
623
|
reception_move = self._create_receptions_from_product()
|
624
|
+
reception_move.picked = True
|
685
625
|
self.write({"reception_move_id": reception_move.id, "state": "confirmed"})
|
686
626
|
self._add_message_subscribe_partner()
|
687
627
|
self._send_confirmation_email()
|
@@ -703,10 +643,10 @@ class Rma(models.Model):
|
|
703
643
|
(0, 0, rma._prepare_refund_line_vals())
|
704
644
|
)
|
705
645
|
refund = self.env["account.move"].sudo().create(refund_vals)
|
706
|
-
refund.with_user(self.env.uid).
|
646
|
+
refund.with_user(self.env.uid).message_post_with_source(
|
707
647
|
"mail.message_origin_link",
|
708
|
-
|
709
|
-
subtype_id=self.env.
|
648
|
+
render_values={"self": refund, "origin": rmas},
|
649
|
+
subtype_id=self.env["ir.model.data"]._xmlid_to_res_id("mail.mt_note"),
|
710
650
|
)
|
711
651
|
for line in refund.invoice_line_ids:
|
712
652
|
line.rma_id.write(
|
@@ -1017,7 +957,7 @@ class Rma(models.Model):
|
|
1017
957
|
).create_returns()
|
1018
958
|
picking_id = picking_action["res_id"]
|
1019
959
|
picking = self.env["stock.picking"].browse(picking_id)
|
1020
|
-
picking.origin = "{} ({
|
960
|
+
picking.origin = f"{self.name} ({picking.origin})"
|
1021
961
|
move = picking.move_ids
|
1022
962
|
move.priority = self.priority
|
1023
963
|
return move
|
@@ -1027,10 +967,10 @@ class Rma(models.Model):
|
|
1027
967
|
picking = self.env["stock.picking"].create(self._prepare_picking_vals())
|
1028
968
|
picking.action_confirm()
|
1029
969
|
picking.action_assign()
|
1030
|
-
picking.
|
970
|
+
picking.message_post_with_source(
|
1031
971
|
"mail.message_origin_link",
|
1032
|
-
|
1033
|
-
subtype_id=self.env.
|
972
|
+
render_values={"self": picking, "origin": self},
|
973
|
+
subtype_id=self.env["ir.model.data"]._xmlid_to_res_id("mail.mt_note"),
|
1034
974
|
)
|
1035
975
|
return picking.move_ids
|
1036
976
|
|
@@ -1052,7 +992,9 @@ class Rma(models.Model):
|
|
1052
992
|
or self.product_id.with_context(
|
1053
993
|
lang=self.partner_id.lang or "en_US"
|
1054
994
|
).display_name,
|
1055
|
-
"location_id":
|
995
|
+
"location_id": (
|
996
|
+
self.partner_shipping_id.property_stock_customer.id
|
997
|
+
),
|
1056
998
|
"location_dest_id": self.location_id.id,
|
1057
999
|
"product_uom_qty": self.product_uom_qty,
|
1058
1000
|
},
|
@@ -1066,7 +1008,7 @@ class Rma(models.Model):
|
|
1066
1008
|
self._ensure_can_be_split()
|
1067
1009
|
self._ensure_qty_to_extract(qty, uom)
|
1068
1010
|
self.product_uom_qty -= uom._compute_quantity(qty, self.product_uom)
|
1069
|
-
if self.
|
1011
|
+
if self.remaining_qty <= 0:
|
1070
1012
|
if self.state == "waiting_return":
|
1071
1013
|
self.state = "returned"
|
1072
1014
|
elif self.state == "waiting_replacement":
|
@@ -1081,10 +1023,10 @@ class Rma(models.Model):
|
|
1081
1023
|
"origin_split_rma_id": self.id,
|
1082
1024
|
}
|
1083
1025
|
)
|
1084
|
-
extracted_rma.
|
1026
|
+
extracted_rma.message_post_with_source(
|
1085
1027
|
"mail.message_origin_link",
|
1086
|
-
|
1087
|
-
subtype_id=self.env.
|
1028
|
+
render_values={"self": extracted_rma, "origin": self},
|
1029
|
+
subtype_id=self.env["ir.model.data"]._xmlid_to_res_id("mail.mt_note"),
|
1088
1030
|
)
|
1089
1031
|
self.message_post(
|
1090
1032
|
body=_(
|
@@ -1173,10 +1115,10 @@ class Rma(models.Model):
|
|
1173
1115
|
)
|
1174
1116
|
picking.action_confirm()
|
1175
1117
|
picking.action_assign()
|
1176
|
-
picking.
|
1118
|
+
picking.message_post_with_source(
|
1177
1119
|
"mail.message_origin_link",
|
1178
|
-
|
1179
|
-
subtype_id=self.env.
|
1120
|
+
render_values={"self": picking, "origin": rmas},
|
1121
|
+
subtype_id=self.env["ir.model.data"]._xmlid_to_res_id("mail.mt_note"),
|
1180
1122
|
)
|
1181
1123
|
rmas_to_return.write({"state": "waiting_return"})
|
1182
1124
|
|
@@ -1232,7 +1174,7 @@ class Rma(models.Model):
|
|
1232
1174
|
% (
|
1233
1175
|
{
|
1234
1176
|
"move_id": new_move.id,
|
1235
|
-
"move_name": new_move.
|
1177
|
+
"move_name": new_move.display_name,
|
1236
1178
|
"picking_id": new_move.picking_id.id,
|
1237
1179
|
"picking_name": new_move.picking_id.name,
|
1238
1180
|
}
|
@@ -1425,10 +1367,7 @@ class Rma(models.Model):
|
|
1425
1367
|
[stock.move]._action_cancel
|
1426
1368
|
"""
|
1427
1369
|
rma = self.filtered(
|
1428
|
-
lambda r: (
|
1429
|
-
r.state == "waiting_replacement"
|
1430
|
-
and 0 >= r.remaining_qty_to_done == r.remaining_qty
|
1431
|
-
)
|
1370
|
+
lambda r: (r.state == "waiting_replacement" and 0 >= r.remaining_qty)
|
1432
1371
|
)
|
1433
1372
|
if rma:
|
1434
1373
|
rma.write({"state": "replaced"})
|
@@ -1436,7 +1375,7 @@ class Rma(models.Model):
|
|
1436
1375
|
def update_returned_state(self):
|
1437
1376
|
"""Invoked by [stock.move]._action_done"""
|
1438
1377
|
rma = self.filtered(
|
1439
|
-
lambda r: (r.state == "waiting_return" and r.
|
1378
|
+
lambda r: (r.state == "waiting_return" and r.remaining_qty <= 0)
|
1440
1379
|
)
|
1441
1380
|
if rma:
|
1442
1381
|
rma.write({"state": "returned"})
|
@@ -59,7 +59,7 @@ class StockMove(models.Model):
|
|
59
59
|
"""
|
60
60
|
for move in self.filtered(lambda r: r.state not in ("done", "cancel")):
|
61
61
|
rma_receiver = move.sudo().rma_receiver_ids
|
62
|
-
if rma_receiver and move.
|
62
|
+
if rma_receiver and move.quantity != rma_receiver.product_uom_qty:
|
63
63
|
raise ValidationError(
|
64
64
|
_(
|
65
65
|
"The quantity done for the product '%(id)s' must "
|
@@ -0,0 +1,22 @@
|
|
1
|
+
If you want RMAs to be created from incoming emails, you need to:
|
2
|
+
|
3
|
+
1. Go to *Settings \> General Settings*.
|
4
|
+
2. Check 'External Email Servers' checkbox under *Discuss* section.
|
5
|
+
3. Set an 'alias domain' and an incoming server.
|
6
|
+
4. Go to *RMA \> Configuration \> RMA Team* and select a team or create
|
7
|
+
a new one.
|
8
|
+
5. Go to 'Email' tab and set an 'Email Alias'.
|
9
|
+
|
10
|
+
If you want to manually finish RMAs, you need to:
|
11
|
+
|
12
|
+
1. Go to *Settings \> Inventory*.
|
13
|
+
2. Set *Finish RMAs manually* checkbox on.
|
14
|
+
|
15
|
+
By default, returns to customer are grouped by shipping address,
|
16
|
+
warehouse and company. If you want to avoid this grouping you can:
|
17
|
+
|
18
|
+
1. Go to *Settings \> Inventory*.
|
19
|
+
2. Set *Group RMA returns by customer address and warehouse* checkbox
|
20
|
+
off.
|
21
|
+
|
22
|
+
The users will still be able to group those pickings from the wizard.
|
@@ -0,0 +1,9 @@
|
|
1
|
+
- [Tecnativa](https://www.tecnativa.com):
|
2
|
+
- Ernesto Tejeda
|
3
|
+
- Pedro M. Baeza
|
4
|
+
- David Vidal
|
5
|
+
- Víctor Martínez
|
6
|
+
- Chafique Delli \<<chafique.delli@akretion.com>\>
|
7
|
+
- Giovanni Serra - Ooops \<<giovanni@ooops404.com>\>
|
8
|
+
- [APSL-Nagarro](https://www.apsl.tech):
|
9
|
+
- Antoni Marroig \<<amarroig@apsl.net>\>
|
@@ -1,8 +1,8 @@
|
|
1
|
-
This module allows you to manage
|
2
|
-
|
1
|
+
This module allows you to manage [Return Merchandise Authorization
|
2
|
+
(RMA)](https://en.wikipedia.org/wiki/Return_merchandise_authorization).
|
3
3
|
RMA documents can be created from scratch, from a delivery order or from
|
4
4
|
an incoming email. Product receptions and returning delivery operations
|
5
5
|
of the RMA module are fully integrated with the Receipts and Deliveries
|
6
6
|
Operations of Odoo inventory core module. It also allows you to generate
|
7
|
-
refunds in the same way as Odoo generates it.
|
8
|
-
|
7
|
+
refunds in the same way as Odoo generates it. Besides, you have full
|
8
|
+
integration of the RMA documents in the customer portal.
|
@@ -0,0 +1,59 @@
|
|
1
|
+
To use this module, you need to:
|
2
|
+
|
3
|
+
1. Go to *RMA \> Orders* and create a new RMA.
|
4
|
+
2. Select a partner, an invoice address, select a product (or select a
|
5
|
+
picking and a move instead), write a quantity, fill the rest of the
|
6
|
+
form and click on 'confirm' button in the status bar.
|
7
|
+
3. You will see an smart button labeled 'Receipt'. Click on that button
|
8
|
+
to see the reception operation form.
|
9
|
+
4. If everything is right, validate the operation and go back to the
|
10
|
+
RMA to see it in a 'received' state.
|
11
|
+
5. Now you are able to generate a refund, generate a delivery order to
|
12
|
+
return to the customer the same product or another product as a
|
13
|
+
replacement, split the RMA by extracting a part of the remaining
|
14
|
+
quantity to another RMA, preview the RMA in the website. All of
|
15
|
+
these operations can be done by clicking on the buttons in the
|
16
|
+
status bar.
|
17
|
+
- If you click on 'To Refund' button, a refund will be created, and it
|
18
|
+
will be accessible via the smart button labeled Refund. The RMA
|
19
|
+
will be set automatically to 'Refunded' state when the refund is
|
20
|
+
validated.
|
21
|
+
- If you click on 'Replace' or 'Return to customer' button instead,
|
22
|
+
a popup wizard will guide you to create a Delivery order to the
|
23
|
+
client and this order will be accessible via the smart button
|
24
|
+
labeled Delivery. The RMA will be set automatically to 'Replaced'
|
25
|
+
or 'Returned' state when the RMA quantity is equal or lower than
|
26
|
+
the quantity in done delivery orders linked to it.
|
27
|
+
6. You can also finish the RMA without further ado. To do so click on
|
28
|
+
the *Finish* button. A wizard will ask you for the reason from a
|
29
|
+
selection of preconfigured ones. Be sure to configure them in
|
30
|
+
advance on *RMA \> Configuration \> Finalization Reasons*. Once the
|
31
|
+
RMA is finished, it will be set to that state and the reason will be
|
32
|
+
registered.
|
33
|
+
|
34
|
+
An RMA can also be created from a return of a delivery order:
|
35
|
+
|
36
|
+
1. Select a delivery order and click on 'Return' button to create a
|
37
|
+
return.
|
38
|
+
2. Check "Create RMAs" checkbox in the returning wizard, select the RMA
|
39
|
+
stock location and click on 'Return' button.
|
40
|
+
3. An RMA will be created for each product returned in the previous
|
41
|
+
step. Every RMA will be in confirmed state and they will be linked
|
42
|
+
to the returning operation generated previously.
|
43
|
+
|
44
|
+
There are Optional RMA Teams that can be used for:
|
45
|
+
|
46
|
+
> - Organize RMAs in sections.
|
47
|
+
> - Subscribe users to notifications.
|
48
|
+
> - Create RMAs from incoming mail to special aliases (See configuration
|
49
|
+
> section).
|
50
|
+
|
51
|
+
To create an RMA Team (RMA Responsible user level required):
|
52
|
+
|
53
|
+
> 1. Go to *RMA \> Configuration \> RMA Teams*
|
54
|
+
> 2. Create a new team and assign a name, a responsible and members.
|
55
|
+
> 3. Subscribe users to notifications, that can be of these subtypes:
|
56
|
+
> - RMA draft. When a new RMA is created.
|
57
|
+
> - Notes, Debates, Activities. As in standard Odoo.
|
58
|
+
> 4. In the list view, use the cross handle to sort RMA Teams. The top
|
59
|
+
> team will be the default one if no team is set.
|