352 lines
13 KiB
Python
352 lines
13 KiB
Python
from trytond.model import fields, ModelSQL, ModelView, Unique, sequence_ordered
|
|
from trytond.pool import PoolMeta, Pool
|
|
from trytond.pyson import Eval, Not, Equal
|
|
import logging
|
|
from trytond.exceptions import UserError
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
__all__ = ['PartyIdentifier','Party','ContactMechanism','Address','PartyTaxLevelCode']
|
|
|
|
|
|
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 Extrangero'),
|
|
('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') == 'persona_natural'),}
|
|
)
|
|
second_name = fields.Char("Segundo Nombre",states={
|
|
'invisible': Not(Eval('type_person') == 'persona_natural'),}
|
|
)
|
|
first_surname = fields.Char("Primer Apellido",states={
|
|
'invisible': Not(Eval('type_person') == 'persona_natural'),}
|
|
)
|
|
second_surname = fields.Char("Segundo Apellido",states={
|
|
'invisible': Not(Eval('type_person') == 'persona_natural'),},
|
|
depends=['type_person'])
|
|
birth_date = fields.Date('Fecha de nacimiento')
|
|
regime_tax = fields.Selection([
|
|
(None, ''),
|
|
('regimen_simplificado', 'Regimen Simplificado'),
|
|
('regimen_comun', 'Regimen Comun'),
|
|
('gran_contribuyente', 'Gran Contribuyente'),
|
|
('entidad_estatal', 'Entidad Estatal'),
|
|
('domiciliado_extranjero', 'Domiciliado en Extranjero'),
|
|
], 'Regimen de Impuestos')
|
|
type_person = fields.Selection([
|
|
(None, ''),
|
|
('persona_natural', 'Persona Natural'),
|
|
('persona_juridica', 'Persona Juridica'),
|
|
], 'Tipo de Persona')
|
|
self_withholding = fields.Boolean('Self Withholding')
|
|
declarant = fields.Boolean('Declarant')
|
|
main_ciiu_code = fields.Char('Main CIIU Code', size=4)
|
|
secondary_ciiu_code = fields.Char('Secondary CIIU Code', size=4)
|
|
other_ciiu_code = fields.Char('Other CIIU Code', 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")
|
|
|
|
|
|
@staticmethod
|
|
def default_type_person():
|
|
return 'persona_natural'
|
|
|
|
@classmethod
|
|
def tax_identifier_types(cls):
|
|
#return ['11', '12', '13', '21', '22', '31', '41', '42', '43', '50', '91']
|
|
return ['31']
|
|
|
|
@classmethod
|
|
def get_tax_level_code(cls):
|
|
pool = Pool()
|
|
TaxLevelCode = pool.get('party.tax_level_code')
|
|
#raise UserError(str(TaxLevelCode.fields_get(['code'])['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 == 'persona_natural':
|
|
self.on_change_name()
|
|
if self.type_person == 'persona_juridica':
|
|
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 == 'persona_natural':
|
|
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 == 'persona_juridica':
|
|
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 == 'persona_natural':
|
|
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:
|
|
self.raise_user_error("El tercero debe tener un documento de identidad")
|
|
|
|
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')
|
|
check_digit = fields.Function(fields.Integer('DV',
|
|
help='Digito de Verificacion colombiano',
|
|
states = {'invisible':Not(Equal(Eval('type'),'31'))})
|
|
,'on_change_with_check_digit')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(PartyIdentifier, cls).__setup__()
|
|
cls.type.selection = CO_IDENTIFIERS
|
|
table = cls.__table__()
|
|
cls._sql_constraints += [
|
|
('UniqueIdentifier', Unique(table, table.code,table.type),
|
|
'La identificacion ya existe')
|
|
]
|
|
|
|
|
|
@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:
|
|
self.raise_user_error('Se requiere modulo stdnum.co.nit')
|
|
if self.type and self.code:
|
|
if self.type in ('31'):
|
|
return int(stdnum.co.nit.calc_check_digit(self.code))
|
|
|
|
@fields.depends('type', 'party', 'code')
|
|
def check_code(self):
|
|
super(PartyIdentifier, self).check_code()
|
|
if self.type == '31':
|
|
#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:
|
|
self.raise_user_error('Se requiere modulo stdnum.co.nit')
|
|
|
|
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 = ''
|
|
self.raise_user_error('invalid_vat', {
|
|
'code': self.code,
|
|
'party': party,
|
|
})
|
|
if self.type in ['12','13','31'] and not self.code.isdigit():
|
|
if self.party and self.party.id > 0:
|
|
party = self.party.rec_name
|
|
else:
|
|
party = ''
|
|
self.raise_user_error('invalid_vat',{
|
|
'code':self.code,
|
|
'party':party
|
|
})
|
|
|
|
@staticmethod
|
|
def default_type_document():
|
|
return '13'
|
|
|
|
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'],
|
|
)
|
|
|
|
|
|
@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
|