Merge lp:~therp-nl/banking-addons/ba7.0-RFR-split_off_payment_part into lp:banking-addons

Proposed by Stefan Rijnhart (Opener)
Status: Merged
Merged at revision: 169
Proposed branch: lp:~therp-nl/banking-addons/ba7.0-RFR-split_off_payment_part
Merge into: lp:banking-addons
Prerequisite: lp:~banking-addons-team/banking-addons/ba70-mig_account_iban_preserve_domestic
Diff against target: 2904 lines (+1420/-999)
31 files modified
account_banking/__openerp__.py (+4/-3)
account_banking/account_banking.py (+0/-475)
account_banking/account_banking_view.xml (+0/-87)
account_banking/banking_import_transaction.py (+38/-330)
account_banking/data/account_banking_data.xml (+0/-7)
account_banking/security/ir.model.access.csv (+0/-1)
account_banking/wizard/__init__.py (+0/-2)
account_banking/wizard/bank_import.py (+0/-3)
account_banking/wizard/banking_transaction_wizard.py (+0/-9)
account_banking/wizard/banking_transaction_wizard.xml (+0/-8)
account_banking_nl_clieop/__terp__.py (+1/-1)
account_banking_payment/__init__.py (+1/-0)
account_banking_payment/__openerp__.py (+57/-0)
account_banking_payment/data/payment_mode_type.xml (+14/-0)
account_banking_payment/model/__init__.py (+10/-0)
account_banking_payment/model/account_bank_statement_line.py (+40/-0)
account_banking_payment/model/account_payment.py (+240/-0)
account_banking_payment/model/bank_payment_manual.py (+32/-32)
account_banking_payment/model/banking_import_line.py (+45/-0)
account_banking_payment/model/banking_import_transaction.py (+381/-0)
account_banking_payment/model/banking_transaction_wizard.py (+45/-0)
account_banking_payment/model/payment_line.py (+218/-0)
account_banking_payment/model/payment_mode.py (+51/-0)
account_banking_payment/model/payment_mode_type.py (+62/-0)
account_banking_payment/model/payment_order_create.py (+27/-28)
account_banking_payment/security/ir.model.access.csv (+2/-0)
account_banking_payment/view/account_payment.xml (+45/-0)
account_banking_payment/view/bank_payment_manual.xml (+16/-0)
account_banking_payment/view/banking_transaction_wizard.xml (+36/-0)
account_banking_payment/view/payment_mode_type.xml (+47/-0)
account_banking_payment/workflow/account_payment.xml (+8/-13)
To merge this branch: bzr merge lp:~therp-nl/banking-addons/ba7.0-RFR-split_off_payment_part
Reviewer Review Type Date Requested Status
Holger Brunn (Therp) code review Approve
Guewen Baconnier @ Camptocamp code review, no test Approve
Alexandre Fayolle - camptocamp code review, no test Needs Fixing
Review via email: mp+153680@code.launchpad.net

Description of the change

This change is a conceptually simple refactoring: the account_banking module has always containted code for importing bank statements as well as exporting payment orders. I have now split off the latter part in a separate module.

Unfortunately, the implementation of this simple concept has lead to a horrendous diff of 3000 lines, stretching what can be possibly expected from a community based review structure. Most of this is just copied code. You might want to focus on the following, actual changes:

l.927 introduction of move_info2values replacing l.1005-1022, so that it can be overridden in the new module (in l.2136)
l.949,965-973,982,986 conditionally using functionality from account_payment (if it is installed)
l.1037-1064 Do not attempt to trigger workflow when *recognizing* a payment order line but after confirmation of the match (in l.1994-2003)
l.1688,1729 Replacing wizard interface object with transient model (and actually calling the workflow instead of overwriting the state field)
l.2157-2179 Akwardly updating a pre-existing function map with functions to deal with additional match types added by the split off module
l.2615-2619,2636,2639,2647-2652,2657-2662 Compare dates from database with UTC date
l.2869-2906 Preserve original module name in xml ids for migration purposes

Note that although the target branch is 7.0, the code is still only compatible with 6.1. The actual migration of the code will be presented in another MP. I do not want to jeopardize the mature 6.1 branch with such large changes. Because I needed to test the code in 6.1, I made sure not to introduce any incompatiblities with this release (meaning: the view type *will* eventually be removed from the xml view definitions).

To post a comment you must log in.
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

Some nitpicking and more in-depth comments

* account_banking_payment/model/account_payment.py:

  - there are several spaces missing in the help strings (e.g. l1507-1510 for date_prefered column
  - btw "prefered" is spelled "preferred" in English (with two 'r'). Maybe it's still time to fix this one
  - l. 1542: missing call to tools.translate._() for 'Payment Order Export' ?

* account_banking_payment/model/payment_order_create.py

  - I'm very suspicious of the value of _today : run this in Tokyo at 7:00 AM localtime, and _today will yield a date one day off. This definitely requires testing with ntpd off and a compyter configured in a widely off TZ (or maybe use http://pythonhosted.org/testfixtures/datetime.html for this, if there's nothing in the OpenERP test framework)
  - I find a bit difficult to read your use of the ternary operator (with the if clause split on 2 lines, and the else clause appended at the end of the second line). If you're concerned about line lenght, I recommend using 3 lines, keeping the 'if' clause on a single line and the else clause by itself.

review: Needs Fixing (code review, no test)
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Hi Alexandre,

thanks for taking the effort of ploughing through this monstrous diff!

Your first point is very good, but there is nothing that I can do about that. The list of fields on the payment model is merely there to add an entry to their 'states' list. In order to do so, I need to duplicate the earlier definitions from the account_payment module. The errors that you point out in field names and help texts are in that module. I wish it was easier to change this field attribute (and it would be if the orm did not lump attrs from the 'states' list and the 'attrs' dictionary together with the implicit 'AND' operator, lp:941901).

Other changes agreed and processed.

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

LGTM

review: Approve (code review, no test)
177. By Stefan Rijnhart (Opener)

[RFR] Merged with target branch

Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

2624: that should be openerp.tools or openerp.tools.misc, right?

Minor thing:

2169ff: I think you can avoid the awkwardness by using banking_import_transaction._confirm_payment_order (that is, the reference to the unbound method)

review: Needs Fixing
178. By Stefan Rijnhart (Opener)

[FIX] Faulty import
[IMP] Method references in confirm/cancel mappings

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Thanks Holger, referring to the methods in that way works very well. Fixed the import as well.

