[IMP] stock_request: black, isort

This commit is contained in:
hveficent
2020-01-28 16:53:34 +01:00
committed by Kitti U
parent 13dc2169c7
commit 854bbe132d
19 changed files with 1375 additions and 1095 deletions

View File

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

View File

@@ -7,12 +7,9 @@
"version": "12.0.1.1.6",
"license": "LGPL-3",
"website": "https://github.com/stock-logistics-warehouse",
"author": "Eficent, "
"Odoo Community Association (OCA)",
"author": "Eficent, " "Odoo Community Association (OCA)",
"category": "Warehouse Management",
"depends": [
"stock",
],
"depends": ["stock"],
"data": [
"security/stock_request_security.xml",
"security/ir.model.access.csv",

View File

@@ -5,15 +5,16 @@ from odoo import api, models
class ProcurementGroup(models.Model):
_inherit = 'procurement.group'
_inherit = "procurement.group"
@api.model
def run(self, product_id, product_qty, product_uom, location_id, name,
origin, values):
if 'stock_request_id' in values and values.get('stock_request_id'):
req = self.env['stock.request'].browse(
values.get('stock_request_id'))
def run(
self, product_id, product_qty, product_uom, location_id, name, origin, values
):
if "stock_request_id" in values and values.get("stock_request_id"):
req = self.env["stock.request"].browse(values.get("stock_request_id"))
if req.order_id:
origin = req.order_id.name
return super().run(product_id, product_qty, product_uom, location_id,
name, origin, values)
return super().run(
product_id, product_qty, product_uom, location_id, name, origin, values
)

View File

@@ -7,8 +7,8 @@ from odoo import fields, models
class ResCompany(models.Model):
_inherit = 'res.company'
_inherit = "res.company"
stock_request_allow_virtual_loc = fields.Boolean(
string='Allow Virtual locations on Stock Requests',
string="Allow Virtual locations on Stock Requests"
)

View File

@@ -5,29 +5,34 @@ from odoo import api, fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
_inherit = "res.config.settings"
group_stock_request_order = fields.Boolean(
implied_group='stock_request.group_stock_request_order')
implied_group="stock_request.group_stock_request_order"
)
module_stock_request_purchase = fields.Boolean(
string='Stock Requests for Purchases')
string="Stock Requests for Purchases"
)
module_stock_request_kanban = fields.Boolean(
string='Stock Requests Kanban integration')
string="Stock Requests Kanban integration"
)
stock_request_allow_virtual_loc = fields.Boolean(
related='company_id.stock_request_allow_virtual_loc',
readonly=False)
related="company_id.stock_request_allow_virtual_loc", readonly=False
)
module_stock_request_analytic = fields.Boolean(
string='Stock Requests Analytic integration')
string="Stock Requests Analytic integration"
)
module_stock_request_submit = fields.Boolean(
string='Submitted state in Stock Requests')
string="Submitted state in Stock Requests"
)
# Dependencies
@api.onchange('stock_request_allow_virtual_loc')
@api.onchange("stock_request_allow_virtual_loc")
def _onchange_stock_request_allow_virtual_loc(self):
if self.stock_request_allow_virtual_loc:
self.group_stock_multi_locations = True

View File

@@ -1,26 +1,45 @@
# Copyright 2018 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, models, _
from odoo import _, api, models
from odoo.exceptions import ValidationError
class StockLocation(models.Model):
_inherit = 'stock.location'
_inherit = "stock.location"
@api.constrains('company_id')
@api.constrains("company_id")
def _check_company_stock_request(self):
if any(rec.company_id and self.env['stock.request'].search(
[('company_id', '!=', rec.company_id.id),
('location_id', '=', rec.id)], limit=1) for rec in self):
if any(
rec.company_id
and self.env["stock.request"].search(
[("company_id", "!=", rec.company_id.id), ("location_id", "=", rec.id)],
limit=1,
)
for rec in self
):
raise ValidationError(
_('You cannot change the company of the location, as it is '
'already assigned to stock requests that belong to '
'another company.'))
if any(rec.company_id and self.env['stock.request.order'].search(
[('company_id', '!=', rec.company_id.id),
('warehouse_id', '=', rec.id)], limit=1) for rec in self):
_(
"You cannot change the company of the location, as it is "
"already assigned to stock requests that belong to "
"another company."
)
)
if any(
rec.company_id
and self.env["stock.request.order"].search(
[
("company_id", "!=", rec.company_id.id),
("warehouse_id", "=", rec.id),
],
limit=1,
)
for rec in self
):
raise ValidationError(
_('You cannot change the company of the location, as it is '
'already assigned to stock request orders that belong to '
'another company.'))
_(
"You cannot change the company of the location, as it is "
"already assigned to stock request orders that belong to "
"another company."
)
)

View File

@@ -1,19 +1,27 @@
# Copyright 2018 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, models, _
from odoo import _, api, models
from odoo.exceptions import ValidationError
class StockLocationRoute(models.Model):
_inherit = 'stock.location.route'
_inherit = "stock.location.route"
@api.constrains('company_id')
@api.constrains("company_id")
def _check_company_stock_request(self):
if any(rec.company_id and self.env['stock.request'].search(
[('company_id', '!=', rec.company_id.id),
('route_id', '=', rec.id)], limit=1) for rec in self):
if any(
rec.company_id
and self.env["stock.request"].search(
[("company_id", "!=", rec.company_id.id), ("route_id", "=", rec.id)],
limit=1,
)
for rec in self
):
raise ValidationError(
_('You cannot change the company of the route, as it is '
'already assigned to stock requests that belong to '
'another company.'))
_(
"You cannot change the company of the route, as it is "
"already assigned to stock requests that belong to "
"another company."
)
)

View File

@@ -1,39 +1,50 @@
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class StockMove(models.Model):
_inherit = 'stock.move'
_inherit = "stock.move"
allocation_ids = fields.One2many(comodel_name='stock.request.allocation',
inverse_name='stock_move_id',
string='Stock Request Allocation')
allocation_ids = fields.One2many(
comodel_name="stock.request.allocation",
inverse_name="stock_move_id",
string="Stock Request Allocation",
)
stock_request_ids = fields.One2many(comodel_name='stock.request',
string='Stock Requests',
compute='_compute_stock_request_ids')
stock_request_ids = fields.One2many(
comodel_name="stock.request",
string="Stock Requests",
compute="_compute_stock_request_ids",
)
@api.depends('allocation_ids')
@api.depends("allocation_ids")
def _compute_stock_request_ids(self):
for rec in self:
rec.stock_request_ids = rec.allocation_ids.mapped(
'stock_request_id')
rec.stock_request_ids = rec.allocation_ids.mapped("stock_request_id")
def _merge_moves_fields(self):
res = super(StockMove, self)._merge_moves_fields()
res['allocation_ids'] = [(4, m.id) for m in
self.mapped('allocation_ids')]
res["allocation_ids"] = [(4, m.id) for m in self.mapped("allocation_ids")]
return res
@api.constrains('company_id')
@api.constrains("company_id")
def _check_company_stock_request(self):
if any(self.env['stock.request.allocation'].search(
[('company_id', '!=', rec.company_id.id),
('stock_move_id', '=', rec.id)], limit=1)
for rec in self):
if any(
self.env["stock.request.allocation"].search(
[
("company_id", "!=", rec.company_id.id),
("stock_move_id", "=", rec.id),
],
limit=1,
)
for rec in self
):
raise ValidationError(
_('The company of the stock request must match with '
'that of the location.'))
_(
"The company of the stock request must match with "
"that of the location."
)
)

View File

