partner_data.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. # -*- coding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # OpenERP, Open Source Management Solution
  5. # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as
  9. # published by the Free Software Foundation, either version 3 of the
  10. # License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. ##############################################################################
  21. from openerp import models, fields, tools, api, _
  22. from openerp.exceptions import ValidationError
  23. from math import floor
  24. import re
  25. import sys
  26. import logging
  27. def calculate_dv_of_ruc(input_str):
  28. # assure that we have a string
  29. if not isinstance(input_str, str):
  30. input_str = str(input_str)
  31. int(input_str)
  32. base = 11
  33. k = 2
  34. the_sum = 0
  35. for i, c in enumerate(reversed(input_str)):
  36. if k > base:
  37. k = 2
  38. the_sum += k * int(c)
  39. k += 1
  40. _, rem = divmod(the_sum, base)
  41. if rem > 1:
  42. dv = base - rem
  43. else:
  44. dv = 0
  45. return dv
  46. class res_partner(models.Model):
  47. _name = 'res.partner'
  48. _inherit = 'res.partner'
  49. _description = 'Add extra data to SET'
  50. ruc_ci = fields.Char(string='Ruc/CI', required=True)
  51. digitointer = fields.Char('RUC Internacional', size=13)
  52. dv = fields.Integer('Dígito Verificador', compute='_compute_dv', store=True)
  53. esinternacional = fields.Boolean(string='Es internacional' ,default = False)
  54. retencion = fields.Boolean(string='Retiene IVA' ,default = False)
  55. retentor_renta = fields.Boolean(string='Retentor renta' ,default = False)
  56. porcentaje_retencion = fields.Integer('Porcentaje de Retención')
  57. porcentaje_retencion_renta = fields.Integer('Porcentaje de Retención Renta')
  58. porcentaje_retencion_absorbida = fields.Integer('Porcentaje de Retención Absorbida')
  59. retiene_iva_cliente = fields.Boolean(string='Es agente retentor' ,default = False)
  60. concepto_iva = fields.Selection([('femenino','Femenino'),('masculino','Masculino')],'Concepto IVA')
  61. concepto_renta = fields.Char('Concepto renta')
  62. rucdv = fields.Char('RUC completo', compute='_compute_ruc_2', store=True)
  63. naturaleza_receptor = fields.Selection([('1','Contribuyente'),('2','No contribuyente')],'Naturaleza receptor')
  64. naturaleza_vendedor = fields.Selection([('1','No contribuyente'),('2','Extranjero')],'Naturaleza vendedor')
  65. nivel = fields.Integer('Nivel', size=2)
  66. nombre_fantasia = fields.Char('Nombre de fantasia')
  67. ci = fields.Char('CI', compute='_compute_ci', store=True)
  68. nro_casa = fields.Integer('Nro. Casa')
  69. nro_documento = fields.Char('Nro. Documento')
  70. timbrado = fields.Char('Timbrado')
  71. tipo_documento_identidad = fields.Char('Tipo Documento Identidad')
  72. iva_retencion_10 = fields.Integer('Porcentaje de retención sobre el IVA 10%')
  73. iva_retencion_5 = fields.Integer('Porcentaje de retención sobre el IVA 5%')
  74. tipo_documento_receptor = fields.Selection([('1','Cédula paraguaya'),('2','Pasaporte'),('3','Cédula extranjera'),('4','Carnet de residencia'),('5','Innominado'),('6','Tarjeta diplomática de exoneración fiscal')],'Tipo Documento Receptor')
  75. tipo_documento_vendedor = fields.Selection([('1','Cédula paraguaya'),('2','Pasaporte'),('3','Cédula extranjera'),('4','Carnet de residencia')],'Tipo Documento Vendedor')
  76. tipo_operacion = fields.Selection([('1','B2B'),('2','B2C'),('3','B2G'),('4','B2F')],'Tipo Operación')
  77. situacion = fields.Selection([('contribuyente','Contribuyente'),('nocontribuyente','No contribuyente')],'Situación')
  78. # activity_id = fields.Many2one("economic.activity",
  79. # string="Default Economic Activity",
  80. # context={'active_test': False})
  81. # economic_activities_ids = fields.Many2many('economic.activity',
  82. # string='Economic Activities',
  83. # context={'active_test': False})
  84. tipo_identificacion = fields.Selection([('1','Cédula paraguaya'),('2','RUC'),('3','Cédula extranjera'),('4','Carnet de residencia'),('5','Innominado')],'Tipo de Identificación')
  85. @api.depends('ruc_ci')
  86. def _compute_dv(self):
  87. for record in self:
  88. if isinstance(record.ruc_ci, str):
  89. ruc_parts = record.ruc_ci.split('-')
  90. ruc_without_verification = ruc_parts[0] if len(ruc_parts) > 1 else record.ruc_ci
  91. if record.tipo_identificacion == '1':
  92. record.dv = calculate_dv_of_ruc(ruc_without_verification)
  93. else:
  94. if record.tipo_identificacion == '2':
  95. record.dv = calculate_dv_of_ruc(ruc_without_verification)
  96. else:
  97. record.dv = 0
  98. else:
  99. record.dv = False
  100. @api.depends('ruc_ci')
  101. def _compute_ci(self):
  102. for record in self:
  103. if isinstance(record.ruc_ci, str):
  104. ruc_parts = record.ruc_ci.split('-')
  105. record.ci = ruc_parts[0] if len(ruc_parts) > 1 else record.ruc_ci
  106. @api.depends('ruc_ci', 'dv')
  107. def _compute_ruc_2(self):
  108. for record in self:
  109. ruc_without_verification = record.ci if record.ci else record.ruc_ci
  110. record.rucdv = "{}-{}".format(ruc_without_verification, record.dv)
  111. # @staticmethod
  112. # def _validate_ruc(vat):
  113. # factor = '43298765432'
  114. # sum = 0
  115. # dig_check = None
  116. # if len(vat) != 12:
  117. # return False
  118. # try:
  119. # int(vat)
  120. # except ValueError:
  121. # return False
  122. # for f in range(0, 11):
  123. # sum += int(factor[f]) * int(vat[f])
  124. # subtraction = 11 - floor((sum % 11))
  125. # if subtraction < 10:
  126. # dig_check = subtraction
  127. # elif subtraction == 10:
  128. # dig_check = ""
  129. # elif subtraction == 11:
  130. # dig_check = 0
  131. #
  132. # if not int(vat[11]) == dig_check:
  133. # return False
  134. # return True
  135. #
  136. # @staticmethod
  137. # # def _validate_ci(vat):
  138. #
  139. # def _validate_ci(vat):
  140. # logging.warning(vat)
  141. # ruc = ''
  142. # basemax = 7
  143. # for c in str(vat).replace('-', ''):
  144. # ruc += c.isdigit() and c or str(ord(c))
  145. # k = 2
  146. # total = 0
  147. #
  148. # for c in reversed(ruc[:-1]):
  149. # n = int(c)
  150. # if n > basemax:
  151. # k = 2
  152. # total += n * k
  153. # k += 1
  154. # resto = total % basemax
  155. # if resto > 1:
  156. # n = basemax - resto
  157. # else:
  158. # n = 0
  159. # return n == int(ruc[-1])
  160. # vat = vat.replace("-", "").replace('.', '')
  161. # sum = 0
  162. # if not vat:
  163. # return False
  164. # try:
  165. # int(vat)
  166. # except ValueError:
  167. # return False
  168. # vat = "%08d" % int(vat)
  169. # long = len(vat)
  170. # if long > 8:
  171. # return False
  172. # code = [2, 9, 8, 7, 6, 3, 4]
  173. # for f in range(0, long - 1):
  174. # sum += int(vat[f]) * int(code[f])
  175. # total = sum + int(vat[-1])
  176. # subtraction = total % 10
  177. # if subtraction != 0:
  178. # return False
  179. # return True
  180. # """
  181. # El numero de una cédula de identidad tiene exactamente 7 dígitos al cual se le adiciona
  182. # un dígito verificador.
  183. #
  184. # Es así que un número valido debe respetar el siguiente formato:
  185. #
  186. # a.bcd.efg-h
  187. #
  188. # El dígito posterior al guión (h) es también llamado dígito verificador.
  189. #
  190. # Para obtener h debemos:
  191. #
  192. # Multiplicar a,b,c,d,e,f,g por las siguientes constantes:
  193. # (a; b; c; d; e; f; g) .* (2; 9; 8; 7; 6; 3; 4)
  194. #
  195. # El resultado de la suma s = 2*a + 9*b + 8*c + 7*d + 6*e + 3*f + 4*g es dividido por 10
  196. # quedándonos con resto (M = s modulo 10)
  197. #
  198. # Finalmente h = (10 - M) % 10
  199. #
  200. # Ejemplo practico:
  201. # Si la CI es 1.234.567:
  202. #
  203. # s = 2*1 + 9*2 + 8*3 + 7*4 + 6*5 + 3*6 + 4*7 = 148
  204. # M = 148 % 10 = 8
  205. # h = (10 - 8) % 10 = 2
  206. # Obteniendo que 1.234.567-2 es un número de CI valido.
  207. # """
  208. # class res_partner(models.Model):
  209. # _inherit = 'res.partner'
  210. # code = [2, 9, 8, 7, 6, 3, 4]
  211. #
  212. # # def __init__(self, vat):
  213. # """ Inicializa la clase
  214. # Asigna un numero de cedula a la propiedad publica numero
  215. #
  216. # Args:
  217. # numero: un numero de cedula entre 6 y 7 digitos, puede ser int o string
  218. # """
  219. # self.ruc = vat
  220. # self._verifier = ""
  221. #
  222. # @property
  223. # def numero(self):
  224. # """ propiedad de lectura
  225. #
  226. # Returns:
  227. # _numero: la propiedad privada de numero de cedula ya normalizada
  228. # """
  229. # return self._ruc
  230. #
  231. # @numero.setter
  232. # def numero(self, val):
  233. # """ asigna a la propiedad privada el numero de cedula asignado a numero,
  234. # lo normaliza y valida
  235. # Args:
  236. # val (int o string): el numero de cedula
  237. #
  238. # """
  239. # try:
  240. # if isinstance(val, str):
  241. # # si la cedula es un string, le saco el formato (puntos y guiones)
  242. # numUpdated = re.sub(r"[\.|\-]", "", val)
  243. # self._ruc = numUpdated
  244. # else:
  245. # self._ruc = str(val)
  246. #
  247. # if not self._ruc.isnumeric():
  248. # sys.exit("cedula should be only numbers")
  249. #
  250. # if (len(self._ruc) < 6 or len(self._ruc) > 7):
  251. # sys.exit("invalid cedula length...")
  252. #
  253. # except:
  254. # sys.exit(
  255. # "Cedula conversion error, check cedula length, value or format.")
  256. #
  257. # @property
  258. # def verifier(self):
  259. # """propiedad de lectura del digito verificador
  260. #
  261. # Returns:
  262. # int: digito verificador
  263. # """
  264. # return self._verifier
  265. #
  266. # def __acumSequence(self, seq, index):
  267. # """ funcion recursiva privada que suma los digitos de una cedula
  268. #
  269. # Args:
  270. # seq: el numero en la constante SEQUENCE
  271. # index (int): la posicion en ambos arrays (secuencia y cedula)
  272. # Deben matchear en posicion
  273. #
  274. # ** NOTA: como la correspondencia debe ser 1:1 seq y _numero, en caso de ser
  275. # una cedula de 6 digitos se podia haber agregado un 0 al inicio de _numero para comenzar
  276. # con el mismo largo (7 digitos), pero asi es mas divertido :D
  277. #
  278. # Returns:
  279. # int: la acumulacion de la suma de digito de self._numero * digito de secuencia
  280. # """
  281. # if index < (len(seq) - 1):
  282. # return (seq[index] * int(self._ruc[index])) + self.__acumSequence(seq, index + 1)
  283. # return seq[index] * int(self._ruc[index])
  284. #
  285. # def getVerifierDigit(self):
  286. # """ calculo de digito verificador
  287. #
  288. # Returns:
  289. # int: digito verificador
  290. # """
  291. # try:
  292. # digit_diff = (len(self.code) - len(self._ruc))
  293. # if digit_diff >= 0:
  294. # acum = 0
  295. # acum = self.__acumSequence(self.code[digit_diff:], 0)
  296. # mod = (acum % 10)
  297. # verifier = ((10 - mod) % 10)
  298. # self._verifier = str(verifier)
  299. # return verifier
  300. # except:
  301. # print("ERROR: unknown error, check params!")
  302. #
  303. # def formatCedula(self):
  304. # """ formatea un numero de cedula al formato de puntos y guion
  305. # ej: 12345678 => 1.234.567-8
  306. #
  307. # Returns:
  308. # string: el numero de cedula completo y formateado
  309. # """
  310. # self.getVerifierDigit()
  311. # if len(self.ruc) == 6:
  312. # return self.ruc[:3] + '.' + self.ruc[3:] + '-' + self.verifier
  313. # return self.ruc[:1] + '.' + self.ruc[1:4] + '.' + self.ruc[4:] + '-' + self.verifier