book, line, category, types: berechtigung für company-user + test,

book: währung neu,
line: buchungstyp, betrag, credit, debit, währung, sortierung
This commit is contained in:
Frederik Jaeckel 2022-08-10 16:30:08 +02:00
parent 1a85b8e80e
commit d57d76ba3b
20 changed files with 620 additions and 115 deletions

29
book.py
View file

@ -4,10 +4,11 @@
# full copyright notices and license terms. # full copyright notices and license terms.
from trytond.model import Workflow, ModelView, ModelSQL, fields, Check from trytond.model import Workflow, ModelView, ModelSQL, fields, Check
from trytond.pyson import Eval from trytond.pyson import Eval, Or, Bool
from trytond.exceptions import UserError from trytond.exceptions import UserError
from trytond.i18n import gettext from trytond.i18n import gettext
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.pool import Pool
STATES = { STATES = {
@ -26,6 +27,8 @@ class Book(Workflow, ModelSQL, ModelView):
'Cashbook' 'Cashbook'
__name__ = 'cashbook.book' __name__ = 'cashbook.book'
company = fields.Many2One(string='Company', model_name='company.company',
required=True, ondelete="RESTRICT")
name = fields.Char(string='Name', required=True, name = fields.Char(string='Name', required=True,
states=STATES, depends=DEPENDS) states=STATES, depends=DEPENDS)
btype = fields.Many2One(string='Type', required=True, btype = fields.Many2One(string='Type', required=True,
@ -45,6 +48,14 @@ class Book(Workflow, ModelSQL, ModelView):
account = fields.Many2One(string='Account', select=True, account = fields.Many2One(string='Account', select=True,
model_name='account.account', ondelete='RESTRICT', model_name='account.account', ondelete='RESTRICT',
states=STATES, depends=DEPENDS) states=STATES, depends=DEPENDS)
currency = fields.Many2One(string='Currency', required=True,
model_name='currency.currency',
states={
'readonly': Or(
STATES['readonly'],
Bool(Eval('lines', [])),
),
}, depends=DEPENDS+['lines'])
state = fields.Selection(string='State', required=True, state = fields.Selection(string='State', required=True,
readonly=True, selection=sel_state_book) readonly=True, selection=sel_state_book)
state_string = state.translated('state') state_string = state.translated('state')
@ -79,6 +90,22 @@ class Book(Workflow, ModelSQL, ModelView):
}, },
}) })
@classmethod
def default_currency(cls):
""" currency of company
"""
Company = Pool().get('company.company')
company = cls.default_company()
if company:
company = Company(company)
if company.currency:
return company.currency.id
@staticmethod
def default_company():
return Transaction().context.get('company') or None
@classmethod @classmethod
def default_state(cls): def default_state(cls):
return 'open' return 'open'

View file

@ -107,6 +107,19 @@ full copyright notices and license terms. -->
<field name="group" ref="group_cashbook"/> <field name="group" ref="group_cashbook"/>
</record> </record>
<record model="ir.rule.group" id="rg_book_companies">
<field name="name">User in companies</field>
<field name="model"
search="[('model', '=', 'cashbook.book')]"/>
<field name="global_p" eval="True"/>
</record>
<record model="ir.rule" id="r_book_companies">
<field name="domain"
eval="[('company', 'in', Eval('companies', []))]"
pyson="1"/>
<field name="rule_group" ref="rg_book_companies"/>
</record>
<!-- button - open --> <!-- button - open -->
<record model="ir.model.button" id="book_wfopen_button"> <record model="ir.model.button" id="book_wfopen_button">
<field name="name">wfopen</field> <field name="name">wfopen</field>

View file

@ -87,5 +87,18 @@ full copyright notices and license terms. -->
<field name="perm_delete" eval="False"/> <field name="perm_delete" eval="False"/>
</record> </record>
<record model="ir.rule.group" id="rg_category_companies">
<field name="name">User in companies</field>
<field name="model"
search="[('model', '=', 'cashbook.category')]"/>
<field name="global_p" eval="True"/>
</record>
<record model="ir.rule" id="r_category_companies">
<field name="domain"
eval="[('company', 'in', Eval('companies', []))]"
pyson="1"/>
<field name="rule_group" ref="rg_category_companies"/>
</record>
</data> </data>
</tryton> </tryton>

112
line.py
View file

