Skip to content

Commit

Permalink
fixes #5 Implements webservice WS_SR_PADRON_A4 to retrieve padron dat…
Browse files Browse the repository at this point in the history
…a from AFIP

Conflicts:
	party.py
	view/get_afip_data_start_view.xml
  • Loading branch information
lukio committed Dec 11, 2017
1 parent 2e53912 commit 469c934
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 177 deletions.
317 changes: 146 additions & 171 deletions party.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@

import stdnum.ar.cuit as cuit
import stdnum.exceptions
from urllib2 import urlopen
import ssl
import sys
from json import loads, dumps
from actividades import CODES

from trytond.model import ModelView, ModelSQL, fields
Expand All @@ -18,6 +14,7 @@
from trytond.transaction import Transaction
from trytond.tools import cursor_dict
from trytond import backend
from trytond.modules.account_invoice_ar.afip_auth import get_cache_dir
import logging
logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -268,6 +265,7 @@ def __setup__(cls):
super(Party, cls).__setup__()
cls._buttons.update({
'get_afip_data': {},
'import_census': {},
})

@staticmethod
Expand Down Expand Up @@ -327,6 +325,108 @@ def search_vat_number_afip_foreign(cls, name, clause):
('identifiers.type', '=', 'ar_foreign'),
]

@classmethod
def get_ws_afip(cls, vat_number):
try:
# authenticate against AFIP:
from pyafipws.ws_sr_padron import WSSrPadronA4
ws = WSSrPadronA4()
Company = Pool().get('company.company')
if Transaction().context.get('company'):
company = Company(Transaction().context['company'])
auth_data = company.pyafipws_authenticate(service='ws_sr_padron_a4')
# connect to the webservice and call to the test method
ws.LanzarExcepciones = True
cache_dir = get_cache_dir()
if company.pyafipws_mode_cert == 'homologacion':
WSDL = 'https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA4?wsdl'
elif company.pyafipws_mode_cert == 'produccion':
WSDL = 'https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA4?wsdl'
ws.Conectar(wsdl=WSDL, cache=cache_dir)
# set AFIP webservice credentials:
ws.Cuit = company.party.vat_number
ws.Token = auth_data['token']
ws.Sign = auth_data['sign']
ws.Consultar(vat_number)
return ws
except Exception, e:
logger.error('Could not retrieve "%s" msg AFIP: "%s".' %
(vat_number, repr(e)))
return None

def set_padron(self, padron, button_afip=True):
if padron.tipo_persona == 'FISICA':
self.name = "%s, %s" % \
(padron.data.get('apellido'), padron.data.get('nombre'))
else:
self.name = padron.data.get('razonSocial', '')
if padron.data.get('estadoClave') == 'ACTIVO':
self.active = True
else:
self.active = False

mt = 'S' == padron.monotributo
impuestos = padron.impuestos
if 32 in impuestos:
self.iva_condition = 'exento'
elif 34 in impuestos:
self.iva_condition = 'no_alcanzado'
else:
if mt:
self.iva_condition = 'monotributo'
elif 30 in impuestos:
self.iva_condition = 'responsable_inscripto'
else:
self.iva_condition = 'consumidor_final'

if button_afip:
fecha_inscripcion = padron.data.get('fechaInscripcion', None)
if fecha_inscripcion:
self.start_activity_date = fecha_inscripcion.date()
activ = padron.actividades
activ1 = str(activ[0]) if len(activ) >= 1 else ''
activ2 = str(activ[1]) if len(activ) >= 2 else ''
if activ1:
self.primary_activity_code = activ1.rjust(6, '0')
if activ2:
self.secondary_activity_code = activ2.rjust(6, '0')

Address = Pool().get('party.address')
address_ = self.address_get('invoice')
address_.active = False
address_.save()
for domicilio in padron.domicilios:
if domicilio.get('tipoDomicilio') == 'FISCAL':
address = Address()
address.street = domicilio.get('direccion', '')
address.city = domicilio.get('localidad', '')
address.zip = domicilio.get('codPostal')
address.country = self.get_afip_country()
address.subdivision = \
self.get_afip_subdivision(domicilio.get('idProvincia', 0))
address.party = self
if domicilio.get('tipoDomicilio') == 'FISCAL':
address.invoice = True
address.save()
self.save()

