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