Revision history for this message
Holger Brunn (Therp) (hbrunn) :
review: Approve (code review)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account_banking/__openerp__.py'
2--- account_banking/__openerp__.py 2013-02-26 21:06:36 +0000
3+++ account_banking/__openerp__.py 2013-05-24 09:03:33 +0000
4@@ -35,15 +35,16 @@
5 'author': 'Banking addons community',
6 'website': 'https://launchpad.net/banking-addons',
7 'category': 'Banking addons',
8- 'depends': ['base', 'account', 'base_iban', 'account_payment',
9- 'account_iban_preserve_domestic'],
10+ 'depends': [
11+ 'account_voucher',
12+ 'account_iban_preserve_domestic',
13+ ],
14 'init_xml': [],
15 'update_xml': [
16 'security/ir.model.access.csv',
17 'data/account_banking_data.xml',
18 'wizard/bank_import_view.xml',
19 'account_banking_view.xml',
20- 'account_banking_workflow.xml',
21 'wizard/banking_transaction_wizard.xml',
22 'workflow/account_invoice.xml',
23 ],
24
25=== modified file 'account_banking/account_banking.py'
26--- account_banking/account_banking.py 2013-03-20 19:25:57 +0000
27+++ account_banking/account_banking.py 2013-05-24 09:03:33 +0000
28@@ -272,68 +272,6 @@
29 }
30 account_banking_imported_file()
31
32-class payment_mode_type(osv.osv):
33- _name= 'payment.mode.type'
34- _description= 'Payment Mode Type'
35- _columns= {
36- 'name': fields.char(
37- 'Name', size=64, required=True,
38- help='Payment Type'
39- ),
40- 'code': fields.char(
41- 'Code', size=64, required=True,
42- help='Specify the Code for Payment Type'
43- ),
44- # Setting suitable_bank_types to required pending
45- # https://bugs.launchpad.net/openobject-addons/+bug/786845
46- 'suitable_bank_types': fields.many2many(
47- 'res.partner.bank.type',
48- 'bank_type_payment_type_rel',
49- 'pay_type_id','bank_type_id',
50- 'Suitable bank types', required=True),
51- 'ir_model_id': fields.many2one(
52- 'ir.model', 'Payment wizard',
53- help=('Select the Payment Wizard for payments of this type. '
54- 'Leave empty for manual processing'),
55- domain=[('osv_memory', '=', True)],
56- ),
57- 'payment_order_type': fields.selection(
58- [('payment', 'Payment'),('debit', 'Direct debit')],
59- 'Payment order type', required=True,
60- ),
61- }
62-
63- _defaults = {
64- 'payment_order_type': lambda *a: 'payment',
65- }
66-
67-payment_mode_type()
68-
69-class payment_mode(osv.osv):
70- ''' Restoring the payment type from version 5,
71- used to select the export wizard (if any) '''
72- _inherit = "payment.mode"
73-
74- def suitable_bank_types(self, cr, uid, payment_mode_id=None, context=None):
75- """ Reinstates functional code for suitable bank type filtering.
76- Current code in account_payment is disfunctional.
77- """
78- res = []
79- payment_mode = self.browse(
80- cr, uid, payment_mode_id, context)
81- if (payment_mode and payment_mode.type and
82- payment_mode.type.suitable_bank_types):
83- res = [type.code for type in payment_mode.type.suitable_bank_types]
84- return res
85-
86- _columns = {
87- 'type': fields.many2one(
88- 'payment.mode.type', 'Payment type',
89- help='Select the Payment Type for the Payment Mode.'
90- ),
91- }
92-payment_mode()
93-
94 class account_bank_statement(osv.osv):
95 '''
96 Extensions from account_bank_statement:
97@@ -785,419 +723,6 @@
98
99 account_bank_statement_line()
100
101-class payment_line(osv.osv):
102- '''
103- Add extra export_state and date_done fields; make destination bank account
104- mandatory, as it makes no sense to send payments into thin air.
105- Edit: Payments can be by cash too, which is prohibited by mandatory bank
106- accounts.
107- '''
108- _inherit = 'payment.line'
109- _columns = {
110- # New fields
111- 'export_state': fields.selection([
112- ('draft', 'Draft'),
113- ('open','Confirmed'),
114- ('cancel','Cancelled'),
115- ('sent', 'Sent'),
116- ('rejected', 'Rejected'),
117- ('done','Done'),
118- ], 'State', select=True
119- ),
120- 'msg': fields.char('Message', size=255, required=False, readonly=True),
121-
122- # Redefined fields: added states
123- 'date_done': fields.datetime('Date Confirmed', select=True,
124- readonly=True),
125- 'name': fields.char(
126- 'Your Reference', size=64, required=True,
127- states={
128- 'sent': [('readonly', True)],
129- 'rejected': [('readonly', True)],
130- 'done': [('readonly', True)]
131- },
132- ),
133- 'communication': fields.char(
134- 'Communication', size=64, required=False,
135- help=("Used as the message between ordering customer and current "
136- "company. Depicts 'What do you want to say to the recipient"
137- " about this order ?'"
138- ),
139- states={
140- 'sent': [('readonly', True)],
141- 'rejected': [('readonly', True)],
142- 'done': [('readonly', True)]
143- },
144- ),
145- 'communication2': fields.char(
146- 'Communication 2', size=128,
147- help='The successor message of Communication.',
148- states={
149- 'sent': [('readonly', True)],
150- 'rejected': [('readonly', True)],
151- 'done': [('readonly', True)]
152- },
153- ),
154- 'move_line_id': fields.many2one(
155- 'account.move.line', 'Entry line',
156- domain=[('reconcile_id','=', False),
157- ('account_id.type', '=','payable')
158- ],
159- help=('This Entry Line will be referred for the information of '
160- 'the ordering customer.'
161- ),
162- states={
163- 'sent': [('readonly', True)],
164- 'rejected': [('readonly', True)],
165- 'done': [('readonly', True)]
166- },
167- ),
168- 'amount_currency': fields.float(
169- 'Amount in Partner Currency', digits=(16,2),
170- required=True,
171- help='Payment amount in the partner currency',
172- states={
173- 'sent': [('readonly', True)],
174- 'rejected': [('readonly', True)],
175- 'done': [('readonly', True)]
176- },
177- ),
178- 'currency': fields.many2one(
179- 'res.currency', 'Partner Currency', required=True,
180- states={
181- 'sent': [('readonly', True)],
182- 'rejected': [('readonly', True)],
183- 'done': [('readonly', True)]
184- },
185- ),
186- 'bank_id': fields.many2one(
187- 'res.partner.bank', 'Destination Bank account',
188- states={
189- 'sent': [('readonly', True)],
190- 'rejected': [('readonly', True)],
191- 'done': [('readonly', True)]
192- },
193- ),
194- 'order_id': fields.many2one(
195- 'payment.order', 'Order', required=True,
196- ondelete='cascade', select=True,
197- states={
198- 'sent': [('readonly', True)],
199- 'rejected': [('readonly', True)],
200- 'done': [('readonly', True)]
201- },
202- ),
203- 'partner_id': fields.many2one(
204- 'res.partner', string="Partner", required=True,
205- help='The Ordering Customer',
206- states={
207- 'sent': [('readonly', True)],
208- 'rejected': [('readonly', True)],
209- 'done': [('readonly', True)]
210- },
211- ),
212- 'date': fields.date(
213- 'Payment Date',
214- help=("If no payment date is specified, the bank will treat this "
215- "payment line directly"
216- ),
217- states={
218- 'sent': [('readonly', True)],
219- 'rejected': [('readonly', True)],
220- 'done': [('readonly', True)]
221- },
222- ),
223- 'state': fields.selection([
224- ('normal','Free'),
225- ('structured','Structured')
226- ], 'Communication Type', required=True,
227- states={
228- 'sent': [('readonly', True)],
229- 'rejected': [('readonly', True)],
230- 'done': [('readonly', True)]
231- },
232- ),
233- }
234- _defaults = {
235- 'export_state': lambda *a: 'draft',
236- 'date_done': lambda *a: False,
237- 'msg': lambda *a: '',
238- }
239-
240- def fields_get(self, cr, uid, fields=None, context=None):
241- res = super(payment_line, self).fields_get(cr, uid, fields, context)
242- if 'communication' in res:
243- res['communication'].setdefault('states', {})
244- res['communication']['states']['structured'] = [('required', True)]
245- if 'communication2' in res:
246- res['communication2'].setdefault('states', {})
247- res['communication2']['states']['structured'] = [('readonly', True)]
248- res['communication2']['states']['normal'] = [('readonly', False)]
249-
250- return res
251-
252- """
253- Hooks for processing direct debit orders, such as implemented in
254- account_direct_debit module.
255- """
256- def get_storno_account_id(self, cr, uid, payment_line_id, amount,
257- currency_id, context=None):
258- """
259- Hook for verifying a match of the payment line with the amount.
260- Return the account associated with the storno.
261- Used in account_banking interactive mode
262- :param payment_line_id: the single payment line id
263- :param amount: the (signed) amount debited from the bank account
264- :param currency: the bank account's currency *browse object*
265- :return: an account if there is a full match, False otherwise
266- :rtype: database id of an account.account resource.
267- """
268-
269- return False
270-
271- def debit_storno(self, cr, uid, payment_line_id, amount,
272- currency_id, storno_retry=True, context=None):
273- """
274- Hook for handling a canceled item of a direct debit order.
275- Presumably called from a bank statement import routine.
276-
277- Decide on the direction that the invoice's workflow needs to take.
278- You may optionally return an incomplete reconcile for the caller
279- to reconcile the now void payment.
280-
281- :param payment_line_id: the single payment line id
282- :param amount: the (negative) amount debited from the bank account
283- :param currency: the bank account's currency *browse object*
284- :param boolean storno_retry: whether the storno is considered fatal \
285- or not.
286- :return: an incomplete reconcile for the caller to fill
287- :rtype: database id of an account.move.reconcile resource.
288- """
289-
290- return False
291-
292-payment_line()
293-
294-class payment_order(osv.osv):
295- '''
296- Enable extra states for payment exports
297- '''
298- _inherit = 'payment.order'
299-
300- _columns = {
301- 'date_scheduled': fields.date(
302- 'Scheduled date if fixed',
303- states={
304- 'sent': [('readonly', True)],
305- 'rejected': [('readonly', True)],
306- 'done': [('readonly', True)]
307- },
308- help='Select a date if you have chosen Preferred Date to be fixed.'
309- ),
310- 'reference': fields.char(
311- 'Reference', size=128, required=True,
312- states={
313- 'sent': [('readonly', True)],
314- 'rejected': [('readonly', True)],
315- 'done': [('readonly', True)]
316- },
317- ),
318- 'mode': fields.many2one(
319- 'payment.mode', 'Payment mode', select=True, required=True,
320- states={
321- 'sent': [('readonly', True)],
322- 'rejected': [('readonly', True)],
323- 'done': [('readonly', True)]
324- },
325- help='Select the Payment Mode to be applied.',
326- ),
327- 'state': fields.selection([
328- ('draft', 'Draft'),
329- ('open','Confirmed'),
330- ('cancel','Cancelled'),
331- ('sent', 'Sent'),
332- ('rejected', 'Rejected'),
333- ('done','Done'),
334- ], 'State', select=True
335- ),
336- 'line_ids': fields.one2many(
337- 'payment.line', 'order_id', 'Payment lines',
338- states={
339- 'sent': [('readonly', True)],
340- 'rejected': [('readonly', True)],
341- 'done': [('readonly', True)]
342- },
343- ),
344- 'user_id': fields.many2one(
345- 'res.users','User', required=True,
346- states={
347- 'sent': [('readonly', True)],
348- 'rejected': [('readonly', True)],
349- 'done': [('readonly', True)]
350- },
351- ),
352- 'date_prefered': fields.selection([
353- ('now', 'Directly'),
354- ('due', 'Due date'),
355- ('fixed', 'Fixed date')
356- ], "Preferred date", change_default=True, required=True,
357- states={
358- 'sent': [('readonly', True)],
359- 'rejected': [('readonly', True)],
360- 'done': [('readonly', True)]
361- },
362- help=("Choose an option for the Payment Order:'Fixed' stands for a "
363- "date specified by you.'Directly' stands for the direct "
364- "execution.'Due date' stands for the scheduled date of "
365- "execution."
366- )
367- ),
368- 'payment_order_type': fields.selection(
369- [('payment', 'Payment'),('debit', 'Direct debit')],
370- 'Payment order type', required=True,
371- ),
372- 'date_sent': fields.date('Send date', readonly=True),
373- }
374-
375- _defaults = {
376- 'payment_order_type': lambda *a: 'payment',
377- }
378-
379- def launch_wizard(self, cr, uid, ids, context=None):
380- """
381- Search for a wizard to launch according to the type.
382- If type is manual. just confirm the order.
383- Previously (pre-v6) in account_payment/wizard/wizard_pay.py
384- """
385- if context == None:
386- context = {}
387- result = {}
388- orders = self.browse(cr, uid, ids, context)
389- order = orders[0]
390- # check if a wizard is defined for the first order
391- if order.mode.type and order.mode.type.ir_model_id:
392- context['active_ids'] = ids
393- wizard_model = order.mode.type.ir_model_id.model
394- wizard_obj = self.pool.get(wizard_model)
395- wizard_id = wizard_obj.create(cr, uid, {}, context)
396- result = {
397- 'name': wizard_obj._description or 'Payment Order Export',
398- 'view_type': 'form',
399- 'view_mode': 'form',
400- 'res_model': wizard_model,
401- 'domain': [],
402- 'context': context,
403- 'type': 'ir.actions.act_window',
404- 'target': 'new',
405- 'res_id': wizard_id,
406- 'nodestroy': True,
407- }
408- else:
409- # should all be manual orders without type or wizard model
410- for order in orders[1:]:
411- if order.mode.type and order.mode.type.ir_model_id:
412- raise osv.except_osv(
413- _('Error'),
414- _('You can only combine payment orders of the same type')
415- )
416- # process manual payments
417- wf_service = netsvc.LocalService('workflow')
418- for order_id in ids:
419- wf_service.trg_validate(uid, 'payment.order', order_id, 'sent', cr)
420- return result
421-
422- def _write_payment_lines(self, cursor, uid, ids, **kwargs):
423- '''
424- ORM method for setting attributes of corresponding payment.line objects.
425- Note that while this is ORM compliant, it is also very ineffecient due
426- to the absence of filters on writes and hence the requirement to
427- filter on the client(=OpenERP server) side.
428- '''
429- if not hasattr(ids, '__iter__'):
430- ids = [ids]
431- payment_line_obj = self.pool.get('payment.line')
432- line_ids = payment_line_obj.search(
433- cursor, uid, [
434- ('order_id', 'in', ids)
435- ])
436- payment_line_obj.write(cursor, uid, line_ids, kwargs)
437-
438- def set_to_draft(self, cursor, uid, ids, *args):
439- '''
440- Set both self and payment lines to state 'draft'.
441- '''
442- self._write_payment_lines(cursor, uid, ids, export_state='draft')
443- return super(payment_order, self).set_to_draft(
444- cursor, uid, ids, *args
445- )
446-
447- def action_sent(self, cursor, uid, ids, *args):
448- '''
449- Set both self and payment lines to state 'sent'.
450- '''
451- self._write_payment_lines(cursor, uid, ids, export_state='sent')
452- self.write(cursor, uid, ids, {'state':'sent',
453- 'date_sent': time.strftime('%Y-%m-%d')})
454- return True
455-
456- def action_rejected(self, cursor, uid, ids, *args):
457- '''
458- Set both self and payment lines to state 'rejected'.
459- '''
460- self._write_payment_lines(cursor, uid, ids, export_state='rejected')
461- wf_service = netsvc.LocalService('workflow')
462- for id in ids:
463- wf_service.trg_validate(uid, 'payment.order', id, 'rejected', cursor)
464- return True
465-
466- def set_done(self, cursor, uid, ids, *args):
467- '''
468- Extend standard transition to update children as well.
469- '''
470- self._write_payment_lines(cursor, uid, ids,
471- export_state='done',
472- date_done=time.strftime('%Y-%m-%d')
473- )
474- return super(payment_order, self).set_done(
475- cursor, uid, ids, *args
476- )
477-
478- def get_wizard(self, type):
479- '''
480- Intercept manual bank payments to include 'sent' state. Default
481- 'manual' payments are flagged 'done' immediately.
482- '''
483- if type == 'BANKMAN':
484- # Note that self._module gets overwritten by inheriters, so make
485- # the module name hard coded.
486- return 'account_banking', 'wizard_account_banking_payment_manual'
487- return super(payment_order, self).get_wizard(type)
488-
489- """
490- Hooks for processing direct debit orders, such as implemented in
491- account_direct_debit module.
492- """
493- def debit_reconcile_transfer(
494- self, cr, uid, payment_order_id, amount, currency, context=None):
495- """
496- Reconcile the payment order if the amount is correct. Return the
497- id of the reconciliation.
498- """
499- raise osv.except_osv(
500- _("Cannot reconcile"),
501- _("Cannot reconcile debit order: "+
502- "Not implemented."))
503-
504- def debit_unreconcile_transfer(
505- self, cr, uid, payment_order_id, reconcile_id, amount, currency,
506- context=None):
507- """ Unreconcile the payment_order if at all possible """
508- raise osv.except_osv(
509- _("Cannot unreconcile"),
510- _("Cannot unreconcile debit order: "+
511- "Not implemented."))
512-
513-payment_order()
514
515 class res_partner_bank(osv.osv):
516 '''
517
518=== modified file 'account_banking/account_banking_view.xml'
519--- account_banking/account_banking_view.xml 2013-01-30 11:34:58 +0000
520+++ account_banking/account_banking_view.xml 2013-05-24 09:03:33 +0000
521@@ -330,45 +330,6 @@
522 </field>
523 </record>
524
525- <!-- Make buttons on payment order sensitive for extra states,
526- restore wizard functionality when making payments
527- -->
528-
529- <record id="view_banking_payment_order_form_1" model="ir.ui.view">
530- <field name="name">account.payment.order.form.banking-1</field>
531- <field name="inherit_id" ref="account_payment.view_payment_order_form" />
532- <field name="model">payment.order</field>
533- <field name="type">form</field>
534- <field name="arch" type="xml">
535- <data>
536- <xpath expr="/form/group/button[@string='Select Invoices to Pay']"
537- position="replace">
538- <button colspan="2" name="%(account_payment.action_create_payment_order)s"
539- string="Select Invoices to Pay" type="action"
540- attrs="{'invisible':[('state','!=','draft')]}"
541- icon="gtk-find"
542- />
543- </xpath>
544- <xpath expr="/form/group/button[@string='Make Payments']"
545- position="replace">
546- <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
547- <newline/>
548- </xpath>
549- </data>
550- </field>
551- </record>
552- <record id="view_banking_payment_order_tree_1" model="ir.ui.view">
553- <field name="name">account.payment.order.tree.banking-1</field>
554- <field name="inherit_id" ref="account_payment.view_payment_order_tree" />
555- <field name="model">payment.order</field>
556- <field name="type">tree</field>
557- <field name="arch" type="xml">
558- <button string="Make Payments" position="replace">
559- <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
560- </button>
561- </field>
562- </record>
563-
564 <!-- Set trigger on IBAN and acc_number fields in res_partner_bank form -->
565 <!--record id="view_partner_bank_account_banking_form_1" model="ir.ui.view">
566 <field name="name">res.partner.bank.form.banking-1</field>
567@@ -459,54 +420,6 @@
568 </field>
569 </record>
570
571- <!-- Insert payment_mode.type -->
572- <record id="view_payment_mode_form_inherit" model="ir.ui.view">
573- <field name="name">payment.mode.form.inherit</field>
574- <field name="model">payment.mode</field>
575- <field name="inherit_id" ref="account_payment.view_payment_mode_form"/>
576- <field name="type">form</field>
577- <field name="arch" type="xml">
578- <field name="company_id" position="after">
579- <field name="type"/>
580- </field>
581- </field>
582- </record>
583- <record id="view_payment_mode_tree_inherit" model="ir.ui.view">
584- <field name="name">payment.mode.tree.inherit</field>
585- <field name="model">payment.mode</field>
586- <field name="inherit_id" ref="account_payment.view_payment_mode_tree"/>
587- <field name="type">tree</field>
588- <field name="arch" type="xml">
589- <field name="company_id" position="after">
590- <field name="type"/>
591- </field>
592- </field>
593- </record>
594-
595- <!-- basic view for payment mode type -->
596- <record model="ir.ui.view" id="view_payment_mode_type_form">
597- <field name="name">view.payment.mode.type.form</field>
598- <field name="model">payment.mode.type</field>
599- <field name="type">form</field>
600- <field name="arch" type="xml">
601- <form>
602- <field name="name" />
603- <field name="code" />
604- <field name="suitable_bank_types"/>
605- <field name="payment_order_type"/>
606- <field name="ir_model_id"/>
607- </form>
608- </field>
609- </record>
610-
611- <!-- fixes https://bugs.launchpad.net/openobject-addons/+bug/903156 for 6.0
612- Note that 6.1 does not suffer from the problem
613- -->
614- <record id="account_payment.action_create_payment_order" model="ir.actions.act_window">
615- <field name="view_id" ref="account_payment.view_create_payment_order"/>
616- </record>
617-
618-
619 <record model="ir.ui.view" id="view_bank_statement_line_tree">
620 <field name="name">Bank statement line tree view</field>
621 <field name="model">account.bank.statement.line</field>
622
623=== modified file 'account_banking/banking_import_transaction.py'
624--- account_banking/banking_import_transaction.py 2013-02-07 09:56:06 +0000
625+++ account_banking/banking_import_transaction.py 2013-05-24 09:03:33 +0000
626@@ -123,43 +123,6 @@
627 # return move_lines to mix with the rest
628 return [x for x in invoice.move_id.line_id if x.account_id.reconcile]
629
630- def _match_debit_order(
631- self, cr, uid, trans, log, context=None):
632-
633- def is_zero(total):
634- return self.pool.get('res.currency').is_zero(
635- cr, uid, trans.statement_id.currency, total)
636-
637- payment_order_obj = self.pool.get('payment.order')
638- order_ids = payment_order_obj.search(
639- cr, uid, [('payment_order_type', '=', 'debit'),
640- ('state', '=', 'sent'),
641- ('date_sent', '<=', str2date(trans.execution_date,
642- '%Y-%m-%d'))
643- ],
644- limit=0, context=context)
645- orders = payment_order_obj.browse(cr, uid, order_ids, context)
646- candidates = [x for x in orders if
647- is_zero(x.total - trans.transferred_amount)]
648- if len(candidates) > 0:
649- # retrieve the common account_id, if any
650- account_id = False
651- for line in candidates[0].line_ids[0].debit_move_line_id.move_id.line_id:
652- if line.account_id.type == 'other':
653- account_id = line.account_id.id
654- break
655- return dict(
656- move_line_ids = False,
657- match_type = 'payment_order',
658- payment_order_ids = [x.id for x in candidates],
659- account_id = account_id,
660- partner_id = False,
661- partner_bank_id = False,
662- reference = False,
663- type='general',
664- )
665- return False
666-
667 def _match_invoice(self, cr, uid, trans, move_lines,
668 partner_ids, bank_account_ids,
669 log, linked_invoices,
670@@ -542,101 +505,6 @@
671 {'voucher_id': voucher_id}, context=context)
672 transaction.refresh()
673
674- def _confirm_storno(
675- self, cr, uid, transaction_id, context=None):
676- """
677- Creation of the reconciliation has been delegated to
678- *a* direct debit module, to allow for various direct debit styles
679- """
680- payment_line_pool = self.pool.get('payment.line')
681- statement_line_pool = self.pool.get('account.bank.statement.line')
682- transaction = self.browse(cr, uid, transaction_id, context=context)
683- if not transaction.payment_line_id:
684- raise osv.except_osv(
685- _("Cannot link with storno"),
686- _("No direct debit order item"))
687- reconcile_id = payment_line_pool.debit_storno(
688- cr, uid,
689- transaction.payment_line_id.id,
690- transaction.statement_line_id.amount,
691- transaction.statement_line_id.currency,
692- transaction.storno_retry,
693- context=context)
694- statement_line_pool.write(
695- cr, uid, transaction.statement_line_id.id,
696- {'reconcile_id': reconcile_id}, context=context)
697- transaction.refresh()
698-
699- def _confirm_payment_order(
700- self, cr, uid, transaction_id, context=None):
701- """
702- Creation of the reconciliation has been delegated to
703- *a* direct debit module, to allow for various direct debit styles
704- """
705- payment_order_obj = self.pool.get('payment.order')
706- statement_line_pool = self.pool.get('account.bank.statement.line')
707- transaction = self.browse(cr, uid, transaction_id, context=context)
708- if not transaction.payment_order_id:
709- raise osv.except_osv(
710- _("Cannot reconcile"),
711- _("Cannot reconcile: no direct debit order"))
712- if transaction.payment_order_id.payment_order_type != 'debit':
713- raise osv.except_osv(
714- _("Cannot reconcile"),
715- _("Reconcile payment order not implemented"))
716- reconcile_id = payment_order_obj.debit_reconcile_transfer(
717- cr, uid,
718- transaction.payment_order_id.id,
719- transaction.statement_line_id.amount,
720- transaction.statement_line_id.currency,
721- context=context)
722- statement_line_pool.write(
723- cr, uid, transaction.statement_line_id.id,
724- {'reconcile_id': reconcile_id}, context=context)
725-
726- def _confirm_payment(
727- self, cr, uid, transaction_id, context=None):
728- """
729- Do some housekeeping on the payment line
730- then pass on to _reconcile_move
731- """
732- transaction = self.browse(cr, uid, transaction_id, context=context)
733- payment_line_obj = self.pool.get('payment.line')
734- payment_line_obj.write(
735- cr, uid, transaction.payment_line_id.id, {
736- 'export_state': 'done',
737- 'date_done': transaction.statement_line_id.date,
738- }
739- )
740- self._confirm_move(cr, uid, transaction_id, context=context)
741-
742- def _cancel_payment(
743- self, cr, uid, transaction_id, context=None):
744- raise osv.except_osv(
745- _("Cannot unreconcile"),
746- _("Cannot unreconcile: this operation is not yet supported for "
747- "match type 'payment'"))
748-
749- def _cancel_payment_order(
750- self, cr, uid, transaction_id, context=None):
751- """
752- """
753- payment_order_obj = self.pool.get('payment.order')
754- transaction = self.browse(cr, uid, transaction_id, context=context)
755- if not transaction.payment_order_id:
756- raise osv.except_osv(
757- _("Cannot unreconcile"),
758- _("Cannot unreconcile: no direct debit order"))
759- if transaction.payment_order_id.payment_order_type != 'debit':
760- raise osv.except_osv(
761- _("Cannot unreconcile"),
762- _("Unreconcile payment order not implemented"))
763- return payment_order_obj.debit_unreconcile_transfer(
764- cr, uid, transaction.payment_order_id.id,
765- transaction.statement_line_id.reconcile_id.id,
766- transaction.statement_line_id.amount,
767- transaction.statement_line_id.currency)
768-
769 def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None):
770 """
771 Legacy method. Allow for canceling bank statement lines that
772@@ -768,70 +636,10 @@
773
774 return True
775
776- def _cancel_storno(
777- self, cr, uid, transaction_id, context=None):
778- """
779- TODO: delegate unreconciliation to the direct debit module,
780- to allow for various direct debit styles
781- """
782- payment_line_obj = self.pool.get('payment.line')
783- reconcile_obj = self.pool.get('account.move.reconcile')
784- transaction = self.browse(cr, uid, transaction_id, context=context)
785-
786- if not transaction.payment_line_id:
787- raise osv.except_osv(
788- _("Cannot cancel link with storno"),
789- _("No direct debit order item"))
790- if not transaction.payment_line_id.storno:
791- raise osv.except_osv(
792- _("Cannot cancel link with storno"),
793- _("The direct debit order item is not marked for storno"))
794-
795- journal = transaction.statement_line_id.statement_id.journal_id
796- if transaction.statement_line_id.amount >= 0:
797- account_id = journal.default_credit_account_id.id
798- else:
799- account_id = journal.default_debit_account_id.id
800- cancel_line = False
801- move_lines = []
802- for move in transaction.statement_line_id.move_ids:
803- # There should usually be just one move, I think
804- move_lines += move.line_id
805- for line in move_lines:
806- if line.account_id.id != account_id:
807- cancel_line = line
808- break
809- if not cancel_line:
810- raise osv.except_osv(
811- _("Cannot cancel link with storno"),
812- _("Line id not found"))
813- reconcile = cancel_line.reconcile_id or cancel_line.reconcile_partial_id
814- lines_reconcile = reconcile.line_id or reconcile.line_partial_ids
815- if len(lines_reconcile) < 3:
816- # delete the full reconciliation
817- reconcile_obj.unlink(cr, uid, reconcile.id, context)
818- else:
819- # we are left with a partial reconciliation
820- reconcile_obj.write(
821- cr, uid, reconcile.id,
822- {'line_partial_ids':
823- [(6, 0, [x.id for x in lines_reconcile if x.id != cancel_line.id])],
824- 'line_id': [(6, 0, [])],
825- }, context)
826- # redo the original payment line reconciliation with the invoice
827- payment_line_obj.write(
828- cr, uid, transaction.payment_line_id.id,
829- {'storno': False}, context)
830- payment_line_obj.debit_reconcile(
831- cr, uid, transaction.payment_line_id.id, context)
832-
833 cancel_map = {
834- 'storno': _cancel_storno,
835 'invoice': _cancel_voucher,
836 'manual': _cancel_voucher,
837 'move': _cancel_voucher,
838- 'payment_order': _cancel_payment_order,
839- 'payment': _cancel_payment,
840 }
841
842 def cancel(self, cr, uid, ids, context=None):
843@@ -850,11 +658,8 @@
844 return True
845
846 confirm_map = {
847- 'storno': _confirm_storno,
848 'invoice': _confirm_move,
849 'manual': _confirm_move,
850- 'payment_order': _confirm_payment_order,
851- 'payment': _confirm_payment,
852 'move': _confirm_move,
853 }
854
855@@ -892,66 +697,6 @@
856 """
857 return True
858
859- def _match_storno(
860- self, cr, uid, trans, log, context=None):
861- payment_line_obj = self.pool.get('payment.line')
862- line_ids = payment_line_obj.search(
863- cr, uid, [
864- ('order_id.payment_order_type', '=', 'debit'),
865- ('order_id.state', 'in', ['sent', 'done']),
866- ('communication', '=', trans.reference)
867- ], context=context)
868- # stornos MUST have an exact match
869- if len(line_ids) == 1:
870- account_id = payment_line_obj.get_storno_account_id(
871- cr, uid, line_ids[0], trans.transferred_amount,
872- trans.statement_id.currency, context=None)
873- if account_id:
874- return dict(
875- account_id = account_id,
876- match_type = 'storno',
877- payment_line_id = line_ids[0],
878- move_line_ids=False,
879- partner_id=False,
880- partner_bank_id=False,
881- reference=False,
882- type='customer',
883- )
884- # TODO log the reason why there is no result for transfers marked
885- # as storno
886- return False
887-
888- def _match_payment(self, cr, uid, trans, payment_lines,
889- partner_ids, bank_account_ids, log, linked_payments):
890- '''
891- Find the payment order belonging to this reference - if there is one
892- This is the easiest part: when sending payments, the returned bank info
893- should be identical to ours.
894- This also means that we do not allow for multiple candidates.
895- '''
896- # TODO: Not sure what side effects are created when payments are done
897- # for credited customer invoices, which will be matched later on too.
898- digits = dp.get_precision('Account')(cr)[1]
899- candidates = [x for x in payment_lines
900- if x.communication == trans.reference
901- and round(x.amount, digits) == -round(trans.transferred_amount, digits)
902- and trans.remote_account in (x.bank_id.acc_number,
903- x.bank_id.acc_number_domestic)
904- ]
905- if len(candidates) == 1:
906- candidate = candidates[0]
907- # Check cache to prevent multiple matching of a single payment
908- if candidate.id not in linked_payments:
909- linked_payments[candidate.id] = True
910- move_info = self._get_move_info(cr, uid, [candidate.move_line_id.id])
911- move_info.update({
912- 'match_type': 'payment',
913- 'payment_line_id': candidate.id,
914- })
915- return move_info
916-
917- return False
918-
919 signal_duplicate_keys = [
920 # does not include float values
921 # such as transferred_amount
922@@ -1059,6 +804,22 @@
923 retval['invoice_ids'] = [x.invoice.id for x in move_lines]
924 retval['type'] = type_map[move_lines[0].invoice.type]
925 return retval
926+
927+ def move_info2values(self, move_info):
928+ vals = {}
929+ vals['match_type'] = move_info['match_type']
930+ vals['move_line_ids'] = [(6, 0, move_info.get('move_line_ids') or [])]
931+ vals['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])]
932+ vals['move_line_id'] = (move_info.get('move_line_ids', False) and
933+ len(move_info['move_line_ids']) == 1 and
934+ move_info['move_line_ids'][0]
935+ )
936+ if move_info['match_type'] == 'invoice':
937+ vals['invoice_id'] = (move_info.get('invoice_ids', False) and
938+ len(move_info['invoice_ids']) == 1 and
939+ move_info['invoice_ids'][0]
940+ )
941+ return vals
942
943 def match(self, cr, uid, ids, results=None, context=None):
944 if not ids:
945@@ -1069,6 +830,7 @@
946 journal_obj = self.pool.get('account.journal')
947 move_line_obj = self.pool.get('account.move.line')
948 payment_line_obj = self.pool.get('payment.line')
949+ has_payment = bool(payment_line_obj)
950 statement_line_obj = self.pool.get('account.bank.statement.line')
951 statement_obj = self.pool.get('account.bank.statement')
952 payment_order_obj = self.pool.get('payment.order')
953@@ -1098,14 +860,15 @@
954 # communication. Most likely there are much less sent payments
955 # than reconciled and open/draft payments.
956 # Strangely, payment_orders still do not have company_id
957- cr.execute("SELECT l.id FROM payment_order o, payment_line l "
958- "WHERE l.order_id = o.id AND "
959- "o.state = 'sent' AND "
960- "l.date_done IS NULL"
961- )
962- payment_line_ids = [x[0] for x in cr.fetchall()]
963- if payment_line_ids:
964- payment_lines = payment_line_obj.browse(cr, uid, payment_line_ids)
965+ if has_payment:
966+ payment_line_ids = payment_line_obj.search(
967+ cr, uid, [
968+ ('order_id.state', '=', 'sent'),
969+ ('date_done', '=', False)], context=context)
970+ payment_lines = payment_line_obj.browse(
971+ cr, uid, payment_line_ids)
972+ else:
973+ payment_lines = False
974
975 # Start the loop over the transactions requested to match
976 transactions = self.browse(cr, uid, ids, context)
977@@ -1270,10 +1033,10 @@
978 # rebrowse the current record after writing
979 transaction = self.browse(cr, uid, transaction.id, context=context)
980 # Match full direct debit orders
981- if transaction.type == bt.DIRECT_DEBIT:
982+ if transaction.type == bt.DIRECT_DEBIT and has_payment:
983 move_info = self._match_debit_order(
984 cr, uid, transaction, results['log'], context)
985- if transaction.type == bt.STORNO:
986+ if transaction.type == bt.STORNO and has_payment:
987 move_info = self._match_storno(
988 cr, uid, transaction, results['log'], context)
989 # Allow inclusion of generated bank invoices
990@@ -1340,6 +1103,10 @@
991 if (not move_info
992 and transaction.transferred_amount < 0 and payment_lines):
993 # Link open payment - if any
994+ # Note that _match_payment is defined in the
995+ # account_banking_payment module which should be installed
996+ # automatically if account_payment is. And if account_payment
997+ # is not installed, then payment_lines will be empty.
998 move_info = self._match_payment(
999 cr, uid, transaction,
1000 payment_lines, partner_ids,
1001@@ -1385,28 +1152,12 @@
1002 self_values = {}
1003 if move_info:
1004 results['trans_matched_cnt'] += 1
1005- self_values['match_type'] = move_info['match_type']
1006- self_values['payment_line_id'] = move_info.get('payment_line_id', False)
1007- self_values['move_line_ids'] = [(6, 0, move_info.get('move_line_ids') or [])]
1008- self_values['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])]
1009- self_values['payment_order_ids'] = [(6, 0, move_info.get('payment_order_ids') or [])]
1010- self_values['payment_order_id'] = (move_info.get('payment_order_ids', False) and
1011- len(move_info['payment_order_ids']) == 1 and
1012- move_info['payment_order_ids'][0]
1013- )
1014- self_values['move_line_id'] = (move_info.get('move_line_ids', False) and
1015- len(move_info['move_line_ids']) == 1 and
1016- move_info['move_line_ids'][0]
1017- )
1018- if move_info['match_type'] == 'invoice':
1019- self_values['invoice_id'] = (move_info.get('invoice_ids', False) and
1020- len(move_info['invoice_ids']) == 1 and
1021- move_info['invoice_ids'][0]
1022- )
1023+ self_values.update(
1024+ self.move_info2values(move_info))
1025+ # values['match_type'] = move_info['match_type']
1026 values['partner_id'] = move_info['partner_id']
1027 values['partner_bank_id'] = move_info['partner_bank_id']
1028 values['type'] = move_info['type']
1029- # values['match_type'] = move_info['match_type']
1030 else:
1031 values['partner_id'] = values['partner_bank_id'] = False
1032 if not values['partner_id'] and partner_ids and len(partner_ids) == 1:
1033@@ -1446,34 +1197,6 @@
1034 statement_obj.button_dummy(
1035 cr, uid, imported_statement_ids, context=context)
1036
1037- if payment_lines:
1038- # As payments lines are treated as individual transactions, the
1039- # batch as a whole is only marked as 'done' when all payment lines
1040- # have been reconciled.
1041- cr.execute(
1042- "SELECT DISTINCT o.id "
1043- "FROM payment_order o, payment_line l "
1044- "WHERE o.state = 'sent' "
1045- "AND o.id = l.order_id "
1046- "AND o.id NOT IN ("
1047- "SELECT DISTINCT order_id AS id "
1048- "FROM payment_line "
1049- "WHERE date_done IS NULL "
1050- "AND id IN (%s)"
1051- ")" % (','.join([str(x) for x in payment_line_ids]))
1052- )
1053- order_ids = [x[0] for x in cr.fetchall()]
1054- if order_ids:
1055- # Use workflow logics for the orders. Recode logic from
1056- # account_payment, in order to increase efficiency.
1057- payment_order_obj.set_done(cr, uid, order_ids,
1058- {'state': 'done'}
1059- )
1060- wf_service = netsvc.LocalService('workflow')
1061- for id in order_ids:
1062- wf_service.trg_validate(
1063- uid, 'payment.order', id, 'done', cr)
1064-
1065 def _get_residual(self, cr, uid, ids, name, args, context=None):
1066 """
1067 Calculate the residual against the candidate reconciliation.
1068@@ -1518,10 +1241,6 @@
1069 elif transaction.match_type == 'invoice':
1070 if transaction.invoice_ids and not transaction.invoice_id:
1071 res[transaction.id] = True
1072- elif transaction.match_type == 'payment_order':
1073- if (transaction.payment_order_ids and not
1074- transaction.payment_order_id):
1075- res[transaction.id] = True
1076 return res
1077
1078 def clear_and_write(self, cr, uid, ids, vals=None, context=None):
1079@@ -1535,12 +1254,10 @@
1080 'invoice_id',
1081 'manual_invoice_id',
1082 'manual_move_line_id',
1083- 'payment_line_id',
1084 ]] +
1085 [(x, [(6, 0, [])]) for x in [
1086 'move_line_ids',
1087 'invoice_ids',
1088- 'payment_order_ids',
1089 ]]))
1090 write_vals.update(vals or {})
1091 return self.write(cr, uid, ids, write_vals, context=context)
1092@@ -1645,23 +1362,15 @@
1093 # match fields
1094 'match_type': fields.selection(
1095 [('manual', 'Manual'), ('move','Move'), ('invoice', 'Invoice'),
1096- ('payment', 'Payment'), ('payment_order', 'Payment order'),
1097- ('storno', 'Storno')],
1098- 'Match type'),
1099+ ], 'Match type'),
1100 'match_multi': fields.function(
1101 _get_match_multi, method=True, string='Multi match',
1102 type='boolean'),
1103- 'payment_order_ids': fields.many2many(
1104- 'payment.order', 'banking_transaction_payment_order_rel',
1105- 'order_id', 'transaction_id', 'Payment orders'),
1106- 'payment_order_id': fields.many2one(
1107- 'payment.order', 'Payment order to reconcile'),
1108 'move_line_ids': fields.many2many(
1109 'account.move.line', 'banking_transaction_move_line_rel',
1110 'move_line_id', 'transaction_id', 'Matching entries'),
1111 'move_line_id': fields.many2one(
1112 'account.move.line', 'Entry to reconcile'),
1113- 'payment_line_id': fields.many2one('payment.line', 'Payment line'),
1114 'invoice_ids': fields.many2many(
1115 'account.invoice', 'banking_transaction_invoice_rel',
1116 'invoice_id', 'transaction_id', 'Matching invoices'),
1117@@ -1722,9 +1431,8 @@
1118 'match_type': fields.related(
1119 'import_transaction_id', 'match_type', type='selection',
1120 selection=[('manual', 'Manual'), ('move','Move'),
1121- ('invoice', 'Invoice'), ('payment', 'Payment'),
1122- ('payment_order', 'Payment order'),
1123- ('storno', 'Storno')],
1124+ ('invoice', 'Invoice'),
1125+ ],
1126 string='Match type', readonly=True,),
1127 'state': fields.selection(
1128 [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',
1129
1130=== modified file 'account_banking/data/account_banking_data.xml'
1131--- account_banking/data/account_banking_data.xml 2012-04-14 08:58:58 +0000
1132+++ account_banking/data/account_banking_data.xml 2013-05-24 09:03:33 +0000
1133@@ -20,12 +20,5 @@
1134 <record id="base_iban.bank_swift_field" model="res.partner.bank.type.field">
1135 <field eval="False" name="required"/>
1136 </record>
1137- <!-- Add manual bank transfer as default payment option -->
1138- <record model="payment.mode.type" id="account_banking.manual_bank_tranfer">
1139- <field name="name">Manual Bank Transfer</field>
1140- <field name="code">BANKMAN</field>
1141- <field name="suitable_bank_types"
1142- eval="[(6,0,[ref('base.bank_normal'),ref('base_iban.bank_iban'),])]" />
1143- </record>
1144 </data>
1145 </openerp>
1146
1147=== modified file 'account_banking/security/ir.model.access.csv'
1148--- account_banking/security/ir.model.access.csv 2011-12-21 15:49:58 +0000
1149+++ account_banking/security/ir.model.access.csv 2013-05-24 09:03:33 +0000
1150@@ -2,6 +2,5 @@
1151 "access_account_banking_settings","account.banking.account.settings","model_account_banking_account_settings","account.group_account_manager",1,1,1,1
1152 "access_account_banking_settings_user","account.banking.account.settings user","model_account_banking_account_settings","account.group_account_user",1,0,0,0
1153 "access_account_banking_import","account.bankimport","model_account_banking_imported_file","account.group_account_user",1,1,1,1
1154-"access_payment_mode_type","payment.mode.type","model_payment_mode_type","account_payment.group_account_payment",1,1,1,1
1155 "access_banking_import_transaction","Banking addons - Bank import transaction","model_banking_import_transaction","account.group_account_user",1,1,1,1
1156 "access_banking_transaction_wizard","Banking addons - Transaction wizard","model_banking_transaction_wizard","account.group_account_user",1,1,1,1
1157
1158=== modified file 'account_banking/wizard/__init__.py'
1159--- account_banking/wizard/__init__.py 2011-12-19 12:03:32 +0000
1160+++ account_banking/wizard/__init__.py 2013-05-24 09:03:33 +0000
1161@@ -19,8 +19,6 @@
1162 #
1163 ##############################################################################
1164 import bank_import
1165-import bank_payment_manual
1166-import account_payment_order
1167 import banking_transaction_wizard
1168
1169 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1170
1171=== modified file 'account_banking/wizard/bank_import.py'
1172--- account_banking/wizard/bank_import.py 2012-07-11 10:37:31 +0000
1173+++ account_banking/wizard/bank_import.py 2013-05-24 09:03:33 +0000
1174@@ -85,13 +85,10 @@
1175 'invoice_ids': fields.many2many(
1176 'account.invoice', 'banking_import_line_invoice_rel',
1177 'line_id', 'invoice_id'),
1178- 'payment_order_id': fields.many2one('payment.order', 'Payment order'),
1179 'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'),
1180 'transaction_type': fields.selection([
1181 # TODO: payment terminal etc...
1182 ('invoice', 'Invoice payment'),
1183- ('payment_order_line', 'Payment from a payment order'),
1184- ('payment_order', 'Aggregate payment order'),
1185 ('storno', 'Canceled debit order'),
1186 ('bank_costs', 'Bank costs'),
1187 ('unknown', 'Unknown'),
1188
1189=== modified file 'account_banking/wizard/banking_transaction_wizard.py'
1190--- account_banking/wizard/banking_transaction_wizard.py 2012-12-01 18:31:34 +0000
1191+++ account_banking/wizard/banking_transaction_wizard.py 2013-05-24 09:03:33 +0000
1192@@ -320,15 +320,6 @@
1193 'import_transaction_id', 'writeoff_journal_id',
1194 type='many2one', relation='account.journal',
1195 string='Write-off journal'),
1196- 'payment_line_id': fields.related(
1197- 'import_transaction_id', 'payment_line_id', string="Matching payment or storno",
1198- type='many2one', relation='payment.line', readonly=True),
1199- 'payment_order_ids': fields.related(
1200- 'import_transaction_id', 'payment_order_ids', string="Matching payment orders",
1201- type='many2many', relation='payment.order'),
1202- 'payment_order_id': fields.related(
1203- 'import_transaction_id', 'payment_order_id', string="Payment order to reconcile",
1204- type='many2one', relation='payment.order'),
1205 'invoice_ids': fields.related(
1206 'import_transaction_id', 'invoice_ids', string="Matching invoices",
1207 type='many2many', relation='account.invoice'),
1208
1209=== modified file 'account_banking/wizard/banking_transaction_wizard.xml'
1210--- account_banking/wizard/banking_transaction_wizard.xml 2013-01-13 14:11:44 +0000
1211+++ account_banking/wizard/banking_transaction_wizard.xml 2013-05-24 09:03:33 +0000
1212@@ -8,7 +8,6 @@
1213 <field name="arch" type="xml">
1214 <form string="Match transaction">
1215 <!-- fields used for form logic -->
1216- <field name="payment_order_ids" invisible="True"/>
1217 <field name="invoice_ids" invisible="True"/>
1218 <field name="move_line_ids" invisible="True"/>
1219 <field name="match_multi" invisible="True"/>
1220@@ -36,9 +35,6 @@
1221 <separator string="Multiple matches" colspan="2"/>
1222 <label colspan="2" string="Multiple matches were found for this bank transfer. You must pick one of the matches or select a match manually below." />
1223 </group>
1224- <field name='payment_line_id'
1225- attrs="{'invisible': [('match_type', '!=', 'storno'),('match_type', '!=', 'payment')]}"
1226- />
1227 <group attrs="{'readonly': [('match_multi', '!=', True)]}" col="8">
1228 <!-- show if we have an invoice type match (but the user may need to select from multiple options)
1229 or whenever there is an invoice_id (e.g. in case of a manual match)
1230@@ -53,10 +49,6 @@
1231 attrs="{'readonly': [('match_multi', '=', False)], 'invisible': [('match_type', '!=', 'move'),('invoice_id', '=', False)]}"
1232 domain="[('id', 'in', move_line_ids[0][2])]"
1233 />
1234- <field name='payment_order_id'
1235- attrs="{'readonly': [('match_multi', '=', False)], 'invisible': [('match_type', '!=', 'payment_order')]}"
1236- domain="[('id', 'in', payment_order_ids[0][2])]"
1237- />
1238 <field name='analytic_account_id' />
1239 </group>
1240 <button colspan="1"
1241
1242=== modified file 'account_banking_nl_clieop/__terp__.py'
1243--- account_banking_nl_clieop/__terp__.py 2011-12-27 12:00:52 +0000
1244+++ account_banking_nl_clieop/__terp__.py 2013-05-24 09:03:33 +0000
1245@@ -30,7 +30,7 @@
1246 'author': 'EduSense BV',
1247 'website': 'http://www.edusense.nl',
1248 'category': 'Account Banking',
1249- 'depends': ['account_banking'],
1250+ 'depends': ['account_banking_payment'],
1251 'init_xml': [],
1252 'update_xml': [
1253 'account_banking_nl_clieop.xml',
1254
1255=== added directory 'account_banking_payment'
1256=== added file 'account_banking_payment/__init__.py'
1257--- account_banking_payment/__init__.py 1970-01-01 00:00:00 +0000
1258+++ account_banking_payment/__init__.py 2013-05-24 09:03:33 +0000
1259@@ -0,0 +1,1 @@
1260+import model
1261
1262=== added file 'account_banking_payment/__openerp__.py'
1263--- account_banking_payment/__openerp__.py 1970-01-01 00:00:00 +0000
1264+++ account_banking_payment/__openerp__.py 2013-05-24 09:03:33 +0000
1265@@ -0,0 +1,57 @@
1266+# -*- coding: utf-8 -*-
1267+##############################################################################
1268+#
1269+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
1270+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
1271+#
1272+# All other contributions are (C) by their respective contributors
1273+#
1274+# All Rights Reserved
1275+#
1276+# This program is free software: you can redistribute it and/or modify
1277+# it under the terms of the GNU Affero General Public License as
1278+# published by the Free Software Foundation, either version 3 of the
1279+# License, or (at your option) any later version.
1280+#
1281+# This program is distributed in the hope that it will be useful,
1282+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1283+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1284+# GNU Affero General Public License for more details.
1285+#
1286+# You should have received a copy of the GNU Affero General Public License
1287+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1288+#
1289+##############################################################################
1290+
1291+{
1292+ 'name': 'Account Banking - Payments',
1293+ 'version': '0.1.164',
1294+ 'license': 'AGPL-3',
1295+ 'author': 'Banking addons community',
1296+ 'website': 'https://launchpad.net/banking-addons',
1297+ 'category': 'Banking addons',
1298+ 'depends': [
1299+ 'account_banking',
1300+ 'account_payment',
1301+ ],
1302+ 'data': [
1303+ 'view/account_payment.xml',
1304+ 'view/banking_transaction_wizard.xml',
1305+ 'view/payment_mode_type.xml',
1306+ 'view/bank_payment_manual.xml',
1307+ 'data/payment_mode_type.xml',
1308+ 'workflow/account_payment.xml',
1309+ 'security/ir.model.access.csv',
1310+ ],
1311+ 'description': '''
1312+ This addon adds payment infrastructure to the Banking Addons.
1313+
1314+ * Extends payments for digital banking:
1315+ + Adapted workflow in payments to reflect banking operations
1316+ + Relies on account_payment mechanics to extend with export generators.
1317+ - ClieOp3 (NL) payment and direct debit orders files available as
1318+ account_banking_nl_clieop
1319+ ''',
1320+ 'auto_install': True,
1321+ 'installable': False,
1322+}
1323
1324=== added directory 'account_banking_payment/data'
1325=== added file 'account_banking_payment/data/payment_mode_type.xml'
1326--- account_banking_payment/data/payment_mode_type.xml 1970-01-01 00:00:00 +0000
1327+++ account_banking_payment/data/payment_mode_type.xml 2013-05-24 09:03:33 +0000
1328@@ -0,0 +1,14 @@
1329+<?xml version="1.0" encoding="utf-8"?>
1330+<openerp>
1331+ <data>
1332+ <!-- Add manual bank transfer as default payment option -->
1333+ <record model="payment.mode.type" id="account_banking.manual_bank_tranfer">
1334+ <field name="name">Manual Bank Transfer</field>
1335+ <field name="code">BANKMAN</field>
1336+ <field name="suitable_bank_types"
1337+ eval="[(6,0,[ref('base.bank_normal'),ref('base_iban.bank_iban'),])]" />
1338+ <field name="ir_model_id"
1339+ ref="account_banking_payment.model_payment_manual"/>
1340+ </record>
1341+ </data>
1342+</openerp>
1343
1344=== added directory 'account_banking_payment/model'
1345=== added file 'account_banking_payment/model/__init__.py'
1346--- account_banking_payment/model/__init__.py 1970-01-01 00:00:00 +0000
1347+++ account_banking_payment/model/__init__.py 2013-05-24 09:03:33 +0000
1348@@ -0,0 +1,10 @@
1349+import account_payment
1350+import payment_line
1351+import payment_mode
1352+import payment_mode_type
1353+import payment_order_create
1354+import banking_import_transaction
1355+import account_bank_statement_line
1356+import banking_transaction_wizard
1357+import bank_payment_manual
1358+import banking_import_line
1359
1360=== added file 'account_banking_payment/model/account_bank_statement_line.py'
1361--- account_banking_payment/model/account_bank_statement_line.py 1970-01-01 00:00:00 +0000
1362+++ account_banking_payment/model/account_bank_statement_line.py 2013-05-24 09:03:33 +0000
1363@@ -0,0 +1,40 @@
1364+# -*- coding: utf-8 -*-
1365+##############################################################################
1366+#
1367+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
1368+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
1369+#
1370+# All other contributions are (C) by their respective contributors
1371+#
1372+# All Rights Reserved
1373+#
1374+# This program is free software: you can redistribute it and/or modify
1375+# it under the terms of the GNU Affero General Public License as
1376+# published by the Free Software Foundation, either version 3 of the
1377+# License, or (at your option) any later version.
1378+#
1379+# This program is distributed in the hope that it will be useful,
1380+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1381+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1382+# GNU Affero General Public License for more details.
1383+#
1384+# You should have received a copy of the GNU Affero General Public License
1385+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1386+#
1387+##############################################################################
1388+
1389+from openerp.osv import orm, fields
1390+
1391+
1392+class account_bank_statement_line(orm.Model):
1393+ _inherit = 'account.bank.statement.line'
1394+ _columns = {
1395+ 'match_type': fields.related(
1396+ # Add payment and storno types
1397+ 'import_transaction_id', 'match_type', type='selection',
1398+ selection=[('manual', 'Manual'), ('move','Move'),
1399+ ('invoice', 'Invoice'), ('payment', 'Payment'),
1400+ ('payment_order', 'Payment order'),
1401+ ('storno', 'Storno')],
1402+ string='Match type', readonly=True,),
1403+ }
1404
1405=== added file 'account_banking_payment/model/account_payment.py'
1406--- account_banking_payment/model/account_payment.py 1970-01-01 00:00:00 +0000
1407+++ account_banking_payment/model/account_payment.py 2013-05-24 09:03:33 +0000
1408@@ -0,0 +1,240 @@
1409+# -*- coding: utf-8 -*-
1410+##############################################################################
1411+#
1412+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
1413+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
1414+#
1415+# All other contributions are (C) by their respective contributors
1416+#
1417+# All Rights Reserved
1418+#
1419+# This program is free software: you can redistribute it and/or modify
1420+# it under the terms of the GNU Affero General Public License as
1421+# published by the Free Software Foundation, either version 3 of the
1422+# License, or (at your option) any later version.
1423+#
1424+# This program is distributed in the hope that it will be useful,
1425+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1426+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1427+# GNU Affero General Public License for more details.
1428+#
1429+# You should have received a copy of the GNU Affero General Public License
1430+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1431+#
1432+##############################################################################
1433+
1434+from openerp.osv import orm, fields
1435+from openerp.tools.translate import _
1436+from openerp import netsvc
1437+
1438+
1439+class payment_order(orm.Model):
1440+ '''
1441+ Enable extra states for payment exports
1442+ '''
1443+ _inherit = 'payment.order'
1444+
1445+ _columns = {
1446+ 'date_scheduled': fields.date(
1447+ 'Scheduled date if fixed',
1448+ states={
1449+ 'sent': [('readonly', True)],
1450+ 'rejected': [('readonly', True)],
1451+ 'done': [('readonly', True)]
1452+ },
1453+ help='Select a date if you have chosen Preferred Date to be fixed.'
1454+ ),
1455+ 'reference': fields.char(
1456+ 'Reference', size=128, required=True,
1457+ states={
1458+ 'sent': [('readonly', True)],
1459+ 'rejected': [('readonly', True)],
1460+ 'done': [('readonly', True)]
1461+ },
1462+ ),
1463+ 'mode': fields.many2one(
1464+ 'payment.mode', 'Payment mode', select=True, required=True,
1465+ states={
1466+ 'sent': [('readonly', True)],
1467+ 'rejected': [('readonly', True)],
1468+ 'done': [('readonly', True)]
1469+ },
1470+ help='Select the Payment Mode to be applied.',
1471+ ),
1472+ 'state': fields.selection([
1473+ ('draft', 'Draft'),
1474+ ('open','Confirmed'),
1475+ ('cancel','Cancelled'),
1476+ ('sent', 'Sent'),
1477+ ('rejected', 'Rejected'),
1478+ ('done','Done'),
1479+ ], 'State', select=True
1480+ ),
1481+ 'line_ids': fields.one2many(
1482+ 'payment.line', 'order_id', 'Payment lines',
1483+ states={
1484+ 'sent': [('readonly', True)],
1485+ 'rejected': [('readonly', True)],
1486+ 'done': [('readonly', True)]
1487+ },
1488+ ),
1489+ 'user_id': fields.many2one(
1490+ 'res.users','User', required=True,
1491+ states={
1492+ 'sent': [('readonly', True)],
1493+ 'rejected': [('readonly', True)],
1494+ 'done': [('readonly', True)]
1495+ },
1496+ ),
1497+ 'date_prefered': fields.selection([
1498+ ('now', 'Directly'),
1499+ ('due', 'Due date'),
1500+ ('fixed', 'Fixed date')
1501+ ], "Preferred date", change_default=True, required=True,
1502+ states={
1503+ 'sent': [('readonly', True)],
1504+ 'rejected': [('readonly', True)],
1505+ 'done': [('readonly', True)]
1506+ },
1507+ help=("Choose an option for the Payment Order:'Fixed' stands for a "
1508+ "date specified by you.'Directly' stands for the direct "
1509+ "execution.'Due date' stands for the scheduled date of "
1510+ "execution."
1511+ )
1512+ ),
1513+ 'payment_order_type': fields.selection(
1514+ [('payment', 'Payment'),('debit', 'Direct debit')],
1515+ 'Payment order type', required=True,
1516+ ),
1517+ 'date_sent': fields.date('Send date', readonly=True),
1518+ }
1519+
1520+ _defaults = {
1521+ 'payment_order_type': 'payment',
1522+ }
1523+
1524+ def launch_wizard(self, cr, uid, ids, context=None):
1525+ """
1526+ Search for a wizard to launch according to the type.
1527+ If type is manual. just confirm the order.
1528+ Previously (pre-v6) in account_payment/wizard/wizard_pay.py
1529+ """
1530+ if context == None:
1531+ context = {}
1532+ result = {}
1533+ orders = self.browse(cr, uid, ids, context)
1534+ order = orders[0]
1535+ # check if a wizard is defined for the first order
1536+ if order.mode.type and order.mode.type.ir_model_id:
1537+ context['active_ids'] = ids
1538+ wizard_model = order.mode.type.ir_model_id.model
1539+ wizard_obj = self.pool.get(wizard_model)
1540+ wizard_id = wizard_obj.create(cr, uid, {}, context)
1541+ result = {
1542+ 'name': wizard_obj._description or _('Payment Order Export'),
1543+ 'view_type': 'form',
1544+ 'view_mode': 'form',
1545+ 'res_model': wizard_model,
1546+ 'domain': [],
1547+ 'context': context,
1548+ 'type': 'ir.actions.act_window',
1549+ 'target': 'new',
1550+ 'res_id': wizard_id,
1551+ 'nodestroy': True,
1552+ }
1553+ else:
1554+ # should all be manual orders without type or wizard model
1555+ for order in orders[1:]:
1556+ if order.mode.type and order.mode.type.ir_model_id:
1557+ raise orm.except_orm(
1558+ _('Error'),
1559+ _('You can only combine payment orders of the same type')
1560+ )
1561+ # process manual payments
1562+ wf_service = netsvc.LocalService('workflow')
1563+ for order_id in ids:
1564+ wf_service.trg_validate(uid, 'payment.order', order_id, 'sent', cr)
1565+ return result
1566+
1567+ def _write_payment_lines(self, cr, uid, ids, **kwargs):
1568+ '''
1569+ ORM method for setting attributes of corresponding payment.line objects.
1570+ Note that while this is ORM compliant, it is also very ineffecient due
1571+ to the absence of filters on writes and hence the requirement to
1572+ filter on the client(=OpenERP server) side.
1573+ '''
1574+ if not hasattr(ids, '__iter__'):
1575+ ids = [ids]
1576+ payment_line_obj = self.pool.get('payment.line')
1577+ line_ids = payment_line_obj.search(
1578+ cr, uid, [
1579+ ('order_id', 'in', ids)
1580+ ])
1581+ payment_line_obj.write(cr, uid, line_ids, kwargs)
1582+
1583+ def set_to_draft(self, cr, uid, ids, *args):
1584+ '''
1585+ Set both self and payment lines to state 'draft'.
1586+ '''
1587+ self._write_payment_lines(cr, uid, ids, export_state='draft')
1588+ return super(payment_order, self).set_to_draft(
1589+ cr, uid, ids, *args
1590+ )
1591+
1592+ def action_sent(self, cr, uid, ids, context=None):
1593+ '''
1594+ Set both self and payment lines to state 'sent'.
1595+ '''
1596+ self._write_payment_lines(cr, uid, ids, export_state='sent')
1597+ self.write(cr, uid, ids, {
1598+ 'state': 'sent',
1599+ 'date_sent': fields.date.context_today(
1600+ self, cr, uid, context=context),
1601+ }, context=context)
1602+ return True
1603+
1604+ def action_rejected(self, cr, uid, ids, *args):
1605+ '''
1606+ Set both self and payment lines to state 'rejected'.
1607+ '''
1608+ self._write_payment_lines(cr, uid, ids, export_state='rejected')
1609+ wf_service = netsvc.LocalService('workflow')
1610+ for id in ids:
1611+ wf_service.trg_validate(uid, 'payment.order', id, 'rejected', cr)
1612+ return True
1613+
1614+ def set_done(self, cr, uid, ids, *args):
1615+ '''
1616+ Extend standard transition to update children as well.
1617+ '''
1618+ self._write_payment_lines(
1619+ cr, uid, ids,
1620+ export_state='done',
1621+ date_done=fields.date.context_today(self, cr, uid))
1622+ return super(payment_order, self).set_done(
1623+ cr, uid, ids, *args
1624+ )
1625+
1626+ """
1627+ Hooks for processing direct debit orders, such as implemented in
1628+ account_direct_debit module.
1629+ """
1630+ def debit_reconcile_transfer(
1631+ self, cr, uid, payment_order_id, amount, currency, context=None):
1632+ """
1633+ Reconcile the payment order if the amount is correct. Return the
1634+ id of the reconciliation.
1635+ """
1636+ raise orm.except_orm(
1637+ _("Cannot reconcile"),
1638+ _("Cannot reconcile debit order: "+
1639+ "Not implemented."))
1640+
1641+ def debit_unreconcile_transfer(
1642+ self, cr, uid, payment_order_id, reconcile_id, amount, currency,
1643+ context=None):
1644+ """ Unreconcile the payment_order if at all possible """
1645+ raise orm.except_orm(
1646+ _("Cannot unreconcile"),
1647+ _("Cannot unreconcile debit order: "+
1648+ "Not implemented."))
1649
1650=== renamed file 'account_banking/wizard/bank_payment_manual.py' => 'account_banking_payment/model/bank_payment_manual.py'
1651--- account_banking/wizard/bank_payment_manual.py 2010-12-20 10:58:51 +0000
1652+++ account_banking_payment/model/bank_payment_manual.py 2013-05-24 09:03:33 +0000
1653@@ -1,20 +1,24 @@
1654-# -*- encoding: utf-8 -*-
1655+# -*- coding: utf-8 -*-
1656 ##############################################################################
1657 #
1658 # Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
1659+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
1660+#
1661+# All other contributions are (C) by their respective contributors
1662+#
1663 # All Rights Reserved
1664 #
1665 # This program is free software: you can redistribute it and/or modify
1666-# it under the terms of the GNU General Public License as published by
1667-# the Free Software Foundation, either version 3 of the License, or
1668-# (at your option) any later version.
1669+# it under the terms of the GNU Affero General Public License as
1670+# published by the Free Software Foundation, either version 3 of the
1671+# License, or (at your option) any later version.
1672 #
1673 # This program is distributed in the hope that it will be useful,
1674 # but WITHOUT ANY WARRANTY; without even the implied warranty of
1675 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1676-# GNU General Public License for more details.
1677+# GNU Affero General Public License for more details.
1678 #
1679-# You should have received a copy of the GNU General Public License
1680+# You should have received a copy of the GNU Affero General Public License
1681 # along with this program. If not, see <http://www.gnu.org/licenses/>.
1682 #
1683 ##############################################################################
1684@@ -24,30 +28,26 @@
1685 bank transfers.
1686 '''
1687
1688-import wizard
1689-import pooler
1690-
1691-class payment_manual(wizard.interface):
1692- def _action_set_state_sent(self, cursor, uid, data, context):
1693- '''
1694- Set the payment order in state 'sent' to reflect money in transfer.
1695- '''
1696- payment_order_obj = pooler.get_pool(cursor.dbname)\
1697- .get('payment.order')
1698- payment_order_obj.action_sent(cursor, uid, [data['id']], context)
1699- return {}
1700-
1701- states= {
1702- 'init' : {
1703- 'actions': [],
1704- 'result': {
1705- 'type':'action',
1706- 'action': _action_set_state_sent,
1707- 'state': 'end'
1708- }
1709+from openerp.osv import orm, fields
1710+from openerp import netsvc
1711+
1712+
1713+class payment_manual(orm.TransientModel):
1714+ _name = 'payment.manual'
1715+ _description = 'Set payment orders to \'sent\' manually'
1716+
1717+ def default_get(self, cr, uid, fields_list, context=None):
1718+ if context and context.get('active_ids'):
1719+ payment_order_obj = self.pool.get('payment.order')
1720+ wf_service = netsvc.LocalService('workflow')
1721+ for order_id in context['active_ids']:
1722+ wf_service.trg_validate(
1723+ uid, 'payment.order', order_id, 'sent', cr)
1724+ return super(payment_manual, self).default_get(
1725+ cr, uid, fields_list, context=None)
1726+
1727+ _columns = {
1728+ # dummy field, to trigger a call to default_get
1729+ 'name': fields.char('Name', size=1),
1730 }
1731- }
1732-
1733-payment_manual('account_banking.payment_manual')
1734-
1735-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1736+
1737
1738=== added file 'account_banking_payment/model/banking_import_line.py'
1739--- account_banking_payment/model/banking_import_line.py 1970-01-01 00:00:00 +0000
1740+++ account_banking_payment/model/banking_import_line.py 2013-05-24 09:03:33 +0000
1741@@ -0,0 +1,45 @@
1742+# -*- coding: utf-8 -*-
1743+##############################################################################
1744+#
1745+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
1746+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
1747+#
1748+# All other contributions are (C) by their respective contributors
1749+#
1750+# All Rights Reserved
1751+#
1752+# This program is free software: you can redistribute it and/or modify
1753+# it under the terms of the GNU Affero General Public License as
1754+# published by the Free Software Foundation, either version 3 of the
1755+# License, or (at your option) any later version.
1756+#
1757+# This program is distributed in the hope that it will be useful,
1758+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1759+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1760+# GNU Affero General Public License for more details.
1761+#
1762+# You should have received a copy of the GNU Affero General Public License
1763+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1764+#
1765+##############################################################################
1766+
1767+from openerp.osv import orm, fields
1768+
1769+
1770+class banking_import_line(orm.TransientModel):
1771+ _inherit = 'banking.import.line'
1772+ _columns = {
1773+ 'payment_order_id': fields.many2one(
1774+ 'payment.order', 'Payment order'),
1775+ 'transaction_type': fields.selection([
1776+ # Add payment order related transaction types
1777+ ('invoice', 'Invoice payment'),
1778+ ('payment_order_line', 'Payment from a payment order'),
1779+ ('payment_order', 'Aggregate payment order'),
1780+ ('storno', 'Canceled debit order'),
1781+ ('bank_costs', 'Bank costs'),
1782+ ('unknown', 'Unknown'),
1783+ ], 'Transaction type'),
1784+ }
1785+
1786+
1787
1788=== added file 'account_banking_payment/model/banking_import_transaction.py'
1789--- account_banking_payment/model/banking_import_transaction.py 1970-01-01 00:00:00 +0000
1790+++ account_banking_payment/model/banking_import_transaction.py 2013-05-24 09:03:33 +0000
1791@@ -0,0 +1,381 @@
1792+# -*- coding: utf-8 -*-
1793+##############################################################################
1794+#
1795+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
1796+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
1797+#
1798+# All other contributions are (C) by their respective contributors
1799+#
1800+# All Rights Reserved
1801+#
1802+# This program is free software: you can redistribute it and/or modify
1803+# it under the terms of the GNU Affero General Public License as
1804+# published by the Free Software Foundation, either version 3 of the
1805+# License, or (at your option) any later version.
1806+#
1807+# This program is distributed in the hope that it will be useful,
1808+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1809+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1810+# GNU Affero General Public License for more details.
1811+#
1812+# You should have received a copy of the GNU Affero General Public License
1813+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1814+#
1815+##############################################################################
1816+
1817+from openerp.osv import orm, fields
1818+from openerp import netsvc
1819+from openerp.tools.translate import _
1820+from openerp.addons.decimal_precision import decimal_precision as dp
1821+
1822+
1823+class banking_import_transaction(orm.Model):
1824+ _inherit = 'banking.import.transaction'
1825+
1826+ def _match_debit_order(
1827+ self, cr, uid, trans, log, context=None):
1828+
1829+ def is_zero(total):
1830+ return self.pool.get('res.currency').is_zero(
1831+ cr, uid, trans.statement_id.currency, total)
1832+
1833+ payment_order_obj = self.pool.get('payment.order')
1834+
1835+ order_ids = payment_order_obj.search(
1836+ cr, uid, [('payment_order_type', '=', 'debit'),
1837+ ('state', '=', 'sent'),
1838+ ('date_sent', '<=', trans.execution_date),
1839+ ],
1840+ limit=0, context=context)
1841+ orders = payment_order_obj.browse(cr, uid, order_ids, context)
1842+ candidates = [x for x in orders if
1843+ is_zero(x.total - trans.transferred_amount)]
1844+ if len(candidates) > 0:
1845+ # retrieve the common account_id, if any
1846+ account_id = False
1847+ for line in candidates[0].line_ids[0].debit_move_line_id.move_id.line_id:
1848+ if line.account_id.type == 'other':
1849+ account_id = line.account_id.id
1850+ break
1851+ return dict(
1852+ move_line_ids = False,
1853+ match_type = 'payment_order',
1854+ payment_order_ids = [x.id for x in candidates],
1855+ account_id = account_id,
1856+ partner_id = False,
1857+ partner_bank_id = False,
1858+ reference = False,
1859+ type='general',
1860+ )
1861+ return False
1862+
1863+ def _match_storno(
1864+ self, cr, uid, trans, log, context=None):
1865+ payment_line_obj = self.pool.get('payment.line')
1866+ line_ids = payment_line_obj.search(
1867+ cr, uid, [
1868+ ('order_id.payment_order_type', '=', 'debit'),
1869+ ('order_id.state', 'in', ['sent', 'done']),
1870+ ('communication', '=', trans.reference)
1871+ ], context=context)
1872+ # stornos MUST have an exact match
1873+ if len(line_ids) == 1:
1874+ account_id = payment_line_obj.get_storno_account_id(
1875+ cr, uid, line_ids[0], trans.transferred_amount,
1876+ trans.statement_id.currency, context=None)
1877+ if account_id:
1878+ return dict(
1879+ account_id = account_id,
1880+ match_type = 'storno',
1881+ payment_line_id = line_ids[0],
1882+ move_line_ids=False,
1883+ partner_id=False,
1884+ partner_bank_id=False,
1885+ reference=False,
1886+ type='customer',
1887+ )
1888+ # TODO log the reason why there is no result for transfers marked
1889+ # as storno
1890+ return False
1891+
1892+ def _match_payment(self, cr, uid, trans, payment_lines,
1893+ partner_ids, bank_account_ids, log, linked_payments):
1894+ '''
1895+ Find the payment order belonging to this reference - if there is one
1896+ This is the easiest part: when sending payments, the returned bank info
1897+ should be identical to ours.
1898+ This also means that we do not allow for multiple candidates.
1899+ '''
1900+ # TODO: Not sure what side effects are created when payments are done
1901+ # for credited customer invoices, which will be matched later on too.
1902+ digits = dp.get_precision('Account')(cr)[1]
1903+ candidates = [
1904+ x for x in payment_lines
1905+ if x.communication == trans.reference
1906+ and round(x.amount, digits) == -round(
1907+ trans.transferred_amount, digits)
1908+ and trans.remote_account in (x.bank_id.acc_number,
1909+ x.bank_id.acc_number_domestic)
1910+ ]
1911+ if len(candidates) == 1:
1912+ candidate = candidates[0]
1913+ # Check cache to prevent multiple matching of a single payment
1914+ if candidate.id not in linked_payments:
1915+ linked_payments[candidate.id] = True
1916+ move_info = self._get_move_info(
1917+ cr, uid, [candidate.move_line_id.id])
1918+ move_info.update({
1919+ 'match_type': 'payment',
1920+ 'payment_line_id': candidate.id,
1921+ })
1922+ return move_info
1923+
1924+ return False
1925+
1926+ def _confirm_storno(
1927+ self, cr, uid, transaction_id, context=None):
1928+ """
1929+ Creation of the reconciliation has been delegated to
1930+ *a* direct debit module, to allow for various direct debit styles
1931+ """
1932+ payment_line_pool = self.pool.get('payment.line')
1933+ statement_line_pool = self.pool.get('account.bank.statement.line')
1934+ transaction = self.browse(cr, uid, transaction_id, context=context)
1935+ if not transaction.payment_line_id:
1936+ raise orm.except_orm(
1937+ _("Cannot link with storno"),
1938+ _("No direct debit order item"))
1939+ reconcile_id = payment_line_pool.debit_storno(
1940+ cr, uid,
1941+ transaction.payment_line_id.id,
1942+ transaction.statement_line_id.amount,
1943+ transaction.statement_line_id.currency,
1944+ transaction.storno_retry,
1945+ context=context)
1946+ statement_line_pool.write(
1947+ cr, uid, transaction.statement_line_id.id,
1948+ {'reconcile_id': reconcile_id}, context=context)
1949+ transaction.refresh()
1950+
1951+ def _confirm_payment_order(
1952+ self, cr, uid, transaction_id, context=None):
1953+ """
1954+ Creation of the reconciliation has been delegated to
1955+ *a* direct debit module, to allow for various direct debit styles
1956+ """
1957+ payment_order_obj = self.pool.get('payment.order')
1958+ statement_line_pool = self.pool.get('account.bank.statement.line')
1959+ transaction = self.browse(cr, uid, transaction_id, context=context)
1960+ if not transaction.payment_order_id:
1961+ raise orm.except_orm(
1962+ _("Cannot reconcile"),
1963+ _("Cannot reconcile: no direct debit order"))
1964+ if transaction.payment_order_id.payment_order_type != 'debit':
1965+ raise orm.except_orm(
1966+ _("Cannot reconcile"),
1967+ _("Reconcile payment order not implemented"))
1968+ reconcile_id = payment_order_obj.debit_reconcile_transfer(
1969+ cr, uid,
1970+ transaction.payment_order_id.id,
1971+ transaction.statement_line_id.amount,
1972+ transaction.statement_line_id.currency,
1973+ context=context)
1974+ statement_line_pool.write(
1975+ cr, uid, transaction.statement_line_id.id,
1976+ {'reconcile_id': reconcile_id}, context=context)
1977+
1978+ def _confirm_payment(
1979+ self, cr, uid, transaction_id, context=None):
1980+ """
1981+ Do some housekeeping on the payment line
1982+ then pass on to _reconcile_move
1983+ """
1984+ transaction = self.browse(cr, uid, transaction_id, context=context)
1985+ payment_line_obj = self.pool.get('payment.line')
1986+ payment_line_obj.write(
1987+ cr, uid, transaction.payment_line_id.id, {
1988+ 'export_state': 'done',
1989+ 'date_done': transaction.statement_line_id.date,
1990+ }
1991+ )
1992+ self._confirm_move(cr, uid, transaction_id, context=context)
1993+ # Check if the payment order is 'done'
1994+ order_id = transaction.payment_line_id.order_id.id
1995+ other_lines = payment_line_obj.search(
1996+ cr, uid, [
1997+ ('order_id', '=', order_id),
1998+ ('date_done', '=', False),
1999+ ], context=context)
2000+ if not other_lines:
2001+ wf_service = netsvc.LocalService('workflow')
2002+ wf_service.trg_validate(
2003+ uid, 'payment.order', order_id, 'done', cr)
2004+
2005+ def _cancel_payment(
2006+ self, cr, uid, transaction_id, context=None):
2007+ """
2008+ Do not support cancelling individual lines yet, because the workflow
2009+ of the payment order does not support reopening.
2010+ """
2011+ raise orm.except_orm(
2012+ _("Cannot unreconcile"),
2013+ _("Cannot unreconcile: this operation is not yet supported for "
2014+ "match type 'payment'"))
2015+
2016+ def _cancel_payment_order(
2017+ self, cr, uid, transaction_id, context=None):
2018+ """
2019+ """
2020+ payment_order_obj = self.pool.get('payment.order')
2021+ transaction = self.browse(cr, uid, transaction_id, context=context)
2022+ if not transaction.payment_order_id:
2023+ raise orm.except_orm(
2024+ _("Cannot unreconcile"),
2025+ _("Cannot unreconcile: no direct debit order"))
2026+ if transaction.payment_order_id.payment_order_type != 'debit':
2027+ raise orm.except_orm(
2028+ _("Cannot unreconcile"),
2029+ _("Unreconcile payment order not implemented"))
2030+ return payment_order_obj.debit_unreconcile_transfer(
2031+ cr, uid, transaction.payment_order_id.id,
2032+ transaction.statement_line_id.reconcile_id.id,
2033+ transaction.statement_line_id.amount,
2034+ transaction.statement_line_id.currency)
2035+
2036+ def _cancel_storno(
2037+ self, cr, uid, transaction_id, context=None):
2038+ """
2039+ TODO: delegate unreconciliation to the direct debit module,
2040+ to allow for various direct debit styles
2041+ """
2042+ payment_line_obj = self.pool.get('payment.line')
2043+ reconcile_obj = self.pool.get('account.move.reconcile')
2044+ transaction = self.browse(cr, uid, transaction_id, context=context)
2045+
2046+ if not transaction.payment_line_id:
2047+ raise orm.except_orm(
2048+ _("Cannot cancel link with storno"),
2049+ _("No direct debit order item"))
2050+ if not transaction.payment_line_id.storno:
2051+ raise orm.except_orm(
2052+ _("Cannot cancel link with storno"),
2053+ _("The direct debit order item is not marked for storno"))
2054+
2055+ journal = transaction.statement_line_id.statement_id.journal_id
2056+ if transaction.statement_line_id.amount >= 0:
2057+ account_id = journal.default_credit_account_id.id
2058+ else:
2059+ account_id = journal.default_debit_account_id.id
2060+ cancel_line = False
2061+ move_lines = []
2062+ for move in transaction.statement_line_id.move_ids:
2063+ # There should usually be just one move, I think
2064+ move_lines += move.line_id
2065+ for line in move_lines:
2066+ if line.account_id.id != account_id:
2067+ cancel_line = line
2068+ break
2069+ if not cancel_line:
2070+ raise orm.except_orm(
2071+ _("Cannot cancel link with storno"),
2072+ _("Line id not found"))
2073+ reconcile = cancel_line.reconcile_id or cancel_line.reconcile_partial_id
2074+ lines_reconcile = reconcile.line_id or reconcile.line_partial_ids
2075+ if len(lines_reconcile) < 3:
2076+ # delete the full reconciliation
2077+ reconcile_obj.unlink(cr, uid, reconcile.id, context)
2078+ else:
2079+ # we are left with a partial reconciliation
2080+ reconcile_obj.write(
2081+ cr, uid, reconcile.id,
2082+ {'line_partial_ids':
2083+ [(6, 0, [x.id for x in lines_reconcile
2084+ if x.id != cancel_line.id])],
2085+ 'line_id': [(6, 0, [])],
2086+ }, context)
2087+ # redo the original payment line reconciliation with the invoice
2088+ payment_line_obj.write(
2089+ cr, uid, transaction.payment_line_id.id,
2090+ {'storno': False}, context)
2091+ payment_line_obj.debit_reconcile(
2092+ cr, uid, transaction.payment_line_id.id, context)
2093+
2094+ _columns = {
2095+ 'match_type': fields.selection(
2096+ # Add payment and storno types
2097+ [
2098+ ('manual', 'Manual'),
2099+ ('move','Move'),
2100+ ('invoice', 'Invoice'),
2101+ ('payment', 'Payment'),
2102+ ('payment_order', 'Payment order'),
2103+ ('storno', 'Storno'),
2104+ ],
2105+ 'Match type'),
2106+ 'payment_order_ids': fields.many2many(
2107+ 'payment.order', 'banking_transaction_payment_order_rel',
2108+ 'order_id', 'transaction_id', 'Payment orders'),
2109+ 'payment_order_id': fields.many2one(
2110+ 'payment.order', 'Payment order to reconcile'),
2111+ 'payment_line_id': fields.many2one('payment.line', 'Payment line'),
2112+ }
2113+
2114+ def _get_match_multi(self, cr, uid, ids, name, args, context=None):
2115+ if not ids:
2116+ return {}
2117+ res = super(banking_import_transaction, self)._get_match_multi(
2118+ cr, uid, ids, name, args, context=context)
2119+ for transaction in self.browse(cr, uid, ids, context):
2120+ if transaction.match_type == 'payment_order':
2121+ if (transaction.payment_order_ids and not
2122+ transaction.payment_order_id):
2123+ res[transaction.id] = True
2124+ return res
2125+
2126+ def clear_and_write(self, cr, uid, ids, vals=None, context=None):
2127+ super(banking_import_transaction, self).clear_and_write(
2128+ cr, uid, ids, vals=vals, context=context)
2129+ return self.write(
2130+ cr, uid, ids, {
2131+ 'payment_line_id': False,
2132+ 'payment_order_ids': [(6, 0, [])],
2133+ },
2134+ context=context)
2135+
2136+ def move_info2values(self, move_info):
2137+ vals = super(banking_import_transaction, self).move_info2values(
2138+ move_info)
2139+ vals['payment_line_id'] = move_info.get('payment_line_id', False)
2140+ vals['payment_order_ids'] = [
2141+ (6, 0, move_info.get('payment_order_ids') or [])]
2142+ vals['payment_order_id'] = (
2143+ move_info.get('payment_order_ids', False) and
2144+ len(move_info['payment_order_ids']) == 1 and
2145+ move_info['payment_order_ids'][0]
2146+ )
2147+ return vals
2148+
2149+ def match(self, cr, uid, ids, results=None, context=None):
2150+ res = super(banking_import_transaction, self).match(
2151+ cr, uid, ids, results=results, context=context)
2152+
2153+ return res
2154+
2155+ def __init__(self, pool, cr):
2156+ """
2157+ Updating the function maps to handle the match types that this
2158+ module adds.
2159+ """
2160+ super(banking_import_transaction, self).__init__(pool, cr)
2161+
2162+ banking_import_transaction.confirm_map.update({
2163+ 'storno': banking_import_transaction._confirm_storno,
2164+ 'payment_order': banking_import_transaction._confirm_payment_order,
2165+ 'payment': banking_import_transaction._confirm_payment,
2166+ })
2167+
2168+ banking_import_transaction.cancel_map.update({
2169+ 'storno': banking_import_transaction._cancel_storno,
2170+ 'payment_order': banking_import_transaction._cancel_payment_order,
2171+ 'payment': banking_import_transaction._cancel_payment,
2172+ })
2173
2174=== added file 'account_banking_payment/model/banking_transaction_wizard.py'
2175--- account_banking_payment/model/banking_transaction_wizard.py 1970-01-01 00:00:00 +0000
2176+++ account_banking_payment/model/banking_transaction_wizard.py 2013-05-24 09:03:33 +0000
2177@@ -0,0 +1,45 @@
2178+# -*- coding: utf-8 -*-
2179+##############################################################################
2180+#
2181+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
2182+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
2183+#
2184+# All other contributions are (C) by their respective contributors
2185+#
2186+# All Rights Reserved
2187+#
2188+# This program is free software: you can redistribute it and/or modify
2189+# it under the terms of the GNU Affero General Public License as
2190+# published by the Free Software Foundation, either version 3 of the
2191+# License, or (at your option) any later version.
2192+#
2193+# This program is distributed in the hope that it will be useful,
2194+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2195+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2196+# GNU Affero General Public License for more details.
2197+#
2198+# You should have received a copy of the GNU Affero General Public License
2199+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2200+#
2201+##############################################################################
2202+
2203+from openerp.osv import orm, fields
2204+
2205+
2206+class banking_transaction_wizard(orm.TransientModel):
2207+ _inherit = 'banking.transaction.wizard'
2208+ _columns = {
2209+ 'payment_line_id': fields.related(
2210+ 'import_transaction_id', 'payment_line_id',
2211+ string="Matching payment or storno",
2212+ type='many2one', relation='payment.line',
2213+ readonly=True),
2214+ 'payment_order_ids': fields.related(
2215+ 'import_transaction_id', 'payment_order_ids',
2216+ string="Matching payment orders",
2217+ type='many2many', relation='payment.order'),
2218+ 'payment_order_id': fields.related(
2219+ 'import_transaction_id', 'payment_order_id',
2220+ string="Payment order to reconcile",
2221+ type='many2one', relation='payment.order'),
2222+ }
2223
2224=== added file 'account_banking_payment/model/payment_line.py'
2225--- account_banking_payment/model/payment_line.py 1970-01-01 00:00:00 +0000
2226+++ account_banking_payment/model/payment_line.py 2013-05-24 09:03:33 +0000
2227@@ -0,0 +1,218 @@
2228+# -*- coding: utf-8 -*-
2229+##############################################################################
2230+#
2231+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
2232+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
2233+#
2234+# All other contributions are (C) by their respective contributors
2235+#
2236+# All Rights Reserved
2237+#
2238+# This program is free software: you can redistribute it and/or modify
2239+# it under the terms of the GNU Affero General Public License as
2240+# published by the Free Software Foundation, either version 3 of the
2241+# License, or (at your option) any later version.
2242+#
2243+# This program is distributed in the hope that it will be useful,
2244+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2245+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2246+# GNU Affero General Public License for more details.
2247+#
2248+# You should have received a copy of the GNU Affero General Public License
2249+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2250+#
2251+##############################################################################
2252+
2253+from openerp.osv import orm, fields
2254+
2255+
2256+class payment_line(orm.Model):
2257+ '''
2258+ Add extra export_state and date_done fields; make destination bank account
2259+ mandatory, as it makes no sense to send payments into thin air.
2260+ Edit: Payments can be by cash too, which is prohibited by mandatory bank
2261+ accounts.
2262+ '''
2263+ _inherit = 'payment.line'
2264+ _columns = {
2265+ # New fields
2266+ 'export_state': fields.selection([
2267+ ('draft', 'Draft'),
2268+ ('open','Confirmed'),
2269+ ('cancel','Cancelled'),
2270+ ('sent', 'Sent'),
2271+ ('rejected', 'Rejected'),
2272+ ('done','Done'),
2273+ ], 'State', select=True
2274+ ),
2275+ 'msg': fields.char('Message', size=255, required=False, readonly=True),
2276+
2277+ # Redefined fields: added states
2278+ 'date_done': fields.datetime('Date Confirmed', select=True,
2279+ readonly=True),
2280+ 'name': fields.char(
2281+ 'Your Reference', size=64, required=True,
2282+ states={
2283+ 'sent': [('readonly', True)],
2284+ 'rejected': [('readonly', True)],
2285+ 'done': [('readonly', True)]
2286+ },
2287+ ),
2288+ 'communication': fields.char(
2289+ 'Communication', size=64, required=False,
2290+ help=("Used as the message between ordering customer and current "
2291+ "company. Depicts 'What do you want to say to the recipient"
2292+ " about this order ?'"
2293+ ),
2294+ states={
2295+ 'sent': [('readonly', True)],
2296+ 'rejected': [('readonly', True)],
2297+ 'done': [('readonly', True)]
2298+ },
2299+ ),
2300+ 'communication2': fields.char(
2301+ 'Communication 2', size=128,
2302+ help='The successor message of Communication.',
2303+ states={
2304+ 'sent': [('readonly', True)],
2305+ 'rejected': [('readonly', True)],
2306+ 'done': [('readonly', True)]
2307+ },
2308+ ),
2309+ 'move_line_id': fields.many2one(
2310+ 'account.move.line', 'Entry line',
2311+ domain=[('reconcile_id','=', False),
2312+ ('account_id.type', '=','payable')
2313+ ],
2314+ help=('This Entry Line will be referred for the information of '
2315+ 'the ordering customer.'
2316+ ),
2317+ states={
2318+ 'sent': [('readonly', True)],
2319+ 'rejected': [('readonly', True)],
2320+ 'done': [('readonly', True)]
2321+ },
2322+ ),
2323+ 'amount_currency': fields.float(
2324+ 'Amount in Partner Currency', digits=(16,2),
2325+ required=True,
2326+ help='Payment amount in the partner currency',
2327+ states={
2328+ 'sent': [('readonly', True)],
2329+ 'rejected': [('readonly', True)],
2330+ 'done': [('readonly', True)]
2331+ },
2332+ ),
2333+ 'currency': fields.many2one(
2334+ 'res.currency', 'Partner Currency', required=True,
2335+ states={
2336+ 'sent': [('readonly', True)],
2337+ 'rejected': [('readonly', True)],
2338+ 'done': [('readonly', True)]
2339+ },
2340+ ),
2341+ 'bank_id': fields.many2one(
2342+ 'res.partner.bank', 'Destination Bank account',
2343+ states={
2344+ 'sent': [('readonly', True)],
2345+ 'rejected': [('readonly', True)],
2346+ 'done': [('readonly', True)]
2347+ },
2348+ ),
2349+ 'order_id': fields.many2one(
2350+ 'payment.order', 'Order', required=True,
2351+ ondelete='cascade', select=True,
2352+ states={
2353+ 'sent': [('readonly', True)],
2354+ 'rejected': [('readonly', True)],
2355+ 'done': [('readonly', True)]
2356+ },
2357+ ),
2358+ 'partner_id': fields.many2one(
2359+ 'res.partner', string="Partner", required=True,
2360+ help='The Ordering Customer',
2361+ states={
2362+ 'sent': [('readonly', True)],
2363+ 'rejected': [('readonly', True)],
2364+ 'done': [('readonly', True)]
2365+ },
2366+ ),
2367+ 'date': fields.date(
2368+ 'Payment Date',
2369+ help=("If no payment date is specified, the bank will treat this "
2370+ "payment line directly"
2371+ ),
2372+ states={
2373+ 'sent': [('readonly', True)],
2374+ 'rejected': [('readonly', True)],
2375+ 'done': [('readonly', True)]
2376+ },
2377+ ),
2378+ 'state': fields.selection([
2379+ ('normal','Free'),
2380+ ('structured','Structured')
2381+ ], 'Communication Type', required=True,
2382+ states={
2383+ 'sent': [('readonly', True)],
2384+ 'rejected': [('readonly', True)],
2385+ 'done': [('readonly', True)]
2386+ },
2387+ ),
2388+ }
2389+ _defaults = {
2390+ 'export_state': 'draft',
2391+ 'date_done': False,
2392+ 'msg': '',
2393+ }
2394+
2395+ def fields_get(self, cr, uid, fields=None, context=None):
2396+ res = super(payment_line, self).fields_get(cr, uid, fields, context)
2397+ if 'communication' in res:
2398+ res['communication'].setdefault('states', {})
2399+ res['communication']['states']['structured'] = [('required', True)]
2400+ if 'communication2' in res:
2401+ res['communication2'].setdefault('states', {})
2402+ res['communication2']['states']['structured'] = [('readonly', True)]
2403+ res['communication2']['states']['normal'] = [('readonly', False)]
2404+
2405+ return res
2406+
2407+ """
2408+ Hooks for processing direct debit orders, such as implemented in
2409+ account_direct_debit module.
2410+ """
2411+ def get_storno_account_id(self, cr, uid, payment_line_id, amount,
2412+ currency_id, context=None):
2413+ """
2414+ Hook for verifying a match of the payment line with the amount.
2415+ Return the account associated with the storno.
2416+ Used in account_banking interactive mode
2417+ :param payment_line_id: the single payment line id
2418+ :param amount: the (signed) amount debited from the bank account
2419+ :param currency: the bank account's currency *browse object*
2420+ :return: an account if there is a full match, False otherwise
2421+ :rtype: database id of an account.account resource.
2422+ """
2423+
2424+ return False
2425+
2426+ def debit_storno(self, cr, uid, payment_line_id, amount,
2427+ currency_id, storno_retry=True, context=None):
2428+ """
2429+ Hook for handling a canceled item of a direct debit order.
2430+ Presumably called from a bank statement import routine.
2431+
2432+ Decide on the direction that the invoice's workflow needs to take.
2433+ You may optionally return an incomplete reconcile for the caller
2434+ to reconcile the now void payment.
2435+
2436+ :param payment_line_id: the single payment line id
2437+ :param amount: the (negative) amount debited from the bank account
2438+ :param currency: the bank account's currency *browse object*
2439+ :param boolean storno_retry: whether the storno is considered fatal \
2440+ or not.
2441+ :return: an incomplete reconcile for the caller to fill
2442+ :rtype: database id of an account.move.reconcile resource.
2443+ """
2444+
2445+ return False
2446
2447=== added file 'account_banking_payment/model/payment_mode.py'
2448--- account_banking_payment/model/payment_mode.py 1970-01-01 00:00:00 +0000
2449+++ account_banking_payment/model/payment_mode.py 2013-05-24 09:03:33 +0000
2450@@ -0,0 +1,51 @@
2451+# -*- coding: utf-8 -*-
2452+##############################################################################
2453+#
2454+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
2455+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
2456+#
2457+# All other contributions are (C) by their respective contributors
2458+#
2459+# All Rights Reserved
2460+#
2461+# This program is free software: you can redistribute it and/or modify
2462+# it under the terms of the GNU Affero General Public License as
2463+# published by the Free Software Foundation, either version 3 of the
2464+# License, or (at your option) any later version.
2465+#
2466+# This program is distributed in the hope that it will be useful,
2467+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2468+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2469+# GNU Affero General Public License for more details.
2470+#
2471+# You should have received a copy of the GNU Affero General Public License
2472+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2473+#
2474+##############################################################################
2475+
2476+from openerp.osv import orm, fields
2477+
2478+
2479+class payment_mode(orm.Model):
2480+ ''' Restoring the payment type from version 5,
2481+ used to select the export wizard (if any) '''
2482+ _inherit = "payment.mode"
2483+
2484+ def suitable_bank_types(self, cr, uid, payment_mode_id=None, context=None):
2485+ """ Reinstates functional code for suitable bank type filtering.
2486+ Current code in account_payment is disfunctional.
2487+ """
2488+ res = []
2489+ payment_mode = self.browse(
2490+ cr, uid, payment_mode_id, context)
2491+ if (payment_mode and payment_mode.type and
2492+ payment_mode.type.suitable_bank_types):
2493+ res = [type.code for type in payment_mode.type.suitable_bank_types]
2494+ return res
2495+
2496+ _columns = {
2497+ 'type': fields.many2one(
2498+ 'payment.mode.type', 'Payment type',
2499+ help='Select the Payment Type for the Payment Mode.'
2500+ ),
2501+ }
2502
2503=== added file 'account_banking_payment/model/payment_mode_type.py'
2504--- account_banking_payment/model/payment_mode_type.py 1970-01-01 00:00:00 +0000
2505+++ account_banking_payment/model/payment_mode_type.py 2013-05-24 09:03:33 +0000
2506@@ -0,0 +1,62 @@
2507+# -*- coding: utf-8 -*-
2508+##############################################################################
2509+#
2510+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
2511+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
2512+#
2513+# All other contributions are (C) by their respective contributors
2514+#
2515+# All Rights Reserved
2516+#
2517+# This program is free software: you can redistribute it and/or modify
2518+# it under the terms of the GNU Affero General Public License as
2519+# published by the Free Software Foundation, either version 3 of the
2520+# License, or (at your option) any later version.
2521+#
2522+# This program is distributed in the hope that it will be useful,
2523+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2524+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2525+# GNU Affero General Public License for more details.
2526+#
2527+# You should have received a copy of the GNU Affero General Public License
2528+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2529+#
2530+##############################################################################
2531+
2532+from openerp.osv import orm, fields
2533+
2534+
2535+class payment_mode_type(orm.Model):
2536+ _name = 'payment.mode.type'
2537+ _description = 'Payment Mode Type'
2538+ _columns = {
2539+ 'name': fields.char(
2540+ 'Name', size=64, required=True,
2541+ help='Payment Type'
2542+ ),
2543+ 'code': fields.char(
2544+ 'Code', size=64, required=True,
2545+ help='Specify the Code for Payment Type'
2546+ ),
2547+ # Setting suitable_bank_types to required pending
2548+ # https://bugs.launchpad.net/openobject-addons/+bug/786845
2549+ 'suitable_bank_types': fields.many2many(
2550+ 'res.partner.bank.type',
2551+ 'bank_type_payment_type_rel',
2552+ 'pay_type_id','bank_type_id',
2553+ 'Suitable bank types', required=True),
2554+ 'ir_model_id': fields.many2one(
2555+ 'ir.model', 'Payment wizard',
2556+ help=('Select the Payment Wizard for payments of this type. '
2557+ 'Leave empty for manual processing'),
2558+ domain=[('osv_memory', '=', True)],
2559+ ),
2560+ 'payment_order_type': fields.selection(
2561+ [('payment', 'Payment'),('debit', 'Direct debit')],
2562+ 'Payment order type', required=True,
2563+ ),
2564+ }
2565+
2566+ _defaults = {
2567+ 'payment_order_type': 'payment',
2568+ }
2569
2570=== renamed file 'account_banking/wizard/account_payment_order.py' => 'account_banking_payment/model/payment_order_create.py'
2571--- account_banking/wizard/account_payment_order.py 2013-01-21 20:25:00 +0000
2572+++ account_banking_payment/model/payment_order_create.py 2013-05-24 09:03:33 +0000
2573@@ -2,35 +2,33 @@
2574 ##############################################################################
2575 #
2576 # Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
2577+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
2578+#
2579+# All other contributions are (C) by their respective contributors
2580+#
2581 # All Rights Reserved
2582 #
2583 # This program is free software: you can redistribute it and/or modify
2584-# it under the terms of the GNU General Public License as published by
2585-# the Free Software Foundation, either version 3 of the License, or
2586-# (at your option) any later version.
2587+# it under the terms of the GNU Affero General Public License as
2588+# published by the Free Software Foundation, either version 3 of the
2589+# License, or (at your option) any later version.
2590 #
2591 # This program is distributed in the hope that it will be useful,
2592 # but WITHOUT ANY WARRANTY; without even the implied warranty of
2593 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2594-# GNU General Public License for more details.
2595+# GNU Affero General Public License for more details.
2596 #
2597-# You should have received a copy of the GNU General Public License
2598+# You should have received a copy of the GNU Affero General Public License
2599 # along with this program. If not, see <http://www.gnu.org/licenses/>.
2600 #
2601 ##############################################################################
2602
2603-import datetime
2604-from osv import osv
2605-from account_banking.struct import struct
2606-from account_banking.parsers import convert
2607-
2608-today = datetime.date.today
2609-
2610-def str2date(str):
2611- dt = convert.str2date(str, '%Y-%m-%d')
2612- return datetime.date(dt.year, dt.month, dt.day)
2613-
2614-class payment_order_create(osv.osv_memory):
2615+from datetime import datetime
2616+from openerp.osv import orm, fields
2617+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
2618+
2619+
2620+class payment_order_create(orm.TransientModel):
2621 _inherit = 'payment.order.create'
2622
2623 def create_payment(self, cr, uid, ids, context=None):
2624@@ -57,8 +55,9 @@
2625 ### account banking
2626 # t = None
2627 # line2bank = line_obj.line2bank(cr, uid, line_ids, t, context)
2628- line2bank = line_obj.line2bank(cr, uid, line_ids, payment.mode.id, context)
2629- _today = today()
2630+ line2bank = line_obj.line2bank(
2631+ cr, uid, line_ids, payment.mode.id, context)
2632+ _today = fields.date.context_today(self, cr, uid, context=context)
2633 ### end account banking
2634
2635 ## Finally populate the current payment with new lines:
2636@@ -69,16 +68,18 @@
2637 elif payment.date_prefered == 'due':
2638 ### account_banking
2639 # date_to_pay = line.date_maturity
2640- date_to_pay = line.date_maturity and \
2641- str2date(line.date_maturity) > _today\
2642- and line.date_maturity or False
2643+ date_to_pay = (
2644+ line.date_maturity
2645+ if line.date_maturity and line.date_maturity > _today
2646+ else False)
2647 ### end account banking
2648 elif payment.date_prefered == 'fixed':
2649 ### account_banking
2650 # date_to_pay = payment.date_planned
2651- date_to_pay = payment.date_planned and \
2652- str2date(payment.date_planned) > _today\
2653- and payment.date_planned or False
2654+ date_to_pay = (
2655+ payment.date_planned
2656+ if payment.date_planned and payment.date_planned > _today
2657+ else False)
2658 ### end account banking
2659
2660 ### account_banking
2661@@ -107,7 +108,7 @@
2662 amount_currency = line.amount_to_pay
2663 ### end account_banking
2664
2665- payment_obj.create(cr, uid,{
2666+ payment_obj.create(cr, uid, {
2667 'move_line_id': line.id,
2668 'amount_currency': amount_currency,
2669 'bank_id': line2bank.get(line.id),
2670@@ -123,5 +124,3 @@
2671 'currency': line.invoice and line.invoice.currency_id.id or line.journal_id.currency.id or line.journal_id.company_id.currency_id.id,
2672 }, context=context)
2673 return {'type': 'ir.actions.act_window_close'}
2674-
2675-payment_order_create()
2676
2677=== added directory 'account_banking_payment/security'
2678=== added file 'account_banking_payment/security/ir.model.access.csv'
2679--- account_banking_payment/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
2680+++ account_banking_payment/security/ir.model.access.csv 2013-05-24 09:03:33 +0000
2681@@ -0,0 +1,2 @@
2682+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
2683+"access_payment_mode_type","payment.mode.type","model_payment_mode_type","account_payment.group_account_payment",1,1,1,1
2684
2685=== added directory 'account_banking_payment/view'
2686=== added file 'account_banking_payment/view/account_payment.xml'
2687--- account_banking_payment/view/account_payment.xml 1970-01-01 00:00:00 +0000
2688+++ account_banking_payment/view/account_payment.xml 2013-05-24 09:03:33 +0000
2689@@ -0,0 +1,45 @@
2690+<?xml version="1.0" encoding="utf-8"?>
2691+<openerp>
2692+ <data>
2693+ <!-- Make buttons on payment order sensitive for extra states,
2694+ restore wizard functionality when making payments
2695+ -->
2696+
2697+ <record id="view_banking_payment_order_form_1" model="ir.ui.view">
2698+ <field name="name">account.payment.order.form.banking-1</field>
2699+ <field name="inherit_id" ref="account_payment.view_payment_order_form" />
2700+ <field name="model">payment.order</field>
2701+ <field name="type">form</field>
2702+ <field name="arch" type="xml">
2703+ <data>
2704+ <xpath expr="/form/group/button[@string='Select Invoices to Pay']"
2705+ position="replace">
2706+ <button colspan="2" name="%(account_payment.action_create_payment_order)s"
2707+ string="Select Invoices to Pay" type="action"
2708+ attrs="{'invisible':[('state','!=','draft')]}"
2709+ icon="gtk-find"
2710+ />
2711+ </xpath>
2712+ <xpath expr="/form/group/button[@string='Make Payments']"
2713+ position="replace">
2714+ <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
2715+ <newline/>
2716+ </xpath>
2717+ </data>
2718+ </field>
2719+ </record>
2720+
2721+ <record id="view_banking_payment_order_tree_1" model="ir.ui.view">
2722+ <field name="name">account.payment.order.tree.banking-1</field>
2723+ <field name="inherit_id" ref="account_payment.view_payment_order_tree" />
2724+ <field name="model">payment.order</field>
2725+ <field name="type">tree</field>
2726+ <field name="arch" type="xml">
2727+ <button string="Make Payments" position="replace">
2728+ <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
2729+ </button>
2730+ </field>
2731+ </record>
2732+
2733+ </data>
2734+</openerp>
2735
2736=== added file 'account_banking_payment/view/bank_payment_manual.xml'
2737--- account_banking_payment/view/bank_payment_manual.xml 1970-01-01 00:00:00 +0000
2738+++ account_banking_payment/view/bank_payment_manual.xml 2013-05-24 09:03:33 +0000
2739@@ -0,0 +1,16 @@
2740+<?xml version="1.0" encoding="utf-8"?>
2741+<openerp>
2742+ <data>
2743+ <record id="view_payment_manual_form" model="ir.ui.view">
2744+ <field name="name">Form for manual payment wizard</field>
2745+ <field name="model">payment.manual</field>
2746+ <field name="type">form</field>
2747+ <field name="arch" type="xml">
2748+ <form>
2749+ <label string="Payment order(s) have been set to 'sent'"/>
2750+ <button special="cancel" icon="gtk-ok" string="OK"/>
2751+ </form>
2752+ </field>
2753+ </record>
2754+ </data>
2755+</openerp>
2756
2757=== added file 'account_banking_payment/view/banking_transaction_wizard.xml'
2758--- account_banking_payment/view/banking_transaction_wizard.xml 1970-01-01 00:00:00 +0000
2759+++ account_banking_payment/view/banking_transaction_wizard.xml 2013-05-24 09:03:33 +0000
2760@@ -0,0 +1,36 @@
2761+<?xml version="1.0" encoding="utf-8"?>
2762+<openerp>
2763+ <data>
2764+ <record model="ir.ui.view" id="transaction_wizard">
2765+ <field name="name">transaction.wizard</field>
2766+ <field name="model">banking.transaction.wizard</field>
2767+ <field name="inherit_id"
2768+ ref="account_banking.transaction_wizard_first" />
2769+ <field name="type">form</field>
2770+ <field name="arch" type="xml">
2771+ <field name="invoice_ids" position="before">
2772+ <field name="payment_order_ids" invisible="True"/>
2773+ </field>
2774+ <xpath expr="//group/separator[@string='Multiple matches']/.."
2775+ position="after">
2776+ <field name='payment_line_id'
2777+ attrs="{'invisible': [
2778+ ('match_type', '!=', 'storno'),
2779+ ('match_type', '!=', 'payment')]
2780+ }" />
2781+ </xpath>
2782+ <field name="move_line_id" position="after">
2783+ <field name='payment_order_id'
2784+ attrs="{'readonly': [
2785+ ('match_multi', '=', False)],
2786+ 'invisible': [
2787+ ('match_type', '!=', 'payment_order')]}"
2788+ domain="[('id', 'in', payment_order_ids[0][2])]"
2789+ />
2790+ </field>
2791+ </field>
2792+ </record>
2793+ </data>
2794+</openerp>
2795+
2796+
2797
2798=== added file 'account_banking_payment/view/payment_mode_type.xml'
2799--- account_banking_payment/view/payment_mode_type.xml 1970-01-01 00:00:00 +0000
2800+++ account_banking_payment/view/payment_mode_type.xml 2013-05-24 09:03:33 +0000
2801@@ -0,0 +1,47 @@
2802+<?xml version="1.0" encoding="utf-8"?>
2803+<openerp>
2804+ <data>
2805+
2806+ <!-- Add the payment mode type to the payment mode views -->
2807+ <record id="view_payment_mode_form_inherit" model="ir.ui.view">
2808+ <field name="name">payment.mode.form.inherit</field>
2809+ <field name="model">payment.mode</field>
2810+ <field name="inherit_id" ref="account_payment.view_payment_mode_form"/>
2811+ <field name="type">form</field>
2812+ <field name="arch" type="xml">
2813+ <field name="company_id" position="after">
2814+ <field name="type"/>
2815+ </field>
2816+ </field>
2817+ </record>
2818+
2819+ <record id="view_payment_mode_tree_inherit" model="ir.ui.view">
2820+ <field name="name">payment.mode.tree.inherit</field>
2821+ <field name="model">payment.mode</field>
2822+ <field name="inherit_id" ref="account_payment.view_payment_mode_tree"/>
2823+ <field name="type">tree</field>
2824+ <field name="arch" type="xml">
2825+ <field name="company_id" position="after">
2826+ <field name="type"/>
2827+ </field>
2828+ </field>
2829+ </record>
2830+
2831+ <!-- basic view for payment mode type -->
2832+ <record model="ir.ui.view" id="view_payment_mode_type_form">
2833+ <field name="name">view.payment.mode.type.form</field>
2834+ <field name="model">payment.mode.type</field>
2835+ <field name="type">form</field>
2836+ <field name="arch" type="xml">
2837+ <form>
2838+ <field name="name" />
2839+ <field name="code" />
2840+ <field name="suitable_bank_types"/>
2841+ <field name="payment_order_type"/>
2842+ <field name="ir_model_id"/>
2843+ </form>
2844+ </field>
2845+ </record>
2846+
2847+ </data>
2848+</openerp>
2849
2850=== added directory 'account_banking_payment/workflow'
2851=== renamed file 'account_banking/account_banking_workflow.xml' => 'account_banking_payment/workflow/account_payment.xml'
2852--- account_banking/account_banking_workflow.xml 2011-12-12 15:00:03 +0000
2853+++ account_banking_payment/workflow/account_payment.xml 2013-05-24 09:03:33 +0000
2854@@ -1,20 +1,15 @@
2855 <?xml version="1.0" encoding="utf-8"?>
2856-<!--
2857- Copyright (C) EduSense BV <http://www.edusense.nl>
2858- All rights reserved.
2859- The licence is in the file __terp__.py
2860--->
2861 <openerp>
2862 <data>
2863 <!-- New activity for workflow payment order: sent -->
2864- <record id="act_sent" model="workflow.activity">
2865+ <record id="account_banking.act_sent" model="workflow.activity">
2866 <field name="name">sent</field>
2867 <field name="wkf_id" ref="account_payment.wkf_payment_order"/>
2868 <field name="action">action_sent()</field>
2869 <field name="kind">function</field>
2870 </record>
2871 <!-- New activity for workflow payment order: rejected -->
2872- <record id="act_rejected" model="workflow.activity">
2873+ <record id="account_banking.act_rejected" model="workflow.activity">
2874 <field name="name">rejected</field>
2875 <field name="wkf_id" ref="account_payment.wkf_payment_order"/>
2876 <field name="action">action_rejected()
2877@@ -22,21 +17,21 @@
2878 <field name="kind">function</field>
2879 </record>
2880 <!-- Add new transition sent -> done -->
2881- <record id="trans_sent_done" model="workflow.transition">
2882- <field name="act_from" ref="act_sent"/>
2883+ <record id="account_banking.trans_sent_done" model="workflow.transition">
2884+ <field name="act_from" ref="account_banking.act_sent"/>
2885 <field name="act_to" ref="account_payment.act_done"/>
2886 <field name="signal">done</field>
2887 </record>
2888 <!-- Add new transition sent -> rejected -->
2889- <record id="trans_sent_rejected" model="workflow.transition">
2890- <field name="act_from" ref="act_sent"/>
2891- <field name="act_to" ref="act_rejected"/>
2892+ <record id="account_banking.trans_sent_rejected" model="workflow.transition">
2893+ <field name="act_from" ref="account_banking.act_sent"/>
2894+ <field name="act_to" ref="account_banking.act_rejected"/>
2895 <field name="signal">rejected</field>
2896 </record>
2897 <!-- Rewrite existing open -> done transition to include 'sent' -->
2898 <record id="account_payment.trans_open_done" model="workflow.transition">
2899 <field name="act_from" ref="account_payment.act_open"/>
2900- <field name="act_to" ref="act_sent"/>
2901+ <field name="act_to" ref="account_banking.act_sent"/>
2902 <field name="signal">sent</field>
2903 </record>
2904 </data>

Subscribers

People subscribed via source and target branches

to status/vote changes: