vanilla 18.0

This commit is contained in:
Ernad Husremovic 2025-10-08 10:48:09 +02:00
parent 5454004ff9
commit d7f6d2725e
979 changed files with 428093 additions and 0 deletions

View file

@ -0,0 +1,31 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class View(models.Model):
_inherit = 'ir.ui.view'
def get_view_info(self):
_view_info = self._get_view_info()
return {
type_: {
'display_name': display_name,
'icon': _view_info[type_]['icon'],
'multi_record': _view_info[type_].get('multi_record', True),
}
for (type_, display_name)
in self.fields_get(['type'], ['selection'])['type']['selection']
if type_ != 'qweb' and type_ in _view_info
}
def _get_view_info(self):
return {
'list': {'icon': 'oi oi-view-list'},
'form': {'icon': 'fa fa-address-card', 'multi_record': False},
'graph': {'icon': 'fa fa-area-chart'},
'pivot': {'icon': 'oi oi-view-pivot'},
'kanban': {'icon': 'oi oi-view-kanban'},
'calendar': {'icon': 'fa fa-calendar'},
'search': {'icon': 'oi oi-search'},
}

View file

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
web_app_name = fields.Char('Web App Name', config_parameter='web.web_app_name')

View file

@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from base64 import b64decode
from odoo import models
from odoo.tools.facade import Proxy, ProxyAttr, ProxyFunc
_logger = logging.getLogger(__name__)
try:
import vobject
except ImportError:
_logger.warning("`vobject` Python module not found, vcard file generation disabled. Consider installing this module if you want to generate vcard files")
vobject = None
if vobject is not None:
class VBaseProxy(Proxy):
_wrapped__ = vobject.base.VBase
encoding_param = ProxyAttr()
type_param = ProxyAttr()
value = ProxyAttr(None)
class VCardContentsProxy(Proxy):
_wrapped__ = dict
__delitem__ = ProxyFunc()
__contains__ = ProxyFunc()
get = ProxyFunc(lambda lines: [VBaseProxy(line) for line in lines])
class VComponentProxy(Proxy):
_wrapped__ = vobject.base.Component
add = ProxyFunc(VBaseProxy)
contents = ProxyAttr(VCardContentsProxy)
serialize = ProxyFunc()
class ResPartner(models.Model):
_inherit = 'res.partner'
def _build_vcard(self):
""" Build the partner's vCard.
:returns a vobject.vCard object
"""
if not vobject:
return False
vcard = vobject.vCard()
# Name
n = vcard.add('n')
n.value = vobject.vcard.Name(family=self.name or self.complete_name or '')
if self.title:
n.value.prefix = self.title.name
# Formatted Name
fn = vcard.add('fn')
fn.value = self.name or self.complete_name or ''
# Address
adr = vcard.add('adr')
adr.value = vobject.vcard.Address(street=self.street or '', city=self.city or '', code=self.zip or '')
if self.state_id:
adr.value.region = self.state_id.name
if self.country_id:
adr.value.country = self.country_id.name
# Email
if self.email:
email = vcard.add('email')
email.value = self.email
email.type_param = 'INTERNET'
# Telephone numbers
if self.phone:
tel = vcard.add('tel')
tel.type_param = 'work'
tel.value = self.phone
if self.mobile:
tel = vcard.add('tel')
tel.type_param = 'cell'
tel.value = self.mobile
# URL
if self.website:
url = vcard.add('url')
url.value = self.website
# Organisation
if self.commercial_company_name:
org = vcard.add('org')
org.value = [self.commercial_company_name]
if self.function:
function = vcard.add('title')
function.value = self.function
# Photo
photo = vcard.add('photo')
photo.value = b64decode(self.avatar_512)
photo.encoding_param = 'B'
photo.type_param = 'JPG'
return VComponentProxy(vcard)
def _get_vcard_file(self):
vcard = self._build_vcard()
if vcard:
return vcard.serialize().encode()
return False

View file

@ -0,0 +1,27 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
from odoo.osv import expression
class ResUsers(models.Model):
_inherit = "res.users"
@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
# if we have a search with a limit, move current user as the first result
user_list = super().name_search(name, args, operator, limit)
uid = self._uid
# index 0 is correct not Falsy in this case, use None to avoid ignoring it
if (index := next((i for i, (user_id, _name) in enumerate(user_list) if user_id == uid), None)) is not None:
# move found user first
user_tuple = user_list.pop(index)
user_list.insert(0, user_tuple)
elif limit is not None and len(user_list) == limit:
# user not found and limit reached, try to find the user again
if user_tuple := super().name_search(name, expression.AND([args or [], [('id', '=', uid)]]), operator, limit=1):
user_list = [user_tuple[0], *user_list[:-1]]
return user_list
def _on_webclient_bootstrap(self):
self.ensure_one()