Merge lp:~extra-addons-commiter/e-commerce-addons/7.0-sale-method into lp:~extra-addons-commiter/e-commerce-addons/7.0

Proposed by Guewen Baconnier @ Camptocamp
Status: Merged
Merged at revision: 283
Proposed branch: lp:~extra-addons-commiter/e-commerce-addons/7.0-sale-method
Merge into: lp:~extra-addons-commiter/e-commerce-addons/7.0
Diff against target: 1633 lines (+977/-392)
18 files modified
sale_automatic_workflow/invoice.py (+41/-17)
sale_payment_method/__init__.py (+24/-26)
sale_payment_method/__openerp__.py (+40/-45)
sale_payment_method/account_move.py (+30/-0)
sale_payment_method/i18n/fr.po (+142/-0)
sale_payment_method/i18n/sale_payment_method.pot (+141/-0)
sale_payment_method/migrations/0.1/post-migration.py (+2/-2)
sale_payment_method/payment_method.py (+39/-34)
sale_payment_method/payment_method_view.xml (+27/-15)
sale_payment_method/sale.py (+282/-151)
sale_payment_method/sale_view.xml (+40/-16)
sale_quick_payment/__init__.py (+22/-0)
sale_quick_payment/__openerp__.py (+55/-0)
sale_quick_payment/account_voucher.py (+0/-33)
sale_quick_payment/sale_view.xml (+40/-0)
sale_quick_payment/wizard/__init__.py (+1/-1)
sale_quick_payment/wizard/pay_sale_order.py (+50/-51)
sale_quick_payment/wizard/pay_sale_order.xml (+1/-1)
To merge this branch: bzr merge lp:~extra-addons-commiter/e-commerce-addons/7.0-sale-method
Reviewer Review Type Date Requested Status
Maxime Chambreuil (http://www.savoirfairelinux.com) Approve
Sébastien BEAU - http://www.akretion.com Approve
Yannick Vaucher @ Camptocamp Approve
Review via email: mp+155916@code.launchpad.net

Commit message

[IMP] review of sale_quick_payment for the new release of the connectors:

* split module in sale_payment_method and sale_quick_payment
* generate bare account move lines instead of voucher
* onchange when the payment method is modified
* new method to generate a payment using the payment terms and the payment method

Description of the change

This is part of the migration of the connectors (especially magentoerpconnect for my part) to version 7.0 of OpenERP.

This merge proposal aims to improve / adapt the module sale_quick_payment for this new release of the Magentoerpconnect.

Most of the changes were discussed with Sébastien Beau.

List of changes:

* The module 'sale_quick_payment' has been split in 2 modules:
  - 'sale_payment_method' which is the 'underwater' part of the module, it manages the payment methods and the creation of payments
  - 'sale_quick_payment' depends on the former and adds a wizard to generate the payments from the sale order and display them in the 'Automation Information' tab.
  This split allows to use the automatic payments from the connectors without using the manual wizard.

* Pursuing the voucher's killing spree, the payment generated are no longer vouchers but bare accounting move lines.

* In version 6.1, the default fiscal position was directly set by the connectors. Now, it is set by an onchange (the onchange will also be used to set the workflow process in my next merge proposal). The connectors still have to call the onchange.

* New method to generate a payment respecting the terms of the payment terms. The connectors should call this method when they generate a payment. It will allow a correct credit control.

* Fix: when a method is used in a sale order, it can no longer be deleted (FK 'restrict' instead of 'set null')

@Sébastien: I didn't do the migration, you said me you could do it yourself. I pushed my branch on the group extra-addons-commiter so you should be able to add it here.

To post a comment you must log in.
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Hi,

Can I have some reviews on this one please? This will be necessary for the release of the new Magento Connector ;-)

297. By Guewen Baconnier @ Camptocamp

[FIX] fr_FR.po files not loaded, should be named fr.po

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Nitpicking

l35: one space to be removed
l434 and l435 aren't aligned as well
l436: missing #

Or

What about removing those trailing and bothering # as you did in sale_payment_method/sale.py?
:%s/\s\+#$//

in xml files name of the module is named in header comment shouldn't we change it to new name sale_payment_method for this splitted part?

l488 misleader name for view this one is in sale_payment_method and not in sale_quick_payment

l600 + l1222
import of decimal_precision should be
import openerp.addons.decimal_precision as dp

in pay_sale_order.xml there is another
            <field name="type">form</field>
you can remove as you did it in edited xml files

review: Needs Fixing (code, no test)
298. By Guewen Baconnier @ Camptocamp

[CHG] removed the trailing # in the headers

299. By Guewen Baconnier @ Camptocamp

[FIX] use explicit relative import

300. By Guewen Baconnier @ Camptocamp

[FIX] misleading module name

301. By Guewen Baconnier @ Camptocamp

[FIX] misleading module name in views names

302. By Guewen Baconnier @ Camptocamp

[CHG] remove trailing # in headers

303. By Guewen Baconnier @ Camptocamp

[FIX] imports

304. By Guewen Baconnier @ Camptocamp

[FIX] removed deprecated view type

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Thanks for the review, I made the changes.

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Thanks for the changes

LGTM

review: Approve
305. By Sébastien BEAU - http://www.akretion.com

[IMP] sale_payment_method add the possibility to add the description when adding a payment

306. By Sébastien BEAU - http://www.akretion.com

[IMP] sale_quick_payment : add the posibility to specify the description when adding a payment with the wizard

307. By Sébastien BEAU - http://www.akretion.com

[REF] start to refactor sale_payment_method, the aim is to link the sale order to the move line and not the move. Indeed when we import a bank statement and we used the module account_bank_statement_one_move we have 1 one with X customer payment. So we have no choice the sale must be linked to the move lines

308. By Sébastien BEAU - http://www.akretion.com

[FIX] fix bug to due previous refactor, compute correctly the amount paid, link the payment with the sale order, and improve the payment view

Revision history for this message
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote :

Hi Guewen,
As talk before it's better to link the account_move_line instead of the account_move (indeed a move can have X line and each line can be linked to a specific sale order).
I made the change and also I add the possibility to specify a description.

For the migration script I don't know was will be the best solution because we move three time the data model (payment_id => payment_ids => then account move => then account_move_line). Due to this change the actual migration script is broken (indeed the script will not work because the payment is not a voucher anymore). I propose for now to remove the actual migration script and working on it when a customer will want to migrate from 6.1 to 7. What do you think?

As always thanks for your really good

309. By Sébastien BEAU - http://www.akretion.com

[REF] adapte sale_automatic_workflow due to the change as sale order are linked to a account move line

310. By Sébastien BEAU - http://www.akretion.com

[IMP] sle_automatic_workflow : add partial reconciliation

Revision history for this message
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote :

I forget to push some change on sale_automatic workflow, now it ok for me

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

I agree with Sebastien's changes.

