Skip to content

Commit 29d8bcb

Browse files
committed
ADD rma_scrap module for v17 from forgeflow 17.0-mig-rma_scrap-good branch
Push code from unmerger PR: ForgeFlow#514 Branch: https://github.com/ForgeFlow/stock-rma/tree/17.0-mig-rma_scrap-good
1 parent 42c6888 commit 29d8bcb

21 files changed

+914
-0
lines changed

rma_scrap/README.rst

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
2+
:alt: License LGPL-3
3+
4+
============
5+
RMA Scrap
6+
============
7+
8+
This module allows you to put scrap the products.
9+
10+
Configuration
11+
=============
12+
13+
Go to *RMA / Configuration / Customer Operations* and define there:
14+
15+
#. The Scrap Policy
16+
#. The default scrap destination location .
17+
18+
Usage
19+
=====
20+
21+
#. Go to a Customer RMA.
22+
#. Click on *Scrap*.
23+
#. Indicate the quantity that you want to scrap.
24+
25+
Bug Tracker
26+
===========
27+
28+
Bugs are tracked on `GitHub Issues
29+
<https://github.com/Eficent/stock-rma/issues>`_. In case of trouble, please
30+
check there if your issue has already been reported. If you spotted it first,
31+
help us smashing it by providing a detailed and welcomed feedback.
32+
33+
Credits
34+
=======
35+
36+
Contributors
37+
------------
38+
39+
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
40+
* David Jimenez <david.jimenez@forgeflow.com>
41+
42+
43+
Maintainer
44+
----------
45+
46+
This module is maintained by ForgeFlow

rma_scrap/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import wizards
2+
from . import models

rma_scrap/__manifest__.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "RMA Scrap",
3+
"version": "17.0.1.0.0",
4+
"license": "LGPL-3",
5+
"category": "RMA",
6+
"summary": "Allows to scrap the received/ordered products in odoo",
7+
"author": "ForgeFlow",
8+
"website": "https://github.com/ForgeFlow",
9+
"depends": ["rma"],
10+
"data": [
11+
"security/ir.model.access.csv",
12+
"views/rma_operation_view.xml",
13+
"views/rma_order_line_view.xml",
14+
"views/rma_order_view.xml",
15+
"views/stock_scrap_view.xml",
16+
"wizards/rma_scrap_view.xml",
17+
],
18+
"installable": True,
19+
}

rma_scrap/models/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from . import rma_operation
2+
from . import stock_move
3+
from . import stock_rule
4+
from . import rma_order_line
5+
from . import rma_order
6+
from . import stock_scrap

rma_scrap/models/rma_operation.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright 2022 ForgeFlow S.L.
2+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html).
3+
4+
from odoo import fields, models
5+
6+
7+
class RmaOperation(models.Model):
8+
_inherit = "rma.operation"
9+
10+
scrap_policy = fields.Selection(
11+
selection=[
12+
("no", "Not required"),
13+
("ordered", "Based on Ordered Quantities"),
14+
("received", "Based on Received Quantities"),
15+
],
16+
default="no",
17+
)
18+
19+
scrap_location_id = fields.Many2one(
20+
comodel_name="stock.location",
21+
string="Scrap Destination Location",
22+
domain="[('scrap_location', '=', True),"
23+
"('company_id', 'in', [company_id, False])]",
24+
)

rma_scrap/models/rma_order.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright 2022 ForgeFlow S.L.
2+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
3+
from odoo import fields, models
4+
5+
6+
class RmaOrder(models.Model):
7+
_inherit = "rma.order"
8+
9+
def _compute_scrap_count(self):
10+
for order in self:
11+
scraps = order.mapped("rma_line_ids.scrap_ids")
12+
order.scrap_count = len(scraps)
13+
14+
scrap_count = fields.Integer(compute="_compute_scrap_count", string="# Scrap")
15+
16+
def action_view_scrap_transfers(self):
17+
self.ensure_one()
18+
action = self.env.ref("stock.action_stock_scrap")
19+
result = action.sudo().read()[0]
20+
scraps = self.env["stock.scrap"].search([("origin", "=", self.name)])
21+
if len(scraps) > 1:
22+
result["domain"] = [("id", "in", scraps.ids)]
23+
elif len(scraps) == 1:
24+
res = self.env.ref("stock.stock_scrap_form_view", False)
25+
result["views"] = [(res and res.id or False, "form")]
26+
result["res_id"] = scraps.ids[0]
27+
return result

