mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] stock_request: black, isort
This commit is contained in:
@@ -1,2 +1 @@
|
||||
|
||||
from . import models
|
||||
|
||||
@@ -7,12 +7,9 @@
|
||||
"version": "12.0.1.1.6",
|
||||
"license": "LGPL-3",
|
||||
"website": "https://github.com/stock-logistics-warehouse",
|
||||
"author": "Eficent, "
|
||||
"Odoo Community Association (OCA)",
|
||||
"author": "Eficent, " "Odoo Community Association (OCA)",
|
||||
"category": "Warehouse Management",
|
||||
"depends": [
|
||||
"stock",
|
||||
],
|
||||
"depends": ["stock"],
|
||||
"data": [
|
||||
"security/stock_request_security.xml",
|
||||
"security/ir.model.access.csv",
|
||||
|
||||
@@ -5,15 +5,16 @@ from odoo import api, models
|
||||
|
||||
|
||||
class ProcurementGroup(models.Model):
|
||||
_inherit = 'procurement.group'
|
||||
_inherit = "procurement.group"
|
||||
|
||||
@api.model
|
||||
def run(self, product_id, product_qty, product_uom, location_id, name,
|
||||
origin, values):
|
||||
if 'stock_request_id' in values and values.get('stock_request_id'):
|
||||
req = self.env['stock.request'].browse(
|
||||
values.get('stock_request_id'))
|
||||
def run(
|
||||
self, product_id, product_qty, product_uom, location_id, name, origin, values
|
||||
):
|
||||
if "stock_request_id" in values and values.get("stock_request_id"):
|
||||
req = self.env["stock.request"].browse(values.get("stock_request_id"))
|
||||
if req.order_id:
|
||||
origin = req.order_id.name
|
||||
return super().run(product_id, product_qty, product_uom, location_id,
|
||||
name, origin, values)
|
||||
return super().run(
|
||||
product_id, product_qty, product_uom, location_id, name, origin, values
|
||||
)
|
||||
|
||||
@@ -7,8 +7,8 @@ from odoo import fields, models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
_inherit = "res.company"
|
||||
|
||||
stock_request_allow_virtual_loc = fields.Boolean(
|
||||
string='Allow Virtual locations on Stock Requests',
|
||||
string="Allow Virtual locations on Stock Requests"
|
||||
)
|
||||
|
||||
@@ -5,29 +5,34 @@ from odoo import api, fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
_inherit = "res.config.settings"
|
||||
|
||||
group_stock_request_order = fields.Boolean(
|
||||
implied_group='stock_request.group_stock_request_order')
|
||||
implied_group="stock_request.group_stock_request_order"
|
||||
)
|
||||
|
||||
module_stock_request_purchase = fields.Boolean(
|
||||
string='Stock Requests for Purchases')
|
||||
string="Stock Requests for Purchases"
|
||||
)
|
||||
|
||||
module_stock_request_kanban = fields.Boolean(
|
||||
string='Stock Requests Kanban integration')
|
||||
string="Stock Requests Kanban integration"
|
||||
)
|
||||
|
||||
stock_request_allow_virtual_loc = fields.Boolean(
|
||||
related='company_id.stock_request_allow_virtual_loc',
|
||||
readonly=False)
|
||||
related="company_id.stock_request_allow_virtual_loc", readonly=False
|
||||
)
|
||||
|
||||
module_stock_request_analytic = fields.Boolean(
|
||||
string='Stock Requests Analytic integration')
|
||||
string="Stock Requests Analytic integration"
|
||||
)
|
||||
|
||||
module_stock_request_submit = fields.Boolean(
|
||||
string='Submitted state in Stock Requests')
|
||||
string="Submitted state in Stock Requests"
|
||||
)
|
||||
|
||||
# Dependencies
|
||||
@api.onchange('stock_request_allow_virtual_loc')
|
||||
@api.onchange("stock_request_allow_virtual_loc")
|
||||
def _onchange_stock_request_allow_virtual_loc(self):
|
||||
if self.stock_request_allow_virtual_loc:
|
||||
self.group_stock_multi_locations = True
|
||||
|
||||
@@ -1,26 +1,45 @@
|
||||
# Copyright 2018 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, models, _
|
||||
from odoo import _, api, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class StockLocation(models.Model):
|
||||
_inherit = 'stock.location'
|
||||
_inherit = "stock.location"
|
||||
|
||||
@api.constrains('company_id')
|
||||
@api.constrains("company_id")
|
||||
def _check_company_stock_request(self):
|
||||
if any(rec.company_id and self.env['stock.request'].search(
|
||||
[('company_id', '!=', rec.company_id.id),
|
||||
('location_id', '=', rec.id)], limit=1) for rec in self):
|
||||
if any(
|
||||
rec.company_id
|
||||
and self.env["stock.request"].search(
|
||||
[("company_id", "!=", rec.company_id.id), ("location_id", "=", rec.id)],
|
||||
limit=1,
|
||||
)
|
||||
for rec in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You cannot change the company of the location, as it is '
|
||||
'already assigned to stock requests that belong to '
|
||||
'another company.'))
|
||||
if any(rec.company_id and self.env['stock.request.order'].search(
|
||||
[('company_id', '!=', rec.company_id.id),
|
||||
('warehouse_id', '=', rec.id)], limit=1) for rec in self):
|
||||
_(
|
||||
"You cannot change the company of the location, as it is "
|
||||
"already assigned to stock requests that belong to "
|
||||
"another company."
|
||||
)
|
||||
)
|
||||
if any(
|
||||
rec.company_id
|
||||
and self.env["stock.request.order"].search(
|
||||
[
|
||||
("company_id", "!=", rec.company_id.id),
|
||||
("warehouse_id", "=", rec.id),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
for rec in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You cannot change the company of the location, as it is '
|
||||
'already assigned to stock request orders that belong to '
|
||||
'another company.'))
|
||||
_(
|
||||
"You cannot change the company of the location, as it is "
|
||||
"already assigned to stock request orders that belong to "
|
||||
"another company."
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
# Copyright 2018 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, models, _
|
||||
from odoo import _, api, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class StockLocationRoute(models.Model):
|
||||
_inherit = 'stock.location.route'
|
||||
_inherit = "stock.location.route"
|
||||
|
||||
@api.constrains('company_id')
|
||||
@api.constrains("company_id")
|
||||
def _check_company_stock_request(self):
|
||||
if any(rec.company_id and self.env['stock.request'].search(
|
||||
[('company_id', '!=', rec.company_id.id),
|
||||
('route_id', '=', rec.id)], limit=1) for rec in self):
|
||||
if any(
|
||||
rec.company_id
|
||||
and self.env["stock.request"].search(
|
||||
[("company_id", "!=", rec.company_id.id), ("route_id", "=", rec.id)],
|
||||
limit=1,
|
||||
)
|
||||
for rec in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You cannot change the company of the route, as it is '
|
||||
'already assigned to stock requests that belong to '
|
||||
'another company.'))
|
||||
_(
|
||||
"You cannot change the company of the route, as it is "
|
||||
"already assigned to stock requests that belong to "
|
||||
"another company."
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,39 +1,50 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
_inherit = "stock.move"
|
||||
|
||||
allocation_ids = fields.One2many(comodel_name='stock.request.allocation',
|
||||
inverse_name='stock_move_id',
|
||||
string='Stock Request Allocation')
|
||||
allocation_ids = fields.One2many(
|
||||
comodel_name="stock.request.allocation",
|
||||
inverse_name="stock_move_id",
|
||||
string="Stock Request Allocation",
|
||||
)
|
||||
|
||||
stock_request_ids = fields.One2many(comodel_name='stock.request',
|
||||
string='Stock Requests',
|
||||
compute='_compute_stock_request_ids')
|
||||
stock_request_ids = fields.One2many(
|
||||
comodel_name="stock.request",
|
||||
string="Stock Requests",
|
||||
compute="_compute_stock_request_ids",
|
||||
)
|
||||
|
||||
@api.depends('allocation_ids')
|
||||
@api.depends("allocation_ids")
|
||||
def _compute_stock_request_ids(self):
|
||||
for rec in self:
|
||||
rec.stock_request_ids = rec.allocation_ids.mapped(
|
||||
'stock_request_id')
|
||||
rec.stock_request_ids = rec.allocation_ids.mapped("stock_request_id")
|
||||
|
||||
def _merge_moves_fields(self):
|
||||
res = super(StockMove, self)._merge_moves_fields()
|
||||
res['allocation_ids'] = [(4, m.id) for m in
|
||||
self.mapped('allocation_ids')]
|
||||
res["allocation_ids"] = [(4, m.id) for m in self.mapped("allocation_ids")]
|
||||
return res
|
||||
|
||||
@api.constrains('company_id')
|
||||
@api.constrains("company_id")
|
||||
def _check_company_stock_request(self):
|
||||
if any(self.env['stock.request.allocation'].search(
|
||||
[('company_id', '!=', rec.company_id.id),
|
||||
('stock_move_id', '=', rec.id)], limit=1)
|
||||
for rec in self):
|
||||
if any(
|
||||
self.env["stock.request.allocation"].search(
|
||||
[
|
||||
("company_id", "!=", rec.company_id.id),
|
||||
("stock_move_id", "=", rec.id),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
for rec in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('The company of the stock request must match with '
|
||||
'that of the location.'))
|
||||
_(
|
||||
"The company of the stock request must match with "
|
||||
"that of the location."
|
||||
)
|
||||
)
|
||||
|
||||
@@ -9,39 +9,44 @@ class StockMoveLine(models.Model):
|
||||
|
||||
@api.model
|
||||
def _stock_request_confirm_done_message_content(self, message_data):
|
||||
title = _('Receipt confirmation %s for your Request %s') % (
|
||||
message_data['picking_name'], message_data['request_name'])
|
||||
message = '<h3>%s</h3>' % title
|
||||
message += _('The following requested items from Stock Request %s '
|
||||
'have now been received in %s using Picking %s:') % (
|
||||
message_data['request_name'], message_data['location_name'],
|
||||
message_data['picking_name'])
|
||||
message += '<ul>'
|
||||
title = _("Receipt confirmation %s for your Request %s") % (
|
||||
message_data["picking_name"],
|
||||
message_data["request_name"],
|
||||
)
|
||||
message = "<h3>%s</h3>" % title
|
||||
message += _(
|
||||
'<li><b>%s</b>: Transferred quantity %s %s</li>'
|
||||
) % (message_data['product_name'],
|
||||
message_data['product_qty'],
|
||||
message_data['product_uom'],
|
||||
)
|
||||
message += '</ul>'
|
||||
"The following requested items from Stock Request %s "
|
||||
"have now been received in %s using Picking %s:"
|
||||
) % (
|
||||
message_data["request_name"],
|
||||
message_data["location_name"],
|
||||
message_data["picking_name"],
|
||||
)
|
||||
message += "<ul>"
|
||||
message += _("<li><b>%s</b>: Transferred quantity %s %s</li>") % (
|
||||
message_data["product_name"],
|
||||
message_data["product_qty"],
|
||||
message_data["product_uom"],
|
||||
)
|
||||
message += "</ul>"
|
||||
return message
|
||||
|
||||
def _prepare_message_data(self, ml, request, allocated_qty):
|
||||
return {
|
||||
'request_name': request.name,
|
||||
'picking_name': ml.picking_id.name,
|
||||
'product_name': ml.product_id.name_get()[0][1],
|
||||
'product_qty': allocated_qty,
|
||||
'product_uom': ml.product_uom_id.name,
|
||||
'location_name': ml.location_dest_id.name_get()[0][1],
|
||||
"request_name": request.name,
|
||||
"picking_name": ml.picking_id.name,
|
||||
"product_name": ml.product_id.name_get()[0][1],
|
||||
"product_qty": allocated_qty,
|
||||
"product_uom": ml.product_uom_id.name,
|
||||
"location_name": ml.location_dest_id.name_get()[0][1],
|
||||
}
|
||||
|
||||
def _action_done(self):
|
||||
res = super(StockMoveLine, self)._action_done()
|
||||
for ml in self.filtered(
|
||||
lambda m: m.exists() and m.move_id.allocation_ids):
|
||||
for ml in self.filtered(lambda m: m.exists() and m.move_id.allocation_ids):
|
||||
qty_done = ml.product_uom_id._compute_quantity(
|
||||
ml.qty_done, ml.product_id.uom_id)
|
||||
ml.qty_done, ml.product_id.uom_id
|
||||
)
|
||||
|
||||
# We do sudo because potentially the user that completes the move
|
||||
# may not have permissions for stock.request.
|
||||
@@ -49,16 +54,12 @@ class StockMoveLine(models.Model):
|
||||
for allocation in ml.move_id.allocation_ids.sudo():
|
||||
allocated_qty = 0.0
|
||||
if allocation.open_product_qty:
|
||||
allocated_qty = min(
|
||||
allocation.open_product_qty, qty_done)
|
||||
allocated_qty = min(allocation.open_product_qty, qty_done)
|
||||
allocation.allocated_product_qty += allocated_qty
|
||||
to_allocate_qty -= allocated_qty
|
||||
request = allocation.stock_request_id
|
||||
message_data = self._prepare_message_data(ml, request,
|
||||
allocated_qty)
|
||||
message = \
|
||||
self._stock_request_confirm_done_message_content(
|
||||
message_data)
|
||||
request.message_post(body=message, subtype='mail.mt_comment')
|
||||
message_data = self._prepare_message_data(ml, request, allocated_qty)
|
||||
message = self._stock_request_confirm_done_message_content(message_data)
|
||||
request.message_post(body=message, subtype="mail.mt_comment")
|
||||
request.check_done()
|
||||
return res
|
||||
|
||||
@@ -5,33 +5,35 @@ from odoo import api, fields, models
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
_inherit = "stock.picking"
|
||||
|
||||
stock_request_ids = fields.One2many(comodel_name='stock.request',
|
||||
string='Stock Requests',
|
||||
compute='_compute_stock_request_ids')
|
||||
stock_request_count = fields.Integer('Stock Request #',
|
||||
compute='_compute_stock_request_ids')
|
||||
stock_request_ids = fields.One2many(
|
||||
comodel_name="stock.request",
|
||||
string="Stock Requests",
|
||||
compute="_compute_stock_request_ids",
|
||||
)
|
||||
stock_request_count = fields.Integer(
|
||||
"Stock Request #", compute="_compute_stock_request_ids"
|
||||
)
|
||||
|
||||
@api.depends('move_lines')
|
||||
@api.depends("move_lines")
|
||||
def _compute_stock_request_ids(self):
|
||||
for rec in self:
|
||||
rec.stock_request_ids = rec.move_lines.mapped('stock_request_ids')
|
||||
rec.stock_request_ids = rec.move_lines.mapped("stock_request_ids")
|
||||
rec.stock_request_count = len(rec.stock_request_ids)
|
||||
|
||||
def action_view_stock_request(self):
|
||||
"""
|
||||
:return dict: dictionary value for created view
|
||||
"""
|
||||
action = self.env.ref(
|
||||
'stock_request.action_stock_request_form').read()[0]
|
||||
action = self.env.ref("stock_request.action_stock_request_form").read()[0]
|
||||
|
||||
requests = self.mapped('stock_request_ids')
|
||||
requests = self.mapped("stock_request_ids")
|
||||
if len(requests) > 1:
|
||||
action['domain'] = [('id', 'in', requests.ids)]
|
||||
action["domain"] = [("id", "in", requests.ids)]
|
||||
elif requests:
|
||||
action['views'] = [
|
||||
(self.env.ref('stock_request.view_stock_request_form').id,
|
||||
'form')]
|
||||
action['res_id'] = requests.id
|
||||
action["views"] = [
|
||||
(self.env.ref("stock_request.view_stock_request_form").id, "form")
|
||||
]
|
||||
action["res_id"] = requests.id
|
||||
return action
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.tools import float_compare
|
||||
|
||||
from odoo.addons import decimal_precision as dp
|
||||
|
||||
REQUEST_STATES = [
|
||||
('draft', 'Draft'),
|
||||
('open', 'In progress'),
|
||||
('done', 'Done'),
|
||||
('cancel', 'Cancelled')]
|
||||
("draft", "Draft"),
|
||||
("open", "In progress"),
|
||||
("done", "Done"),
|
||||
("cancel", "Cancelled"),
|
||||
]
|
||||
|
||||
|
||||
class StockRequest(models.Model):
|
||||
_name = "stock.request"
|
||||
_description = "Stock Request"
|
||||
_inherit = 'stock.request.abstract'
|
||||
_order = 'id desc'
|
||||
_inherit = "stock.request.abstract"
|
||||
_order = "id desc"
|
||||
|
||||
def __get_request_states(self):
|
||||
return REQUEST_STATES
|
||||
@@ -26,7 +28,7 @@ class StockRequest(models.Model):
|
||||
return self.__get_request_states()
|
||||
|
||||
def _get_default_requested_by(self):
|
||||
return self.env['res.users'].browse(self.env.uid)
|
||||
return self.env["res.users"].browse(self.env.uid)
|
||||
|
||||
@staticmethod
|
||||
def _get_expected_date():
|
||||
@@ -39,178 +41,177 @@ class StockRequest(models.Model):
|
||||
res = self._get_expected_date()
|
||||
return res
|
||||
|
||||
name = fields.Char(
|
||||
states={'draft': [('readonly', False)]}
|
||||
)
|
||||
name = fields.Char(states={"draft": [("readonly", False)]})
|
||||
state = fields.Selection(
|
||||
selection=_get_request_states, string='Status',
|
||||
copy=False, default='draft', index=True,
|
||||
readonly=True, track_visibility='onchange',
|
||||
selection=_get_request_states,
|
||||
string="Status",
|
||||
copy=False,
|
||||
default="draft",
|
||||
index=True,
|
||||
readonly=True,
|
||||
track_visibility="onchange",
|
||||
)
|
||||
requested_by = fields.Many2one(
|
||||
'res.users', 'Requested by', required=True,
|
||||
track_visibility='onchange',
|
||||
"res.users",
|
||||
"Requested by",
|
||||
required=True,
|
||||
track_visibility="onchange",
|
||||
default=lambda s: s._get_default_requested_by(),
|
||||
)
|
||||
expected_date = fields.Datetime(
|
||||
'Expected Date', default=lambda s: s._get_default_expected_date(),
|
||||
index=True, required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
"Expected Date",
|
||||
default=lambda s: s._get_default_expected_date(),
|
||||
index=True,
|
||||
required=True,
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
help="Date when you expect to receive the goods.",
|
||||
)
|
||||
picking_policy = fields.Selection([
|
||||
('direct', 'Receive each product when available'),
|
||||
('one', 'Receive all products at once')],
|
||||
string='Shipping Policy', required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
default='direct',
|
||||
picking_policy = fields.Selection(
|
||||
[
|
||||
("direct", "Receive each product when available"),
|
||||
("one", "Receive all products at once"),
|
||||
],
|
||||
string="Shipping Policy",
|
||||
required=True,
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
default="direct",
|
||||
)
|
||||
move_ids = fields.One2many(
|
||||
comodel_name="stock.move",
|
||||
compute="_compute_move_ids",
|
||||
string="Stock Moves",
|
||||
readonly=True,
|
||||
)
|
||||
picking_ids = fields.One2many(
|
||||
"stock.picking",
|
||||
compute="_compute_picking_ids",
|
||||
string="Pickings",
|
||||
readonly=True,
|
||||
)
|
||||
move_ids = fields.One2many(comodel_name='stock.move',
|
||||
compute='_compute_move_ids',
|
||||
string='Stock Moves', readonly=True,
|
||||
)
|
||||
picking_ids = fields.One2many('stock.picking',
|
||||
compute='_compute_picking_ids',
|
||||
string='Pickings', readonly=True,
|
||||
)
|
||||
qty_in_progress = fields.Float(
|
||||
'Qty In Progress', digits=dp.get_precision('Product Unit of Measure'),
|
||||
readonly=True, compute='_compute_qty', store=True,
|
||||
"Qty In Progress",
|
||||
digits=dp.get_precision("Product Unit of Measure"),
|
||||
readonly=True,
|
||||
compute="_compute_qty",
|
||||
store=True,
|
||||
help="Quantity in progress.",
|
||||
)
|
||||
qty_done = fields.Float(
|
||||
'Qty Done', digits=dp.get_precision('Product Unit of Measure'),
|
||||
readonly=True, compute='_compute_qty', store=True,
|
||||
"Qty Done",
|
||||
digits=dp.get_precision("Product Unit of Measure"),
|
||||
readonly=True,
|
||||
compute="_compute_qty",
|
||||
store=True,
|
||||
help="Quantity completed",
|
||||
)
|
||||
picking_count = fields.Integer(string='Delivery Orders',
|
||||
compute='_compute_picking_ids',
|
||||
readonly=True,
|
||||
)
|
||||
allocation_ids = fields.One2many(comodel_name='stock.request.allocation',
|
||||
inverse_name='stock_request_id',
|
||||
string='Stock Request Allocation')
|
||||
order_id = fields.Many2one(
|
||||
'stock.request.order',
|
||||
readonly=True,
|
||||
picking_count = fields.Integer(
|
||||
string="Delivery Orders", compute="_compute_picking_ids", readonly=True
|
||||
)
|
||||
allocation_ids = fields.One2many(
|
||||
comodel_name="stock.request.allocation",
|
||||
inverse_name="stock_request_id",
|
||||
string="Stock Request Allocation",
|
||||
)
|
||||
order_id = fields.Many2one("stock.request.order", readonly=True)
|
||||
warehouse_id = fields.Many2one(
|
||||
states={'draft': [('readonly', False)]}, readonly=True
|
||||
states={"draft": [("readonly", False)]}, readonly=True
|
||||
)
|
||||
location_id = fields.Many2one(
|
||||
states={'draft': [('readonly', False)]}, readonly=True
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
states={'draft': [('readonly', False)]}, readonly=True
|
||||
states={"draft": [("readonly", False)]}, readonly=True
|
||||
)
|
||||
product_id = fields.Many2one(states={"draft": [("readonly", False)]}, readonly=True)
|
||||
product_uom_id = fields.Many2one(
|
||||
states={'draft': [('readonly', False)]}, readonly=True
|
||||
states={"draft": [("readonly", False)]}, readonly=True
|
||||
)
|
||||
product_uom_qty = fields.Float(
|
||||
states={'draft': [('readonly', False)]}, readonly=True
|
||||
states={"draft": [("readonly", False)]}, readonly=True
|
||||
)
|
||||
procurement_group_id = fields.Many2one(
|
||||
states={'draft': [('readonly', False)]}, readonly=True
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
states={'draft': [('readonly', False)]}, readonly=True
|
||||
)
|
||||
route_id = fields.Many2one(
|
||||
states={'draft': [('readonly', False)]}, readonly=True
|
||||
states={"draft": [("readonly", False)]}, readonly=True
|
||||
)
|
||||
company_id = fields.Many2one(states={"draft": [("readonly", False)]}, readonly=True)
|
||||
route_id = fields.Many2one(states={"draft": [("readonly", False)]}, readonly=True)
|
||||
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique(name, company_id)',
|
||||
'Stock Request name must be unique'),
|
||||
("name_uniq", "unique(name, company_id)", "Stock Request name must be unique")
|
||||
]
|
||||
|
||||
@api.depends('allocation_ids')
|
||||
@api.depends("allocation_ids")
|
||||
def _compute_move_ids(self):
|
||||
for request in self:
|
||||
request.move_ids = request.allocation_ids.mapped('stock_move_id')
|
||||
request.move_ids = request.allocation_ids.mapped("stock_move_id")
|
||||
|
||||
@api.depends('allocation_ids')
|
||||
@api.depends("allocation_ids")
|
||||
def _compute_picking_ids(self):
|
||||
for request in self:
|
||||
request.picking_count = 0
|
||||
request.picking_ids = self.env['stock.picking']
|
||||
request.picking_ids = self.env["stock.picking"]
|
||||
request.picking_ids = request.move_ids.filtered(
|
||||
lambda m: m.state != 'cancel').mapped('picking_id')
|
||||
lambda m: m.state != "cancel"
|
||||
).mapped("picking_id")
|
||||
request.picking_count = len(request.picking_ids)
|
||||
|
||||
@api.depends('allocation_ids', 'allocation_ids.stock_move_id.state',
|
||||
'allocation_ids.stock_move_id.move_line_ids',
|
||||
'allocation_ids.stock_move_id.move_line_ids.qty_done')
|
||||
@api.depends(
|
||||
"allocation_ids",
|
||||
"allocation_ids.stock_move_id.state",
|
||||
"allocation_ids.stock_move_id.move_line_ids",
|
||||
"allocation_ids.stock_move_id.move_line_ids.qty_done",
|
||||
)
|
||||
def _compute_qty(self):
|
||||
for request in self:
|
||||
done_qty = sum(request.allocation_ids.mapped(
|
||||
'allocated_product_qty'))
|
||||
open_qty = sum(request.allocation_ids.mapped('open_product_qty'))
|
||||
done_qty = sum(request.allocation_ids.mapped("allocated_product_qty"))
|
||||
open_qty = sum(request.allocation_ids.mapped("open_product_qty"))
|
||||
request.qty_done = request.product_id.uom_id._compute_quantity(
|
||||
done_qty, request.product_uom_id)
|
||||
request.qty_in_progress = \
|
||||
request.product_id.uom_id._compute_quantity(
|
||||
open_qty, request.product_uom_id)
|
||||
done_qty, request.product_uom_id
|
||||
)
|
||||
request.qty_in_progress = request.product_id.uom_id._compute_quantity(
|
||||
open_qty, request.product_uom_id
|
||||
)
|
||||
|
||||
@api.constrains('order_id', 'requested_by')
|
||||
@api.constrains("order_id", "requested_by")
|
||||
def check_order_requested_by(self):
|
||||
if self.order_id and self.order_id.requested_by != self.requested_by:
|
||||
raise ValidationError(_(
|
||||
'Requested by must be equal to the order'
|
||||
))
|
||||
raise ValidationError(_("Requested by must be equal to the order"))
|
||||
|
||||
@api.constrains('order_id', 'warehouse_id')
|
||||
@api.constrains("order_id", "warehouse_id")
|
||||
def check_order_warehouse_id(self):
|
||||
if self.order_id and self.order_id.warehouse_id != self.warehouse_id:
|
||||
raise ValidationError(_(
|
||||
'Warehouse must be equal to the order'
|
||||
))
|
||||
raise ValidationError(_("Warehouse must be equal to the order"))
|
||||
|
||||
@api.constrains('order_id', 'location_id')
|
||||
@api.constrains("order_id", "location_id")
|
||||
def check_order_location(self):
|
||||
if self.order_id and self.order_id.location_id != self.location_id:
|
||||
raise ValidationError(_(
|
||||
'Location must be equal to the order'
|
||||
))
|
||||
raise ValidationError(_("Location must be equal to the order"))
|
||||
|
||||
@api.constrains('order_id', 'procurement_group_id')
|
||||
@api.constrains("order_id", "procurement_group_id")
|
||||
def check_order_procurement_group(self):
|
||||
if (
|
||||
self.order_id and
|
||||
self.order_id.procurement_group_id != self.procurement_group_id
|
||||
self.order_id
|
||||
and self.order_id.procurement_group_id != self.procurement_group_id
|
||||
):
|
||||
raise ValidationError(_(
|
||||
'Procurement group must be equal to the order'
|
||||
))
|
||||
raise ValidationError(_("Procurement group must be equal to the order"))
|
||||
|
||||
@api.constrains('order_id', 'company_id')
|
||||
@api.constrains("order_id", "company_id")
|
||||
def check_order_company(self):
|
||||
if self.order_id and self.order_id.company_id != self.company_id:
|
||||
raise ValidationError(_(
|
||||
'Company must be equal to the order'
|
||||
))
|
||||
raise ValidationError(_("Company must be equal to the order"))
|
||||
|
||||
@api.constrains('order_id', 'expected_date')
|
||||
@api.constrains("order_id", "expected_date")
|
||||
def check_order_expected_date(self):
|
||||
if self.order_id and self.order_id.expected_date != self.expected_date:
|
||||
raise ValidationError(_(
|
||||
'Expected date must be equal to the order'
|
||||
))
|
||||
raise ValidationError(_("Expected date must be equal to the order"))
|
||||
|
||||
@api.constrains('order_id', 'picking_policy')
|
||||
@api.constrains("order_id", "picking_policy")
|
||||
def check_order_picking_policy(self):
|
||||
if (
|
||||
self.order_id and
|
||||
self.order_id.picking_policy != self.picking_policy
|
||||
):
|
||||
raise ValidationError(_(
|
||||
'The picking policy must be equal to the order'
|
||||
))
|
||||
if self.order_id and self.order_id.picking_policy != self.picking_policy:
|
||||
raise ValidationError(_("The picking policy must be equal to the order"))
|
||||
|
||||
@api.multi
|
||||
def _action_confirm(self):
|
||||
self._action_launch_procurement_rule()
|
||||
self.state = 'open'
|
||||
self.state = "open"
|
||||
|
||||
@api.multi
|
||||
def action_confirm(self):
|
||||
@@ -218,30 +219,35 @@ class StockRequest(models.Model):
|
||||
return True
|
||||
|
||||
def action_draft(self):
|
||||
self.write({'state': 'draft'})
|
||||
self.write({"state": "draft"})
|
||||
return True
|
||||
|
||||
def action_cancel(self):
|
||||
self.sudo().mapped('move_ids')._action_cancel()
|
||||
self.state = 'cancel'
|
||||
self.sudo().mapped("move_ids")._action_cancel()
|
||||
self.state = "cancel"
|
||||
return True
|
||||
|
||||
def action_done(self):
|
||||
self.state = 'done'
|
||||
self.state = "done"
|
||||
if self.order_id:
|
||||
self.order_id.check_done()
|
||||
return True
|
||||
|
||||
def check_done(self):
|
||||
precision = self.env['decimal.precision'].precision_get(
|
||||
'Product Unit of Measure')
|
||||
precision = self.env["decimal.precision"].precision_get(
|
||||
"Product Unit of Measure"
|
||||
)
|
||||
for request in self:
|
||||
allocated_qty = sum(request.allocation_ids.mapped(
|
||||
'allocated_product_qty'))
|
||||
allocated_qty = sum(request.allocation_ids.mapped("allocated_product_qty"))
|
||||
qty_done = request.product_id.uom_id._compute_quantity(
|
||||
allocated_qty, request.product_uom_id)
|
||||
if float_compare(qty_done, request.product_uom_qty,
|
||||
precision_digits=precision) >= 0:
|
||||
allocated_qty, request.product_uom_id
|
||||
)
|
||||
if (
|
||||
float_compare(
|
||||
qty_done, request.product_uom_qty, precision_digits=precision
|
||||
)
|
||||
>= 0
|
||||
):
|
||||
request.action_done()
|
||||
return True
|
||||
|
||||
@@ -254,17 +260,16 @@ class StockRequest(models.Model):
|
||||
move/po creation.
|
||||
"""
|
||||
return {
|
||||
'date_planned': self.expected_date,
|
||||
'warehouse_id': self.warehouse_id,
|
||||
'stock_request_allocation_ids': self.id,
|
||||
'group_id': group_id or self.procurement_group_id.id or False,
|
||||
'route_ids': self.route_id,
|
||||
'stock_request_id': self.id,
|
||||
"date_planned": self.expected_date,
|
||||
"warehouse_id": self.warehouse_id,
|
||||
"stock_request_allocation_ids": self.id,
|
||||
"group_id": group_id or self.procurement_group_id.id or False,
|
||||
"route_ids": self.route_id,
|
||||
"stock_request_id": self.id,
|
||||
}
|
||||
|
||||
def _skip_procurement(self):
|
||||
return self.state != 'draft' or \
|
||||
self.product_id.type not in ('consu', 'product')
|
||||
return self.state != "draft" or self.product_id.type not in ("consu", "product")
|
||||
|
||||
@api.multi
|
||||
def _action_launch_procurement_rule(self):
|
||||
@@ -275,61 +280,63 @@ class StockRequest(models.Model):
|
||||
'_run_buy' or '_run_manufacture'
|
||||
depending on the stock request product rule.
|
||||
"""
|
||||
precision = self.env['decimal.precision'].precision_get(
|
||||
'Product Unit of Measure')
|
||||
precision = self.env["decimal.precision"].precision_get(
|
||||
"Product Unit of Measure"
|
||||
)
|
||||
errors = []
|
||||
for request in self:
|
||||
if request._skip_procurement():
|
||||
continue
|
||||
qty = 0.0
|
||||
for move in request.move_ids.filtered(
|
||||
lambda r: r.state != 'cancel'):
|
||||
for move in request.move_ids.filtered(lambda r: r.state != "cancel"):
|
||||
qty += move.product_qty
|
||||
|
||||
if float_compare(qty, request.product_qty,
|
||||
precision_digits=precision) >= 0:
|
||||
if float_compare(qty, request.product_qty, precision_digits=precision) >= 0:
|
||||
continue
|
||||
|
||||
values = request._prepare_procurement_values(
|
||||
group_id=request.procurement_group_id)
|
||||
group_id=request.procurement_group_id
|
||||
)
|
||||
try:
|
||||
# We launch with sudo because potentially we could create
|
||||
# objects that the user is not authorized to create, such
|
||||
# as PO.
|
||||
self.env['procurement.group'].sudo().run(
|
||||
request.product_id, request.product_uom_qty,
|
||||
self.env["procurement.group"].sudo().run(
|
||||
request.product_id,
|
||||
request.product_uom_qty,
|
||||
request.product_uom_id,
|
||||
request.location_id, request.name,
|
||||
request.name, values)
|
||||
request.location_id,
|
||||
request.name,
|
||||
request.name,
|
||||
values,
|
||||
)
|
||||
except UserError as error:
|
||||
errors.append(error.name)
|
||||
if errors:
|
||||
raise UserError('\n'.join(errors))
|
||||
raise UserError("\n".join(errors))
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def action_view_transfer(self):
|
||||
action = self.env.ref('stock.action_picking_tree_all').read()[0]
|
||||
action = self.env.ref("stock.action_picking_tree_all").read()[0]
|
||||
|
||||
pickings = self.mapped('picking_ids')
|
||||
pickings = self.mapped("picking_ids")
|
||||
if len(pickings) > 1:
|
||||
action['domain'] = [('id', 'in', pickings.ids)]
|
||||
action["domain"] = [("id", "in", pickings.ids)]
|
||||
elif pickings:
|
||||
action['views'] = [
|
||||
(self.env.ref('stock.view_picking_form').id, 'form')]
|
||||
action['res_id'] = pickings.id
|
||||
action["views"] = [(self.env.ref("stock.view_picking_form").id, "form")]
|
||||
action["res_id"] = pickings.id
|
||||
return action
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
upd_vals = vals.copy()
|
||||
if upd_vals.get('name', '/') == '/':
|
||||
upd_vals['name'] = self.env['ir.sequence'].next_by_code(
|
||||
'stock.request')
|
||||
if upd_vals.get("name", "/") == "/":
|
||||
upd_vals["name"] = self.env["ir.sequence"].next_by_code("stock.request")
|
||||
return super().create(upd_vals)
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
if self.filtered(lambda r: r.state != 'draft'):
|
||||
raise UserError(_('Only requests on draft state can be unlinked'))
|
||||
if self.filtered(lambda r: r.state != "draft"):
|
||||
raise UserError(_("Only requests on draft state can be unlinked"))
|
||||
return super(StockRequest, self).unlink()
|
||||
|
||||
@@ -1,118 +1,133 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
from odoo.addons import decimal_precision as dp
|
||||
|
||||
|
||||
class StockRequest(models.AbstractModel):
|
||||
_name = "stock.request.abstract"
|
||||
_description = "Stock Request Template"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_inherit = ["mail.thread", "mail.activity.mixin"]
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super(StockRequest, self).default_get(fields)
|
||||
warehouse = None
|
||||
if 'warehouse_id' not in res and res.get('company_id'):
|
||||
warehouse = self.env['stock.warehouse'].search(
|
||||
[('company_id', '=', res['company_id'])], limit=1)
|
||||
if "warehouse_id" not in res and res.get("company_id"):
|
||||
warehouse = self.env["stock.warehouse"].search(
|
||||
[("company_id", "=", res["company_id"])], limit=1
|
||||
)
|
||||
if warehouse:
|
||||
res['warehouse_id'] = warehouse.id
|
||||
res['location_id'] = warehouse.lot_stock_id.id
|
||||
res["warehouse_id"] = warehouse.id
|
||||
res["location_id"] = warehouse.lot_stock_id.id
|
||||
return res
|
||||
|
||||
@api.depends('product_id', 'product_uom_id', 'product_uom_qty',
|
||||
'product_id.product_tmpl_id.uom_id')
|
||||
@api.depends(
|
||||
"product_id",
|
||||
"product_uom_id",
|
||||
"product_uom_qty",
|
||||
"product_id.product_tmpl_id.uom_id",
|
||||
)
|
||||
def _compute_product_qty(self):
|
||||
for rec in self:
|
||||
rec.product_qty = rec.product_uom_id._compute_quantity(
|
||||
rec.product_uom_qty, rec.product_id.product_tmpl_id.uom_id)
|
||||
rec.product_uom_qty, rec.product_id.product_tmpl_id.uom_id
|
||||
)
|
||||
|
||||
name = fields.Char(
|
||||
'Name', copy=False, required=True, readonly=True,
|
||||
default='/')
|
||||
name = fields.Char("Name", copy=False, required=True, readonly=True, default="/")
|
||||
warehouse_id = fields.Many2one(
|
||||
'stock.warehouse', 'Warehouse',
|
||||
ondelete="cascade", required=True,
|
||||
"stock.warehouse", "Warehouse", ondelete="cascade", required=True
|
||||
)
|
||||
location_id = fields.Many2one(
|
||||
'stock.location', 'Location',
|
||||
domain=[('usage', 'in', ['internal', 'transit'])],
|
||||
ondelete="cascade", required=True,
|
||||
"stock.location",
|
||||
"Location",
|
||||
domain=[("usage", "in", ["internal", "transit"])],
|
||||
ondelete="cascade",
|
||||
required=True,
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
'product.product', 'Product',
|
||||
domain=[('type', 'in', ['product', 'consu'])], ondelete='cascade',
|
||||
"product.product",
|
||||
"Product",
|
||||
domain=[("type", "in", ["product", "consu"])],
|
||||
ondelete="cascade",
|
||||
required=True,
|
||||
)
|
||||
allow_virtual_location = fields.Boolean(
|
||||
related='company_id.stock_request_allow_virtual_loc',
|
||||
readonly=True,
|
||||
related="company_id.stock_request_allow_virtual_loc", readonly=True
|
||||
)
|
||||
product_uom_id = fields.Many2one(
|
||||
'uom.uom', 'Product Unit of Measure',
|
||||
"uom.uom",
|
||||
"Product Unit of Measure",
|
||||
required=True,
|
||||
default=lambda self: self._context.get('product_uom_id', False),
|
||||
default=lambda self: self._context.get("product_uom_id", False),
|
||||
)
|
||||
product_uom_qty = fields.Float(
|
||||
'Quantity', digits=dp.get_precision('Product Unit of Measure'),
|
||||
"Quantity",
|
||||
digits=dp.get_precision("Product Unit of Measure"),
|
||||
required=True,
|
||||
help="Quantity, specified in the unit of measure indicated in the "
|
||||
"request.",
|
||||
help="Quantity, specified in the unit of measure indicated in the " "request.",
|
||||
)
|
||||
product_qty = fields.Float(
|
||||
'Real Quantity', compute='_compute_product_qty',
|
||||
store=True, copy=False,
|
||||
digits=dp.get_precision('Product Unit of Measure'),
|
||||
help='Quantity in the default UoM of the product',
|
||||
"Real Quantity",
|
||||
compute="_compute_product_qty",
|
||||
store=True,
|
||||
copy=False,
|
||||
digits=dp.get_precision("Product Unit of Measure"),
|
||||
help="Quantity in the default UoM of the product",
|
||||
)
|
||||
procurement_group_id = fields.Many2one(
|
||||
'procurement.group', 'Procurement Group',
|
||||
"procurement.group",
|
||||
"Procurement Group",
|
||||
help="Moves created through this stock request will be put in this "
|
||||
"procurement group. If none is given, the moves generated by "
|
||||
"procurement rules will be grouped into one big picking.",
|
||||
"procurement group. If none is given, the moves generated by "
|
||||
"procurement rules will be grouped into one big picking.",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
'res.company', 'Company', required=True,
|
||||
default=lambda self: self.env['res.company']._company_default_get(
|
||||
'stock.request'),
|
||||
"res.company",
|
||||
"Company",
|
||||
required=True,
|
||||
default=lambda self: self.env["res.company"]._company_default_get(
|
||||
"stock.request"
|
||||
),
|
||||
)
|
||||
route_id = fields.Many2one(
|
||||
"stock.location.route",
|
||||
string="Route",
|
||||
domain="[('id', 'in', route_ids)]",
|
||||
ondelete="restrict",
|
||||
)
|
||||
route_id = fields.Many2one('stock.location.route', string='Route',
|
||||
domain="[('id', 'in', route_ids)]",
|
||||
ondelete='restrict')
|
||||
|
||||
route_ids = fields.Many2many(
|
||||
'stock.location.route', string='Routes',
|
||||
compute='_compute_route_ids',
|
||||
"stock.location.route",
|
||||
string="Routes",
|
||||
compute="_compute_route_ids",
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique(name, company_id)',
|
||||
'Name must be unique'),
|
||||
("name_uniq", "unique(name, company_id)", "Name must be unique")
|
||||
]
|
||||
|
||||
@api.depends('product_id', 'warehouse_id', 'location_id')
|
||||
@api.depends("product_id", "warehouse_id", "location_id")
|
||||
def _compute_route_ids(self):
|
||||
route_obj = self.env['stock.location.route']
|
||||
for wh in self.mapped('warehouse_id'):
|
||||
wh_routes = route_obj.search(
|
||||
[('warehouse_ids', '=', wh.id)])
|
||||
route_obj = self.env["stock.location.route"]
|
||||
for wh in self.mapped("warehouse_id"):
|
||||
wh_routes = route_obj.search([("warehouse_ids", "=", wh.id)])
|
||||
for record in self.filtered(lambda r: r.warehouse_id == wh):
|
||||
routes = route_obj
|
||||
if record.product_id:
|
||||
routes += record.product_id.mapped(
|
||||
'route_ids'
|
||||
) | record.product_id.mapped(
|
||||
'categ_id'
|
||||
).mapped('total_route_ids')
|
||||
"route_ids"
|
||||
) | record.product_id.mapped("categ_id").mapped("total_route_ids")
|
||||
if record.warehouse_id:
|
||||
routes |= wh_routes
|
||||
parents = record.get_parents().ids
|
||||
record.route_ids = routes.filtered(lambda r: any(
|
||||
p.location_id.id in parents for p in r.rule_ids))
|
||||
record.route_ids = routes.filtered(
|
||||
lambda r: any(p.location_id.id in parents for p in r.rule_ids)
|
||||
)
|
||||
|
||||
def get_parents(self):
|
||||
location = self.location_id
|
||||
@@ -122,54 +137,80 @@ class StockRequest(models.AbstractModel):
|
||||
result |= location
|
||||
return result
|
||||
|
||||
@api.constrains('company_id', 'product_id', 'warehouse_id',
|
||||
'location_id', 'route_id')
|
||||
@api.constrains(
|
||||
"company_id", "product_id", "warehouse_id", "location_id", "route_id"
|
||||
)
|
||||
def _check_company_constrains(self):
|
||||
""" Check if the related models have the same company """
|
||||
for rec in self:
|
||||
if rec.product_id.company_id and \
|
||||
rec.product_id.company_id != rec.company_id:
|
||||
if (
|
||||
rec.product_id.company_id
|
||||
and rec.product_id.company_id != rec.company_id
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You have entered a product that is assigned '
|
||||
'to another company.'))
|
||||
if rec.location_id.company_id and \
|
||||
rec.location_id.company_id != rec.company_id:
|
||||
_(
|
||||
"You have entered a product that is assigned "
|
||||
"to another company."
|
||||
)
|
||||
)
|
||||
if (
|
||||
rec.location_id.company_id
|
||||
and rec.location_id.company_id != rec.company_id
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You have entered a location that is '
|
||||
'assigned to another company.'))
|
||||
_(
|
||||
"You have entered a location that is "
|
||||
"assigned to another company."
|
||||
)
|
||||
)
|
||||
if rec.warehouse_id.company_id != rec.company_id:
|
||||
raise ValidationError(
|
||||
_('You have entered a warehouse that is '
|
||||
'assigned to another company.'))
|
||||
if rec.route_id and rec.route_id.company_id and \
|
||||
rec.route_id.company_id != rec.company_id:
|
||||
_(
|
||||
"You have entered a warehouse that is "
|
||||
"assigned to another company."
|
||||
)
|
||||
)
|
||||
if (
|
||||
rec.route_id
|
||||
and rec.route_id.company_id
|
||||
and rec.route_id.company_id != rec.company_id
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You have entered a route that is '
|
||||
'assigned to another company.'))
|
||||
_(
|
||||
"You have entered a route that is "
|
||||
"assigned to another company."
|
||||
)
|
||||
)
|
||||
|
||||
@api.constrains('product_id')
|
||||
@api.constrains("product_id")
|
||||
def _check_product_uom(self):
|
||||
''' Check if the UoM has the same category as the
|
||||
product standard UoM '''
|
||||
if any(request.product_id.uom_id.category_id !=
|
||||
request.product_uom_id.category_id for request in self):
|
||||
""" Check if the UoM has the same category as the
|
||||
product standard UoM """
|
||||
if any(
|
||||
request.product_id.uom_id.category_id != request.product_uom_id.category_id
|
||||
for request in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You have to select a product unit of measure in the '
|
||||
'same category than the default unit '
|
||||
'of measure of the product'))
|
||||
_(
|
||||
"You have to select a product unit of measure in the "
|
||||
"same category than the default unit "
|
||||
"of measure of the product"
|
||||
)
|
||||
)
|
||||
|
||||
@api.constrains('product_qty')
|
||||
@api.constrains("product_qty")
|
||||
def _check_qty(self):
|
||||
for rec in self:
|
||||
if rec.product_qty <= 0:
|
||||
raise ValueError(_('Stock Request product quantity has to be'
|
||||
' strictly positive.'))
|
||||
raise ValueError(
|
||||
_("Stock Request product quantity has to be" " strictly positive.")
|
||||
)
|
||||
|
||||
@api.onchange('warehouse_id')
|
||||
@api.onchange("warehouse_id")
|
||||
def onchange_warehouse_id(self):
|
||||
""" Finds location id for changed warehouse. """
|
||||
res = {'domain': {}}
|
||||
if self._name == 'stock.request' and self.order_id:
|
||||
res = {"domain": {}}
|
||||
if self._name == "stock.request" and self.order_id:
|
||||
# When the stock request is created from an order the wh and
|
||||
# location are taken from the order and we rely on it to change
|
||||
# all request associated. Thus, no need to apply
|
||||
@@ -183,42 +224,41 @@ class StockRequest(models.AbstractModel):
|
||||
self.company_id = self.warehouse_id.company_id
|
||||
return res
|
||||
|
||||
@api.onchange('location_id')
|
||||
@api.onchange("location_id")
|
||||
def onchange_location_id(self):
|
||||
if self.location_id:
|
||||
loc_wh = self.location_id.sudo().get_warehouse()
|
||||
if loc_wh and self.warehouse_id != loc_wh:
|
||||
self.warehouse_id = loc_wh
|
||||
self.with_context(
|
||||
no_change_childs=True).onchange_warehouse_id()
|
||||
self.with_context(no_change_childs=True).onchange_warehouse_id()
|
||||
|
||||
@api.onchange('allow_virtual_location')
|
||||
@api.onchange("allow_virtual_location")
|
||||
def onchange_allow_virtual_location(self):
|
||||
if self.allow_virtual_location:
|
||||
return {'domain': {'location_id': []}}
|
||||
return {"domain": {"location_id": []}}
|
||||
|
||||
@api.onchange('company_id')
|
||||
@api.onchange("company_id")
|
||||
def onchange_company_id(self):
|
||||
""" Sets a default warehouse when the company is changed and limits
|
||||
the user selection of warehouses. """
|
||||
if self.company_id and (
|
||||
not self.warehouse_id or
|
||||
self.warehouse_id.company_id != self.company_id):
|
||||
self.warehouse_id = self.env['stock.warehouse'].search(
|
||||
[('company_id', '=', self.company_id.id)], limit=1)
|
||||
not self.warehouse_id or self.warehouse_id.company_id != self.company_id
|
||||
):
|
||||
self.warehouse_id = self.env["stock.warehouse"].search(
|
||||
[("company_id", "=", self.company_id.id)], limit=1
|
||||
)
|
||||
self.onchange_warehouse_id()
|
||||
|
||||
return {
|
||||
'domain': {
|
||||
'warehouse_id': [('company_id', '=', self.company_id.id)]}}
|
||||
return {"domain": {"warehouse_id": [("company_id", "=", self.company_id.id)]}}
|
||||
|
||||
@api.onchange('product_id')
|
||||
@api.onchange("product_id")
|
||||
def onchange_product_id(self):
|
||||
res = {'domain': {}}
|
||||
res = {"domain": {}}
|
||||
if self.product_id:
|
||||
self.product_uom_id = self.product_id.uom_id.id
|
||||
res['domain']['product_uom_id'] = [
|
||||
('category_id', '=', self.product_id.uom_id.category_id.id)]
|
||||
res["domain"]["product_uom_id"] = [
|
||||
("category_id", "=", self.product_id.uom_id.category_id.id)
|
||||
]
|
||||
return res
|
||||
res['domain']['product_uom_id'] = []
|
||||
res["domain"]["product_uom_id"] = []
|
||||
return res
|
||||
|
||||
@@ -5,67 +5,84 @@ from odoo import api, fields, models
|
||||
|
||||
|
||||
class StockRequestAllocation(models.Model):
|
||||
_name = 'stock.request.allocation'
|
||||
_description = 'Stock Request Allocation'
|
||||
_name = "stock.request.allocation"
|
||||
_description = "Stock Request Allocation"
|
||||
|
||||
stock_request_id = fields.Many2one(string='Stock Request',
|
||||
comodel_name='stock.request',
|
||||
required=True, ondelete='cascade',
|
||||
)
|
||||
company_id = fields.Many2one(string='Company',
|
||||
comodel_name='res.company',
|
||||
readonly=True,
|
||||
related='stock_request_id.company_id',
|
||||
store=True,
|
||||
)
|
||||
stock_move_id = fields.Many2one(string='Stock Move',
|
||||
comodel_name='stock.move',
|
||||
required=True, ondelete='cascade',
|
||||
)
|
||||
product_id = fields.Many2one(string='Product',
|
||||
comodel_name='product.product',
|
||||
related='stock_request_id.product_id',
|
||||
readonly=True,
|
||||
)
|
||||
product_uom_id = fields.Many2one(string='UoM', comodel_name='uom.uom',
|
||||
related='stock_request_id.product_uom_id',
|
||||
readonly=True,
|
||||
)
|
||||
stock_request_id = fields.Many2one(
|
||||
string="Stock Request",
|
||||
comodel_name="stock.request",
|
||||
required=True,
|
||||
ondelete="cascade",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
string="Company",
|
||||
comodel_name="res.company",
|
||||
readonly=True,
|
||||
related="stock_request_id.company_id",
|
||||
store=True,
|
||||
)
|
||||
stock_move_id = fields.Many2one(
|
||||
string="Stock Move",
|
||||
comodel_name="stock.move",
|
||||
required=True,
|
||||
ondelete="cascade",
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
string="Product",
|
||||
comodel_name="product.product",
|
||||
related="stock_request_id.product_id",
|
||||
readonly=True,
|
||||
)
|
||||
product_uom_id = fields.Many2one(
|
||||
string="UoM",
|
||||
comodel_name="uom.uom",
|
||||
related="stock_request_id.product_uom_id",
|
||||
readonly=True,
|
||||
)
|
||||
requested_product_uom_qty = fields.Float(
|
||||
'Requested Quantity (UoM)',
|
||||
help='Quantity of the stock request allocated to the stock move, '
|
||||
'in the UoM of the Stock Request',
|
||||
"Requested Quantity (UoM)",
|
||||
help="Quantity of the stock request allocated to the stock move, "
|
||||
"in the UoM of the Stock Request",
|
||||
)
|
||||
requested_product_qty = fields.Float(
|
||||
'Requested Quantity',
|
||||
help='Quantity of the stock request allocated to the stock move, '
|
||||
'in the default UoM of the product',
|
||||
compute='_compute_requested_product_qty'
|
||||
"Requested Quantity",
|
||||
help="Quantity of the stock request allocated to the stock move, "
|
||||
"in the default UoM of the product",
|
||||
compute="_compute_requested_product_qty",
|
||||
)
|
||||
allocated_product_qty = fields.Float(
|
||||
'Allocated Quantity',
|
||||
help='Quantity of the stock request allocated to the stock move, '
|
||||
'in the default UoM of the product',
|
||||
"Allocated Quantity",
|
||||
help="Quantity of the stock request allocated to the stock move, "
|
||||
"in the default UoM of the product",
|
||||
)
|
||||
open_product_qty = fields.Float(
|
||||
"Open Quantity", compute="_compute_open_product_qty"
|
||||
)
|
||||
open_product_qty = fields.Float('Open Quantity',
|
||||
compute='_compute_open_product_qty')
|
||||
|
||||
@api.depends('stock_request_id.product_id',
|
||||
'stock_request_id.product_uom_id',
|
||||
'requested_product_uom_qty')
|
||||
@api.depends(
|
||||
"stock_request_id.product_id",
|
||||
"stock_request_id.product_uom_id",
|
||||
"requested_product_uom_qty",
|
||||
)
|
||||
def _compute_requested_product_qty(self):
|
||||
for rec in self:
|
||||
rec.requested_product_qty = rec.product_uom_id._compute_quantity(
|
||||
rec.requested_product_uom_qty, rec.product_id.uom_id)
|
||||
rec.requested_product_uom_qty, rec.product_id.uom_id
|
||||
)
|
||||
|
||||
@api.depends('requested_product_qty', 'allocated_product_qty',
|
||||
'stock_move_id', 'stock_move_id.state')
|
||||
@api.depends(
|
||||
"requested_product_qty",
|
||||
"allocated_product_qty",
|
||||
"stock_move_id",
|
||||
"stock_move_id.state",
|
||||
)
|
||||
def _compute_open_product_qty(self):
|
||||
for rec in self:
|
||||
if rec.stock_move_id.state == 'cancel':
|
||||
if rec.stock_move_id.state == "cancel":
|
||||
rec.open_product_qty = 0.0
|
||||
else:
|
||||
rec.open_product_qty = \
|
||||
rec.open_product_qty = (
|
||||
rec.requested_product_qty - rec.allocated_product_qty
|
||||
)
|
||||
if rec.open_product_qty < 0.0:
|
||||
rec.open_product_qty = 0.0
|
||||
|
||||
@@ -1,163 +1,190 @@
|
||||
# Copyright 2018 Creu Blanca
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError, ValidationError, AccessError
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import AccessError, UserError, ValidationError
|
||||
|
||||
|
||||
class StockRequestOrder(models.Model):
|
||||
_name = 'stock.request.order'
|
||||
_description = 'Stock Request Order'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'id desc'
|
||||
_name = "stock.request.order"
|
||||
_description = "Stock Request Order"
|
||||
_inherit = ["mail.thread", "mail.activity.mixin"]
|
||||
_order = "id desc"
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super().default_get(fields)
|
||||
warehouse = None
|
||||
if 'warehouse_id' not in res and res.get('company_id'):
|
||||
warehouse = self.env['stock.warehouse'].search(
|
||||
[('company_id', '=', res['company_id'])], limit=1)
|
||||
if "warehouse_id" not in res and res.get("company_id"):
|
||||
warehouse = self.env["stock.warehouse"].search(
|
||||
[("company_id", "=", res["company_id"])], limit=1
|
||||
)
|
||||
if warehouse:
|
||||
res['warehouse_id'] = warehouse.id
|
||||
res['location_id'] = warehouse.lot_stock_id.id
|
||||
res["warehouse_id"] = warehouse.id
|
||||
res["location_id"] = warehouse.lot_stock_id.id
|
||||
return res
|
||||
|
||||
def __get_request_order_states(self):
|
||||
return self.env['stock.request']._get_request_states()
|
||||
return self.env["stock.request"]._get_request_states()
|
||||
|
||||
def _get_request_order_states(self):
|
||||
return self.__get_request_order_states()
|
||||
|
||||
def _get_default_requested_by(self):
|
||||
return self.env['res.users'].browse(self.env.uid)
|
||||
return self.env["res.users"].browse(self.env.uid)
|
||||
|
||||
name = fields.Char(
|
||||
'Name', copy=False, required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
default='/')
|
||||
"Name",
|
||||
copy=False,
|
||||
required=True,
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
default="/",
|
||||
)
|
||||
state = fields.Selection(
|
||||
selection=_get_request_order_states,
|
||||
string='Status', copy=False, default='draft', index=True,
|
||||
readonly=True, track_visibility='onchange',
|
||||
string="Status",
|
||||
copy=False,
|
||||
default="draft",
|
||||
index=True,
|
||||
readonly=True,
|
||||
track_visibility="onchange",
|
||||
)
|
||||
requested_by = fields.Many2one(
|
||||
'res.users', 'Requested by', required=True,
|
||||
track_visibility='onchange',
|
||||
"res.users",
|
||||
"Requested by",
|
||||
required=True,
|
||||
track_visibility="onchange",
|
||||
default=lambda s: s._get_default_requested_by(),
|
||||
)
|
||||
warehouse_id = fields.Many2one(
|
||||
'stock.warehouse', 'Warehouse', readonly=True,
|
||||
ondelete="cascade", required=True,
|
||||
states={'draft': [('readonly', False)]})
|
||||
"stock.warehouse",
|
||||
"Warehouse",
|
||||
readonly=True,
|
||||
ondelete="cascade",
|
||||
required=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
)
|
||||
location_id = fields.Many2one(
|
||||
'stock.location', 'Location', readonly=True,
|
||||
domain=[('usage', 'in', ['internal', 'transit'])],
|
||||
ondelete="cascade", required=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
"stock.location",
|
||||
"Location",
|
||||
readonly=True,
|
||||
domain=[("usage", "in", ["internal", "transit"])],
|
||||
ondelete="cascade",
|
||||
required=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
)
|
||||
allow_virtual_location = fields.Boolean(
|
||||
related='company_id.stock_request_allow_virtual_loc',
|
||||
readonly=True,
|
||||
related="company_id.stock_request_allow_virtual_loc", readonly=True
|
||||
)
|
||||
procurement_group_id = fields.Many2one(
|
||||
'procurement.group', 'Procurement Group', readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
"procurement.group",
|
||||
"Procurement Group",
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
help="Moves created through this stock request will be put in this "
|
||||
"procurement group. If none is given, the moves generated by "
|
||||
"procurement rules will be grouped into one big picking.",
|
||||
"procurement group. If none is given, the moves generated by "
|
||||
"procurement rules will be grouped into one big picking.",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
'res.company', 'Company', required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
default=lambda self: self.env['res.company']._company_default_get(
|
||||
'stock.request.order'),
|
||||
"res.company",
|
||||
"Company",
|
||||
required=True,
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
default=lambda self: self.env["res.company"]._company_default_get(
|
||||
"stock.request.order"
|
||||
),
|
||||
)
|
||||
expected_date = fields.Datetime(
|
||||
'Expected Date', default=fields.Datetime.now, index=True,
|
||||
required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
"Expected Date",
|
||||
default=fields.Datetime.now,
|
||||
index=True,
|
||||
required=True,
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
help="Date when you expect to receive the goods.",
|
||||
)
|
||||
picking_policy = fields.Selection([
|
||||
('direct', 'Receive each product when available'),
|
||||
('one', 'Receive all products at once')],
|
||||
string='Shipping Policy', required=True, readonly=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
default='direct',
|
||||
picking_policy = fields.Selection(
|
||||
[
|
||||
("direct", "Receive each product when available"),
|
||||
("one", "Receive all products at once"),
|
||||
],
|
||||
string="Shipping Policy",
|
||||
required=True,
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
default="direct",
|
||||
)
|
||||
move_ids = fields.One2many(
|
||||
comodel_name="stock.move",
|
||||
compute="_compute_move_ids",
|
||||
string="Stock Moves",
|
||||
readonly=True,
|
||||
)
|
||||
picking_ids = fields.One2many(
|
||||
"stock.picking",
|
||||
compute="_compute_picking_ids",
|
||||
string="Pickings",
|
||||
readonly=True,
|
||||
)
|
||||
picking_count = fields.Integer(
|
||||
string="Delivery Orders", compute="_compute_picking_ids", readonly=True
|
||||
)
|
||||
move_ids = fields.One2many(comodel_name='stock.move',
|
||||
compute='_compute_move_ids',
|
||||
string='Stock Moves', readonly=True,
|
||||
)
|
||||
picking_ids = fields.One2many('stock.picking',
|
||||
compute='_compute_picking_ids',
|
||||
string='Pickings', readonly=True,
|
||||
)
|
||||
picking_count = fields.Integer(string='Delivery Orders',
|
||||
compute='_compute_picking_ids',
|
||||
readonly=True,
|
||||
)
|
||||
stock_request_ids = fields.One2many(
|
||||
'stock.request',
|
||||
inverse_name='order_id',
|
||||
copy=True,
|
||||
"stock.request", inverse_name="order_id", copy=True
|
||||
)
|
||||
stock_request_count = fields.Integer(
|
||||
string='Stock requests',
|
||||
compute='_compute_stock_request_count',
|
||||
readonly=True,
|
||||
string="Stock requests", compute="_compute_stock_request_count", readonly=True
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique(name, company_id)',
|
||||
'Stock Request name must be unique'),
|
||||
("name_uniq", "unique(name, company_id)", "Stock Request name must be unique")
|
||||
]
|
||||
|
||||
@api.depends('stock_request_ids.allocation_ids')
|
||||
@api.depends("stock_request_ids.allocation_ids")
|
||||
def _compute_picking_ids(self):
|
||||
for record in self:
|
||||
record.picking_ids = record.stock_request_ids.mapped('picking_ids')
|
||||
record.picking_ids = record.stock_request_ids.mapped("picking_ids")
|
||||
record.picking_count = len(record.picking_ids)
|
||||
|
||||
@api.depends('stock_request_ids')
|
||||
@api.depends("stock_request_ids")
|
||||
def _compute_move_ids(self):
|
||||
for record in self:
|
||||
record.move_ids = record.stock_request_ids.mapped('move_ids')
|
||||
record.move_ids = record.stock_request_ids.mapped("move_ids")
|
||||
|
||||
@api.depends('stock_request_ids')
|
||||
@api.depends("stock_request_ids")
|
||||
def _compute_stock_request_count(self):
|
||||
for record in self:
|
||||
record.stock_request_count = len(record.stock_request_ids)
|
||||
|
||||
@api.onchange('requested_by')
|
||||
@api.onchange("requested_by")
|
||||
def onchange_requested_by(self):
|
||||
self.change_childs()
|
||||
|
||||
@api.onchange('expected_date')
|
||||
@api.onchange("expected_date")
|
||||
def onchange_expected_date(self):
|
||||
self.change_childs()
|
||||
|
||||
@api.onchange('picking_policy')
|
||||
@api.onchange("picking_policy")
|
||||
def onchange_picking_policy(self):
|
||||
self.change_childs()
|
||||
|
||||
@api.onchange('location_id')
|
||||
@api.onchange("location_id")
|
||||
def onchange_location_id(self):
|
||||
if self.location_id:
|
||||
loc_wh = self.location_id.sudo().get_warehouse()
|
||||
if loc_wh and self.warehouse_id != loc_wh:
|
||||
self.warehouse_id = loc_wh
|
||||
self.with_context(
|
||||
no_change_childs=True).onchange_warehouse_id()
|
||||
self.with_context(no_change_childs=True).onchange_warehouse_id()
|
||||
self.change_childs()
|
||||
|
||||
@api.onchange('allow_virtual_location')
|
||||
@api.onchange("allow_virtual_location")
|
||||
def onchange_allow_virtual_location(self):
|
||||
if self.allow_virtual_location:
|
||||
return {'domain': {'location_id': []}}
|
||||
return {"domain": {"location_id": []}}
|
||||
|
||||
@api.onchange('warehouse_id')
|
||||
@api.onchange("warehouse_id")
|
||||
def onchange_warehouse_id(self):
|
||||
if self.warehouse_id:
|
||||
# search with sudo because the user may not have permissions
|
||||
@@ -170,26 +197,25 @@ class StockRequestOrder(models.Model):
|
||||
self.with_context(no_change_childs=True).onchange_company_id()
|
||||
self.change_childs()
|
||||
|
||||
@api.onchange('procurement_group_id')
|
||||
@api.onchange("procurement_group_id")
|
||||
def onchange_procurement_group_id(self):
|
||||
self.change_childs()
|
||||
|
||||
@api.onchange('company_id')
|
||||
@api.onchange("company_id")
|
||||
def onchange_company_id(self):
|
||||
if self.company_id and (
|
||||
not self.warehouse_id or
|
||||
self.warehouse_id.sudo().company_id != self.company_id
|
||||
not self.warehouse_id
|
||||
or self.warehouse_id.sudo().company_id != self.company_id
|
||||
):
|
||||
self.warehouse_id = self.env['stock.warehouse'].search(
|
||||
[('company_id', '=', self.company_id.id)], limit=1)
|
||||
self.warehouse_id = self.env["stock.warehouse"].search(
|
||||
[("company_id", "=", self.company_id.id)], limit=1
|
||||
)
|
||||
self.with_context(no_change_childs=True).onchange_warehouse_id()
|
||||
self.change_childs()
|
||||
return {
|
||||
'domain': {
|
||||
'warehouse_id': [('company_id', '=', self.company_id.id)]}}
|
||||
return {"domain": {"warehouse_id": [("company_id", "=", self.company_id.id)]}}
|
||||
|
||||
def change_childs(self):
|
||||
if not self._context.get('no_change_childs', False):
|
||||
if not self._context.get("no_change_childs", False):
|
||||
for line in self.stock_request_ids:
|
||||
line.warehouse_id = self.warehouse_id
|
||||
line.location_id = self.location_id
|
||||
@@ -203,121 +229,142 @@ class StockRequestOrder(models.Model):
|
||||
def action_confirm(self):
|
||||
for line in self.stock_request_ids:
|
||||
line.action_confirm()
|
||||
self.state = 'open'
|
||||
self.state = "open"
|
||||
return True
|
||||
|
||||
def action_draft(self):
|
||||
for line in self.stock_request_ids:
|
||||
line.action_draft()
|
||||
self.state = 'draft'
|
||||
self.state = "draft"
|
||||
return True
|
||||
|
||||
def action_cancel(self):
|
||||
for line in self.stock_request_ids:
|
||||
line.action_cancel()
|
||||
self.state = 'cancel'
|
||||
self.state = "cancel"
|
||||
return True
|
||||
|
||||
def action_done(self):
|
||||
self.state = 'done'
|
||||
self.state = "done"
|
||||
return True
|
||||
|
||||
def check_done(self):
|
||||
if not self.stock_request_ids.filtered(lambda r: r.state != 'done'):
|
||||
if not self.stock_request_ids.filtered(lambda r: r.state != "done"):
|
||||
self.action_done()
|
||||
return
|
||||
|
||||
@api.multi
|
||||
def action_view_transfer(self):
|
||||
action = self.env.ref('stock.action_picking_tree_all').read()[0]
|
||||
action = self.env.ref("stock.action_picking_tree_all").read()[0]
|
||||
|
||||
pickings = self.mapped('picking_ids')
|
||||
pickings = self.mapped("picking_ids")
|
||||
if len(pickings) > 1:
|
||||
action['domain'] = [('id', 'in', pickings.ids)]
|
||||
action["domain"] = [("id", "in", pickings.ids)]
|
||||
elif pickings:
|
||||
action['views'] = [
|
||||
(self.env.ref('stock.view_picking_form').id, 'form')]
|
||||
action['res_id'] = pickings.id
|
||||
action["views"] = [(self.env.ref("stock.view_picking_form").id, "form")]
|
||||
action["res_id"] = pickings.id
|
||||
return action
|
||||
|
||||
@api.multi
|
||||
def action_view_stock_requests(self):
|
||||
action = self.env.ref(
|
||||
'stock_request.action_stock_request_form').read()[0]
|
||||
action = self.env.ref("stock_request.action_stock_request_form").read()[0]
|
||||
if len(self.stock_request_ids) > 1:
|
||||
action['domain'] = [('order_id', 'in', self.ids)]
|
||||
action["domain"] = [("order_id", "in", self.ids)]
|
||||
elif self.stock_request_ids:
|
||||
action['views'] = [
|
||||
(self.env.ref(
|
||||
'stock_request.view_stock_request_form').id, 'form')]
|
||||
action['res_id'] = self.stock_request_ids.id
|
||||
action["views"] = [
|
||||
(self.env.ref("stock_request.view_stock_request_form").id, "form")
|
||||
]
|
||||
action["res_id"] = self.stock_request_ids.id
|
||||
return action
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
upd_vals = vals.copy()
|
||||
if upd_vals.get('name', '/') == '/':
|
||||
upd_vals['name'] = self.env['ir.sequence'].next_by_code(
|
||||
'stock.request.order')
|
||||
if upd_vals.get("name", "/") == "/":
|
||||
upd_vals["name"] = self.env["ir.sequence"].next_by_code(
|
||||
"stock.request.order"
|
||||
)
|
||||
return super().create(upd_vals)
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
if self.filtered(lambda r: r.state != 'draft'):
|
||||
raise UserError(_('Only orders on draft state can be unlinked'))
|
||||
if self.filtered(lambda r: r.state != "draft"):
|
||||
raise UserError(_("Only orders on draft state can be unlinked"))
|
||||
return super().unlink()
|
||||
|
||||
@api.constrains('warehouse_id', 'company_id')
|
||||
@api.constrains("warehouse_id", "company_id")
|
||||
def _check_warehouse_company(self):
|
||||
if any(request.warehouse_id.company_id !=
|
||||
request.company_id for request in self):
|
||||
if any(
|
||||
request.warehouse_id.company_id != request.company_id for request in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('The company of the stock request must match with '
|
||||
'that of the warehouse.'))
|
||||
_(
|
||||
"The company of the stock request must match with "
|
||||
"that of the warehouse."
|
||||
)
|
||||
)
|
||||
|
||||
@api.constrains('location_id', 'company_id')
|
||||
@api.constrains("location_id", "company_id")
|
||||
def _check_location_company(self):
|
||||
if any(request.location_id.company_id and
|
||||
request.location_id.company_id !=
|
||||
request.company_id for request in self):
|
||||
if any(
|
||||
request.location_id.company_id
|
||||
and request.location_id.company_id != request.company_id
|
||||
for request in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('The company of the stock request must match with '
|
||||
'that of the location.'))
|
||||
_(
|
||||
"The company of the stock request must match with "
|
||||
"that of the location."
|
||||
)
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _create_from_product_multiselect(self, products):
|
||||
if not products:
|
||||
return False
|
||||
if products._name not in ('product.product', 'product.template'):
|
||||
if products._name not in ("product.product", "product.template"):
|
||||
raise ValidationError(
|
||||
_("This action only works in the context of products"))
|
||||
if products._name == 'product.template':
|
||||
_("This action only works in the context of products")
|
||||
)
|
||||
if products._name == "product.template":
|
||||
# search instead of mapped so we don't include archived variants
|
||||
products = self.env['product.product'].search([
|
||||
('product_tmpl_id', 'in', products.ids)
|
||||
])
|
||||
expected = self.default_get(['expected_date'])['expected_date']
|
||||
products = self.env["product.product"].search(
|
||||
[("product_tmpl_id", "in", products.ids)]
|
||||
)
|
||||
expected = self.default_get(["expected_date"])["expected_date"]
|
||||
try:
|
||||
order = self.env['stock.request.order'].create(dict(
|
||||
expected_date=expected,
|
||||
stock_request_ids=[(0, 0, dict(
|
||||
product_id=product.id,
|
||||
product_uom_id=product.uom_id.id,
|
||||
product_uom_qty=1.0,
|
||||
order = self.env["stock.request.order"].create(
|
||||
dict(
|
||||
expected_date=expected,
|
||||
)) for product in products]
|
||||
))
|
||||
stock_request_ids=[
|
||||
(
|
||||
0,
|
||||
0,
|
||||
dict(
|
||||
product_id=product.id,
|
||||
product_uom_id=product.uom_id.id,
|
||||
product_uom_qty=1.0,
|
||||
expected_date=expected,
|
||||
),
|
||||
)
|
||||
for product in products
|
||||
],
|
||||
)
|
||||
)
|
||||
except AccessError:
|
||||
# TODO: if there is a nice way to hide the action from the
|
||||
# Action-menu if the user doesn't have the necessary rights,
|
||||
# that would be a better way of doing this
|
||||
raise UserError(_(
|
||||
"Unfortunately it seems you do not have the necessary rights "
|
||||
"for creating stock requests. Please contact your "
|
||||
"administrator."))
|
||||
action = self.env.ref('stock_request.stock_request_order_action'
|
||||
).read()[0]
|
||||
action['views'] = [(
|
||||
self.env.ref('stock_request.stock_request_order_form').id, 'form')]
|
||||
action['res_id'] = order.id
|
||||
raise UserError(
|
||||
_(
|
||||
"Unfortunately it seems you do not have the necessary rights "
|
||||
"for creating stock requests. Please contact your "
|
||||
"administrator."
|
||||
)
|
||||
)
|
||||
action = self.env.ref("stock_request.stock_request_order_action").read()[0]
|
||||
action["views"] = [
|
||||
(self.env.ref("stock_request.stock_request_order_form").id, "form")
|
||||
]
|
||||
action["res_id"] = order.id
|
||||
return action
|
||||
|
||||
@@ -5,16 +5,38 @@ from odoo import models
|
||||
|
||||
|
||||
class StockRule(models.Model):
|
||||
_inherit = 'stock.rule'
|
||||
_inherit = "stock.rule"
|
||||
|
||||
def _get_stock_move_values(self, product_id, product_qty, product_uom,
|
||||
location_id, name, origin, values, group_id):
|
||||
def _get_stock_move_values(
|
||||
self,
|
||||
product_id,
|
||||
product_qty,
|
||||
product_uom,
|
||||
location_id,
|
||||
name,
|
||||
origin,
|
||||
values,
|
||||
group_id,
|
||||
):
|
||||
result = super(StockRule, self)._get_stock_move_values(
|
||||
product_id, product_qty, product_uom,
|
||||
location_id, name, origin, values, group_id)
|
||||
if values.get('stock_request_id', False):
|
||||
result['allocation_ids'] = [(0, 0, {
|
||||
'stock_request_id': values.get('stock_request_id'),
|
||||
'requested_product_uom_qty': product_qty,
|
||||
})]
|
||||
product_id,
|
||||
product_qty,
|
||||
product_uom,
|
||||
location_id,
|
||||
name,
|
||||
origin,
|
||||
values,
|
||||
group_id,
|
||||
)
|
||||
if values.get("stock_request_id", False):
|
||||
result["allocation_ids"] = [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"stock_request_id": values.get("stock_request_id"),
|
||||
"requested_product_uom_qty": product_qty,
|
||||
},
|
||||
)
|
||||
]
|
||||
return result
|
||||
|
||||
@@ -1,28 +1,46 @@
|
||||
# Copyright 2018 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, models, _
|
||||
from odoo import _, api, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class StockWarehouse(models.Model):
|
||||
_inherit = 'stock.warehouse'
|
||||
_inherit = "stock.warehouse"
|
||||
|
||||
@api.constrains('company_id')
|
||||
@api.constrains("company_id")
|
||||
def _check_company_stock_request(self):
|
||||
if any(self.env['stock.request'].search(
|
||||
[('company_id', '!=', rec.company_id.id),
|
||||
('warehouse_id', '=', rec.id)], limit=1)
|
||||
for rec in self):
|
||||
if any(
|
||||
self.env["stock.request"].search(
|
||||
[
|
||||
("company_id", "!=", rec.company_id.id),
|
||||
("warehouse_id", "=", rec.id),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
for rec in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You cannot change the company of the warehouse, as it is '
|
||||
'already assigned to stock requests that belong to '
|
||||
'another company.'))
|
||||
if any(self.env['stock.request.order'].search(
|
||||
[('company_id', '!=', rec.company_id.id),
|
||||
('warehouse_id', '=', rec.id)], limit=1)
|
||||
for rec in self):
|
||||
_(
|
||||
"You cannot change the company of the warehouse, as it is "
|
||||
"already assigned to stock requests that belong to "
|
||||
"another company."
|
||||
)
|
||||
)
|
||||
if any(
|
||||
self.env["stock.request.order"].search(
|
||||
[
|
||||
("company_id", "!=", rec.company_id.id),
|
||||
("warehouse_id", "=", rec.id),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
for rec in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_('You cannot change the company of the warehouse, as it is '
|
||||
'already assigned to stock request orders that belong to '
|
||||
'another company.'))
|
||||
_(
|
||||
"You cannot change the company of the warehouse, as it is "
|
||||
"already assigned to stock request orders that belong to "
|
||||
"another company."
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
from . import test_stock_request
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user