Revision history for this message
Sébastien BEAU - http://www.akretion.com (sebastien.beau) :
review: Approve
Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'sale_automatic_workflow/invoice.py'
2--- sale_automatic_workflow/invoice.py 2012-12-26 13:22:11 +0000
3+++ sale_automatic_workflow/invoice.py 2013-10-13 16:10:00 +0000
4@@ -30,21 +30,41 @@
5 'sale_ids': fields.many2many('sale.order', 'sale_order_invoice_rel', 'invoice_id', 'order_id', 'Sale Orders')
6 }
7
8+ def _get_payment(self, cr, uid, invoice, context=None):
9+ if invoice.type == "out_invoice" and invoice.sale_ids:
10+ return invoice.sale_ids[0].payment_ids
11+ return []
12+
13 def _can_be_reconciled(self, cr, uid, invoice, context=None):
14- if not (invoice.sale_ids and invoice.sale_ids[0].payment_ids and invoice.move_id):
15+ payments = self._get_payment(cr, uid, invoice, context=context)
16+ if not (payments and invoice.move_id):
17 return False
18- #Check currency
19- for payment in invoice.sale_ids[0].payment_ids:
20- for move in payment.move_ids:
21- if (move.currency_id.id or invoice.company_id.currency_id.id) != invoice.currency_id.id:
22- return False
23+ # Check currency
24+ company_currency_id = invoice.company_id.currency_id.id
25+ for payment in payments:
26+ currency_id = payment.currency_id.id or company_currency_id
27+ if currency_id != invoice.currency_id.id:
28+ return False
29 return True
30
31- def _get_sum_invoice_move_line(self, cr, uid, move_lines, context=None):
32- return self._get_sum_move_line(cr, uid, move_lines, 'debit', context=None)
33-
34- def _get_sum_payment_move_line(self, cr, uid, move_lines, context=None):
35- return self._get_sum_move_line(cr, uid, move_lines, 'credit', context=None)
36+ def _get_sum_invoice_move_line(self, cr, uid, move_lines,\
37+ invoice_type, context=None):
38+ if invoice_type in ['in_refund', 'out_invoice']:
39+ line_type = 'debit'
40+ else:
41+ line_type = 'credit'
42+ return self._get_sum_move_line(cr, uid, move_lines,\
43+ line_type, context=None)
44+
45+ def _get_sum_payment_move_line(self, cr, uid, move_lines,\
46+ invoice_type, context=None):
47+ if invoice_type in ['in_refund', 'out_invoice']:
48+ line_type = 'credit'
49+ else:
50+ line_type = 'debit'
51+ return self._get_sum_move_line(cr, uid, move_lines,\
52+ line_type, context=None)
53+
54
55 def _get_sum_move_line(self, cr, uid, move_lines, line_type, context=None):
56 res = {
57@@ -93,20 +113,24 @@
58 obj_move_line = self.pool.get('account.move.line')
59 for invoice in self.browse(cr, uid, ids, context=context):
60 use_currency = invoice.currency_id.id != invoice.company_id.currency_id.id
61+ reconcile = False
62+ payment_move_lines = self._get_payment(cr, uid, invoice, context=context)
63+ res_payment = self._get_sum_payment_move_line(cr, uid, payment_move_line, invoice.type, context=context)
64+ res_invoice = self._get_sum_invoice_move_line(cr, uid, invoice.move_id.line_id, invoice.type, context=context)
65+ line_ids = res_invoice['line_ids'] + res_payment['line_ids']
66 if self._can_be_reconciled(cr, uid, invoice, context=context):
67- payment_move_line = []
68- for payment in invoice.sale_ids[0].payment_ids:
69- payment_move_line += payment.move_ids
70- res_payment = self._get_sum_payment_move_line(cr, uid, payment_move_line, context=context)
71- res_invoice = self._get_sum_invoice_move_line(cr, uid, invoice.move_id.line_id, context=context)
72- line_ids = res_invoice['line_ids'] + res_payment['line_ids']
73 if not use_currency:
74 balance = abs(res_invoice['total_amount']-res_payment['total_amount'])
75 if line_ids and not round(balance, precision):
76 obj_move_line.reconcile(cr, uid, line_ids, context=context)
77+ reconcile=True
78 else:
79 balance = abs(res_invoice['total_amount_currency']-res_payment['total_amount_currency'])
80 if line_ids and not round(balance, precision):
81 kwargs = self._prepare_write_off(cr, uid, invoice, res_invoice, res_payment, context=context)
82 obj_move_line.reconcile(cr, uid, line_ids, **kwargs)
83+ reconcile = True
84+ unreconciled_payment = [line for line in payment_move_lines if not line.reconcile_partial_id]
85+ if not reconcile and unreconciled_payment:
86+ move_line_obj.reconcile_partial(cr, uid, line_ids, context=context)
87 return True
88
89=== renamed directory 'sale_quick_payment' => 'sale_payment_method'
90=== modified file 'sale_payment_method/__init__.py'
91--- sale_quick_payment/__init__.py 2012-12-26 13:13:25 +0000
92+++ sale_payment_method/__init__.py 2013-10-13 16:10:00 +0000
93@@ -1,26 +1,24 @@
94-# -*- encoding: utf-8 -*-
95-#################################################################################
96-# #
97-# sale_quick_payment for OpenERP #
98-# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com> #
99-# #
100-# This program is free software: you can redistribute it and/or modify #
101-# it under the terms of the GNU Affero General Public License as #
102-# published by the Free Software Foundation, either version 3 of the #
103-# License, or (at your option) any later version. #
104-# #
105-# This program is distributed in the hope that it will be useful, #
106-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
107-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
108-# GNU Affero General Public License for more details. #
109-# #
110-# You should have received a copy of the GNU Affero General Public License #
111-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
112-# #
113-#################################################################################
114-
115-
116-import sale
117-import payment_method
118-import wizard
119-import account_voucher
120+# -*- coding: utf-8 -*-
121+##############################################################################
122+#
123+# sale_payment_method for OpenERP
124+# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
125+#
126+# This program is free software: you can redistribute it and/or modify
127+# it under the terms of the GNU Affero General Public License as
128+# published by the Free Software Foundation, either version 3 of the
129+# License, or (at your option) any later version.
130+#
131+# This program is distributed in the hope that it will be useful,
132+# but WITHOUT ANY WARRANTY; without even the implied warranty of
133+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
134+# GNU Affero General Public License for more details.
135+#
136+# You should have received a copy of the GNU Affero General Public License
137+# along with this program. If not, see <http://www.gnu.org/licenses/>.
138+#
139+##############################################################################
140+
141+from . import sale
142+from . import payment_method
143+from . import account_move
144
145=== modified file 'sale_payment_method/__openerp__.py'
146--- sale_quick_payment/__openerp__.py 2012-12-26 13:22:58 +0000
147+++ sale_payment_method/__openerp__.py 2013-10-13 16:10:00 +0000
148@@ -1,54 +1,49 @@
149-# -*- encoding: utf-8 -*-
150-###############################################################################
151-# #
152-# sale_quick_payment for OpenERP #
153-# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com> #
154-# #
155-# This program is free software: you can redistribute it and/or modify #
156-# it under the terms of the GNU Affero General Public License as #
157-# published by the Free Software Foundation, either version 3 of the #
158-# License, or (at your option) any later version. #
159-# #
160-# This program is distributed in the hope that it will be useful, #
161-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
162-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
163-# GNU Affero General Public License for more details. #
164-# #
165-# You should have received a copy of the GNU Affero General Public License #
166-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
167-# #
168-###############################################################################
169-
170+# -*- coding: utf-8 -*-
171+##############################################################################
172+#
173+# sale_payment_method for OpenERP
174+# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
175+#
176+# This program is free software: you can redistribute it and/or modify
177+# it under the terms of the GNU Affero General Public License as
178+# published by the Free Software Foundation, either version 3 of the
179+# License, or (at your option) any later version.
180+#
181+# This program is distributed in the hope that it will be useful,
182+# but WITHOUT ANY WARRANTY; without even the implied warranty of
183+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
184+# GNU Affero General Public License for more details.
185+#
186+# You should have received a copy of the GNU Affero General Public License
187+# along with this program. If not, see <http://www.gnu.org/licenses/>.
188+#
189+##############################################################################
190
191 {
192- 'name': 'sale_quick_payment',
193- 'version': '0.1',
194+ 'name': 'Sale Payment Method',
195+ 'version': '0.2',
196 'category': 'Generic Modules/Others',
197 'license': 'AGPL-3',
198 'description': """
199- Sale Quick Payment give the posibility to paid an sale order.
200- The payment will be linked to the sale order
201- If you install the module Sale Automatic Workflow you can forbid the validation
202- of an unpaid order and also the Invoice will be automatically reconciled with
203- the payment.
204- This module was design for e-commerce sector.
205- """,
206+Sale Payment Method
207+===================
208+
209+This module adds low-level features used for instance by modules:
210+
211+- Sale Automatic Workflow
212+- Sale Quick Payment
213+
214+It adds a payment method on the sales orders and allow to register
215+payments entries on sales orders.
216+""",
217 'author': 'Akretion',
218 'website': 'http://www.akretion.com/',
219- 'depends': [
220- 'sale_exceptions',
221- 'account_voucher',
222- ],
223- 'init_xml': [],
224- 'update_xml': [
225- 'wizard/pay_sale_order.xml',
226- 'sale_view.xml',
227- 'payment_method_view.xml',
228- 'security/ir.model.access.csv',
229- 'settings/sale.exception.csv',
230- ],
231- 'demo_xml': [],
232+ 'depends': ['sale',
233+ ],
234+ 'data': ['sale_view.xml',
235+ 'payment_method_view.xml',
236+ 'security/ir.model.access.csv',
237+ ],
238+ 'demo': [],
239 'installable': True,
240- 'active': False,
241 }
242-
243
244=== added file 'sale_payment_method/account_move.py'
245--- sale_payment_method/account_move.py 1970-01-01 00:00:00 +0000
246+++ sale_payment_method/account_move.py 2013-10-13 16:10:00 +0000
247@@ -0,0 +1,30 @@
248+# -*- coding: utf-8 -*-
249+##############################################################################
250+#
251+# Author: Guewen Baconnier
252+# Copyright 2013 Camptocamp SA
253+#
254+# This program is free software: you can redistribute it and/or modify
255+# it under the terms of the GNU Affero General Public License as
256+# published by the Free Software Foundation, either version 3 of the
257+# License, or (at your option) any later version.
258+#
259+# This program is distributed in the hope that it will be useful,
260+# but WITHOUT ANY WARRANTY; without even the implied warranty of
261+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
262+# GNU Affero General Public License for more details.
263+#
264+# You should have received a copy of the GNU Affero General Public License
265+# along with this program. If not, see <http://www.gnu.org/licenses/>.
266+#
267+##############################################################################
268+
269+from openerp.osv import orm, fields
270+
271+
272+class account_move_line(orm.Model):
273+ _inherit = 'account.move.line'
274+
275+ _columns = {
276+ 'sale_ids': fields.many2many('sale.order', string='Sales Orders'),
277+ }
278
279=== added directory 'sale_payment_method/i18n'
280=== added file 'sale_payment_method/i18n/fr.po'
281--- sale_payment_method/i18n/fr.po 1970-01-01 00:00:00 +0000
282+++ sale_payment_method/i18n/fr.po 2013-10-13 16:10:00 +0000
283@@ -0,0 +1,142 @@
284+# Translation of OpenERP Server.
285+# This file contains the translation of the following modules:
286+# * sale_payment_method
287+#
288+msgid ""
289+msgstr ""
290+"Project-Id-Version: OpenERP Server 7.0\n"
291+"Report-Msgid-Bugs-To: \n"
292+"POT-Creation-Date: 2013-05-02 07:06+0000\n"
293+"PO-Revision-Date: 2013-05-02 07:06+0000\n"
294+"Last-Translator: <>\n"
295+"Language-Team: \n"
296+"MIME-Version: 1.0\n"
297+"Content-Type: text/plain; charset=UTF-8\n"
298+"Content-Transfer-Encoding: \n"
299+"Plural-Forms: \n"
300+
301+#. module: sale_payment_method
302+#: view:sale.order:0
303+msgid "Automation Information"
304+msgstr "Informations d'automatisation"
305+
306+#. module: sale_payment_method
307+#: help:payment.method,journal_id:0
308+msgid "If a journal a selected, when a payment is recorded on a backend, payment entries will be created in this journal. "
309+msgstr "Si un journal est sélectionné, lorsqu'un paiement est enregistré sur le backend, des lignes de paiement seront générées dans ce journal."
310+
311+#. module: sale_payment_method
312+#: view:payment.method:0
313+msgid "Even if the E-commerce backend receives a payment for a sale order,\n"
314+" no payment entries will be generated."
315+msgstr "Même si le backend e-commerce reçoit un payment pour un bon de commande, aucune ligne de paiement ne sera générée."
316+
317+#. module: sale_payment_method
318+#: view:payment.method:0
319+msgid "Default Values"
320+msgstr "Valeurs par défaut"
321+
322+#. module: sale_payment_method
323+#: model:ir.model,name:sale_payment_method.model_payment_method
324+#: field:sale.order,payment_method_id:0
325+msgid "Payment Method"
326+msgstr "Méthode de paiement"
327+
328+#. module: sale_payment_method
329+#: view:sale.order:0
330+msgid "View Automatic Payment"
331+msgstr "Voir les paiements automatiques"
332+
333+#. module: sale_payment_method
334+#: help:sale.order,payment_exists:0
335+msgid "It indicates that sales order has at least one payment."
336+msgstr "Indique que la commande a reçu au moins un paiement."
337+
338+#. module: sale_payment_method
339+#: field:payment.method,journal_id:0
340+msgid "Journal"
341+msgstr "Journal"
342+
343+#. module: sale_payment_method
344+#: model:ir.actions.act_window,name:sale_payment_method.act_payment_method_form
345+#: model:ir.ui.menu,name:sale_payment_method.menu_action_paymetn_method_form
346+msgid "Payment Methods "
347+msgstr "Méthodes de paiement"
348+
349+#. module: sale_payment_method
350+#: field:account.move,order_ids:0
351+msgid "Sales Orders"
352+msgstr "Bons de commande"
353+
354+#. module: sale_payment_method
355+#: view:sale.order:0
356+msgid "Other Information"
357+msgstr "Autres informations"
358+
359+#. module: sale_payment_method
360+#: view:payment.method:0
361+msgid "Payment Methods"
362+msgstr "Méthodes de paiement"
363+
364+#. module: sale_payment_method
365+#: field:payment.method,name:0
366+msgid "Name"
367+msgstr "Nom"
368+
369+#. module: sale_payment_method
370+#: field:sale.order,payment_ids:0
371+msgid "Payments Entries"
372+msgstr "Écritures de paiement"
373+
374+#. module: sale_payment_method
375+#: view:payment.method:0
376+msgid "When the E-commerce backend will receive a payment for a sale order,\n"
377+" payment entries will be generated in the selected journal."
378+msgstr "Lorsque le backend e-commerce reçoit un paiement pour la commande,\n"
379+" des écritures de paiement sont générées dans le journal sélectionné."
380+
381+#. module: sale_payment_method
382+#: view:payment.method:0
383+msgid "Journal for payment"
384+msgstr "Journal pour le paiement"
385+
386+#. module: sale_payment_method
387+#: field:sale.order,residual:0
388+msgid "Balance"
389+msgstr "Solde"
390+
391+#. module: sale_payment_method
392+#: model:ir.model,name:sale_payment_method.model_account_move
393+msgid "Account Entry"
394+msgstr "Ecriture"
395+
396+#. module: sale_payment_method
397+#: help:payment.method,payment_term_id:0
398+msgid "Default payment term of a sale order using this method."
399+msgstr "Condition de règlement par défaut pour les commandes utilisant cette méthode."
400+
401+#. module: sale_payment_method
402+#: field:payment.method,payment_term_id:0
403+msgid "Payment Term"
404+msgstr "Condition de règlement"
405+
406+#. module: sale_payment_method
407+#: view:sale.order:0
408+msgid "Create Invoice"
409+msgstr "Créer la facture"
410+
411+#. module: sale_payment_method
412+#: help:payment.method,name:0
413+msgid "The name of the method on the backend"
414+msgstr "Nom de la méthode sur le backend"
415+
416+#. module: sale_payment_method
417+#: model:ir.model,name:sale_payment_method.model_sale_order
418+msgid "Sales Order"
419+msgstr "Bon de commande"
420+
421+#. module: sale_payment_method
422+#: field:sale.order,payment_exists:0
423+msgid "Has automatic payment"
424+msgstr "A un paiement automatique"
425+
426
427=== added file 'sale_payment_method/i18n/sale_payment_method.pot'
428--- sale_payment_method/i18n/sale_payment_method.pot 1970-01-01 00:00:00 +0000
429+++ sale_payment_method/i18n/sale_payment_method.pot 2013-10-13 16:10:00 +0000
430@@ -0,0 +1,141 @@
431+# Translation of OpenERP Server.
432+# This file contains the translation of the following modules:
433+# * sale_payment_method
434+#
435+msgid ""
436+msgstr ""
437+"Project-Id-Version: OpenERP Server 7.0\n"
438+"Report-Msgid-Bugs-To: \n"
439+"POT-Creation-Date: 2013-05-02 07:06+0000\n"
440+"PO-Revision-Date: 2013-05-02 07:06+0000\n"
441+"Last-Translator: <>\n"
442+"Language-Team: \n"
443+"MIME-Version: 1.0\n"
444+"Content-Type: text/plain; charset=UTF-8\n"
445+"Content-Transfer-Encoding: \n"
446+"Plural-Forms: \n"
447+
448+#. module: sale_payment_method
449+#: view:sale.order:0
450+msgid "Automation Information"
451+msgstr ""
452+
453+#. module: sale_payment_method
454+#: help:payment.method,journal_id:0
455+msgid "If a journal a selected, when a payment is recorded on a backend, payment entries will be created in this journal. "
456+msgstr ""
457+
458+#. module: sale_payment_method
459+#: view:payment.method:0
460+msgid "Even if the E-commerce backend receives a payment for a sale order,\n"
461+" no payment entries will be generated."
462+msgstr ""
463+
464+#. module: sale_payment_method
465+#: view:payment.method:0
466+msgid "Default Values"
467+msgstr ""
468+
469+#. module: sale_payment_method
470+#: model:ir.model,name:sale_payment_method.model_payment_method
471+#: field:sale.order,payment_method_id:0
472+msgid "Payment Method"
473+msgstr ""
474+
475+#. module: sale_payment_method
476+#: view:sale.order:0
477+msgid "View Automatic Payment"
478+msgstr ""
479+
480+#. module: sale_payment_method
481+#: help:sale.order,payment_exists:0
482+msgid "It indicates that sales order has at least one payment."
483+msgstr ""
484+
485+#. module: sale_payment_method
486+#: field:payment.method,journal_id:0
487+msgid "Journal"
488+msgstr ""
489+
490+#. module: sale_payment_method
491+#: model:ir.actions.act_window,name:sale_payment_method.act_payment_method_form
492+#: model:ir.ui.menu,name:sale_payment_method.menu_action_paymetn_method_form
493+msgid "Payment Methods "
494+msgstr ""
495+
496+#. module: sale_payment_method
497+#: field:account.move,order_ids:0
498+msgid "Sales Orders"
499+msgstr ""
500+
501+#. module: sale_payment_method
502+#: view:sale.order:0
503+msgid "Other Information"
504+msgstr ""
505+
506+#. module: sale_payment_method
507+#: view:payment.method:0
508+msgid "Payment Methods"
509+msgstr ""
510+
511+#. module: sale_payment_method
512+#: field:payment.method,name:0
513+msgid "Name"
514+msgstr ""
515+
516+#. module: sale_payment_method
517+#: field:sale.order,payment_ids:0
518+msgid "Payments Entries"
519+msgstr ""
520+
521+#. module: sale_payment_method
522+#: view:payment.method:0
523+msgid "When the E-commerce backend will receive a payment for a sale order,\n"
524+" payment entries will be generated in the selected journal."
525+msgstr ""
526+
527+#. module: sale_payment_method
528+#: view:payment.method:0
529+msgid "Journal for payment"
530+msgstr ""
531+
532+#. module: sale_payment_method
533+#: field:sale.order,residual:0
534+msgid "Balance"
535+msgstr ""
536+
537+#. module: sale_payment_method
538+#: model:ir.model,name:sale_payment_method.model_account_move
539+msgid "Account Entry"
540+msgstr ""
541+
542+#. module: sale_payment_method
543+#: help:payment.method,payment_term_id:0
544+msgid "Default payment term of a sale order using this method."
545+msgstr ""
546+
547+#. module: sale_payment_method
548+#: field:payment.method,payment_term_id:0
549+msgid "Payment Term"
550+msgstr ""
551+
552+#. module: sale_payment_method
553+#: view:sale.order:0
554+msgid "Create Invoice"
555+msgstr ""
556+
557+#. module: sale_payment_method
558+#: help:payment.method,name:0
559+msgid "The name of the method on the backend"
560+msgstr ""
561+
562+#. module: sale_payment_method
563+#: model:ir.model,name:sale_payment_method.model_sale_order
564+msgid "Sales Order"
565+msgstr ""
566+
567+#. module: sale_payment_method
568+#: field:sale.order,payment_exists:0
569+msgid "Has automatic payment"
570+msgstr ""
571+
572
573=== modified file 'sale_payment_method/migrations/0.1/post-migration.py'
574--- sale_quick_payment/migrations/0.1/post-migration.py 2012-12-26 13:13:25 +0000
575+++ sale_payment_method/migrations/0.1/post-migration.py 2013-10-13 16:10:00 +0000
576@@ -1,5 +1,5 @@
577 # -*- encoding: utf-8 -*-
578-###############################################################################
579+##############################################################################
580 #
581 # sale_quick_payment for OpenERP
582 # Copyright (C) 2012-TODAY Akretion <http://www.akretion.com>.
583@@ -18,7 +18,7 @@
584 # You should have received a copy of the GNU Affero General Public License
585 # along with this program. If not, see <http://www.gnu.org/licenses/>.
586 #
587-###############################################################################
588+##############################################################################
589
590 """ r0.1: Migration 6.1 => 7.0.0.1
591 migrate the field payment_id from one2many to payment_ids many2many
592
593=== modified file 'sale_payment_method/payment_method.py'
594--- sale_quick_payment/payment_method.py 2012-08-21 13:57:44 +0000
595+++ sale_payment_method/payment_method.py 2013-10-13 16:10:00 +0000
596@@ -1,38 +1,43 @@
597-# -*- encoding: utf-8 -*-
598-###############################################################################
599-# #
600-# sale_quick_payment for OpenERP #
601-# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com> #
602-# #
603-# This program is free software: you can redistribute it and/or modify #
604-# it under the terms of the GNU Affero General Public License as #
605-# published by the Free Software Foundation, either version 3 of the #
606-# License, or (at your option) any later version. #
607-# #
608-# This program is distributed in the hope that it will be useful, #
609-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
610-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
611-# GNU Affero General Public License for more details. #
612-# #
613-# You should have received a copy of the GNU Affero General Public License #
614-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
615-# #
616-###############################################################################
617-
618-from openerp.osv.orm import Model
619-from openerp.osv import fields
620-import netsvc
621-
622-
623-class payment_method(Model):
624-
625+# -*- coding: utf-8 -*-
626+##############################################################################
627+#
628+# sale_quick_payment for OpenERP
629+# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
630+# Copyright 2013 Camptocamp SA (Guewen Baconnier)
631+#
632+# This program is free software: you can redistribute it and/or modify
633+# it under the terms of the GNU Affero General Public License as
634+# published by the Free Software Foundation, either version 3 of the
635+# License, or (at your option) any later version.
636+#
637+# This program is distributed in the hope that it will be useful,
638+# but WITHOUT ANY WARRANTY; without even the implied warranty of
639+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
640+# GNU Affero General Public License for more details.
641+#
642+# You should have received a copy of the GNU Affero General Public License
643+# along with this program. If not, see <http://www.gnu.org/licenses/>.
644+#
645+##############################################################################
646+
647+from openerp.osv import fields, orm
648+
649+
650+class payment_method(orm.Model):
651 _name = "payment.method"
652- _description = "payment method"
653-
654+ _description = "Payment Method"
655
656 _columns = {
657- 'name': fields.char('Name', size=64),
658- 'journal_id': fields.many2one('account.journal', 'Journal'),
659- 'payment_term_id': fields.many2one('account.payment.term', 'Payment Term'),
660+ 'name': fields.char('Name',
661+ help="The name of the method on the backend"),
662+ 'journal_id': fields.many2one(
663+ 'account.journal',
664+ 'Journal',
665+ help="If a journal a selected, when a payment is recorded "
666+ "on a backend, payment entries will be created in this "
667+ "journal. "),
668+ 'payment_term_id': fields.many2one(
669+ 'account.payment.term',
670+ 'Payment Term',
671+ help="Default payment term of a sale order using this method."),
672 }
673-
674
675=== modified file 'sale_payment_method/payment_method_view.xml'
676--- sale_quick_payment/payment_method_view.xml 2012-04-22 12:48:34 +0000
677+++ sale_payment_method/payment_method_view.xml 2013-10-13 16:10:00 +0000
678@@ -1,6 +1,6 @@
679 <?xml version="1.0" encoding="utf-8"?>
680 <!--
681- sale_quick_payment for OpenERP
682+ sale_payment_method for OpenERP
683 Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
684 The licence is in the file __openerp__.py
685 -->
686@@ -8,28 +8,41 @@
687 <openerp>
688 <data>
689
690- <!-- VIEW FOR THE OBJECT : payment_method -->
691 <record id="payment_method_view_form" model="ir.ui.view">
692- <field name="name">sale_quick_payment.payment_method.view_form</field>
693+ <field name="name">sale_payment_method.payment_method.view_form</field>
694 <field name="model">payment.method</field>
695- <field eval="16" name="priority"/>
696- <field name="type">form</field>
697 <field name="arch" type="xml">
698- <form string="payment_method">
699- <field name="name" />
700- <field name="journal_id" />
701- <field name="payment_term_id" />
702+ <form string="Payment Methods" version="7.0">
703+ <h1>
704+ <field name="name" class="oe_inline"/>
705+ </h1>
706+ <group name="general">
707+ <group name="config">
708+ <field name="journal_id" string="Journal for payment"/>
709+ </group>
710+ <group name="payment_help" class="oe_grey" col="1">
711+ <p attrs="{'invisible': [('journal_id', '=', False)]}">
712+ When the E-commerce backend will receive a payment for a sale order,
713+ payment entries will be generated in the selected journal.
714+ </p>
715+ <p attrs="{'invisible': [('journal_id', '!=', False)]}">
716+ Even if the E-commerce backend receives a payment for a sale order,
717+ no payment entries will be generated.
718+ </p>
719+ </group>
720+ </group>
721+ <group string="Default Values">
722+ <field name="payment_term_id" />
723+ </group>
724 </form>
725 </field>
726 </record>
727
728 <record id="payment_method_view_tree" model="ir.ui.view">
729- <field name="name">sale_quick_payment.payment_method.view_tree</field>
730+ <field name="name">sale_payment_method.payment_method.view_tree</field>
731 <field name="model">payment.method</field>
732- <field eval="16" name="priority"/>
733- <field name="type">tree</field>
734 <field name="arch" type="xml">
735- <tree string="payment_method">
736+ <tree string="Payment Methods">
737 <field name="name" />
738 <field name="journal_id" />
739 <field name="payment_term_id" />
740@@ -37,9 +50,8 @@
741 </field>
742 </record>
743
744-
745 <record id="act_payment_method_form" model="ir.actions.act_window">
746- <field name="name">Customer Payment Method</field>
747+ <field name="name">Payment Methods </field>
748 <field name="res_model">payment.method</field>
749 <field name="view_type">form</field>
750 <field name="view_mode">tree,form</field>
751
752=== modified file 'sale_payment_method/sale.py'
753--- sale_quick_payment/sale.py 2012-12-26 09:32:43 +0000
754+++ sale_payment_method/sale.py 2013-10-13 16:10:00 +0000
755@@ -1,165 +1,296 @@
756-# -*- encoding: utf-8 -*-
757-###############################################################################
758-# #
759-# sale_quick_payment for OpenERP #
760-# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com> #
761-# #
762-# This program is free software: you can redistribute it and/or modify #
763-# it under the terms of the GNU Affero General Public License as #
764-# published by the Free Software Foundation, either version 3 of the #
765-# License, or (at your option) any later version. #
766-# #
767-# This program is distributed in the hope that it will be useful, #
768-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
769-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
770-# GNU Affero General Public License for more details. #
771-# #
772-# You should have received a copy of the GNU Affero General Public License #
773-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
774-# #
775-###############################################################################
776+# -*- coding: utf-8 -*-
777+##############################################################################
778+#
779+# Author: Guewen Baconnier, Sébastien Beau
780+# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
781+# Copyright 2013 Camptocamp SA (Guewen Baconnier)
782+#
783+# This program is free software: you can redistribute it and/or modify
784+# it under the terms of the GNU Affero General Public License as
785+# published by the Free Software Foundation, either version 3 of the
786+# License, or (at your option) any later version.
787+#
788+# This program is distributed in the hope that it will be useful,
789+# but WITHOUT ANY WARRANTY; without even the implied warranty of
790+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
791+# GNU Affero General Public License for more details.
792+#
793+# You should have received a copy of the GNU Affero General Public License
794+# along with this program. If not, see <http://www.gnu.org/licenses/>.
795+#
796+##############################################################################
797
798-from openerp.osv.orm import Model
799-from openerp.osv import fields
800-from openerp.osv.osv import except_osv
801-import netsvc
802+from openerp.osv import orm, fields, osv
803+from openerp.tools.translate import _
804 from collections import Iterable
805-from openerp.tools.translate import _
806-import decimal_precision as dp
807-
808-class sale_order(Model):
809- _inherit = "sale.order"
810-
811- def _get_order_from_voucher(self, cr, uid, ids, context=None):
812- result = []
813- for voucher in self.pool.get('account.voucher').browse(cr, uid, ids, context=context):
814- for order in voucher.order_ids:
815- result.append(order.id)
816- return list(set(result))
817+import openerp.addons.decimal_precision as dp
818+
819+
820+class sale_order(orm.Model):
821+ _inherit = 'sale.order'
822+
823+ def _get_order_from_move(self, cr, uid, ids, context=None):
824+ result = set()
825+ move_obj = self.pool.get('account.move')
826+ for move in move_obj.browse(cr, uid, ids, context=context):
827+ for order in move.order_ids:
828+ result.add(order.id)
829+ return list(result)
830
831 def _get_order_from_line(self, cr, uid, ids, context=None):
832- return self.pool.get('sale.order')._get_order(cr, uid, ids, context=context)
833+ so_obj = self.pool.get('sale.order')
834+ return so_obj._get_order(cr, uid, ids, context=context)
835
836- def _amount_residual(self, cr, uid, ids, field_name, args, context=None):
837+ def _get_amount(self, cr, uid, ids, fields, args, context=None):
838 res = {}
839- #TODO add here the support of multi-currency payment if need
840 for order in self.browse(cr, uid, ids, context=context):
841- res[order.id] = order.amount_total
842- for payment in order.payment_ids:
843- if payment.state == 'posted':
844- res[order.id] -= payment.amount
845+ #TODO add support when payment is linked to many order
846+ paid_amount = 0
847+ for line in order.payment_ids:
848+ paid_amount += line.credit - line.debit
849+ res[order.id] = {
850+ 'amount_paid': paid_amount,
851+ 'residual': order.amount_total - paid_amount,
852+ }
853+ return res
854+
855+ def _payment_exists(self, cursor, user, ids, name, arg, context=None):
856+ res = {}
857+ for sale in self.browse(cursor, user, ids, context=context):
858+ res[sale.id] = bool(sale.payment_ids)
859 return res
860
861 _columns = {
862- 'payment_ids': fields.many2many('account.voucher', string='Payments'),
863- 'payment_method_id': fields.many2one('payment.method', 'Payment Method'),
864- 'residual': fields.function(_amount_residual, digits_compute=dp.get_precision('Account'), string='Balance',
865- store = {
866- 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line', 'payment_ids'], 10),
867- 'sale.order.line': (_get_order_from_line, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 20),
868- 'account.voucher': (_get_order_from_voucher, ['amount'], 30),
869- },
870- ),
871+ 'payment_ids': fields.many2many('account.move.line',
872+ string='Payments Entries'),
873+ 'payment_method_id': fields.many2one('payment.method',
874+ 'Payment Method',
875+ ondelete='restrict'),
876+ 'residual': fields.function(
877+ _get_amount,
878+ digits_compute=dp.get_precision('Account'),
879+ string='Balance',
880+ store=False,
881+ multi='payment'),
882+ 'amount_paid': fields.function(
883+ _get_amount,
884+ digits_compute=dp.get_precision('Account'),
885+ string='Amount Paid',
886+ store=False,
887+ multi='payment'),
888+ 'payment_exists': fields.function(
889+ _payment_exists,
890+ string='Has automatic payment',
891+ type='boolean',
892+ help="It indicates that sales order has at least one payment."),
893 }
894
895 def copy(self, cr, uid, id, default=None, context=None):
896- if not default:
897+ if default is None:
898 default = {}
899- default.update({
900- 'payment_ids': False,
901- })
902- return super(sale_order, self).copy(cr, uid, id, default, context=context)
903-
904- def pay_sale_order(self, cr, uid, sale_id, journal_id, amount, date, context=None):
905- """
906- Generate a voucher for the payment
907-
908- It will try to match with the invoice of the order by
909- matching the payment ref and the invoice origin.
910-
911- The invoice does not necessarily exists at this point, so if yes,
912- it will be matched in the voucher, otherwise, the voucher won't
913- have any invoice lines and the payment lines will be reconciled
914- later with "auto-reconcile" if the option is used.
915-
916- """
917- if isinstance(sale_id, Iterable):
918- sale_id = sale_id[0]
919-
920- voucher_obj = self.pool.get('account.voucher')
921- voucher_line_obj = self.pool.get('account.voucher.line')
922- move_line_obj = self.pool.get('account.move.line')
923- sale = self.browse(cr, uid, sale_id, context=context)
924-
925- journal = self.pool.get('account.journal').browse(
926- cr, uid, journal_id, context=context)
927-
928- voucher_vals = {'reference': sale.name,
929- 'journal_id': journal_id,
930- 'period_id': self.pool.get('account.period').find(cr, uid, dt=date,
931- context=context)[0],
932- 'amount': amount,
933- 'date': date,
934- 'partner_id': sale.partner_id.id,
935- 'account_id': journal.default_credit_account_id.id,
936- 'currency_id': journal.company_id.currency_id.id,
937- 'company_id': journal.company_id.id,
938- 'type': 'receipt', }
939-
940- # Set the payment rate if currency are different
941- if journal.currency.id and journal.company_id.currency_id.id != journal.currency.id:
942- currency_id = journal.company_id.currency_id.id
943- payment_rate_currency_id = journal.currency.id
944-
945- currency_obj = self.pool.get('res.currency')
946- ctx= context.copy()
947- ctx.update({'date': date})
948- tmp = currency_obj.browse(cr, uid, payment_rate_currency_id, context=ctx).rate
949- payment_rate = tmp / currency_obj.browse(cr, uid, currency_id, context=ctx).rate
950- voucher_vals.update({
951- 'payment_rate_currency_id': payment_rate_currency_id,
952- 'payment_rate': payment_rate,
953- })
954-
955- voucher_id = voucher_obj.create(cr, uid, voucher_vals, context=context)
956-
957- # call on change to search the invoice lines
958- onchange_voucher = voucher_obj.onchange_partner_id(
959- cr, uid, [],
960- partner_id=sale.partner_id.id,
961- journal_id=journal.id,
962- amount=amount,
963- currency_id=journal.company_id.currency_id.id,
964- ttype='receipt',
965- date=date,
966- context=context)['value']
967-
968- # keep in the voucher only the move line of the
969- # invoice (eventually) created for this order
970- matching_line = {}
971- if onchange_voucher.get('line_cr_ids'):
972- voucher_lines = onchange_voucher['line_cr_ids']
973- line_ids = [line['move_line_id'] for line in voucher_lines]
974- matching_ids = [line.id for line
975- in move_line_obj.browse(
976- cr, uid, line_ids, context=context)
977- if line.ref == sale.name]
978- matching_lines = [line for line
979- in voucher_lines
980- if line['move_line_id'] in matching_ids]
981- if matching_lines:
982- matching_line = matching_lines[0]
983- matching_line.update({
984- 'amount': amount,
985- 'voucher_id': voucher_id,
986- })
987-
988- if matching_line:
989- voucher_line_obj.create(cr, uid, matching_line, context=context)
990-
991- wf_service = netsvc.LocalService("workflow")
992- wf_service.trg_validate(
993- uid, 'account.voucher', voucher_id, 'proforma_voucher', cr)
994- sale.write({'payment_ids': [(4,voucher_id)]}, context=context)
995- return True
996-
997+ default['payment_ids'] = False
998+ return super(sale_order, self).copy(cr, uid, id,
999+ default, context=context)
1000+
1001+ def automatic_payment(self, cr, uid, ids, amount=None, context=None):
1002+ """ Create the payment entries to pay a sale order, respecting
1003+ the payment terms.
1004+ If no amount is defined, it will pay the residual amount of the sale
1005+ order. """
1006+ if isinstance(ids, Iterable):
1007+ assert len(ids) == 1, "one sale order at a time can be paid"
1008+ ids = ids[0]
1009+ sale = self.browse(cr, uid, ids, context=context)
1010+ method = sale.payment_method_id
1011+ if not method:
1012+ raise osv.except_osv(
1013+ _('Configuration Error'),
1014+ _("An automatic payment can not be created for the sale "
1015+ "order %s because it has no payment method.") % sale.name)
1016+
1017+ if not method.journal_id:
1018+ raise osv.except_osv(
1019+ _('Configuration Error'),
1020+ _("An automatic payment should be created for the sale order %s "
1021+ "but the payment method '%s' has no journal defined.") %
1022+ (sale.name, method.name))
1023+
1024+ journal = method.journal_id
1025+ date = sale.date_order
1026+ if amount is None:
1027+ amount = sale.residual
1028+ if sale.payment_term:
1029+ term_obj = self.pool.get('account.payment.term')
1030+ amounts = term_obj.compute(cr, uid, sale.payment_term.id,
1031+ amount, date_ref=date,
1032+ context=context)
1033+ else:
1034+ amounts = [(date, amount)]
1035+
1036+ # reversed is cosmetic, compute returns terms in the 'wrong' order
1037+ for date, amount in reversed(amounts):
1038+ self._add_payment(cr, uid, sale, journal,
1039+ amount, date, context=context)
1040+ return True
1041+
1042+ def add_payment(self, cr, uid, ids, journal_id, amount,
1043+ date=None, description=None, context=None):
1044+ """ Generate payment move lines of a certain amount linked
1045+ with the sale order. """
1046+ if isinstance(ids, Iterable):
1047+ assert len(ids) == 1, "one sale order at a time can be paid"
1048+ ids = ids[0]
1049+ journal_obj = self.pool.get('account.journal')
1050+
1051+ sale = self.browse(cr, uid, ids, context=context)
1052+ if date is None:
1053+ date = sale.date_order
1054+ journal = journal_obj.browse(cr, uid, journal_id, context=context)
1055+ self._add_payment(cr, uid, sale, journal, amount, date, description, context=context)
1056+ return True
1057+
1058+ def _add_payment(self, cr, uid, sale, journal, amount, date, description, context=None):
1059+ """ Generate move lines entries to pay the sale order. """
1060+ move_obj = self.pool.get('account.move')
1061+ period_obj = self.pool.get('account.period')
1062+ period_id = period_obj.find(cr, uid, dt=date, context=context)[0]
1063+ period = period_obj.browse(cr, uid, period_id, context=context)
1064+ move_name = description or self._get_payment_move_name(cr, uid, journal,
1065+ period, context=context)
1066+ move_vals = self._prepare_payment_move(cr, uid, move_name, sale,
1067+ journal, period, date,
1068+ context=context)
1069+ move_lines = self._prepare_payment_move_line(cr, uid, move_name, sale,
1070+ journal, period, amount,
1071+ date, context=context)
1072+
1073+ move_vals['line_id'] = [(0, 0, line) for line in move_lines]
1074+ move_obj.create(cr, uid, move_vals, context=context)
1075+
1076+ def _get_payment_move_name(self, cr, uid, journal, period, context=None):
1077+ if context is None:
1078+ context = {}
1079+ seq_obj = self.pool.get('ir.sequence')
1080+ sequence = journal.sequence_id
1081+
1082+ if not sequence:
1083+ raise osv.except_osv(
1084+ _('Configuration Error'),
1085+ _('Please define a sequence on the journal %s.') %
1086+ journal.name)
1087+ if not sequence.active:
1088+ raise osv.except_osv(
1089+ _('Configuration Error'),
1090+ _('Please activate the sequence of the journal %s.') %
1091+ journal.name)
1092+
1093+ ctx = context.copy()
1094+ ctx['fiscalyear_id'] = period.fiscalyear_id.id
1095+ name = seq_obj.next_by_id(cr, uid, sequence.id, context=ctx)
1096+ return name
1097+
1098+ def _prepare_payment_move(self, cr, uid, move_name, sale, journal,
1099+ period, date, context=None):
1100+ return {'name': move_name,
1101+ 'journal_id': journal.id,
1102+ 'date': date,
1103+ 'ref': sale.name,
1104+ 'period_id': period.id,
1105+ }
1106+
1107+ def _prepare_payment_move_line(self, cr, uid, move_name, sale, journal,
1108+ period, amount, date, context=None):
1109+ """ """
1110+ partner_obj = self.pool.get('res.partner')
1111+ currency_obj = self.pool.get('res.currency')
1112+ partner = partner_obj._find_accounting_partner(sale.partner_id)
1113+
1114+ company = journal.company_id
1115+
1116+ currency_id = False
1117+ amount_currency = 0.0
1118+ if journal.currency and journal.currency.id != company.currency_id.id:
1119+ currency_id = journal.currency.id
1120+ amount_currency, amount = (amount,
1121+ currency_obj.compute(cr, uid,
1122+ currency_id,
1123+ company.currency_id.id,
1124+ amount,
1125+ context=context))
1126+
1127+ # payment line (bank / cash)
1128+ debit_line = {
1129+ 'name': move_name,
1130+ 'debit': amount,
1131+ 'credit': 0.0,
1132+ 'account_id': journal.default_credit_account_id.id,
1133+ 'journal_id': journal.id,
1134+ 'period_id': period.id,
1135+ 'partner_id': partner.id,
1136+ 'date': date,
1137+ 'amount_currency': amount_currency,
1138+ 'currency_id': currency_id,
1139+ }
1140+
1141+ # payment line (receivable)
1142+ credit_line = {
1143+ 'name': move_name,
1144+ 'debit': 0.0,
1145+ 'credit': amount,
1146+ 'account_id': partner.property_account_receivable.id,
1147+ 'journal_id': journal.id,
1148+ 'period_id': period.id,
1149+ 'partner_id': partner.id,
1150+ 'date': date,
1151+ 'amount_currency': -amount_currency,
1152+ 'currency_id': currency_id,
1153+ 'sale_ids': [(4, sale.id)],
1154+ }
1155+ return debit_line, credit_line
1156+
1157+ def onchange_payment_method_id(self, cr, uid, ids, payment_method_id, context=None):
1158+ if not payment_method_id:
1159+ return {}
1160+ result = {}
1161+ method_obj = self.pool.get('payment.method')
1162+ method = method_obj.browse(cr, uid, payment_method_id, context=context)
1163+ if method.payment_term_id:
1164+ result['payment_term'] = method.payment_term_id.id
1165+ return {'value': result}
1166+
1167+ def action_view_payments(self, cr, uid, ids, context=None):
1168+ """ Return an action to display the payment linked
1169+ with the sale order """
1170+
1171+ mod_obj = self.pool.get('ir.model.data')
1172+ act_obj = self.pool.get('ir.actions.act_window')
1173+
1174+ payment_ids = []
1175+ for so in self.browse(cr, uid, ids, context=context):
1176+ payment_ids += [move.id for move in so.payment_ids]
1177+
1178+ ref = mod_obj.get_object_reference(cr, uid, 'account',
1179+ 'action_move_journal_line')
1180+ action_id = False
1181+ if ref:
1182+ __, action_id = ref
1183+ action = act_obj.read(cr, uid, [action_id], context=context)[0]
1184+
1185+ # choose the view_mode accordingly
1186+ if len(payment_ids) > 1:
1187+ action['domain'] = str([('id', 'in', payment_ids)])
1188+ else:
1189+ ref = mod_obj.get_object_reference(cr, uid, 'account',
1190+ 'view_move_form')
1191+ action['views'] = [(ref[1] if ref else False, 'form')]
1192+ action['res_id'] = payment_ids[0] if payment_ids else False
1193+ return action
1194+
1195+ def action_cancel(self, cr, uid, ids, context=None):
1196+ for sale in self.browse(cr, uid, ids, context=context):
1197+ if sale.payment_ids:
1198+ raise osv.except_osv(
1199+ _('Cannot cancel this sales order!'),
1200+ _('Automatic payment entries are linked '
1201+ 'with the sale order.'))
1202+ return super(sale_order, self).action_cancel(cr, uid, ids, context=context)
1203
1204=== modified file 'sale_payment_method/sale_view.xml'
1205--- sale_quick_payment/sale_view.xml 2012-12-26 13:13:25 +0000
1206+++ sale_payment_method/sale_view.xml 2013-10-13 16:10:00 +0000
1207@@ -1,48 +1,47 @@
1208 <?xml version="1.0" encoding="utf-8"?>
1209 <!--
1210- sale_quick_payment for OpenERP
1211+ sale_payment_method for OpenERP
1212 Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
1213 The licence is in the file __openerp__.py
1214 -->
1215
1216 <openerp>
1217 <data>
1218-
1219+
1220 <!-- INHERITED VIEW FOR THE OBJECT : sale_order -->
1221
1222 <record id="sale_order_view_form" model="ir.ui.view">
1223- <field name="name">sale_quick_payment.sale_order.view_form</field>
1224+ <field name="name">sale.order.view.form</field>
1225 <field name="model">sale.order</field>
1226 <field name="inherit_id" ref="sale.view_order_form" />
1227- <field eval="16" name="priority"/>
1228- <field name="type">form</field>
1229 <field name="arch" type="xml">
1230- <button name="print_quotation" position="after">
1231- <button name="%(open_pay_sale_order)d" string="Register Payments" type="action" states="draft,sent"/>
1232- </button>
1233 <page string="Other Information" position="after">
1234 <page name="automation_information" string="Automation Information">
1235 <group name="payment_information" colspan="4">
1236- <field name="payment_method_id" />
1237- <group name="payments" colspan="4">
1238- <separator string="Payments" colspan="4"/>
1239- <field name="payment_ids" nolabel="1" />
1240- </group>
1241+ <field name="payment_method_id"
1242+ on_change="onchange_payment_method_id(payment_method_id)"/>
1243 </group>
1244 </page>
1245 </page>
1246 <field name="amount_total" position="after">
1247 <field name="residual" invisible="1"/>
1248 </field>
1249+
1250+ <button string="Create Invoice" position="after">
1251+ <field name="payment_exists" invisible="1"/>
1252+ <button name="action_view_payments"
1253+ string="View Automatic Payment"
1254+ type="object" class="oe_highlight"
1255+ attrs="{'invisible': [('payment_exists', '=', False)]}"
1256+ groups="base.group_user"/>
1257+ </button>
1258 </field>
1259 </record>
1260
1261 <record id="sale_order_view_tree" model="ir.ui.view">
1262- <field name="name">sale_quick_payment.sale_order.view_tree</field>
1263+ <field name="name">sale.order.view.tree</field>
1264 <field name="model">sale.order</field>
1265 <field name="inherit_id" ref="sale.view_order_tree" />
1266- <field eval="16" name="priority"/>
1267- <field name="type">tree</field>
1268 <field name="arch" type="xml">
1269 <field name="state" position="after">
1270 <field name="payment_method_id" />
1271@@ -50,5 +49,30 @@
1272 </field>
1273 </record>
1274
1275+ <record id="view_quotation_tree" model="ir.ui.view">
1276+ <field name="name">sale.order.view.tree</field>
1277+ <field name="model">sale.order</field>
1278+ <field name="inherit_id" ref="sale.view_quotation_tree" />
1279+ <field name="arch" type="xml">
1280+ <field name="amount_total" position="after">
1281+ <field name="amount_paid"/>
1282+ <field name="payment_method_id"/>
1283+ </field>
1284+ </field>
1285+ </record>
1286+
1287+
1288+ <record id="view_sales_order_filter" model="ir.ui.view">
1289+ <field name="model">sale.order</field>
1290+ <field name="inherit_id" ref="sale.view_sales_order_filter"/>
1291+ <field name="arch" type="xml">
1292+ <filter name="my_sale_orders_filter" position="before">
1293+ <filter string="With Payment" domain="[('payment_ids','!=',False)]" help="Order With Payment" name="with_payment"/>
1294+ <separator/>
1295+ </filter>
1296+ </field>
1297+ </record>
1298+
1299+
1300 </data>
1301 </openerp>
1302
1303=== added directory 'sale_quick_payment'
1304=== added file 'sale_quick_payment/__init__.py'
1305--- sale_quick_payment/__init__.py 1970-01-01 00:00:00 +0000
1306+++ sale_quick_payment/__init__.py 2013-10-13 16:10:00 +0000
1307@@ -0,0 +1,22 @@
1308+# -*- coding: utf-8 -*-
1309+##############################################################################
1310+#
1311+# sale_quick_payment for OpenERP
1312+# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
1313+#
1314+# This program is free software: you can redistribute it and/or modify
1315+# it under the terms of the GNU Affero General Public License as
1316+# published by the Free Software Foundation, either version 3 of the
1317+# License, or (at your option) any later version.
1318+#
1319+# This program is distributed in the hope that it will be useful,
1320+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1321+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1322+# GNU Affero General Public License for more details.
1323+#
1324+# You should have received a copy of the GNU Affero General Public License
1325+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1326+#
1327+##############################################################################
1328+
1329+from . import wizard
1330
1331=== added file 'sale_quick_payment/__openerp__.py'
1332--- sale_quick_payment/__openerp__.py 1970-01-01 00:00:00 +0000
1333+++ sale_quick_payment/__openerp__.py 2013-10-13 16:10:00 +0000
1334@@ -0,0 +1,55 @@
1335+# -*- coding: utf-8 -*-
1336+##############################################################################
1337+#
1338+# sale_payment_method for OpenERP
1339+# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
1340+#
1341+# This program is free software: you can redistribute it and/or modify
1342+# it under the terms of the GNU Affero General Public License as
1343+# published by the Free Software Foundation, either version 3 of the
1344+# License, or (at your option) any later version.
1345+#
1346+# This program is distributed in the hope that it will be useful,
1347+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1348+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1349+# GNU Affero General Public License for more details.
1350+#
1351+# You should have received a copy of the GNU Affero General Public License
1352+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1353+#
1354+##############################################################################
1355+
1356+
1357+{
1358+ 'name': 'Sale Quick Payment',
1359+ 'version': '0.2',
1360+ 'category': 'Generic Modules/Others',
1361+ 'license': 'AGPL-3',
1362+ 'description': """
1363+Sale Quick Payment
1364+==================
1365+
1366+Sale Quick Payment gives the possibility to pay a sale order from the
1367+sale order itself.
1368+
1369+The payment will be linked to the sale order.
1370+
1371+If you install the module Sale Automatic Workflow, you can forbid the
1372+validation of an unpaid order and the invoice will be automatically
1373+reconciled with the payment.
1374+
1375+This module was originally designed for the e-commerce sector, but it
1376+does not preclude to use it in other sectors.
1377+ """,
1378+ 'author': 'Akretion',
1379+ 'website': 'http://www.akretion.com/',
1380+ 'depends': ['sale_payment_method',
1381+ 'sale_exceptions',
1382+ ],
1383+ 'data': ['wizard/pay_sale_order.xml',
1384+ 'sale_view.xml',
1385+ 'settings/sale.exception.csv',
1386+ ],
1387+ 'demo': [],
1388+ 'installable': True,
1389+}
1390
1391=== removed file 'sale_quick_payment/account_voucher.py'
1392--- sale_quick_payment/account_voucher.py 2012-12-26 09:32:43 +0000
1393+++ sale_quick_payment/account_voucher.py 1970-01-01 00:00:00 +0000
1394@@ -1,33 +0,0 @@
1395-# -*- encoding: utf-8 -*-
1396-###############################################################################
1397-#
1398-# sale_quick_payment for OpenERP
1399-# Copyright (C) 2012-TODAY Akretion <http://www.akretion.com>.
1400-# All Rights Reserved
1401-# @author Sébastien BEAU <sebastien.beau@akretion.com>
1402-# This program is free software: you can redistribute it and/or modify
1403-# it under the terms of the GNU Affero General Public License as
1404-# published by the Free Software Foundation, either version 3 of the
1405-# License, or (at your option) any later version.
1406-#
1407-# This program is distributed in the hope that it will be useful,
1408-# but WITHOUT ANY WARRANTY; without even the implied warranty of
1409-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1410-# GNU Affero General Public License for more details.
1411-#
1412-# You should have received a copy of the GNU Affero General Public License
1413-# along with this program. If not, see <http://www.gnu.org/licenses/>.
1414-#
1415-###############################################################################
1416-
1417-from openerp.osv.orm import Model
1418-from openerp.osv import fields
1419-
1420-class payment_method(Model):
1421- _inherit = "account.voucher"
1422-
1423- _columns = {
1424- 'order_ids': fields.many2many('sale.order', string='Sale Order'),
1425- }
1426-
1427-
1428
1429=== added file 'sale_quick_payment/sale_view.xml'
1430--- sale_quick_payment/sale_view.xml 1970-01-01 00:00:00 +0000
1431+++ sale_quick_payment/sale_view.xml 2013-10-13 16:10:00 +0000
1432@@ -0,0 +1,40 @@
1433+<?xml version="1.0" encoding="utf-8"?>
1434+<!--
1435+ sale_quick_payment for OpenERP
1436+ Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
1437+ The licence is in the file __openerp__.py
1438+-->
1439+
1440+<openerp>
1441+ <data>
1442+
1443+ <!-- INHERITED VIEW FOR THE OBJECT : sale_order -->
1444+
1445+ <record id="sale_order_view_form" model="ir.ui.view">
1446+ <field name="name">sale_quick_payment.sale_order.view_form</field>
1447+ <field name="model">sale.order</field>
1448+ <field name="inherit_id" ref="sale_payment_method.sale_order_view_form" />
1449+ <field name="arch" type="xml">
1450+ <button name="print_quotation" position="after">
1451+ <button name="%(open_pay_sale_order)d"
1452+ string="Register Payments"
1453+ type="action" states="draft,sent"/>
1454+ </button>
1455+ <field name="payment_method_id" position="after" >
1456+ <group name="payments" string="Generated Payments" colspan="4">
1457+ <field name="payment_ids" nolabel="1">
1458+ <tree string="Payment">
1459+ <field name="date"/>
1460+ <field name="journal_id"/>
1461+ <field name="partner_id"/>
1462+ <field name="debit"/>
1463+ <field name="credit"/>
1464+ </tree>
1465+ </field>
1466+ </group>
1467+ </field>
1468+ </field>
1469+ </record>
1470+
1471+ </data>
1472+</openerp>
1473
1474=== renamed directory 'sale_quick_payment/settings' => 'sale_quick_payment/settings'
1475=== renamed directory 'sale_quick_payment/wizard' => 'sale_quick_payment/wizard'
1476=== modified file 'sale_quick_payment/wizard/__init__.py'
1477--- sale_quick_payment/wizard/__init__.py 2012-04-22 12:48:34 +0000
1478+++ sale_quick_payment/wizard/__init__.py 2013-10-13 16:10:00 +0000
1479@@ -1,1 +1,1 @@
1480-import pay_sale_order
1481+from . import pay_sale_order
1482
1483=== modified file 'sale_quick_payment/wizard/pay_sale_order.py'
1484--- sale_quick_payment/wizard/pay_sale_order.py 2012-12-26 09:32:43 +0000
1485+++ sale_quick_payment/wizard/pay_sale_order.py 2013-10-13 16:10:00 +0000
1486@@ -1,47 +1,47 @@
1487-# -*- encoding: utf-8 -*-
1488-#################################################################################
1489-# #
1490-# Magentoerpconnect for OpenERP #
1491-# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com> #
1492-# #
1493-# This program is free software: you can redistribute it and/or modify #
1494-# it under the terms of the GNU Affero General Public License as #
1495-# published by the Free Software Foundation, either version 3 of the #
1496-# License, or (at your option) any later version. #
1497-# #
1498-# This program is distributed in the hope that it will be useful, #
1499-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
1500-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
1501-# GNU Affero General Public License for more details. #
1502-# #
1503-# You should have received a copy of the GNU Affero General Public License #
1504-# along with this program. If not, see <http://www.gnu.org/licenses/>. #
1505-# #
1506-#################################################################################
1507-
1508-
1509-from openerp.osv.orm import TransientModel
1510-from openerp.osv import fields
1511-import decimal_precision as dp
1512-from datetime import datetime
1513-
1514-#TODO add button on sale_form header instead of more button
1515-
1516-class pay_sale_order(TransientModel):
1517+# -*- coding: utf-8 -*-
1518+##############################################################################
1519+#
1520+# sale_quick_payment for OpenERP
1521+# Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com>
1522+#
1523+# This program is free software: you can redistribute it and/or modify
1524+# it under the terms of the GNU Affero General Public License as
1525+# published by the Free Software Foundation, either version 3 of the
1526+# License, or (at your option) any later version.
1527+#
1528+# This program is distributed in the hope that it will be useful,
1529+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1530+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1531+# GNU Affero General Public License for more details.
1532+#
1533+# You should have received a copy of the GNU Affero General Public License
1534+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1535+#
1536+##############################################################################
1537+
1538+from openerp.osv import orm, fields
1539+import openerp.addons.decimal_precision as dp
1540+
1541+
1542+class pay_sale_order(orm.TransientModel):
1543 _name = 'pay.sale.order'
1544 _description = 'Wizard to generate a payment from the sale order'
1545
1546 _columns = {
1547 'journal_id': fields.many2one('account.journal', 'Journal'),
1548- 'amount': fields.float('Amount', digits_compute=dp.get_precision('Sale Price')),
1549+ 'amount': fields.float('Amount',
1550+ digits_compute=dp.get_precision('Sale Price')),
1551 'date': fields.datetime('Payment Date'),
1552- }
1553+ 'description': fields.char('Description', size=64),
1554+ }
1555
1556 def _get_journal_id(self, cr, uid, context=None):
1557 if context is None:
1558 context = {}
1559 if context.get('active_id'):
1560- order = self.pool.get('sale.order').browse(cr, uid, context['active_id'], context=context)
1561+ sale_obj = self.pool.get('sale.order')
1562+ order = sale_obj.browse(cr, uid, context['active_id'],
1563+ context=context)
1564 if order.payment_method_id:
1565 return order.payment_method_id.journal_id.id
1566 return False
1567@@ -50,7 +50,9 @@
1568 if context is None:
1569 context = {}
1570 if context.get('active_id'):
1571- order = self.pool.get('sale.order').browse(cr, uid, context['active_id'], context=context)
1572+ sale_obj = self.pool.get('sale.order')
1573+ order = sale_obj.browse(cr, uid, context['active_id'],
1574+ context=context)
1575 return order.residual
1576 return False
1577
1578@@ -61,25 +63,22 @@
1579 }
1580
1581 def pay_sale_order(self, cr, uid, ids, context=None):
1582- """
1583- Pay the sale order
1584- @param cr: the current row, from the database cursor,
1585- @param uid: the current user’s ID for security checks,
1586- @param ids: List of account chart’s IDs
1587- @return: dictionary of Product list window for a given attributs set
1588- """
1589+ """ Pay the sale order """
1590 wizard = self.browse(cr, uid, ids[0], context=context)
1591- self.pool.get('sale.order').pay_sale_order(cr, uid, context['active_id'], wizard.journal_id.id, wizard.amount, wizard.date, context=context)
1592+ sale_obj = self.pool.get('sale.order')
1593+ sale_obj.add_payment(cr, uid,
1594+ context['active_id'],
1595+ wizard.journal_id.id,
1596+ wizard.amount,
1597+ wizard.date,
1598+ description=wizard.description,
1599+ context=context)
1600 return {'type': 'ir.actions.act_window_close'}
1601
1602 def pay_sale_order_and_confirm(self, cr, uid, ids, context=None):
1603- """
1604- Pay the sale order
1605- @param cr: the current row, from the database cursor,
1606- @param uid: the current user’s ID for security checks,
1607- @param ids: List of account chart’s IDs
1608- @return: dictionary of Product list window for a given attributs set
1609- """
1610+ """ Pay the sale order """
1611 self.pay_sale_order(cr, uid, ids, context=context)
1612- return self.pool.get('sale.order').action_button_confirm(cr, uid, [context['active_id']], context=context)
1613-
1614+ sale_obj = self.pool.get('sale.order')
1615+ return sale_obj.action_button_confirm(cr, uid,
1616+ [context['active_id']],
1617+ context=context)
1618
1619=== modified file 'sale_quick_payment/wizard/pay_sale_order.xml'
1620--- sale_quick_payment/wizard/pay_sale_order.xml 2012-12-26 09:32:43 +0000
1621+++ sale_quick_payment/wizard/pay_sale_order.xml 2013-10-13 16:10:00 +0000
1622@@ -4,10 +4,10 @@
1623 <record model="ir.ui.view" id="pay_sale_order_view">
1624 <field name="name">pay.sale.order.view</field>
1625 <field name="model">pay.sale.order</field>
1626- <field name="type">form</field>
1627 <field name="arch" type="xml">
1628 <form string="Pay Sale Order" version="7.0">
1629 <group>
1630+ <field name="description" string="Description"/>
1631 <field name="journal_id" string="Journal"/>
1632 <field name="amount" string="Paid Amount"/>
1633 <field name="date" string="Date"/>

Subscribers

People subscribed via source and target branches