Compare commits

...

17 commits

Author SHA1 Message Date
Frederik Jaeckel
a895d2a0de Version 6.8.32 2023-12-06 21:18:49 +01:00
Frederik Jaeckel
57dea9a65d merge... 2023-12-06 21:15:16 +01:00
Frederik Jaeckel
6008532475 columns optional 2023-12-06 20:20:13 +01:00
Frederik Jaeckel
d2ceb5419e Etikett ver 6.8.31 zum Änderungssatz 78475f7c20a0 hinzugefügt 2023-11-30 13:39:17 +01:00
Frederik Jaeckel
04acb27b60 Version 6.8.31 2023-11-30 13:39:05 +01:00
Frederik Jaeckel
aa7af9844b ir.rule: Eval('user').get('groups') --> Eval('groups') 2023-11-30 13:14:54 +01:00
Frederik Jaeckel
018e265cff merge... 2023-11-30 13:33:46 +01:00
Frederik Jaeckel
9ee924f0d8 formatting, indexes optimized 2023-11-29 15:19:38 +01:00
Frederik Jaeckel
510357a13c Etikett ver 6.8.30 zum Änderungssatz 6b2cd4807eca hinzugefügt 2023-07-25 21:14:47 +02:00
Frederik Jaeckel
b237981a9b Version 6.8.30 2023-07-25 21:14:31 +02:00
Frederik Jaeckel
aac6930999 splitline: add tests 2023-07-25 21:11:32 +02:00
Frederik Jaeckel
7a4fd94981 optimize search-queries, line: fix state-selection 2023-07-24 17:31:34 +02:00
Frederik Jaeckel
6550baa468 Etikett ver 6.8.29 zum Änderungssatz eca41028d0c7 hinzugefügt 2023-07-24 16:35:28 +02:00
Frederik Jaeckel
e017f20df4 Version 6.8.29 2023-07-24 16:35:19 +02:00
Frederik Jaeckel
3a0df50d52 line, type: fix index 2023-06-08 17:08:47 +02:00
Frederik Jaeckel
eaa502a626 Etikett ver 6.8.28 zum Änderungssatz 5fae2c803879 hinzugefügt 2023-06-05 20:23:11 +02:00
Frederik Jaeckel
7769f5f14a Version 6.8.28 2023-06-05 20:22:53 +02:00
27 changed files with 224 additions and 185 deletions

View file

@ -9,7 +9,7 @@ pip install mds-cashbook
Requires Requires
======== ========
- Tryton 6.0 - Tryton 6.8
How to How to
====== ======
@ -153,6 +153,22 @@ currency are converted into the display currency of the parent cash book.
Changes Changes
======= =======
*6.0.0 - 05.08.2022* *6.8.32 - 06.12.2023*
- columns optional
*6.8.31 - 30.11.2023*
- optimized ir.rule
*6.8.30 - 25.07.2023*
- updt: optimize code, add tests
*6.8.29 - 24.07.2023*
- fix: type of indexes
*6.8.28 - 05.06.2023*
- init - init

17
book.py
View file

@ -74,8 +74,7 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
states={ states={
'readonly': Or( 'readonly': Or(
STATES['readonly'], STATES['readonly'],
Len(Eval('lines')) > 0, Len(Eval('lines')) > 0),
),
}, depends=DEPENDS+['lines']) }, depends=DEPENDS+['lines'])
feature = fields.Function(fields.Char( feature = fields.Function(fields.Char(
string='Feature', readonly=True, string='Feature', readonly=True,
@ -124,8 +123,7 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
states={ states={
'readonly': Or( 'readonly': Or(
STATES2['readonly'], STATES2['readonly'],
Len(Eval('lines')) > 0, Len(Eval('lines')) > 0),
),
'invisible': STATES2['invisible'], 'invisible': STATES2['invisible'],
'required': ~STATES2['invisible'], 'required': ~STATES2['invisible'],
}, depends=DEPENDS2+['lines']) }, depends=DEPENDS2+['lines'])
@ -165,8 +163,7 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
states={ states={
'readonly': Or( 'readonly': Or(
STATES2['readonly'], STATES2['readonly'],
Len(Eval('lines', [])) > 0, Len(Eval('lines', [])) > 0),
),
}, depends=DEPENDS2+['lines']) }, depends=DEPENDS2+['lines'])
currency_digits = fields.Function(fields.Integer( currency_digits = fields.Function(fields.Integer(
string='Currency Digits', string='Currency Digits',
@ -202,9 +199,6 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
Index( Index(
t, t,
(t.btype, Index.Equality())), (t.btype, Index.Equality())),
Index(
t,
(t.parent, Index.Equality())),
Index( Index(
t, t,
(t.company, Index.Equality())), (t.company, Index.Equality())),
@ -396,8 +390,7 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
query = tab_line.select( query = tab_line.select(
tab_line.cashbook, tab_line.cashbook,
where=Operator( where=Operator(
getattr(tab_line, name), clause[2]), getattr(tab_line, name), clause[2]))
)
return [('id', 'in', query)] return [('id', 'in', query)]
@classmethod @classmethod
@ -574,7 +567,7 @@ class Book(tree(separator='/'), Workflow, ModelSQL, ModelView):
'defbook', 'book1', 'book2', 'book3', 'defbook', 'book1', 'book2', 'book3',
'book4', 'book5']: 'book4', 'book5']:
cfg1 = ConfigUser.search([ cfg1 = ConfigUser.search([
('iduser.id', '=', book.owner.id), ('iduser', '=', book.owner.id),
('%s.id' % x, '=', book.id)]) ('%s.id' % x, '=', book.id)])
if len(cfg1) > 0: if len(cfg1) > 0:
to_write_config.extend([cfg1, {x: None}]) to_write_config.extend([cfg1, {x: None}])

View file

@ -143,8 +143,8 @@ full copyright notices and license terms. -->
</record> </record>
<record model="ir.rule" id="rg_book_read_nonowner-1"> <record model="ir.rule" id="rg_book_read_nonowner-1">
<field name="domain" eval="['OR', <field name="domain" eval="['OR',
('observer.id', 'in', Eval('user', {}).get('groups', [])), ('observer.id', 'in', Eval('groups', [])),
('reviewer.id', 'in', Eval('user', {}).get('groups', [])), ('reviewer.id', 'in', Eval('groups', [])),
]" pyson="1"/> ]" pyson="1"/>
<field name="rule_group" ref="rg_book_read_nonowner"/> <field name="rule_group" ref="rg_book_read_nonowner"/>
</record> </record>

View file

@ -11,6 +11,7 @@ from trytond.exceptions import UserError
from trytond.i18n import gettext from trytond.i18n import gettext
from sql.operators import Equal from sql.operators import Equal
from .model import order_name_hierarchical from .model import order_name_hierarchical
from .const import DEF_NONE
sel_categorytype = [ sel_categorytype = [
@ -70,7 +71,7 @@ class Category(tree(separator='/'), ModelSQL, ModelView):
t, t,
(t.name, Equal), (t.name, Equal),
(t.cattype, Equal), (t.cattype, Equal),
where=(t.parent == None)), where=(t.parent == DEF_NONE)),
'cashbook.msg_category_name_unique'), 'cashbook.msg_category_name_unique'),
]) ])

