diff --git a/book.py b/book.py
index 206e839..56a4d35 100644
--- a/book.py
+++ b/book.py
@@ -139,7 +139,7 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
states={
'invisible': ~Bool(Eval('company_currency')),
}, depends=['company_currency_digits', 'company_currency']),
- 'get_balance_cashbook')
+ 'get_balance_cashbook', searcher='search_balance')
company_currency = fields.Function(fields.Many2One(
readonly=True,
string='Company Currency', states={'invisible': True},
@@ -346,44 +346,92 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
)
return (query, tab_line)
+ @classmethod
+ def work_order_balance(cls, tables, field_name):
+ """ get order-query
+ """
+ pool = Pool()
+ Book2 = pool.get('cashbook.book')
+ ValueStore = pool.get('cashbook.values')
+ context = Transaction().context
+
+ query_date = context.get('date', None)
+ table, _ = tables[None]
+ if query_date is not None:
+ if field_name == 'balance_ref':
+ raise UserError(gettext(
+ 'cashbook.msg_nosearch_with_date',
+ fname=field_name, model=Book2.__name__))
+
+ (tab_book, tab2) = Book2.get_balance_of_cashbook_sql()
+ query = tab_book.select(
+ getattr(tab_book, field_name),
+ where=tab_book.cashbook == table.id)
+ return [query]
+ else:
+ tab_val = ValueStore.__table__()
+ tab_book = Book2.__table__()
+
+ query = tab_book.join(
+ tab_val,
+ condition=(
+ tab_book.id == tab_val.cashbook) & (
+ tab_val.field_name == field_name),
+ ).select(
+ tab_val.numvalue,
+ where=tab_book.id == table.id)
+ return [query]
+
@staticmethod
def order_balance(tables):
""" order by balance
"""
Book2 = Pool().get('cashbook.book')
- (tab_book, tab2) = Book2.get_balance_of_cashbook_sql()
- table, _ = tables[None]
-
- query = tab_book.select(
- tab_book.balance,
- where=tab_book.cashbook == table.id)
- return [query]
+ return Book2.work_order_balance(tables, 'balance')
@staticmethod
def order_balance_all(tables):
""" order by balance-all
"""
Book2 = Pool().get('cashbook.book')
- (tab_book, tab2) = Book2.get_balance_of_cashbook_sql()
- table, _ = tables[None]
+ return Book2.work_order_balance(tables, 'balance_all')
- query = tab_book.select(
- tab_book.balance_all,
- where=tab_book.cashbook == table.id)
- return [query]
+ @staticmethod
+ def order_balance_ref(tables):
+ """ order by balance-all
+ """
+ Book2 = Pool().get('cashbook.book')
+ return Book2.work_order_balance(tables, 'balance_ref')
@classmethod
def search_balance(cls, name, clause):
""" search in 'balance'
"""
- (tab_line, tab2) = cls.get_balance_of_cashbook_sql()
+ ValueStore = Pool().get('cashbook.values')
Operator = fields.SQL_OPERATORS[clause[1]]
+ context = Transaction().context
- query = tab_line.select(
- tab_line.cashbook,
- where=Operator(
- getattr(tab_line, name), clause[2]))
- return [('id', 'in', query)]
+ query_date = context.get('date', None)
+ if query_date is not None:
+
+ if name == 'balance_ref':
+ raise UserError(gettext(
+ 'cashbook.msg_nosearch_with_date',
+ fname=name, model=cls.__name__))
+
+ (tab_line, tab2) = cls.get_balance_of_cashbook_sql()
+ query = tab_line.select(
+ tab_line.cashbook,
+ where=Operator(
+ getattr(tab_line, name), clause[2]))
+ return [('id', 'in', query)]
+ else:
+ value_query = ValueStore.search([
+ ('field_name', '=', clause[0]),
+ ('numvalue',) + tuple(clause[1:]),
+ ],
+ query=True)
+ return [('value_store', 'in', value_query)]
@classmethod
def valuestore_delete_records(cls, records):
diff --git a/locale/de.po b/locale/de.po
index c441d5b..0e30415 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -168,7 +168,11 @@ msgstr "Allgemein"
msgctxt "model:ir.message,text:msg_value_exists_in_store"
msgid "The value already exists for the record."
-msgstr "Der Wert existiert für den Datensatz bereits. "
+msgstr "Der Wert existiert für den Datensatz bereits."
+
+msgctxt "model:ir.message,text:msg_nosearch_with_date"
+msgid "Search with 'date' no allowed for field '%(fname)s' on model '%(model)s'."
+msgstr "Suche mit 'date' nicht erlaubt für Feld '%(fname)s' auf Modell '%(model)s'."
#############
diff --git a/locale/en.po b/locale/en.po
index 0a45ad4..7b2424f 100644
--- a/locale/en.po
+++ b/locale/en.po
@@ -162,6 +162,10 @@ msgctxt "model:ir.message,text:msg_value_exists_in_store"
msgid "The value already exists for the record."
msgstr "The value already exists for the record."
+msgctxt "model:ir.message,text:msg_nosearch_with_date"
+msgid "Search with 'date' no allowed for field '%(fname)s' on model '%(model)s'."
+msgstr "Search with 'date' no allowed for field '%(fname)s' on model '%(model)s'."
+
msgctxt "model:res.group,name:group_cashbook"
msgid "Cashbook"
msgstr "Cashbook"
diff --git a/message.xml b/message.xml
index ff2d735..57a9823 100644
--- a/message.xml
+++ b/message.xml
@@ -122,6 +122,9 @@ full copyright notices and license terms. -->
The value already exists for the record.
+
+ Search with 'date' no allowed for field '%(fname)s' on model '%(model)s'.
+
diff --git a/tests/book.py b/tests/book.py
index 8678173..fa7d028 100644
--- a/tests/book.py
+++ b/tests/book.py
@@ -307,6 +307,10 @@ class BookTestCase(object):
Book.search_count([('balance_all', '<', Decimal('5.0'))]),
0)
+ self.assertEqual(
+ Book.search_count([('balance_ref', '<', Decimal('5.0'))]),
+ 0)
+
@with_transaction()
def test_book_deny_btype_set_none(self):
""" create cashbook, add lines,
diff --git a/tests/valuestore.py b/tests/valuestore.py
index fed00ab..d6c800c 100644
--- a/tests/valuestore.py
+++ b/tests/valuestore.py
@@ -539,6 +539,194 @@ class ValuestoreTestCase(object):
values[8].rec_name,
'[Lev 0/Lev 1b | 0.00 € | Open]|balance_ref|0.00|2')
+ @with_transaction()
+ def test_valstore_search_sort_books(self):
+ """ create cashbooks add lines, search/sort
+ with and w/o 'date' in context
+ """
+ pool = Pool()
+ Book = pool.get('cashbook.book')
+ Line = pool.get('cashbook.line')
+
+ types = self.prep_type()
+ company = self.prep_company()
+ (usd, euro) = self.prep_2nd_currency(company)
+ self.assertEqual(company.currency.rec_name, 'Euro')
+
+ with Transaction().set_context({'company': company.id}):
+ category = self.prep_category(cattype='in')
+ party = self.prep_party()
+ books = Book.create([{
+ 'name': 'Cashbook 1',
+ 'btype': types.id,
+ 'company': company.id,
+ 'currency': usd.id,
+ 'number_sequ': self.prep_sequence().id,
+ 'start_date': date(2022, 5, 1),
+ 'lines': [('create', [{
+ 'date': date(2022, 5, 1),
+ 'description': '10 US$',
+ 'category': category.id,
+ 'bookingtype': 'in',
+ 'amount': Decimal('10.0'),
+ 'party': party.id,
+ }])]}, {
+ 'name': 'Cashbook 2',
+ 'btype': types.id,
+ 'company': company.id,
+ 'currency': euro.id,
+ 'number_sequ': self.prep_sequence().id,
+ 'start_date': date(2022, 5, 1),
+ }, {
+ 'name': 'Cashbook 3',
+ 'btype': types.id,
+ 'company': company.id,
+ 'currency': euro.id,
+ 'number_sequ': self.prep_sequence().id,
+ 'start_date': date(2022, 5, 1),
+ }])
+ self.assertEqual(len(books), 3)
+ self.assertEqual(books[0].rec_name, 'Cashbook 1 | 10.00 usd | Open')
+ self.assertEqual(books[1].rec_name, 'Cashbook 2 | 0.00 € | Open')
+ self.assertEqual(books[2].rec_name, 'Cashbook 3 | 0.00 € | Open')
+
+ Line.create([{
+ 'cashbook': books[1].id,
+ 'bookingtype': 'in',
+ 'amount': Decimal('5.0'),
+ 'date': date(2022, 5, 6),
+ 'description': '5€ in',
+ 'category': category.id,
+ }, {
+ 'cashbook': books[2].id,
+ 'bookingtype': 'in',
+ 'amount': Decimal('6.0'),
+ 'date': date(2022, 5, 7),
+ 'description': '6€ in',
+ 'category': category.id,
+ }])
+
+ # no 'date' in context, using stored values
+ # workers not yet processed
+ books = Book.search([], order=[('name', 'ASC')])
+ self.assertEqual(len(books), 3)
+ self.assertEqual(books[0].rec_name, 'Cashbook 1 | 10.00 usd | Open')
+ self.assertEqual(books[1].rec_name, 'Cashbook 2 | 0.00 € | Open')
+ self.assertEqual(books[2].rec_name, 'Cashbook 3 | 0.00 € | Open')
+
+ self.assertEqual(
+ Book.search_count([('balance', '=', Decimal('0.0'))]),
+ 2)
+ self.assertEqual(
+ Book.search_count([('balance_all', '=', Decimal('0.0'))]),
+ 2)
+ self.assertEqual(
+ Book.search_count([('balance_ref', '=', Decimal('0.0'))]),
+ 2)
+
+ # check sorting - using stored values
+ books = Book.search([], order=[
+ ('balance_all', 'DESC'), ('name', 'ASC')])
+ self.assertEqual(len(books), 3)
+ self.assertEqual(books[0].rec_name, 'Cashbook 1 | 10.00 usd | Open')
+ self.assertEqual(books[1].rec_name, 'Cashbook 2 | 0.00 € | Open')
+ self.assertEqual(books[2].rec_name, 'Cashbook 3 | 0.00 € | Open')
+
+ # search again with 'date' - using computed values
+ with Transaction().set_context({'date': date(2022, 5, 6)}):
+ self.assertEqual(
+ Book.search_count([('balance', '=', Decimal('5.0'))]),
+ 1)
+ self.assertEqual(
+ Book.search_count([
+ ('balance', '>=', Decimal('5.0')),
+ ('balance', '<', Decimal('9.0')),
+ ]),
+ 1)
+ self.assertEqual(
+ Book.search_count([
+ ('balance_all', '>=', Decimal('5.0'))]),
+ 3)
+ self.assertRaisesRegex(
+ UserError,
+ "Search with 'date' no allowed for field " +
+ "'balance_ref' on model 'cashbook.book'.",
+ Book.search_count,
+ [('balance_ref', '=', Decimal('0.0'))])
+
+ self.assertRaisesRegex(
+ UserError,
+ "Search with 'date' no allowed for field " +
+ "'balance_ref' on model 'cashbook.book'.",
+ Book.search,
+ [], order=[('balance_ref', 'ASC')])
+
+ # check sorting - using computed values
+ books = Book.search([], order=[
+ ('balance_all', 'DESC'),
+ ('name', 'ASC'),
+ ('balance', 'ASC')])
+ self.assertEqual(len(books), 3)
+ self.assertEqual(
+ books[0].rec_name, 'Cashbook 1 | 10.00 usd | Open')
+ self.assertEqual(
+ books[1].rec_name, 'Cashbook 3 | 0.00 € | Open')
+ self.assertEqual(books[1].balance_all, Decimal('6.0'))
+ self.assertEqual(
+ books[2].rec_name, 'Cashbook 2 | 5.00 € | Open')
+
+ with Transaction().set_context({'date': date(2022, 5, 7)}):
+ self.assertEqual(
+ Book.search_count([('balance', '=', Decimal('5.0'))]),
+ 1)
+ self.assertEqual(
+ Book.search_count([
+ ('balance', '>=', Decimal('5.0')),
+ ('balance', '<', Decimal('9.0')),
+ ]),
+ 2)
+
+ # run workers
+ self.prep_valstore_run_worker()
+
+ # check stored values - no 'date' in context
+ books = Book.search([], order=[('name', 'ASC')])
+ self.assertEqual(len(books), 3)
+ self.assertEqual(books[0].rec_name, 'Cashbook 1 | 10.00 usd | Open')
+ self.assertEqual(books[1].rec_name, 'Cashbook 2 | 5.00 € | Open')
+ self.assertEqual(books[2].rec_name, 'Cashbook 3 | 6.00 € | Open')
+
+ # check sorting - using stored values
+ # run most sorters
+ books = Book.search([], order=[
+ ('balance_all', 'DESC'),
+ ('name', 'ASC'),
+ ('balance', 'ASC'),
+ ('balance_ref', 'ASC')])
+ self.assertEqual(len(books), 3)
+ self.assertEqual(books[0].rec_name, 'Cashbook 1 | 10.00 usd | Open')
+ self.assertEqual(books[1].rec_name, 'Cashbook 3 | 6.00 € | Open')
+ self.assertEqual(books[2].rec_name, 'Cashbook 2 | 5.00 € | Open')
+
+ self.assertEqual(
+ Book.search_count([('balance', '=', Decimal('0.0'))]),
+ 0)
+ self.assertEqual(
+ Book.search_count([('balance', '=', Decimal('5.0'))]),
+ 1)
+ self.assertEqual(
+ Book.search_count([('balance', '=', Decimal('6.0'))]),
+ 1)
+ self.assertEqual(
+ Book.search_count([
+ ('balance', '>=', Decimal('5.0')),
+ ('balance', '<', Decimal('9.0')),
+ ]),
+ 2)
+ self.assertEqual(
+ Book.search_count([('balance_ref', '=', Decimal('6.0'))]),
+ 1)
+
@with_transaction()
def test_valstore_maintain_values(self):
""" create cashbook, check maintenance -