@ -10,8 +10,10 @@ from trytond.transaction import Transaction
from trytond.report import Report from trytond.report import Report
from trytond.exceptions import UserError from trytond.exceptions import UserError
from trytond.i18n import gettext from trytond.i18n import gettext
from decimal import Decimal
from sql import Cast, Literal from sql import Cast, Literal
from sql.functions import DatePart from sql.functions import DatePart
from sql.conditionals import Case
from .book import sel_state_book from .book import sel_state_book
@ -21,6 +23,13 @@ sel_linetype = [
('done', 'Done'), ('done', 'Done'),
] ]
sel_bookingtype = [
('in', 'Revenue'),
('out', 'Expense'),
('mvin', 'Transfer from'),
('mvout', 'Transfer to'),
]
STATES = { STATES = {
'readonly': Or( 'readonly': Or(
Eval('state', '') != 'edit', Eval('state', '') != 'edit',
@ -47,6 +56,21 @@ class Line(Workflow, ModelSQL, ModelView):
states=STATES, depends=DEPENDS) states=STATES, depends=DEPENDS)
category_view = fields.Function(fields.Char(string='Category', readonly=True), category_view = fields.Function(fields.Char(string='Category', readonly=True),
'on_change_with_category_view', searcher='search_category_view') 'on_change_with_category_view', searcher='search_category_view')
bookingtype = fields.Selection(string='Type', required=True,
help='Type of Booking', selection=sel_bookingtype,
states=STATES, depends=DEPENDS)
amount = fields.Numeric(string='Amount', digits=(16, Eval('currency_digits', 2)),
required=True, states=STATES, depends=DEPENDS+['currency_digits'])
debit = fields.Numeric(string='Debit', digits=(16, Eval('currency_digits', 2)),
required=True, readonly=True, depends=['currency_digits'])
credit = fields.Numeric(string='Credit', digits=(16, Eval('currency_digits', 2)),
required=True, readonly=True, depends=['currency_digits'])
currency = fields.Function(fields.Many2One(model_name='currency.currency',
string="Currency"), 'on_change_with_currency')
currency_digits = fields.Function(fields.Integer(string='Currency Digits'),
'on_change_with_currency_digits')
state = fields.Selection(string='State', required=True, readonly=True, state = fields.Selection(string='State', required=True, readonly=True,
select=True, selection=sel_linetype) select=True, selection=sel_linetype)
state_string = state.translated('state') state_string = state.translated('state')
@ -59,6 +83,7 @@ class Line(Workflow, ModelSQL, ModelView):
@classmethod @classmethod
def __setup__(cls): def __setup__(cls):
super(Line, cls).__setup__() super(Line, cls).__setup__()
cls._order.insert(0, ('state', 'ASC'))
cls._order.insert(0, ('date', 'ASC')) cls._order.insert(0, ('date', 'ASC'))
t = cls.__table__() t = cls.__table__()
cls._sql_constraints.extend([ cls._sql_constraints.extend([
@ -138,6 +163,23 @@ class Line(Workflow, ModelSQL, ModelView):
'desc': (self.description or '-')[:40], 'desc': (self.description or '-')[:40],
} }
@staticmethod
def order_state(tables):
""" edit = 0, check/done = 1
"""
Line = Pool().get('cashbook.line')
tab_line = Line.__table__()
table, _ = tables[None]
query = tab_line.select(
Case(
(tab_line.state == 'edit', 1),
(tab_line.state.in_(['check', 'done']), 0),
else_ = 2),
where=tab_line.id==table.id
)
return [query]
@staticmethod @staticmethod
def order_category_view(tables): def order_category_view(tables):
""" order: name """ order: name
@ -219,11 +261,65 @@ class Line(Workflow, ModelSQL, ModelView):
""" """
return [('cashbook.state',) + tuple(clause[1:])] return [('cashbook.state',) + tuple(clause[1:])]
@fields.depends('cashbook', '_parent_cashbook.currency')
def on_change_with_currency(self, name=None):
""" currency of cashbook
"""
if self.cashbook:
return self.cashbook.currency.id
@fields.depends('cashbook', '_parent_cashbook.currency')
def on_change_with_currency_digits(self, name=None):
""" currency of cashbook
"""
if self.cashbook:
return self.cashbook.currency.digits
else:
return 2
@classmethod
def get_debit_credit(cls, values):
""" compute debit/credit from amount
"""
if isinstance(values, dict):
type_ = values.get('bookingtype', None)
amount = values.get('amount', None)
else :
type_ = getattr(values, 'bookingtype', None)
amount = getattr(values, 'amount', None)
if type_:
if amount is not None:
if type_ in ['in', 'mvin']:
return {
'debit': Decimal('0.0'),
'credit': amount,
}
elif type_ in ['out', 'mvout']:
return {
'debit': amount,
'credit': Decimal('0.0'),
}
else :
raise ValueError('invalid "bookingtype"')
return {}
@classmethod
def create(cls, vlist):
""" add debit/credit
"""
vlist = [x.copy() for x in vlist]
for vals in vlist:
vals.update(cls.get_debit_credit(vals))
return super(Line, cls).create(vlist)
@classmethod @classmethod
def write(cls, *args): def write(cls, *args):
""" deny update if cashbook.line!='open' """ deny update if cashbook.line!='open',
add or update debit/credit
""" """
actions = iter(args) actions = iter(args)
to_write = []
for lines, values in zip(actions, actions): for lines, values in zip(actions, actions):
for line in lines: for line in lines:
if line.cashbook.state != 'open': if line.cashbook.state != 'open':
@ -232,7 +328,19 @@ class Line(Workflow, ModelSQL, ModelView):
bookname = line.cashbook.rec_name, bookname = line.cashbook.rec_name,
state_txt = line.cashbook.state_string, state_txt = line.cashbook.state_string,
)) ))
super(Line, cls).write(*args)
# debit / credit
if len(set(values.keys()).intersection(set({'amount', 'bookingtype'}))) > 0:
for line in lines:
values2 = {}
values2.update(values)
values2.update(cls.get_debit_credit({
x:values.get(x, getattr(line, x)) for x in ['amount', 'bookingtype']
}))
to_write.extend([lines, values2])
else :
to_write.extend([lines, values])
super(Line, cls).write(*to_write)
@classmethod @classmethod
def delete(cls, lines): def delete(cls, lines):

View file

@ -169,6 +169,19 @@ full copyright notices and license terms. -->
<field name="group" ref="group_cashbook"/> <field name="group" ref="group_cashbook"/>
</record> </record>
<record model="ir.rule.group" id="rg_line_companies">
<field name="name">User in companies</field>
<field name="model"
search="[('model', '=', 'cashbook.line')]"/>
<field name="global_p" eval="True"/>
</record>
<record model="ir.rule" id="r_line_companies">
<field name="domain"
eval="[('cashbook.company', 'in', Eval('companies', []))]"
pyson="1"/>
<field name="rule_group" ref="rg_line_companies"/>
</record>
<!-- button - edit --> <!-- button - edit -->
<record model="ir.model.button" id="line_wfedit_button"> <record model="ir.model.button" id="line_wfedit_button">

View file