@@ -9,39 +9,44 @@ class StockMoveLine(models.Model):
@api.model
def _stock_request_confirm_done_message_content(self, message_data):
title = _('Receipt confirmation %s for your Request %s') % (
message_data['picking_name'], message_data['request_name'])
message = '<h3>%s</h3>' % title
message += _('The following requested items from Stock Request %s '
'have now been received in %s using Picking %s:') % (
message_data['request_name'], message_data['location_name'],
message_data['picking_name'])
message += '<ul>'
title = _("Receipt confirmation %s for your Request %s") % (
message_data["picking_name"],
message_data["request_name"],
)
message = "<h3>%s</h3>" % title
message += _(
'<li><b>%s</b>: Transferred quantity %s %s</li>'
) % (message_data['product_name'],
message_data['product_qty'],
message_data['product_uom'],
)
message += '</ul>'
"The following requested items from Stock Request %s "
"have now been received in %s using Picking %s:"
) % (
message_data["request_name"],
message_data["location_name"],
message_data["picking_name"],
)
message += "<ul>"
message += _("<li><b>%s</b>: Transferred quantity %s %s</li>") % (
message_data["product_name"],
message_data["product_qty"],
message_data["product_uom"],
)
message += "</ul>"
return message
def _prepare_message_data(self, ml, request, allocated_qty):
return {
'request_name': request.name,
'picking_name': ml.picking_id.name,
'product_name': ml.product_id.name_get()[0][1],
'product_qty': allocated_qty,
'product_uom': ml.product_uom_id.name,
'location_name': ml.location_dest_id.name_get()[0][1],
"request_name": request.name,
"picking_name": ml.picking_id.name,
"product_name": ml.product_id.name_get()[0][1],
"product_qty": allocated_qty,
"product_uom": ml.product_uom_id.name,
"location_name": ml.location_dest_id.name_get()[0][1],
}
def _action_done(self):
res = super(StockMoveLine, self)._action_done()
for ml in self.filtered(
lambda m: m.exists() and m.move_id.allocation_ids):
for ml in self.filtered(lambda m: m.exists() and m.move_id.allocation_ids):
qty_done = ml.product_uom_id._compute_quantity(
ml.qty_done, ml.product_id.uom_id)
ml.qty_done, ml.product_id.uom_id
)
# We do sudo because potentially the user that completes the move
# may not have permissions for stock.request.
@@ -49,16 +54,12 @@ class StockMoveLine(models.Model):
for allocation in ml.move_id.allocation_ids.sudo():
allocated_qty = 0.0
if allocation.open_product_qty:
allocated_qty = min(
allocation.open_product_qty, qty_done)
allocated_qty = min(allocation.open_product_qty, qty_done)
allocation.allocated_product_qty += allocated_qty
to_allocate_qty -= allocated_qty
request = allocation.stock_request_id
message_data = self._prepare_message_data(ml, request,
allocated_qty)
message = \
self._stock_request_confirm_done_message_content(
message_data)
request.message_post(body=message, subtype='mail.mt_comment')
message_data = self._prepare_message_data(ml, request, allocated_qty)
message = self._stock_request_confirm_done_message_content(message_data)
request.message_post(body=message, subtype="mail.mt_comment")
request.check_done()
return res

View File

@@ -5,33 +5,35 @@ from odoo import api, fields, models
class StockPicking(models.Model):
_inherit = 'stock.picking'
_inherit = "stock.picking"
stock_request_ids = fields.One2many(comodel_name='stock.request',
string='Stock Requests',
compute='_compute_stock_request_ids')
stock_request_count = fields.Integer('Stock Request #',
compute='_compute_stock_request_ids')
stock_request_ids = fields.One2many(
comodel_name="stock.request",
string="Stock Requests",
compute="_compute_stock_request_ids",
)
stock_request_count = fields.Integer(
"Stock Request #", compute="_compute_stock_request_ids"
)
@api.depends('move_lines')
@api.depends("move_lines")
def _compute_stock_request_ids(self):
for rec in self:
rec.stock_request_ids = rec.move_lines.mapped('stock_request_ids')
rec.stock_request_ids = rec.move_lines.mapped("stock_request_ids")
rec.stock_request_count = len(rec.stock_request_ids)
def action_view_stock_request(self):
"""
:return dict: dictionary value for created view
"""
action = self.env.ref(
'stock_request.action_stock_request_form').read()[0]
action = self.env.ref("stock_request.action_stock_request_form").read()[0]
requests = self.mapped('stock_request_ids')
requests = self.mapped("stock_request_ids")
if len(requests) > 1:
action['domain'] = [('id', 'in', requests.ids)]
action["domain"] = [("id", "in", requests.ids)]
elif requests:
action['views'] = [
(self.env.ref('stock_request.view_stock_request_form').id,
'form')]
action['res_id'] = requests.id
action["views"] = [
(self.env.ref("stock_request.view_stock_request_form").id, "form")
]
action["res_id"] = requests.id
return action

View File