@classmethod
def get_afip_subdivision(cls, subdivision_code):
Subdivision = Pool().get('country.subdivision')
subdivision = PROVINCIAS[subdivision_code]
subdivision = Subdivision().search(
['name', '=', subdivision]
)
if len(subdivision) > 0:
return subdivision[0]
else:
return ''

@classmethod
def get_afip_country(cls):
Country = Pool().get('country.country')
return Country().search(['code', '=', 'AR'])[0]

# Button de AFIP
@classmethod
@ModelView.button_action('party_ar.wizard_get_afip_data')
Expand All @@ -341,53 +441,16 @@ def import_census(cls, configs):
'''
partys = Pool().get('party.party').search([
('vat_number', '!=', None),
])
], limit=5)

for party in partys:
afip_dict = {}
try:
data = cls.get_json_afip(party.vat_number)
afip_dict = loads(data)
success = afip_dict['success']
if success is True:
afip_dict = afip_dict['data']
else:
logger.error('Afip return error message %s.' %
afip_dict['error']['mensaje'])
except:
logging.error('Could not retrieve vat_number: %s.' %
party.vat_number)
logging.info('got afip_json:\n' + dumps(afip_dict))
mt = afip_dict.get('categoriasMonotributo', {})
impuestos = afip_dict.get('impuestos', [])

if 32 in impuestos:
party.iva_condition = 'exento'
else:
if mt:
party.iva_condition = 'monotributo'
elif 30 in impuestos:
party.iva_condition = 'responsable_inscripto'
else:
party.iva_condition = 'consumidor_final'
party.save()
padron = cls.get_ws_afip(party.vat_number)
if padron:
logging.info('got "%s" afip_ws_sr_padron_a4: "%s"' %
(party.vat_number, padron.data))
party.set_padron(padron, button_afip=False)
Transaction().cursor.commit()

@classmethod
def get_json_afip(cls, vat_number):
try:
afip_url = 'https://soa.afip.gob.ar/sr-padron/v2/persona/%s' \
% vat_number
if sys.version_info >= (2, 7, 9):
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
afip_stream = urlopen(afip_url, context=context)
else:
afip_stream = urlopen(afip_url)
afip_json = afip_stream.read()
return afip_json
except Exception, e:
logger.error('Could not retrieve %s.' % repr(e))

@classmethod
def import_cron_afip(cls, args=None):
'''
Expand Down Expand Up @@ -630,12 +693,11 @@ def check_foreign_vat(self):
class GetAFIPDataStart(ModelView):
'Get AFIP Data Start'
__name__ = 'party.get_afip_data.start'
afip_data = fields.Text('Datos extras')
nombre = fields.Char('Nombre', readonly=True)
name = fields.Char('Name', readonly=True)
direccion = fields.Char('Direccion', readonly=True)
localidad = fields.Char('Localidad', readonly=True)
codigo_postal = fields.Char('Codigo Postal', readonly=True)
fecha_inscripcion = fields.Char('Fecha de Inscripcion', readonly=True)
fecha_inscripcion = fields.Date('Fecha de Inscripcion', readonly=True)
subdivision_code = fields.Integer('Subdivision', readonly=True)
primary_activity_code = fields.Selection(CODES, 'Actividad primaria',
readonly=True)
Expand Down Expand Up @@ -668,133 +730,46 @@ def default_start(self, fields):
res = {}
party = Party(Transaction().context['active_id'])
if party:
afip_json = self.get_json(party.vat_number)
afip_dict = loads(afip_json)
print ' >>> got json:\n' + dumps(afip_dict)
if afip_dict['success'] is True:
afip_dict = afip_dict['data']
padron = Party.get_ws_afip(party.vat_number)
if padron:
activ = padron.actividades
for domicilio in padron.domicilios:
if domicilio.get('tipoDomicilio') == 'FISCAL':
res['direccion'] = domicilio.get("direccion", "")
res['localidad'] = domicilio.get("localidad", "") # no usado en CABA
res['subdivision_code'] = domicilio.get("idProvincia", 0)
res['codigo_postal'] = domicilio.get("codPostal")

activ1 = str(activ[0]) if len(activ) >= 1 else ''
activ2 = str(activ[1]) if len(activ) >= 2 else ''
if activ1:
activ1 = activ1.rjust(6, '0')
if activ2:
activ2 = activ2.rjust(6, '0')

if padron.tipo_persona == 'FISICA':
res['name'] = "%s, %s" % \
(padron.data.get('apellido'), padron.data.get('nombre'))
else:
res['name'] = padron.data.get('razonSocial', '')

