151 lines
6.2 KiB
Python
151 lines
6.2 KiB
Python
from urllib.parse import urljoin
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import ValidationError
|
|
|
|
from odoo.addons.account.models.company import PEPPOL_LIST
|
|
|
|
try:
|
|
import phonenumbers
|
|
except ImportError:
|
|
phonenumbers = None
|
|
|
|
|
|
class ResCompany(models.Model):
|
|
_inherit = 'res.company'
|
|
|
|
nemhandel_contact_email = fields.Char(
|
|
string='Nemhandel Contact email',
|
|
compute='_compute_nemhandel_contact_email', store=True, readonly=False,
|
|
help='Primary contact email for Nemhandel-related communication',
|
|
)
|
|
nemhandel_phone_number = fields.Char(
|
|
string='Nemhandel Phone number (for validation)',
|
|
compute='_compute_nemhandel_phone_number', store=True, readonly=False,
|
|
help='You will receive a verification code to this phone number',
|
|
)
|
|
l10n_dk_nemhandel_proxy_state = fields.Selection(
|
|
selection=[
|
|
('not_registered', 'Not registered'),
|
|
('in_verification', 'In verification'),
|
|
('receiver', 'Can send and receive'),
|
|
('rejected', 'Rejected'),
|
|
],
|
|
string='Nemhandel status', required=True, default='not_registered',
|
|
)
|
|
nemhandel_identifier_type = fields.Selection(related='partner_id.nemhandel_identifier_type', readonly=False)
|
|
nemhandel_identifier_value = fields.Char(related='partner_id.nemhandel_identifier_value', readonly=False)
|
|
nemhandel_purchase_journal_id = fields.Many2one(
|
|
comodel_name='account.journal',
|
|
string='Nemhandel Purchase Journal',
|
|
domain=[('type', '=', 'purchase')],
|
|
compute='_compute_nemhandel_purchase_journal_id', store=True, readonly=False,
|
|
)
|
|
nemhandel_edi_user = fields.Many2one(
|
|
comodel_name='account_edi_proxy_client.user',
|
|
compute='_compute_nemhandel_edi_user',
|
|
)
|
|
|
|
# -------------------------------------------------------------------------
|
|
# HELPER METHODS
|
|
# -------------------------------------------------------------------------
|
|
|
|
@api.model
|
|
def _check_phonenumbers_import(self):
|
|
if not phonenumbers:
|
|
raise ValidationError(_("Please install the phonenumbers library."))
|
|
|
|
def _sanitize_nemhandel_phone_number(self, phone_number=None):
|
|
self.ensure_one()
|
|
|
|
error_message = _(
|
|
"Please enter the phone number in the correct international format.\n"
|
|
"For example: +32123456789, where +32 is the country code.\n"
|
|
"Currently, only European countries are supported."
|
|
)
|
|
|
|
self._check_phonenumbers_import()
|
|
|
|
phone_number = phone_number or self.nemhandel_phone_number
|
|
if not phone_number:
|
|
return
|
|
|
|
if not phone_number.startswith('+'):
|
|
phone_number = f'+{phone_number}'
|
|
|
|
try:
|
|
phone_nbr = phonenumbers.parse(phone_number)
|
|
except phonenumbers.phonenumberutil.NumberParseException:
|
|
raise ValidationError(error_message)
|
|
|
|
country_code = phonenumbers.phonenumberutil.region_code_for_number(phone_nbr)
|
|
if country_code not in PEPPOL_LIST or not phonenumbers.is_valid_number(phone_nbr):
|
|
raise ValidationError(error_message)
|
|
|
|
# -------------------------------------------------------------------------
|
|
# CONSTRAINTS
|
|
# -------------------------------------------------------------------------
|
|
|
|
@api.constrains('nemhandel_phone_number')
|
|
def _check_nemhandel_phone_number(self):
|
|
for company in self:
|
|
if company.nemhandel_phone_number:
|
|
company._sanitize_nemhandel_phone_number()
|
|
|
|
@api.constrains('nemhandel_purchase_journal_id')
|
|
def _check_nemhandel_purchase_journal_id(self):
|
|
for company in self:
|
|
if company.nemhandel_purchase_journal_id and company.nemhandel_purchase_journal_id.type != 'purchase':
|
|
raise ValidationError(_("A purchase journal must be used to receive Nemhandel documents."))
|
|
|
|
# -------------------------------------------------------------------------
|
|
# COMPUTE METHODS
|
|
# -------------------------------------------------------------------------
|
|
|
|
@api.depends('l10n_dk_nemhandel_proxy_state')
|
|
def _compute_nemhandel_purchase_journal_id(self):
|
|
for company in self:
|
|
if not company.nemhandel_purchase_journal_id and company.l10n_dk_nemhandel_proxy_state not in {'not_registered', 'rejected'}:
|
|
company.nemhandel_purchase_journal_id = self.env['account.journal'].search([
|
|
*self.env['account.journal']._check_company_domain(company),
|
|
('type', '=', 'purchase'),
|
|
], limit=1)
|
|
company.nemhandel_purchase_journal_id.is_nemhandel_journal = True
|
|
else:
|
|
company.nemhandel_purchase_journal_id = company.nemhandel_purchase_journal_id
|
|
|
|
@api.depends('email')
|
|
def _compute_nemhandel_contact_email(self):
|
|
for company in self:
|
|
if not company.nemhandel_contact_email:
|
|
company.nemhandel_contact_email = company.email
|
|
|
|
@api.depends('phone')
|
|
def _compute_nemhandel_phone_number(self):
|
|
for company in self:
|
|
if not company.nemhandel_phone_number:
|
|
try:
|
|
# precompute only if it's a valid phone number
|
|
company._sanitize_nemhandel_phone_number(company.phone)
|
|
company.nemhandel_phone_number = company.phone
|
|
except ValidationError:
|
|
continue
|
|
|
|
@api.depends('account_edi_proxy_client_ids')
|
|
def _compute_nemhandel_edi_user(self):
|
|
for company in self:
|
|
company.nemhandel_edi_user = company.account_edi_proxy_client_ids.filtered(lambda u: u.proxy_type == 'nemhandel')
|
|
|
|
# -------------------------------------------------------------------------
|
|
# PEPPOL PARTICIPANT MANAGEMENT
|
|
# -------------------------------------------------------------------------
|
|
|
|
def _get_nemhandel_edi_mode(self):
|
|
self.ensure_one()
|
|
config_param = self.env['ir.config_parameter'].sudo().get_param('l10n_dk_nemhandel.edi.mode')
|
|
return self.sudo().nemhandel_edi_user.edi_mode or config_param or 'prod'
|
|
|
|
def _get_nemhandel_webhook_endpoint(self):
|
|
self.ensure_one()
|
|
return urljoin(self.get_base_url(), '/nemhandel/webhook')
|