adopted OCA file layout
This commit is contained in:
6
base_usability/models/__init__.py
Normal file
6
base_usability/models/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from . import users
|
||||
from . import partner
|
||||
from . import company
|
||||
from . import mail
|
||||
from . import misc
|
||||
from . import report_sxw
|
||||
81
base_usability/models/company.py
Normal file
81
base_usability/models/company.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# © 2015-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models, api, _
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
@api.model
|
||||
def generate_line(self, fields, options, icon=True, separator=' - '):
|
||||
assert fields
|
||||
assert options
|
||||
content = []
|
||||
for field in fields:
|
||||
value = False
|
||||
if isinstance(field, tuple) and len(field) == 2:
|
||||
value = field[0]
|
||||
label = field[1]
|
||||
uicon = False
|
||||
elif isinstance(field, str) and field in options:
|
||||
value = options[field]['value']
|
||||
label = options[field].get('label')
|
||||
uicon = options[field].get('icon')
|
||||
if value:
|
||||
prefix = icon and uicon or label
|
||||
if prefix:
|
||||
content.append('%s %s' % (prefix, value))
|
||||
else:
|
||||
content.append(value)
|
||||
line = separator.join(content)
|
||||
return line
|
||||
|
||||
@api.multi
|
||||
def _prepare_header_options(self):
|
||||
self.ensure_one()
|
||||
options = {
|
||||
'phone': {
|
||||
'value': self.phone,
|
||||
# http://www.fileformat.info/info/unicode/char/1f4de/index.htm
|
||||
'icon': '\U0001F4DE',
|
||||
'label': _('Tel:')},
|
||||
'email': {
|
||||
'value': self.email,
|
||||
# http://www.fileformat.info/info/unicode/char/2709/index.htm
|
||||
'icon': '\u2709',
|
||||
'label': _('E-mail:')},
|
||||
'website': {
|
||||
'value': self.website,
|
||||
'icon': '\U0001f310',
|
||||
'label': _('Website:')},
|
||||
'vat': {
|
||||
'value': self.vat,
|
||||
'label': _('TVA :')}, # TODO translate
|
||||
}
|
||||
return options
|
||||
|
||||
def _report_company_legal_name(self):
|
||||
'''Method inherited in the module base_company_extension'''
|
||||
self.ensure_one()
|
||||
return self.name
|
||||
|
||||
# for reports
|
||||
@api.multi
|
||||
def _display_report_header(
|
||||
self, line_details=[['phone', 'website'], ['vat']],
|
||||
icon=True, line_separator=' - '):
|
||||
self.ensure_one()
|
||||
res = ''
|
||||
address = self.partner_id._display_address(without_company=True)
|
||||
address = address.replace('\n', ' - ')
|
||||
|
||||
line1 = '%s - %s' % (self._report_company_legal_name(), address)
|
||||
lines = [line1]
|
||||
options = self._prepare_header_options()
|
||||
for details in line_details:
|
||||
line = self.generate_line(
|
||||
details, options, icon=icon, separator=line_separator)
|
||||
lines.append(line)
|
||||
res = '\n'.join(lines)
|
||||
return res
|
||||
35
base_usability/models/mail.py
Normal file
35
base_usability/models/mail.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# © 2015-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models, api
|
||||
from odoo.addons.base.models.ir_mail_server import extract_rfc2822_addresses
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IrMailServer(models.Model):
|
||||
_inherit = "ir.mail_server"
|
||||
|
||||
@api.model
|
||||
def send_email(
|
||||
self, message, mail_server_id=None, smtp_server=None,
|
||||
smtp_port=None, smtp_user=None, smtp_password=None,
|
||||
smtp_encryption=None, smtp_debug=False, smtp_session=None):
|
||||
# Start copy from native method
|
||||
smtp_from = message['Return-Path'] or\
|
||||
self._get_default_bounce_address() or message['From']
|
||||
from_rfc2822 = extract_rfc2822_addresses(smtp_from)
|
||||
smtp_from = from_rfc2822[-1]
|
||||
# End copy from native method
|
||||
logger.info(
|
||||
"Sending email from '%s' to '%s' Cc '%s' Bcc '%s' "
|
||||
"with subject '%s'",
|
||||
smtp_from, message.get('To'), message.get('Cc'),
|
||||
message.get('Bcc'), message.get('Subject'))
|
||||
return super(IrMailServer, self).send_email(
|
||||
message, mail_server_id=mail_server_id,
|
||||
smtp_server=smtp_server, smtp_port=smtp_port,
|
||||
smtp_user=smtp_user, smtp_password=smtp_password,
|
||||
smtp_encryption=smtp_encryption, smtp_debug=smtp_debug,
|
||||
smtp_session=smtp_session)
|
||||
17
base_usability/models/misc.py
Normal file
17
base_usability/models/misc.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# © 2015-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class BaseLanguageExport(models.TransientModel):
|
||||
_inherit = 'base.language.export'
|
||||
|
||||
# Default format for language files = format used by OpenERP modules
|
||||
format = fields.Selection(default='po')
|
||||
|
||||
|
||||
class BaseLanguageInstall(models.TransientModel):
|
||||
_inherit = 'base.language.install'
|
||||
|
||||
overwrite = fields.Boolean(default=True)
|
||||
139
base_usability/models/partner.py
Normal file
139
base_usability/models/partner.py
Normal file
@@ -0,0 +1,139 @@
|
||||
# © 2015-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
# track_visibility is handled in the 'mail' module, and base_usability
|
||||
# doesn't depend on 'mail', but that doesn't hurt, it will just be
|
||||
# ignored if mail is not installed
|
||||
name = fields.Char(track_visibility='onchange')
|
||||
parent_id = fields.Many2one(track_visibility='onchange')
|
||||
ref = fields.Char(track_visibility='onchange', copy=False)
|
||||
lang = fields.Selection(track_visibility='onchange')
|
||||
user_id = fields.Many2one(track_visibility='onchange')
|
||||
vat = fields.Char(track_visibility='onchange')
|
||||
customer = fields.Boolean(track_visibility='onchange')
|
||||
supplier = fields.Boolean(track_visibility='onchange')
|
||||
type = fields.Selection(track_visibility='onchange')
|
||||
street = fields.Char(track_visibility='onchange')
|
||||
street2 = fields.Char(track_visibility='onchange')
|
||||
zip = fields.Char(track_visibility='onchange')
|
||||
city = fields.Char(track_visibility='onchange')
|
||||
state_id = fields.Many2one(track_visibility='onchange')
|
||||
country_id = fields.Many2one(track_visibility='onchange')
|
||||
email = fields.Char(track_visibility='onchange')
|
||||
is_company = fields.Boolean(track_visibility='onchange')
|
||||
active = fields.Boolean(track_visibility='onchange')
|
||||
company_id = fields.Many2one(track_visibility='onchange')
|
||||
# For reports
|
||||
name_title = fields.Char(
|
||||
compute='_compute_name_title', string='Name with Title')
|
||||
|
||||
@api.multi
|
||||
@api.depends('name', 'title')
|
||||
def _compute_name_title(self):
|
||||
for partner in self:
|
||||
name_title = partner.name
|
||||
if partner.title and not partner.is_company:
|
||||
partner_lg = partner
|
||||
# If prefer to read the lang of the partner than the lang
|
||||
# of the context. That way, an English man will be displayed
|
||||
# with his title in English whatever the environment
|
||||
if partner.lang:
|
||||
partner_lg = partner.with_context(lang=partner.lang)
|
||||
title = partner_lg.title.shortcut or partner_lg.title.name
|
||||
name_title = ' '.join([title, name_title])
|
||||
partner.name_title = name_title
|
||||
|
||||
@api.multi
|
||||
def _display_address(self, without_company=False):
|
||||
'''Remove empty lines'''
|
||||
res = super(ResPartner, self)._display_address(
|
||||
without_company=without_company)
|
||||
while "\n\n" in res:
|
||||
res = res.replace('\n\n', '\n')
|
||||
return res
|
||||
|
||||
# for reports
|
||||
@api.multi
|
||||
def _display_full_address(
|
||||
self, details=[
|
||||
'company', 'name', 'address', 'phone',
|
||||
'mobile', 'email'],
|
||||
icon=True):
|
||||
self.ensure_one()
|
||||
# To make the icons work with py3o with PDF export, on the py3o server:
|
||||
# 1) sudo apt-get install fonts-symbola
|
||||
# 2) start libreoffice in xvfb (don't use --headless) (To confirm)
|
||||
if self.is_company:
|
||||
company = self.name
|
||||
name = False
|
||||
else:
|
||||
name = self.name_title
|
||||
company = self.parent_id and self.parent_id.is_company and\
|
||||
self.parent_id.name or False
|
||||
options = {
|
||||
'name': {
|
||||
'value': name,
|
||||
},
|
||||
'company': {
|
||||
'value': company,
|
||||
},
|
||||
'phone': {
|
||||
'value': self.phone,
|
||||
# http://www.fileformat.info/info/unicode/char/1f4de/index.htm
|
||||
'icon': '\U0001F4DE',
|
||||
'label': _('Tel:'),
|
||||
},
|
||||
'mobile': {
|
||||
'value': self.mobile,
|
||||
# http://www.fileformat.info/info/unicode/char/1f4f1/index.htm
|
||||
'icon': '\U0001F4F1',
|
||||
'label': _('Mobile:'),
|
||||
},
|
||||
'email': {
|
||||
'value': self.email,
|
||||
# http://www.fileformat.info/info/unicode/char/2709/index.htm
|
||||
'icon': '\u2709',
|
||||
'label': _('E-mail:'),
|
||||
},
|
||||
'website': {
|
||||
'value': self.website,
|
||||
# http://www.fileformat.info/info/unicode/char/1f310/index.htm
|
||||
'icon': '\U0001f310',
|
||||
'label': _('Website:'),
|
||||
},
|
||||
'address': {
|
||||
'value': self._display_address(without_company=True),
|
||||
}
|
||||
}
|
||||
res = []
|
||||
for detail in details:
|
||||
if options.get(detail) and options[detail]['value']:
|
||||
entry = options[detail]
|
||||
prefix = icon and entry.get('icon') or entry.get('label')
|
||||
if prefix:
|
||||
res.append('%s %s' % (prefix, entry['value']))
|
||||
else:
|
||||
res.append('%s' % entry['value'])
|
||||
res = '\n'.join(res)
|
||||
return res
|
||||
|
||||
|
||||
class ResPartnerCategory(models.Model):
|
||||
_inherit = 'res.partner.category'
|
||||
|
||||
name = fields.Char(translate=False)
|
||||
|
||||
|
||||
class ResPartnerBank(models.Model):
|
||||
_inherit = 'res.partner.bank'
|
||||
|
||||
# In the 'base' module, they didn't put any string, so the bank name is
|
||||
# displayed as 'Name', which the string of the related field it
|
||||
# points to
|
||||
bank_name = fields.Char(string='Bank Name')
|
||||
35
base_usability/models/report_sxw.py
Normal file
35
base_usability/models/report_sxw.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models, api
|
||||
from odoo.tools import misc
|
||||
from odoo.tools import float_compare
|
||||
|
||||
|
||||
class BaseUsabilityInstalled(models.AbstractModel):
|
||||
_name = "base.usability.installed"
|
||||
|
||||
|
||||
formatLang_original = misc.formatLang
|
||||
|
||||
def formatLang(self, value, digits=None, grouping=True, monetary=False,
|
||||
dp=False, currency_obj=False, int_no_digits=True):
|
||||
with api.Environment.manage():
|
||||
env = api.Environment(self.cr, self.uid, {})
|
||||
if (
|
||||
'base.usability.installed' in env and
|
||||
int_no_digits and
|
||||
not monetary and
|
||||
isinstance(value, float) and
|
||||
dp):
|
||||
prec = env['decimal.precision'].precision_get(dp)
|
||||
if not float_compare(value, int(value), precision_digits=prec):
|
||||
digits = 0
|
||||
dp = False
|
||||
res = formatLang_original(
|
||||
self, value, digits=digits, grouping=grouping, monetary=monetary,
|
||||
dp=dp, currency_obj=currency_obj)
|
||||
return res
|
||||
|
||||
|
||||
misc.formatLang = formatLang
|
||||
40
base_usability/models/users.py
Normal file
40
base_usability/models/users.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Copyright 2018 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models, api, SUPERUSER_ID, _
|
||||
from odoo.exceptions import UserError
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super(ResUsers, self).default_get(fields_list)
|
||||
# For a new partner auto-created when you create a new user, we prefer
|
||||
# customer=False and supplier=True by default
|
||||
res.update({
|
||||
'customer': False,
|
||||
'supplier': True,
|
||||
})
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _script_partners_linked_to_users_no_company(self):
|
||||
if self.env.user.id != SUPERUSER_ID:
|
||||
raise UserError(_('You must run this script as admin user'))
|
||||
logger.info(
|
||||
'START to set company_id=False on partners related to users')
|
||||
users = self.search(
|
||||
['|', ('active', '=', True), ('active', '=', False)])
|
||||
for user in users:
|
||||
if user.partner_id.company_id:
|
||||
user.partner_id.company_id = False
|
||||
logger.info(
|
||||
'Wrote company_id=False on user %s ID %d',
|
||||
user.login, user.id)
|
||||
logger.info(
|
||||
'END setting company_id=False on partners related to users')
|
||||
return True
|
||||
Reference in New Issue
Block a user