123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- # -*- coding: utf-8 -*-
- ##############################################################################
- #
- # OpenERP, Open Source Management Solution
- # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU Affero General Public License as
- # published by the Free Software Foundation, either version 3 of the
- # License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU Affero General Public License for more details.
- #
- # You should have received a copy of the GNU Affero General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- #
- ##############################################################################
- import logging
- from openerp import models, fields, tools, api, _
- from openerp.exceptions import Warning as ValidationError
- import json
- import base64
- import requests
- import io
- import hashlib
- _logger = logging.getLogger(__name__)
- class AccountInvoice(models.Model):
- _name = 'account.invoice'
- _inherit = 'account.invoice'
- _description = 'Add extra data to SET in account invoice'
- numero_factura = fields.Char(string='Factura Nº', related='number', store = True)
- sucursal = fields.Char(string='Establecimiento', compute='_compute_suc_sec', store=True)
- sec = fields.Char(string='Punto', compute='_compute_suc_sec', store=True)
- descripcion = fields.Text("Descripción")
- nro_actual = fields.Char('Nro Actual', compute='_compute_suc_sec', store=True)
- talonario_id = fields.Many2one('talonario', 'Talonario') # Remover required temporalmente
- timbrado_name = fields.Char(related='talonario_id.name', string='Número de timbrado', readonly=True)
- talonario_tipo_documento = fields.Selection(related='talonario_id.tipo_documento', string='Tipo de documento', readonly=True)
- fecha_final = fields.Date(related='talonario_id.fecha_final', string='Fecha de expiración de timbrado', readonly=True)
- nro_fin = fields.Integer(
- string='Nro Final',
- related='talonario_id.nro_fin',
- store=True,
- readonly=True
- )
- no_mostrar_libro_iva = fields.Boolean(string='No visualizar en el libro IVA')
- importacion = fields.Boolean(string='Fact. de importación')
- importacion_gasto = fields.Boolean(string='Fact. de gastos de importación')
- # envio_lote_id = fields.Many2one('envio.lotes', string='Envio Lote')
- # qr_code = fields.Binary('Código QR', compute='_generate_qr_code')
- # texto_qr = fields.Char(invisible=True)
- dProtAut = fields.Char('Código de operación')
- operacion_credito = fields.Selection([('1','Normal'),('2','Contingencia')],'Operación Crédito')
- tipo_factura = fields.Selection([('1','1'),('2','2')],'Tipo de Factura')
- metodo_pago = fields.Selection([('1','Dinero En Efectivo'),('2','Transferencia'),('3','Cheque'),('4','Tarjeta de crédito'),('5','Tarjeta de débito'),('6','Giro'),('7','Billetera Electronica'),('8','Tarjeta Empresarial'),('9','Vales'),('10','Retención')],'Método de Pago')
- # mje_resultado_ids = fields.One2many('mje.resultado', 'invoice_id', string='Resultados de mensajes')
- # dEstRes = fields.Char('Estado de respuesta')
- @api.depends('number', 'journal_id', 'state')
- def _compute_suc_sec(self):
- for invoice in self:
- if invoice.state == 'cancel' and invoice.type == 'out_invoice':
- invoice.sucursal = ''
- invoice.sec = ''
- invoice.nro_actual = ''
- elif invoice.journal_id.id == 2 and invoice.number and invoice.type == 'out_invoice':
- parts = invoice.number.split('-')
- invoice.sucursal = parts[0] if len(parts) > 0 else ''
- invoice.sec = parts[1] if len(parts) > 1 else ''
- invoice.nro_actual = parts[2] if len(parts) > 2 else ''
- else:
- invoice.sucursal = ''
- invoice.sec = ''
- invoice.nro_actual = ''
- @api.constrains('nro_actual', 'nro_fin')
- def _check_nro_actual_vs_nro_fin(self):
- for invoice in self:
- if invoice.talonario_id and invoice.nro_fin and invoice.nro_actual:
- try:
- nro_actual_int = int(invoice.nro_actual)
- except ValueError:
- raise ValidationError("El número actual debe ser un número válido.")
- if nro_actual_int > invoice.nro_fin:
- raise ValidationError(
- "El número actual (%s) excede el número final permitido en el talonario (%s)." %
- (nro_actual_int, invoice.nro_fin)
- )
- @api.onchange('talonario_id')
- def _onchange_talonario_id(self):
- if self.talonario_id:
- self.timbrado_name = self.talonario_id.name
- self.talonario_tipo_documento = self.talonario_id.tipo_documento
- self.fecha_final = self.talonario_id.fecha_final
- else:
- self.timbrado_name = False
- self.talonario_tipo_documento = False
- self.fecha_final = False
- @api.onchange('type', 'company_id')
- def _onchange_type_set_talonario_domain(self):
- """
- - out_invoice -> talonario.tipo_documento '1' (Factura)
- - out_refund -> talonario.tipo_documento '5' (Nota de crédito)
- Siempre filtra por active=True y company_id de la factura.
- Autoselecciona si existe exactamente uno.
- """
- domain = []
- if self.type == 'out_invoice':
- domain = [('tipo_documento', '=', '1'), ('activo', '=', True)]
- elif self.type == 'out_refund':
- domain = [('tipo_documento', '=', '5'), ('activo', '=', True)]
- else:
- domain = [('id', '=', False)]
- if self.company_id:
- domain.append(('company_id', '=', self.company_id.id))
- res = {'domain': {'talonario_id': domain}}
- # Autoseleccionar si hay exactamente un talonario válido
- if not self.talonario_id and domain and domain != [('id', '=', False)]:
- talonarios = self.env['talonario'].search(domain, limit=2)
- if len(talonarios) == 1:
- self.talonario_id = talonarios[0].id
- return res
- @api.model
- def create(self, vals):
- """
- Si no se pasa talonario_id, se asigna automáticamente:
- - out_invoice -> talonario.tipo_documento '1'
- - out_refund -> talonario.tipo_documento '5'
- Filtrado por active=True y company_id de la factura.
- """
- if not vals.get('talonario_id'):
- inv_type = vals.get('type') or self._context.get('type')
- company_id = vals.get('company_id') or self._context.get('company_id')
- if inv_type in ('out_invoice', 'out_refund'):
- tipo = '1' if inv_type == 'out_invoice' else '5'
- domain = [('tipo_documento', '=', tipo), ('activo', '=', True)]
- if company_id:
- domain.append(('company_id', '=', company_id))
- tal = self.env['talonario'].search(domain, limit=1)
- if tal:
- vals['talonario_id'] = tal.id
- return super(AccountInvoice, self).create(vals)
- # class AccountInvoice1(models.Model):
- # _inherit = 'account.invoice'
- #
- # def send_invoice_to_sifen(self):
- # for record in self:
- # url = 'https://sifen.set.gov.py/api'
- # headers = {'Content-Type': 'application/json'}
- # data = record.prepare_invoice_data()
- # response = requests.post(url, json=data, headers=headers)
- # if response.status_code == 200:
- # self.handle_response(response.json())
- # else:
- # raise UserError('Error sending invoice to SIFEN: {}'.format(response.content))
- #
- # def prepare_invoice_data(self):
- # self.ensure_one()
- # return {
- # "tipoDocumento": self.talonario_tipo_documento,
- # "establecimiento": self.sucursal,
- # "codigoSeguridadAleatorio": self.cdc,
- # "punto": self.sec,
- # "numero": self.nro_actual,
- # "descripcion": self.descripcion,
- # "observacion": self.observacion,
- # "tipoContribuyente": self.tipo_contribuyente,
- # "fecha": self.date_invoice.isoformat(),
- # "tipoEmision": self.tipo_emision,
- # "tipoTransaccion": self.tipo_contribuyente,
- # "tipoImpuesto": self.tipo_impuesto,
- # "moneda": self.moneda,
- # "condicionAnticipo": self.condicion_anticipo,
- # "condicionTipoCambio": self.condicion_tipo_cambio,
- # "cambio": self.cambio,
- # "cliente": {
- # "contribuyente": self.partner_id.situacion,
- # "ruc": self.partner_id.ruc,
- # "razonSocial": self.partner_id.name,
- # "nombreFantasia": self.partner_id.name,
- # "tipoOperacion": self.partner_id.tipo_operacion,
- # "direccion": self.partner_id.street,
- # "numeroCasa": self.partner_id.nro_casa,
- # "departamento": self.partner_id.street,
- # "departamentoDescripcion": self.partner_id.street,
- # "distrito": self.partner_id.city,
- # "distritoDescripcion": self.partner_id.street,
- # "ciudad": self.partner_id.city,
- # "ciudadDescripcion": self.partner_id.street,
- # "pais": self.partner_id.country_id.code,
- # "paisDescripcion": self.partner_id.country_id.name,
- # "tipoContribuyente": self.partner_id.situacion,
- # "documentoTipo": self.partner_id.tipo_documento_receptor,
- # "documentoNumero": self.partner_id.nro_documento,
- # "telefono": self.partner_id.phone,
- # "celular": self.partner_id.mobile,
- # "email": self.partner_id.email,
- # "codigo": self.partner_id.dv
- # },
- # # Añadir otros campos según sea necesario
- # }
- #
- # def handle_response(self, response):
- # if response.get('status') == 'approved':
- # self.write({'state': 'open'})
- # else:
- # raise UserError('Factura no fue aprobado por la SIFEN: {}'.format(response.get('message')))
- #
- # def _generate_cdc(self):
- # data_to_hash = (
- # str(self.talonario_tipo_documento) +
- # self.sucursal +
- # self.cdc +
- # self.sec +
- # self.nro_actual +
- # self.date_invoice.strftime('%Y%m%d%H%M%S') +
- # str(self.tipo_transaccion) +
- # str(self.amount_total)
- # )
- # md5_hash = hashlib.md5(data_to_hash.encode('utf-8')).digest()
- # cdc_base32 = base64.b32encode(md5_hash).decode('utf-8').rstrip('=')
- # self.cdc = cdc_base32
- #
- # def _generate_qr_code(self):
- # import qrcode
- # from io import BytesIO
- # qr_data = "cdc={}&ruc={}&date={}".format(self.cdc, self.partner_id.ruc, self.date_invoice)
- # qr = qrcode.QRCode(
- # version=1,
- # error_correction=qrcode.constants.ERROR_CORRECT_L,
- # box_size=10,
- # border=4,
- # )
- # qr.add_data(qr_data)
- # qr.make(fit=True)
- # img = qr.make_image(fill='black', back_color='white')
- # buffer = BytesIO()
- # img.save(buffer, format="PNG")
- # self.qr_code = base64.b64encode(buffer.getvalue())
|