@@ -1,23 +1,25 @@
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models, _
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.addons import decimal_precision as dp
from odoo.tools import float_compare
from odoo.addons import decimal_precision as dp
REQUEST_STATES = [
('draft', 'Draft'),
('open', 'In progress'),
('done', 'Done'),
('cancel', 'Cancelled')]
("draft", "Draft"),
("open", "In progress"),
("done", "Done"),
("cancel", "Cancelled"),
]
class StockRequest(models.Model):
_name = "stock.request"
_description = "Stock Request"
_inherit = 'stock.request.abstract'
_order = 'id desc'
_inherit = "stock.request.abstract"
_order = "id desc"
def __get_request_states(self):
return REQUEST_STATES
@@ -26,7 +28,7 @@ class StockRequest(models.Model):
return self.__get_request_states()
def _get_default_requested_by(self):
return self.env['res.users'].browse(self.env.uid)
return self.env["res.users"].browse(self.env.uid)
@staticmethod
def _get_expected_date():
@@ -39,178 +41,177 @@ class StockRequest(models.Model):
res = self._get_expected_date()
return res
name = fields.Char(
states={'draft': [('readonly', False)]}
)
name = fields.Char(states={"draft": [("readonly", False)]})
state = fields.Selection(
selection=_get_request_states, string='Status',
copy=False, default='draft', index=True,
readonly=True, track_visibility='onchange',
selection=_get_request_states,
string="Status",
copy=False,
default="draft",
index=True,
readonly=True,
track_visibility="onchange",
)
requested_by = fields.Many2one(
'res.users', 'Requested by', required=True,
track_visibility='onchange',
"res.users",
"Requested by",
required=True,
track_visibility="onchange",
default=lambda s: s._get_default_requested_by(),
)
expected_date = fields.Datetime(
'Expected Date', default=lambda s: s._get_default_expected_date(),
index=True, required=True, readonly=True,
states={'draft': [('readonly', False)]},
"Expected Date",
default=lambda s: s._get_default_expected_date(),
index=True,
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
help="Date when you expect to receive the goods.",
)
picking_policy = fields.Selection([
('direct', 'Receive each product when available'),
('one', 'Receive all products at once')],
string='Shipping Policy', required=True, readonly=True,
states={'draft': [('readonly', False)]},
default='direct',
picking_policy = fields.Selection(
[
("direct", "Receive each product when available"),
("one", "Receive all products at once"),
],
string="Shipping Policy",
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
default="direct",
)
move_ids = fields.One2many(
comodel_name="stock.move",
compute="_compute_move_ids",
string="Stock Moves",
readonly=True,
)
picking_ids = fields.One2many(
"stock.picking",
compute="_compute_picking_ids",
string="Pickings",
readonly=True,
)
move_ids = fields.One2many(comodel_name='stock.move',
compute='_compute_move_ids',
string='Stock Moves', readonly=True,
)
picking_ids = fields.One2many('stock.picking',
compute='_compute_picking_ids',
string='Pickings', readonly=True,
)
qty_in_progress = fields.Float(
'Qty In Progress', digits=dp.get_precision('Product Unit of Measure'),
readonly=True, compute='_compute_qty', store=True,
"Qty In Progress",
digits=dp.get_precision("Product Unit of Measure"),
readonly=True,
compute="_compute_qty",
store=True,
help="Quantity in progress.",
)
qty_done = fields.Float(
'Qty Done', digits=dp.get_precision('Product Unit of Measure'),
readonly=True, compute='_compute_qty', store=True,
"Qty Done",
digits=dp.get_precision("Product Unit of Measure"),
readonly=True,
compute="_compute_qty",
store=True,
help="Quantity completed",
)
picking_count = fields.Integer(string='Delivery Orders',
compute='_compute_picking_ids',
readonly=True,
)
allocation_ids = fields.One2many(comodel_name='stock.request.allocation',
inverse_name='stock_request_id',
string='Stock Request Allocation')
order_id = fields.Many2one(
'stock.request.order',
readonly=True,
picking_count = fields.Integer(
string="Delivery Orders", compute="_compute_picking_ids", readonly=True
)
allocation_ids = fields.One2many(
comodel_name="stock.request.allocation",
inverse_name="stock_request_id",
string="Stock Request Allocation",
)
order_id = fields.Many2one("stock.request.order", readonly=True)
warehouse_id = fields.Many2one(
states={'draft': [('readonly', False)]}, readonly=True
states={"draft": [("readonly", False)]}, readonly=True
)
location_id = fields.Many2one(
states={'draft': [('readonly', False)]}, readonly=True
)
product_id = fields.Many2one(
states={'draft': [('readonly', False)]}, readonly=True
states={"draft": [("readonly", False)]}, readonly=True
)
product_id = fields.Many2one(states={"draft": [("readonly", False)]}, readonly=True)
product_uom_id = fields.Many2one(
states={'draft': [('readonly', False)]}, readonly=True
states={"draft": [("readonly", False)]}, readonly=True
)
product_uom_qty = fields.Float(
states={'draft': [('readonly', False)]}, readonly=True
states={"draft": [("readonly", False)]}, readonly=True
)
procurement_group_id = fields.Many2one(
states={'draft': [('readonly', False)]}, readonly=True
)
company_id = fields.Many2one(
states={'draft': [('readonly', False)]}, readonly=True
)
route_id = fields.Many2one(
states={'draft': [('readonly', False)]}, readonly=True
states={"draft": [("readonly", False)]}, readonly=True
)
company_id = fields.Many2one(states={"draft": [("readonly", False)]}, readonly=True)
route_id = fields.Many2one(states={"draft": [("readonly", False)]}, readonly=True)
_sql_constraints = [
('name_uniq', 'unique(name, company_id)',
'Stock Request name must be unique'),
("name_uniq", "unique(name, company_id)", "Stock Request name must be unique")
]
@api.depends('allocation_ids')
@api.depends("allocation_ids")
def _compute_move_ids(self):
for request in self:
request.move_ids = request.allocation_ids.mapped('stock_move_id')
request.move_ids = request.allocation_ids.mapped("stock_move_id")
@api.depends('allocation_ids')
@api.depends("allocation_ids")
def _compute_picking_ids(self):
for request in self:
request.picking_count = 0
request.picking_ids = self.env['stock.picking']
request.picking_ids = self.env["stock.picking"]
request.picking_ids = request.move_ids.filtered(
lambda m: m.state != 'cancel').mapped('picking_id')
lambda m: m.state != "cancel"
).mapped("picking_id")
request.picking_count = len(request.picking_ids)
@api.depends('allocation_ids', 'allocation_ids.stock_move_id.state',
'allocation_ids.stock_move_id.move_line_ids',
'allocation_ids.stock_move_id.move_line_ids.qty_done')
@api.depends(
"allocation_ids",
"allocation_ids.stock_move_id.state",
"allocation_ids.stock_move_id.move_line_ids",
"allocation_ids.stock_move_id.move_line_ids.qty_done",
)
def _compute_qty(self):
for request in self:
done_qty = sum(request.allocation_ids.mapped(
'allocated_product_qty'))
open_qty = sum(request.allocation_ids.mapped('open_product_qty'))
done_qty = sum(request.allocation_ids.mapped("allocated_product_qty"))
open_qty = sum(request.allocation_ids.mapped("open_product_qty"))
request.qty_done = request.product_id.uom_id._compute_quantity(
done_qty, request.product_uom_id)
request.qty_in_progress = \
request.product_id.uom_id._compute_quantity(
open_qty, request.product_uom_id)
done_qty, request.product_uom_id
)
request.qty_in_progress = request.product_id.uom_id._compute_quantity(
open_qty, request.product_uom_id
)
@api.constrains('order_id', 'requested_by')
@api.constrains("order_id", "requested_by")
def check_order_requested_by(self):
if self.order_id and self.order_id.requested_by != self.requested_by:
raise ValidationError(_(
'Requested by must be equal to the order'
))
raise ValidationError(_("Requested by must be equal to the order"))
@api.constrains('order_id', 'warehouse_id')
@api.constrains("order_id", "warehouse_id")
def check_order_warehouse_id(self):
if self.order_id and self.order_id.warehouse_id != self.warehouse_id:
raise ValidationError(_(
'Warehouse must be equal to the order'
))
raise ValidationError(_("Warehouse must be equal to the order"))
@api.constrains('order_id', 'location_id')
@api.constrains("order_id", "location_id")
def check_order_location(self):
if self.order_id and self.order_id.location_id != self.location_id:
raise ValidationError(_(
'Location must be equal to the order'
))
raise ValidationError(_("Location must be equal to the order"))
@api.constrains('order_id', 'procurement_group_id')
@api.constrains("order_id", "procurement_group_id")
def check_order_procurement_group(self):
if (
self.order_id and
self.order_id.procurement_group_id != self.procurement_group_id
self.order_id
and self.order_id.procurement_group_id != self.procurement_group_id
):
raise ValidationError(_(
'Procurement group must be equal to the order'
))
raise ValidationError(_("Procurement group must be equal to the order"))
@api.constrains('order_id', 'company_id')
@api.constrains("order_id", "company_id")
def check_order_company(self):
if self.order_id and self.order_id.company_id != self.company_id:
raise ValidationError(_(
'Company must be equal to the order'
))
raise ValidationError(_("Company must be equal to the order"))
@api.constrains('order_id', 'expected_date')
@api.constrains("order_id", "expected_date")
def check_order_expected_date(self):
if self.order_id and self.order_id.expected_date != self.expected_date:
raise ValidationError(_(
'Expected date must be equal to the order'
))
raise ValidationError(_("Expected date must be equal to the order"))
@api.constrains('order_id', 'picking_policy')
@api.constrains("order_id", "picking_policy")
def check_order_picking_policy(self):
if (
self.order_id and
self.order_id.picking_policy != self.picking_policy
):
raise ValidationError(_(
'The picking policy must be equal to the order'
))
if self.order_id and self.order_id.picking_policy != self.picking_policy:
raise ValidationError(_("The picking policy must be equal to the order"))
@api.multi
def _action_confirm(self):
self._action_launch_procurement_rule()
self.state = 'open'
self.state = "open"
@api.multi
def action_confirm(self):
@@ -218,30 +219,35 @@ class StockRequest(models.Model):
return True
def action_draft(self):
self.write({'state': 'draft'})
self.write({"state": "draft"})
return True
def action_cancel(self):
self.sudo().mapped('move_ids')._action_cancel()
self.state = 'cancel'
self.sudo().mapped("move_ids")._action_cancel()
self.state = "cancel"
return True
def action_done(self):
self.state = 'done'
self.state = "done"
if self.order_id:
self.order_id.check_done()
return True
def check_done(self):
precision = self.env['decimal.precision'].precision_get(
'Product Unit of Measure')
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
for request in self:
allocated_qty = sum(request.allocation_ids.mapped(
'allocated_product_qty'))
allocated_qty = sum(request.allocation_ids.mapped("allocated_product_qty"))
qty_done = request.product_id.uom_id._compute_quantity(
allocated_qty, request.product_uom_id)
if float_compare(qty_done, request.product_uom_qty,
precision_digits=precision) >= 0:
allocated_qty, request.product_uom_id
)
if (
float_compare(
qty_done, request.product_uom_qty, precision_digits=precision
)
>= 0
):
request.action_done()
return True
@@ -254,17 +260,16 @@ class StockRequest(models.Model):
move/po creation.
"""
return {
'date_planned': self.expected_date,
'warehouse_id': self.warehouse_id,
'stock_request_allocation_ids': self.id,
'group_id': group_id or self.procurement_group_id.id or False,
'route_ids': self.route_id,
'stock_request_id': self.id,
"date_planned": self.expected_date,
"warehouse_id": self.warehouse_id,
"stock_request_allocation_ids": self.id,
"group_id": group_id or self.procurement_group_id.id or False,
"route_ids": self.route_id,
"stock_request_id": self.id,
}
def _skip_procurement(self):
return self.state != 'draft' or \
self.product_id.type not in ('consu', 'product')
return self.state != "draft" or self.product_id.type not in ("consu", "product")
@api.multi
def _action_launch_procurement_rule(self):
@@ -275,61 +280,63 @@ class StockRequest(models.Model):
'_run_buy' or '_run_manufacture'
depending on the stock request product rule.
"""
precision = self.env['decimal.precision'].precision_get(
'Product Unit of Measure')
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
errors = []
for request in self:
if request._skip_procurement():
continue
qty = 0.0
for move in request.move_ids.filtered(
lambda r: r.state != 'cancel'):
for move in request.move_ids.filtered(lambda r: r.state != "cancel"):
qty += move.product_qty
if float_compare(qty, request.product_qty,
precision_digits=precision) >= 0:
if float_compare(qty, request.product_qty, precision_digits=precision) >= 0:
continue
values = request._prepare_procurement_values(
group_id=request.procurement_group_id)
group_id=request.procurement_group_id
)
try:
# We launch with sudo because potentially we could create
# objects that the user is not authorized to create, such
# as PO.
self.env['procurement.group'].sudo().run(
request.product_id, request.product_uom_qty,
self.env["procurement.group"].sudo().run(
request.product_id,
request.product_uom_qty,
request.product_uom_id,
request.location_id, request.name,
request.name, values)
request.location_id,
request.name,
request.name,
values,
)
except UserError as error:
errors.append(error.name)
if errors:
raise UserError('\n'.join(errors))
raise UserError("\n".join(errors))
return True
@api.multi
def action_view_transfer(self):
action = self.env.ref('stock.action_picking_tree_all').read()[0]
action = self.env.ref("stock.action_picking_tree_all").read()[0]
pickings = self.mapped('picking_ids')
pickings = self.mapped("picking_ids")
if len(pickings) > 1:
action['domain'] = [('id', 'in', pickings.ids)]
action["domain"] = [("id", "in", pickings.ids)]
elif pickings:
action['views'] = [
(self.env.ref('stock.view_picking_form').id, 'form')]
action['res_id'] = pickings.id
action["views"] = [(self.env.ref("stock.view_picking_form").id, "form")]
action["res_id"] = pickings.id
return action
@api.model
def create(self, vals):
upd_vals = vals.copy()
if upd_vals.get('name', '/') == '/':
upd_vals['name'] = self.env['ir.sequence'].next_by_code(
'stock.request')
if upd_vals.get("name", "/") == "/":
upd_vals["name"] = self.env["ir.sequence"].next_by_code("stock.request")
return super().create(upd_vals)
@api.multi
def unlink(self):
if self.filtered(lambda r: r.state != 'draft'):
raise UserError(_('Only requests on draft state can be unlinked'))
if self.filtered(lambda r: r.state != "draft"):
raise UserError(_("Only requests on draft state can be unlinked"))
return super(StockRequest, self).unlink()

