Initial commit: Ventor Odoo packages (4 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:49:21 +02:00
commit 1f20ad87e6
190 changed files with 10375 additions and 0 deletions

View file

@ -0,0 +1,12 @@
# Copyright 2020 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
from . import stock_location
from . import stock_picking
from . import stock_quant
from . import res_company
from . import res_config
from . import res_users
from . import stock_warehouse
from . import ventor_option_setting
from . import pallet_transfer

View file

@ -0,0 +1,37 @@
# Copyright 2022 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
# Odoo:
from odoo import _, api, fields, models
class PalletTransfer(models.Model):
_name = "pallet.transfer"
_description = "All Pallet Transfers"
name = fields.Char(
string="Transfer Name",
required=True,
default="New",
)
pallet_name = fields.Char(string="Pallet Name")
pallet_id = fields.Many2one("stock.location", string="Pallets")
source_location_id = fields.Many2one("stock.location", string="Source Location")
destination_location_id = fields.Many2one("stock.location", string="Destination Location")
def update_value(self):
self.write(
{
"name": self.env["ir.sequence"].next_by_code("pallet.transfer"),
"pallet_name": self.pallet_id.name,
"source_location_id": self.pallet_id.location_id,
}
)
self.pallet_id.location_id = self.destination_location_id
@api.model_create_multi
def create(self, vals_list):
res = super().create(vals_list)
if res:
res.update_value()
return res

View file

@ -0,0 +1,58 @@
# Copyright 2020 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
from odoo import _, models, fields
from odoo.exceptions import UserError
import io
import base64
from PIL import Image
LOGOTYPE_W = 500
LOGOTYPE_H = 500
class Company(models.Model):
_inherit = 'res.company'
barcode_on_picking_document = fields.Boolean(
string='Show Sales Order Barcode on Picking document',
help='Showing a barcode of the related sales order on all printed picking documents',
)
force_lot_validation_on_inventory_adjustment = fields.Boolean(
string='Force Lot Validation on Inventory Adjustment',
)
logotype_file = fields.Binary('Ventor Application Logo File', default=False)
def _validate_logotype(self, vals):
if not vals.get('logotype_file'):
return False
dat = base64.decodebytes(vals.get('logotype_file'))
image = Image.open(io.BytesIO(dat))
if image.format.lower() != 'png':
raise UserError(
_(
'Apparently, the logotype is not a .png file'
' or the file was incorrectly converted to .png format'
)
)
if int(image.width) < LOGOTYPE_W or int(image.height) < LOGOTYPE_H:
raise UserError(
_(
'The logotype can\'t be less than {}x{} px.'.format(LOGOTYPE_W, LOGOTYPE_H)
)
)
return True
def write(self, vals):
if 'logotype_file' in vals:
self._validate_logotype(vals)
res = super(Company, self).write(vals)
return res

View file

@ -0,0 +1,182 @@
# Copyright 2020 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
from odoo import models, fields, api
import logging
_logger = logging.getLogger(__name__)
class VentorConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
logotype_file = fields.Binary(
string='Ventor Application Logo File',
related='company_id.logotype_file',
readonly=False
)
module_outgoing_routing = fields.Boolean(
string='Outgoing Routing'
)
add_barcode_on_view = fields.Boolean(
string='Show the Location barcode field on the form',
)
base_version = fields.Char(
string='Base Module Version',
compute='_compute_base_version',
store=False,
)
barcode_on_picking_document = fields.Boolean(
string='Show Sales Order Barcode on Picking document',
readonly=False,
related='company_id.barcode_on_picking_document',
)
force_lot_validation_on_inventory_adjustment = fields.Boolean(
string='Force Lot Validation on Inventory Adjustment',
readonly=False,
related='company_id.force_lot_validation_on_inventory_adjustment',
)
custom_package_name = fields.Char(
string='Custom package name',
config_parameter='ventor_base.custom_package_name',
)
@api.depends('company_id')
def _compute_base_version(self):
self.env.cr.execute(
"SELECT latest_version FROM ir_module_module WHERE name='ventor_base'"
)
result = self.env.cr.fetchone()
full_version = result and result[0]
split_value = full_version and full_version.split('.')
self.base_version = split_value and '.'.join(split_value[-3:])
@api.model
def get_values(self):
res = super(VentorConfigSettings, self).get_values()
view_with_barcode = self.env.ref(
'ventor_base.view_location_form_inherit_additional_barcode',
raise_if_not_found=False
)
if view_with_barcode:
res['add_barcode_on_view'] = view_with_barcode.active
return res
def _set_apply_default_lots(self, previous_group):
operation_type_ids = self.env['stock.picking.type'].search([])
group_stock_production_lot = previous_group.get('group_stock_production_lot')
if (
group_stock_production_lot != self.group_stock_production_lot
and not self.group_stock_production_lot
):
operation_type_ids.apply_default_lots = False
ventor_apply_default_lots = self.env['ventor.option.setting'].search(
[
('technical_name', '=', 'apply_default_lots'),
]
)
ventor_apply_default_lots.with_context(
disable_apply_default_lots=True
).set_apply_default_lots_fields(self.group_stock_production_lot)
def _set_packages_fields(self, previous_group):
operation_type_ids = self.env['stock.picking.type'].search([])
group_stock_tracking_lot = previous_group.get('group_stock_tracking_lot')
if group_stock_tracking_lot != self.group_stock_tracking_lot:
operation_type_ids.manage_packages = self.group_stock_tracking_lot
operation_type_ids.show_put_in_pack_button = self.group_stock_tracking_lot
if not self.group_stock_tracking_lot:
operation_type_ids.show_put_in_pack_button = self.group_stock_tracking_lot
operation_type_ids.scan_destination_package = self.group_stock_tracking_lot
operation_type_ids.confirm_source_package = self.group_stock_tracking_lot
operation_type_ids.allow_creating_new_packages = self.group_stock_tracking_lot
ventor_packages_settings = self.env['ventor.option.setting'].search(
[
(
'technical_name',
'in',
(
'confirm_source_package',
'scan_destination_package',
'manage_packages',
'allow_creating_new_packages',
'pack_all_items',
'use_reusable_packages',
),
),
]
)
ventor_packages_settings.with_context(
disable_package_fields=True
).set_related_package_fields(self.group_stock_tracking_lot)
if self.group_stock_tracking_lot:
ventor_packages_settings = self.env['ventor.option.setting'].search(
[
('technical_name', '=', 'manage_packages'),
]
)
ventor_packages_settings.value = self.env.ref('ventor_base.bool_true')
def _set_manage_product_owner(self, previous_group):
operation_type_ids = self.env['stock.picking.type'].search([])
group_stock_tracking_owner = previous_group.get('group_stock_tracking_owner')
if group_stock_tracking_owner != self.group_stock_tracking_owner:
operation_type_ids.manage_product_owner = self.group_stock_tracking_owner
ventor_owner_settings = self.env['ventor.option.setting'].search(
[
('technical_name', '=', 'manage_product_owner'),
]
)
ventor_owner_settings.value = self.env.ref('ventor_base.bool_true') if self.group_stock_tracking_owner else self.env.ref('ventor_base.bool_false')
def _update_display_wave_picking_menu(self, previous_group):
group_stock_picking_wave = previous_group.get('group_stock_picking_wave')
if group_stock_picking_wave != self.group_stock_picking_wave:
merp_wave_picking_menu = self.env.ref('ventor_base.merp_wave_picking_menu')
users = self.env['res.users'].with_context(active_test=False).search([
('share', '=', False)
])
merp_wave_picking_menu.write(
{
'users': [(6, 0, users.ids)]
if self.group_stock_picking_wave
else [(5, 0, 0)],
}
)
def set_values(self):
previous_group = self.default_get(
[
'group_stock_tracking_lot',
'group_stock_tracking_owner',
'group_stock_production_lot',
'group_stock_picking_wave',
]
)
res = super(VentorConfigSettings, self).set_values()
view_with_barcode = self.env.ref('ventor_base.view_location_form_inherit_additional_barcode')
view_with_barcode.active = self.add_barcode_on_view
# Updating the values of dependent fields
self.sudo()._set_apply_default_lots(previous_group)
self.sudo()._set_packages_fields(previous_group)
self.sudo()._set_manage_product_owner(previous_group)
# Updating the menu display in Ventor for users
self.sudo()._update_display_wave_picking_menu(previous_group)
return res

View file

@ -0,0 +1,131 @@
# Copyright 2020 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
import json
from odoo import api, models, fields
class ResUsers(models.Model):
_inherit = 'res.users'
allowed_warehouse_ids = fields.Many2many(
comodel_name='stock.warehouse',
string='Allowed Warehouses',
help='List of all warehouses user has access to',
)
custom_package_name = fields.Char(
string='Custom Build Name',
compute="_compute_custom_package_name",
compute_sudo=True,
)
ventor_base_version = fields.Char(
compute="_compute_ventor_base_version",
compute_sudo=True,
readonly=True,
)
ventor_global_settings = fields.Text(
string='Global Settings',
readonly=True,
compute='_compute_global_settings'
)
ventor_user_settings = fields.Text(
string='User Settings'
)
@property
def SELF_READABLE_FIELDS(self):
readable_fields = [
'ventor_global_settings',
'ventor_user_settings',
'custom_package_name',
'ventor_base_version',
]
return super().SELF_READABLE_FIELDS + readable_fields
@property
def SELF_WRITEABLE_FIELDS(self):
writable_fields = ['ventor_user_settings']
return super().SELF_WRITEABLE_FIELDS + writable_fields
def _compute_custom_package_name(self):
custom_package_name = (
self.env["ir.config_parameter"]
.get_param("ventor_base.custom_package_name", "")
)
self.custom_package_name = custom_package_name
def _compute_ventor_base_version(self):
ventor_base_version = (
self.env["ir.module.module"]
.search([("name", "=", "ventor_base"), ("state", "=", "installed")])
.latest_version
)
for user in self:
if ventor_base_version:
user.ventor_base_version = ventor_base_version
else:
user.ventor_base_version = ""
def _compute_global_settings(self):
settings = []
for stock_picking_type in self.env['stock.picking.type'].search([]):
stock_picking_type_settings = stock_picking_type.get_warehouse_operation_settings()
if stock_picking_type.code != 'outgoing':
stock_picking_type_settings['settings'].pop('check_shipping_information')
if stock_picking_type.code != 'incoming':
stock_picking_type_settings['settings'].pop('hide_qty_to_receive')
settings.append(stock_picking_type_settings)
ventor_option_settings = self._get_ventor_option_settings()
obj = {'operation_types': settings}
obj.update(ventor_option_settings)
self.ventor_global_settings = json.dumps(
obj=obj,
indent=' ',
sort_keys=True
)
def _get_ventor_option_settings(self):
ventor_option_settings = self.env['ventor.option.setting'].sudo().get_general_settings()
if self.env.ref('ventor_base.merp_wave_picking_menu') not in self.groups_id:
ventor_option_settings.pop('wave_picking')
return ventor_option_settings
def _update_group_picking_wave_menu(self, vals):
vals = self._remove_reified_groups(vals)
if 'groups_id' in vals:
group_stock_picking_wave = self.env.ref('stock.group_stock_picking_wave')
merp_wave_picking_menu = self.env.ref('ventor_base.merp_wave_picking_menu')
for user in self:
if group_stock_picking_wave not in user.groups_id and merp_wave_picking_menu in user.groups_id:
merp_wave_picking_menu.write({'users': [(3, user.id)]})
@api.model_create_multi
def create(self, vals_list):
result = super().create(vals_list)
if not result.allowed_warehouse_ids:
result.write(
{
'allowed_warehouse_ids': [
(
6, 0, self.env["stock.warehouse"].sudo().with_context(active_test=False).search([]).ids
)
]
}
)
return result
def write(self, vals):
result = super().write(vals)
if result and 'allowed_warehouse_ids' in vals:
self.env['ir.rule'].clear_caches()
self._update_group_picking_wave_menu(vals)
return result

View file

@ -0,0 +1,14 @@
# Copyright 2021 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
# Odoo:
from odoo import api, fields, models
class StockLocation(models.Model):
_inherit = "stock.location"
# store attribute for Group By 'Warehouse', locations tree view
warehouse_id = fields.Many2one(store=True)
is_pallet = fields.Boolean(string="Is Pallet")

View file

@ -0,0 +1,299 @@
from odoo import fields, models, api, _
class StockPickingType(models.Model):
_inherit = "stock.picking.type"
allow_creating_new_packages = fields.Boolean(
string="Allow creating new packages",
help="User can create new packages by scanning a new barcode or create it manually"
)
apply_default_lots = fields.Boolean(
string="Apply default lots and serials",
help="If it's on, you don't need to scan lot number to confirm it. "
"On receipts the app will create default Odoo lots and apply them to the product. "
"On delivery zone you don't need to confirm lots and "
"they will be taken Odoo by default"
)
apply_quantity_automatically = fields.Boolean(
string="Apply quantity automatically",
help="Automatically validate the line after scanning a destination location. "
"Warning: you have to insert QTY first before destination location"
)
autocomplete_the_item_quantity_field = fields.Boolean(
string="Autocomplete item quantity",
help="Automatically insert expected quantity. No need to enter the quantity "
"of goods using the keyboard or using scanning"
)
behavior_on_backorder_creation = fields.Selection(
[
("always_create_backorder", "Always Create Backorder"),
("never_create_backorder", "Never Create Backorder"),
("ask_me_every_time", "Ask Me Every Time"),
],
string="Behavior On Backorder Creation",
default="ask_me_every_time",
required=True,
help="Choose how to process backorders. You can always create backorders, "
"always ignore backorders or choose it all the time (default)"
)
behavior_on_split_operation = fields.Selection(
[
("always_split_line", "Always Split the Line"),
("always_move_less_items", "Always Move Less Items"),
("ask_me_every_time", "Ask Me Every Time"),
],
string="Behavior On Split Operation",
compute="_compute_behavior_on_split_operation",
readonly=False,
store=True,
help="Choose how to process less product qty than initial. You can always split "
"the line, always move less items or choose it all the time(default)"
)
change_destination_location = fields.Boolean(
string="Change destination location",
help="If this setting is active a user can change destination location "
"while receiving to be placed at any available location",
)
change_source_location = fields.Boolean(
string="Change source location",
help="User can change default source location to pick item from another location. "
"Works only if 'Confirm source location' setting is active",
)
check_shipping_information = fields.Boolean(
string="Check shipping information",
help="If the setting is active the user can edit shipping information "
"before validate OUT transfer",
)
confirm_destination_location = fields.Boolean(
string="Confirm destination location",
help="The dot next to the field gets yellow color means user has to confirm it. "
"User has to scan a barcode of destination location"
)
confirm_product = fields.Boolean(
string="Confirm product",
help="The dot next to the field gets yellow color means user has to confirm it. "
"User has to scan a barcode of product."
)
confirm_source_location = fields.Boolean(
string="Confirm source location",
help="The dot next to the field gets yellow color means user has to confirm it. "
"User has to scan a barcode of source location"
)
confirm_source_package = fields.Boolean(
string="Confirm source package",
help="User has to scan a barcode of source package. "
"The dot next to the field gets yellow color means user has to confirm it"
)
hide_qty_to_receive = fields.Boolean(
string="Hide QTYs to receive",
help="Settings description: User will not see how many QTYs they need to receive."
)
is_consignment_enabled = fields.Boolean(
compute="_compute_is_consignment_enabled"
)
is_package_tracking_enabled = fields.Boolean(
compute="_compute_is_package_tracking_enabled"
)
is_stock_production_lot_enabled = fields.Boolean(
compute="_compute_is_stock_production_lot_enabled"
)
manage_packages = fields.Boolean(
string="Show packages fields",
default=lambda self: self.env.ref("stock.group_tracking_lot")
in self.env.ref("base.group_user").implied_ids,
help="Scan source (destination) packages right after scanning source (destination) "
"location. Use it if you move from one package to another or pick items from "
"packages or pallets. Works only if package management settings is active on Odoo "
"side.\n\n If you want to use Show packages fields, you must turn on setting "
"'Packages' in inventory settings",
)
manage_product_owner = fields.Boolean(
string="Show Product Owner field",
default=lambda self: self.env.ref("stock.group_tracking_owner")
in self.env.ref("base.group_user").implied_ids,
help="Allow scan product owner. You can specify product owner while moving items. "
"Working only with 'Consignment' setting on Odoo side"
)
scan_destination_location_once = fields.Boolean(
string="Scan destination location once",
help="Scan the destination location only once with the last item. "
"The destination location will be applied to all lines."
)
scan_destination_package = fields.Boolean(
string="Confirm destination package",
help="User has to scan a barcode of destination package. The dot next to the field "
"gets yellow color means user has to confirm it"
)
show_next_product = fields.Boolean(
string="Show next product",
help="Product field will show the next product to be picked. "
"Use the setting during picking and delivery. "
"It is recommended to disable the setting for the reception area",
)
show_print_attachment_button = fields.Boolean(
string="Show Print attachments button",
default=True,
help="Showing the Print attachments button in the toolbar instead of "
"keeping it in the hidden menu"
)
show_put_in_pack_button = fields.Boolean(
string="Show Put in pack button",
default=lambda self: self.env.ref("stock.group_tracking_lot")
in self.env.ref("base.group_user").implied_ids,
help="Showing the Put in pack button in the toolbar instead of "
"keeping it in the hidden menu"
)
transfer_more_items = fields.Boolean(
string="Move more than planned",
help="Allows moving more items than expected (for example kg of meat, etc)"
)
@api.depends('code')
def _compute_behavior_on_split_operation(self):
for operation_type in self:
if operation_type.code == 'incoming':
operation_type.behavior_on_split_operation = 'always_split_line'
else:
operation_type.behavior_on_split_operation = 'ask_me_every_time'
def _compute_is_consignment_enabled(self):
internal_user_groups = self.env.ref('base.group_user').implied_ids
group_tracking_owner = self.env.ref("stock.group_tracking_owner")
for item in self:
item.is_consignment_enabled = group_tracking_owner in internal_user_groups
def _compute_is_package_tracking_enabled(self):
internal_user_groups = self.env.ref('base.group_user').implied_ids
group_tracking_lot = self.env.ref("stock.group_tracking_lot")
for item in self:
item.is_package_tracking_enabled = group_tracking_lot in internal_user_groups
def _compute_is_stock_production_lot_enabled(self):
internal_user_groups = self.env.ref('base.group_user').implied_ids
group_production_lot = self.env.ref("stock.group_production_lot")
for item in self:
item.is_stock_production_lot_enabled = group_production_lot in internal_user_groups
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if 'code' in vals:
vals['show_next_product'] = vals['code'] != "incoming"
vals['change_destination_location'] = True
return super(StockPickingType, self).create(vals_list)
@api.onchange('confirm_source_location')
def _onchange_confirm_source_location(self):
if not self.confirm_source_location:
self.change_source_location = False
@api.onchange('confirm_destination_location')
def _onchange_confirm_destination_location(self):
if not self.confirm_destination_location:
self.apply_quantity_automatically = False
@api.onchange('change_source_location')
def _onchange_change_source_location(self):
if self.change_source_location and not self.confirm_source_location:
return {
'warning': {
'title': _("Warning"),
'message': _("'Change source location' is available only "
"if 'Confirm source location' is enabled")
}
}
@api.onchange('apply_quantity_automatically')
def _onchange_apply_quantity_automatically(self):
if self.apply_quantity_automatically and not self.confirm_destination_location:
return {
'warning': {
'title': _("Warning"),
'message': _("'Apply quantity automatically' is available only "
"if 'Confirm destination location' is enabled")
}
}
def write(self, vals):
res = super(StockPickingType, self).write(vals)
if 'change_source_location' in vals or 'confirm_source_location' in vals:
for stock_picking_type in self:
if stock_picking_type.change_source_location:
if not stock_picking_type.confirm_source_location:
stock_picking_type.change_source_location = False
if 'apply_quantity_automatically' in vals or 'confirm_destination_location' in vals:
for stock_picking_type in self:
if stock_picking_type.apply_quantity_automatically:
if not stock_picking_type.confirm_destination_location:
stock_picking_type.apply_quantity_automatically = False
if 'manage_packages' in vals:
for stock_picking_type in self:
if not stock_picking_type.manage_packages:
if stock_picking_type.scan_destination_package:
stock_picking_type.scan_destination_package = False
if stock_picking_type.confirm_source_package:
stock_picking_type.confirm_source_package = False
if stock_picking_type.allow_creating_new_packages:
stock_picking_type.allow_creating_new_packages = False
return res
def get_warehouse_operation_settings(self):
return {
"id": self.id,
"name": self.name,
"wh_code": self.warehouse_id.code,
"wh_name": self.warehouse_id.name,
"settings": {
"allow_creating_new_packages": self.allow_creating_new_packages,
"confirm_source_location": self.confirm_source_location,
"change_source_location": self.change_source_location,
"show_next_product": self.show_next_product,
"confirm_product": self.confirm_product,
"apply_default_lots": self.apply_default_lots,
"transfer_more_items": self.transfer_more_items,
"confirm_destination_location": self.confirm_destination_location,
"apply_quantity_automatically": self.apply_quantity_automatically,
"change_destination_location": self.change_destination_location,
"scan_destination_location_once": self.scan_destination_location_once,
"autocomplete_the_item_quantity_field": self.autocomplete_the_item_quantity_field,
"show_print_attachment_button": self.show_print_attachment_button,
"show_put_in_pack_button": self.show_put_in_pack_button,
"manage_packages": self.manage_packages,
"manage_product_owner": self.manage_product_owner,
"behavior_on_backorder_creation": self.behavior_on_backorder_creation,
"behavior_on_split_operation": self.behavior_on_split_operation,
"scan_destination_package": self.scan_destination_package,
"confirm_source_package": self.confirm_source_package,
"check_shipping_information": self.check_shipping_information,
"hide_qty_to_receive": self.hide_qty_to_receive,
}
}

View file

@ -0,0 +1,45 @@
# Copyright 2021 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class StockQuant(models.Model):
_inherit = 'stock.quant'
@api.constrains("lot_id", "inventory_quantity")
def _check_product_lot(self):
""" check product lot/serial except for stock_fix_lot """
for quant in self:
if (
not quant.inventory_quantity
or not quant.company_id.force_lot_validation_on_inventory_adjustment
or (
quant.env.context.get("skip_product_lot_check") and not quant.inventory_quantity)
):
return
if quant.tracking in ("lot", "serial") and not quant.lot_id:
raise ValidationError(
_(
"You need to supply a Lot/Serial number for product: %s",
quant.product_id.display_name,
)
)
@api.model
def user_has_groups(self, groups):
# we need to override method as we need different access group
# to be allowed to validate inventory
if (
self.env.context.get("validate_inventory")
and groups == "stock.group_stock_manager"
):
groups = "ventor_base.merp_user_validate_inventory_adjustment"
res = super(StockQuant, self).user_has_groups(groups)
return res
def _apply_inventory(self):
res = super(StockQuant, self.with_context(validate_inventory=True))._apply_inventory()
return res

View file

@ -0,0 +1,45 @@
# Copyright 2020 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
from odoo import api, models, fields
class StockWarehouse(models.Model):
_inherit = 'stock.warehouse'
is_internal = fields.Boolean(
string='Is Internal Warehouse',
)
@api.model_create_multi
def create(self, vals_list):
res = super(StockWarehouse, self).create(vals_list)
if res:
res.update_users_calculated_warehouse()
return res
def update_users_calculated_warehouse(self):
for warehouse in self:
users = self.env['res.users'].with_context(active_test=False).search([
('share', '=', False)])
wh_ids = self.env['stock.warehouse'].with_context(active_test=False).search([
('id', '!=', warehouse.id)]).ids
wh_ids.sort()
modified_user_ids = []
for user in users.with_context(active_test=False):
# Because of specifics on how Odoo working with companies on first start, we have to filter by company
user_wh_ids = user.allowed_warehouse_ids.filtered(
lambda wh: wh.company_id.id == warehouse.env.company.id
).ids
user_wh_ids.sort()
if wh_ids == user_wh_ids:
user.allowed_warehouse_ids = [(4, warehouse.id, 0)]
modified_user_ids.append(user.id)
# Because access rights are using this field, we need to invalidate cache
if modified_user_ids:
self.env['res.users'].browse(modified_user_ids).invalidate_recordset(
[
'allowed_warehouse_ids',
]
)

View file

@ -0,0 +1,268 @@
# Copyright 2022 VentorTech OU
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).
from odoo import _, api, models, fields
class VentorOptionSetting(models.Model):
_name = 'ventor.option.setting'
_description = 'Ventor Option Setting'
name = fields.Char(required=True, index=True)
action_type = fields.Selection(
[
('warehouse_opration', 'Warehouse Opration'),
('package_management', 'Package Management'),
('batch_picking', 'Batch Picking'),
('wave_picking', 'Wave Picking'),
('cluster_picking', 'Cluster Picking'),
('internal_transfers', 'Internal Transfers'),
('putaway', 'Putaway'),
('instant_inventory', 'Instant Inventory'),
('inventory_adjustments', 'Inventory Adjustments'),
('quick_info', 'Quick Info'),
('scrap_management', 'Scrap Management'),
('create_so', 'Create SO'),
('create_po', 'Create PO'),
], required=True
)
description = fields.Text()
technical_name = fields.Char(required=True)
value = fields.Many2one(
'ventor.setting.value',
string='Value',
required=True,
domain="[('id', 'in', settings_dependency)]",
)
value_type = fields.Selection(
[
('bool', 'Boolean'),
('select', 'Selection'),
]
)
settings_dependency = fields.Many2many(
comodel_name='ventor.setting.value'
)
@api.onchange('value')
def _onchange_value(self):
if self.technical_name in ('confirm_source_location', 'change_source_location'):
return self._set_change_source_location()
elif self.technical_name in ('add_boxes_before_cluster', 'multiple_boxes_for_one_transfer'):
return self._set_add_boxes_before_cluster()
elif self.technical_name in (
'manage_packages',
'confirm_source_package',
'scan_destination_package',
'allow_creating_new_packages',
'pack_all_items',
'allow_validate_less',
):
return self.set_related_package_fields(self._get_group_settings_value('stock.group_tracking_lot'))
elif self.technical_name in ('manage_product_owner'):
self.set_manage_product_owner_fields(self._get_group_settings_value('stock.group_tracking_owner'))
elif self.technical_name in ('apply_default_lots'):
self.set_apply_default_lots_fields(self._get_group_settings_value('stock.group_production_lot'))
elif self.technical_name in ('move_multiple_products', 'hold_destination_location'):
return self.set_hold_destination_location_fields()
elif self.technical_name in ('use_reusable_packages'):
return self.set_reusable_packages_related_fields(self._get_group_settings_value('stock.group_tracking_lot'))
elif self.technical_name in ('confirm_destination_location'):
self._set_confirm_destination_location_cluster_picking_fields()
def _get_group_settings_value(self, key):
internal_user_groups = self.env.ref('base.group_user').implied_ids
group = self.env.ref(key)
return group in internal_user_groups
def _get_warning(self, message):
return {'warning': {
'title': _('Another Settings were changed automatically!'),
'message': message,
}}
def get_setting_field(self, technical_name):
if not isinstance(technical_name, list):
technical_name = [technical_name]
return self.env['ventor.option.setting'].search(
[
('action_type', '=', self.action_type),
('technical_name', 'in', technical_name),
]
)
def get_general_settings(self):
action_types = [
'package_management',
'batch_picking',
'wave_picking',
'cluster_picking',
'internal_transfers',
'putaway',
'instant_inventory',
'inventory_adjustments',
'quick_info',
'scrap_management',
'create_so',
'create_po',
]
ventor_option_settings = self.env['ventor.option.setting'].search([])
settings = {}
for action_type in action_types:
settings[action_type] = {
set.technical_name: self.get_normalized_value(set.value.setting_value)
for set in ventor_option_settings.filtered(lambda r: r.action_type == action_type)
}
return settings
def set_allow_validate_less(self):
if self.technical_name == 'allow_validate_less':
pack_all_items = self.get_setting_field('pack_all_items')
if pack_all_items.value == self.env.ref('ventor_base.bool_true'):
self.value = self.env.ref('ventor_base.bool_false')
elif self.technical_name == 'pack_all_items':
allow_validate_less = self.get_setting_field('allow_validate_less')
if allow_validate_less.value == self.env.ref('ventor_base.bool_true'):
allow_validate_less.value = self.env.ref('ventor_base.bool_false')
return self._get_warning(_(
'Because you changed "Force Pack" to True, '
'automatically the following settings were also changed: '
'\n- "Validate uncompleted orders" was changed to False'
))
def set_apply_default_lots_fields(self, group_stock_production_lot):
if self.env.context.get('disable_apply_default_lots'):
self.value = self.env.ref('ventor_base.bool_false')
elif not group_stock_production_lot and self.value == self.env.ref('ventor_base.bool_true'):
self.value = self.env.ref('ventor_base.bool_false')
def _set_add_boxes_before_cluster(self):
if self.technical_name == 'add_boxes_before_cluster' and self.value == self.env.ref('ventor_base.bool_true'):
multiple_boxes_for_one_transfer = self.get_setting_field('multiple_boxes_for_one_transfer')
use_reusable_packages = self.get_setting_field('use_reusable_packages')
if multiple_boxes_for_one_transfer.value == self.env.ref('ventor_base.bool_true'):
multiple_boxes_for_one_transfer.value = self.env.ref('ventor_base.bool_false')
return self._get_warning(_(
'Because you changed "Add boxes before cluster" to True, '
'automatically the following settings were also changed: '
'\n- "Multiple boxes for one transfer" was changed to False'
))
if use_reusable_packages.value == self.env.ref('ventor_base.bool_true'):
self.value = self.env.ref('ventor_base.bool_false')
elif self.technical_name == 'multiple_boxes_for_one_transfer' and self.value == self.env.ref('ventor_base.bool_true'):
add_boxes_before_cluster = self.get_setting_field('add_boxes_before_cluster')
if add_boxes_before_cluster.value == self.env.ref('ventor_base.bool_true'):
self.value = self.env.ref('ventor_base.bool_false')
def _set_change_source_location(self):
if self.technical_name == 'confirm_source_location' and self.value == self.env.ref('ventor_base.bool_false'):
change_source_location = self.get_setting_field('change_source_location')
change_source_location.value = self.env.ref('ventor_base.bool_false')
return self._get_warning(_(
'Because you changed "Confirm source location" to False, '
'automatically the following settings were also changed: '
'\n- "Change source location" was changed to False'
))
elif self.technical_name == 'change_source_location' and self.value == self.env.ref('ventor_base.bool_true'):
confirm_source_location = self.get_setting_field('confirm_source_location')
if confirm_source_location.value == self.env.ref('ventor_base.bool_false'):
self.value = self.env.ref('ventor_base.bool_false')
def _set_confirm_destination_location_cluster_picking_fields(self):
if self.value == self.env.ref('ventor_base.bool_true') and self.action_type == 'cluster_picking':
use_reusable_packages = self.get_setting_field('use_reusable_packages')
if use_reusable_packages.value == self.env.ref('ventor_base.bool_true'):
self.value = self.env.ref('ventor_base.bool_false')
def set_hold_destination_location_fields(self):
if self.technical_name == 'move_multiple_products' and self.value == self.env.ref('ventor_base.bool_true'):
hold_destination_location = self.get_setting_field('hold_destination_location')
if hold_destination_location.value == self.env.ref('ventor_base.bool_true'):
hold_destination_location.value = self.env.ref('ventor_base.bool_false')
return self._get_warning(_(
'Because you changed "Move multiple items" to True, '
'automatically the following settings were also changed: '
'\n- "Hold destination location" was changed to False'
))
elif self.technical_name == 'hold_destination_location' and self.value == self.env.ref('ventor_base.bool_true'):
move_multiple_products = self.get_setting_field('move_multiple_products')
if move_multiple_products.value == self.env.ref('ventor_base.bool_true'):
self.value = self.env.ref('ventor_base.bool_false')
def set_manage_product_owner_fields(self, group_stock_tracking_owner):
if not group_stock_tracking_owner and self.value == self.env.ref('ventor_base.bool_true'):
self.value = self.env.ref('ventor_base.bool_false')
def set_related_package_fields(self, group_stock_tracking_lot):
if not group_stock_tracking_lot:
self.value = self.env.ref('ventor_base.bool_false')
elif group_stock_tracking_lot:
manage_packages = self.get_setting_field('manage_packages')
if self.value.setting_value == 'False' and self.technical_name == 'manage_packages':
relate_manage_packages_fields = self.get_setting_field(
[
'confirm_source_package',
'scan_destination_package',
]
)
relate_manage_packages_fields.value = self.env.ref('ventor_base.bool_false')
if self.action_type in ('batch_picking', 'cluster_picking'):
return self._get_warning(_(
'Because you changed "Show packages fields" to False, '
'automatically the following settings were also changed: '
'\n- "Confirm source package" was changed to False'
'\n- "Confirm destination package" was changed to False'
))
if self.technical_name != 'manage_packages' and manage_packages.value == self.env.ref('ventor_base.bool_false'):
self.value = self.env.ref('ventor_base.bool_false')
if self.value.setting_value == 'True' and self.technical_name in ('pack_all_items', 'allow_validate_less'):
return self.set_allow_validate_less()
if self.technical_name == 'scan_destination_package' and self.value == self.env.ref('ventor_base.bool_false'):
use_reusable_packages = self.get_setting_field('use_reusable_packages')
if use_reusable_packages.value == self.env.ref('ventor_base.bool_true'):
self.value = self.env.ref('ventor_base.bool_true')
def set_reusable_packages_related_fields(self, group_stock_tracking_lot):
if not group_stock_tracking_lot:
self.value = self.env.ref('ventor_base.bool_false')
elif self.value == self.env.ref('ventor_base.bool_true'):
related_settings_for_disabling = self.get_setting_field(
[
'confirm_destination_location',
'add_boxes_before_cluster',
]
)
related_settings_for_enabling = self.get_setting_field('scan_destination_package')
if related_settings_for_disabling:
related_settings_for_disabling.value = self.env.ref('ventor_base.bool_false')
if related_settings_for_enabling:
related_settings_for_enabling.value = self.env.ref('ventor_base.bool_true')
return self._get_warning(_(
'Because you changed "Use reusable packages" to True, '
'automatically the following settings were also changed: '
'\n- "Confirm destination location" was changed to False'
'\n- "Add boxes before cluster" was changed to False'
'\n- "Confirm destination package" was changed to True'
))
def get_normalized_value(self, setting_value):
normalized_settings = {
'True': 'true',
'False': 'false',
'Always Create Backorder': 'always_create_backorder',
'Never Create Backorder': 'never_create_backorder',
'Always Split the Line': 'always_split_line',
'Always Move Less Items': 'always_move_less_items',
'Ask Me Every Time': 'ask_me_every_time',
}
return normalized_settings.get(setting_value)
class VentorSettingValue(models.Model):
_name = 'ventor.setting.value'
_description = 'Ventor Setting Value'
_rec_name = 'setting_value'
setting_type = fields.Char()
setting_value = fields.Char()