Enable periods to end on any day of the month

issue8855
review252671002
This commit is contained in:
David Harper committed 2020-02-04 10:10:32 +01:00
1 parent cf6a464261
commit 96a6fb6bce
7 files changed
+233 -116

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
* Allow periods to end on any day of the month
* Use a wizard to select parameters when creating periods
* Modularize code in GroupLines wizard
Version 5.4.0 - 2019-11-04
+74 -72
View File
@@ -2,62 +2,62 @@
# this repository contains the full copyright notices and license terms.
from trytond.pool import Pool
from .fiscalyear import *
from .account import *
from . import account
from . import configuration
from .period import *
from .journal import *
from .move import *
from .move_template import *
from . import tax
from . import fiscalyear
from . import journal
from . import move
from . import move_template
from . import party
from . import period
from . import tax
def register():
Pool.register(
FiscalYear,
BalanceNonDeferralStart,
TypeTemplate,
Type,
AccountTemplate,
AccountTemplateTaxTemplate,
Account,
AccountDeferral,
AccountTax,
OpenChartAccountStart,
GeneralLedgerAccount,
GeneralLedgerAccountContext,
GeneralLedgerLine,
GeneralLedgerLineContext,
BalanceSheetContext,
BalanceSheetComparisionContext,
IncomeStatementContext,
CreateChartStart,
CreateChartAccount,
CreateChartProperties,
UpdateChartStart,
UpdateChartSucceed,
AgedBalanceContext,
AgedBalance,
fiscalyear.FiscalYear,
fiscalyear.BalanceNonDeferralStart,
account.TypeTemplate,
account.Type,
account.AccountTemplate,
account.AccountTemplateTaxTemplate,
account.Account,
account.AccountDeferral,
account.AccountTax,
account.OpenChartAccountStart,
account.GeneralLedgerAccount,
account.GeneralLedgerAccountContext,
account.GeneralLedgerLine,
account.GeneralLedgerLineContext,
account.BalanceSheetContext,
account.BalanceSheetComparisionContext,
account.IncomeStatementContext,
account.CreateChartStart,
account.CreateChartAccount,
account.CreateChartProperties,
account.UpdateChartStart,
account.UpdateChartSucceed,
account.AgedBalanceContext,
account.AgedBalance,
configuration.Configuration,
configuration.ConfigurationDefaultAccount,
configuration.DefaultTaxRule,
Period,
Journal,
JournalSequence,
JournalCashContext,
JournalPeriod,
Move,
Reconciliation,
period.Period,
journal.Journal,
journal.JournalSequence,
journal.JournalCashContext,
journal.JournalPeriod,
move.Move,
move.Reconciliation,
configuration.ConfigurationTaxRounding,
Line,
WriteOff,
OpenJournalAsk,
ReconcileLinesWriteOff,
ReconcileShow,
CancelMovesDefault,
GroupLinesStart,
PrintGeneralJournalStart,
move.Line,
move.WriteOff,
move.OpenJournalAsk,
move.ReconcileLinesWriteOff,
move.ReconcileShow,
move.CancelMovesDefault,
move.GroupLinesStart,
move.PrintGeneralJournalStart,
tax.TaxGroup,
tax.TaxCodeTemplate,
tax.TaxCode,
@@ -73,41 +73,43 @@ def register():
tax.TaxRuleLine,
tax.TestTaxView,
tax.TestTaxViewResult,
MoveTemplate,
MoveTemplateKeyword,
MoveLineTemplate,
TaxLineTemplate,
CreateMoveTemplate,
CreateMoveKeywords,
move_template.MoveTemplate,
move_template.MoveTemplateKeyword,
move_template.MoveLineTemplate,
move_template.TaxLineTemplate,
move_template.CreateMoveTemplate,
move_template.CreateMoveKeywords,
party.Party,
party.PartyAccount,
RenewFiscalYearStart,
fiscalyear.CreatePeriodsStart,
fiscalyear.RenewFiscalYearStart,
module='account', type_='model')
Pool.register(
OpenType,
BalanceNonDeferral,
OpenChartAccount,
CreateChart,
UpdateChart,
OpenJournal,
OpenAccount,
ReconcileLines,
UnreconcileLines,
Reconcile,
CancelMoves,
GroupLines,
PrintGeneralJournal,
CreateMove,
account.OpenType,
fiscalyear.BalanceNonDeferral,
account.OpenChartAccount,
account.CreateChart,
account.UpdateChart,
move.OpenJournal,
move.OpenAccount,
move.ReconcileLines,
move.UnreconcileLines,
move.Reconcile,
move.CancelMoves,
move.GroupLines,
move.PrintGeneralJournal,
move_template.CreateMove,
tax.OpenChartTaxCode,
tax.OpenTaxCode,
tax.TestTax,
party.PartyReplace,
party.PartyErase,
RenewFiscalYear,
fiscalyear.CreatePeriods,
fiscalyear.RenewFiscalYear,
module='account', type_='wizard')
Pool.register(
GeneralLedger,
TrialBalance,
AgedBalanceReport,
GeneralJournal,
account.GeneralLedger,
account.TrialBalance,
account.AgedBalanceReport,
move.GeneralJournal,
module='account', type_='report')
+83 -29
View File
@@ -6,18 +6,16 @@ from dateutil.relativedelta import relativedelta
from trytond.i18n import gettext
from trytond.model import ModelView, ModelSQL, Workflow, fields
from trytond.model.exceptions import AccessError
from trytond.wizard import Wizard, StateView, StateAction, Button
from trytond.pyson import Eval, If, PYSONEncoder
from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.pyson import Eval, If, PYSONEncoder
from trytond.rpc import RPC
from trytond.transaction import Transaction
from trytond.wizard import (
Wizard, StateView, StateTransition, StateAction, Button)
from .exceptions import (FiscalYearNotFoundError, FiscalYearDatesError,
FiscalYearSequenceError, FiscalYearCloseError, FiscalYearReOpenError)
__all__ = ['FiscalYear',
'BalanceNonDeferralStart', 'BalanceNonDeferral',
'RenewFiscalYearStart', 'RenewFiscalYear']
STATES = {
'readonly': Eval('state') != 'open',
}
@@ -73,12 +71,7 @@ class FiscalYear(Workflow, ModelSQL, ModelView):
('close', 'open'),
))
cls._buttons.update({
'create_period': {
'invisible': ((Eval('state') != 'open')
| Eval('periods', [0])),
'depends': ['state'],
},
'create_period_3': {
'create_periods': {
'invisible': ((Eval('state') != 'open')
| Eval('periods', [0])),
'depends': ['state'],
@@ -96,6 +89,9 @@ class FiscalYear(Workflow, ModelSQL, ModelView):
'depends': ['state'],
},
})
cls.__rpc__.update({
'create_period': RPC(readonly=False, instantiate=0),
})
@staticmethod
def default_state():
@@ -181,8 +177,7 @@ class FiscalYear(Workflow, ModelSQL, ModelView):
super(FiscalYear, cls).delete(fiscalyears)
@classmethod
@ModelView.button
def create_period(cls, fiscalyears, interval=1):
def create_period(cls, fiscalyears, interval=1, end_day=31):
'''
Create periods for the fiscal years with month interval
'''
@@ -191,9 +186,10 @@ class FiscalYear(Workflow, ModelSQL, ModelView):
for fiscalyear in fiscalyears:
period_start_date = fiscalyear.start_date
while period_start_date < fiscalyear.end_date:
period_end_date = period_start_date + \
relativedelta(months=interval - 1) + \
relativedelta(day=31)
month_offset = 1 if period_start_date.day < end_day else 0
period_end_date = (period_start_date
+ relativedelta(months=interval - month_offset)
+ relativedelta(day=end_day))
if period_end_date > fiscalyear.end_date:
period_end_date = fiscalyear.end_date
name = period_start_date.strftime('%Y-%m')
@@ -211,12 +207,9 @@ class FiscalYear(Workflow, ModelSQL, ModelView):
Period.create(to_create)
@classmethod
@ModelView.button
def create_period_3(cls, fiscalyears):
'''
Create periods for the fiscal years with 3 months interval
'''
cls.create_period(fiscalyears, interval=3)
@ModelView.button_action('account.act_create_periods')
def create_periods(cls, fiscalyears):
pass
@classmethod
def find(cls, company_id, date=None, exception=True):
@@ -476,8 +469,67 @@ class BalanceNonDeferral(Wizard):
return action, {}
class CreatePeriodsStart(ModelView):
"Create Periods Start"
__name__ = 'account.fiscalyear.create_periods.start'
frequency = fields.Selection([
('monthly', "Monthly"),
('quarterly', "Quarterly"),
('other', "Other"),
], "Frequency", sort=False, required=True)
interval = fields.Integer("Interval", required=True,
states={
'invisible': Eval('frequency') != 'other',
},
depends=['frequency'],
help="The length of each period, in months.")
end_day = fields.Integer("End Day", required=True,
help="The day of the month on which periods end.\n"
"Months with fewer days will end on the last day.")
@classmethod
def default_frequency(cls):
return 'monthly'
@classmethod
def default_end_day(cls):
return 31
@classmethod
def frequency_intervals(cls):
return {
'monthly': 1,
'quarterly': 3,
'other': None,
}
@fields.depends('frequency', 'interval')
def on_change_frequency(self):
if self.frequency:
self.interval = self.frequency_intervals()[self.frequency]
class CreatePeriods(Wizard):
"Create Periods"
__name__ = 'account.fiscalyear.create_periods'
start = StateView('account.fiscalyear.create_periods.start',
'account.fiscalyear_create_periods_start_view_form', [
Button("Cancel", 'end', 'tryton-cancel'),
Button("Create", 'create_periods', 'tryton-ok', default=True),
])
create_periods = StateTransition()
def transition_create_periods(self):
FiscalYear = Pool().get('account.fiscalyear')
fiscalyear = FiscalYear(Transaction().context['active_id'])
FiscalYear.create_period(
[fiscalyear], self.start.interval, self.start.end_day)
return 'end'
def month_delta(d1, d2):
return (d1.year - d2.year) * 12 + d1.month - d2.month
month_offset = 1 if d1.day < d2.day else 0
return (d1.year - d2.year) * 12 + d1.month - d2.month - month_offset
class RenewFiscalYearStart(ModelView):
@@ -577,10 +629,12 @@ class RenewFiscalYear(Wizard):
periods = [p for p in self.start.previous_fiscalyear.periods
if p.type == 'standard']
months = month_delta(fiscalyear.end_date, fiscalyear.start_date) + 1
if len(periods) == months:
FiscalYear.create_period([fiscalyear])
elif len(periods) == months / 3:
FiscalYear.create_period_3([fiscalyear])
interval = months / len(periods)
end_day = max(p.end_date.day
for p in self.start.previous_fiscalyear.periods
if p.type == 'standard')
if interval.is_integer():
FiscalYear.create_period([fiscalyear], interval, end_day)
return fiscalyear
def do_create_(self, action):
+13 -10
View File
@@ -54,16 +54,9 @@ this repository contains the full copyright notices and license terms. -->
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.model.button" id="fiscalyear_create_period_button">
<field name="name">create_period</field>
<field name="string">Create Monthly Periods</field>
<field name="model"
search="[('model', '=', 'account.fiscalyear')]"/>
</record>
<record model="ir.model.button" id="fiscalyear_create_period_3_button">
<field name="name">create_period_3</field>
<field name="string">Create 3 Monthly Periods</field>
<record model="ir.model.button" id="fiscalyear_create_periods_button">
<field name="name">create_periods</field>
<field name="string">Create Periods</field>
<field name="model"
search="[('model', '=', 'account.fiscalyear')]"/>
</record>
@@ -114,6 +107,16 @@ this repository contains the full copyright notices and license terms. -->
<menuitem parent="menu_processing" sequence="40"
action="act_fiscalyear_form_close" id="menu_close_fiscalyear"/>
<record model="ir.ui.view" id="fiscalyear_create_periods_start_view_form">
<field name="model">account.fiscalyear.create_periods.start</field>
<field name="type">form</field>
<field name="name">fiscalyear_create_periods_start_form</field>
</record>
<record model="ir.action.wizard" id="act_create_periods">
<field name="name">Create Periods</field>
<field name="wiz_name">account.fiscalyear.create_periods</field>
</record>
<record model="ir.ui.view"
id="fiscalyear_balance_non_deferral_start_view_form">
<field
+46 -3
View File
@@ -81,13 +81,17 @@ def create_chart(company, tax=False):
create_chart.transition_create_properties()
def get_fiscalyear(company, today=None):
def get_fiscalyear(company, today=None, start_date=None, end_date=None):
pool = Pool()
Sequence = pool.get('ir.sequence')
FiscalYear = pool.get('account.fiscalyear')
if not today:
today = datetime.date.today()
if not start_date:
start_date = today.replace(month=1, day=1)
if not end_date:
end_date = today.replace(month=12, day=31)
sequence, = Sequence.create([{
'name': '%s' % today.year,
@@ -95,8 +99,8 @@ def get_fiscalyear(company, today=None):
'company': company.id,
}])
fiscalyear = FiscalYear(name='%s' % today.year, company=company)
fiscalyear.start_date = today.replace(month=1, day=1)
fiscalyear.end_date = today.replace(month=12, day=31)
fiscalyear.start_date = start_date
fiscalyear.end_date = end_date
fiscalyear.post_move_sequence = sequence
return fiscalyear
@@ -205,6 +209,45 @@ class AccountTestCase(ModuleTestCase):
FiscalYear.create_period([fiscalyear])
self.assertEqual(len(fiscalyear.periods), 12)
@with_transaction()
def test_fiscalyear_create_periods(self):
'Test fiscalyear create periods'
FiscalYear = Pool().get('account.fiscalyear')
company = create_company()
with set_company(company):
year = datetime.date.today().year
date = datetime.date
for start_date, end_date, interval, end_day, num_periods in [
(date(year, 1, 1), date(year, 12, 31), 1, 31, 12),
(date(year + 1, 1, 1), date(year + 1, 12, 31), 3, 31, 4),
(date(year + 2, 1, 1), date(year + 2, 12, 31), 5, 31, 3),
(date(year + 3, 4, 6), date(year + 4, 4, 5), 1, 5, 12),
(date(year + 4, 4, 6), date(year + 5, 4, 5), 3, 5, 4),
(date(year + 5, 4, 6), date(year + 6, 4, 5), 5, 5, 3),
(date(year + 6, 6, 6), date(year + 6, 12, 31), 1, 29, 8),
(date(year + 7, 7, 7), date(year + 7, 12, 31), 3, 29, 3),
(date(year + 8, 1, 1), date(year + 9, 8, 7), 1, 29, 20),
(date(year + 9, 9, 9), date(year + 10, 11, 12), 3, 29, 5),
]:
fiscalyear = get_fiscalyear(
company, start_date, start_date, end_date)
fiscalyear.save()
FiscalYear.create_period([fiscalyear], interval, end_day)
self.assertEqual(len(fiscalyear.periods), num_periods)
self.assertEqual(fiscalyear.periods[-1].end_date, end_date)
self.assertTrue(all(
p.end_date == p.end_date + relativedelta(day=end_day)
for p in fiscalyear.periods[:-1]))
self.assertEqual(fiscalyear.periods[0].start_date, start_date)
self.assertTrue(all(
p1.end_date + relativedelta(days=1) == p2.start_date
for p1, p2 in zip(
fiscalyear.periods[:-1], fiscalyear.periods[1:])))
@with_transaction()
def test_account_debit_credit(self):
'Test account debit/credit'
@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="frequency"/>
<field name="frequency"/>
<label name="interval" string="every"/>
<group col="2" id="interval">
<field name="interval" xexpand="0"/>
<label name="interval" string="months" xalign="0.0" xexpand="1"/>
</group>
<label name="end_day"/>
<field name="end_day"/>
</form>
+1 -2
View File
@@ -14,8 +14,7 @@ this repository contains the full copyright notices and license terms. -->
<page string="Periods" id="periods">
<field name="periods" colspan="4"/>
<group col="-1" colspan="4" id="buttons">
<button name="create_period"/>
<button name="create_period_3"/>
<button name="create_periods"/>
</group>
</page>
<page string="Sequences" id="sequences">