View File

@@ -1,118 +1,133 @@
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models, _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.addons import decimal_precision as dp
class StockRequest(models.AbstractModel):
_name = "stock.request.abstract"
_description = "Stock Request Template"
_inherit = ['mail.thread', 'mail.activity.mixin']
_inherit = ["mail.thread", "mail.activity.mixin"]
@api.model
def default_get(self, fields):
res = super(StockRequest, self).default_get(fields)
warehouse = None
if 'warehouse_id' not in res and res.get('company_id'):
warehouse = self.env['stock.warehouse'].search(
[('company_id', '=', res['company_id'])], limit=1)
if "warehouse_id" not in res and res.get("company_id"):
warehouse = self.env["stock.warehouse"].search(
[("company_id", "=", res["company_id"])], limit=1
)
if warehouse:
res['warehouse_id'] = warehouse.id
res['location_id'] = warehouse.lot_stock_id.id
res["warehouse_id"] = warehouse.id
res["location_id"] = warehouse.lot_stock_id.id
return res
@api.depends('product_id', 'product_uom_id', 'product_uom_qty',
'product_id.product_tmpl_id.uom_id')
@api.depends(
"product_id",
"product_uom_id",
"product_uom_qty",
"product_id.product_tmpl_id.uom_id",
)
def _compute_product_qty(self):
for rec in self:
rec.product_qty = rec.product_uom_id._compute_quantity(
rec.product_uom_qty, rec.product_id.product_tmpl_id.uom_id)
rec.product_uom_qty, rec.product_id.product_tmpl_id.uom_id
)
name = fields.Char(
'Name', copy=False, required=True, readonly=True,
default='/')
name = fields.Char("Name", copy=False, required=True, readonly=True, default="/")
warehouse_id = fields.Many2one(
'stock.warehouse', 'Warehouse',
ondelete="cascade", required=True,
"stock.warehouse", "Warehouse", ondelete="cascade", required=True
)
location_id = fields.Many2one(
'stock.location', 'Location',
domain=[('usage', 'in', ['internal', 'transit'])],
ondelete="cascade", required=True,
"stock.location",
"Location",
domain=[("usage", "in", ["internal", "transit"])],
ondelete="cascade",
required=True,
)
product_id = fields.Many2one(
'product.product', 'Product',
domain=[('type', 'in', ['product', 'consu'])], ondelete='cascade',
"product.product",
"Product",
domain=[("type", "in", ["product", "consu"])],
ondelete="cascade",
required=True,
)
allow_virtual_location = fields.Boolean(
related='company_id.stock_request_allow_virtual_loc',
readonly=True,
related="company_id.stock_request_allow_virtual_loc", readonly=True
)
product_uom_id = fields.Many2one(
'uom.uom', 'Product Unit of Measure',
"uom.uom",
"Product Unit of Measure",
required=True,
default=lambda self: self._context.get('product_uom_id', False),
default=lambda self: self._context.get("product_uom_id", False),
)
product_uom_qty = fields.Float(
'Quantity', digits=dp.get_precision('Product Unit of Measure'),
"Quantity",
digits=dp.get_precision("Product Unit of Measure"),
required=True,
help="Quantity, specified in the unit of measure indicated in the "
"request.",
help="Quantity, specified in the unit of measure indicated in the " "request.",
)
product_qty = fields.Float(
'Real Quantity', compute='_compute_product_qty',
store=True, copy=False,
digits=dp.get_precision('Product Unit of Measure'),
help='Quantity in the default UoM of the product',
"Real Quantity",
compute="_compute_product_qty",
store=True,
copy=False,
digits=dp.get_precision("Product Unit of Measure"),
help="Quantity in the default UoM of the product",
)
procurement_group_id = fields.Many2one(
'procurement.group', 'Procurement Group',
"procurement.group",
"Procurement Group",
help="Moves created through this stock request will be put in this "
"procurement group. If none is given, the moves generated by "
"procurement rules will be grouped into one big picking.",
"procurement group. If none is given, the moves generated by "
"procurement rules will be grouped into one big picking.",
)
company_id = fields.Many2one(
'res.company', 'Company', required=True,
default=lambda self: self.env['res.company']._company_default_get(
'stock.request'),
"res.company",
"Company",
required=True,
default=lambda self: self.env["res.company"]._company_default_get(
"stock.request"
),
)
route_id = fields.Many2one(
"stock.location.route",
string="Route",
domain="[('id', 'in', route_ids)]",
ondelete="restrict",
)
route_id = fields.Many2one('stock.location.route', string='Route',
domain="[('id', 'in', route_ids)]",
ondelete='restrict')
route_ids = fields.Many2many(
'stock.location.route', string='Routes',
compute='_compute_route_ids',
"stock.location.route",
string="Routes",
compute="_compute_route_ids",
readonly=True,
)
_sql_constraints = [
('name_uniq', 'unique(name, company_id)',
'Name must be unique'),
("name_uniq", "unique(name, company_id)", "Name must be unique")
]
@api.depends('product_id', 'warehouse_id', 'location_id')
@api.depends("product_id", "warehouse_id", "location_id")
def _compute_route_ids(self):
route_obj = self.env['stock.location.route']
for wh in self.mapped('warehouse_id'):
wh_routes = route_obj.search(
[('warehouse_ids', '=', wh.id)])
route_obj = self.env["stock.location.route"]
for wh in self.mapped("warehouse_id"):
wh_routes = route_obj.search([("warehouse_ids", "=", wh.id)])
for record in self.filtered(lambda r: r.warehouse_id == wh):
routes = route_obj
if record.product_id:
routes += record.product_id.mapped(
'route_ids'
) | record.product_id.mapped(
'categ_id'
).mapped('total_route_ids')
"route_ids"
) | record.product_id.mapped("categ_id").mapped("total_route_ids")
if record.warehouse_id:
routes |= wh_routes
parents = record.get_parents().ids
record.route_ids = routes.filtered(lambda r: any(
p.location_id.id in parents for p in r.rule_ids))
record.route_ids = routes.filtered(
lambda r: any(p.location_id.id in parents for p in r.rule_ids)
)
def get_parents(self):
location = self.location_id
@@ -122,54 +137,80 @@ class StockRequest(models.AbstractModel):
result |= location
return result
@api.constrains('company_id', 'product_id', 'warehouse_id',
'location_id', 'route_id')
@api.constrains(
"company_id", "product_id", "warehouse_id", "location_id", "route_id"
)
def _check_company_constrains(self):
""" Check if the related models have the same company """
for rec in self:
if rec.product_id.company_id and \
rec.product_id.company_id != rec.company_id:
if (
rec.product_id.company_id
and rec.product_id.company_id != rec.company_id
):
raise ValidationError(
_('You have entered a product that is assigned '
'to another company.'))
if rec.location_id.company_id and \
rec.location_id.company_id != rec.company_id:
_(
"You have entered a product that is assigned "
"to another company."
)
)
if (
rec.location_id.company_id
and rec.location_id.company_id != rec.company_id
):
raise ValidationError(
_('You have entered a location that is '
'assigned to another company.'))
_(
"You have entered a location that is "
"assigned to another company."
)
)
if rec.warehouse_id.company_id != rec.company_id:
raise ValidationError(
_('You have entered a warehouse that is '
'assigned to another company.'))
if rec.route_id and rec.route_id.company_id and \
rec.route_id.company_id != rec.company_id:
_(
"You have entered a warehouse that is "
"assigned to another company."
)
)
if (
rec.route_id
and rec.route_id.company_id
and rec.route_id.company_id != rec.company_id
):
raise ValidationError(
_('You have entered a route that is '
'assigned to another company.'))
_(
"You have entered a route that is "
"assigned to another company."
)
)
@api.constrains('product_id')
@api.constrains("product_id")
def _check_product_uom(self):
''' Check if the UoM has the same category as the
product standard UoM '''
if any(request.product_id.uom_id.category_id !=
request.product_uom_id.category_id for request in self):
""" Check if the UoM has the same category as the
product standard UoM """
if any(
request.product_id.uom_id.category_id != request.product_uom_id.category_id
for request in self
):
raise ValidationError(
_('You have to select a product unit of measure in the '
'same category than the default unit '
'of measure of the product'))
_(
"You have to select a product unit of measure in the "
"same category than the default unit "
"of measure of the product"
)
)
@api.constrains('product_qty')
@api.constrains("product_qty")
def _check_qty(self):
for rec in self:
if rec.product_qty <= 0:
raise ValueError(_('Stock Request product quantity has to be'
' strictly positive.'))
raise ValueError(
_("Stock Request product quantity has to be" " strictly positive.")
)
@api.onchange('warehouse_id')
@api.onchange("warehouse_id")
def onchange_warehouse_id(self):
""" Finds location id for changed warehouse. """
res = {'domain': {}}
if self._name == 'stock.request' and self.order_id:
res = {"domain": {}}
if self._name == "stock.request" and self.order_id:
# When the stock request is created from an order the wh and
# location are taken from the order and we rely on it to change
# all request associated. Thus, no need to apply
@@ -183,42 +224,41 @@ class StockRequest(models.AbstractModel):
self.company_id = self.warehouse_id.company_id
return res
@api.onchange('location_id')
@api.onchange("location_id")
def onchange_location_id(self):
if self.location_id:
loc_wh = self.location_id.sudo().get_warehouse()
if loc_wh and self.warehouse_id != loc_wh:
self.warehouse_id = loc_wh
self.with_context(
no_change_childs=True).onchange_warehouse_id()
self.with_context(no_change_childs=True).onchange_warehouse_id()
@api.onchange('allow_virtual_location')
@api.onchange("allow_virtual_location")
def onchange_allow_virtual_location(self):
if self.allow_virtual_location:
return {'domain': {'location_id': []}}
return {"domain": {"location_id": []}}
@api.onchange('company_id')
@api.onchange("company_id")
def onchange_company_id(self):
""" Sets a default warehouse when the company is changed and limits
the user selection of warehouses. """
if self.company_id and (
not self.warehouse_id or
self.warehouse_id.company_id != self.company_id):
self.warehouse_id = self.env['stock.warehouse'].search(
[('company_id', '=', self.company_id.id)], limit=1)
not self.warehouse_id or self.warehouse_id.company_id != self.company_id
):
self.warehouse_id = self.env["stock.warehouse"].search(
[("company_id", "=", self.company_id.id)], limit=1
)
self.onchange_warehouse_id()
return {
'domain': {
'warehouse_id': [('company_id', '=', self.company_id.id)]}}
return {"domain": {"warehouse_id": [("company_id", "=", self.company_id.id)]}}
@api.onchange('product_id')
@api.onchange("product_id")
def onchange_product_id(self):
res = {'domain': {}}
res = {"domain": {}}
if self.product_id:
self.product_uom_id = self.product_id.uom_id.id
res['domain']['product_uom_id'] = [
('category_id', '=', self.product_id.uom_id.category_id.id)]
res["domain"]["product_uom_id"] = [
("category_id", "=", self.product_id.uom_id.category_id.id)
]
return res
res['domain']['product_uom_id'] = []
res["domain"]["product_uom_id"] = []
return res

