[14.0][IMP]rma_put_away: allows to do stock moves from rma

This commit is contained in:
DavidJForgeFlow
2022-06-14 09:54:55 +02:00
parent 6b84bef6a2
commit acea5d4cdc
12 changed files with 373 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,16 @@
{
"name": "RMA Free of Charge True",
"summary": "Make the field free of charge true by default",
"version": "14.0.1.1.0",
"author": "ForgeFlow, " "Odoo Community Association (OCA)",
"website": "https://github.com/ForgeFlow/stock-rma",
"category": "RMA",
"depends": ["account_move_line_rma_order_line"],
"license": "AGPL-3",
"data": [
],
"installable": True,
"maintainers": ["DavidJForgeFlow"],
"development_status": "Beta",
}

View File

@@ -0,0 +1 @@
from . import rma_line_make_purchase_order_item

View File

@@ -0,0 +1,7 @@
from odoo import fields, models
class RmaLineMakePurchaseOrderItem(models.TransientModel):
_inherit = "rma.order.line.make.purchase.order.item"
free_of_charge = fields.Boolean(default="True")

1
rma_put_away/__init__.py Normal file
View File

@@ -0,0 +1 @@
from . import wizards

View File

@@ -0,0 +1,15 @@
{
"name": "RMA Put Away",
"version": "14.0.1.0.0",
"license": "LGPL-3",
"category": "RMA",
"summary": "Allows to put away the recieved products"
"in odoo",
"author": "ForgeFlow",
"website": "https://github.com/ForgeFlow/stock-rma",
"depends": ["rma"],
"data": [
"views/rma_put_away_view.xml",
],
"installable": True,
}

View File

View File

@@ -0,0 +1,41 @@
from odoo import _, api, fields, models
class RmaOrderLine(models.Model):
_inherit = "rma.order.line"
qty_to_put_away = fields.Float(
string="Qty To Put Away",
digits="Product Unit of Measure",
compute="_compute_qty_to_put_away",
store=True,
)
qty_put_away = fields.Float(
string="Qty Put Away",
copy=False,
digits="Product Unit of Measure",
readonly=True,
compute="_compute_qty_put_away",
store=True,
help="Quantity Put Away.",
)
put_away_policy = fields.Selection(
selection=[
("no", "Not required"),
("ordered", "Based on Ordered Quantities"),
("received", "Based on Received Quantities"),
],
string="Put Away Policy",
default="no",
required=True,
)
def _compute_qty_to_put_away(self):
for rec in self:
rec.qty_to_put_away = 0.0
if rec.put_away_policy == "ordered":
rec.qty_to_put_away = rec.product_qty - rec.qty_put_away
elif rec.put_away_policy == "received":
rec.qty_to_put_away = rec.qty_received - rec.qty_put_away

View File