@ -27,7 +27,7 @@ msgid "The cashbook '%(bookname)s' cannot be deleted because it contains %(bookl
msgstr "Das Kassenbuch '%(bookname)s' kann nicht gelöscht werden, da es %(booklines)s Zeilen enthält und nicht im Status 'Archiv' ist." msgstr "Das Kassenbuch '%(bookname)s' kann nicht gelöscht werden, da es %(booklines)s Zeilen enthält und nicht im Status 'Archiv' ist."
msgctxt "model:ir.message,text:msg_book_deny_write" msgctxt "model:ir.message,text:msg_book_deny_write"
msgid "The cash book '%(bookname)s' is '%(state_txt)s' and cannot be changed." msgid "The cashbook '%(bookname)s' is '%(state_txt)s' and cannot be changed."
msgstr "Das Kassenbuch '%(bookname)s' ist '%(state_txt)s' und kann nicht geändert werden." msgstr "Das Kassenbuch '%(bookname)s' ist '%(state_txt)s' und kann nicht geändert werden."
msgctxt "model:ir.message,text:msg_line_deny_delete1" msgctxt "model:ir.message,text:msg_line_deny_delete1"
@ -90,6 +90,18 @@ msgctxt "model:ir.rule.group,name:rg_line_read"
msgid "Observer: Cashbook line read" msgid "Observer: Cashbook line read"
msgstr "Beobachter: Kassenbuchzeile lesen" msgstr "Beobachter: Kassenbuchzeile lesen"
msgctxt "model:ir.rule.group,name:rg_line_read"
msgid "User in companies"
msgstr "Benutzer im Unternehmen"
msgctxt "model:ir.rule.group,name:rg_type_companies"
msgid "User in companies"
msgstr "Benutzer im Unternehmen"
msgctxt "model:ir.rule.group,name:rg_book_companies"
msgid "User in companies"
msgstr "Benutzer im Unternehmen"
############## ##############
# ir.ui.menu # # ir.ui.menu #
@ -127,8 +139,8 @@ msgstr "Kategorie"
# ir.action # # ir.action #
############# #############
msgctxt "model:ir.action,name:act_book_view" msgctxt "model:ir.action,name:act_book_view"
msgid "Account" msgid "Cashbook"
msgstr "Konto" msgstr "Kassenbuch"
msgctxt "model:ir.action,name:act_type_view" msgctxt "model:ir.action,name:act_type_view"
msgid "Cashbook Type" msgid "Cashbook Type"
@ -147,6 +159,22 @@ msgid "Category"
msgstr "Kategorie" msgstr "Kategorie"
###############################
# ir.action.act_window.domain #
###############################
msgctxt "model:ir.action.act_window.domain,name:act_line_domain_current"
msgid "Current Month"
msgstr "aktueller Monat"
msgctxt "model:ir.action.act_window.domain,name:act_line_domain_last"
msgid "Last Month"
msgstr "letzter Monat"
msgctxt "model:ir.action.act_window.domain,name:act_line_domain_all"
msgid "All"
msgstr "Alle"
################### ###################
# ir.model.button # # ir.model.button #
################### ###################
@ -183,8 +211,8 @@ msgid "Cashbook"
msgstr "Kassenbuch" msgstr "Kassenbuch"
msgctxt "view:cashbook.book:" msgctxt "view:cashbook.book:"
msgid "Owner & Authorizeds" msgid "Owner and Authorizeds"
msgstr "Eigentümer & Autorisierte" msgstr "Eigentümer und Autorisierte"
msgctxt "field:cashbook.book,name:" msgctxt "field:cashbook.book,name:"
msgid "Name" msgid "Name"
@ -234,6 +262,14 @@ msgctxt "field:cashbook.book,account:"
msgid "Account" msgid "Account"
msgstr "Konto" msgstr "Konto"
msgctxt "field:cashbook.book,company:"
msgid "Company"
msgstr "Unternehmen"
msgctxt "field:cashbook.book,currency:"
msgid "Currency"
msgstr "Währung"
################# #################
# cashbook.line # # cashbook.line #
@ -242,6 +278,14 @@ msgctxt "model:cashbook.line,name:"
msgid "Cashbook Line" msgid "Cashbook Line"
msgstr "Kassenbuchzeile" msgstr "Kassenbuchzeile"
msgctxt "view:cashbook.line:"
msgid "Credit"
msgstr "Einnahme"
msgctxt "view:cashbook.line:"
msgid "Debit"
msgstr "Ausgabe"
msgctxt "view:cashbook.line:" msgctxt "view:cashbook.line:"
msgid "Cashbook Line" msgid "Cashbook Line"
msgstr "Kassenbuchzeile" msgstr "Kassenbuchzeile"
@ -294,17 +338,53 @@ msgctxt "field:cashbook.line,category_view:"
msgid "Category" msgid "Category"
msgstr "Kategorie" msgstr "Kategorie"
msgctxt "model:ir.action.act_window.domain,name:act_line_domain_current" msgctxt "field:cashbook.line,bookingtype:"
msgid "Current Month" msgid "Type"
msgstr "aktueller Monat" msgstr "Typ"
msgctxt "model:ir.action.act_window.domain,name:act_line_domain_last" msgctxt "help:cashbook.line,bookingtype:"
msgid "Last Month" msgid "Type of Booking"
msgstr "letzter Monat" msgstr "Typ der Buchung"
msgctxt "model:ir.action.act_window.domain,name:act_line_domain_all" msgctxt "selection:cashbook.line,bookingtype:"
msgid "All" msgid "Revenue"
msgstr "Alle" msgstr "Einnahme"
msgctxt "selection:cashbook.line,bookingtype:"
msgid "Expense"
msgstr "Ausgabe"
msgctxt "selection:cashbook.line,bookingtype:"
msgid "Transfer from"
msgstr "Umbuchung von"
msgctxt "selection:cashbook.line,bookingtype:"
msgid "Transfer to"
msgstr "Umbuchung nach"
msgctxt "field:cashbook.line,company:"
msgid "Company"
msgstr "Unternehmen"
msgctxt "field:cashbook.line,amount:"
msgid "Amount"
msgstr "Betrag"
msgctxt "field:cashbook.line,debit:"
msgid "Debit"
msgstr "Ausgabe"
msgctxt "field:cashbook.line,credit:"
msgid "Credit"
msgstr "Einnahme"
msgctxt "field:cashbook.line,currency:"
msgid "Currency"
msgstr "Währung"
msgctxt "field:cashbook.line,currency_digits:"
msgid "Currency Digits"
msgstr "Nachkommastellen Währung"
################# #################
@ -322,17 +402,9 @@ msgctxt "field:cashbook.type,short:"
msgid "Abbreviation" msgid "Abbreviation"
msgstr "Kürzel" msgstr "Kürzel"
msgctxt "model:cashbook.type,name:atype_cash" msgctxt "field:cashbook.type,company:"
msgid "Cash" msgid "Company"
msgstr "Bar" msgstr "Unternehmen"
msgctxt "model:cashbook.type,name:atype_giro"
msgid "Giro"
msgstr "Giro"
msgctxt "model:cashbook.type,name:atype_fixtermdep"
msgid "Fixed-term deposit"
msgstr "Festgeld"
##################### #####################
@ -434,11 +506,11 @@ msgctxt "model:cashbook.open_lines,name:"
msgid "Open Cashbook" msgid "Open Cashbook"
msgstr "Kassenbuch öffnen" msgstr "Kassenbuch öffnen"
msgctxt "wizard_button:cashbook.open_lines,start,end:" msgctxt "wizard_button:cashbook.open_lines,askuser,end:"
msgid "Cancel" msgid "Cancel"
msgstr "Abbruch" msgstr "Abbruch"
msgctxt "wizard_button:cashbook.open_lines,start,open_:" msgctxt "wizard_button:cashbook.open_lines,askuser,open_:"
msgid "Open" msgid "Open"
msgstr "Öffnen" msgstr "Öffnen"

