trytond-aeat_sii/invoice.py

284 lines
9.0 KiB
Python

# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from trytond.model import ModelView, fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval
from trytond.transaction import Transaction
from sql.aggregate import Max
from .aeat import (
OPERATION_KEY, BOOK_KEY, SEND_SPECIAL_REGIME_KEY,
RECEIVE_SPECIAL_REGIME_KEY, AEAT_INVOICE_STATE, IVA_SUBJECTED,
EXCEMPTION_CAUSE, INTRACOMUNITARY_TYPE, COMMUNICATION_TYPE)
__all__ = ['Invoice', 'Sale', 'Purchase']
_SII_INVOICE_KEYS = ['sii_book_key', 'sii_issued_key', 'sii_received_key',
'sii_subjected_key', 'sii_excemption_key',
'sii_intracomunity_key']
class Invoice:
__metaclass__ = PoolMeta
__name__ = 'account.invoice'
sii_book_key = fields.Selection(BOOK_KEY, 'SII Book Key')
sii_operation_key = fields.Selection(OPERATION_KEY, 'SII Operation Key')
sii_issued_key = fields.Selection(SEND_SPECIAL_REGIME_KEY,
'SII Issued Key',
states={
'invisible': ~Eval('sii_book_key').in_(['E']),
}, depends=['sii_book_key'])
sii_received_key = fields.Selection(RECEIVE_SPECIAL_REGIME_KEY,
'SII Recived Key',
states={
'invisible': ~Eval('sii_book_key').in_(['R']),
}, depends=['sii_book_key'])
sii_subjected_key = fields.Selection(IVA_SUBJECTED, 'Subjected')
sii_excemption_key = fields.Selection(EXCEMPTION_CAUSE,
'Excemption Cause')
sii_intracomunity_key = fields.Selection(INTRACOMUNITARY_TYPE,
'SII Intracommunity Key',
states={
'invisible': ~Eval('sii_book_key').in_(['U']),
}, depends=['sii_book_key'])
sii_records = fields.One2Many('aeat.sii.report.lines', 'invoice',
"SII Report Lines")
sii_state = fields.Function(fields.Selection(AEAT_INVOICE_STATE,
'SII State'), 'get_sii_state', searcher='search_sii_state')
sii_communication_type = fields.Function(fields.Selection(
COMMUNICATION_TYPE, 'SII Communication Type'),
'get_sii_state')
@classmethod
def __setup__(cls):
super(Invoice, cls).__setup__()
sii_fields = ['sii_book_key', 'sii_operation_key',
'sii_received_key', 'sii_issued_key', 'sii_subjected_key',
'sii_excemption_key', 'sii_intracomunity_key']
cls._check_modify_exclude += sii_fields
cls._error_messages.update({
'invoices_sii': 'The next invoices are related with SII books:\n'
'%s.\n\nIf yuo edit them take care if you need to update '
'again to SII',
})
cls._buttons.update({
'reset_sii_keys': {
'invisible': Eval('sii_state', None) != None,
'icon': 'tryton-executable'}
})
if hasattr(cls, '_intercompany_excluded_fields'):
cls._intercompany_excluded_fields += sii_fields
cls._intercompany_excluded_fields += ['sii_records']
@staticmethod
def default_sii_operation_key():
type_ = Transaction().context.get('type', 'out_invoice')
if type_ in ('in_credit_note', 'out_credit_note'):
return 'R1'
return 'F1'
@classmethod
def search_sii_state(cls, name, clause):
pool = Pool()
SIILines = pool.get('aeat.sii.report.lines')
table = SIILines.__table__()
cursor = Transaction().cursor
cursor.execute(*table.select(Max(table.id), table.invoice,
group_by=table.invoice))
invoices = []
lines = []
for id_, invoice in cursor.fetchall():
invoices.append(invoice)
lines.append(id_)
is_none = False
c = clause[-1]
if isinstance(clause[-1], list):
if None in clause[-1]:
is_none = True
c.remove(None)
c0 = []
if clause[-1] == None or is_none:
c0 = [('id', 'not in', invoices)]
clause2 = [tuple(('state',)) + tuple(clause[1:])] + \
[('id', 'in', lines)]
res_lines = SIILines.search(clause2)
if is_none:
return ['OR', c0, [('id', 'in', [x.invoice.id for x in res_lines])]]
else:
return [('id', 'in', [x.invoice.id for x in res_lines])]
@classmethod
def get_sii_state(cls, invoices, names):
pool = Pool()
SIILines = pool.get('aeat.sii.report.lines')
SIIReport = pool.get('aeat.sii.report')
result = {}
for name in names:
result[name] = dict((i.id, None) for i in invoices)
table = SIILines.__table__()
report = SIIReport.__table__()
cursor = Transaction().cursor
join = table.join(report, condition=table.report == report.id)
cursor.execute(*table.select(Max(table.id), table.invoice,
where=(table.invoice.in_([x.id for x in invoices]) &
(table.state != None)),
group_by=table.invoice))
lines = [a[0] for a in cursor.fetchall()]
if lines:
cursor.execute(*join.select(table.state, report.operation_type,
table.invoice,
where=((table.id.in_(lines)) & (table.state != None) &
(table.company == report.company))))
for state, op, inv in cursor.fetchall():
if 'sii_state' in names:
result['sii_state'][inv] = state
if 'sii_communication_type' in names:
result['sii_communication_type'][inv] = op
return result
def _credit(self):
res = super(Invoice, self)._credit()
for field in _SII_INVOICE_KEYS:
res[field] = getattr(self, field)
res['sii_operation_key'] = 'R4'
return res
@fields.depends(*_SII_INVOICE_KEYS)
def on_change_lines(self):
res = super(Invoice, self).on_change_lines()
for field in _SII_INVOICE_KEYS:
if getattr(self, field):
return res
Tax = Pool().get('account.tax')
taxes = res.get('taxes') and res['taxes'].get('add')
if not taxes:
return res
tax = Tax(taxes[0][1]['tax'])
if not tax:
return res
for field in _SII_INVOICE_KEYS:
res[field] = getattr(tax, field)
return res
def _set_sii_keys(self):
sii_keys = {}
tax = None
for t in self.taxes:
if t.tax.tax_used:
tax = t.tax
break
if not tax:
return sii_keys
for field in _SII_INVOICE_KEYS:
sii_keys[field] = getattr(tax, field)
return sii_keys
@fields.depends(*_SII_INVOICE_KEYS)
def _on_change_lines_taxes(self):
res = super(Invoice, self)._on_change_lines_taxes()
for field in _SII_INVOICE_KEYS:
if getattr(self, field):
return res
sii_keys = self._set_sii_keys()
for k, v in sii_keys.iteritems():
res[k] = v
return res
@classmethod
def copy(cls, records, default=None):
if default is None:
default = {}
default = default.copy()
default['sii_records'] = None
return super(Invoice, cls).copy(records, default=default)
@classmethod
@ModelView.button
def reset_sii_keys(cls, records):
to_write = []
for record in records:
sii_keys = record._set_sii_keys()
sii_keys['sii_operation_key'] = ('R1' if record.type in [
'in_credit_note', 'out_credit_note'] else 'F1')
to_write.extend(([record], sii_keys))
if to_write:
cls.write(*to_write)
@classmethod
def draft(cls, invoices):
super(Invoice, cls).draft(invoices)
invoices_sii = ''
for invoice in invoices:
if invoice.sii_state:
invoices_sii += '\n%s: %s' % (invoice.number, invoice.sii_state)
if invoices_sii:
warning_name = 'invoices_sii_report'
cls.raise_user_warning(warning_name, 'invoices_sii', invoices_sii)
class Sale:
__metaclass__ = PoolMeta
__name__ = 'sale.sale'
def create_invoice(self, invoice_type):
invoice = super(Sale, self).create_invoice(invoice_type)
if not invoice:
return
tax = invoice.taxes and invoice.taxes[0]
if not tax:
return invoice
for field in _SII_INVOICE_KEYS:
setattr(invoice, field, getattr(tax.tax, field))
invoice.save()
return invoice
class Purchase:
__metaclass__ = PoolMeta
__name__ = 'purchase.purchase'
def create_invoice(self, invoice_type):
invoice = super(Purchase, self).create_invoice(invoice_type)
if not invoice:
return
tax = invoice.taxes and invoice.taxes[0]
if not tax:
return invoice
for field in _SII_INVOICE_KEYS:
setattr(invoice, field, getattr(tax.tax, field))
invoice.save()
return invoice