View File

@@ -5,67 +5,84 @@ from odoo import api, fields, models
class StockRequestAllocation(models.Model):
_name = 'stock.request.allocation'
_description = 'Stock Request Allocation'
_name = "stock.request.allocation"
_description = "Stock Request Allocation"
stock_request_id = fields.Many2one(string='Stock Request',
comodel_name='stock.request',
required=True, ondelete='cascade',
)
company_id = fields.Many2one(string='Company',
comodel_name='res.company',
readonly=True,
related='stock_request_id.company_id',
store=True,
)
stock_move_id = fields.Many2one(string='Stock Move',
comodel_name='stock.move',
required=True, ondelete='cascade',
)
product_id = fields.Many2one(string='Product',
comodel_name='product.product',
related='stock_request_id.product_id',
readonly=True,
)
product_uom_id = fields.Many2one(string='UoM', comodel_name='uom.uom',
related='stock_request_id.product_uom_id',
readonly=True,
)
stock_request_id = fields.Many2one(
string="Stock Request",
comodel_name="stock.request",
required=True,
ondelete="cascade",
)
company_id = fields.Many2one(
string="Company",
comodel_name="res.company",
readonly=True,
related="stock_request_id.company_id",
store=True,
)
stock_move_id = fields.Many2one(
string="Stock Move",
comodel_name="stock.move",
required=True,
ondelete="cascade",
)
product_id = fields.Many2one(
string="Product",
comodel_name="product.product",
related="stock_request_id.product_id",
readonly=True,
)
product_uom_id = fields.Many2one(
string="UoM",
comodel_name="uom.uom",
related="stock_request_id.product_uom_id",
readonly=True,
)
requested_product_uom_qty = fields.Float(
'Requested Quantity (UoM)',
help='Quantity of the stock request allocated to the stock move, '
'in the UoM of the Stock Request',
"Requested Quantity (UoM)",
help="Quantity of the stock request allocated to the stock move, "
"in the UoM of the Stock Request",
)
requested_product_qty = fields.Float(
'Requested Quantity',
help='Quantity of the stock request allocated to the stock move, '
'in the default UoM of the product',
compute='_compute_requested_product_qty'
"Requested Quantity",
help="Quantity of the stock request allocated to the stock move, "
"in the default UoM of the product",
compute="_compute_requested_product_qty",
)
allocated_product_qty = fields.Float(
'Allocated Quantity',
help='Quantity of the stock request allocated to the stock move, '
'in the default UoM of the product',
"Allocated Quantity",
help="Quantity of the stock request allocated to the stock move, "
"in the default UoM of the product",
)
open_product_qty = fields.Float(
"Open Quantity", compute="_compute_open_product_qty"
)
open_product_qty = fields.Float('Open Quantity',
compute='_compute_open_product_qty')
@api.depends('stock_request_id.product_id',
'stock_request_id.product_uom_id',
'requested_product_uom_qty')
@api.depends(
"stock_request_id.product_id",
"stock_request_id.product_uom_id",
"requested_product_uom_qty",
)
def _compute_requested_product_qty(self):
for rec in self:
rec.requested_product_qty = rec.product_uom_id._compute_quantity(
rec.requested_product_uom_qty, rec.product_id.uom_id)
rec.requested_product_uom_qty, rec.product_id.uom_id
)
@api.depends('requested_product_qty', 'allocated_product_qty',
'stock_move_id', 'stock_move_id.state')
@api.depends(
"requested_product_qty",
"allocated_product_qty",
"stock_move_id",
"stock_move_id.state",
)
def _compute_open_product_qty(self):
for rec in self:
if rec.stock_move_id.state == 'cancel':
if rec.stock_move_id.state == "cancel":
rec.open_product_qty = 0.0
else:
rec.open_product_qty = \
rec.open_product_qty = (
rec.requested_product_qty - rec.allocated_product_qty
)
if rec.open_product_qty < 0.0:
rec.open_product_qty = 0.0

