changeset 0a4b8d475ed7 in modules/account:default
details: https://hg.tryton.org/modules/account?cmd=changeset&node=0a4b8d475ed7
description:
Add wizard to delegate move lines to another party
issue11645
review429251004
diffstat:
CHANGELOG | 1 +
__init__.py | 2 +
exceptions.py | 4 +
message.xml | 6 +
move.py | 123 ++++++++++++++++++++++++++++++++-
move.xml | 27 +++++++
tests/scenario_move_line_delegate.rst | 106 ++++++++++++++++++++++++++++
view/move_line_delegate_start_form.xml | 12 +++
8 files changed, 278 insertions(+), 3 deletions(-)
diffs (357 lines):
diff -r 0d42af3244b9 -r 0a4b8d475ed7 CHANGELOG
--- a/CHANGELOG Sun Sep 11 15:15:12 2022 +0200
+++ b/CHANGELOG Sun Sep 11 17:45:41 2022 +0200
@@ -1,3 +1,4 @@
+* Add wizard to delegate move lines to another party
* Support date range context for account type amount
* Use context model for chart of accounts and taxes
diff -r 0d42af3244b9 -r 0a4b8d475ed7 __init__.py
--- a/__init__.py Sun Sep 11 15:15:12 2022 +0200
+++ b/__init__.py Sun Sep 11 17:45:41 2022 +0200
@@ -63,6 +63,7 @@
move.RescheduleLinesStart,
move.RescheduleLinesPreview,
move.RescheduleLinesTerm,
+ move.DelegateLinesStart,
tax.TaxGroup,
tax.TaxCodeTemplate,
tax.TaxCode,
@@ -103,6 +104,7 @@
move.CancelMoves,
move.GroupLines,
move.RescheduleLines,
+ move.DelegateLines,
move_template.CreateMove,
tax.OpenTaxCode,
tax.TestTax,
diff -r 0d42af3244b9 -r 0a4b8d475ed7 exceptions.py
--- a/exceptions.py Sun Sep 11 15:15:12 2022 +0200
+++ b/exceptions.py Sun Sep 11 17:45:41 2022 +0200
@@ -99,3 +99,7 @@
class RescheduleLineError(UserError):
pass
+
+
+class DelegateLineError(UserError):
+ pass
diff -r 0d42af3244b9 -r 0a4b8d475ed7 message.xml
--- a/message.xml Sun Sep 11 15:15:12 2022 +0200
+++ b/message.xml Sun Sep 11 17:45:41 2022 +0200
@@ -228,6 +228,12 @@
<record model="ir.message" id="msg_reschedule_line_wrong_amount">
<field name="text">To reschedule the lines you must change the
terms to have a total amount of %(total_amount)s instead of %(amount)s.</field>
</record>
+ <record model="ir.message" id="msg_delegate_line_same_company">
+ <field name="text">You cannot delegate together lines of different
companies.</field>
+ </record>
+ <record model="ir.message" id="msg_delegate_line_same_origins">
+ <field name="text">You cannot delegate together lines with
different origins.</field>
+ </record>
<record model="ir.message" id="msg_cancel_line_delegated">
<field name="text">The moves "%(moves)s" contain grouped lines,
cancelling them will ungroup the lines.</field>
</record>
diff -r 0d42af3244b9 -r 0a4b8d475ed7 move.py
--- a/move.py Sun Sep 11 15:15:12 2022 +0200
+++ b/move.py Sun Sep 11 17:45:41 2022 +0200
@@ -27,9 +27,9 @@
Button, StateAction, StateTransition, StateView, Wizard)
from .exceptions import (
- CancelDelegatedWarning, CancelWarning, DeleteDelegatedWarning,
- GroupLineError, MoveDatesError, PostError, ReconciliationError,
- RescheduleLineError)
+ CancelDelegatedWarning, CancelWarning, DelegateLineError,
+ DeleteDelegatedWarning, GroupLineError, MoveDatesError, PostError,
+ ReconciliationError, RescheduleLineError)
_MOVE_STATES = {
'readonly': Eval('state') == 'posted',
@@ -2577,6 +2577,123 @@
currency = fields.Many2One('currency.currency', "Currency", required=True)
+class DelegateLines(Wizard):
+ "Delegate Lines"
+ __name__ = 'account.move.line.delegate'
+ start = StateView(
+ 'account.move.line.delegate.start',
+ 'account.move_line_delegate_start_view_form', [
+ Button("Cancel", 'end', 'tryton-cancel'),
+ Button("Delegate", 'delegate', 'tryton-ok', default=True),
+ ])
+ delegate = StateAction('account.act_move_form_delegate')
+
+ def default_start(self, fields):
+ values = {}
+ if 'journal' in fields:
+ journals = {l.journal for l in self.records}
+ if len(journals) == 1:
+ journal, = journals
+ values['journal'] = journal.id
+ return values
+
+ def do_delegate(self, action):
+ move = self._delegate_lines(self.records, self.start.party)
+ return action, {'res_id': move.id}
+
+ def _delegate_lines(self, lines, party, date=None):
+ move = self.delegate_lines(lines, party, self.start.journal, date)
+ move.description = self.start.description
+ move.save()
+ return move
+
+ @classmethod
+ def delegate_lines(cls, lines, party, journal, date=None):
+ pool = Pool()
+ Line = pool.get('account.move.line')
+
+ move, counterpart, delegated = cls.get_move(
+ lines, party, journal, date=date)
+ move.save()
+ Line.save(counterpart + delegated)
+
+ for line, cline, dline in zip(lines, counterpart, delegated):
+ Line.reconcile([line, cline], delegate_to=dline)
+ return move
+
+ @classmethod
+ def get_move(cls, lines, party, journal, date=None):
+ pool = Pool()
+ Date = pool.get('ir.date')
+ Move = pool.get('account.move')
+ Period = pool.get('account.period')
+
+ try:
+ company, = {l.company for l in lines}
+ except ValueError:
+ raise DelegateLineError(
+ gettext('account.msg_delegate_line_same_company'))
+
+ try:
+ origin, = {l.move.origin for l in lines}
+ except ValueError:
+ raise DelegateLineError(
+ gettext('account.msg_delegate_line_same_origins'))
+
+ if not date:
+ with Transaction().set_context(company=company.id):
+ date = Date.today()
+ period = Period.find(company.id, date=date)
+
+ move = Move()
+ move.company = company
+ move.date = date
+ move.period = period
+ move.journal = journal
+ move.origin = origin
+
+ counterpart = []
+ delegated = []
+ for line in lines:
+ cline = cls.get_move_line(line)
+ cline.move = move
+ cline.debit, cline.credit = line.credit, line.debit
+ if cline.amount_second_currency:
+ cline.amount_second_currency *= -1
+ counterpart.append(cline)
+ dline = cls.get_move_line(line)
+ dline.move = move
+ dline.party = party
+ delegated.append(dline)
+ return move, counterpart, delegated
+
+ @classmethod
+ def get_move_line(cls, line):
+ pool = Pool()
+ Line = pool.get('account.move.line')
+
+ new = Line()
+ new.debit = line.debit
+ new.credit = line.credit
+ new.account = line.account
+ new.origin = line
+ new.description = line.description
+ new.amount_second_currency = line.amount_second_currency
+ new.second_currency = line.second_currency
+ new.party = line.party
+ new.maturity_date = line.maturity_date
+ return new
+
+
+class DelegateLinesStart(ModelView):
+ "Delegate Lines"
+ __name__ = 'account.move.line.delegate.start'
+
+ journal = fields.Many2One('account.journal', "Journal", required=True)
+ party = fields.Many2One('party.party', "Party", required=True)
+ description = fields.Char("Description")
+
+
class GeneralJournal(Report):
__name__ = 'account.move.general_journal'
diff -r 0d42af3244b9 -r 0a4b8d475ed7 move.xml
--- a/move.xml Sun Sep 11 15:15:12 2022 +0200
+++ b/move.xml Sun Sep 11 17:45:41 2022 +0200
@@ -497,6 +497,33 @@
<field name="act_window" ref="act_move_form_rescheduling"/>
</record>
+ <record model="ir.action.wizard" id="act_delegate_lines_wizard">
+ <field name="name">Delegate Lines</field>
+ <field name="wiz_name">account.move.line.delegate</field>
+ <field name="model">account.move.line</field>
+ </record>
+ <record model="ir.action.keyword" id="act_delegate_lines_keyword1">
+ <field name="keyword">form_action</field>
+ <field name="model">account.move.line,-1</field>
+ <field name="action" ref="act_delegate_lines_wizard"/>
+ </record>
+
+ <record model="ir.ui.view" id="move_line_delegate_start_view_form">
+ <field name="model">account.move.line.delegate.start</field>
+ <field name="type">form</field>
+ <field name="name">move_line_delegate_start_form</field>
+ </record>
+
+ <record model="ir.action.act_window" id="act_move_form_delegate">
+ <field name="name">Delegate Account Move</field>
+ <field name="res_model">account.move</field>
+ </record>
+ <record model="ir.action.act_window.view"
id="act_move_form_delegate_view1">
+ <field name="sequence" eval="10"/>
+ <field name="view" ref="move_view_form"/>
+ <field name="act_window" ref="act_move_form_delegate"/>
+ </record>
+
<record model="ir.action.report" id="report_general_journal">
<field name="name">General Journal</field>
<field name="model">account.move</field>
diff -r 0d42af3244b9 -r 0a4b8d475ed7 tests/scenario_move_line_delegate.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/scenario_move_line_delegate.rst Sun Sep 11 17:45:41 2022 +0200
@@ -0,0 +1,106 @@
+=======================
+Delegate Lines Scenario
+=======================
+
+Imports::
+
+ >>> from decimal import Decimal
+
+ >>> from proteus import Model, Wizard
+ >>> from trytond.tests.tools import activate_modules
+ >>> from trytond.modules.currency.tests.tools import get_currency
+ >>> from trytond.modules.company.tests.tools import (
+ ... create_company, get_company)
+ >>> from trytond.modules.account.tests.tools import (
+ ... create_fiscalyear, create_chart, get_accounts)
+
+Activate modules::
+
+ >>> config = activate_modules('account')
+
+ >>> Journal = Model.get('account.journal')
+ >>> Move = Model.get('account.move')
+ >>> Party = Model.get('party.party')
+
+Create company::
+
+ >>> usd = get_currency('USD')
+ >>> eur = get_currency('EUR')
+ >>> _ = create_company(currency=usd)
+ >>> company = get_company()
+
+Create fiscal year::
+
+ >>> fiscalyear = create_fiscalyear(company)
+ >>> fiscalyear.click('create_period')
+ >>> period = fiscalyear.periods[0]
+
+Create chart of accounts::
+
+ >>> _ = create_chart(company)
+ >>> accounts = get_accounts(company)
+
+Create parties::
+
+ >>> party1 = Party(name="Party 1")
+ >>> party1.save()
+ >>> party2 = Party(name="Party 2")
+ >>> party2.save()
+
+Create lines to delegate::
+
+ >>> journal, = Journal.find([
+ ... ('code', '=', 'REV'),
+ ... ])
+
+ >>> move = Move(journal=journal)
+ >>> move.date = period.start_date
+ >>> line = move.lines.new()
+ >>> line.account = accounts['revenue']
+ >>> line.credit = Decimal('100.00')
+ >>> line = move.lines.new()
+ >>> line.account = accounts['receivable']
+ >>> line.party = party1
+ >>> line.debit = Decimal('80.00')
+ >>> line.second_currency = eur
+ >>> line.amount_second_currency = Decimal('100.00')
+ >>> line.maturity_date = period.end_date
+ >>> line = move.lines.new()
+ >>> line.account = accounts['receivable']
+ >>> line.party = party1
+ >>> line.debit = Decimal('20.00')
+ >>> move.save()
+
+ >>> receivable_lines = [
+ ... l for l in move.lines if l.account == accounts['receivable']]
+ >>> accounts['receivable'].reload()
+ >>> accounts['receivable'].balance
+ Decimal('100.00')
+ >>> party1.reload()
+ >>> party1.receivable
+ Decimal('100.00')
+ >>> party2.reload()
+ >>> party2.receivable
+ Decimal('0.0')
+
+Delegate lines::
+
+ >>> delegate = Wizard('account.move.line.delegate', receivable_lines)
+ >>> delegate.form.journal == journal
+ True
+ >>> delegate.form.party = party2
+ >>> delegate.form.description = "Delegate lines"
+ >>> delegate.execute('delegate')
+
+ >>> accounts['receivable'].reload()
+ >>> accounts['receivable'].balance
+ Decimal('100.00')
+ >>> party1.reload()
+ >>> party1.receivable
+ Decimal('0.0')
+ >>> party2.reload()
+ >>> party2.receivable
+ Decimal('100.00')
+
+ >>> all(l.reconciliation.delegate_to for l in receivable_lines)
+ True
diff -r 0d42af3244b9 -r 0a4b8d475ed7 view/move_line_delegate_start_form.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/view/move_line_delegate_start_form.xml Sun Sep 11 17:45:41 2022 +0200
@@ -0,0 +1,12 @@
+<?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="party"/>
+ <field name="party"/>
+ <label name="journal"/>
+ <field name="journal"/>
+
+ <label name="description"/>
+ <field name="description" colspan="3"/>
+</form>