rma_scrap/models/rma_order_line.py

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Copyright 2022 ForgeFlow S.L.
2+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
3+
from odoo import api, fields, models
4+
5+
6+
class RmaOrderLine(models.Model):
7+
_inherit = "rma.order.line"
8+
9+
@api.depends(
10+
"move_ids",
11+
"move_ids.state",
12+
"move_ids.is_rma_scrap",
13+
"qty_scrap",
14+
"scrap_policy",
15+
"product_qty",
16+
"scrap_ids",
17+
"scrap_ids.state",
18+
"scrap_ids.is_rma_scrap",
19+
)
20+
def _compute_qty_to_scrap(self):
21+
for rec in self:
22+
rec.qty_to_scrap = 0.0
23+
if rec.scrap_policy == "ordered":
24+
rec.qty_to_scrap = rec.product_qty - rec.qty_scrap
25+
elif rec.scrap_policy == "received":
26+
rec.qty_to_scrap = rec.qty_received - rec.qty_scrap
27+
28+
@api.depends(
29+
"move_ids",
30+
"move_ids.state",
31+
"move_ids.is_rma_scrap",
32+
"scrap_ids",
33+
"scrap_ids.state",
34+
"scrap_ids.is_rma_scrap",
35+
)
36+
def _compute_qty_in_scrap(self):
37+
product_obj = self.env["uom.uom"]
38+
for rec in self:
39+
qty = 0.0
40+
for move in self.scrap_ids.filtered(lambda m: m.state in ["draft"]):
41+
qty += product_obj._compute_quantity(move.scrap_qty, rec.uom_id)
42+
rec.qty_in_scrap = qty
43+
44+
@api.depends("scrap_ids", "scrap_ids.state", "scrap_ids.is_rma_scrap")
45+
def _compute_qty_scrap(self):
46+
product_obj = self.env["uom.uom"]
47+
for rec in self:
48+
qty = 0.0
49+
for move in rec.move_ids.filtered(
50+
lambda m: m.state in ["done"] and m.is_rma_scrap
51+
):
52+
qty += product_obj._compute_quantity(move.product_uom_qty, rec.uom_id)
53+
rec.qty_scrap = qty
54+
55+
def _compute_scrap_count(self):
56+
for line in self:
57+
line.scrap_count = len(self.scrap_ids)
58+
59+
qty_to_scrap = fields.Float(
60+
copy=False,
61+
digits="Product Unit of Measure",
62+
readonly=True,
63+
compute="_compute_qty_to_scrap",
64+
store=True,
65+
)
66+
qty_in_scrap = fields.Float(
67+
copy=False,
68+
digits="Product Unit of Measure",
69+
readonly=True,
70+
compute="_compute_qty_in_scrap",
71+
store=True,
72+
)
73+
qty_scrap = fields.Float(
74+
copy=False,
75+
digits="Product Unit of Measure",
76+
readonly=True,
77+
compute="_compute_qty_scrap",
78+
store=True,
79+
)
80+
scrap_policy = fields.Selection(
81+
selection=[
82+
("no", "Not required"),
83+
("ordered", "Based on Ordered Quantities"),
84+
("received", "Based on Received Quantities"),
85+
],
86+
default="no",
87+
required=True,
88+
readonly=False,
89+
)
90+
scrap_count = fields.Integer(compute="_compute_scrap_count", string="# Scraps")
91+
scrap_ids = fields.One2many("stock.scrap", "rma_line_id")
92+
93+
@api.onchange("operation_id")
94+
def _onchange_operation_id(self):
95+
res = super()._onchange_operation_id()
96+
if self.operation_id:
97+
self.scrap_policy = self.operation_id.scrap_policy or "no"
98+
return res
99+
100+
def action_view_scrap_transfers(self):
101+
action = self.env.ref("stock.action_stock_scrap")
102+
result = action.sudo().read()[0]
103+
if len(self.scrap_ids) > 1:
104+
result["domain"] = [("id", "in", self.scrap_ids.ids)]
105+
elif len(self.scrap_ids) == 1:
106+
res = self.env.ref("stock.stock_scrap_form_view", False)
107+
result["views"] = [(res and res.id or False, "form")]
108+
result["res_id"] = self.scrap_ids.ids[0]
109+
return result

rma_scrap/models/stock_move.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright 2022 ForgeFlow S.L.
2+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
3+
4+
from odoo import fields, models
5+
6+
7+
class StockMove(models.Model):
8+
_inherit = "stock.move"
9+
10+
is_rma_scrap = fields.Boolean(
11+
string="Is RMA Scrap",
12+
copy=False,
13+
help="This Stock Move has been created from a Scrap operation in " "the RMA.",
14+
)

rma_scrap/models/stock_rule.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright 2022 ForgeFlow S.L.
2+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
3+
4+
from odoo import models
5+
6+
7+
class StockRule(models.Model):
8+
_inherit = "stock.rule"
9+
10+
def _get_stock_move_values(
11+
self,
12+
product_id,
13+
product_qty,
14+
product_uom,
15+
location_id,
16+
name,
17+
origin,
18+
company_id,
19+
values,
20+
):
21+
res = super()._get_stock_move_values(
22+
product_id,
23+
product_qty,
24+
product_uom,
25+
location_id,
26+
name,
27+
origin,
28+
company_id,
29+
values,
30+
)
31+
if "is_rma_scrap" in values:
32+
res["is_rma_scrap"] = values.get("is_rma_scrap")
33+
return res