@@ -0,0 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_rma_put_away_wizard,rma.order.manager,model_rma_make_put_away.wizard,group_rma_manager,1,1,1,1
access_rma_put_away_wizard_customer,rma.order.manager,model_rma_make_put_away.wizard,group_rma_customer_user,1,1,1,1
access_rma_put_away_wizard_supplier,rma.order.manager,model_rma_make_put_away.wizard,group_rma_supplier_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_rma_put_away_wizard rma.order.manager model_rma_make_put_away.wizard group_rma_manager 1 1 1 1
3 access_rma_put_away_wizard_customer rma.order.manager model_rma_make_put_away.wizard group_rma_customer_user 1 1 1 1
4 access_rma_put_away_wizard_supplier rma.order.manager model_rma_make_put_away.wizard group_rma_supplier_user 1 1 1 1

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" ?>
<odoo>
<record id="view_rma_put_away" model="ir.ui.view">
<field name="name">Create Put Away</field>
<field name="model">rma_make_put_away.wizard</field>
<field name="arch" type="xml">
<form string="Select lines for picking" name="lines">
<separator string="Select lines for put away" />
<field name="item_ids">
<tree string="RMA Lines" editable="bottom" create="false">
<field name="rma_id" groups="rma.group_rma_groups" />
<field name="product_id" />
<field name="product_qty" />
<field name="line_id" invisible="1" />
<field name="uom_id" groups="uom.group_uom" />
</tree>
</field>
<footer>
<button
string="Confirm"
name="action_create_put_away"
type="object"
class="oe_highlight"
/>
or
<button
name="action_cancel"
string="Cancel"
class="oe_link"
special="cancel"
/>
</footer>
</form>
</field>
</record>
<record id="action_rma_put_away" model="ir.actions.act_window">
<field name="name">Create Put Away</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">rma_make_put_away.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="view_id" ref="view_rma_put_away" />
<field name="groups_id" eval="[(4, ref('stock.group_stock_user'))]" />
<field name="context">{'picking_type': 'internal'}</field>
<field name="binding_model_id" ref="rma.model_rma_order_line" />
</record>
<record id="view_rma_line_button_put_away_form" model="ir.ui.view">
<field name="name">rma.order.line.form</field>
<field name="model">rma.order.line</field>
<field name="inherit_id" ref="rma.view_rma_line_button_form" />
<field name="arch" type="xml">
<header position="inside">
<button
name="%(action_rma_put_away)d"
string="Create Put Away"
class="oe_highlight"
attrs="{'invisible':['|', ('qty_to_deliver', '=', 0), ('state', '!=', 'approved')]}"
type="action"
/>
<button
name="%(action_rma_put_away)d"
string="Create Put Away"
attrs="{'invisible':['|', ('qty_to_deliver', '!=', 0), ('state', '!=', 'approved')]}"
type="action"
/>
</header>
</field>
</record>
</odoo>

View File

@@ -0,0 +1 @@
from . import rma_make_put_away

View File