res.update({
'fecha_inscripcion': padron.data.get('fechaInscripcion', None),
'primary_activity_code': activ1,
'secondary_activity_code': activ2,
'estado': padron.data.get('estadoClave', ''),
})
else:
self.raise_user_error('vat_number_not_found')

activ = afip_dict.get('actividades', {})
domicilioFiscal = afip_dict.get('domicilioFiscal', {})
activ1 = str(activ[0]) if len(activ) >= 1 else ''
activ2 = str(activ[1]) if len(activ) >= 2 else ''
if activ1:
activ1 = activ1.rjust(6, '0')
if activ2:
activ2 = activ2.rjust(6, '0')
res = {
'nombre': afip_dict['nombre'],
'direccion': domicilioFiscal.get('direccion', ''),
'localidad': domicilioFiscal.get('localidad', ''),
'codigo_postal': domicilioFiscal.get('codPostal', ''),
'fecha_inscripcion': afip_dict['fechaInscripcion'],
'primary_activity_code': activ1,
'secondary_activity_code': activ2,
'estado': afip_dict['estadoClave'],
'subdivision_code': domicilioFiscal.get('idProvincia', 0),
'afip_data': afip_json,
}

return res

def transition_update_party(self):
# Actualizamos la party con la data que vino de AFIP
Party = Pool().get('party.party')
party = Party(Transaction().context.get('active_id'))
print ' >>> should be updating party...'

import datetime
# formato de fecha: AAAA-MM-DD
fecha = self.start.fecha_inscripcion.split('-')
if len(fecha) == 3 and len(fecha) == 3:
year = int(fecha[0])
month = int(fecha[1])
day = int(fecha[2])

party.name = self.start.nombre
party.primary_activity_code = self.start.primary_activity_code
party.secondary_activity_code = self.start.secondary_activity_code
party.vat_country = 'AR'
party.start_activity_date = datetime.date(year, month, day)
if self.start.estado == 'ACTIVO':
party.active = True
else:
party.active = False

# Direccion
Address = Pool().get('party.address')
direccion = Address().search(['party', '=', party])

if len(direccion) > 0 and (direccion[0].street is None
or direccion[0].street == ''):
self._update_direccion(direccion[0], party, self.start)
else:
direccion = Address()
self._update_direccion(direccion, party, self.start)

afip_dict = loads(self.start.afip_data)['data']
mt = afip_dict.get('categoriasMonotributo', {})
impuestos = afip_dict.get('impuestos', [])

if 32 in impuestos:
party.iva_condition = 'exento'
else:
if mt:
party.iva_condition = 'monotributo'
elif 30 in impuestos:
party.iva_condition = 'responsable_inscripto'
else:
party.iva_condition = 'consumidor_final'

party.save()
padron = Party.get_ws_afip(party.vat_number)
if padron:
logging.info('got "%s" afip_ws_sr_padron_a4: "%s"' %
(party.vat_number, padron.data))
party.set_padron(padron)
return 'end'

@classmethod
def _update_direccion(self, direccion, party, start):
'Actualizamos direccion de una party'
direccion.name = start.nombre
direccion.street = start.direccion
direccion.city = start.localidad
direccion.zip = start.codigo_postal
direccion.subdivision = self.get_subdivision(start.subdivision_code)
direccion.country = self.get_country()
direccion.party = party
direccion.invoice = True
direccion.save()

@classmethod
def get_json(self, vat_number):
try:
afip_url = 'https://soa.afip.gob.ar/sr-padron/v2/persona/%s' \
% vat_number
if sys.version_info >= (2, 7, 9):
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
afip_stream = urlopen(afip_url, context=context)
else:
afip_stream = urlopen(afip_url)
afip_json = afip_stream.read()
return afip_json
except Exception:
self.raise_user_error('vat_number_not_found')

@classmethod
def get_subdivision(self, subdivision_code):
Subdivision = Pool().get('country.subdivision')
subdivision = PROVINCIAS[subdivision_code]
subdivision = Subdivision().search(
['name', '=', subdivision]
)
if len(subdivision) > 0:
return subdivision[0]
else:
return ''

@classmethod
def get_country(self):
Country = Pool().get('country.country')
country = Country().search(
['code', '=', 'AR']
)[0]
return country
Loading

0 comments on commit 469c934

Please sign in to comment.