Files
Cédric Krier 5310b00496 Remove grouped_slice per IN_MAX
The usage of ``grouped_slice`` without size is deprecated since `=
ANY(ARRAY[%s])` is used for PostgreSQL and SQLite is used only for tests.

The ``Database.IN_MAX`` is replaced by ``backend.MAX_QUERY_PARAMS`` which is a
more accurate limit of the backend.
The SQLite limits is indeed SQLITE_MAX_EXPR_DEPTH so we use a empirical value.
2026-03-22 21:05:26 +01:00

98 lines
3.5 KiB
Python

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from collections import defaultdict
from sql import Null
from sql.conditionals import Greatest
from sql.functions import CurrentTimestamp
from trytond import backend
from trytond.model import ModelView, Workflow, fields
from trytond.pool import Pool, PoolMeta
from trytond.tools import sqlite_apply_types
from trytond.transaction import Transaction
class Invoice(metaclass=PoolMeta):
__name__ = 'account.invoice'
numbered_at = fields.Timestamp("Numbered At")
history_datetime = fields.Function(
fields.Timestamp("History DateTime"),
'get_history_datetime')
@classmethod
def __setup__(cls):
super().__setup__()
cls._check_modify_exclude.add('numbered_at')
cls.party.datetime_field = 'history_datetime'
cls.party_tax_identifier.datetime_field = 'history_datetime'
cls.invoice_address.datetime_field = 'history_datetime'
cls.payment_term.datetime_field = 'history_datetime'
@classmethod
def get_history_datetime(cls, invoices, name):
pool = Pool()
Party = pool.get('party.party')
Address = pool.get('party.address')
Identifier = pool.get('party.identifier')
PaymentTerm = pool.get('account.invoice.payment_term')
table = cls.__table__()
party = Party.__table__()
address = Address.__table__()
identifier = Identifier.__table__()
payment_term = PaymentTerm.__table__()
cursor = Transaction().connection.cursor()
datetimes = defaultdict(lambda: None)
query = (table
.join(party, condition=table.party == party.id)
.join(address, condition=table.invoice_address == address.id)
.join(identifier, 'LEFT',
condition=table.party_tax_identifier == identifier.id)
.join(payment_term, 'LEFT',
condition=table.payment_term == payment_term.id)
.select(table.id,
Greatest(table.numbered_at, party.create_date,
address.create_date, identifier.create_date,
payment_term.create_date).as_('history_datetime'),
where=fields.SQL_OPERATORS['in'](table.id, map(int, invoices))
& (table.numbered_at != Null)
& (table.state.in_(cls._history_states()))))
if backend.name == 'sqlite':
sqlite_apply_types(query, [None, 'DATETIME'])
cursor.execute(*query)
datetimes.update(cursor)
return datetimes
@classmethod
def _history_states(cls):
return ['posted', 'paid', 'cancelled']
@classmethod
def set_number(cls, invoices):
numbered = [i for i in invoices if not i.number or not i.numbered_at]
super().set_number(invoices)
if numbered:
cls.write(numbered, {
'numbered_at': CurrentTimestamp(),
})
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, invoices):
super().draft(invoices)
cls.write(invoices, {
'numbered_at': None,
})
@classmethod
def copy(cls, invoices, default=None):
if default is None:
default = {}
else:
default = default.copy()
default.setdefault('numbered_at', None)
return super().copy(invoices, default=default)