View file

@ -17,7 +17,8 @@ field_done = fields.Boolean(
help='Show cashbook lines in Done-state.') help='Show cashbook lines in Done-state.')
field_catnamelong = fields.Boolean( field_catnamelong = fields.Boolean(
string='Category: Show long name', string='Category: Show long name',
help='Shows the long name of the category in the Category field of a cash book line.') help='Shows the long name of the category in the Category ' +
'field of a cash book line.')
class Configuration(ModelSingleton, ModelSQL, ModelView, UserMultiValueMixin): class Configuration(ModelSingleton, ModelSQL, ModelView, UserMultiValueMixin):
@ -29,60 +30,47 @@ class Configuration(ModelSingleton, ModelSQL, ModelView, UserMultiValueMixin):
domain=[ domain=[
If(Eval('date_to') & Eval('date_from'), If(Eval('date_to') & Eval('date_from'),
('date_from', '<=', Eval('date_to')), ('date_from', '<=', Eval('date_to')),
()), ())]))
]))
date_to = fields.MultiValue(fields.Date( date_to = fields.MultiValue(fields.Date(
string='End Date', depends=['date_from'], string='End Date', depends=['date_from'],
domain=[ domain=[
If(Eval('date_to') & Eval('date_from'), If(Eval('date_to') & Eval('date_from'),
('date_from', '<=', Eval('date_to')), ('date_from', '<=', Eval('date_to')),
()), ())]))
]))
checked = fields.MultiValue(field_checked) checked = fields.MultiValue(field_checked)
done = fields.MultiValue(field_done) done = fields.MultiValue(field_done)
catnamelong = fields.MultiValue(field_catnamelong) catnamelong = fields.MultiValue(field_catnamelong)
defbook = fields.MultiValue(fields.Many2One( defbook = fields.MultiValue(fields.Many2One(
string='Default Cashbook', string='Default Cashbook',
help='The default cashbook is selected when you open the booking wizard.', help='The default cashbook is selected when you open ' +
'the booking wizard.',
model_name='cashbook.book', ondelete='SET NULL', model_name='cashbook.book', ondelete='SET NULL',
domain=[ domain=[('btype', '!=', None), ('state', '=', 'open')]))
('btype', '!=', None), ('state', '=', 'open'),
]))
book1 = fields.MultiValue(fields.Many2One( book1 = fields.MultiValue(fields.Many2One(
string='Cashbook 1', string='Cashbook 1',
help='Cash book available in selection dialog.', help='Cash book available in selection dialog.',
model_name='cashbook.book', ondelete='SET NULL', model_name='cashbook.book', ondelete='SET NULL',
domain=[ domain=[('btype', '!=', None), ('state', '=', 'open')]))
('btype', '!=', None), ('state', '=', 'open'),
]))
book2 = fields.MultiValue(fields.Many2One( book2 = fields.MultiValue(fields.Many2One(
string='Cashbook 2', string='Cashbook 2',
help='Cash book available in selection dialog.', help='Cash book available in selection dialog.',
model_name='cashbook.book', ondelete='SET NULL', model_name='cashbook.book', ondelete='SET NULL',
domain=[ domain=[('btype', '!=', None), ('state', '=', 'open')]))
('btype', '!=', None), ('state', '=', 'open'),
]))
book3 = fields.MultiValue(fields.Many2One( book3 = fields.MultiValue(fields.Many2One(
string='Cashbook 3', string='Cashbook 3',
help='Cash book available in selection dialog.', help='Cash book available in selection dialog.',
model_name='cashbook.book', ondelete='SET NULL', model_name='cashbook.book', ondelete='SET NULL',
domain=[ domain=[('btype', '!=', None), ('state', '=', 'open')]))
('btype', '!=', None), ('state', '=', 'open'),
]))
book4 = fields.MultiValue(fields.Many2One( book4 = fields.MultiValue(fields.Many2One(
string='Cashbook 4', string='Cashbook 4',
help='Cash book available in selection dialog.', help='Cash book available in selection dialog.',
model_name='cashbook.book', ondelete='SET NULL', model_name='cashbook.book', ondelete='SET NULL',
domain=[ domain=[('btype', '!=', None), ('state', '=', 'open')]))
('btype', '!=', None), ('state', '=', 'open'),
]))
book5 = fields.MultiValue(fields.Many2One( book5 = fields.MultiValue(fields.Many2One(
string='Cashbook 5', string='Cashbook 5',
help='Cash book available in selection dialog.', help='Cash book available in selection dialog.',
model_name='cashbook.book', ondelete='SET NULL', model_name='cashbook.book', ondelete='SET NULL',
domain=[ domain=[('btype', '!=', None), ('state', '=', 'open')]))
('btype', '!=', None), ('state', '=', 'open'),
]))
@classmethod @classmethod
def multivalue_model(cls, field): def multivalue_model(cls, field):
@ -121,21 +109,20 @@ class UserConfiguration(ModelSQL, UserValueMixin):
domain=[ domain=[
If(Eval('date_to') & Eval('date_from'), If(Eval('date_to') & Eval('date_from'),
('date_from', '<=', Eval('date_to')), ('date_from', '<=', Eval('date_to')),
()), ())])
])
date_to = fields.Date( date_to = fields.Date(
string='End Date', depends=['date_from'], string='End Date', depends=['date_from'],
domain=[ domain=[
If(Eval('date_to') & Eval('date_from'), If(Eval('date_to') & Eval('date_from'),
('date_from', '<=', Eval('date_to')), ('date_from', '<=', Eval('date_to')),
()), ())])
])
checked = field_checked checked = field_checked
done = field_done done = field_done
catnamelong = field_catnamelong catnamelong = field_catnamelong
defbook = fields.Many2One( defbook = fields.Many2One(
string='Default Cashbook', string='Default Cashbook',
help='The default cashbook is selected when you open the booking wizard.', help='The default cashbook is selected when you open ' +
'the booking wizard.',
model_name='cashbook.book', ondelete='SET NULL', model_name='cashbook.book', ondelete='SET NULL',
domain=[ domain=[
('btype', '!=', None), ('btype', '!=', None),

8
const.py Normal file
View file

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# This file is part of the cashbook-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
DEF_NONE = None

View file

@ -42,7 +42,8 @@ class CurrencyRate(metaclass=PoolMeta):
MemCache = Pool().get('cashbook.memcache') MemCache = Pool().get('cashbook.memcache')
for record in records: for record in records:
MemCache.record_update(CACHEKEY_CURRENCY % record.currency.id, None) MemCache.record_update(
CACHEKEY_CURRENCY % record.currency.id, None)
super(CurrencyRate, cls).delete(records) super(CurrencyRate, cls).delete(records)
# end # end

59
line.py
View file

@ -16,6 +16,7 @@ from sql.functions import DatePart
from sql.conditionals import Case from sql.conditionals import Case
from .book import sel_state_book from .book import sel_state_book
from .mixin import SecondCurrencyMixin, MemCacheIndexMx from .mixin import SecondCurrencyMixin, MemCacheIndexMx
from .const import DEF_NONE
sel_payee = [ sel_payee = [
@ -23,7 +24,7 @@ sel_payee = [
('party.party', 'Party') ('party.party', 'Party')
] ]
sel_linetype = [ sel_linestate = [
('edit', 'Edit'), ('edit', 'Edit'),
('check', 'Checked'), ('check', 'Checked'),
('recon', 'Reconciled'), ('recon', 'Reconciled'),
@ -48,7 +49,9 @@ STATES = {
DEPENDS = ['state', 'state_cashbook'] DEPENDS = ['state', 'state_cashbook']
class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView): class Line(
SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL,
ModelView):
'Cashbook Line' 'Cashbook Line'
__name__ = 'cashbook.line' __name__ = 'cashbook.line'
@ -75,8 +78,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
states={ states={
'readonly': Or( 'readonly': Or(
STATES['readonly'], STATES['readonly'],
Bool(Eval('bookingtype')) == False, ~Bool(Eval('bookingtype'))),
),
'required': Eval('bookingtype', '').in_(['in', 'out']), 'required': Eval('bookingtype', '').in_(['in', 'out']),
'invisible': ~Eval('bookingtype', '').in_(['in', 'out']), 'invisible': ~Eval('bookingtype', '').in_(['in', 'out']),
}, depends=DEPENDS+['bookingtype'], }, depends=DEPENDS+['bookingtype'],
@ -161,7 +163,8 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
splitlines = fields.One2Many( splitlines = fields.One2Many(
string='Split booking lines', string='Split booking lines',
model_name='cashbook.split', model_name='cashbook.split',
help='Rows with different categories form the total sum of the booking', help='Rows with different categories form the total ' +
'sum of the booking',
states={ states={
'invisible': ~Eval('bookingtype' '').in_(['spin', 'spout']), 'invisible': ~Eval('bookingtype' '').in_(['spin', 'spout']),
'readonly': Or( 'readonly': Or(
@ -197,7 +200,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
state = fields.Selection( state = fields.Selection(
string='State', required=True, readonly=True, string='State', required=True, readonly=True,
selection=sel_linetype) selection=sel_linestate)
state_string = state.translated('state') state_string = state.translated('state')
state_cashbook = fields.Function(fields.Selection( state_cashbook = fields.Function(fields.Selection(
string='State of Cashbook', string='State of Cashbook',
@ -225,9 +228,6 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
t = cls.__table__() t = cls.__table__()
cls._sql_indexes.update({ cls._sql_indexes.update({
Index(
t,
(t.cashbook, Index.Equality())),
Index( Index(
t, t,
(t.date, Index.Range(order='ASC'))), (t.date, Index.Range(order='ASC'))),
@ -245,7 +245,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
(t.state, Index.Equality())), (t.state, Index.Equality())),
Index( Index(
t, t,
(t.reference, Index.Range())), (t.reference, Index.Equality())),
}) })
cls._sql_constraints.extend([ cls._sql_constraints.extend([
('state_val2', ('state_val2',
@ -308,7 +308,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
).select( ).select(
tab_line.id, tab_line.id,
where=tab_line.bookingtype.in_(['mvin', 'mvout']) & where=tab_line.bookingtype.in_(['mvin', 'mvout']) &
(tab_line.amount_2nd_currency == None) & (tab_line.amount_2nd_currency == DEF_NONE) &
(tab_book.currency != tab_book2.currency) (tab_book.currency != tab_book2.currency)
) )
lines = Line2.search([('id', 'in', query)]) lines = Line2.search([('id', 'in', query)])
@ -344,7 +344,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
for line in lines: for line in lines:
if line.reference: if line.reference:
if Transaction().context.get( if Transaction().context.get(
'line.allow.wfedit', False) == False: 'line.allow.wfedit', False) is False:
raise UserError(gettext( raise UserError(gettext(
'cashbook.msg_line_denywf_by_reference', 'cashbook.msg_line_denywf_by_reference',
recname=line.reference.rec_name, recname=line.reference.rec_name,
@ -375,7 +375,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
# allow cashbook-line at range-limits # allow cashbook-line at range-limits
if Recon.search_count([ if Recon.search_count([
('state', 'in', ['check', 'done']), ('state', 'in', ['check', 'done']),
('cashbook.id', '=', line.cashbook.id), ('cashbook', '=', line.cashbook.id),
('date_from', '<', line.date), ('date_from', '<', line.date),
('date_to', '>', line.date)]) > 0: ('date_to', '>', line.date)]) > 0:
raise UserError(gettext( raise UserError(gettext(
@ -386,7 +386,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
# reconciliations exist # reconciliations exist
if Recon.search_count([ if Recon.search_count([
('state', 'in', ['check', 'done']), ('state', 'in', ['check', 'done']),
('cashbook.id', '=', line.cashbook.id), ('cashbook', '=', line.cashbook.id),
['OR', ['OR',
('date_from', '=', line.date), ('date_from', '=', line.date),
('date_to', '=', line.date)]]) > 1: ('date_to', '=', line.date)]]) > 1:
@ -508,19 +508,20 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
""" """
credit = self.credit if self.credit is not None else Decimal('0.0') credit = self.credit if self.credit is not None else Decimal('0.0')
debit = self.debit if self.debit is not None else Decimal('0.0') debit = self.debit if self.debit is not None else Decimal('0.0')
return '%(date)s|%(type)s|%(amount)s %(symbol)s|%(desc)s [%(category)s]' % { return '|'.join([
'date': Report.format_date(self.date), Report.format_date(self.date),
'desc': (self.description or '-')[:40], gettext('cashbook.msg_line_bookingtype_%s' % self.bookingtype),
'%(amount)s %(symbol)s' % {
'amount': Report.format_number( 'amount': Report.format_number(
credit - debit, None, credit - debit, None,
digits=getattr(self.currency, 'digits', 2)), digits=getattr(self.currency, 'digits', 2)),
'symbol': getattr(self.currency, 'symbol', '-'), 'symbol': getattr(self.currency, 'symbol', '-')},
'%(desc)s [%(category)s]' % {
'desc': (self.description or '-')[:40],
'category': self.category_view 'category': self.category_view
if self.bookingtype in ['in', 'out'] if self.bookingtype in ['in', 'out']
else getattr(self.booktransf, 'rec_name', '-'), else getattr(self.booktransf, 'rec_name', '-')},
'type': gettext( ])
'cashbook.msg_line_bookingtype_%s' %
self.bookingtype)}
@staticmethod @staticmethod
def order_state(tables): def order_state(tables):
@ -535,8 +536,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
(tab_line.state == 'edit', 1), (tab_line.state == 'edit', 1),
(tab_line.state.in_(['check', 'recon', 'done']), 0), (tab_line.state.in_(['check', 'recon', 'done']), 0),
else_=2), else_=2),
where=tab_line.id == table.id where=tab_line.id == table.id)
)
return [query] return [query]
@staticmethod @staticmethod
@ -626,7 +626,8 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
if self.bookingtype: if self.bookingtype:
if self.category: if self.category:
if self.bookingtype not in types.get(self.category.cattype, ''): if self.bookingtype not in types.get(
self.category.cattype, ''):
self.category = None self.category = None
if self.bookingtype.startswith('sp'): # split booking if self.bookingtype.startswith('sp'): # split booking
@ -751,7 +752,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
end_value = None end_value = None
recons = Reconciliation.search([ recons = Reconciliation.search([
('cashbook.id', '=', line.cashbook.id), ('cashbook', '=', line.cashbook.id),
('date_to', '<=', line2.date), ('date_to', '<=', line2.date),
('state', '=', 'done'), ('state', '=', 'done'),
], order=[('date_from', 'DESC')], limit=1) ], order=[('date_from', 'DESC')], limit=1)
@ -761,14 +762,14 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
('date', '<=', line2.date), ('date', '<=', line2.date),
['OR', ['OR',
('reconciliation', '=', None), ('reconciliation', '=', None),
('reconciliation.id', '!=', recons[0])], ('reconciliation', '!=', recons[0])],
]) ])
end_value = getattr(recons[0], 'end_%s' % field_name) end_value = getattr(recons[0], 'end_%s' % field_name)
return (query2, end_value) return (query2, end_value)
if line.cashbook: if line.cashbook:
query = [ query = [
('cashbook.id', '=', line.cashbook.id), ('cashbook', '=', line.cashbook.id),
] ]
balance = Decimal('0.0') balance = Decimal('0.0')
@ -778,7 +779,7 @@ class Line(SecondCurrencyMixin, MemCacheIndexMx, Workflow, ModelSQL, ModelView):
if line.reconciliation: if line.reconciliation:
if line.reconciliation.state == 'done': if line.reconciliation.state == 'done':
query.append( query.append(
('reconciliation.id', '=', line.reconciliation.id), ('reconciliation', '=', line.reconciliation.id),
) )
balance = getattr( balance = getattr(
line.reconciliation, 'start_%s' % field_name) line.reconciliation, 'start_%s' % field_name)

View file

@ -146,7 +146,7 @@ full copyright notices and license terms. -->
<record model="ir.rule" id="rg_line_write-1"> <record model="ir.rule" id="rg_line_write-1">
<field name="domain" eval="['OR', <field name="domain" eval="['OR',
('cashbook.owner.id', '=', Eval('user', {}).get('id', -1)), ('cashbook.owner.id', '=', Eval('user', {}).get('id', -1)),
('cashbook.reviewer.id', 'in', Eval('user', {}).get('groups', [])), ('cashbook.reviewer.id', 'in', Eval('groups', [])),
]" pyson="1"/> ]" pyson="1"/>
<field name="rule_group" ref="rg_line_write"/> <field name="rule_group" ref="rg_line_write"/>
</record> </record>
@ -168,7 +168,7 @@ full copyright notices and license terms. -->
</record> </record>
<record model="ir.rule" id="rg_line_read-1"> <record model="ir.rule" id="rg_line_read-1">
<field name="domain" eval="[ <field name="domain" eval="[
('cashbook.observer.id', 'in', Eval('user', {}).get('groups', [])), ('cashbook.observer.id', 'in', Eval('groups', [])),
]" pyson="1"/> ]" pyson="1"/>
<field name="rule_group" ref="rg_line_read"/> <field name="rule_group" ref="rg_line_read"/>
</record> </record>

View file

@ -31,20 +31,19 @@ class SecondCurrencyMixin:
states={ states={
'readonly': Or( 'readonly': Or(
STATES['readonly'], STATES['readonly'],
~Bool(Eval('currency2nd')) ~Bool(Eval('currency2nd'))),
),
'required': Bool(Eval('currency2nd')), 'required': Bool(Eval('currency2nd')),
'invisible': ~Bool(Eval('currency2nd')), 'invisible': ~Bool(Eval('currency2nd')),
}, depends=DEPENDS+['currency2nd_digits', 'currency2nd']) }, depends=DEPENDS+['currency2nd_digits', 'currency2nd'])
rate_2nd_currency = fields.Function(fields.Numeric( rate_2nd_currency = fields.Function(fields.Numeric(
string='Rate', string='Rate',
help='Exchange rate between the currencies of the participating cashbooks.', help='Exchange rate between the currencies of the ' +
'participating cashbooks.',
digits=(rate_decimal * 2, rate_decimal), digits=(rate_decimal * 2, rate_decimal),
states={ states={
'readonly': Or( 'readonly': Or(
STATES['readonly'], STATES['readonly'],
~Bool(Eval('currency2nd')) ~Bool(Eval('currency2nd'))),
),
'required': Bool(Eval('currency2nd')), 'required': Bool(Eval('currency2nd')),
'invisible': ~Bool(Eval('currency2nd')), 'invisible': ~Bool(Eval('currency2nd')),
}, depends=DEPENDS+['currency2nd_digits', 'currency2nd']), }, depends=DEPENDS+['currency2nd_digits', 'currency2nd']),
@ -124,15 +123,13 @@ class SecondCurrencyMixin:
self.amount_2nd_currency = Currency.compute( self.amount_2nd_currency = Currency.compute(
self.currency, self.currency,
self.amount, self.amount,
self.booktransf.currency self.booktransf.currency)
)
if self.amount != Decimal('0.0'): if self.amount != Decimal('0.0'):
self.rate_2nd_currency = \ self.rate_2nd_currency = \
self.amount_2nd_currency / self.amount self.amount_2nd_currency / self.amount
else: else:
self.amount_2nd_currency = self.booktransf.currency.round( self.amount_2nd_currency = self.booktransf.currency.round(
self.amount * self.rate_2nd_currency self.amount * self.rate_2nd_currency)
)
@classmethod @classmethod
def set_rate_2nd_currency(cls, lines, name, value): def set_rate_2nd_currency(cls, lines, name, value):

View file

@ -15,6 +15,8 @@ from sql import With
from sql.functions import Function from sql.functions import Function
from sql.conditionals import Coalesce from sql.conditionals import Coalesce
import copy import copy
from .const import DEF_NONE
if config.get('cashbook', 'memcache', default='yes').lower() \ if config.get('cashbook', 'memcache', default='yes').lower() \
in ['yes', '1', 'true']: in ['yes', '1', 'true']:
@ -269,7 +271,7 @@ def order_name_hierarchical(model_name, tables):
lines = With('id', 'name', 'name_path', recursive=True) lines = With('id', 'name', 'name_path', recursive=True)
lines.query = tab_mod.select( lines.query = tab_mod.select(
tab_mod.id, tab_mod.name, Array(tab_mod.name), tab_mod.id, tab_mod.name, Array(tab_mod.name),
where=tab_mod.parent == None, where=tab_mod.parent == DEF_NONE,
) )
lines.query |= tab_mod2.join( lines.query |= tab_mod2.join(
lines, lines,

View file

@ -183,7 +183,7 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
if Line.search_count([ if Line.search_count([
('date', '>', reconciliation.date_from), ('date', '>', reconciliation.date_from),
('date', '<', reconciliation.date_to), ('date', '<', reconciliation.date_to),
('cashbook.id', '=', reconciliation.cashbook.id), ('cashbook', '=', reconciliation.cashbook.id),
('state', 'not in', ['check', 'recon']), ('state', 'not in', ['check', 'recon']),
]) > 0: ]) > 0:
raise UserError(gettext( raise UserError(gettext(
@ -204,7 +204,8 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
# unlink lines from reconciliation # unlink lines from reconciliation
if len(reconciliation.lines) > 0: if len(reconciliation.lines) > 0:
values['lines'] = [('remove', [x.id for x in reconciliation.lines])] values['lines'] = [
('remove', [x.id for x in reconciliation.lines])]
return values return values
@classmethod @classmethod
@ -224,7 +225,7 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
lines = Line.search([ lines = Line.search([
('date', '>=', reconciliation.date_from), ('date', '>=', reconciliation.date_from),
('date', '<=', reconciliation.date_to), ('date', '<=', reconciliation.date_to),
('cashbook.id', '=', reconciliation.cashbook.id), ('cashbook', '=', reconciliation.cashbook.id),
('reconciliation', '=', None), ('reconciliation', '=', None),
('state', 'in', ['check', 'recon']), ('state', 'in', ['check', 'recon']),
]) ])
@ -315,7 +316,7 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
# deny if there are lines not linked to reconciliation # deny if there are lines not linked to reconciliation
if Line.search_count([ if Line.search_count([
('cashbook.id', '=', reconciliation.cashbook.id), ('cashbook', '=', reconciliation.cashbook.id),
('reconciliation', '=', None), ('reconciliation', '=', None),
['OR', ['OR',
[ # lines inside of date-range [ # lines inside of date-range
@ -339,20 +340,24 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
def get_rec_name(self, name): def get_rec_name(self, name):
""" short + name """ short + name
""" """
return '%(from)s - %(to)s | %(start_amount)s %(symbol)s - %(end_amount)s %(symbol)s [%(num)s]' % { return ' '.join([
'from': Report.format_date(self.date_from, None) Report.format_date(self.date_from, None)
if self.date_from is not None else '-', if self.date_from is not None else '-',
'to': Report.format_date(self.date_to, None) '-',
Report.format_date(self.date_to, None)
if self.date_to is not None else '-', if self.date_to is not None else '-',
'start_amount': Report.format_number( '|',
Report.format_number(
self.start_amount or 0.0, None, self.start_amount or 0.0, None,
digits=getattr(self.currency, 'digits', 2)), digits=getattr(self.currency, 'digits', 2)),
'end_amount': Report.format_number( getattr(self.currency, 'symbol', '-'),
'-',
Report.format_number(
self.end_amount or 0.0, None, self.end_amount or 0.0, None,
digits=getattr(self.currency, 'digits', 2)), digits=getattr(self.currency, 'digits', 2)),
'symbol': getattr(self.currency, 'symbol', '-'), getattr(self.currency, 'symbol', '-'),
'num': len(self.lines), '[%(num)s]' % {'num': len(self.lines)},
} ])
@classmethod @classmethod
def default_date_from(cls): def default_date_from(cls):
@ -405,7 +410,7 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
if self.cashbook: if self.cashbook:
if self.date_from is not None: if self.date_from is not None:
reconciliations = Recon.search([ reconciliations = Recon.search([
('cashbook.id', '=', self.cashbook.id), ('cashbook', '=', self.cashbook.id),
('date_from', '<', self.date_from), ('date_from', '<', self.date_from),
], order=[('date_from', 'DESC')], limit=1) ], order=[('date_from', 'DESC')], limit=1)
if len(reconciliations) > 0: if len(reconciliations) > 0:
@ -457,7 +462,7 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
# set date_from to date_to of predecessor # set date_from to date_to of predecessor
recons = Recon.search([ recons = Recon.search([
('cashbook.id', '=', id_cashbook), ('cashbook', '=', id_cashbook),
], order=[('date_to', 'DESC')], limit=1) ], order=[('date_to', 'DESC')], limit=1)
if len(recons) > 0: if len(recons) > 0:
values['date_from'] = recons[0].date_to values['date_from'] = recons[0].date_to
@ -466,7 +471,7 @@ class Reconciliation(Workflow, ModelSQL, ModelView):
# set date_to to day of last 'checked'-booking in selected cashbook # set date_to to day of last 'checked'-booking in selected cashbook
lines = Line.search([ lines = Line.search([
('cashbook.id', '=', id_cashbook), ('cashbook', '=', id_cashbook),
('state', '=', 'check'), ('state', '=', 'check'),
('reconciliation', '=', None), ('reconciliation', '=', None),
], order=[('date', 'DESC')], limit=1) ], order=[('date', 'DESC')], limit=1)

View file

@ -97,7 +97,7 @@ full copyright notices and license terms. -->
<record model="ir.rule" id="rg_recon_write-1"> <record model="ir.rule" id="rg_recon_write-1">
<field name="domain" eval="['OR', <field name="domain" eval="['OR',
('cashbook.owner.id', '=', Eval('user', {}).get('id', -1)), ('cashbook.owner.id', '=', Eval('user', {}).get('id', -1)),
('cashbook.reviewer.id', 'in', Eval('user', {}).get('groups', [])), ('cashbook.reviewer.id', 'in', Eval('groups', [])),
]" pyson="1"/> ]" pyson="1"/>
<field name="rule_group" ref="rg_recon_write"/> <field name="rule_group" ref="rg_recon_write"/>
</record> </record>
@ -119,7 +119,7 @@ full copyright notices and license terms. -->
</record> </record>
<record model="ir.rule" id="rg_recon_read-1"> <record model="ir.rule" id="rg_recon_read-1">
<field name="domain" eval="[ <field name="domain" eval="[
('cashbook.observer.id', 'in', Eval('user', {}).get('groups', [])), ('cashbook.observer.id', 'in', Eval('groups', [])),
]" pyson="1"/> ]" pyson="1"/>
<field name="rule_group" ref="rg_recon_read"/> <field name="rule_group" ref="rg_recon_read"/>
</record> </record>

View file

@ -2,7 +2,7 @@
""" """
# Always prefer setuptools over distutils # Always prefer setuptools over distutils
from setuptools import setup, find_packages from setuptools import setup
# To use a consistent encoding # To use a consistent encoding
from codecs import open from codecs import open
from os import path from os import path
@ -40,7 +40,7 @@ with open(path.join(here, 'versiondep.txt'), encoding='utf-8') as f:
# tryton-version # tryton-version
major_version = 6 major_version = 6
minor_version = 0 minor_version = 8
requires = ['python-slugify'] requires = ['python-slugify']
for dep in info.get('depends', []): for dep in info.get('depends', []):
@ -51,19 +51,21 @@ for dep in info.get('depends', []):
prefix = modversion[dep]['prefix'] prefix = modversion[dep]['prefix']
if len(modversion[dep]['max']) > 0: if len(modversion[dep]['max']) > 0:
requires.append('%s_%s >= %s, <= %s' % requires.append('%s_%s >= %s, <= %s' % (
(prefix, dep, modversion[dep]['min'], modversion[dep]['max'])) prefix, dep, modversion[dep]['min'],
modversion[dep]['max']))
else: else:
requires.append('%s_%s >= %s' % requires.append('%s_%s >= %s' % (
(prefix, dep, modversion[dep]['min'])) prefix, dep, modversion[dep]['min']))
else: else:
requires.append('%s_%s >= %s.%s, < %s.%s' % requires.append('%s_%s >= %s.%s, < %s.%s' % (
('trytond', dep, major_version, minor_version, 'trytond', dep, major_version, minor_version,
major_version, minor_version + 1)) major_version, minor_version + 1))
requires.append('trytond >= %s.%s, < %s.%s' % requires.append('trytond >= %s.%s, < %s.%s' % (
(major_version, minor_version, major_version, minor_version + 1)) major_version, minor_version, major_version, minor_version + 1))
setup(name='%s_%s' % (PREFIX, MODULE), setup(
name='%s_%s' % (PREFIX, MODULE),
version=info.get('version', '0.0.1'), version=info.get('version', '0.0.1'),
description='Tryton module to add a cashbook.', description='Tryton module to add a cashbook.',
long_description=long_description, long_description=long_description,
@ -97,8 +99,8 @@ setup(name='%s_%s' % (PREFIX, MODULE),
'trytond.modules.%s' % MODULE, 'trytond.modules.%s' % MODULE,
], ],
package_data={ package_data={
'trytond.modules.%s' % MODULE: (info.get('xml', []) 'trytond.modules.%s' % MODULE: (info.get('xml', []) + [
+ ['tryton.cfg', 'locale/*.po', 'tests/*.py', 'tryton.cfg', 'locale/*.po', 'tests/*.py',
'view/*.xml', 'icon/*.svg', 'docs/*.txt', 'view/*.xml', 'icon/*.svg', 'docs/*.txt',
'report/*.fods', 'versiondep.txt', 'README.rst']), 'report/*.fods', 'versiondep.txt', 'README.rst']),
}, },

View file

@ -9,7 +9,7 @@ from trytond.pool import Pool
from trytond.pyson import Eval, If from trytond.pyson import Eval, If
from trytond.report import Report from trytond.report import Report
from trytond.i18n import gettext from trytond.i18n import gettext
from .line import sel_bookingtype, STATES, DEPENDS from .line import sel_bookingtype, sel_linestate, STATES, DEPENDS
from .book import sel_state_book from .book import sel_state_book
from .mixin import SecondCurrencyMixin, MemCacheIndexMx from .mixin import SecondCurrencyMixin, MemCacheIndexMx
@ -90,7 +90,7 @@ class SplitLine(SecondCurrencyMixin, MemCacheIndexMx, ModelSQL, ModelView):
selection=sel_bookingtype), 'on_change_with_bookingtype') selection=sel_bookingtype), 'on_change_with_bookingtype')
state = fields.Function(fields.Selection( state = fields.Function(fields.Selection(
string='State', readonly=True, string='State', readonly=True,
selection=sel_linetype), 'on_change_with_state') selection=sel_linestate), 'on_change_with_state')
cashbook = fields.Function(fields.Many2One( cashbook = fields.Function(fields.Many2One(
string='Cashbook', string='Cashbook',
readonly=True, states={'invisible': True}, model_name='cashbook.book'), readonly=True, states={'invisible': True}, model_name='cashbook.book'),

View file

@ -81,7 +81,7 @@ full copyright notices and license terms. -->
<record model="ir.rule" id="rg_split_write-1"> <record model="ir.rule" id="rg_split_write-1">
<field name="domain" eval="['OR', <field name="domain" eval="['OR',
('line.cashbook.owner.id', '=', Eval('user', {}).get('id', -1)), ('line.cashbook.owner.id', '=', Eval('user', {}).get('id', -1)),
('line.cashbook.reviewer.id', 'in', Eval('user', {}).get('groups', [])), ('line.cashbook.reviewer.id', 'in', Eval('groups', [])),
]" pyson="1"/> ]" pyson="1"/>
<field name="rule_group" ref="rg_split_write"/> <field name="rule_group" ref="rg_split_write"/>
</record> </record>
@ -103,7 +103,7 @@ full copyright notices and license terms. -->
</record> </record>
<record model="ir.rule" id="rg_split_read-1"> <record model="ir.rule" id="rg_split_read-1">
<field name="domain" eval="[ <field name="domain" eval="[
('line.cashbook.observer.id', 'in', Eval('user', {}).get('groups', [])), ('line.cashbook.observer.id', 'in', Eval('groups', [])),
]" pyson="1"/> ]" pyson="1"/>
<field name="rule_group" ref="rg_split_read"/> <field name="rule_group" ref="rg_split_read"/>
</record> </record>

View file

@ -73,6 +73,26 @@ class SplitLineTestCase(object):
book.lines[0].splitlines[1].rec_name, book.lines[0].splitlines[1].rec_name,
'Rev/Sp|6.00 usd|from cashbook [Cat1]') 'Rev/Sp|6.00 usd|from cashbook [Cat1]')
# check function fields
self.assertEqual(
book.lines[0].splitlines[0].category_view,
'Cat1')
self.assertEqual(book.lines[0].splitlines[0].date, date(2022, 5, 1))
self.assertEqual(book.lines[0].splitlines[0].target.rec_name, 'Cat1')
self.assertEqual(book.lines[0].splitlines[0].currency.rec_name, 'usd')
self.assertEqual(book.lines[0].splitlines[0].currency_digits, 2)
self.assertEqual(book.lines[0].splitlines[0].bookingtype, 'spin')
self.assertEqual(book.lines[0].splitlines[0].state, 'edit')
self.assertEqual(
book.lines[0].splitlines[0].cashbook.rec_name,
'Book 1 | 11.00 usd | Open')
self.assertEqual(book.lines[0].splitlines[0].feature, 'gen')
self.assertEqual(book.lines[0].splitlines[0].booktransf_feature, None)
self.assertEqual(book.lines[0].splitlines[0].state_cashbook, 'open')
self.assertEqual(
book.lines[0].splitlines[0].owner_cashbook.rec_name,
'Administrator')
@with_transaction() @with_transaction()
def test_splitline_category_and_transfer(self): def test_splitline_category_and_transfer(self):
""" add book, line, two split-lines, """ add book, line, two split-lines,

View file

@ -1,5 +1,5 @@
[tryton] [tryton]
version=6.0.0 version=6.8.32
depends: depends:
res res
currency currency

View file

@ -3,7 +3,7 @@
# The COPYRIGHT file at the top level of this repository contains the # The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms. # full copyright notices and license terms.
from trytond.model import ModelView, ModelSQL, fields, Unique from trytond.model import ModelView, ModelSQL, fields, Unique, Index
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.i18n import gettext from trytond.i18n import gettext
@ -28,8 +28,15 @@ class Type(ModelSQL, ModelView):
cls._order.insert(0, ('name', 'ASC')) cls._order.insert(0, ('name', 'ASC'))
t = cls.__table__() t = cls.__table__()
cls._sql_constraints.extend([ cls._sql_constraints.extend([
('code_uniq', Unique(t, t.short), 'cashbook.msg_type_short_unique'), ('code_uniq',
Unique(t, t.short),
'cashbook.msg_type_short_unique'),
]) ])
cls._sql_indexes.update({
Index(
t,
(t.feature, Index.Equality())),
})
@classmethod @classmethod
def default_feature(cls): def default_feature(cls):
@ -48,8 +55,7 @@ class Type(ModelSQL, ModelView):
""" """
return '%(short)s - %(name)s' % { return '%(short)s - %(name)s' % {
'short': self.short or '-', 'short': self.short or '-',
'name': self.name or '-', 'name': self.name or '-'}
}
@classmethod @classmethod
def search_rec_name(cls, name, clause): def search_rec_name(cls, name, clause):
@ -58,8 +64,7 @@ class Type(ModelSQL, ModelView):
return [ return [
'OR', 'OR',
('name',) + tuple(clause[1:]), ('name',) + tuple(clause[1:]),
('short',) + tuple(clause[1:]), ('short',) + tuple(clause[1:])]
]
@staticmethod @staticmethod
def default_company(): def default_company():

View file

@ -5,5 +5,5 @@ full copyright notices and license terms. -->
<tree keyword_open="1"> <tree keyword_open="1">
<field name="rec_name" expand="1"/> <field name="rec_name" expand="1"/>
<field name="balance" sum="Balance" symbol="currency"/> <field name="balance" sum="Balance" symbol="currency"/>
<field name="state"/> <field name="state" optional="0"/>
</tree> </tree>

View file

@ -5,7 +5,7 @@ full copyright notices and license terms. -->
<tree keyword_open="1" tree_state="1"> <tree keyword_open="1" tree_state="1">
<field name="name" expand="1"/> <field name="name" expand="1"/>
<field name="balance" symbol="currency"/> <field name="balance" symbol="currency"/>
<field name="state"/> <field name="state" optional="0"/>
<field name="parent" tree_invisible="1"/> <field name="parent" tree_invisible="1"/>
<field name="childs" tree_invisible="1"/> <field name="childs" tree_invisible="1"/>
</tree> </tree>

View file

@ -4,14 +4,14 @@ The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. --> full copyright notices and license terms. -->
<tree> <tree>
<field name="cashbook" tree_invisible="1"/> <field name="cashbook" tree_invisible="1"/>
<field name="number"/> <field name="number" optional="0"/>
<field name="date"/> <field name="date"/>
<field name="payee"/> <field name="payee"/>
<field name="category_view"/> <field name="category_view"/>
<field name="descr_short" expand="1"/> <field name="descr_short" expand="1"/>
<field name="credit" sum="Credit"/> <field name="credit" sum="Credit" optional="0"/>
<field name="debit" sum="Debit"/> <field name="debit" sum="Debit" optional="0"/>
<field name="balance"/> <field name="balance" optional="0"/>
<field name="state"/> <field name="state" optional="0"/>
<button name="wfcheck"/> <button name="wfcheck"/>
</tree> </tree>

View file

@ -4,13 +4,13 @@ The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. --> full copyright notices and license terms. -->
<tree> <tree>
<field name="cashbook" tree_invisible="1"/> <field name="cashbook" tree_invisible="1"/>
<field name="number"/> <field name="number" optional="0"/>
<field name="date"/> <field name="date" optional="0"/>
<field name="payee"/> <field name="payee" optional="0"/>
<field name="category_view"/> <field name="category_view" optional="0"/>
<field name="descr_short" expand="1"/> <field name="descr_short" expand="1" optional="0"/>
<field name="credit" sum="Credit"/> <field name="credit" sum="Credit" optional="0"/>
<field name="debit" sum="Debit"/> <field name="debit" sum="Debit" optional="0"/>
<field name="state"/> <field name="state" optional="0"/>
<button name="wfrecon"/> <button name="wfrecon"/>
</tree> </tree>

View file

@ -4,11 +4,11 @@ The COPYRIGHT file at the top level of this repository contains the
full copyright notices and license terms. --> full copyright notices and license terms. -->
<tree> <tree>
<field name="cashbook"/> <field name="cashbook"/>
<field name="date"/> <field name="date" optional="0"/>
<field name="date_from"/> <field name="date_from" optional="0"/>
<field name="date_to"/> <field name="date_to" optional="0"/>
<field name="start_amount"/> <field name="start_amount" optional="0"/>
<field name="end_amount"/> <field name="end_amount" optional="0"/>
<field name="lines"/> <field name="lines" optional="0"/>
<field name="state"/> <field name="state" optional="0"/>
</tree> </tree>

View file

@ -8,7 +8,7 @@ full copyright notices and license terms. -->
<field name="splittype"/> <field name="splittype"/>
<field name="category"/> <field name="category"/>
<field name="booktransf"/> <field name="booktransf"/>
<field name="description" expand="1"/> <field name="description" expand="1" optional="0"/>
<field name="amount" sum="Amount" symbol="currency"/> <field name="amount" sum="Amount" symbol="currency" optional="0"/>
<field name="amount_2nd_currency" symbol="currency2nd"/> <field name="amount_2nd_currency" symbol="currency2nd" optional="0"/>
</tree> </tree>

View file

@ -50,7 +50,7 @@ class EnterBookingStart(ModelView):
string='Category', string='Category',
model_name='cashbook.category', depends=['bookingtype'], model_name='cashbook.category', depends=['bookingtype'],
states={ states={
'readonly': Bool(Eval('bookingtype')) == False, 'readonly': ~Bool(Eval('bookingtype')),
'required': Eval('bookingtype', '').in_(['in', 'out']), 'required': Eval('bookingtype', '').in_(['in', 'out']),
'invisible': ~Eval('bookingtype', '').in_(['in', 'out']), 'invisible': ~Eval('bookingtype', '').in_(['in', 'out']),
}, },
@ -90,7 +90,8 @@ class EnterBookingStart(ModelView):
if self.bookingtype: if self.bookingtype:
if self.category: if self.category:
if self.bookingtype not in types.get(self.category.cattype, ''): if self.bookingtype not in types.get(
self.category.cattype, ''):
self.category = None self.category = None
@fields.depends('cashbook', '_parent_cashbook.owner') @fields.depends('cashbook', '_parent_cashbook.owner')
@ -152,7 +153,7 @@ class EnterBookingWizard(Wizard):
'cashbooks': [x.id for x in Cashbook.search([ 'cashbooks': [x.id for x in Cashbook.search([
('state', '=', 'open'), ('state', '=', 'open'),
('btype', '!=', None), ('btype', '!=', None),
('owner.id', '=', Transaction().user), ('owner', '=', Transaction().user),
('id', 'in', book_ids), ('id', 'in', book_ids),
])], ])],
'bookingtype': getattr(self.start, 'bookingtype', 'out'), 'bookingtype': getattr(self.start, 'bookingtype', 'out'),

View file

@ -55,7 +55,7 @@ class RunCbReportStart(ModelView):
if self.cashbook: if self.cashbook:
recons = Recon2.search([ recons = Recon2.search([
('cashbook.id', '=', self.cashbook.id), ('cashbook', '=', self.cashbook.id),
], order=[('date_from', 'DESC')]) ], order=[('date_from', 'DESC')])
return [x.id for x in recons] return [x.id for x in recons]
@ -103,7 +103,7 @@ class RunCbReport(Wizard):
result['cashbook'] = result['cashbooks'][0] result['cashbook'] = result['cashbooks'][0]
recons = Recon2.search([ recons = Recon2.search([
('cashbook.id', '=', result['cashbook']), ('cashbook', '=', result['cashbook']),
], order=[('date_from', 'DESC')]) ], order=[('date_from', 'DESC')])
if len(recons) > 0: if len(recons) > 0:
result['reconciliations'] = [x.id for x in recons] result['reconciliations'] = [x.id for x in recons]