Add invoice payment method

issue7450
review45561002
This commit is contained in:
Sergi Almacellas Abellana
2018-09-01 11:21:06 +02:00
parent a0d25923ea
commit ea724b8a22
11 changed files with 190 additions and 63 deletions
+1
View File
@@ -1,3 +1,4 @@
* Add invoice payment method
* Show number and reference in invoice rec_name
* Remove support for Python 2.7
* Use today as fallback for invoice date report
+1
View File
@@ -35,6 +35,7 @@ def register():
Move,
MoveLine,
Reconciliation,
PaymentMethod,
module='account_invoice', type_='model')
Pool.register(
TestPaymentTerm,
+14
View File
@@ -127,6 +127,20 @@ computed terms base on an amount and a date.
.. note:: The last line of payment term must be a remainder.
Payment Method
**************
The payment options available when paying an invoice. It has the following
fields:
- Name
- Company
- Journal: Will be used for creating the payment move
- Credit Account and Debit Account: The accounts used for the payment move
depending on the amount sign.
- Active: A checkbox that allow to disable the payment method.
Fiscal Year Sequences
*********************
+55 -32
View File
@@ -10,7 +10,7 @@ from sql.conditionals import Coalesce, Case
from sql.functions import Round
from trytond.model import Workflow, ModelView, ModelSQL, fields, Check, \
sequence_ordered, Unique
sequence_ordered, Unique, DeactivableMixin
from trytond.report import Report
from trytond.wizard import Wizard, StateView, StateTransition, StateAction, \
Button
@@ -26,7 +26,7 @@ from trytond.modules.account.tax import TaxableMixin
from trytond.modules.product import price_digits
__all__ = ['Invoice', 'InvoicePaymentLine', 'InvoiceLine',
'InvoiceLineTax', 'InvoiceTax',
'InvoiceLineTax', 'InvoiceTax', 'PaymentMethod',
'InvoiceReport',
'PayInvoiceStart', 'PayInvoiceAsk', 'PayInvoice',
'CreditInvoiceStart', 'CreditInvoice']
@@ -239,16 +239,6 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin):
'invoice "%(invoice)s" on fiscalyear "%(fiscalyear)s".'),
'modify_invoice': ('You can not modify invoice "%s" because '
'it is posted, paid or cancelled.'),
'same_debit_account': ('The debit account on journal '
'"%(journal)s" is the same as invoice "%(invoice)s"\'s '
'account.'),
'missing_debit_account': ('The debit account on journal "%s" '
'is missing.'),
'same_credit_account': ('The credit account on journal '
'"%(journal)s" is the same as invoice "%(invoice)s"\'s '
'account.'),
'missing_credit_account': ('The credit account on journal '
'"%s" is missing.'),
'same_account_on_line': ('Invoice "%(invoice)s" uses the same '
'account "%(account)s" for the invoice and in line '
'"%(line)s".'),
@@ -1190,7 +1180,7 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin):
best = result
return best
def pay_invoice(self, amount, journal, date, description,
def pay_invoice(self, amount, payment_method, date, description,
amount_second_currency=None, second_currency=None):
'''
Adds a payment of amount to an invoice using the journal, date and
@@ -1219,18 +1209,10 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin):
line2.debit, line2.credit = line1.credit, line1.debit
if line2.debit:
account_journal = 'debit_account'
payment_acccount = 'debit_account'
else:
account_journal = 'credit_account'
line2.account = getattr(journal, account_journal)
if self.account == line2.account:
self.raise_user_error('same_%s' % account_journal, {
'journal': journal.rec_name,
'invoice': self.rec_name,
})
if not line2.account:
self.raise_user_error('missing_%s' % account_journal,
(journal.rec_name,))
payment_acccount = 'credit_account'
line2.account = getattr(payment_method, payment_acccount)
for line in lines:
if line.account.party_required:
@@ -1242,7 +1224,8 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin):
period_id = Period.find(self.company.id, date=date)
move = Move(journal=journal, period=period_id, date=date,
move = Move(
journal=payment_method.journal, period=period_id, date=date,
company=self.company, lines=lines)
move.save()
Move.post([move])
@@ -2378,6 +2361,33 @@ class InvoiceTax(sequence_ordered(), ModelSQL, ModelView):
return line
class PaymentMethod(DeactivableMixin, ModelSQL, ModelView):
'Payment Method'
__name__ = 'account.invoice.payment.method'
company = fields.Many2One('company.company', "Company", required=True)
name = fields.Char("Name", required=True, translate=True)
journal = fields.Many2One('account.journal', "Journal", required=True,
domain=[('type', '=', 'cash')])
credit_account = fields.Many2One('account.account', "Credit Account",
required=True,
domain=[
('kind', '!=', 'view'),
('company', '=', Eval('company')),
],
depends=['company'])
debit_account = fields.Many2One('account.account', "Debit Account",
required=True,
domain=[
('kind', '!=', 'view'),
('company', '=', Eval('company')),
],
depends=['company'])
@classmethod
def default_company(cls):
return Transaction().context.get('company')
class InvoiceReport(Report):
__name__ = 'account.invoice'
@@ -2441,8 +2451,17 @@ class PayInvoiceStart(ModelView):
currency = fields.Many2One('currency.currency', 'Currency', required=True)
currency_digits = fields.Integer('Currency Digits', readonly=True)
description = fields.Char('Description', size=None)
journal = fields.Many2One('account.journal', 'Journal', required=True,
domain=[('type', '=', 'cash')])
company = fields.Many2One('company.company', "Company", readonly=True)
invoice_account = fields.Many2One(
'account.account', "Invoice Account", readonly=True)
payment_method = fields.Many2One(
'account.invoice.payment.method', "Payment Method", required=True,
domain=[
('company', '=', Eval('company')),
('debit_account', '!=', Eval('invoice_account')),
('credit_account', '!=', Eval('invoice_account')),
],
depends=['company', 'amount', 'invoice_account'])
date = fields.Date('Date', required=True)
@staticmethod
@@ -2468,14 +2487,16 @@ class PayInvoiceAsk(ModelView):
('writeoff', 'Write-Off'),
('partial', 'Partial Payment'),
], 'Type', required=True)
journal_writeoff = fields.Many2One('account.journal', 'Write-Off Journal',
writeoff = fields.Many2One(
'account.move.reconcile.write_off', "Write Off",
domain=[
('type', '=', 'write-off'),
('company', '=', Eval('company')),
],
states={
'invisible': Eval('type') != 'writeoff',
'required': Eval('type') == 'writeoff',
}, depends=['type'])
},
depends=['company', 'type'])
amount = fields.Numeric('Payment Amount',
digits=(16, Eval('currency_digits', 2)),
readonly=True, depends=['currency_digits'])
@@ -2577,11 +2598,13 @@ class PayInvoice(Wizard):
Invoice = Pool().get('account.invoice')
default = {}
invoice = Invoice(Transaction().context['active_id'])
default['company'] = invoice.company.id
default['currency'] = invoice.currency.id
default['currency_digits'] = invoice.currency.digits
default['amount'] = (invoice.amount_to_pay_today
or invoice.amount_to_pay)
default['description'] = invoice.number
default['invoice_account'] = invoice.account.id
return default
def transition_choice(self):
@@ -2675,7 +2698,7 @@ class PayInvoice(Wizard):
line = None
if not invoice.company.currency.is_zero(amount):
line = invoice.pay_invoice(amount,
self.start.journal, self.start.date,
self.start.payment_method, self.start.date,
self.start.description, amount_second_currency,
second_currency)
@@ -2690,7 +2713,7 @@ class PayInvoice(Wizard):
lines += [line]
if lines:
MoveLine.reconcile(lines,
journal=self.ask.journal_writeoff,
writeoff=self.ask.writeoff,
date=self.start.date)
else:
if line:
+44
View File
@@ -315,6 +315,50 @@ this repository contains the full copyright notices and license terms. -->
<field name="name">pay_ask_form</field>
</record>
<record model="ir.ui.view" id="payment_method_view_form">
<field name="model">account.invoice.payment.method</field>
<field name="type">form</field>
<field name="name">payment_method_form</field>
</record>
<record model="ir.ui.view" id="payment_method_view_list">
<field name="model">account.invoice.payment.method</field>
<field name="type">tree</field>
<field name="name">payment_method_tree</field>
</record>
<record model="ir.action.act_window" id="act_payment_method_form">
<field name="name">Invoice Payment Methods</field>
<field name="res_model">account.invoice.payment.method</field>
</record>
<record model="ir.action.act_window.view" id="act_payment_method_form_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="payment_method_view_list"/>
<field name="act_window" ref="act_payment_method_form"/>
</record>
<record model="ir.action.act_window.view" id="act_payment_method_form_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="payment_method_view_form"/>
<field name="act_window" ref="act_payment_method_form"/>
</record>
<menuitem parent="account.menu_journal_configuration"
action="act_payment_method_form"
id="menu_payment_method_form"/>
<record model="ir.model.access" id="access_payment_method">
<field name="model" search="[('model', '=', 'account.invoice.payment.method')]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_payment_method_account_admin">
<field name="model" search="[('model', '=', 'account.invoice.payment.method')]"/>
<field name="group" ref="account.group_account_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.ui.view" id="credit_start_view_form">
<field name="model">account.invoice.credit.start</field>
<field name="type">form</field>
+25 -15
View File
@@ -62,22 +62,32 @@ Create tax::
>>> credit_note_tax_code = create_tax_code(tax, 'tax', 'credit')
>>> credit_note_tax_code.save()
Set Cash journal::
Create payment method::
>>> Journal = Model.get('account.journal')
>>> journal_cash, = Journal.find([('type', '=', 'cash')])
>>> journal_cash.credit_account = account_cash
>>> journal_cash.debit_account = account_cash
>>> journal_cash.save()
Create Write-Off journal::
>>> PaymentMethod = Model.get('account.invoice.payment.method')
>>> Sequence = Model.get('ir.sequence')
>>> journal_cash, = Journal.find([('type', '=', 'cash')])
>>> payment_method = PaymentMethod()
>>> payment_method.name = 'Cash'
>>> payment_method.journal = journal_cash
>>> payment_method.credit_account = account_cash
>>> payment_method.debit_account = account_cash
>>> payment_method.save()
Create Write Off method::
>>> WriteOff = Model.get('account.move.reconcile.write_off')
>>> sequence_journal, = Sequence.find([('code', '=', 'account.journal')])
>>> journal_writeoff = Journal(name='Write-Off', type='write-off',
... sequence=sequence_journal,
... credit_account=revenue, debit_account=expense)
... sequence=sequence_journal)
>>> journal_writeoff.save()
>>> writeoff_method = WriteOff()
>>> writeoff_method.name = 'Rate loss'
>>> writeoff_method.journal = journal_writeoff
>>> writeoff_method.credit_account = expense
>>> writeoff_method.debit_account = expense
>>> writeoff_method.save()
Create party::
@@ -250,7 +260,7 @@ Pay invoice::
>>> pay.form.amount
Decimal('240.00')
>>> pay.form.amount = Decimal('120.00')
>>> pay.form.journal = journal_cash
>>> pay.form.payment_method = payment_method
>>> pay.execute('choice')
>>> pay.state
'end'
@@ -259,7 +269,7 @@ Pay invoice::
>>> pay.form.amount
Decimal('120.00')
>>> pay.form.amount = Decimal('20.00')
>>> pay.form.journal = journal_cash
>>> pay.form.payment_method = payment_method
>>> pay.execute('choice')
>>> pay.form.type = 'partial'
>>> pay.form.amount
@@ -278,10 +288,10 @@ Pay invoice::
>>> pay.form.amount
Decimal('-20.00')
>>> pay.form.amount = Decimal('99.00')
>>> pay.form.journal = journal_cash
>>> pay.form.payment_method = payment_method
>>> pay.execute('choice')
>>> pay.form.type = 'writeoff'
>>> pay.form.journal_writeoff = journal_writeoff
>>> pay.form.writeoff = writeoff_method
>>> pay.form.amount
Decimal('99.00')
>>> len(pay.form.lines_to_pay)
@@ -349,7 +359,7 @@ Create a paid invoice::
>>> line.unit_price = Decimal('40')
>>> invoice.click('post')
>>> pay = Wizard('account.invoice.pay', [invoice])
>>> pay.form.journal = journal_cash
>>> pay.form.payment_method = payment_method
>>> pay.execute('choice')
>>> pay.state
'end'
+22 -12
View File
@@ -61,22 +61,32 @@ Create tax::
>>> tax = create_tax(Decimal('.10'))
>>> tax.save()
Set Cash journal::
Create payment method::
>>> Journal = Model.get('account.journal')
>>> journal_cash, = Journal.find([('type', '=', 'cash')])
>>> journal_cash.credit_account = account_cash
>>> journal_cash.debit_account = account_cash
>>> journal_cash.save()
Create Write-Off journal::
>>> PaymentMethod = Model.get('account.invoice.payment.method')
>>> Sequence = Model.get('ir.sequence')
>>> journal_cash, = Journal.find([('type', '=', 'cash')])
>>> payment_method = PaymentMethod()
>>> payment_method.name = 'Cash'
>>> payment_method.journal = journal_cash
>>> payment_method.credit_account = account_cash
>>> payment_method.debit_account = account_cash
>>> payment_method.save()
Create writeoff method::
>>> WriteOff = Model.get('account.move.reconcile.write_off')
>>> sequence_journal, = Sequence.find([('code', '=', 'account.journal')])
>>> journal_writeoff = Journal(name='Write-Off', type='write-off',
... sequence=sequence_journal,
... credit_account=revenue, debit_account=expense)
... sequence=sequence_journal)
>>> journal_writeoff.save()
>>> writeoff = WriteOff()
>>> writeoff.name = 'Rate loss'
>>> writeoff.journal = journal_writeoff
>>> writeoff.credit_account = expense
>>> writeoff.debit_account = expense
>>> writeoff.save()
Create party::
@@ -148,11 +158,11 @@ Pay the invoice with rate change::
>>> pay = Wizard('account.invoice.pay', [invoice])
>>> pay.form.amount
Decimal('460.00')
>>> pay.form.journal = journal_cash
>>> pay.form.payment_method = payment_method
>>> pay.form.date = tomorrow
>>> pay.execute('choice')
>>> pay.form.type = 'writeoff'
>>> pay.form.journal_writeoff = journal_writeoff
>>> pay.form.writeoff = writeoff
>>> pay.form.amount
Decimal('460.00')
>>> pay.form.currency == eur
+2 -2
View File
@@ -12,8 +12,8 @@ this repository contains the full copyright notices and license terms. -->
<field name="amount_writeoff"/>
<label name="currency_writeoff"/>
<field name="currency_writeoff"/>
<label name="journal_writeoff"/>
<field name="journal_writeoff"/>
<label name="writeoff"/>
<field name="writeoff"/>
<field name="lines" colspan="4"
view_ids="account_invoice.move_line_view_list_to_pay"/>
<field name="payment_lines" colspan="4"
+2 -2
View File
@@ -8,8 +8,8 @@ this repository contains the full copyright notices and license terms. -->
<field name="currency"/>
<label name="description"/>
<field name="description" colspan="3"/>
<label name="journal"/>
<field name="journal"/>
<label name="payment_method"/>
<field name="payment_method"/>
<label name="date"/>
<field name="date"/>
<field name="currency_digits" colspan="4" invisible="1"/>
+17
View File
@@ -0,0 +1,17 @@
<?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="name"/>
<field name="name"/>
<label name="active"/>
<field name="active"/>
<label name="journal"/>
<field name="journal"/>
<label name="company"/>
<field name="company"/>
<label name="debit_account"/>
<field name="debit_account"/>
<label name="credit_account"/>
<field name="credit_account"/>
</form>
+7
View File
@@ -0,0 +1,7 @@
<?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. -->
<tree>
<field name="company"/>
<field name="name"/>
</tree>