Add invoice payment method
issue7450 review45561002
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -35,6 +35,7 @@ def register():
|
||||
Move,
|
||||
MoveLine,
|
||||
Reconciliation,
|
||||
PaymentMethod,
|
||||
module='account_invoice', type_='model')
|
||||
Pool.register(
|
||||
TestPaymentTerm,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user