View File

@@ -1,163 +1,190 @@
# Copyright 2018 Creu Blanca
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError, AccessError
from odoo import _, api, fields, models
from odoo.exceptions import AccessError, UserError, ValidationError
class StockRequestOrder(models.Model):
_name = 'stock.request.order'
_description = 'Stock Request Order'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'id desc'
_name = "stock.request.order"
_description = "Stock Request Order"
_inherit = ["mail.thread", "mail.activity.mixin"]
_order = "id desc"
@api.model
def default_get(self, fields):
res = super().default_get(fields)
warehouse = None
if 'warehouse_id' not in res and res.get('company_id'):
warehouse = self.env['stock.warehouse'].search(
[('company_id', '=', res['company_id'])], limit=1)
if "warehouse_id" not in res and res.get("company_id"):
warehouse = self.env["stock.warehouse"].search(
[("company_id", "=", res["company_id"])], limit=1
)
if warehouse:
res['warehouse_id'] = warehouse.id
res['location_id'] = warehouse.lot_stock_id.id
res["warehouse_id"] = warehouse.id
res["location_id"] = warehouse.lot_stock_id.id
return res
def __get_request_order_states(self):
return self.env['stock.request']._get_request_states()
return self.env["stock.request"]._get_request_states()
def _get_request_order_states(self):
return self.__get_request_order_states()
def _get_default_requested_by(self):
return self.env['res.users'].browse(self.env.uid)
return self.env["res.users"].browse(self.env.uid)
name = fields.Char(
'Name', copy=False, required=True, readonly=True,
states={'draft': [('readonly', False)]},
default='/')
"Name",
copy=False,
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
default="/",
)
state = fields.Selection(
selection=_get_request_order_states,
string='Status', copy=False, default='draft', index=True,
readonly=True, track_visibility='onchange',
string="Status",
copy=False,
default="draft",
index=True,
readonly=True,
track_visibility="onchange",
)
requested_by = fields.Many2one(
'res.users', 'Requested by', required=True,
track_visibility='onchange',
"res.users",
"Requested by",
required=True,
track_visibility="onchange",
default=lambda s: s._get_default_requested_by(),
)
warehouse_id = fields.Many2one(
'stock.warehouse', 'Warehouse', readonly=True,
ondelete="cascade", required=True,
states={'draft': [('readonly', False)]})
"stock.warehouse",
"Warehouse",
readonly=True,
ondelete="cascade",
required=True,
states={"draft": [("readonly", False)]},
)
location_id = fields.Many2one(
'stock.location', 'Location', readonly=True,
domain=[('usage', 'in', ['internal', 'transit'])],
ondelete="cascade", required=True,
states={'draft': [('readonly', False)]},
"stock.location",
"Location",
readonly=True,
domain=[("usage", "in", ["internal", "transit"])],
ondelete="cascade",
required=True,
states={"draft": [("readonly", False)]},
)
allow_virtual_location = fields.Boolean(
related='company_id.stock_request_allow_virtual_loc',
readonly=True,
related="company_id.stock_request_allow_virtual_loc", readonly=True
)
procurement_group_id = fields.Many2one(
'procurement.group', 'Procurement Group', readonly=True,
states={'draft': [('readonly', False)]},
"procurement.group",
"Procurement Group",
readonly=True,
states={"draft": [("readonly", False)]},
help="Moves created through this stock request will be put in this "
"procurement group. If none is given, the moves generated by "
"procurement rules will be grouped into one big picking.",
"procurement group. If none is given, the moves generated by "
"procurement rules will be grouped into one big picking.",
)
company_id = fields.Many2one(
'res.company', 'Company', required=True, readonly=True,
states={'draft': [('readonly', False)]},
default=lambda self: self.env['res.company']._company_default_get(
'stock.request.order'),
"res.company",
"Company",
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
default=lambda self: self.env["res.company"]._company_default_get(
"stock.request.order"
),
)
expected_date = fields.Datetime(
'Expected Date', default=fields.Datetime.now, index=True,
required=True, readonly=True,
states={'draft': [('readonly', False)]},
"Expected Date",
default=fields.Datetime.now,
index=True,
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
help="Date when you expect to receive the goods.",
)
picking_policy = fields.Selection([
('direct', 'Receive each product when available'),
('one', 'Receive all products at once')],
string='Shipping Policy', required=True, readonly=True,
states={'draft': [('readonly', False)]},
default='direct',
picking_policy = fields.Selection(
[
("direct", "Receive each product when available"),
("one", "Receive all products at once"),
],
string="Shipping Policy",
required=True,
readonly=True,
states={"draft": [("readonly", False)]},
default="direct",
)
move_ids = fields.One2many(
comodel_name="stock.move",
compute="_compute_move_ids",
string="Stock Moves",
readonly=True,
)
picking_ids = fields.One2many(
"stock.picking",
compute="_compute_picking_ids",
string="Pickings",
readonly=True,
)
picking_count = fields.Integer(
string="Delivery Orders", compute="_compute_picking_ids", readonly=True
)
move_ids = fields.One2many(comodel_name='stock.move',
compute='_compute_move_ids',
string='Stock Moves', readonly=True,
)
picking_ids = fields.One2many('stock.picking',
compute='_compute_picking_ids',
string='Pickings', readonly=True,
)
picking_count = fields.Integer(string='Delivery Orders',
compute='_compute_picking_ids',
readonly=True,
)
stock_request_ids = fields.One2many(
'stock.request',
inverse_name='order_id',
copy=True,
"stock.request", inverse_name="order_id", copy=True
)
stock_request_count = fields.Integer(
string='Stock requests',
compute='_compute_stock_request_count',
readonly=True,
string="Stock requests", compute="_compute_stock_request_count", readonly=True
)
_sql_constraints = [
('name_uniq', 'unique(name, company_id)',
'Stock Request name must be unique'),
("name_uniq", "unique(name, company_id)", "Stock Request name must be unique")
]
@api.depends('stock_request_ids.allocation_ids')
@api.depends("stock_request_ids.allocation_ids")
def _compute_picking_ids(self):
for record in self:
record.picking_ids = record.stock_request_ids.mapped('picking_ids')
record.picking_ids = record.stock_request_ids.mapped("picking_ids")
record.picking_count = len(record.picking_ids)
@api.depends('stock_request_ids')
@api.depends("stock_request_ids")
def _compute_move_ids(self):
for record in self:
record.move_ids = record.stock_request_ids.mapped('move_ids')
record.move_ids = record.stock_request_ids.mapped("move_ids")
@api.depends('stock_request_ids')
@api.depends("stock_request_ids")
def _compute_stock_request_count(self):
for record in self:
record.stock_request_count = len(record.stock_request_ids)
@api.onchange('requested_by')
@api.onchange("requested_by")
def onchange_requested_by(self):
self.change_childs()
@api.onchange('expected_date')
@api.onchange("expected_date")
def onchange_expected_date(self):
self.change_childs()
@api.onchange('picking_policy')
@api.onchange("picking_policy")
def onchange_picking_policy(self):
self.change_childs()
@api.onchange('location_id')
@api.onchange("location_id")
def onchange_location_id(self):
if self.location_id:
loc_wh = self.location_id.sudo().get_warehouse()
if loc_wh and self.warehouse_id != loc_wh:
self.warehouse_id = loc_wh
self.with_context(
no_change_childs=True).onchange_warehouse_id()
self.with_context(no_change_childs=True).onchange_warehouse_id()
self.change_childs()
@api.onchange('allow_virtual_location')
@api.onchange("allow_virtual_location")
def onchange_allow_virtual_location(self):
if self.allow_virtual_location:
return {'domain': {'location_id': []}}
return {"domain": {"location_id": []}}
@api.onchange('warehouse_id')
@api.onchange("warehouse_id")
def onchange_warehouse_id(self):
if self.warehouse_id:
# search with sudo because the user may not have permissions
@@ -170,26 +197,25 @@ class StockRequestOrder(models.Model):
self.with_context(no_change_childs=True).onchange_company_id()
self.change_childs()
@api.onchange('procurement_group_id')
@api.onchange("procurement_group_id")
def onchange_procurement_group_id(self):
self.change_childs()
@api.onchange('company_id')
@api.onchange("company_id")
def onchange_company_id(self):
if self.company_id and (
not self.warehouse_id or
self.warehouse_id.sudo().company_id != self.company_id
not self.warehouse_id
or self.warehouse_id.sudo().company_id != self.company_id
):
self.warehouse_id = self.env['stock.warehouse'].search(
[('company_id', '=', self.company_id.id)], limit=1)
self.warehouse_id = self.env["stock.warehouse"].search(
[("company_id", "=", self.company_id.id)], limit=1
)
self.with_context(no_change_childs=True).onchange_warehouse_id()
self.change_childs()
return {
'domain': {
'warehouse_id': [('company_id', '=', self.company_id.id)]}}
return {"domain": {"warehouse_id": [("company_id", "=", self.company_id.id)]}}
def change_childs(self):
if not self._context.get('no_change_childs', False):
if not self._context.get("no_change_childs", False):
for line in self.stock_request_ids:
line.warehouse_id = self.warehouse_id
line.location_id = self.location_id
@@ -203,121 +229,142 @@ class StockRequestOrder(models.Model):
def action_confirm(self):
for line in self.stock_request_ids:
line.action_confirm()
self.state = 'open'
self.state = "open"
return True
def action_draft(self):
for line in self.stock_request_ids:
line.action_draft()
self.state = 'draft'
self.state = "draft"
return True
def action_cancel(self):
for line in self.stock_request_ids:
line.action_cancel()
self.state = 'cancel'
self.state = "cancel"
return True
def action_done(self):
self.state = 'done'
self.state = "done"
return True
def check_done(self):
if not self.stock_request_ids.filtered(lambda r: r.state != 'done'):
if not self.stock_request_ids.filtered(lambda r: r.state != "done"):
self.action_done()
return
@api.multi
def action_view_transfer(self):
action = self.env.ref('stock.action_picking_tree_all').read()[0]
action = self.env.ref("stock.action_picking_tree_all").read()[0]
pickings = self.mapped('picking_ids')
pickings = self.mapped("picking_ids")
if len(pickings) > 1:
action['domain'] = [('id', 'in', pickings.ids)]
action["domain"] = [("id", "in", pickings.ids)]
elif pickings:
action['views'] = [
(self.env.ref('stock.view_picking_form').id, 'form')]
action['res_id'] = pickings.id
action["views"] = [(self.env.ref("stock.view_picking_form").id, "form")]
action["res_id"] = pickings.id
return action
@api.multi
def action_view_stock_requests(self):
action = self.env.ref(
'stock_request.action_stock_request_form').read()[0]
action = self.env.ref("stock_request.action_stock_request_form").read()[0]
if len(self.stock_request_ids) > 1:
action['domain'] = [('order_id', 'in', self.ids)]
action["domain"] = [("order_id", "in", self.ids)]
elif self.stock_request_ids:
action['views'] = [
(self.env.ref(
'stock_request.view_stock_request_form').id, 'form')]
action['res_id'] = self.stock_request_ids.id
action["views"] = [
(self.env.ref("stock_request.view_stock_request_form").id, "form")
]
action["res_id"] = self.stock_request_ids.id
return action
@api.model
def create(self, vals):
upd_vals = vals.copy()
if upd_vals.get('name', '/') == '/':
upd_vals['name'] = self.env['ir.sequence'].next_by_code(
'stock.request.order')
if upd_vals.get("name", "/") == "/":
upd_vals["name"] = self.env["ir.sequence"].next_by_code(
"stock.request.order"
)
return super().create(upd_vals)
@api.multi
def unlink(self):
if self.filtered(lambda r: r.state != 'draft'):
raise UserError(_('Only orders on draft state can be unlinked'))
if self.filtered(lambda r: r.state != "draft"):
raise UserError(_("Only orders on draft state can be unlinked"))
return super().unlink()
@api.constrains('warehouse_id', 'company_id')
@api.constrains("warehouse_id", "company_id")
def _check_warehouse_company(self):
if any(request.warehouse_id.company_id !=
request.company_id for request in self):
if any(
request.warehouse_id.company_id != request.company_id for request in self
):
raise ValidationError(
_('The company of the stock request must match with '
'that of the warehouse.'))
_(
"The company of the stock request must match with "
"that of the warehouse."
)
)
@api.constrains('location_id', 'company_id')
@api.constrains("location_id", "company_id")
def _check_location_company(self):
if any(request.location_id.company_id and
request.location_id.company_id !=
request.company_id for request in self):
if any(
request.location_id.company_id
and request.location_id.company_id != request.company_id
for request in self
):
raise ValidationError(
_('The company of the stock request must match with '
'that of the location.'))
_(
"The company of the stock request must match with "
"that of the location."
)
)
@api.model
def _create_from_product_multiselect(self, products):
if not products:
return False
if products._name not in ('product.product', 'product.template'):
if products._name not in ("product.product", "product.template"):
raise ValidationError(
_("This action only works in the context of products"))
if products._name == 'product.template':
_("This action only works in the context of products")
)
if products._name == "product.template":
# search instead of mapped so we don't include archived variants
products = self.env['product.product'].search([
('product_tmpl_id', 'in', products.ids)
])
expected = self.default_get(['expected_date'])['expected_date']
products = self.env["product.product"].search(
[("product_tmpl_id", "in", products.ids)]
)
expected = self.default_get(["expected_date"])["expected_date"]
try:
order = self.env['stock.request.order'].create(dict(
expected_date=expected,
stock_request_ids=[(0, 0, dict(
product_id=product.id,
product_uom_id=product.uom_id.id,
product_uom_qty=1.0,
order = self.env["stock.request.order"].create(
dict(
expected_date=expected,
)) for product in products]
))
stock_request_ids=[
(
0,
0,
dict(
product_id=product.id,
product_uom_id=product.uom_id.id,
product_uom_qty=1.0,
expected_date=expected,
),
)
for product in products
],
)
)
except AccessError:
# TODO: if there is a nice way to hide the action from the
# Action-menu if the user doesn't have the necessary rights,
# that would be a better way of doing this
raise UserError(_(
"Unfortunately it seems you do not have the necessary rights "
"for creating stock requests. Please contact your "
"administrator."))
action = self.env.ref('stock_request.stock_request_order_action'
).read()[0]
action['views'] = [(
self.env.ref('stock_request.stock_request_order_form').id, 'form')]
action['res_id'] = order.id
raise UserError(
_(
"Unfortunately it seems you do not have the necessary rights "
"for creating stock requests. Please contact your "
"administrator."
)
)
action = self.env.ref("stock_request.stock_request_order_action").read()[0]
action["views"] = [
(self.env.ref("stock_request.stock_request_order_form").id, "form")
]
action["res_id"] = order.id
return action

