trytondo-account_co_co/party.py

390 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from trytond.model import fields, ModelSQL, ModelView, Unique, sequence_ordered
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Not, Equal, Or, And
from trytond.i18n import gettext
from trytond.exceptions import UserError
from .exceptions import PartyIdentifierError
import logging
logger = logging.getLogger(__name__)
__all__ = ['PartyIdentifier','Party','ContactMechanism','Address','PartyTaxLevelCode']
TAX_CO_IDENTIFIERS = [
(None, ''),
('11', 'Registro Civil'),
('12', 'Tarjeta de Identidad'),
('13', 'Cedula de Ciudadania'),
('21', 'Tarjeta de Extranjeria'),
('22', 'Cedula de Extranjeria'),
('31', 'NIT'),
('41', 'Pasaporte'),
('42', 'Tipo de Documento Extranjero'),
('43', 'Documento de identificación extranjero'),
('50', 'NIT de otro país'),
('91', 'NUIP')
]
CO_CONTACT_MECHANISM_TYPES = [
('sms','SMS')
]
class Party(ModelSQL,ModelView):
"Party Colombian"
__name__='party.party'
__metaclass__ = PoolMeta
first_name = fields.Char("Primer Nombre",states={
'invisible': Not(Eval('type_person') == '2'),}
)
second_name = fields.Char("Segundo Nombre",states={
'invisible': Not(Eval('type_person') == '2'),}
)
first_surname = fields.Char("Primer Apellido",states={
'invisible': Not(Eval('type_person') == '2'),}
)
second_surname = fields.Char("Segundo Apellido",states={
'invisible': Not(Eval('type_person') == '2'),},
depends=['type_person'])
birth_date = fields.Date('Fecha de nacimiento')
tax_regime = fields.Selection([
(None, ''),
('48', 'Responsable del impuesto sobre las ventas IVA'),
('49', 'No responsable de IVA')
], 'Tax Regime')
type_taxpayer = fields.Selection([
(None, ''),
('regimen_simplificado', 'Regimen Simplificado'),
('regimen_comun', 'Regimen Comun'),
('gran_contribuyente', 'Gran Contribuyente'),
('entidad_estatal', 'Entidad Estatal'),
('domiciliado_extranjero', 'Domiciliado en Extranjero'),
], 'Type Taxpayer')
type_person = fields.Selection([
(None, ''),
('1', 'Persona Juridica'),
('2', 'Persona Natural'),
], 'Type Person')
self_withholding = fields.Boolean('Self Withholding')
declarant = fields.Boolean('Declarant')
main_ciiu = fields.Char('Main Activity', size=4)
secondary_ciiu = fields.Char('Secondary Activity', size=4)
other_ciiu = fields.Char('Other Activity', size=4)
age = fields.Function(fields.Integer('Edad'),'on_change_with_age')
type_tax_identifier = fields.Function(fields.Selection('get_types_identifier',
'Tipo de Identidad'),
'on_change_with_type_tax_identifier')
tax_level_code =fields.Many2Many('party.party_tax_level_code','party', 'tax_level_code', "TaxLevelCode")
@classmethod
def __setup__(cls):
super(Party, cls).__setup__()
cls.name.required = True
@staticmethod
def default_type_person():
return '2'
@classmethod
def tax_identifier_types(cls):
return ['12','13','31']
@classmethod
def get_tax_level_code(cls):
pool = Pool()
TaxLevelCode = pool.get('party.tax_level_code')
return TaxLevelCode.fields_get(['code'])['code']
@fields.depends('birth_date')
def on_change_with_age(self,name=None):
if self.birth_date:
Date = Pool().get('ir.date')
today = Date.today()
age = today.year - self.birth_date.year
age -= (today.month, today.day) < (self.birth_date.month, self.birth_date.day)
return age
@fields.depends('name','first_name','second_name','first_surname',
'second_surname','type_person')
def on_change_type_person(self):
if self.type_person == '2':
self.on_change_name()
if self.type_person == '1':
pass
@fields.depends('name','first_name','second_name','first_surname',
'second_surname','type_person')
def on_change_name(self):
self.rebuild_name()
@fields.depends('name','first_name','second_name','first_surname',
'second_surname','type_person')
def on_change_first_name(self):
self.rebuild_name()
@fields.depends('name','first_name','second_name','first_surname',
'second_surname','type_person')
def on_change_second_name(self):
self.rebuild_name()
@fields.depends('name','first_name','second_name','first_surname',
'second_surname','type_person')
def on_change_second_surname(self):
self.rebuild_name()
@fields.depends('name','first_name','second_name','first_surname',
'second_surname','type_person')
def on_change_first_surname(self):
self.rebuild_name()
def rebuild_name(self):
"""reconstruye los campos relacionados con el nombre dependiendo de
estos y del tipo de persona."""
if self.type_person == '2':
if not (self.first_name or self.second_name \
or self.first_surname or self.second_surname):
if self.name:
self.first_name, self.second_name, self.first_surname, \
self.second_surname = self.split_name(self.name)
else:
return
else:
self.name = self.get_full_name()
if self.type_person == '1':
if self.name:
self.clean_split_name()
else:
self.name = self.get_full_name()
def clean_split_name(self):
self.first_name = self.second_name = self.first_surname = self.second_surname = ''
@staticmethod
def split_name(name):
"""Divide un nombre completo en una lista de 4 elementos"""
second_surname = None
first_surname = None
second_name = None
first_name = None
names = name.split(' ')
if len(names) > 0:
first_name = names[0]
if len(names) == 2:
second_surname = None
first_surname = names[1]
elif len(names) == 3:
first_surname = names[1]
second_surname = names[2]
elif len(names) >= 4:
second_name = names[1]
first_surname = names[2]
second_surname = " ".join(names[3:])
return [first_name,second_name,first_surname, second_surname]
@fields.depends('identifiers')
def on_change_with_type_tax_identifier(self,name=None):
types = self._tax_identifier_types()
if self.identifiers:
for identifier in self.identifiers:
if identifier.type in types:
return identifier.type
@fields.depends('identifiers')
def on_change_with_tax_identifier(self,name=None):
if self.identifiers:
return self.get_tax_identifier(name)
@classmethod
def _tax_identifier_types(cls):
types = super(Party, cls).tax_identifier_types()
types.extend(['31','13'])
return types
def get_full_name(self, name=None):
if self.type_person == '2':
name_list = [self.first_name, self.second_name,
self.first_surname,self.second_surname]
return " ".join([x for x in name_list if x])
return self.name
@staticmethod
def get_types_identifier():
PartyIdentifier = Pool().get('party.identifier')
return PartyIdentifier.type.selection
def pre_validate(self):
super(Party, self).pre_validate()
if not self.identifiers:
raise PartyIdentifierError(gettext(
'account_co_co.msg_not_identifier'))
class PartyIdentifier(ModelSQL, ModelView):
"Party Identifier Colombian"
__name__ = "party.identifier"
__metaclass__ = PoolMeta
expedition_city = fields.Many2One("country.subdivision",
'Ciudad de Expedicion',
help="Lugar donde fue expedido el documento de identidad",
domain=[('parent', '!=', None)],
states = {'invisible':Not(Equal(Eval('type'),'13'))}
)
rut = fields.Boolean('Rut',
states = {'invisible':And(Not(Equal(Eval('type'),('12'))),
Not(Equal(Eval('type'),('13'))),
Not(Equal(Eval('type'),('31')))),
'readonly':Equal(Eval('type'),('31'))})
check_digit = fields.Function(fields.Integer('DV',
help='Digito de Verificacion colombiano',
states = {'invisible':~Eval('rut', False)})
,'on_change_with_check_digit')
@classmethod
def __setup__(cls):
super(PartyIdentifier, cls).__setup__()
cls.type.selection = TAX_CO_IDENTIFIERS
cls.type.required = True
table = cls.__table__()
cls._sql_constraints += [
('UniqueIdentifier', Unique(table, table.code,table.type),
'La identificacion ya existe')
]
@fields.depends('rut','type')
def on_change_type(self):
if self.type == '31':
self.rut = True
@fields.depends('type','code')
def on_change_with_check_digit(self,name=None):
try:
import stdnum.co.nit #la version debe ser mayor a la 1.2 o 1.3
except:
raise PartyIdentifierError(gettext(
'account_co_co.msg_stdnum_error'))
if self.type and self.code:
if self.type in ('12','13','31') and self.code.isdigit():
return int(stdnum.co.nit.calc_check_digit(self.code))
@fields.depends('type', 'party', 'code', 'rut')
def check_code(self):
super(PartyIdentifier, self).check_code()
tax_identifiers = ['12', '13', '31']
if self.type == '31':
self.rut = True
if self.rut != False and self.type in tax_identifiers:
#generalizar multiples paises
#puede ser por el country del party de la company actual
try:
import stdnum.co.nit #la version debe ser mayor a la 1.2 o 1.3
except:
raise PartyIdentifierError(gettext(
'account_co_co.msg_stdnum_error'))
if self.code.isdigit() is not True:
raise PartyIdentifierError(gettext(
'account_co_co.msg_invalid_vat_str'))
if not stdnum.co.nit.is_valid(self.code + str(self.check_digit)):
if self.party and self.party.id > 0:
party = self.party.rec_name
else:
party = ''
raise PartyIdentifierError(
gettext('account_co_co.msg_invalid_vat',
code=self.code))
if self.type in tax_identifiers and not self.code.isdigit():
if self.party and self.party.id > 0:
party = self.party.rec_name
else:
party = ''
raise PartyIdentifierError(
gettext('account_co_co.msg_invalid_vat',
code=self.code))
@staticmethod
def default_type_document():
return '13'
@staticmethod
def default_rut():
return False
def get_rec_name(self,name=None):
if self.code:
return self.code
elif self.id:
return self.id
return ''
class PartyTaxLevelCode(ModelSQL, ModelView):
"Party Tax Level Code"
__name__ = 'party.party_tax_level_code'
party = fields.Many2One('party.party', 'Party', select=True)
tax_level_code = fields.Many2One('party.tax_level_code', 'TaxLevelCode', select=True)
class ContactMechanism(sequence_ordered(), ModelSQL, ModelView):
"Contact Mechanism"
__name__ = 'party.contact_mechanism'
__metaclass__ = PoolMeta
@classmethod
def __setup__(cls):
super(ContactMechanism, cls).__setup__()
cls.type.selection.extend(CO_CONTACT_MECHANISM_TYPES)
class Address(ModelSQL, ModelView):
"Address"
__metaclass__ = PoolMeta
__name__ = 'party.address'
subdivision_municipality = fields.Many2One("country.subdivision",
'Municipality',
domain=[
('country', '=', Eval('country', -1)),
('parent', '=', Eval('subdivision', -1)),
('type', '=', 'municipality')
],
depends=['country', 'subdivision', 'city'],
required=True
)
@fields.depends('subdivision', 'subdivision_municipality', 'country')
def on_change_country(self):
super(Address, self).on_change_country()
if (self.subdivision_municipality
and self.subdivision_municipality.parent != self.subdivision):
self.subdivision_municipality = None
@fields.depends('subdivision', 'subdivision_municipality')
def on_change_subdivision(self):
if hasattr(super(Address, self), 'on_change_subdivision'):
super(Address, self).on_change_subdivision()
if (self.subdivision_municipality
and self.subdivision_municipality.parent != self.subdivision):
self.subdivision_municipality = None
@fields.depends('city', 'subdivision_municipality')
def on_change_subdivision_municipality(self):
if self.subdivision_municipality:
self.city = self.subdivision_municipality.name
else:
self.city = None