@@ -0,0 +1,214 @@
import time
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DT_FORMAT
class RmaMakePutAway(models.TransientModel):
_name = "rma_make_put_away.wizard"
_description = "Wizard to create put away from rma lines"
item_ids = fields.One2many("rma_make_picking.wizard.item", "wiz_id", string="Items")
@api.returns("rma.order.line")
def _prepare_item(self, line):
values = {
"product_id": line.product_id.id,
"product_qty": line.product_qty,
"uom_id": line.uom_id.id,
"qty_to_receive": line.qty_to_receive,
"qty_to_deliver": line.qty_to_deliver,
"line_id": line.id,
"rma_id": line.rma_id and line.rma_id.id or False,
}
return values
@api.model
def default_get(self, fields_list):
"""Default values for wizard, if there is more than one supplier on
lines the supplier field is empty otherwise is the unique line
supplier.
"""
context = self._context.copy()
res = super(RmaMakePutAway, self).default_get(fields_list)
rma_line_obj = self.env["rma.order.line"]
rma_line_ids = self.env.context["active_ids"] or []
active_model = self.env.context["active_model"]
if not rma_line_ids:
return res
assert active_model == "rma.order.line", "Bad context propagation"
items = []
lines = rma_line_obj.browse(rma_line_ids)
if len(lines.mapped("partner_id")) > 1:
raise ValidationError(
_(
"Only RMA lines from the same partner can be processed at "
"the same time"
)
)
for line in lines:
items.append([0, 0, self._prepare_item(line)])
res["item_ids"] = items
context.update({"items_ids": items})
return res
def _create_put_away(self):
"""Method called when the user clicks on create picking"""
picking_type = "internal"
procurements = []
for item in self.item_ids:
line = item.line_id
if line.state != "approved":
raise ValidationError(_("RMA %s is not approved") % line.name)
if line.receipt_policy == "no" and picking_type == "incoming":
raise ValidationError(_("No shipments needed for this operation"))
if line.delivery_policy == "no" and picking_type == "outgoing":
raise ValidationError(_("No deliveries needed for this operation"))
procurement = self._create_procurement(item, picking_type)
procurements.extend(procurement)
return procurements
def action_create_put_away(self):
self._create_put_away()
move_line_model = self.env["stock.move.line"]
picking_type = "internal"
pickings = self.mapped("item_ids.line_id")._get_in_pickings()
action = self.item_ids.line_id.action_view_in_shipments()
if picking_type == "internal":
# Force the reservation of the RMA specific lot for incoming shipments.
# FIXME: still needs fixing, not reserving appropriate serials.
for move in pickings.move_lines.filtered(
lambda x: x.state not in ("draft", "cancel", "done")
and x.rma_line_id
and x.product_id.tracking in ("lot", "serial")
and x.rma_line_id.lot_id
):
# Force the reservation of the RMA specific lot for incoming shipments.
move.move_line_ids.unlink()
if move.product_id.tracking == "serial":
move.write(
{
"lot_ids": [(6, 0, move.rma_line_id.lot_id.ids)],
}
)
move.move_line_ids.write(
{
"product_uom_qty": 1,
"qty_done": 0,
}
)
elif move.product_id.tracking == "lot":
if picking_type == "internal":
qty = self.item_ids.filtered(
lambda x: x.line_id.id == move.rma_line_id.id
).qty_to_receive
else:
qty = self.item_ids.filtered(
lambda x: x.line_id.id == move.rma_line_id.id
).qty_to_deliver
move_line_data = move._prepare_move_line_vals()
move_line_data.update(
{
"lot_id": move.rma_line_id.lot_id.id,
"product_uom_id": move.product_id.uom_id.id,
"qty_done": 0,
"product_uom_qty": qty,
}
)
move_line_model.create(move_line_data)
pickings.with_context(force_no_bypass_reservation=True).action_assign()
return action
@api.model
def _get_address(self, item):
if item.line_id.customer_to_supplier:
delivery_address = item.line_id.supplier_address_id
elif item.line_id.supplier_to_customer:
delivery_address = item.line_id.customer_address_id
elif item.line_id.delivery_address_id:
delivery_address = item.line_id.delivery_address_id
elif item.line_id.partner_id:
delivery_address = item.line_id.partner_id
else:
raise ValidationError(_("Unknown delivery address"))
return delivery_address
@api.model
def _get_address_location(self, delivery_address_id, a_type):
if a_type == "supplier":
return delivery_address_id.property_stock_supplier
elif a_type == "customer":
return delivery_address_id.property_stock_customer
@api.model
def _get_procurement_data(self, item, group, qty, picking_type):
line = item.line_id
delivery_address_id = self._get_address(item)
location = self._get_address_location(delivery_address_id, line.type)
warehouse = line.out_warehouse_id
route = line.out_route_id
if not route:
raise ValidationError(_("No route specified"))
if not warehouse:
raise ValidationError(_("No warehouse specified"))
procurement_data = {
"name": line.rma_id and line.rma_id.name or line.name,
"group_id": group,
"origin": line.name,
"warehouse_id": warehouse,
"date_planned": time.strftime(DT_FORMAT),
"product_id": item.product_id,
"product_qty": qty,
"partner_id": delivery_address_id.id,
"product_uom": line.product_id.product_tmpl_id.uom_id.id,
"location_id": location,
"rma_line_id": line.id,
"route_ids": route,
}
return procurement_data
@api.model
def _create_procurement(self, item, picking_type):
errors = []
group = self.find_procurement_group(item)
if not group:
pg_data = self._get_procurement_group_data(item)
group = self.env["procurement.group"].create(pg_data)
qty = item.product_qty
values = self._get_procurement_data(item, group, qty, picking_type)
values = dict(values, rma_line_id=item.line_id, rma_id=item.line_id.rma_id)
# create picking
procurements = []
try:
procurement = group.Procurement(
item.line_id.product_id,
qty,
item.line_id.product_id.product_tmpl_id.uom_id,
values.get("location_id"),
values.get("origin"),
values.get("origin"),
self.env.company,
values,
)
procurements.append(procurement)
self.env["procurement.group"].run(procurements)
except UserError as error:
errors.append(error.name)
if errors:
raise UserError("\n".join(errors))
return procurements
def find_procurement_group(self, item):
if item.line_id.rma_id:
return self.env["procurement.group"].search(
[("rma_id", "=", item.line_id.rma_id.id)]
)
else:
return self.env["procurement.group"].search(
[("rma_line_id", "=", item.line_id.id)]
)