View file

@ -18,10 +18,10 @@ full copyright notices and license terms. -->
<field name="text">Invalid value of the field 'Status', allowed: open, closed, archive.</field> <field name="text">Invalid value of the field 'Status', allowed: open, closed, archive.</field>
</record> </record>
<record model="ir.message" id="msg_book_deny_delete"> <record model="ir.message" id="msg_book_deny_delete">
<field name="text">The cash book '%(bookname)s' cannot be deleted because it contains %(booklines)s lines and is not in the status 'Archive'.</field> <field name="text">The cashbook '%(bookname)s' cannot be deleted because it contains %(booklines)s lines and is not in the status 'Archive'.</field>
</record> </record>
<record model="ir.message" id="msg_book_deny_write"> <record model="ir.message" id="msg_book_deny_write">
<field name="text">The cash book '%(bookname)s' is '%(state_txt)s' and cannot be changed.</field> <field name="text">The cashbook '%(bookname)s' is '%(state_txt)s' and cannot be changed.</field>
</record> </record>
<record model="ir.message" id="msg_line_deny_delete1"> <record model="ir.message" id="msg_line_deny_delete1">
<field name="text">The cashbook line '%(linetxt)s' cannot be deleted because the Cashbook '%(bookname)s' is in state '%(bookstate)s'.</field> <field name="text">The cashbook line '%(linetxt)s' cannot be deleted because the Cashbook '%(bookname)s' is in state '%(bookstate)s'.</field>

View file

@ -8,6 +8,7 @@ from trytond.pool import Pool
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.exceptions import UserError from trytond.exceptions import UserError
from datetime import date from datetime import date
from decimal import Decimal
class BookTestCase(ModuleTestCase): class BookTestCase(ModuleTestCase):
@ -20,13 +21,14 @@ class BookTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=','CAS')])
types = self.prep_type()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.btype.rec_name, 'CAS - Cash') self.assertEqual(book.btype.rec_name, 'CAS - Cash')
@ -39,18 +41,21 @@ class BookTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'test 1', 'description': 'test 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -67,18 +72,21 @@ class BookTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'test 1', 'description': 'test 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -97,18 +105,21 @@ class BookTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'test 1', 'description': 'test 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -125,13 +136,14 @@ class BookTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')])
types = self.prep_type()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.state, 'open') self.assertEqual(book.state, 'open')
@ -188,18 +200,22 @@ class BookTestCase(ModuleTestCase):
ResUser = pool.get('res.user') ResUser = pool.get('res.user')
ResGroup = pool.get('res.group') ResGroup = pool.get('res.group')
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')]) grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
usr_lst = ResUser.create([{ usr_lst = ResUser.create([{
'login': 'frida', 'login': 'frida',
'name': 'Frida', 'name': 'Frida',
'groups': [('add', [grp_cashbook.id])], 'groups': [('add', [grp_cashbook.id])],
'companies': [('add', [company.id])],
'company': company.id,
}, { }, {
'login': 'diego', 'login': 'diego',
'name': 'Diego', 'name': 'Diego',
'groups': [('add', [grp_cashbook.id])], 'groups': [('add', [grp_cashbook.id])],
'companies': [('add', [company.id])],
'company': company.id,
}]) }])
self.assertEqual(len(usr_lst), 2) self.assertEqual(len(usr_lst), 2)
self.assertEqual(usr_lst[0].name, 'Frida') self.assertEqual(usr_lst[0].name, 'Frida')
@ -209,6 +225,8 @@ class BookTestCase(ModuleTestCase):
'name': 'Fridas book', 'name': 'Fridas book',
'owner': usr_lst[0].id, 'owner': usr_lst[0].id,
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
}]) }])
self.assertEqual(book.rec_name, 'Fridas book'), self.assertEqual(book.rec_name, 'Fridas book'),
self.assertEqual(book.owner.rec_name, 'Frida'), self.assertEqual(book.owner.rec_name, 'Frida'),
@ -245,9 +263,9 @@ class BookTestCase(ModuleTestCase):
ResUser = pool.get('res.user') ResUser = pool.get('res.user')
ResGroup = pool.get('res.group') ResGroup = pool.get('res.group')
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')]) grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
grp_reviewer, = ResGroup.create([{ grp_reviewer, = ResGroup.create([{
'name': 'Cashbook Reviewer', 'name': 'Cashbook Reviewer',
@ -257,10 +275,14 @@ class BookTestCase(ModuleTestCase):
'login': 'frida', 'login': 'frida',
'name': 'Frida', 'name': 'Frida',
'groups': [('add', [grp_cashbook.id])], 'groups': [('add', [grp_cashbook.id])],
'companies': [('add', [company.id])],
'company': company.id,
}, { }, {
'login': 'diego', 'login': 'diego',
'name': 'Diego', 'name': 'Diego',
'groups': [('add', [grp_cashbook.id, grp_reviewer.id])], 'groups': [('add', [grp_cashbook.id, grp_reviewer.id])],
'companies': [('add', [company.id])],
'company': company.id,
}]) }])
self.assertEqual(len(usr_lst), 2) self.assertEqual(len(usr_lst), 2)
self.assertEqual(usr_lst[0].name, 'Frida') self.assertEqual(usr_lst[0].name, 'Frida')
@ -272,6 +294,8 @@ class BookTestCase(ModuleTestCase):
'name': 'Fridas book', 'name': 'Fridas book',
'owner': usr_lst[0].id, 'owner': usr_lst[0].id,
'reviewer': grp_reviewer.id, 'reviewer': grp_reviewer.id,
'company': company.id,
'currency': company.currency.id,
'btype': types.id, 'btype': types.id,
}]) }])
self.assertEqual(book.rec_name, 'Fridas book'), self.assertEqual(book.rec_name, 'Fridas book'),
@ -301,9 +325,9 @@ class BookTestCase(ModuleTestCase):
ResUser = pool.get('res.user') ResUser = pool.get('res.user')
ResGroup = pool.get('res.group') ResGroup = pool.get('res.group')
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')]) grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
grp_observer, = ResGroup.create([{ grp_observer, = ResGroup.create([{
'name': 'Cashbook Observer', 'name': 'Cashbook Observer',
@ -313,10 +337,14 @@ class BookTestCase(ModuleTestCase):
'login': 'frida', 'login': 'frida',
'name': 'Frida', 'name': 'Frida',
'groups': [('add', [grp_cashbook.id])], 'groups': [('add', [grp_cashbook.id])],
'companies': [('add', [company.id])],
'company': company.id,
}, { }, {
'login': 'diego', 'login': 'diego',
'name': 'Diego', 'name': 'Diego',
'groups': [('add', [grp_cashbook.id, grp_observer.id])], 'groups': [('add', [grp_cashbook.id, grp_observer.id])],
'companies': [('add', [company.id])],
'company': company.id,
}]) }])
self.assertEqual(len(usr_lst), 2) self.assertEqual(len(usr_lst), 2)
self.assertEqual(usr_lst[0].name, 'Frida') self.assertEqual(usr_lst[0].name, 'Frida')
@ -328,6 +356,8 @@ class BookTestCase(ModuleTestCase):
'name': 'Fridas book', 'name': 'Fridas book',
'owner': usr_lst[0].id, 'owner': usr_lst[0].id,
'observer': grp_observer.id, 'observer': grp_observer.id,
'company': company.id,
'currency': company.currency.id,
'btype': types.id, 'btype': types.id,
}]) }])
self.assertEqual(book.rec_name, 'Fridas book'), self.assertEqual(book.rec_name, 'Fridas book'),

