========================= Payment Clearing Scenario ========================= Imports:: >>> import datetime as dt >>> from decimal import Decimal >>> from proteus import Model, Wizard >>> from trytond.modules.account.tests.tools import ( ... create_chart, create_fiscalyear, get_accounts) >>> from trytond.modules.account_invoice.tests.tools import ( ... set_fiscalyear_invoice_sequences) >>> from trytond.modules.company.tests.tools import create_company, get_company >>> from trytond.modules.currency.tests.tools import get_currency >>> from trytond.tests.tools import activate_modules, assertEqual >>> today = dt.date.today() >>> yesterday = today - dt.timedelta(days=1) >>> first = today + dt.timedelta(days=1) Activate modules:: >>> config = activate_modules( ... ['account_payment_clearing', 'account_statement'], ... create_company, create_chart) Get company:: >>> company = get_company() Create fiscal year:: >>> fiscalyear = set_fiscalyear_invoice_sequences( ... create_fiscalyear(today=(yesterday, first))) >>> fiscalyear.click('create_period') Get accounts:: >>> accounts = get_accounts() >>> receivable = accounts['receivable'] >>> revenue = accounts['revenue'] >>> expense = accounts['expense'] >>> payable = accounts['payable'] >>> cash = accounts['cash'] >>> Account = Model.get('account.account') >>> bank_clearing = Account(parent=payable.parent) >>> bank_clearing.name = 'Bank Clearing' >>> bank_clearing.type = payable.type >>> bank_clearing.reconcile = True >>> bank_clearing.deferral = True >>> bank_clearing.save() >>> Journal = Model.get('account.journal') >>> expense_journal, = Journal.find([('code', '=', 'EXP')]) >>> revenue_journal, = Journal.find([('code', '=', 'REV')]) Create payment journal:: >>> PaymentJournal = Model.get('account.payment.journal') >>> payment_journal = PaymentJournal(name='Manual', ... process_method='manual', ... clearing_journal=expense_journal, ... clearing_account=bank_clearing, ... clearing_posting_delay=dt.timedelta(1)) >>> payment_journal.save() Create parties:: >>> Party = Model.get('party.party') >>> supplier = Party(name='Supplier') >>> supplier.save() >>> customer = Party(name='Customer') >>> customer.save() Create payable move:: >>> Move = Model.get('account.move') >>> move = Move() >>> move.journal = expense_journal >>> line = move.lines.new( ... account=payable, party=supplier, maturity_date=today, ... credit=Decimal('50.00')) >>> line = move.lines.new(account=expense, debit=Decimal('50.00')) >>> move.click('post') >>> payable.reload() >>> payable.balance Decimal('-50.00') Partially pay the line:: >>> Payment = Model.get('account.payment') >>> line, = [l for l in move.lines if l.account == payable] >>> pay_line = Wizard('account.move.line.pay', [line]) >>> pay_line.execute('next_') >>> pay_line.form.journal = payment_journal >>> pay_line.execute('next_') >>> payment, = Payment.find() >>> payment.amount = Decimal('30.0') >>> payment.click('submit') >>> payment.click('approve') >>> payment.state 'approved' >>> process_payment = payment.click('process_wizard') >>> payment.state 'processing' Succeed payment:: >>> succeed = payment.click('succeed_wizard') >>> succeed.form.date = first >>> succeed.execute('succeed') >>> payment.state 'succeeded' >>> assertEqual(payment.clearing_move.date, first) >>> payment.clearing_move.state 'draft' >>> bool(payment.clearing_reconciled) False >>> payable.reload() >>> payable.balance Decimal('-20.00') >>> bank_clearing.reload() >>> bank_clearing.balance Decimal('-30.00') >>> payment.line.reconciliation Fail payment:: >>> payment.click('fail') >>> payment.state 'failed' >>> payment.clearing_move >>> bool(payment.clearing_reconciled) False >>> payment.line.reconciliation >>> payable.reload() >>> payable.balance Decimal('-50.00') >>> bank_clearing.reload() >>> bank_clearing.balance Decimal('0.00') Pay the line:: >>> line, = [l for l in move.lines if l.account == payable] >>> pay_line = Wizard('account.move.line.pay', [line]) >>> pay_line.execute('next_') >>> pay_line.form.journal = payment_journal >>> pay_line.execute('next_') >>> payment, = Payment.find([('state', '=', 'draft')]) >>> payment.amount Decimal('50.00') >>> payment.click('submit') >>> payment.click('approve') >>> payment.state 'approved' >>> process_payment = payment.click('process_wizard') >>> payment.state 'processing' Succeed payment:: >>> succeed = payment.click('succeed_wizard') >>> succeed.execute('succeed') >>> payment.state 'succeeded' >>> payment.clearing_move.state 'draft' >>> payable.reload() >>> payable.balance Decimal('0.00') >>> bank_clearing.reload() >>> bank_clearing.balance Decimal('-50.00') >>> bool(payment.line.reconciliation) True Fail payment:: >>> payment.click('fail') >>> payment.state 'failed' >>> payment.clearing_move >>> payment.line.reconciliation Succeed payment and post clearing:: >>> succeed = payment.click('succeed_wizard') >>> succeed.form.date = yesterday >>> succeed.execute('succeed') >>> payment.state 'succeeded' >>> Cron = Model.get('ir.cron') >>> Company = Model.get('company.company') >>> cron_post_clearing_moves, = Cron.find([ ... ('method', '=', ... 'account.payment.journal|cron_post_clearing_moves'), ... ]) >>> cron_post_clearing_moves.companies.append(Company(company.id)) >>> cron_post_clearing_moves.click('run_once') >>> payment.reload() >>> clearing_move = payment.clearing_move >>> clearing_move.state 'posted' Fail payment with posted clearing:: >>> payment.click('fail') >>> payment.state 'failed' >>> payment.clearing_move >>> bool(payment.clearing_reconciled) False >>> payment.line.reconciliation >>> clearing_move.reload() >>> line, = [l for l in clearing_move.lines ... if l.account == payment.line.account] >>> bool(line.reconciliation) True Succeed payment to use on statement:: >>> succeed = payment.click('succeed_wizard') >>> succeed.execute('succeed') >>> payment.state 'succeeded' Create statement:: >>> StatementJournal = Model.get('account.statement.journal') >>> Statement = Model.get('account.statement') >>> account_journal, = Journal.find([('code', '=', 'STA')], limit=1) >>> statement_journal = StatementJournal(name='Test', ... journal=account_journal, ... account=cash, ... ) >>> statement_journal.save() >>> statement = Statement(name='test', ... journal=statement_journal, ... start_balance=Decimal('0.00'), ... end_balance=Decimal('-50.00'), ... ) Create a line for the payment:: >>> line = statement.lines.new(date=today) >>> line.amount = Decimal('-50.00') >>> line.related_to = payment >>> assertEqual(line.party, supplier) >>> assertEqual(line.account, bank_clearing) Remove the party must remove payment:: >>> line.party = None >>> line.related_to >>> line.related_to = payment Change account must remove payment:: >>> line.account = receivable >>> line.related_to >>> line.account = None >>> line.related_to = payment Validate statement:: >>> statement.click('validate_statement') >>> statement.state 'validated' >>> line, = statement.lines >>> move_line, = [l for l in line.move.lines ... if l.account == bank_clearing] >>> bool(move_line.reconciliation) True >>> bank_clearing.reload() >>> bank_clearing.balance Decimal('0.00') >>> payment.reload() >>> bool(payment.clearing_reconciled) True >>> bool(payment.group.clearing_reconciled) True Unreconcile payment clearing to allow reimbursement:: >>> move_line.reconciliation.delete() >>> payment.reload() >>> bool(payment.clearing_reconciled) False >>> bool(payment.group.clearing_reconciled) False Create a statement that reimburse the payment group:: >>> statement = Statement(name='test', ... journal=statement_journal, ... start_balance=Decimal('-50.00'), ... end_balance=Decimal('0.00'), ... ) >>> line = statement.lines.new(date=today) >>> line.related_to = payment.group >>> assertEqual(line.account, bank_clearing) >>> line.amount = Decimal('50.00') >>> statement.click('validate_statement') >>> statement.state 'validated' Payment must be failed:: >>> payment.reload() >>> payment.state 'failed' Payment in a foreign currency ----------------------------- Create a payment journal in Euro:: >>> euro = get_currency('EUR') >>> euro_payment_journal = PaymentJournal( ... name='Euro Payments', process_method='manual', currency=euro, ... clearing_journal=expense_journal, clearing_account=bank_clearing) >>> euro_payment_journal.save() Create a payable move:: >>> move = Move() >>> move.journal = expense_journal >>> line = move.lines.new( ... account=payable, party=supplier, maturity_date=today, ... credit=Decimal('20.00'), ... amount_second_currency=Decimal('-40.00'), second_currency=euro) >>> line = move.lines.new( ... account=expense, debit=Decimal('20.00'), ... amount_second_currency=Decimal('40.00'), second_currency=euro) >>> move.click('post') Pay the line:: >>> line, = [l for l in move.lines if l.account == payable] >>> pay_line = Wizard('account.move.line.pay', [line]) >>> pay_line.execute('next_') >>> pay_line.form.journal = euro_payment_journal >>> pay_line.execute('next_') >>> payment, = Payment.find([('state', '=', 'draft')]) >>> payment.amount Decimal('40.00') >>> payment.click('submit') >>> payment.click('approve') >>> process_payment = payment.click('process_wizard') >>> payment.state 'processing' Succeed payment:: >>> succeed = payment.click('succeed_wizard') >>> succeed.execute('succeed') >>> debit_line, = [l for l in payment.clearing_move.lines if l.debit > 0] >>> debit_line.debit Decimal('20.00') >>> debit_line.amount_second_currency Decimal('40.00') Create receivable move:: >>> move = Move() >>> move.journal = revenue_journal >>> line = move.lines.new( ... account=receivable, party=customer, maturity_date=today, ... debit=Decimal('50.00'), second_currency=euro, ... amount_second_currency=Decimal('100.0')) >>> line = move.lines.new(account=revenue, credit=Decimal('50.00')) >>> move.click('post') >>> receivable.reload() >>> receivable.balance Decimal('50.00') Pay the line:: >>> Payment = Model.get('account.payment') >>> line, = [l for l in move.lines if l.account == receivable] >>> pay_line = Wizard('account.move.line.pay', [line]) >>> pay_line.execute('next_') >>> pay_line.form.journal = euro_payment_journal >>> pay_line.execute('next_') >>> payment, = Payment.find([('state', '=', 'draft')]) >>> payment.amount Decimal('100.0') >>> payment.click('submit') >>> process_payment = payment.click('process_wizard') >>> payment.state 'processing' Succeed payment:: >>> succeed = payment.click('succeed_wizard') >>> succeed.execute('succeed') >>> credit_line, = [l for l in payment.clearing_move.lines if l.credit > 0] >>> credit_line.credit Decimal('50.00') >>> credit_line.amount_second_currency Decimal('-100.0') Validate Statement with processing payment -------------------------------------------- Create a payable move:: >>> move = Move() >>> move.journal = expense_journal >>> line = move.lines.new( ... account=payable, party=supplier, maturity_date=today, ... credit=Decimal('50.00')) >>> line = move.lines.new(account=expense, debit=Decimal('50.00')) >>> move.click('post') Create a processing payment for the move:: >>> Payment = Model.get('account.payment') >>> line, = [l for l in move.lines if l.account == payable] >>> pay_line = Wizard('account.move.line.pay', [line]) >>> pay_line.execute('next_') >>> pay_line.form.journal = payment_journal >>> pay_line.execute('next_') >>> payment, = Payment.find([('line', '=', line.id)]) >>> payment.click('submit') >>> payment.click('approve') >>> payment.state 'approved' >>> process_payment = payment.click('process_wizard') >>> payment.state 'processing' Create statement for the payment:: >>> statement = Statement(name='test', ... journal=statement_journal, ... start_balance=Decimal('0.00'), ... end_balance=Decimal('-50.00')) >>> line = statement.lines.new(date=yesterday) >>> line.amount = Decimal('-50.00') >>> line.related_to = payment >>> assertEqual(line.party, supplier) >>> assertEqual(line.account, bank_clearing) >>> statement.save() Validate statement and check the payment is confirmed:: >>> statement.click('validate_statement') >>> statement.state 'validated' >>> line, = statement.lines >>> move_line, = [l for l in line.move.lines ... if l.account == bank_clearing] >>> bool(move_line.reconciliation) True >>> payment.reload() >>> payment.state 'succeeded' >>> bool(payment.clearing_reconciled) True >>> debit_line, = [l for l in payment.clearing_move.lines if l.debit > 0] >>> debit_line.debit Decimal('50.00') >>> assertEqual(debit_line.date, yesterday)