rma_scrap/models/stock_scrap.py

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Copyright 2022 ForgeFlow S.L.
2+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html).
3+
4+
from odoo import _, fields, models
5+
from odoo.exceptions import UserError
6+
from odoo.tools import float_compare, float_is_zero
7+
8+
9+
class StockScrap(models.Model):
10+
_inherit = "stock.scrap"
11+
12+
rma_line_id = fields.Many2one("rma.order.line", string="RMA order Line")
13+
14+
is_rma_scrap = fields.Boolean(
15+
string="Is RMA Scrap",
16+
default=False,
17+
copy=False,
18+
help="This Stock Move has been created from a Scrap operation in " "the RMA.",
19+
)
20+
21+
def do_scrap(self):
22+
res = super().do_scrap()
23+
if self.is_rma_scrap:
24+
self.move_ids.is_rma_scrap = True
25+
self.rma_line_id.move_ids |= self.move_ids
26+
return res
27+
28+
def _prepare_move_values(self):
29+
res = super()._prepare_move_values()
30+
res["rma_line_id"] = self.rma_line_id.id
31+
return res
32+
33+
def action_view_rma_line(self):
34+
if self.rma_line_id.type == "customer":
35+
action = self.env.ref("rma.action_rma_customer_lines")
36+
res = self.env.ref("rma.view_rma_line_form", False)
37+
else:
38+
action = self.env.ref("rma.action_rma_supplier_lines")
39+
res = self.env.ref("rma.view_rma_line_supplier_form", False)
40+
result = action.sudo().read()[0]
41+
# choose the view_mode accordingly
42+
result["views"] = [(res and res.id or False, "form")]
43+
result["res_id"] = self.rma_line_id.id
44+
return result
45+
46+
def action_validate(self):
47+
self.ensure_one()
48+
if float_is_zero(
49+
self.scrap_qty, precision_rounding=self.product_uom_id.rounding
50+
):
51+
raise UserError(_("You can only enter positive quantities."))
52+
if self.product_id.type != "product":
53+
return self.do_scrap()
54+
precision = self.env["decimal.precision"].precision_get(
55+
"Product Unit of Measure"
56+
)
57+
available_qty = sum(
58+
self.env["stock.quant"]
59+
._gather(
60+
self.product_id,
61+
self.location_id,
62+
self.lot_id,
63+
self.package_id,
64+
self.owner_id,
65+
strict=True,
66+
)
67+
.mapped("quantity")
68+
)
69+
scrap_qty = self.product_uom_id._compute_quantity(
70+
self.scrap_qty, self.product_id.uom_id
71+
)
72+
if float_compare(available_qty, scrap_qty, precision_digits=precision) >= 0:
73+
return self.do_scrap()
74+
else:
75+
ctx = dict(self.env.context)
76+
ctx.update(
77+
{
78+
"default_product_id": self.product_id.id,
79+
"default_location_id": self.location_id.id,
80+
"default_scrap_id": self.id,
81+
"default_quantity": scrap_qty,
82+
"default_product_uom_name": self.product_id.uom_name,
83+
}
84+
)
85+
return {
86+
"name": self.product_id.display_name
87+
+ _(": Insufficient Quantity To Scrap"),
88+
"view_mode": "form",
89+
"res_model": "stock.warn.insufficient.qty.scrap",
90+
"view_id": self.env.ref(
91+
"stock.stock_warn_insufficient_qty_scrap_form_view"
92+
).id,
93+
"type": "ir.actions.act_window",
94+
"context": ctx,
95+
"target": "new",
96+
}

rma_scrap/pyproject.toml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["whool"]
3+
build-backend = "whool.buildapi"
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2+
access_rma_scrap_wizard,rma.order.manager,model_rma_make_scrap_wizard,rma.group_rma_manager,1,1,1,1
3+
access_rma_scrap_wizard_customer,rma.order.manager,model_rma_make_scrap_wizard,rma.group_rma_customer_user,1,1,1,1
4+
access_rma_scrap_wizard_supplier,rma.order.manager,model_rma_make_scrap_wizard,rma.group_rma_supplier_user,1,1,1,1
5+
access_rma_scrap_item_wizard,rma.order.manager,model_rma_make_scrap_item_wizard,rma.group_rma_manager,1,1,1,1
6+
access_rma_scrap_item_wizard_customer,rma.order.manager,model_rma_make_scrap_item_wizard,rma.group_rma_customer_user,1,1,1,1
7+
access_rma_scrap_item_wizard_supplier,rma.order.manager,model_rma_make_scrap_item_wizard,rma.group_rma_supplier_user,1,1,1,1

rma_scrap/tests/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import test_rma_scrap

0 commit comments

Comments
 (0)