View file

@ -7,7 +7,6 @@ from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.pool import Pool from trytond.pool import Pool
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.exceptions import UserError from trytond.exceptions import UserError
from trytond.modules.company.tests import create_company
class CategoryTestCase(ModuleTestCase): class CategoryTestCase(ModuleTestCase):
@ -21,12 +20,7 @@ class CategoryTestCase(ModuleTestCase):
Company = pool.get('company.company') Company = pool.get('company.company')
Category = pool.get('cashbook.category') Category = pool.get('cashbook.category')
company = Company.search([]) company = self.prep_company()
if len(company) > 0:
company = company[0]
else :
company = create_company(name='m-ds')
category, = Category.create([{ category, = Category.create([{
'company': company.id, 'company': company.id,
'name': name, 'name': name,
@ -40,7 +34,7 @@ class CategoryTestCase(ModuleTestCase):
pool = Pool() pool = Pool()
Category = pool.get('cashbook.category') Category = pool.get('cashbook.category')
company = create_company(name='m-ds') company = self.prep_company()
with Transaction().set_context({ with Transaction().set_context({
'company': company.id, 'company': company.id,
@ -73,7 +67,7 @@ class CategoryTestCase(ModuleTestCase):
pool = Pool() pool = Pool()
Category = pool.get('cashbook.category') Category = pool.get('cashbook.category')
company = create_company(name='m-ds') company = self.prep_company()
with Transaction().set_context({ with Transaction().set_context({
'company': company.id, 'company': company.id,
@ -100,7 +94,7 @@ class CategoryTestCase(ModuleTestCase):
pool = Pool() pool = Pool()
Category = pool.get('cashbook.category') Category = pool.get('cashbook.category')
company = create_company(name='m-ds') company = self.prep_company()
with Transaction().set_context({ with Transaction().set_context({
'company': company.id, 'company': company.id,
@ -126,7 +120,7 @@ class CategoryTestCase(ModuleTestCase):
Account = pool.get('account.account') Account = pool.get('account.account')
Category = pool.get('cashbook.category') Category = pool.get('cashbook.category')
company = create_company(name='m-ds') company = self.prep_company()
with Transaction().set_context({ with Transaction().set_context({
'company': company.id, 'company': company.id,

View file

@ -7,6 +7,7 @@ from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.pool import Pool from trytond.pool import Pool
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.exceptions import UserError from trytond.exceptions import UserError
from trytond.modules.company.tests import create_company
from datetime import date from datetime import date
@ -14,6 +15,18 @@ class ConfigTestCase(ModuleTestCase):
'Test config type module' 'Test config type module'
module = 'cashbook' module = 'cashbook'
def prep_company(self):
""" get/create company
"""
Company = Pool().get('company.company')
company = Company.search([])
if len(company) > 0:
company = company[0]
else :
company = create_company(name='m-ds')
return company
@with_transaction() @with_transaction()
def test_config_create(self): def test_config_create(self):
""" create config """ create config

View file

@ -9,6 +9,7 @@ from trytond.transaction import Transaction
from trytond.exceptions import UserError from trytond.exceptions import UserError
from datetime import date from datetime import date
from unittest.mock import MagicMock from unittest.mock import MagicMock
from decimal import Decimal
class LineTestCase(ModuleTestCase): class LineTestCase(ModuleTestCase):
@ -21,23 +22,28 @@ class LineTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
Lines = pool.get('cashbook.line') Lines = pool.get('cashbook.line')
types, = Types.search([('short', '=','CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Text 1', 'description': 'Text 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, { }, {
'date': date(2022, 5, 2), 'date': date(2022, 5, 2),
'description': 'Text 2', 'description': 'Text 2',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -59,29 +65,62 @@ class LineTestCase(ModuleTestCase):
self.assertEqual(Lines.search_count([('cashbook.state', '=', 'open')]), 2) self.assertEqual(Lines.search_count([('cashbook.state', '=', 'open')]), 2)
self.assertEqual(Lines.search_count([('cashbook.state', '=', 'closed')]), 0) self.assertEqual(Lines.search_count([('cashbook.state', '=', 'closed')]), 0)
# sorting: date -> state -> id
self.assertEqual(len(book.lines), 2)
self.assertEqual(book.lines[0].rec_name, '05/01/2022 Text 1')
self.assertEqual(book.lines[0].state, 'edit')
self.assertEqual(book.lines[1].rec_name, '05/02/2022 Text 2')
self.assertEqual(book.lines[1].state, 'edit')
# set to same date
Lines.write(*[
list(book.lines),
{
'date': date(2022, 5, 1),
}])
# check again
book, = Book.search([])
self.assertEqual(book.lines[0].rec_name, '05/01/2022 Text 1')
self.assertEqual(book.lines[0].state, 'edit')
self.assertEqual(book.lines[1].rec_name, '05/01/2022 Text 2')
self.assertEqual(book.lines[1].state, 'edit')
# set to 'check', will sort first
Lines.wfcheck([book.lines[1]])
book, = Book.search([])
self.assertEqual(book.lines[0].rec_name, '05/01/2022 Text 2')
self.assertEqual(book.lines[0].state, 'check')
self.assertEqual(book.lines[1].rec_name, '05/01/2022 Text 1')
self.assertEqual(book.lines[1].state, 'edit')
@with_transaction() @with_transaction()
def test_line_create_check_deny_write(self): def test_line_create_check_deny_write(self):
""" create cashbook + line, 'close' book, write to line """ create cashbook + line, 'close' book, write to line
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
Line = pool.get('cashbook.line') Line = pool.get('cashbook.line')
types, = Types.search([('short', '=','CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Text 1', 'description': 'Text 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, { }, {
'date': date(2022, 6, 1), 'date': date(2022, 6, 1),
'description': 'Text 2', 'description': 'Text 2',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -107,26 +146,31 @@ class LineTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
Line = pool.get('cashbook.line') Line = pool.get('cashbook.line')
IrDate = pool.get('ir.date') IrDate = pool.get('ir.date')
types, = Types.search([('short', '=','CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
IrDate.today = MagicMock(return_value=date(2022, 6, 1)) IrDate.today = MagicMock(return_value=date(2022, 6, 1))
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Text 1', 'description': 'Text 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, { }, {
'date': date(2022, 6, 1), 'date': date(2022, 6, 1),
'description': 'Text 2', 'description': 'Text 2',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -159,21 +203,125 @@ class LineTestCase(ModuleTestCase):
IrDate.today = MagicMock(return_value=date.today()) IrDate.today = MagicMock(return_value=date.today())
@with_transaction()
def test_line_create_check_debit_credit(self):
""" create cashbook + line, check calculation of debit/credit
"""
pool = Pool()
Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
Configuration = pool.get('cashbook.configuration')
Category = pool.get('cashbook.category')
types = self.prep_type()
category = self.prep_category()
company = self.prep_company()
category2, = Category.create([{
'company': company.id,
'name': 'Category',
}])
book, = Book.create([{
'name': 'Book 1',
'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Revenue',
'category': category2.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, {
'date': date(2022, 6, 1),
'description': 'Expense',
'category': category2.id,
'bookingtype': 'out',
'amount': Decimal('1.0'),
}, {
'date': date(2022, 6, 1),
'description': 'Transfer from',
'category': category2.id,
'bookingtype': 'mvin',
'amount': Decimal('1.0'),
}, {
'date': date(2022, 6, 1),
'description': 'Transfer to',
'category': category2.id,
'bookingtype': 'mvout',
'amount': Decimal('1.0'),
}])],
}])
self.assertEqual(book.name, 'Book 1')
self.assertEqual(book.state, 'open')
self.assertEqual(len(book.lines), 4)
self.assertEqual(book.lines[0].amount, Decimal('1.0'))
self.assertEqual(book.lines[0].bookingtype, 'in')
self.assertEqual(book.lines[0].credit, Decimal('1.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
self.assertEqual(book.lines[1].amount, Decimal('1.0'))
self.assertEqual(book.lines[1].bookingtype, 'out')
self.assertEqual(book.lines[1].credit, Decimal('0.0'))
self.assertEqual(book.lines[1].debit, Decimal('1.0'))
self.assertEqual(book.lines[2].amount, Decimal('1.0'))
self.assertEqual(book.lines[2].bookingtype, 'mvin')
self.assertEqual(book.lines[2].credit, Decimal('1.0'))
self.assertEqual(book.lines[2].debit, Decimal('0.0'))
self.assertEqual(book.lines[3].amount, Decimal('1.0'))
self.assertEqual(book.lines[3].bookingtype, 'mvout')
self.assertEqual(book.lines[3].credit, Decimal('0.0'))
self.assertEqual(book.lines[3].debit, Decimal('1.0'))
Line.write(*[
[book.lines[0]],
{
'amount': Decimal('2.0'),
}])
self.assertEqual(book.lines[0].amount, Decimal('2.0'))
self.assertEqual(book.lines[0].bookingtype, 'in')
self.assertEqual(book.lines[0].credit, Decimal('2.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
Line.write(*[
[book.lines[0]],
{
'bookingtype': 'out',
}])
self.assertEqual(book.lines[0].amount, Decimal('2.0'))
self.assertEqual(book.lines[0].bookingtype, 'out')
self.assertEqual(book.lines[0].credit, Decimal('0.0'))
self.assertEqual(book.lines[0].debit, Decimal('2.0'))
Line.write(*[
[book.lines[0]],
{
'bookingtype': 'mvin',
'amount': Decimal('3.0'),
}])
self.assertEqual(book.lines[0].amount, Decimal('3.0'))
self.assertEqual(book.lines[0].bookingtype, 'mvin')
self.assertEqual(book.lines[0].credit, Decimal('3.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
@with_transaction() @with_transaction()
def test_line_create_check_category_view(self): def test_line_create_check_category_view(self):
""" create cashbook + line, check 'category_view' """ create cashbook + line, check 'category_view'
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
Line = pool.get('cashbook.line') Line = pool.get('cashbook.line')
Configuration = pool.get('cashbook.configuration') Configuration = pool.get('cashbook.configuration')
Category = pool.get('cashbook.category') Category = pool.get('cashbook.category')
Account = pool.get('account.account') Account = pool.get('account.account')
types, = Types.search([('short', '=','CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = category.company company = self.prep_company()
with Transaction().set_context({ with Transaction().set_context({
'company': company.id, 'company': company.id,
@ -208,14 +356,20 @@ class LineTestCase(ModuleTestCase):
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Text 1', 'description': 'Text 1',
'category': category2.id, 'category': category2.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, { }, {
'date': date(2022, 6, 1), 'date': date(2022, 6, 1),
'description': 'Text 2', 'description': 'Text 2',
'category': category2.childs[0].id, 'category': category2.childs[0].id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -257,23 +411,28 @@ class LineTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
Lines = pool.get('cashbook.line') Lines = pool.get('cashbook.line')
types, = Types.search([('short', '=','CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Text 1', 'description': 'Text 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, { }, {
'date': date(2022, 5, 2), 'date': date(2022, 5, 2),
'description': 'Text 2', 'description': 'Text 2',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -288,23 +447,28 @@ class LineTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
Lines = pool.get('cashbook.line') Lines = pool.get('cashbook.line')
types, = Types.search([('short', '=','CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Text 1', 'description': 'Text 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, { }, {
'date': date(2022, 5, 2), 'date': date(2022, 5, 2),
'description': 'Text 2', 'description': 'Text 2',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -324,23 +488,28 @@ class LineTestCase(ModuleTestCase):
""" """
pool = Pool() pool = Pool()
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Types = pool.get('cashbook.type')
Lines = pool.get('cashbook.line') Lines = pool.get('cashbook.line')
types, = Types.search([('short', '=','CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
book, = Book.create([{ book, = Book.create([{
'name': 'Book 1', 'name': 'Book 1',
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Text 1', 'description': 'Text 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}, { }, {
'date': date(2022, 5, 2), 'date': date(2022, 5, 2),
'description': 'Text 2', 'description': 'Text 2',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.name, 'Book 1') self.assertEqual(book.name, 'Book 1')
@ -365,19 +534,23 @@ class LineTestCase(ModuleTestCase):
ResGroup = pool.get('res.group') ResGroup = pool.get('res.group')
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line') Line = pool.get('cashbook.line')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')]) grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
usr_lst = ResUser.create([{ usr_lst = ResUser.create([{
'login': 'frida', 'login': 'frida',
'name': 'Frida', 'name': 'Frida',
'groups': [('add', [grp_cashbook.id])], 'groups': [('add', [grp_cashbook.id])],
'companies': [('add', [company.id])],
'company': company.id,
}, { }, {
'login': 'diego', 'login': 'diego',
'name': 'Diego', 'name': 'Diego',
'groups': [('add', [grp_cashbook.id])], 'groups': [('add', [grp_cashbook.id])],
'companies': [('add', [company.id])],
'company': company.id,
}]) }])
self.assertEqual(len(usr_lst), 2) self.assertEqual(len(usr_lst), 2)
self.assertEqual(usr_lst[0].name, 'Frida') self.assertEqual(usr_lst[0].name, 'Frida')
@ -387,10 +560,14 @@ class LineTestCase(ModuleTestCase):
'name': 'Fridas book', 'name': 'Fridas book',
'owner': usr_lst[0].id, 'owner': usr_lst[0].id,
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Test 1', 'description': 'Test 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.rec_name, 'Fridas book'), self.assertEqual(book.rec_name, 'Fridas book'),
@ -427,10 +604,10 @@ class LineTestCase(ModuleTestCase):
ResGroup = pool.get('res.group') ResGroup = pool.get('res.group')
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line') Line = pool.get('cashbook.line')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')]) grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
grp_reviewer, = ResGroup.create([{ grp_reviewer, = ResGroup.create([{
'name': 'Cashbook Reviewer', 'name': 'Cashbook Reviewer',
@ -440,10 +617,14 @@ class LineTestCase(ModuleTestCase):
'login': 'frida', 'login': 'frida',
'name': 'Frida', 'name': 'Frida',
'groups': [('add', [grp_cashbook.id])], 'groups': [('add', [grp_cashbook.id])],
'companies': [('add', [company.id])],
'company': company.id,
}, { }, {
'login': 'diego', 'login': 'diego',
'name': 'Diego', 'name': 'Diego',
'groups': [('add', [grp_cashbook.id, grp_reviewer.id])], 'groups': [('add', [grp_cashbook.id, grp_reviewer.id])],
'companies': [('add', [company.id])],
'company': company.id,
}]) }])
self.assertEqual(len(usr_lst), 2) self.assertEqual(len(usr_lst), 2)
self.assertEqual(usr_lst[0].name, 'Frida') self.assertEqual(usr_lst[0].name, 'Frida')
@ -456,10 +637,14 @@ class LineTestCase(ModuleTestCase):
'owner': usr_lst[0].id, 'owner': usr_lst[0].id,
'reviewer': grp_reviewer.id, 'reviewer': grp_reviewer.id,
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Test 1', 'description': 'Test 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.rec_name, 'Fridas book'), self.assertEqual(book.rec_name, 'Fridas book'),
@ -503,10 +688,10 @@ class LineTestCase(ModuleTestCase):
ResGroup = pool.get('res.group') ResGroup = pool.get('res.group')
Book = pool.get('cashbook.book') Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line') Line = pool.get('cashbook.line')
Types = pool.get('cashbook.type')
types, = Types.search([('short', '=', 'CAS')]) types = self.prep_type()
category = self.prep_category() category = self.prep_category()
company = self.prep_company()
grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')]) grp_cashbook, = ResGroup.search([('name', '=', 'Cashbook')])
grp_observer, = ResGroup.create([{ grp_observer, = ResGroup.create([{
'name': 'Cashbook Observer', 'name': 'Cashbook Observer',
@ -516,10 +701,14 @@ class LineTestCase(ModuleTestCase):
'login': 'frida', 'login': 'frida',
'name': 'Frida', 'name': 'Frida',
'groups': [('add', [grp_cashbook.id])], 'groups': [('add', [grp_cashbook.id])],
'companies': [('add', [company.id])],
'company': company.id,
}, { }, {
'login': 'diego', 'login': 'diego',
'name': 'Diego', 'name': 'Diego',
'groups': [('add', [grp_cashbook.id, grp_observer.id])], 'groups': [('add', [grp_cashbook.id, grp_observer.id])],
'companies': [('add', [company.id])],
'company': company.id,
}]) }])
self.assertEqual(len(usr_lst), 2) self.assertEqual(len(usr_lst), 2)
self.assertEqual(usr_lst[0].name, 'Frida') self.assertEqual(usr_lst[0].name, 'Frida')
@ -532,10 +721,14 @@ class LineTestCase(ModuleTestCase):
'owner': usr_lst[0].id, 'owner': usr_lst[0].id,
'observer': grp_observer.id, 'observer': grp_observer.id,
'btype': types.id, 'btype': types.id,
'company': company.id,
'currency': company.currency.id,
'lines': [('create', [{ 'lines': [('create', [{
'date': date(2022, 5, 1), 'date': date(2022, 5, 1),
'description': 'Test 1', 'description': 'Test 1',
'category': category.id, 'category': category.id,
'bookingtype': 'in',
'amount': Decimal('1.0'),
}])], }])],
}]) }])
self.assertEqual(book.rec_name, 'Fridas book'), self.assertEqual(book.rec_name, 'Fridas book'),

View file

@ -13,17 +13,20 @@ class TypeTestCase(ModuleTestCase):
'Test cashbook type module' 'Test cashbook type module'
module = 'cashbook' module = 'cashbook'
@with_transaction() def prep_type(self, name='Cash', short='CAS'):
def test_type_read_existing(self): """ create book-type
""" read predefined types
""" """
AccType = Pool().get('cashbook.type') AccType = Pool().get('cashbook.type')
t_lst = AccType.search([], order=[('name', 'ASC')]) company = self.prep_company()
self.assertEqual(len(t_lst), 3) at, = AccType.create([{
self.assertEqual(t_lst[0].rec_name, 'CAS - Cash') 'name': name,
self.assertEqual(t_lst[1].rec_name, 'FTD - Fixed-term deposit') 'short': short,
self.assertEqual(t_lst[2].rec_name, 'GIR - Giro') 'company': company.id,
}])
self.assertEqual(at.name, name)
self.assertEqual(at.short, short)
return at
@with_transaction() @with_transaction()
def test_type_create(self): def test_type_create(self):
@ -31,9 +34,12 @@ class TypeTestCase(ModuleTestCase):
""" """
AccType = Pool().get('cashbook.type') AccType = Pool().get('cashbook.type')
company = self.prep_company()
at, = AccType.create([{ at, = AccType.create([{
'name': 'Test 1', 'name': 'Test 1',
'short': 'T1', 'short': 'T1',
'company': company.id,
}]) }])
self.assertEqual(at.name, 'Test 1') self.assertEqual(at.name, 'Test 1')
self.assertEqual(at.short, 'T1') self.assertEqual(at.short, 'T1')
@ -45,6 +51,7 @@ class TypeTestCase(ModuleTestCase):
[{ [{
'name': 'Test 2', 'name': 'Test 2',
'short': 'T1', 'short': 'T1',
'company': company.id,
}]) }])
# end TypeTestCase # end TypeTestCase

View file

@ -3,6 +3,7 @@ version=6.0.0
depends: depends:
res res
account account
currency
xml: xml:
icon.xml icon.xml
group.xml group.xml

View file

@ -4,6 +4,7 @@
# 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
from trytond.transaction import Transaction
class Type(ModelSQL, ModelView): class Type(ModelSQL, ModelView):
@ -12,6 +13,8 @@ class Type(ModelSQL, ModelView):
name = fields.Char(string='Name', required=True, translate=True) name = fields.Char(string='Name', required=True, translate=True)
short = fields.Char(string='Abbreviation', required=True, size=3) short = fields.Char(string='Abbreviation', required=True, size=3)
company = fields.Many2One(string='Company', model_name='company.company',
required=True, ondelete="RESTRICT")
@classmethod @classmethod
def __setup__(cls): def __setup__(cls):
@ -39,4 +42,8 @@ class Type(ModelSQL, ModelView):
('short',) + tuple(clause[1:]), ('short',) + tuple(clause[1:]),
] ]
@staticmethod
def default_company():
return Transaction().context.get('company') or None
# end Type # end Type

View file

@ -63,18 +63,17 @@ full copyright notices and license terms. -->
<field name="perm_delete" eval="False"/> <field name="perm_delete" eval="False"/>
</record> </record>
<!-- defaults --> <record model="ir.rule.group" id="rg_type_companies">
<record model="cashbook.type" id="atype_cash"> <field name="name">User in companies</field>
<field name="short">CAS</field> <field name="model"
<field name="name">Cash</field> search="[('model', '=', 'cashbook.type')]"/>
<field name="global_p" eval="True"/>
</record> </record>
<record model="cashbook.type" id="atype_giro"> <record model="ir.rule" id="r_type_companies">
<field name="short">GIR</field> <field name="domain"
<field name="name">Giro</field> eval="[('company', 'in', Eval('companies', []))]"
</record> pyson="1"/>
<record model="cashbook.type" id="atype_fixtermdep"> <field name="rule_group" ref="rg_type_companies"/>
<field name="short">FTD</field>
<field name="name">Fixed-term deposit</field>
</record> </record>
</data> </data>

View file

@ -8,9 +8,10 @@ full copyright notices and license terms. -->
<label name="btype"/> <label name="btype"/>
<field name="btype"/> <field name="btype"/>
<label name="currency"/>
<field name="currency"/>
<label name="account"/> <label name="account"/>
<field name="account"/> <field name="account"/>
<newline/>
<label name="state"/> <label name="state"/>
<field name="state"/> <field name="state"/>

View file

@ -5,6 +5,7 @@ full copyright notices and license terms. -->
<tree> <tree>
<field name="name"/> <field name="name"/>
<field name="btype"/> <field name="btype"/>
<field name="currency"/>
<field name="account"/> <field name="account"/>
<field name="owner"/> <field name="owner"/>
<field name="reviewer"/> <field name="reviewer"/>

View file

@ -7,8 +7,7 @@ full copyright notices and license terms. -->
<separator name="state" colspan="2" string="State"/> <separator name="state" colspan="2" string="State"/>
<field name="cashbook" colspan="2"/> <field name="cashbook" colspan="2"/>
<label name="date"/> <label id="lab1" string=" " colspan="2"/>
<field name="date"/>
<field name="state"/> <field name="state"/>
<group id="grpstate" col="2"> <group id="grpstate" col="2">
@ -16,10 +15,17 @@ full copyright notices and license terms. -->
<button name="wfcheck"/> <button name="wfcheck"/>
</group> </group>
<label name="date"/>
<field name="date"/>
<label name="category"/> <label name="category"/>
<field name="category"/> <field name="category"/>
<newline/> <newline/>
<label name="bookingtype"/>
<field name="bookingtype"/>
<label name="amount"/>
<field name="amount" symbol="currency"/>
<group name="description" colspan="4" col="1" string="Description"> <group name="description" colspan="4" col="1" string="Description">
<field name="description"/> <field name="description"/>
</group> </group>

View file

@ -3,10 +3,13 @@
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. -->
<tree> <tree>
<field name="cashbook"/> <field name="cashbook" tree_invisible="1"/>
<field name="date"/> <field name="date"/>
<field name="category_view"/> <field name="category_view"/>
<field name="description"/> <field name="description" expand="1"/>
<field name="credit" sum="Credit"/>
<field name="debit" sum="Debit"/>
<field name="currency"/>
<field name="state"/> <field name="state"/>
<button name="wfedit"/> <button name="wfedit"/>
<button name="wfcheck"/> <button name="wfcheck"/>

View file

@ -82,6 +82,10 @@ class OpenCashBook(Wizard):
Configuration = pool.get('cashbook.configuration') Configuration = pool.get('cashbook.configuration')
cfg1 = Configuration.get_singleton() cfg1 = Configuration.get_singleton()
if cfg1 is None:
cfg1 = Configuration()
cfg1.save()
book = getattr(self.askuser, 'cashbook', None) book = getattr(self.askuser, 'cashbook', None)
if book is None: if book is None:
with Transaction().set_context({ with Transaction().set_context({