add booking with category + test, todo: booking of asset
This commit is contained in:
parent
e51abf589b
commit
b86e421298
6 changed files with 372 additions and 19 deletions
56
locale/de.po
56
locale/de.po
|
@ -102,6 +102,10 @@ msgctxt "view:cashbook.planner:"
|
|||
msgid "Booking"
|
||||
msgstr "Buchung"
|
||||
|
||||
msgctxt "view:cashbook.planner:"
|
||||
msgid "Booking text"
|
||||
msgstr "Buchungstext"
|
||||
|
||||
msgctxt "field:cashbook.planner,company:"
|
||||
msgid "Company"
|
||||
msgstr "Unternehmen"
|
||||
|
@ -238,18 +242,10 @@ msgctxt "selection:cashbook.planner,bookingtype:"
|
|||
msgid "Revenue"
|
||||
msgstr "Einnahme"
|
||||
|
||||
msgctxt "selection:cashbook.planner,bookingtype:"
|
||||
msgid "Revenue Splitbooking"
|
||||
msgstr "Einnahme Splitbuchung"
|
||||
|
||||
msgctxt "selection:cashbook.planner,bookingtype:"
|
||||
msgid "Expense"
|
||||
msgstr "Ausgabe"
|
||||
|
||||
msgctxt "selection:cashbook.planner,bookingtype:"
|
||||
msgid "Expense Splitbooking"
|
||||
msgstr "Ausgabe Splitbuchung"
|
||||
|
||||
msgctxt "selection:cashbook.planner,bookingtype:"
|
||||
msgid "Transfer from"
|
||||
msgstr "Umbuchung von"
|
||||
|
@ -258,6 +254,50 @@ msgctxt "selection:cashbook.planner,bookingtype:"
|
|||
msgid "Transfer to"
|
||||
msgstr "Umbuchung nach"
|
||||
|
||||
msgctxt "field:cashbook.planner,currency_cashbook:"
|
||||
msgid "Currency"
|
||||
msgstr "Währung"
|
||||
|
||||
msgctxt "help:cashbook.planner,currency_cashbook:"
|
||||
msgid "Currency of Cashbook"
|
||||
msgstr "Währung des Kassenbuchs"
|
||||
|
||||
msgctxt "field:cashbook.planner,amount:"
|
||||
msgid "Amount"
|
||||
msgstr "Betrag"
|
||||
|
||||
msgctxt "field:cashbook.planner,category:"
|
||||
msgid "Category"
|
||||
msgstr "Kategorie"
|
||||
|
||||
msgctxt "help:cashbook.planner,category:"
|
||||
msgid "Category for the planned booking"
|
||||
msgstr "Kategorie für die geplante Buchung"
|
||||
|
||||
msgctxt "field:cashbook.planner,booktransf:"
|
||||
msgid "Source/Dest"
|
||||
msgstr "Quelle/Ziel"
|
||||
|
||||
msgctxt "field:cashbook.planner,owner_cashbook:"
|
||||
msgid "Owner"
|
||||
msgstr "Eigentümer"
|
||||
|
||||
msgctxt "field:cashbook.planner,state_cashbook:"
|
||||
msgid "State of Cashbook"
|
||||
msgstr "Status des Kassenbuchs"
|
||||
|
||||
msgctxt "field:cashbook.planner,subject:"
|
||||
msgid "Booking text"
|
||||
msgstr "Buchungstext"
|
||||
|
||||
msgctxt "field:cashbook.planner,wfcheck:"
|
||||
msgid "Set to 'Checked'"
|
||||
msgstr "auf 'Geprüft' setzen"
|
||||
|
||||
msgctxt "help:cashbook.planner,wfcheck:"
|
||||
msgid "Switches the booking to the 'Verified' state."
|
||||
msgstr "Schaltet die Buchung in den Zustand 'Geprüft'"
|
||||
|
||||
|
||||
############################
|
||||
# cashbook.planner.nextrun #
|
||||
|
|
56
locale/en.po
56
locale/en.po
|
@ -78,6 +78,10 @@ msgctxt "view:cashbook.planner:"
|
|||
msgid "Booking"
|
||||
msgstr "Booking"
|
||||
|
||||
msgctxt "view:cashbook.planner:"
|
||||
msgid "Booking text"
|
||||
msgstr "Booking text"
|
||||
|
||||
msgctxt "field:cashbook.planner,company:"
|
||||
msgid "Company"
|
||||
msgstr "Company"
|
||||
|
@ -214,18 +218,10 @@ msgctxt "selection:cashbook.planner,bookingtype:"
|
|||
msgid "Revenue"
|
||||
msgstr "Revenue"
|
||||
|
||||
msgctxt "selection:cashbook.planner,bookingtype:"
|
||||
msgid "Revenue Splitbooking"
|
||||
msgstr "Revenue Splitbooking"
|
||||
|
||||
msgctxt "selection:cashbook.planner,bookingtype:"
|
||||
msgid "Expense"
|
||||
msgstr "Expense"
|
||||
|
||||
msgctxt "selection:cashbook.planner,bookingtype:"
|
||||
msgid "Expense Splitbooking"
|
||||
msgstr "Expense Splitbooking"
|
||||
|
||||
msgctxt "selection:cashbook.planner,bookingtype:"
|
||||
msgid "Transfer from"
|
||||
msgstr "Transfer from"
|
||||
|
@ -234,6 +230,50 @@ msgctxt "selection:cashbook.planner,bookingtype:"
|
|||
msgid "Transfer to"
|
||||
msgstr "Transfer to"
|
||||
|
||||
msgctxt "field:cashbook.planner,currency_cashbook:"
|
||||
msgid "Currency"
|
||||
msgstr "Currency"
|
||||
|
||||
msgctxt "help:cashbook.planner,currency_cashbook:"
|
||||
msgid "Currency of Cashbook"
|
||||
msgstr "Currency of Cashbook"
|
||||
|
||||
msgctxt "field:cashbook.planner,amount:"
|
||||
msgid "Amount"
|
||||
msgstr "Amount"
|
||||
|
||||
msgctxt "field:cashbook.planner,category:"
|
||||
msgid "Category"
|
||||
msgstr "Category"
|
||||
|
||||
msgctxt "help:cashbook.planner,category:"
|
||||
msgid "Category for the planned booking"
|
||||
msgstr "Category for the planned booking"
|
||||
|
||||
msgctxt "field:cashbook.planner,booktransf:"
|
||||
msgid "Source/Dest"
|
||||
msgstr "Source/Dest"
|
||||
|
||||
msgctxt "field:cashbook.planner,owner_cashbook:"
|
||||
msgid "Owner"
|
||||
msgstr "Owner"
|
||||
|
||||
msgctxt "field:cashbook.planner,state_cashbook:"
|
||||
msgid "State of Cashbook"
|
||||
msgstr "State of Cashbook"
|
||||
|
||||
msgctxt "field:cashbook.planner,subject:"
|
||||
msgid "Booking text"
|
||||
msgstr "Booking text"
|
||||
|
||||
msgctxt "field:cashbook.planner,wfcheck:"
|
||||
msgid "Set to 'Checked'"
|
||||
msgstr "Set to 'Checked'"
|
||||
|
||||
msgctxt "help:cashbook.planner,wfcheck:"
|
||||
msgid "Switches the booking to the 'Verified' state."
|
||||
msgstr "Switches the booking to the 'Verified' state."
|
||||
|
||||
msgctxt "model:cashbook.planner.nextrun,name:"
|
||||
msgid "Next Execution Date"
|
||||
msgstr "Next Execution Date"
|
||||
|
|
140
planner.py
140
planner.py
|
@ -3,6 +3,7 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the
|
||||
# full copyright notices and license terms.
|
||||
|
||||
from decimal import Decimal
|
||||
from datetime import date, timedelta
|
||||
from dateutil.rrule import (
|
||||
rrule, YEARLY, MONTHLY, WEEKLY, DAILY, MO, TU, WE, TH, FR, SA, SU)
|
||||
|
@ -11,9 +12,15 @@ from trytond.transaction import Transaction
|
|||
from trytond.pool import Pool
|
||||
from trytond.report import Report
|
||||
from trytond.pyson import Eval, Bool, If, And
|
||||
from trytond.modules.cashbook.line import sel_bookingtype
|
||||
from trytond.modules.currency.fields import Monetary
|
||||
from trytond.modules.cashbook.book import sel_state_book
|
||||
from trytond.modules.cashbook.line import sel_bookingtype as sel_bookingtype_cb
|
||||
|
||||
|
||||
sel_bookingtype = [
|
||||
x for x in sel_bookingtype_cb if x[0]
|
||||
in ['in', 'out', 'mvin', 'mvout']]
|
||||
|
||||
DEF_NONE = None
|
||||
SEL_FREQU = [
|
||||
('year', 'Yearly'),
|
||||
|
@ -97,6 +104,48 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
bookingtype = fields.Selection(
|
||||
string='Type', selection=sel_bookingtype, required=True,
|
||||
help='Type of Booking')
|
||||
currency_cashbook = fields.Function(fields.Many2One(
|
||||
string='Currency', help='Currency of Cashbook',
|
||||
model_name='currency.currency'), 'on_change_with_currency_cashbook')
|
||||
amount = Monetary(
|
||||
string='Amount', currency='currency_cashbook',
|
||||
digits='currency_cashbook', required=True)
|
||||
category = fields.Many2One(
|
||||
string='Category', model_name='cashbook.category',
|
||||
help='Category for the planned booking', depends=['bookingtype'],
|
||||
states={
|
||||
'required': Eval('bookingtype', '').in_(['in', 'out']),
|
||||
'invisible': ~Eval('bookingtype', '').in_(['in', 'out'])})
|
||||
party = fields.Many2One(
|
||||
string='Party', model_name='party.party', depends=['bookingtype'],
|
||||
states={
|
||||
'required': Eval('bookingtype', '').in_(['in', 'out']),
|
||||
'invisible': ~Eval('bookingtype', '').in_(['in', 'out'])})
|
||||
booktransf = fields.Many2One(
|
||||
string='Source/Dest',
|
||||
ondelete='RESTRICT', model_name='cashbook.book',
|
||||
domain=[
|
||||
('owner.id', '=', Eval('owner_cashbook', -1)),
|
||||
('id', '!=', Eval('cashbook', -1)),
|
||||
('btype', '!=', None)],
|
||||
states={
|
||||
'readonly': Eval('state_cashbook', '') != 'open',
|
||||
'invisible': ~Eval('bookingtype', '').in_(['mvin', 'mvout']),
|
||||
'required': Eval('bookingtype', '').in_(['mvin', 'mvout'])},
|
||||
depends=[
|
||||
'state_cashbook', 'bookingtype', 'owner_cashbook', 'cashbook'])
|
||||
owner_cashbook = fields.Function(fields.Many2One(
|
||||
string='Owner', readonly=True,
|
||||
states={'invisible': True}, model_name='res.user'),
|
||||
'on_change_with_owner_cashbook')
|
||||
state_cashbook = fields.Function(fields.Selection(
|
||||
string='State of Cashbook',
|
||||
readonly=True, states={'invisible': True}, selection=sel_state_book),
|
||||
'on_change_with_state_cashbook')
|
||||
subject = fields.Text(string='Booking text', required=True)
|
||||
wfcheck = fields.Boolean(
|
||||
string="Set to 'Checked'",
|
||||
help="Switches the booking to the 'Verified' state.")
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
|
@ -177,6 +226,19 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
break
|
||||
return result
|
||||
|
||||
@fields.depends('cashbook', '_parent_cashbook.currency')
|
||||
def on_change_with_currency_cashbook(self, name=None):
|
||||
""" get currency of selected cashbook
|
||||
|
||||
Args:
|
||||
name (str, optional): name of field. Defaults to None.
|
||||
|
||||
Returns:
|
||||
int: id of cashbook currency
|
||||
"""
|
||||
if self.cashbook:
|
||||
return self.cashbook.currency.id
|
||||
|
||||
@fields.depends('nextrun')
|
||||
def on_change_with_nextrun_link(self, name=None):
|
||||
""" get nextrun-record if exist
|
||||
|
@ -229,6 +291,30 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
'setpos': self.setpos}
|
||||
)])
|
||||
|
||||
@fields.depends('cashbook', '_parent_cashbook.owner')
|
||||
def on_change_with_owner_cashbook(self, name=None):
|
||||
""" get current owner
|
||||
"""
|
||||
if self.cashbook:
|
||||
return self.cashbook.owner.id
|
||||
|
||||
@fields.depends('cashbook', '_parent_cashbook.state')
|
||||
def on_change_with_state_cashbook(self, name=None):
|
||||
""" get state of cashbook
|
||||
"""
|
||||
if self.cashbook:
|
||||
return self.cashbook.state
|
||||
|
||||
@fields.depends('bookingtype', 'category', 'booktransf')
|
||||
def on_change_bookingtype(self):
|
||||
""" reset category/booktransf on change of bookingtype
|
||||
"""
|
||||
if self.bookingtype:
|
||||
if self.bookingtype in ['in', 'out']:
|
||||
self.booktransf = None
|
||||
elif self.bookingtype in ['mvin', 'mvout']:
|
||||
self.category = None
|
||||
|
||||
@fields.depends('frequ', 'setpos', 'weekday', 'monthday')
|
||||
def on_change_frequ(self):
|
||||
""" update fields
|
||||
|
@ -254,6 +340,24 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
"""
|
||||
self.on_change_frequ()
|
||||
|
||||
@classmethod
|
||||
def default_wfcheck(cls):
|
||||
""" False as default for wf-state 'checked'
|
||||
|
||||
Returns:
|
||||
bool: False
|
||||
"""
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def default_amount(cls):
|
||||
""" default for amount
|
||||
|
||||
Returns:
|
||||
Decimal: 0.00
|
||||
"""
|
||||
return Decimal('0.0')
|
||||
|
||||
@classmethod
|
||||
def default_interval(cls):
|
||||
""" get default for interval
|
||||
|
@ -387,8 +491,40 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
def run_booking(cls, records):
|
||||
""" do prepared booking
|
||||
"""
|
||||
pool = Pool()
|
||||
IrDate = pool.get('ir.date')
|
||||
Line = pool.get('cashbook.line')
|
||||
|
||||
to_create = []
|
||||
to_create_check = []
|
||||
for record in records:
|
||||
print('-- booking:', record.rec_name)
|
||||
line = {
|
||||
'cashbook': record.cashbook.id,
|
||||
'bookingtype': record.bookingtype,
|
||||
'date': IrDate.today(),
|
||||
'amount': record.amount,
|
||||
'description': record.subject}
|
||||
|
||||
if record.bookingtype in ['in', 'out']:
|
||||
if record.category:
|
||||
line['category'] = record.category.id
|
||||
if record.party:
|
||||
line['party'] = record.party.id
|
||||
elif record.bookingtype in ['mvin', 'mvout']:
|
||||
if record.booktransf:
|
||||
line['booktransf'] = record.booktransf.id
|
||||
|
||||
if record.wfcheck:
|
||||
to_create_check.append(line)
|
||||
else:
|
||||
to_create.append(line)
|
||||
|
||||
if to_create_check:
|
||||
lines = Line.create(to_create_check)
|
||||
Line.wfcheck(lines)
|
||||
|
||||
if to_create:
|
||||
Line.create(to_create)
|
||||
|
||||
@classmethod
|
||||
def cronjob(cls):
|
||||
|
|
118
tests/planner.py
118
tests/planner.py
|
@ -3,6 +3,7 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the
|
||||
# full copyright notices and license terms.
|
||||
|
||||
from decimal import Decimal
|
||||
from unittest.mock import MagicMock
|
||||
from trytond.tests.test_tryton import with_transaction
|
||||
from trytond.pool import Pool
|
||||
|
@ -19,6 +20,7 @@ class PlannerTestCase(object):
|
|||
pool = Pool()
|
||||
Book = pool.get('cashbook.book')
|
||||
Planner = pool.get('cashbook.planner')
|
||||
Party = pool.get('party.party')
|
||||
|
||||
types = self.prep_type()
|
||||
company = self.prep_company()
|
||||
|
@ -36,11 +38,18 @@ class PlannerTestCase(object):
|
|||
}])
|
||||
self.assertEqual(book.rec_name, 'Book 1 | 0.00 usd | Open')
|
||||
|
||||
category = self.prep_category()
|
||||
party, = Party.create([{
|
||||
'name': 'Party',
|
||||
'addresses': [('create', [{}])]}])
|
||||
job, = Planner.create([{
|
||||
'cashbook': book.id,
|
||||
'name': name,
|
||||
'start_date': date(2022, 5, 1),
|
||||
'bookingtype': 'out'}])
|
||||
'bookingtype': 'out',
|
||||
'category': category.id,
|
||||
'party': party.id,
|
||||
'subject': 'Booking text'}])
|
||||
# check applied defaults
|
||||
self.assertEqual(job.rec_name, 'Job 1')
|
||||
self.assertEqual(job.start_date, date(2022, 5, 1))
|
||||
|
@ -286,4 +295,111 @@ class PlannerTestCase(object):
|
|||
|
||||
IrDate.today = MagicMock(return_value=date.today())
|
||||
|
||||
@with_transaction()
|
||||
def test_planner_cronjobs_booking_with_category(self):
|
||||
""" create job, configure booking with category, run job
|
||||
"""
|
||||
pool = Pool()
|
||||
Planner = pool.get('cashbook.planner')
|
||||
IrDate = pool.get('ir.date')
|
||||
Category = pool.get('cashbook.category')
|
||||
Cashbook = pool.get('cashbook.book')
|
||||
|
||||
job = self.prep_create_job()
|
||||
self.assertEqual(
|
||||
job._compute_dates_by_rrule(
|
||||
count=1, query_date=date(2022, 5, 1)), [
|
||||
date(2022, 5, 1)])
|
||||
|
||||
IrDate.today = MagicMock(return_value=date(2022, 5, 24))
|
||||
|
||||
category, = Category.search([('name', '=', 'Cat1')])
|
||||
Planner.write(*[
|
||||
[job],
|
||||
{
|
||||
'name': 'Booking to category',
|
||||
'amount': Decimal('10.0'),
|
||||
'bookingtype': 'out',
|
||||
'category': category.id,
|
||||
'subject': 'booking ${month}/${year}, ${date}',
|
||||
'wfcheck': True,
|
||||
}])
|
||||
self.assertEqual(job.rec_name, 'Booking to category')
|
||||
self.assertEqual(job.cashbook.rec_name, 'Book 1 | 0.00 usd | Open')
|
||||
self.assertEqual(len(job.cashbook.lines), 0)
|
||||
|
||||
job, = Planner.search([])
|
||||
self.assertEqual(job.nextrun[0].date, date(2022, 6, 1))
|
||||
IrDate.today = MagicMock(return_value=date(2022, 6, 1))
|
||||
Planner.cronjob()
|
||||
self.assertEqual(job.nextrun[0].date, date(2022, 7, 1))
|
||||
|
||||
# check cashbook
|
||||
self.assertEqual(len(job.cashbook.lines), 1)
|
||||
self.assertEqual(
|
||||
job.cashbook.lines[0].rec_name,
|
||||
"06/01/2022|Exp|-10.00 usd|booking " +
|
||||
"${month}/${year}, ${date} [Cat1]")
|
||||
self.assertEqual(job.cashbook.lines[0].state, 'check')
|
||||
|
||||
with Transaction().set_context({'date': date(2022, 6, 1)}):
|
||||
cashbook, = Cashbook.browse([job.cashbook])
|
||||
self.assertEqual(cashbook.rec_name, 'Book 1 | -10.00 usd | Open')
|
||||
|
||||
IrDate.today = MagicMock(return_value=date.today())
|
||||
|
||||
@with_transaction()
|
||||
def test_planner_cronjobs_booking_transfer_nonasset_eur(self):
|
||||
""" create job, configure transfer-booking to non-asset-cashbook,
|
||||
run job
|
||||
"""
|
||||
pool = Pool()
|
||||
Planner = pool.get('cashbook.planner')
|
||||
IrDate = pool.get('ir.date')
|
||||
Category = pool.get('cashbook.category')
|
||||
Cashbook = pool.get('cashbook.book')
|
||||
|
||||
job = self.prep_create_job()
|
||||
self.assertEqual(
|
||||
job._compute_dates_by_rrule(
|
||||
count=1, query_date=date(2022, 5, 1)), [
|
||||
date(2022, 5, 1)])
|
||||
|
||||
IrDate.today = MagicMock(return_value=date(2022, 5, 24))
|
||||
|
||||
category, = Category.search([('name', '=', 'Cat1')])
|
||||
Planner.write(*[
|
||||
[job],
|
||||
{
|
||||
'name': 'Booking to category',
|
||||
'amount': Decimal('10.0'),
|
||||
'bookingtype': 'out',
|
||||
'category': category.id,
|
||||
'subject': 'booking ${month}/${year}, ${date}',
|
||||
'wfcheck': True,
|
||||
}])
|
||||
self.assertEqual(job.rec_name, 'Booking to category')
|
||||
self.assertEqual(job.cashbook.rec_name, 'Book 1 | 0.00 usd | Open')
|
||||
self.assertEqual(len(job.cashbook.lines), 0)
|
||||
|
||||
job, = Planner.search([])
|
||||
self.assertEqual(job.nextrun[0].date, date(2022, 6, 1))
|
||||
IrDate.today = MagicMock(return_value=date(2022, 6, 1))
|
||||
Planner.cronjob()
|
||||
self.assertEqual(job.nextrun[0].date, date(2022, 7, 1))
|
||||
|
||||
# check cashbook
|
||||
self.assertEqual(len(job.cashbook.lines), 1)
|
||||
self.assertEqual(
|
||||
job.cashbook.lines[0].rec_name,
|
||||
"06/01/2022|Exp|-10.00 usd|booking " +
|
||||
"${month}/${year}, ${date} [Cat1]")
|
||||
self.assertEqual(job.cashbook.lines[0].state, 'check')
|
||||
|
||||
with Transaction().set_context({'date': date(2022, 6, 1)}):
|
||||
cashbook, = Cashbook.browse([job.cashbook])
|
||||
self.assertEqual(cashbook.rec_name, 'Book 1 | -10.00 usd | Open')
|
||||
|
||||
IrDate.today = MagicMock(return_value=date.today())
|
||||
|
||||
# end PlannerTestCase
|
||||
|
|
|
@ -41,6 +41,23 @@ full copyright notices and license terms. -->
|
|||
<page id="booking" col="4" string="Booking">
|
||||
<label name="bookingtype"/>
|
||||
<field name="bookingtype"/>
|
||||
<label name="amount"/>
|
||||
<field name="amount"/>
|
||||
|
||||
<label name="category"/>
|
||||
<field name="category"/>
|
||||
<label name="party"/>
|
||||
<field name="party"/>
|
||||
|
||||
<label name="booktransf"/>
|
||||
<field name="booktransf" colspan="3"/>
|
||||
|
||||
<label name="wfcheck"/>
|
||||
<field name="wfcheck"/>
|
||||
<newline/>
|
||||
|
||||
<separator name="subject" colspan="4" string="Booking text"/>
|
||||
<field name="subject" colspan="4"/>
|
||||
</page>
|
||||
<page name="description" col="1" string="Description">
|
||||
<field name="description"/>
|
||||
|
|
|
@ -8,4 +8,8 @@ full copyright notices and license terms. -->
|
|||
<field name="cashbook"/>
|
||||
<field name="nextrun_link"/>
|
||||
<field name="bookingtype"/>
|
||||
<field name="amount"/>
|
||||
<field name="category"/>
|
||||
<field name="party"/>
|
||||
<field name="booktransf"/>
|
||||
</tree>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue