========================== Account Statement Scenario ========================== Imports:: >>> import datetime as dt >>> from decimal import Decimal >>> from proteus import Model, Report >>> from trytond.modules.account.tests.tools import ( ... create_chart, create_fiscalyear, get_accounts) >>> from trytond.modules.account_invoice.tests.tools import ( ... create_payment_term, set_fiscalyear_invoice_sequences) >>> from trytond.modules.company.tests.tools import create_company >>> from trytond.tests.tools import activate_modules, assertEqual >>> today = dt.date.today() Activate modules:: >>> config = activate_modules( ... ['account_statement', 'account_invoice'], ... create_company, create_chart) Create fiscal year:: >>> fiscalyear = set_fiscalyear_invoice_sequences( ... create_fiscalyear(today=today)) >>> fiscalyear.click('create_period') Get accounts:: >>> accounts = get_accounts() >>> receivable = accounts['receivable'] >>> payable = accounts['payable'] >>> revenue = accounts['revenue'] >>> expense = accounts['expense'] >>> cash = accounts['cash'] Create parties:: >>> Party = Model.get('party.party') >>> supplier = Party(name='Supplier') >>> supplier.save() >>> customer = Party(name='Customer') >>> customer.save() Create payment term:: >>> payment_term = create_payment_term() >>> payment_term.save() Create 2 customer invoices:: >>> Invoice = Model.get('account.invoice') >>> customer_invoice1 = Invoice(type='out') >>> customer_invoice1.party = customer >>> customer_invoice1.payment_term = payment_term >>> invoice_line = customer_invoice1.lines.new() >>> invoice_line.quantity = 1 >>> invoice_line.unit_price = Decimal('100') >>> invoice_line.account = revenue >>> invoice_line.description = 'Test' >>> customer_invoice1.click('post') >>> customer_invoice1.state 'posted' >>> customer_invoice2 = Invoice(type='out') >>> customer_invoice2.party = customer >>> customer_invoice2.payment_term = payment_term >>> invoice_line = customer_invoice2.lines.new() >>> invoice_line.quantity = 1 >>> invoice_line.unit_price = Decimal('150') >>> invoice_line.account = revenue >>> invoice_line.description = 'Test' >>> customer_invoice2.click('post') >>> customer_invoice2.state 'posted' Create 1 customer credit note:: >>> customer_credit_note = Invoice(type='out') >>> customer_credit_note.party = customer >>> customer_credit_note.payment_term = payment_term >>> invoice_line = customer_credit_note.lines.new() >>> invoice_line.quantity = -1 >>> invoice_line.unit_price = Decimal('50') >>> invoice_line.account = revenue >>> invoice_line.description = 'Test' >>> customer_credit_note.click('post') >>> customer_credit_note.state 'posted' Create 1 supplier invoices:: >>> supplier_invoice = Invoice(type='in') >>> supplier_invoice.party = supplier >>> supplier_invoice.payment_term = payment_term >>> invoice_line = supplier_invoice.lines.new() >>> invoice_line.quantity = 1 >>> invoice_line.unit_price = Decimal('50') >>> invoice_line.account = expense >>> invoice_line.description = 'Test' >>> supplier_invoice.invoice_date = today >>> supplier_invoice.click('post') >>> supplier_invoice.state 'posted' Create statement:: >>> StatementJournal = Model.get('account.statement.journal') >>> Statement = Model.get('account.statement') >>> StatementLine = Model.get('account.statement.line') >>> AccountJournal = Model.get('account.journal') >>> account_journal, = AccountJournal.find([('code', '=', 'STA')], limit=1) >>> statement_journal = StatementJournal(name='Test', ... journal=account_journal, ... account=cash, ... validation='balance', ... ) >>> statement_journal.save() >>> statement_journal.last_date >>> statement_journal.last_amount >>> statement = Statement(name='test', ... journal=statement_journal, ... start_balance=Decimal('0'), ... end_balance=Decimal('80'), ... date=today, ... ) Received 180 from customer:: >>> statement_line = StatementLine() >>> statement.lines.append(statement_line) >>> statement_line.number = '0001' >>> statement_line.description = 'description' >>> statement_line.date = today >>> statement_line.amount = Decimal('180') >>> statement_line.party = customer >>> assertEqual(statement_line.account, receivable) >>> statement_line.related_to = customer_invoice1 >>> statement_line.amount Decimal('100.00') >>> statement_line = statement.lines[-1] >>> statement_line.amount Decimal('80.00') >>> statement_line.number '0001' >>> statement_line.description 'description' >>> assertEqual(statement_line.party, customer) >>> assertEqual(statement_line.account, receivable) >>> statement_line.description = 'other description' >>> statement_line.related_to = customer_invoice2 >>> statement_line.amount Decimal('80.00') Paid 50 to customer:: >>> statement_line = StatementLine() >>> statement.lines.append(statement_line) >>> statement_line.number = '0002' >>> statement_line.description = 'description' >>> statement_line.date = today >>> statement_line.amount = Decimal('-50') >>> statement_line.party = customer >>> statement_line.account = receivable >>> statement_line.related_to = customer_credit_note Paid 50 to supplier:: >>> statement_line = StatementLine() >>> statement.lines.append(statement_line) >>> statement_line.date = today >>> statement_line.amount = Decimal('-60') >>> statement_line.party = supplier >>> assertEqual(statement_line.account, payable) >>> statement_line.related_to = supplier_invoice >>> statement_line.amount Decimal('-50.00') >>> statement_line = statement.lines[-1] >>> statement_line.amount Decimal('-10.00') Try to overpay supplier invoice:: >>> statement_line.related_to = supplier_invoice >>> statement_line.amount Decimal('-0.00') >>> statement_line = statement.lines.pop() >>> statement_line.amount Decimal('-10.00') >>> statement.save() >>> statement_journal.reload() >>> assertEqual(statement_journal.last_date, today) >>> statement_journal.last_amount Decimal('80.00') Validate statement:: >>> statement.click('validate_statement') >>> statement.state 'validated' Try posting a move:: >>> statement_line = statement.lines[0] >>> statement_line.move.click('post') Traceback (most recent call last): ... trytond.modules.account.exceptions.PostError: ... Cancel statement:: >>> statement.click('cancel') >>> statement.state 'cancelled' >>> [l.move for l in statement.lines if l.move] [] >>> statement_journal.reload() >>> statement_journal.last_date >>> statement_journal.last_amount Reset to draft, validate and post statement:: >>> statement.click('draft') >>> statement.state 'draft' >>> statement.click('validate_statement') >>> statement.state 'validated' >>> statement.click('post') >>> statement.state 'posted' >>> statement_journal.reload() >>> assertEqual(statement_journal.last_date, today) >>> statement_journal.last_amount Decimal('80.00') Test posted moves:: >>> statement_line = statement.lines[0] >>> move = statement_line.move >>> sorted((l.description_used or '' for l in move.lines)) ['description', 'description', 'other description'] >>> statement_line = statement.lines[2] >>> move = statement_line.move >>> sorted((l.description_used or '' for l in move.lines)) ['description', 'description'] Test invoice state:: >>> customer_invoice1.reload() >>> customer_invoice1.state 'paid' >>> customer_invoice2.reload() >>> customer_invoice2.state 'posted' >>> customer_invoice2.amount_to_pay Decimal('70.00') >>> customer_credit_note.reload() >>> customer_credit_note.state 'paid' >>> supplier_invoice.reload() >>> supplier_invoice.state 'paid' Test statement report:: >>> report = Report('account.statement') >>> _ = report.execute([statement], {}) Let's test the negative amount version of the supplier/customer invoices:: >>> customer_invoice3 = Invoice(type='out') >>> customer_invoice3.party = customer >>> customer_invoice3.payment_term = payment_term >>> invoice_line = customer_invoice3.lines.new() >>> invoice_line.quantity = 1 >>> invoice_line.unit_price = Decimal('-120') >>> invoice_line.account = revenue >>> invoice_line.description = 'Test' >>> customer_invoice3.click('post') >>> customer_invoice3.state 'posted' >>> supplier_invoice2 = Invoice(type='in') >>> supplier_invoice2.party = supplier >>> supplier_invoice2.payment_term = payment_term >>> invoice_line = supplier_invoice2.lines.new() >>> invoice_line.quantity = 1 >>> invoice_line.unit_price = Decimal('-40') >>> invoice_line.account = expense >>> invoice_line.description = 'Test' >>> supplier_invoice2.invoice_date = today >>> supplier_invoice2.click('post') >>> supplier_invoice2.state 'posted' >>> statement = Statement(name='test negative', ... journal=statement_journal, ... end_balance=Decimal('0'), ... ) >>> statement_line = StatementLine() >>> statement.lines.append(statement_line) >>> statement_line.date = today >>> statement_line.party = customer >>> statement_line.account = receivable >>> statement_line.amount = Decimal(-120) >>> statement_line.related_to = customer_invoice3 >>> assertEqual(statement_line.related_to, customer_invoice3) >>> statement_line = StatementLine() >>> statement.lines.append(statement_line) >>> statement_line.date = today >>> statement_line.party = supplier >>> statement_line.account = payable >>> statement_line.amount = Decimal(50) >>> statement_line.related_to = supplier_invoice2 >>> statement_line.amount Decimal('40.00') >>> len(statement.lines) 3 >>> statement.lines[-1].amount Decimal('10.00') Testing the use of an invoice in multiple statements:: >>> customer_invoice4 = Invoice(type='out') >>> customer_invoice4.party = customer >>> customer_invoice4.payment_term = payment_term >>> invoice_line = customer_invoice4.lines.new() >>> invoice_line.quantity = 1 >>> invoice_line.unit_price = Decimal('300') >>> invoice_line.account = revenue >>> invoice_line.description = 'Test' >>> customer_invoice4.click('post') >>> customer_invoice4.state 'posted' >>> statement1 = Statement(name='1', journal=statement_journal) >>> statement1.end_balance = Decimal(380) >>> statement_line = statement1.lines.new() >>> statement_line.date = today >>> statement_line.party = customer >>> statement_line.account = receivable >>> statement_line.amount = Decimal(300) >>> statement_line.related_to = customer_invoice4 >>> statement1.save() >>> statement2 = Statement(name='2', journal=statement_journal) >>> statement2.end_balance = Decimal(680) >>> statement_line = statement2.lines.new() >>> statement_line.date = today >>> statement_line.party = customer >>> statement_line.account = receivable >>> statement_line.amount = Decimal(300) >>> statement_line.related_to = customer_invoice4 >>> statement2.save() >>> statement1.click('validate_statement') Traceback (most recent call last): ... StatementValidateWarning: ... >>> statement2.reload() >>> Model.get('res.user.warning')(user=config.user, ... name=str(statement2.lines[0].id), always=True).save() >>> statement1.click('validate_statement') >>> statement1.state 'validated' >>> statement1.reload() >>> bool(statement1.lines[0].related_to) True >>> statement2.reload() >>> bool(statement2.lines[0].related_to) False Testing balance validation:: >>> journal_balance = StatementJournal(name='Balance', ... journal=account_journal, ... account=cash, ... validation='balance', ... ) >>> journal_balance.save() >>> statement = Statement(name='balance') >>> statement.journal = journal_balance >>> statement.start_balance = Decimal('50.00') >>> statement.end_balance = Decimal('150.00') >>> line = statement.lines.new() >>> line.date = today >>> line.amount = Decimal('60.00') >>> line.account = receivable >>> line.party = customer >>> statement.click('validate_statement') Traceback (most recent call last): ... StatementValidateError: ... >>> second_line = statement.lines.new() >>> second_line.date = today >>> second_line.amount = Decimal('40.00') >>> second_line.account = receivable >>> second_line.party = customer >>> statement.click('validate_statement') Testing amount validation:: >>> journal_amount = StatementJournal(name='Amount', ... journal=account_journal, ... account=cash, ... validation='amount', ... ) >>> journal_amount.save() >>> statement = Statement(name='amount') >>> statement.journal = journal_amount >>> statement.total_amount = Decimal('80.00') >>> line = statement.lines.new() >>> line.date = today >>> line.amount = Decimal('50.00') >>> line.account = receivable >>> line.party = customer >>> statement.click('validate_statement') Traceback (most recent call last): ... StatementValidateError: ... >>> second_line = statement.lines.new() >>> second_line.date = today >>> second_line.amount = Decimal('30.00') >>> second_line.account = receivable >>> second_line.party = customer >>> statement.click('validate_statement') Test number of lines validation:: >>> journal_number = StatementJournal(name='Number', ... journal=account_journal, ... account=cash, ... validation='number_of_lines', ... ) >>> journal_number.save() >>> statement = Statement(name='number') >>> statement.journal = journal_number >>> statement.number_of_lines = 2 >>> line = statement.lines.new() >>> line.date = today >>> line.amount = Decimal('50.00') >>> line.account = receivable >>> line.party = customer >>> statement.click('validate_statement') Traceback (most recent call last): ... StatementValidateError: ... >>> second_line = statement.lines.new() >>> second_line.date = today >>> second_line.amount = Decimal('10.00') >>> second_line.account = receivable >>> second_line.party = customer >>> statement.click('validate_statement') Validate empty statement:: >>> statement = Statement(name='empty', journal=statement_journal) >>> statement.end_balance = statement.start_balance >>> statement.click('validate_statement')