diff --git a/CHANGELOG b/CHANGELOG
index 460c53def5..f2fb50c070 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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
diff --git a/__init__.py b/__init__.py
index 422837c506..aa806d4b1c 100644
--- a/__init__.py
+++ b/__init__.py
@@ -35,6 +35,7 @@ def register():
Move,
MoveLine,
Reconciliation,
+ PaymentMethod,
module='account_invoice', type_='model')
Pool.register(
TestPaymentTerm,
diff --git a/doc/index.rst b/doc/index.rst
index d8a4ec55bc..bb72e16758 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -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
*********************
diff --git a/invoice.py b/invoice.py
index cad9b7ba59..ebf43f9184 100644
--- a/invoice.py
+++ b/invoice.py
@@ -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:
diff --git a/invoice.xml b/invoice.xml
index 544e00366f..63b1ad9dec 100644
--- a/invoice.xml
+++ b/invoice.xml
@@ -315,6 +315,50 @@ this repository contains the full copyright notices and license terms. -->
pay_ask_form
+
+ account.invoice.payment.method
+ form
+ payment_method_form
+
+
+ account.invoice.payment.method
+ tree
+ payment_method_tree
+
+
+ Invoice Payment Methods
+ account.invoice.payment.method
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
account.invoice.credit.start
form
diff --git a/tests/scenario_invoice.rst b/tests/scenario_invoice.rst
index eabb4bc7b0..8ae0ce0d45 100644
--- a/tests/scenario_invoice.rst
+++ b/tests/scenario_invoice.rst
@@ -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'
diff --git a/tests/scenario_invoice_alternate_currency.rst b/tests/scenario_invoice_alternate_currency.rst
index e42a6d151e..7136eb7d21 100644
--- a/tests/scenario_invoice_alternate_currency.rst
+++ b/tests/scenario_invoice_alternate_currency.rst
@@ -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
diff --git a/view/pay_ask_form.xml b/view/pay_ask_form.xml
index 91e8517620..5b8393e409 100644
--- a/view/pay_ask_form.xml
+++ b/view/pay_ask_form.xml
@@ -12,8 +12,8 @@ this repository contains the full copyright notices and license terms. -->
-
-
+
+
-
-
+
+
diff --git a/view/payment_method_form.xml b/view/payment_method_form.xml
new file mode 100644
index 0000000000..1a0b5ef923
--- /dev/null
+++ b/view/payment_method_form.xml
@@ -0,0 +1,17 @@
+
+
+
diff --git a/view/payment_method_tree.xml b/view/payment_method_tree.xml
new file mode 100644
index 0000000000..9b9e542ed2
--- /dev/null
+++ b/view/payment_method_tree.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+