View File

@@ -5,16 +5,38 @@ from odoo import models
class StockRule(models.Model):
_inherit = 'stock.rule'
_inherit = "stock.rule"
def _get_stock_move_values(self, product_id, product_qty, product_uom,
location_id, name, origin, values, group_id):
def _get_stock_move_values(
self,
product_id,
product_qty,
product_uom,
location_id,
name,
origin,
values,
group_id,
):
result = super(StockRule, self)._get_stock_move_values(
product_id, product_qty, product_uom,
location_id, name, origin, values, group_id)
if values.get('stock_request_id', False):
result['allocation_ids'] = [(0, 0, {
'stock_request_id': values.get('stock_request_id'),
'requested_product_uom_qty': product_qty,
})]
product_id,
product_qty,
product_uom,
location_id,
name,
origin,
values,
group_id,
)
if values.get("stock_request_id", False):
result["allocation_ids"] = [
(
0,
0,
{
"stock_request_id": values.get("stock_request_id"),
"requested_product_uom_qty": product_qty,
},
)
]
return result

View File

@@ -1,28 +1,46 @@
# Copyright 2018 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, models, _
from odoo import _, api, models
from odoo.exceptions import ValidationError
class StockWarehouse(models.Model):
_inherit = 'stock.warehouse'
_inherit = "stock.warehouse"
@api.constrains('company_id')
@api.constrains("company_id")
def _check_company_stock_request(self):
if any(self.env['stock.request'].search(
[('company_id', '!=', rec.company_id.id),
('warehouse_id', '=', rec.id)], limit=1)
for rec in self):
if any(
self.env["stock.request"].search(
[
("company_id", "!=", rec.company_id.id),
("warehouse_id", "=", rec.id),
],
limit=1,
)
for rec in self
):
raise ValidationError(
_('You cannot change the company of the warehouse, as it is '
'already assigned to stock requests that belong to '
'another company.'))
if any(self.env['stock.request.order'].search(
[('company_id', '!=', rec.company_id.id),
('warehouse_id', '=', rec.id)], limit=1)
for rec in self):
_(
"You cannot change the company of the warehouse, as it is "
"already assigned to stock requests that belong to "
"another company."
)
)
if any(
self.env["stock.request.order"].search(
[
("company_id", "!=", rec.company_id.id),
("warehouse_id", "=", rec.id),
],
limit=1,
)
for rec in self
):
raise ValidationError(
_('You cannot change the company of the warehouse, as it is '
'already assigned to stock request orders that belong to '
'another company.'))
_(
"You cannot change the company of the warehouse, as it is "
"already assigned to stock request orders that belong to "
"another company."
)
)

View File

@@ -39,7 +39,7 @@
<field name="global" eval="True"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<record id="stock_request_followers_rule" model="ir.rule">
<field name="name">Follow Stock Request</field>
<field name="model_id" ref="model_stock_request"/>
@@ -51,7 +51,7 @@
<field name="domain_force">['|',('requested_by','=',user.id),
('message_partner_ids', 'in', [user.partner_id.id])]</field>
</record>
<record id="stock_request_rule" model="ir.rule">
<field name="name">Stock Request User</field>
<field name="model_id" ref="model_stock_request"/>
@@ -62,7 +62,7 @@
<field name="perm_unlink" eval="True"/>
<field name="domain_force">[('requested_by','=',user.id)]</field>
</record>
<record id="stock_request_manager_rule" model="ir.rule">
<field name="name">Stock Request Manager</field>
<field name="model_id" ref="model_stock_request"/>

View File

@@ -1,2 +1 @@
from . import test_stock_request

File diff suppressed because it is too large Load Diff