trytond-aeat_sii/invoice.py

268 lines
8.5 KiB
Python
Raw Normal View History

2017-04-28 09:26:42 +02:00
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from decimal import Decimal
2017-07-04 11:44:44 +02:00
from trytond.model import ModelView, fields
2017-04-28 09:26:42 +02:00
from trytond.pool import Pool, PoolMeta
2018-01-18 17:08:54 +01:00
from trytond.pyson import Eval, Bool
2017-04-28 09:26:42 +02:00
from trytond.transaction import Transaction
2018-01-18 17:08:54 +01:00
from sql import Null
2017-04-28 09:26:42 +02:00
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,
2017-06-13 15:59:42 +02:00
EXCEMPTION_CAUSE, INTRACOMUNITARY_TYPE, COMMUNICATION_TYPE)
2017-05-22 18:08:28 +02:00
2017-04-28 09:26:42 +02:00
__all__ = ['Invoice', 'Sale', 'Purchase']
2017-04-28 09:26:42 +02:00
2017-06-22 23:36:46 +02:00
_SII_INVOICE_KEYS = ['sii_book_key', 'sii_issued_key', 'sii_received_key',
'sii_subjected_key', 'sii_excemption_key',
'sii_intracomunity_key']
2018-10-11 15:32:09 +02:00
class Invoice(metaclass=PoolMeta):
2017-04-28 09:26:42 +02:00
__name__ = 'account.invoice'
2017-06-07 16:45:12 +02:00
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,
2017-04-28 09:26:42 +02:00
'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',
2017-04-28 09:26:42 +02:00
states={
2018-01-18 17:08:54 +01:00
'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,
2017-04-28 09:26:42 +02:00
'Excemption Cause')
sii_intracomunity_key = fields.Selection(INTRACOMUNITARY_TYPE,
'SII Intracommunity Key',
states={
'invisible': ~Eval('sii_book_key').in_(['U']),
}, depends=['sii_book_key'])
2017-04-28 09:26:42 +02:00
sii_records = fields.One2Many('aeat.sii.report.lines', 'invoice',
"SII Report Lines")
2017-04-28 09:26:42 +02:00
sii_state = fields.Function(fields.Selection(AEAT_INVOICE_STATE,
'SII State'), 'get_sii_state', searcher='search_sii_state')
2017-06-13 15:59:42 +02:00
sii_communication_type = fields.Function(fields.Selection(
2017-06-30 10:33:42 +02:00
COMMUNICATION_TYPE, 'SII Communication Type'),
2017-06-13 15:59:42 +02:00
'get_sii_state')
2017-04-28 09:26:42 +02:00
@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'
2018-10-19 09:57:07 +02:00
'%s.\n\nIf you edit them take care if you need to update '
'again to SII',
})
2017-07-04 11:44:44 +02:00
cls._buttons.update({
'reset_sii_keys': {
2018-01-18 17:08:54 +01:00
'invisible': Bool(Eval('sii_state', None)),
2017-07-04 11:44:44 +02:00
'icon': 'tryton-executable'}
})
if hasattr(cls, '_intercompany_excluded_fields'):
cls._intercompany_excluded_fields += sii_fields
cls._intercompany_excluded_fields += ['sii_records']
2017-06-12 13:52:37 +02:00
@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'
2017-04-28 09:26:42 +02:00
@classmethod
def search_sii_state(cls, name, clause):
pool = Pool()
SIILines = pool.get('aeat.sii.report.lines')
assert clause[1] in ('=', 'in')
2017-04-28 09:26:42 +02:00
table = SIILines.__table__()
2017-06-08 08:41:46 +02:00
cursor = Transaction().connection.cursor()
2017-04-28 09:26:42 +02:00
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_)
values = clause[-1]
is_none = False
if isinstance(clause[-1], (list, tuple, set)):
if None in clause[-1]:
is_none = True
values.remove(None)
else:
is_none = bool(clause[-1] is None)
c0 = []
if is_none:
c0 = [('sii_records', '=', None)]
2017-04-28 09:26:42 +02:00
clause2 = [
('state', ) + tuple(clause[1:2]) + (values, ),
('id', 'in', lines)
]
2017-04-28 09:26:42 +02:00
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])]
2017-04-28 09:26:42 +02:00
@classmethod
def get_sii_state(cls, invoices, names):
pool = Pool()
SIILines = pool.get('aeat.sii.report.lines')
2017-06-13 15:59:42 +02:00
SIIReport = pool.get('aeat.sii.report')
2017-04-28 09:26:42 +02:00
result = {}
2017-04-28 09:26:42 +02:00
for name in names:
result[name] = dict((i.id, None) for i in invoices)
2017-04-28 09:26:42 +02:00
table = SIILines.__table__()
2017-06-13 15:59:42 +02:00
report = SIIReport.__table__()
2017-06-08 08:41:46 +02:00
cursor = Transaction().connection.cursor()
2017-06-13 15:59:42 +02:00
join = table.join(report, condition=table.report == report.id)
2017-04-28 09:26:42 +02:00
cursor.execute(*table.select(Max(table.id), table.invoice,
where=(table.invoice.in_([x.id for x in invoices]) &
2018-01-18 17:08:54 +01:00
(table.state != Null)),
2017-04-28 09:26:42 +02:00
group_by=table.invoice))
lines = [a[0] for a in cursor.fetchall()]
if lines:
2017-06-13 15:59:42 +02:00
cursor.execute(*join.select(table.state, report.operation_type,
table.invoice,
2018-01-18 17:08:54 +01:00
where=((table.id.in_(lines)) & (table.state != Null) &
(table.company == report.company))))
2017-04-28 09:26:42 +02:00
2017-06-13 15:59:42 +02:00
for state, op, inv in cursor.fetchall():
2017-06-16 09:32:47 +02:00
if 'sii_state' in names:
result['sii_state'][inv] = state
if 'sii_communication_type' in names:
result['sii_communication_type'][inv] = op
2017-06-13 15:59:42 +02:00
2017-04-28 09:26:42 +02:00
return result
2017-05-25 10:11:07 +02:00
def _credit(self):
credit = super(Invoice, self)._credit()
2017-06-22 23:36:46 +02:00
for field in _SII_INVOICE_KEYS:
setattr(credit, field, getattr(self, field))
2017-05-25 10:11:07 +02:00
credit.sii_operation_key = 'R4'
return credit
2017-07-04 11:44:44 +02:00
def _set_sii_keys(self):
tax = None
for t in self.taxes:
if t.tax.sii_book_key:
2018-07-08 23:09:34 +02:00
tax = t.tax
break
2017-07-04 11:44:44 +02:00
if not tax:
return
for field in _SII_INVOICE_KEYS:
2018-07-08 23:09:34 +02:00
setattr(self, field, getattr(tax, field))
2017-07-04 11:44:44 +02:00
2017-06-22 23:36:46 +02:00
@fields.depends(*_SII_INVOICE_KEYS)
def _on_change_lines_taxes(self):
super(Invoice, self)._on_change_lines_taxes()
2017-06-22 23:36:46 +02:00
for field in _SII_INVOICE_KEYS:
if getattr(self, field):
return
2017-07-04 11:44:44 +02:00
self._set_sii_keys()
@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)
2017-07-04 11:44:44 +02:00
@classmethod
@ModelView.button
def reset_sii_keys(cls, records):
to_write = []
for record in records:
record._set_sii_keys()
record.sii_operation_key = ('R1'
if record.untaxed_amount < Decimal('0.0') else 'F1')
2017-07-04 11:44:44 +02:00
to_write.extend(([record], record._save_values))
if to_write:
cls.write(*to_write)
@classmethod
def process(cls, invoices):
super(Invoice, cls).process(invoices)
invoices_sii = ''
for invoice in invoices:
if invoice.state != 'draft':
continue
if invoice.sii_state:
invoices_sii += '\n%s: %s' % (invoice.number, invoice.sii_state)
if invoices_sii:
warning_name = 'invoices_sii_report_%s' % ",".join([str(x.id) for x in invoices])
cls.raise_user_warning(warning_name, 'invoices_sii', invoices_sii)
2018-10-11 15:32:09 +02:00
class Sale(metaclass=PoolMeta):
__name__ = 'sale.sale'
def create_invoice(self):
invoice = super(Sale, self).create_invoice()
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
2018-10-11 15:32:09 +02:00
class Purchase(metaclass=PoolMeta):
__name__ = 'purchase.purchase'
def create_invoice(self):
invoice = super(Purchase, self).create_invoice()
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