Merge lp:~therp-nl/banking-addons/ba7.0-MIG-payment into lp:banking-addons

Proposed by Stefan Rijnhart (Opener)
Status: Merged
Merged at revision: 174
Proposed branch: lp:~therp-nl/banking-addons/ba7.0-MIG-payment
Merge into: lp:banking-addons
Prerequisite: lp:~therp-nl/banking-addons/ba7.0-MIG-import
Diff against target: 4032 lines (+1174/-1209)
48 files modified
account_banking/account_banking.py (+26/-26)
account_banking/account_banking_view.xml (+0/-9)
account_banking/banking_import_transaction.py (+84/-85)
account_banking/wizard/bank_import.py (+16/-16)
account_banking/wizard/bank_import_view.xml (+0/-1)
account_banking/wizard/banking_transaction_wizard.py (+40/-66)
account_banking/wizard/banking_transaction_wizard.xml (+0/-1)
account_banking/wizard/banktools.py (+18/-18)
account_banking_nl_clieop/__openerp__.py (+1/-1)
account_banking_nl_clieop/account_banking_nl_clieop.py (+7/-8)
account_banking_nl_clieop/account_banking_nl_clieop.xml (+0/-2)
account_banking_nl_clieop/wizard/export_clieop.py (+42/-48)
account_banking_nl_clieop/wizard/export_clieop_view.xml (+0/-1)
account_banking_nl_girotel/girotel.py (+14/-2)
account_banking_payment/__openerp__.py (+2/-1)
account_banking_payment/model/__init__.py (+0/-1)
account_banking_payment/model/account_bank_statement_line.py (+0/-40)
account_banking_payment/model/account_payment.py (+166/-46)
account_banking_payment/model/banking_import_transaction.py (+56/-46)
account_banking_payment/model/banking_transaction_wizard.py (+58/-0)
account_banking_payment/model/payment_line.py (+91/-129)
account_banking_payment/model/payment_mode.py (+21/-0)
account_banking_payment/model/payment_order_create.py (+74/-5)
account_banking_payment/view/account_payment.xml (+16/-21)
account_banking_payment/view/bank_payment_manual.xml (+1/-2)
account_banking_payment/view/banking_transaction_wizard.xml (+11/-9)
account_banking_payment/view/payment_mode.xml (+43/-0)
account_banking_payment/view/payment_mode_type.xml (+1/-16)
account_banking_payment/workflow/account_payment.xml (+40/-9)
account_banking_uk_hsbc/__openerp__.py (+1/-1)
account_direct_debit/__openerp__.py (+4/-5)
account_direct_debit/i18n/nl.po (+2/-2)
account_direct_debit/migrations/7.0.2/pre-migration.py (+57/-0)
account_direct_debit/model/__init__.py (+2/-0)
account_direct_debit/model/account_invoice.py (+26/-5)
account_direct_debit/model/account_move_line.py (+7/-67)
account_direct_debit/model/account_payment.py (+5/-434)
account_direct_debit/model/payment_line.py (+152/-0)
account_direct_debit/model/payment_order_create.py (+41/-0)
account_direct_debit/view/account_invoice.xml (+5/-10)
account_direct_debit/view/account_payment.xml (+2/-28)
account_direct_debit/workflow/account_payment.xml (+0/-25)
account_payment_shortcut/__init__.py (+1/-0)
account_payment_shortcut/payment_order.py (+26/-6)
bank_statement_instant_voucher/model/account_bank_statement_line.py (+5/-5)
bank_statement_instant_voucher/model/account_voucher_instant.py (+10/-10)
bank_statement_instant_voucher/view/account_bank_statement_line.xml (+0/-1)
bank_statement_instant_voucher/view/account_voucher_instant.xml (+0/-1)
To merge this branch: bzr merge lp:~therp-nl/banking-addons/ba7.0-MIG-payment
Reviewer Review Type Date Requested Status
Holger Brunn (Therp) Approve
Review via email: mp+166451@code.launchpad.net

Commit message

[MRG] Migration of payment modules

Description of the change

- Apply invoice integration of debit orders also to payment orders
- Allow for manual reconciliation of payment and debit orders
- Update payment order workflow so as to allow for unreconciliation
- Consistency in usage of cr and uid variable names
- Adapt to API changes
- Removed obsolete workaround for old bugs in OpenERP server
- Remove unused code paths

For migrations from 6.1, I am still considering how to provide an upgrade path that migrates payment order workflow instances in activity 'sent' to the new 'sent_wait' state.

To post a comment you must log in.
Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

just a few small things, approving anyways:

#102 maybe use the opportunity to make this function contaxt-aware?
#140ff same with passing context in the onchange_functions
#550 570, 880 considering how often you use this selection, you should move it to its own field. This also simplifies adjusting the selection
#1591 check if there are line_ids
#1682 should be translated
#1692 too
#1784 why can we drop this check? shouldn't it be changed to check for transit_move_line_id?

Could you elaborate on the sent_wait state? If it's meant how I think it is, such a migration seems not necessary to me.

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

should I wait with merging this one until you had a look at my points?

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

Yes, will do so this week! Thanks for the review.

227. By Stefan Rijnhart (Opener)

[MGR] HSBC module depends on split off payment part

228. By Stefan Rijnhart (Opener)

[FIX] Add context to browse calls in account_banking.py

229. By Stefan Rijnhart (Opener)

[FIX] Improve translatable labels for move and move lines

230. By Stefan Rijnhart (Opener)

[MRG] Merged with target branch

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

Holger, thanks for your comments. I tried to address them in my latest commits or the comments below.

> #550 570, 880 considering how often you use this selection, you should move it to its own field. This also
> simplifies adjusting the selection

I'll leave it for now as I want to refactor it later on to make the selection options more dynamic.

> #1591 check if there are line_ids

As this code path occurs after a match with a bank transaction on amount, an absence of line_ids should not occur as the payment order amount would be zero as would the transaction amount.

> #1784 why can we drop this check? shouldn't it be changed to check for transit_move_line_id?

As per l.1591, implement old style behaviour for legacy payment orders depending on the presence of transit_move_line_id.

The sent state implements the transit move. Making it go into sent_wait allows the reconciliation process to cancel and reconfirm confirmed matches. Before I introduced the latter state and modified the workflow to go from 'done' to 'sent', I could not reconfirm a match on a payment order, because then the workflow would attempt to create the transit move again. I'd think that a manual migration for wkf instances currently in the 'sent' state should be necessary, or they might get stuck at that state.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'account_banking/account_banking.py'
--- account_banking/account_banking.py 2013-04-29 09:17:46 +0000
+++ account_banking/account_banking.py 2013-06-26 21:16:23 +0000
@@ -267,7 +267,7 @@
267 }267 }
268 _defaults = {268 _defaults = {
269 'date': fields.date.context_today,269 'date': fields.date.context_today,
270 'user_id': lambda self, cursor, uid, context: uid,270 'user_id': lambda self, cr, uid, context: uid,
271 }271 }
272account_banking_imported_file()272account_banking_imported_file()
273273
@@ -320,12 +320,12 @@
320 ['journal_id','period_id']),320 ['journal_id','period_id']),
321 ]321 ]
322322
323 def _get_period(self, cursor, uid, date, context=None):323 def _get_period(self, cr, uid, date, context=None):
324 '''324 '''
325 Find matching period for date, not meant for _defaults.325 Find matching period for date, not meant for _defaults.
326 '''326 '''
327 period_obj = self.pool.get('account.period')327 period_obj = self.pool.get('account.period')
328 periods = period_obj.find(cursor, uid, dt=date, context=context)328 periods = period_obj.find(cr, uid, dt=date, context=context)
329 return periods and periods[0] or False329 return periods and periods[0] or False
330330
331 def _prepare_move(331 def _prepare_move(
@@ -398,7 +398,7 @@
398 # Write stored reconcile_id and pay invoices through workflow 398 # Write stored reconcile_id and pay invoices through workflow
399 if st_line.reconcile_id:399 if st_line.reconcile_id:
400 move_ids = [move.id for move in st_line.move_ids]400 move_ids = [move.id for move in st_line.move_ids]
401 torec = account_move_obj.search(401 torec = account_move_line_obj.search(
402 cr, uid, [402 cr, uid, [
403 ('move_id', 'in', move_ids),403 ('move_id', 'in', move_ids),
404 ('account_id', '=', st_line.account_id.id)],404 ('account_id', '=', st_line.account_id.id)],
@@ -450,7 +450,7 @@
450 context = {}450 context = {}
451 if not context.get('period_id') and context.get('move_line_ids'):451 if not context.get('period_id') and context.get('move_line_ids'):
452 return self.pool.get('account.move.line').browse(452 return self.pool.get('account.move.line').browse(
453 cr, uid , context.get('move_line_ids'))[0].period_id.id453 cr, uid , context.get('move_line_ids'), context=context)[0].period_id.id
454 return super(account_voucher, self)._get_period(cr, uid, context)454 return super(account_voucher, self)._get_period(cr, uid, context)
455455
456account_voucher()456account_voucher()
@@ -467,12 +467,12 @@
467 _inherit = 'account.bank.statement.line'467 _inherit = 'account.bank.statement.line'
468 _description = 'Bank Transaction'468 _description = 'Bank Transaction'
469469
470 def _get_period(self, cursor, user, context=None):470 def _get_period(self, cr, uid, context=None):
471 date = context.get('date', None)471 date = context.get('date', None)
472 periods = self.pool.get('account.period').find(cursor, user, dt=date)472 periods = self.pool.get('account.period').find(cr, uid, dt=date)
473 return periods and periods[0] or False473 return periods and periods[0] or False
474474
475 def _get_currency(self, cursor, user, context=None):475 def _get_currency(self, cr, uid, context=None):
476 '''476 '''
477 Get the default currency (required to allow other modules to function,477 Get the default currency (required to allow other modules to function,
478 which assume currency to be a calculated field and thus optional)478 which assume currency to be a calculated field and thus optional)
@@ -480,7 +480,7 @@
480 which is inaccessible from within this method.480 which is inaccessible from within this method.
481 '''481 '''
482 res_users_obj = self.pool.get('res.users')482 res_users_obj = self.pool.get('res.users')
483 return res_users_obj.browse(cursor, user, user,483 return res_users_obj.browse(cr, uid, uid,
484 context=context).company_id.currency_id.id484 context=context).company_id.currency_id.id
485485
486 def _get_invoice_id(self, cr, uid, ids, name, args, context=None):486 def _get_invoice_id(self, cr, uid, ids, name, args, context=None):
@@ -605,7 +605,7 @@
605 iban = sepa.IBAN(acc_number)605 iban = sepa.IBAN(acc_number)
606 return (str(iban), iban.localized_BBAN)606 return (str(iban), iban.localized_BBAN)
607607
608 def create(self, cursor, uid, vals, context=None):608 def create(self, cr, uid, vals, context=None):
609 '''609 '''
610 Create dual function IBAN account for SEPA countries610 Create dual function IBAN account for SEPA countries
611 '''611 '''
@@ -614,7 +614,7 @@
614 or vals.get('acc_number_domestic', False))614 or vals.get('acc_number_domestic', False))
615 vals['acc_number'], vals['acc_number_domestic'] = (615 vals['acc_number'], vals['acc_number_domestic'] = (
616 self._correct_IBAN(iban))616 self._correct_IBAN(iban))
617 return self._founder.create(self, cursor, uid, vals, context)617 return self._founder.create(self, cr, uid, vals, context)
618618
619 def write(self, cr, uid, ids, vals, context=None):619 def write(self, cr, uid, ids, vals, context=None):
620 '''620 '''
@@ -637,7 +637,7 @@
637 self._founder.write(self, cr, uid, account['id'], vals, context)637 self._founder.write(self, cr, uid, account['id'], vals, context)
638 return True638 return True
639639
640 def search(self, cursor, uid, args, *rest, **kwargs):640 def search(self, cr, uid, args, *rest, **kwargs):
641 '''641 '''
642 Overwrite search, as both acc_number and iban now can be filled, so642 Overwrite search, as both acc_number and iban now can be filled, so
643 the original base_iban 'search and search again fuzzy' tactic now can643 the original base_iban 'search and search again fuzzy' tactic now can
@@ -698,7 +698,7 @@
698 698
699 # Original search699 # Original search
700 results = super(res_partner_bank, self).search(700 results = super(res_partner_bank, self).search(
701 cursor, uid, newargs, *rest, **kwargs)701 cr, uid, newargs, *rest, **kwargs)
702 return results702 return results
703703
704 def read(704 def read(
@@ -721,23 +721,23 @@
721 return records721 return records
722 return records[0]722 return records[0]
723723
724 def check_iban(self, cursor, uid, ids):724 def check_iban(self, cr, uid, ids, context=None):
725 '''725 '''
726 Check IBAN number726 Check IBAN number
727 '''727 '''
728 for bank_acc in self.browse(cursor, uid, ids):728 for bank_acc in self.browse(cr, uid, ids, context=context):
729 if bank_acc.state == 'iban' and bank_acc.acc_number:729 if bank_acc.state == 'iban' and bank_acc.acc_number:
730 iban = sepa.IBAN(bank_acc.acc_number)730 iban = sepa.IBAN(bank_acc.acc_number)
731 if not iban.valid:731 if not iban.valid:
732 return False732 return False
733 return True733 return True
734734
735 def get_bban_from_iban(self, cursor, uid, ids, context=None):735 def get_bban_from_iban(self, cr, uid, ids, context=None):
736 '''736 '''
737 Return the local bank account number aka BBAN from the IBAN.737 Return the local bank account number aka BBAN from the IBAN.
738 '''738 '''
739 res = {}739 res = {}
740 for record in self.browse(cursor, uid, ids, context):740 for record in self.browse(cr, uid, ids, context):
741 if not record.state == 'iban':741 if not record.state == 'iban':
742 res[record.id] = False742 res[record.id] = False
743 else:743 else:
@@ -763,7 +763,7 @@
763 )763 )
764764
765 def onchange_domestic(765 def onchange_domestic(
766 self, cursor, uid, ids, acc_number,766 self, cr, uid, ids, acc_number,
767 partner_id, country_id, context=None):767 partner_id, country_id, context=None):
768 '''768 '''
769 Trigger to find IBAN. When found:769 Trigger to find IBAN. When found:
@@ -785,7 +785,7 @@
785 # which can be overridden by the user.785 # which can be overridden by the user.
786 # 1. Use provided country_id (manually filled)786 # 1. Use provided country_id (manually filled)
787 if country_id:787 if country_id:
788 country = country_obj.browse(cursor, uid, country_id)788 country = country_obj.browse(cr, uid, country_id, context=context)
789 country_ids = [country_id]789 country_ids = [country_id]
790 # 2. Use country_id of found bank accounts790 # 2. Use country_id of found bank accounts
791 # This can be usefull when there is no country set in the partners791 # This can be usefull when there is no country set in the partners
@@ -793,7 +793,7 @@
793 # account itself before this method was triggered.793 # account itself before this method was triggered.
794 elif ids and len(ids) == 1:794 elif ids and len(ids) == 1:
795 partner_bank_obj = self.pool.get('res.partner.bank')795 partner_bank_obj = self.pool.get('res.partner.bank')
796 partner_bank_id = partner_bank_obj.browse(cursor, uid, ids[0])796 partner_bank_id = partner_bank_obj.browse(cr, uid, ids[0], context=context)
797 if partner_bank_id.country_id:797 if partner_bank_id.country_id:
798 country = partner_bank_id.country_id798 country = partner_bank_id.country_id
799 country_ids = [country.id]799 country_ids = [country.id]
@@ -804,12 +804,12 @@
804 # bank account, hence the additional check.804 # bank account, hence the additional check.
805 elif partner_id:805 elif partner_id:
806 partner_obj = self.pool.get('res.partner')806 partner_obj = self.pool.get('res.partner')
807 country = partner_obj.browse(cursor, uid, partner_id).country807 country = partner_obj.browse(cr, uid, partner_id, context=context).country
808 country_ids = country and [country.id] or []808 country_ids = country and [country.id] or []
809 # 4. Without any of the above, take the country from the company of809 # 4. Without any of the above, take the country from the company of
810 # the handling user810 # the handling user
811 if not country_ids:811 if not country_ids:
812 user = self.pool.get('res.users').browse(cursor, uid, uid)812 user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
813 # Try user companies partner (user no longer has address in 6.1)813 # Try user companies partner (user no longer has address in 6.1)
814 if (user.company_id and814 if (user.company_id and
815 user.company_id.partner_id and815 user.company_id.partner_id and
@@ -830,7 +830,7 @@
830 # Complete data with online database when available830 # Complete data with online database when available
831 if country_ids:831 if country_ids:
832 country = country_obj.browse(832 country = country_obj.browse(
833 cursor, uid, country_ids[0], context=context)833 cr, uid, country_ids[0], context=context)
834 values['country_id'] = country_ids[0]834 values['country_id'] = country_ids[0]
835 if country and country.code in sepa.IBAN.countries:835 if country and country.code in sepa.IBAN.countries:
836 try:836 try:
@@ -842,7 +842,7 @@
842 values['acc_number'] = unicode(iban_acc)842 values['acc_number'] = unicode(iban_acc)
843 values['state'] = 'iban'843 values['state'] = 'iban'
844 bank_id, country_id = get_or_create_bank(844 bank_id, country_id = get_or_create_bank(
845 self.pool, cursor, uid,845 self.pool, cr, uid,
846 info.bic or iban_acc.BIC_searchkey,846 info.bic or iban_acc.BIC_searchkey,
847 name = info.bank847 name = info.bank
848 )848 )
@@ -911,7 +911,7 @@
911 '''911 '''
912 _inherit = 'res.bank'912 _inherit = 'res.bank'
913913
914 def onchange_bic(self, cursor, uid, ids, bic, name, context=None):914 def onchange_bic(self, cr, uid, ids, bic, name, context=None):
915 '''915 '''
916 Trigger to auto complete other fields.916 Trigger to auto complete other fields.
917 '''917 '''
@@ -924,7 +924,7 @@
924924
925 if address and address.country_id:925 if address and address.country_id:
926 country_id = self.pool.get('res.country').search(926 country_id = self.pool.get('res.country').search(
927 cursor, uid, [('code','=',address.country_id)]927 cr, uid, [('code','=',address.country_id)]
928 )928 )
929 country_id = country_id and country_id[0] or False929 country_id = country_id and country_id[0] or False
930 else:930 else:
931931
=== modified file 'account_banking/account_banking_view.xml'
--- account_banking/account_banking_view.xml 2013-05-01 14:25:04 +0000
+++ account_banking/account_banking_view.xml 2013-06-26 21:16:23 +0000
@@ -36,7 +36,6 @@
36 <record model="ir.ui.view" id="view_banking_account_settings_form">36 <record model="ir.ui.view" id="view_banking_account_settings_form">
37 <field name="name">account.banking.account.settings.form</field>37 <field name="name">account.banking.account.settings.form</field>
38 <field name="model">account.banking.account.settings</field>38 <field name="model">account.banking.account.settings</field>
39 <field name="type">form</field>
40 <field name="arch" type="xml">39 <field name="arch" type="xml">
41 <form string="Default Import Settings for Bank Account">40 <form string="Default Import Settings for Bank Account">
42 <field name="company_id"41 <field name="company_id"
@@ -70,7 +69,6 @@
70 <record model="ir.ui.view" id="view_banking_account_settings_tree">69 <record model="ir.ui.view" id="view_banking_account_settings_tree">
71 <field name="name">account.banking.account.settings.tree</field>70 <field name="name">account.banking.account.settings.tree</field>
72 <field name="model">account.banking.account.settings</field>71 <field name="model">account.banking.account.settings</field>
73 <field name="type">tree</field>
74 <field name="arch" type="xml">72 <field name="arch" type="xml">
75 <tree string="Default Import Settings for Bank Account">73 <tree string="Default Import Settings for Bank Account">
76 <field name="company_id" />74 <field name="company_id" />
@@ -99,7 +97,6 @@
99 <record model="ir.ui.view" id="view_account_banking_imported_file_form">97 <record model="ir.ui.view" id="view_account_banking_imported_file_form">
100 <field name="name">account.banking.imported.file.form</field>98 <field name="name">account.banking.imported.file.form</field>
101 <field name="model">account.banking.imported.file</field>99 <field name="model">account.banking.imported.file</field>
102 <field name="type">form</field>
103 <field name="arch" type="xml">100 <field name="arch" type="xml">
104 <form string="Imported Bank Statements">101 <form string="Imported Bank Statements">
105 <notebook colspan="4">102 <notebook colspan="4">
@@ -124,7 +121,6 @@
124 <record model="ir.ui.view" id="view_account_banking_imported_file_tree">121 <record model="ir.ui.view" id="view_account_banking_imported_file_tree">
125 <field name="name">account.banking.imported.file.tree</field>122 <field name="name">account.banking.imported.file.tree</field>
126 <field name="model">account.banking.imported.file</field>123 <field name="model">account.banking.imported.file</field>
127 <field name="type">tree</field>
128 <field name="arch" type="xml">124 <field name="arch" type="xml">
129 <tree string="Imported Bank Statements Files" colors="red:state=='error';blue:state=='unfinished'">125 <tree string="Imported Bank Statements Files" colors="red:state=='error';blue:state=='unfinished'">
130 <field name="company_id" />126 <field name="company_id" />
@@ -182,7 +178,6 @@
182 <field name="name">account.bank.statement.tree.banking</field>178 <field name="name">account.bank.statement.tree.banking</field>
183 <field name="inherit_id" ref="account.view_bank_statement_tree" />179 <field name="inherit_id" ref="account.view_bank_statement_tree" />
184 <field name="model">account.bank.statement</field>180 <field name="model">account.bank.statement</field>
185 <field name="type">tree</field>
186 <field name="arch" type="xml">181 <field name="arch" type="xml">
187 <!-- Remove period from bank statement -->182 <!-- Remove period from bank statement -->
188 <field name="period_id" position="replace">183 <field name="period_id" position="replace">
@@ -197,7 +192,6 @@
197 <field name="inherit_id" ref="account.view_bank_statement_form" />192 <field name="inherit_id" ref="account.view_bank_statement_form" />
198 <field name="model">account.bank.statement</field>193 <field name="model">account.bank.statement</field>
199 <field name="sequence" eval="60"/>194 <field name="sequence" eval="60"/>
200 <field name="type">form</field>
201 <field name="arch" type="xml">195 <field name="arch" type="xml">
202 <data>196 <data>
203 <page string="Transactions" position="after">197 <page string="Transactions" position="after">
@@ -292,7 +286,6 @@
292 <field name="name">res.partner.bank.form.banking-2</field>286 <field name="name">res.partner.bank.form.banking-2</field>
293 <field name="model">res.partner.bank</field>287 <field name="model">res.partner.bank</field>
294 <field name="inherit_id" ref="base.view_partner_bank_form"/>288 <field name="inherit_id" ref="base.view_partner_bank_form"/>
295 <field name="type">form</field>
296 <field name="priority" eval="24"/>289 <field name="priority" eval="24"/>
297 <field name="arch" type="xml">290 <field name="arch" type="xml">
298 <data>291 <data>
@@ -311,7 +304,6 @@
311 <field name="name">res.bank.form.banking-1</field>304 <field name="name">res.bank.form.banking-1</field>
312 <field name="model">res.bank</field>305 <field name="model">res.bank</field>
313 <field name="inherit_id" ref="base.view_res_bank_form"/>306 <field name="inherit_id" ref="base.view_res_bank_form"/>
314 <field name="type">form</field>
315 <field name="arch" type="xml">307 <field name="arch" type="xml">
316 <field name="bic" position="replace">308 <field name="bic" position="replace">
317 <field name="bic" on_change="onchange_bic(bic, name)"/>309 <field name="bic" on_change="onchange_bic(bic, name)"/>
@@ -322,7 +314,6 @@
322 <record model="ir.ui.view" id="view_bank_statement_line_tree">314 <record model="ir.ui.view" id="view_bank_statement_line_tree">
323 <field name="name">Bank statement line tree view</field>315 <field name="name">Bank statement line tree view</field>
324 <field name="model">account.bank.statement.line</field>316 <field name="model">account.bank.statement.line</field>
325 <field name="type">tree</field>
326 <field name="arch" type="xml">317 <field name="arch" type="xml">
327 <tree string="Statement lines" colors="black:state == 'confirmed';darkmagenta:match_multi == True;crimson:duplicate == True;grey:state=='draft';">318 <tree string="Statement lines" colors="black:state == 'confirmed';darkmagenta:match_multi == True;crimson:duplicate == True;grey:state=='draft';">
328 <field name="sequence" readonly="1" invisible="1"/>319 <field name="sequence" readonly="1" invisible="1"/>
329320
=== modified file 'account_banking/banking_import_transaction.py'
--- account_banking/banking_import_transaction.py 2013-06-10 10:14:31 +0000
+++ account_banking/banking_import_transaction.py 2013-06-26 21:16:23 +0000
@@ -62,7 +62,7 @@
62 return []62 return []
6363
64 digits = dp.get_precision('Account')(cr)[1]64 digits = dp.get_precision('Account')(cr)[1]
65 amount = round(abs(trans.transferred_amount), digits)65 amount = round(abs(trans.statement_line_id.amount), digits)
66 # Make sure to be able to pinpoint our costs invoice for later66 # Make sure to be able to pinpoint our costs invoice for later
67 # matching67 # matching
68 reference = '%s.%s: %s' % (trans.statement, trans.transaction, trans.reference)68 reference = '%s.%s: %s' % (trans.statement, trans.transaction, trans.reference)
@@ -233,10 +233,6 @@
233 digits = dp.get_precision('Account')(cr)[1]233 digits = dp.get_precision('Account')(cr)[1]
234 partial = False234 partial = False
235235
236 # Disabled splitting transactions for now
237 # TODO allow splitting in the interactive wizard
238 allow_splitting = False
239
240 # Search invoice on partner236 # Search invoice on partner
241 if partner_ids:237 if partner_ids:
242 candidates = [238 candidates = [
@@ -276,7 +272,7 @@
276 candidates = [272 candidates = [
277 x for x in move_lines 273 x for x in move_lines
278 if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) -274 if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) -
279 trans.transferred_amount)275 trans.statement_line_id.amount)
280 and convert.str2date(x.date, '%Y-%m-%d') <=276 and convert.str2date(x.date, '%Y-%m-%d') <=
281 (convert.str2date(trans.execution_date, '%Y-%m-%d') +277 (convert.str2date(trans.execution_date, '%Y-%m-%d') +
282 self.payment_window)278 self.payment_window)
@@ -292,7 +288,7 @@
292 # TODO: currency coercing288 # TODO: currency coercing
293 best = [x for x in candidates289 best = [x for x in candidates
294 if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) -290 if (is_zero(x.move_id, ((x.debit or 0.0) - (x.credit or 0.0)) -
295 trans.transferred_amount)291 trans.statement_line_id.amount)
296 and convert.str2date(x.date, '%Y-%m-%d') <=292 and convert.str2date(x.date, '%Y-%m-%d') <=
297 (convert.str2date(trans.execution_date, '%Y-%m-%d') +293 (convert.str2date(trans.execution_date, '%Y-%m-%d') +
298 self.payment_window))294 self.payment_window))
@@ -343,7 +339,7 @@
343339
344 trans2 = None340 trans2 = None
345 if move_line and partial:341 if move_line and partial:
346 found = round(trans.transferred_amount, digits)342 found = round(trans.statement_line_id.amount, digits)
347 if abs(expected) == abs(found):343 if abs(expected) == abs(found):
348 partial = False344 partial = False
349 # Last partial payment will not flag invoice paid without345 # Last partial payment will not flag invoice paid without
@@ -358,24 +354,6 @@
358 elif abs(expected) > abs(found):354 elif abs(expected) > abs(found):
359 # Partial payment, reuse invoice355 # Partial payment, reuse invoice
360 _cache(move_line, expected - found)356 _cache(move_line, expected - found)
361 elif abs(expected) < abs(found) and allow_splitting:
362 # Possible combined payments, need to split transaction to
363 # verify
364 _cache(move_line)
365 trans2 = self.copy(
366 cr, uid, trans.id,
367 dict(
368 transferred_amount = trans.transferred_amount - expected,
369 transaction = trans.transaction + 'b',
370 parent_id = trans.id,
371 ), context=context)
372 # update the current record
373 self.write(cr, uid, trans.id, dict(
374 transferred_amount = expected,
375 transaction = trans.transaction + 'a',
376 ), context)
377 # rebrowse the current record after writing
378 trans = self.browse(cr, uid, trans.id, context=context)
379 if move_line:357 if move_line:
380 account_ids = [358 account_ids = [
381 x.id for x in bank_account_ids 359 x.id for x in bank_account_ids
@@ -712,7 +690,7 @@
712 # due to float representation and rounding difficulties690 # due to float representation and rounding difficulties
713 for trans in self.browse(cr, uid, ids, context=context):691 for trans in self.browse(cr, uid, ids, context=context):
714 if self.pool.get('res.currency').is_zero(692 if self.pool.get('res.currency').is_zero(
715 cr, uid, 693 cr, uid,
716 trans.statement_id.currency,694 trans.statement_id.currency,
717 me['transferred_amount'] - trans.transferred_amount):695 me['transferred_amount'] - trans.transferred_amount):
718 dupes.append(trans.id)696 dupes.append(trans.id)
@@ -810,6 +788,12 @@
810 move_info['invoice_ids'][0]788 move_info['invoice_ids'][0]
811 )789 )
812 return vals790 return vals
791
792 def hook_match_payment(self, cr, uid, transaction, log, context=None):
793 """
794 To override in module 'account_banking_payment'
795 """
796 return False
813 797
814 def match(self, cr, uid, ids, results=None, context=None):798 def match(self, cr, uid, ids, results=None, context=None):
815 if not ids:799 if not ids:
@@ -872,12 +856,6 @@
872 else:856 else:
873 transaction = transactions[i]857 transaction = transactions[i]
874858
875 if (transaction.statement_line_id and
876 transaction.statement_line_id.state == 'confirmed'):
877 raise orm.except_orm(
878 _("Cannot perform match"),
879 _("Cannot perform match on a confirmed transction"))
880
881 if transaction.local_account in error_accounts:859 if transaction.local_account in error_accounts:
882 results['trans_skipped_cnt'] += 1860 results['trans_skipped_cnt'] += 1
883 if not injected:861 if not injected:
@@ -962,6 +940,44 @@
962 else:940 else:
963 info[transaction.local_account][currency_code] = account_info941 info[transaction.local_account][currency_code] = account_info
964942
943 # Link accounting period
944 period_id = banktools.get_period(
945 self.pool, cr, uid, transaction.effective_date,
946 company, results['log'])
947 if not period_id:
948 results['trans_skipped_cnt'] += 1
949 if not injected:
950 i += 1
951 continue
952
953 if transaction.statement_line_id:
954 if transaction.statement_line_id.state == 'confirmed':
955 raise orm.except_orm(
956 _("Cannot perform match"),
957 _("Cannot perform match on a confirmed transction"))
958 else:
959 values = {
960 'name': '%s.%s' % (transaction.statement, transaction.transaction),
961 'date': transaction.effective_date,
962 'amount': transaction.transferred_amount,
963 'statement_id': transaction.statement_id.id,
964 'note': transaction.message,
965 'ref': transaction.reference,
966 'period_id': period_id,
967 'currency': account_info.currency_id.id,
968 'import_transaction_id': transaction.id,
969 'account_id': (
970 transaction.transferred_amount < 0 and
971 account_info.default_credit_account_id.id or
972 account_info.default_debit_account_id.id),
973 }
974 statement_line_id = statement_line_obj.create(cr, uid, values, context)
975 results['trans_loaded_cnt'] += 1
976 transaction.write({'statement_line_id': statement_line_id})
977 transaction.refresh()
978 if transaction.statement_id.id not in imported_statement_ids:
979 imported_statement_ids.append(transaction.statement_id.id)
980
965 # Final check: no coercion of currencies!981 # Final check: no coercion of currencies!
966 if transaction.local_currency \982 if transaction.local_currency \
967 and account_info.currency_id.name != transaction.local_currency:983 and account_info.currency_id.name != transaction.local_currency:
@@ -971,8 +987,8 @@
971 ' uses different currency than the defined bank journal.'987 ' uses different currency than the defined bank journal.'
972 ) % {988 ) % {
973 'bank_account': transactions.local_account,989 'bank_account': transactions.local_account,
974 'transaction_id': transaction.statement,990 'statement_id': transaction.statement,
975 'statement_id': transaction.transaction,991 'transaction_id': transaction.transaction,
976 }992 }
977 )993 )
978 error_accounts[transaction.local_account] = True994 error_accounts[transaction.local_account] = True
@@ -981,16 +997,6 @@
981 i += 1997 i += 1
982 continue998 continue
983999
984 # Link accounting period
985 period_id = banktools.get_period(
986 self.pool, cr, uid, transaction.effective_date,
987 company, results['log'])
988 if not period_id:
989 results['trans_skipped_cnt'] += 1
990 if not injected:
991 i += 1
992 continue
993
994 # When bank costs are part of transaction itself, split it.1000 # When bank costs are part of transaction itself, split it.
995 if transaction.type != bt.BANK_COSTS and transaction.provision_costs:1001 if transaction.type != bt.BANK_COSTS and transaction.provision_costs:
996 # Create new transaction for bank costs1002 # Create new transaction for bank costs
@@ -1022,13 +1028,12 @@
1022 ), context=context)1028 ), context=context)
1023 # rebrowse the current record after writing1029 # rebrowse the current record after writing
1024 transaction = self.browse(cr, uid, transaction.id, context=context)1030 transaction = self.browse(cr, uid, transaction.id, context=context)
1025 # Match full direct debit orders1031
1026 if transaction.type == bt.DIRECT_DEBIT and has_payment:1032 # Match payment and direct debit orders
1027 move_info = self._match_debit_order(1033 move_info_payment = self.hook_match_payment(
1028 cr, uid, transaction, results['log'], context)1034 cr, uid, transaction, results['log'], context=context)
1029 if transaction.type == bt.STORNO and has_payment:1035 if move_info_payment:
1030 move_info = self._match_storno(1036 move_info = move_info_payment
1031 cr, uid, transaction, results['log'], context)
10321037
1033 # Allow inclusion of generated bank invoices1038 # Allow inclusion of generated bank invoices
1034 if transaction.type == bt.BANK_COSTS:1039 if transaction.type == bt.BANK_COSTS:
@@ -1075,7 +1080,7 @@
10751080
1076 # Credit means payment... isn't it?1081 # Credit means payment... isn't it?
1077 if (not move_info1082 if (not move_info
1078 and transaction.transferred_amount < 0 and payment_lines):1083 and transaction.statement_line_id.amount < 0 and payment_lines):
1079 # Link open payment - if any1084 # Link open payment - if any
1080 # Note that _match_payment is defined in the1085 # Note that _match_payment is defined in the
1081 # account_banking_payment module which should be installed1086 # account_banking_payment module which should be installed
@@ -1106,7 +1111,7 @@
1106 # settings to overrule this. Note that you need to change1111 # settings to overrule this. Note that you need to change
1107 # the internal type of these accounts to either 'payable'1112 # the internal type of these accounts to either 'payable'
1108 # or 'receivable' to enable usage like this.1113 # or 'receivable' to enable usage like this.
1109 if transaction.transferred_amount < 0:1114 if transaction.statement_line_id.amount < 0:
1110 if len(partner_banks) == 1:1115 if len(partner_banks) == 1:
1111 account_id = (1116 account_id = (
1112 partner_banks[0].partner_id.property_account_payable and1117 partner_banks[0].partner_id.property_account_payable and
@@ -1122,7 +1127,7 @@
1122 if len(partner_banks) != 1 or not account_id or account_id == def_rec_account_id:1127 if len(partner_banks) != 1 or not account_id or account_id == def_rec_account_id:
1123 account_id = (account_info.default_debit_account_id and1128 account_id = (account_info.default_debit_account_id and
1124 account_info.default_debit_account_id.id)1129 account_info.default_debit_account_id.id)
1125 values = {}1130 values = {'account_id': account_id}
1126 self_values = {}1131 self_values = {}
1127 if move_info:1132 if move_info:
1128 results['trans_matched_cnt'] += 11133 results['trans_matched_cnt'] += 1
@@ -1140,28 +1145,8 @@
1140 len(partner_banks) == 1):1145 len(partner_banks) == 1):
1141 values['partner_bank_id'] = partner_banks[0].id1146 values['partner_bank_id'] = partner_banks[0].id
11421147
1143 if not transaction.statement_line_id:1148 statement_line_obj.write(
1144 values.update(dict(1149 cr, uid, transaction.statement_line_id.id, values, context)
1145 name = '%s.%s' % (transaction.statement, transaction.transaction),
1146 date = transaction.effective_date,
1147 amount = transaction.transferred_amount,
1148 statement_id = transaction.statement_id.id,
1149 note = transaction.message,
1150 ref = transaction.reference,
1151 period_id = period_id,
1152 currency = account_info.currency_id.id,
1153 account_id = account_id,
1154 import_transaction_id = transaction.id,
1155 ))
1156
1157 statement_line_id = statement_line_obj.create(cr, uid, values, context)
1158 results['trans_loaded_cnt'] += 1
1159 self_values['statement_line_id'] = statement_line_id
1160 if transaction.statement_id.id not in imported_statement_ids:
1161 imported_statement_ids.append(transaction.statement_id.id)
1162 else:
1163 statement_line_obj.write(
1164 cr, uid, transaction.statement_line_id.id, values, context)
1165 self.write(cr, uid, transaction.id, self_values, context)1150 self.write(cr, uid, transaction.id, self_values, context)
1166 if not injected:1151 if not injected:
1167 i += 11152 i += 1
@@ -1350,9 +1335,16 @@
1350 'parent_id': fields.many2one(1335 'parent_id': fields.many2one(
1351 'banking.import.transaction', 'Split off from this transaction'),1336 'banking.import.transaction', 'Split off from this transaction'),
1352 # match fields1337 # match fields
1353 'match_type': fields.selection(1338 'match_type': fields.selection([
1354 [('manual', 'Manual'), ('move','Move'), ('invoice', 'Invoice'),1339 ('move','Move'),
1355 ], 'Match type'),1340 ('invoice', 'Invoice'),
1341 ('payment', 'Payment line'),
1342 ('payment_order', 'Payment order'),
1343 ('storno', 'Storno'),
1344 ('manual', 'Manual'),
1345 ('payment_manual', 'Payment line (manual)'),
1346 ('payment_order_manual', 'Payment order (manual)'),
1347 ], 'Match type'),
1356 'match_multi': fields.function(1348 'match_multi': fields.function(
1357 _get_match_multi, method=True, string='Multi match',1349 _get_match_multi, method=True, string='Multi match',
1358 type='boolean'),1350 type='boolean'),
@@ -1439,9 +1431,16 @@
1439 string='Possible duplicate import', readonly=True),1431 string='Possible duplicate import', readonly=True),
1440 'match_type': fields.related(1432 'match_type': fields.related(
1441 'import_transaction_id', 'match_type', type='selection',1433 'import_transaction_id', 'match_type', type='selection',
1442 selection=[('manual', 'Manual'), ('move','Move'),1434 selection=[
1443 ('invoice', 'Invoice'),1435 ('move','Move'),
1444 ], 1436 ('invoice', 'Invoice'),
1437 ('payment', 'Payment line'),
1438 ('payment_order', 'Payment order'),
1439 ('storno', 'Storno'),
1440 ('manual', 'Manual'),
1441 ('payment_manual', 'Payment line (manual)'),
1442 ('payment_order_manual', 'Payment order (manual)'),
1443 ],
1445 string='Match type', readonly=True,),1444 string='Match type', readonly=True,),
1446 'state': fields.selection(1445 'state': fields.selection(
1447 [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',1446 [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',
@@ -1755,14 +1754,14 @@
1755class account_bank_statement(orm.Model):1754class account_bank_statement(orm.Model):
1756 _inherit = 'account.bank.statement'1755 _inherit = 'account.bank.statement'
17571756
1758 def _end_balance(self, cursor, user, ids, name, attr, context=None):1757 def _end_balance(self, cr, uid, ids, name, attr, context=None):
1759 """1758 """
1760 This method taken from account/account_bank_statement.py and1759 This method taken from account/account_bank_statement.py and
1761 altered to take the statement line subflow into account1760 altered to take the statement line subflow into account
1762 """1761 """
1763 res = {}1762 res = {}
1764 1763
1765 statements = self.browse(cursor, user, ids, context=context)1764 statements = self.browse(cr, uid, ids, context=context)
1766 for statement in statements:1765 for statement in statements:
1767 res[statement.id] = statement.balance_start1766 res[statement.id] = statement.balance_start
17681767
17691768
=== modified file 'account_banking/wizard/bank_import.py'
--- account_banking/wizard/bank_import.py 2013-04-27 10:14:24 +0000
+++ account_banking/wizard/bank_import.py 2013-06-26 21:16:23 +0000
@@ -28,9 +28,9 @@
28The parsing is done in the parser modules. Every parser module is required to28The parsing is done in the parser modules. Every parser module is required to
29use parser.models as a mean of communication with the business logic.29use parser.models as a mean of communication with the business logic.
30'''30'''
31from osv import orm, fields
32import base6431import base64
33import datetime32import datetime
33from openerp.osv import orm, fields
34from openerp.tools.translate import _34from openerp.tools.translate import _
35from openerp.addons.account_banking.parsers import models35from openerp.addons.account_banking.parsers import models
36from openerp.addons.account_banking.parsers import convert36from openerp.addons.account_banking.parsers import convert
@@ -97,13 +97,13 @@
97class banking_import(orm.TransientModel):97class banking_import(orm.TransientModel):
98 _name = 'account.banking.bank.import'98 _name = 'account.banking.bank.import'
9999
100 def import_statements_file(self, cursor, uid, ids, context):100 def import_statements_file(self, cr, uid, ids, context):
101 '''101 '''
102 Import bank statements / bank transactions file.102 Import bank statements / bank transactions file.
103 This method is a wrapper for the business logic on the transaction.103 This method is a wrapper for the business logic on the transaction.
104 The parser modules represent the decoding logic.104 The parser modules represent the decoding logic.
105 '''105 '''
106 banking_import = self.browse(cursor, uid, ids, context)[0]106 banking_import = self.browse(cr, uid, ids, context)[0]
107 statements_file = banking_import.file107 statements_file = banking_import.file
108 data = base64.decodestring(statements_file)108 data = base64.decodestring(statements_file)
109109
@@ -125,10 +125,10 @@
125125
126 # Get the company126 # Get the company
127 company = (banking_import.company or127 company = (banking_import.company or
128 user_obj.browse(cursor, uid, uid, context).company_id)128 user_obj.browse(cr, uid, uid, context).company_id)
129129
130 # Parse the file130 # Parse the file
131 statements = parser.parse(cursor, data)131 statements = parser.parse(cr, data)
132132
133 if any([x for x in statements if not x.is_valid()]):133 if any([x for x in statements if not x.is_valid()]):
134 raise orm.except_orm(134 raise orm.except_orm(
@@ -137,7 +137,7 @@
137 )137 )
138138
139 # Create the file now, as the statements need to be linked to it139 # Create the file now, as the statements need to be linked to it
140 import_id = statement_file_obj.create(cursor, uid, dict(140 import_id = statement_file_obj.create(cr, uid, dict(
141 company_id = company.id,141 company_id = company.id,
142 file = statements_file,142 file = statements_file,
143 state = 'unfinished',143 state = 'unfinished',
@@ -184,7 +184,7 @@
184 else:184 else:
185 # Pull account info/currency185 # Pull account info/currency
186 account_info = banktools.get_company_bank_account(186 account_info = banktools.get_company_bank_account(
187 self.pool, cursor, uid, statement.local_account,187 self.pool, cr, uid, statement.local_account,
188 statement.local_currency, company, results.log188 statement.local_currency, company, results.log
189 )189 )
190 if not account_info:190 if not account_info:
@@ -238,7 +238,7 @@
238 # (e.g. a datetime string of the moment of import)238 # (e.g. a datetime string of the moment of import)
239 # and have potential duplicates flagged by the 239 # and have potential duplicates flagged by the
240 # matching procedure240 # matching procedure
241 statement_ids = statement_obj.search(cursor, uid, [241 statement_ids = statement_obj.search(cr, uid, [
242 ('name', '=', statement.id),242 ('name', '=', statement.id),
243 ('date', '=', convert.date2str(statement.date)),243 ('date', '=', convert.date2str(statement.date)),
244 ])244 ])
@@ -252,7 +252,7 @@
252252
253 # Get the period for the statement (as bank statement object checks this)253 # Get the period for the statement (as bank statement object checks this)
254 period_ids = period_obj.search(254 period_ids = period_obj.search(
255 cursor, uid, [255 cr, uid, [
256 ('company_id', '=', company.id),256 ('company_id', '=', company.id),
257 ('date_start', '<=', statement.date),257 ('date_start', '<=', statement.date),
258 ('date_stop', '>=', statement.date),258 ('date_stop', '>=', statement.date),
@@ -270,7 +270,7 @@
270 continue270 continue
271271
272 # Create the bank statement record272 # Create the bank statement record
273 statement_id = statement_obj.create(cursor, uid, dict(273 statement_id = statement_obj.create(cr, uid, dict(
274 name = statement.id,274 name = statement.id,
275 journal_id = account_info.journal_id.id,275 journal_id = account_info.journal_id.id,
276 date = convert.date2str(statement.date),276 date = convert.date2str(statement.date),
@@ -302,21 +302,21 @@
302 values['local_currency'] = statement.local_currency302 values['local_currency'] = statement.local_currency
303303
304 transaction_id = import_transaction_obj.create(304 transaction_id = import_transaction_obj.create(
305 cursor, uid, values, context=context)305 cr, uid, values, context=context)
306 transaction_ids.append(transaction_id)306 transaction_ids.append(transaction_id)
307 307
308 results.stat_loaded_cnt += 1308 results.stat_loaded_cnt += 1
309309
310 import_transaction_obj.match(cursor, uid, transaction_ids, results=results, context=context)310 import_transaction_obj.match(cr, uid, transaction_ids, results=results, context=context)
311 311
312 #recompute statement end_balance for validation312 #recompute statement end_balance for validation
313 statement_obj.button_dummy(313 statement_obj.button_dummy(
314 cursor, uid, imported_statement_ids, context=context)314 cr, uid, imported_statement_ids, context=context)
315315
316316
317 # Original code. Didn't take workflow logistics into account...317 # Original code. Didn't take workflow logistics into account...
318 #318 #
319 #cursor.execute(319 #cr.execute(
320 # "UPDATE payment_order o "320 # "UPDATE payment_order o "
321 # "SET state = 'done', "321 # "SET state = 'done', "
322 # "date_done = '%s' "322 # "date_done = '%s' "
@@ -358,13 +358,13 @@
358 ]358 ]
359 text_log = '\n'.join(report + results.log)359 text_log = '\n'.join(report + results.log)
360 state = results.error_cnt and 'error' or 'ready'360 state = results.error_cnt and 'error' or 'ready'
361 statement_file_obj.write(cursor, uid, import_id, dict(361 statement_file_obj.write(cr, uid, import_id, dict(
362 state = state, log = text_log,362 state = state, log = text_log,
363 ), context)363 ), context)
364 if not imported_statement_ids or not results.trans_loaded_cnt:364 if not imported_statement_ids or not results.trans_loaded_cnt:
365 # file state can be 'ready' while import state is 'error'365 # file state can be 'ready' while import state is 'error'
366 state = 'error'366 state = 'error'
367 self.write(cursor, uid, [ids[0]], dict(367 self.write(cr, uid, [ids[0]], dict(
368 import_id = import_id, log = text_log, state = state,368 import_id = import_id, log = text_log, state = state,
369 statement_ids = [(6, 0, imported_statement_ids)],369 statement_ids = [(6, 0, imported_statement_ids)],
370 ), context)370 ), context)
371371
=== modified file 'account_banking/wizard/bank_import_view.xml'
--- account_banking/wizard/bank_import_view.xml 2012-05-02 15:09:49 +0000
+++ account_banking/wizard/bank_import_view.xml 2013-06-26 21:16:23 +0000
@@ -4,7 +4,6 @@
4 <record id="view_banking_import" model="ir.ui.view">4 <record id="view_banking_import" model="ir.ui.view">
5 <field name="name">account.banking.bank.import</field>5 <field name="name">account.banking.bank.import</field>
6 <field name="model">account.banking.bank.import</field>6 <field name="model">account.banking.bank.import</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">7 <field name="arch" type="xml">
9 <form string="Import Bank Transactions File">8 <form string="Import Bank Transactions File">
10 <group colspan="4" states="init,ready,error">9 <group colspan="4" states="init,ready,error">
1110
=== modified file 'account_banking/wizard/banking_transaction_wizard.py'
--- account_banking/wizard/banking_transaction_wizard.py 2013-06-10 10:14:31 +0000
+++ account_banking/wizard/banking_transaction_wizard.py 2013-06-26 21:16:23 +0000
@@ -90,56 +90,33 @@
90 statement_line_obj = self.pool.get('account.bank.statement.line')90 statement_line_obj = self.pool.get('account.bank.statement.line')
91 transaction_obj = self.pool.get('banking.import.transaction')91 transaction_obj = self.pool.get('banking.import.transaction')
9292
93 if not vals:93 if not vals or not ids:
94 return True94 return True
9595
96 wiz = self.browse(cr, uid, ids[0], context=context)
97
96 # The following fields get never written98 # The following fields get never written
97 # they are just triggers for manual matching99 # they are just triggers for manual matching
98 # which populates regular fields on the transaction100 # which populates regular fields on the transaction
99 manual_invoice_ids = vals.pop('manual_invoice_ids', [])101 manual_invoice_ids = vals.pop('manual_invoice_ids', [])
100 manual_move_line_ids = vals.pop('manual_move_line_ids', [])102 manual_move_line_ids = vals.pop('manual_move_line_ids', [])
101103
102 # Support for writing fields.related is still flakey:
103 # https://bugs.launchpad.net/openobject-server/+bug/915975
104 # Will do so myself.
105
106 # Separate the related fields
107 transaction_vals = {}
108 wizard_vals = vals.copy()
109 for key in vals.keys():
110 field = self._columns[key]
111 if (isinstance(field, fields.related) and
112 field._arg[0] == 'import_transaction_id'):
113 transaction_vals[field._arg[1]] = vals[key]
114 del wizard_vals[key]
115
116 # write the related fields on the transaction model
117 if isinstance(ids, int):
118 ids = [ids]
119 for wizard in self.browse(cr, uid, ids, context=context):
120 if wizard.import_transaction_id:
121 transaction_obj.write(
122 cr, uid, wizard.import_transaction_id.id,
123 transaction_vals, context=context)
124
125 # write other fields to the wizard model
126 res = super(banking_transaction_wizard, self).write(104 res = super(banking_transaction_wizard, self).write(
127 cr, uid, ids, wizard_vals, context=context)105 cr, uid, ids, vals, context=context)
106 wiz.refresh()
128107
129 # End of workaround for lp:915975108 # Process the logic of the written values
130
131 """ Process the logic of the written values """
132109
133 # An invoice is selected from multiple candidates110 # An invoice is selected from multiple candidates
134 if vals and 'invoice_id' in vals:111 if vals and 'invoice_id' in vals:
135 for wiz in self.browse(cr, uid, ids, context=context):112 if (wiz.import_transaction_id.match_type == 'invoice' and
136 if (wiz.import_transaction_id.match_type == 'invoice' and
137 wiz.import_transaction_id.invoice_id):113 wiz.import_transaction_id.invoice_id):
138 # the current value might apply114 found = False
139 if (wiz.move_line_id and wiz.move_line_id.invoice and115 # the current value might apply
140 wiz.move_line_id.invoice.id == wiz.invoice_id.id):116 if (wiz.move_line_id and wiz.move_line_id.invoice and
141 found = True117 wiz.move_line_id.invoice == wiz.invoice_id):
142 continue118 found = True
119 else:
143 # Otherwise, retrieve the move line for this invoice120 # Otherwise, retrieve the move line for this invoice
144 # Given the arity of the relation, there is are always121 # Given the arity of the relation, there is are always
145 # multiple possibilities but the move lines here are122 # multiple possibilities but the move lines here are
@@ -147,8 +124,8 @@
147 # and the regular invoice workflow should only come up with 124 # and the regular invoice workflow should only come up with
148 # one of those only.125 # one of those only.
149 for move_line in wiz.import_transaction_id.move_line_ids:126 for move_line in wiz.import_transaction_id.move_line_ids:
150 if (move_line.invoice.id ==127 if (move_line.invoice ==
151 wiz.import_transaction_id.invoice_id.id):128 wiz.import_transaction_id.invoice_id):
152 transaction_obj.write(129 transaction_obj.write(
153 cr, uid, wiz.import_transaction_id.id,130 cr, uid, wiz.import_transaction_id.id,
154 { 'move_line_id': move_line.id, }, context=context)131 { 'move_line_id': move_line.id, }, context=context)
@@ -159,15 +136,12 @@
159 }, context=context)136 }, context=context)
160 found = True137 found = True
161 break138 break
162 # Cannot match the invoice 139 # Cannot match the invoice
163 if not found:140 if not found:
164 # transaction_obj.write(141 orm.except_orm(
165 # cr, uid, wiz.import_transaction_id.id,142 _("No entry found for the selected invoice"),
166 # { 'invoice_id': False, }, context=context)143 _("No entry found for the selected invoice. " +
167 orm.except_orm(144 "Try manual reconciliation."))
168 _("No entry found for the selected invoice"),
169 _("No entry found for the selected invoice. " +
170 "Try manual reconciliation."))
171145
172 if manual_move_line_ids or manual_invoice_ids:146 if manual_move_line_ids or manual_invoice_ids:
173 move_line_obj = self.pool.get('account.move.line')147 move_line_obj = self.pool.get('account.move.line')
@@ -323,24 +297,9 @@
323 {'duplicate': not wiz['duplicate']}, context=context)297 {'duplicate': not wiz['duplicate']}, context=context)
324 return self.create_act_window(cr, uid, ids, context=None)298 return self.create_act_window(cr, uid, ids, context=None)
325299
326 def _get_default_match_type(self, cr, uid, context=None):
327 """
328 Take initial value for the match type from the statement line
329 """
330 res = False
331 if context and 'statement_line_id' in context:
332 res = self.pool.get('account.bank.statement.line').read(
333 cr, uid, context['statement_line_id'],
334 ['match_type'], context=context)['match_type']
335 return res
336
337 def button_done(self, cr, uid, ids, context=None):300 def button_done(self, cr, uid, ids, context=None):
338 return {'type': 'ir.actions.act_window_close'} 301 return {'type': 'ir.actions.act_window_close'}
339302
340 _defaults = {
341# 'match_type': _get_default_match_type,
342 }
343
344 _columns = {303 _columns = {
345 'name': fields.char('Name', size=64),304 'name': fields.char('Name', size=64),
346 'statement_line_id': fields.many2one(305 'statement_line_id': fields.many2one(
@@ -392,8 +351,25 @@
392 'import_transaction_id', 'match_multi', 351 'import_transaction_id', 'match_multi',
393 type="boolean", string='Multiple matches'),352 type="boolean", string='Multiple matches'),
394 'match_type': fields.related(353 'match_type': fields.related(
395 'import_transaction_id', 'match_type', 354 'import_transaction_id', 'match_type', type='selection',
396 type="char", size=16, string='Match type', readonly=True),355 selection=[
356 ('move','Move'),
357 ('invoice', 'Invoice'),
358 ('payment', 'Payment line'),
359 ('payment_order', 'Payment order'),
360 ('storno', 'Storno'),
361 ('manual', 'Manual'),
362 ('payment_manual', 'Payment line (manual)'),
363 ('payment_order_manual', 'Payment order (manual)'),
364 ],
365 string='Match type', readonly=True),
366 'manual_invoice_id': fields.many2one(
367 'account.invoice', 'Match this invoice',
368 domain=[('reconciled', '=', False)]),
369 'manual_move_line_id': fields.many2one(
370 'account.move.line', 'Or match this entry',
371 domain=[('account_id.reconcile', '=', True),
372 ('reconcile_id', '=', False)]),
397 'manual_invoice_ids': fields.many2many(373 'manual_invoice_ids': fields.many2many(
398 'account.invoice',374 'account.invoice',
399 'banking_transaction_wizard_account_invoice_rel',375 'banking_transaction_wizard_account_invoice_rel',
@@ -417,8 +393,6 @@
417 string="Analytic Account"),393 string="Analytic Account"),
418 'move_currency_amount': fields.related('import_transaction_id','move_currency_amount',394 'move_currency_amount': fields.related('import_transaction_id','move_currency_amount',
419 type='float', string='Match Currency Amount', readonly=True),395 type='float', string='Match Currency Amount', readonly=True),
420 #'manual_payment_order_id': fields.many2one(
421 # 'payment.order', "Payment order to reconcile"),
422 }396 }
423397
424banking_transaction_wizard()398banking_transaction_wizard()
425399
=== modified file 'account_banking/wizard/banking_transaction_wizard.xml'
--- account_banking/wizard/banking_transaction_wizard.xml 2013-05-01 15:12:53 +0000
+++ account_banking/wizard/banking_transaction_wizard.xml 2013-06-26 21:16:23 +0000
@@ -3,7 +3,6 @@
3 <data>3 <data>
4 <record model="ir.ui.view" id="transaction_wizard_first">4 <record model="ir.ui.view" id="transaction_wizard_first">
5 <field name="name">transaction.wizard.first</field>5 <field name="name">transaction.wizard.first</field>
6 <field name="type">form</field>
7 <field name="model">banking.transaction.wizard</field>6 <field name="model">banking.transaction.wizard</field>
8 <field name="arch" type="xml">7 <field name="arch" type="xml">
9 <form string="Match transaction">8 <form string="Match transaction">
109
=== modified file 'account_banking/wizard/banktools.py'
--- account_banking/wizard/banktools.py 2013-05-01 14:25:04 +0000
+++ account_banking/wizard/banktools.py 2013-06-26 21:16:23 +0000
@@ -51,7 +51,7 @@
51 return False51 return False
52 return period_ids[0]52 return period_ids[0]
5353
54def get_bank_accounts(pool, cursor, uid, account_number, log, fail=False):54def get_bank_accounts(pool, cr, uid, account_number, log, fail=False):
55 '''55 '''
56 Get the bank account with account number account_number56 Get the bank account with account number account_number
57 '''57 '''
@@ -60,13 +60,13 @@
60 return []60 return []
6161
62 partner_bank_obj = pool.get('res.partner.bank')62 partner_bank_obj = pool.get('res.partner.bank')
63 bank_account_ids = partner_bank_obj.search(cursor, uid, [63 bank_account_ids = partner_bank_obj.search(cr, uid, [
64 ('acc_number', '=', account_number)64 ('acc_number', '=', account_number)
65 ])65 ])
66 if not bank_account_ids:66 if not bank_account_ids:
67 # SR 2012-02-19 does the search() override in res_partner_bank67 # SR 2012-02-19 does the search() override in res_partner_bank
68 # provides this result on the previous query?68 # provides this result on the previous query?
69 bank_account_ids = partner_bank_obj.search(cursor, uid, [69 bank_account_ids = partner_bank_obj.search(cr, uid, [
70 ('acc_number_domestic', '=', account_number)70 ('acc_number_domestic', '=', account_number)
71 ])71 ])
72 if not bank_account_ids:72 if not bank_account_ids:
@@ -76,7 +76,7 @@
76 % dict(account_no=account_number)76 % dict(account_no=account_number)
77 )77 )
78 return []78 return []
79 return partner_bank_obj.browse(cursor, uid, bank_account_ids)79 return partner_bank_obj.browse(cr, uid, bank_account_ids)
8080
81def _has_attr(obj, attr):81def _has_attr(obj, attr):
82 # Needed for dangling addresses and a weird exception scheme in82 # Needed for dangling addresses and a weird exception scheme in
@@ -129,14 +129,14 @@
129 'name %(name)s') % {'name': name})129 'name %(name)s') % {'name': name})
130 return partner_ids and partner_ids[0] or False130 return partner_ids and partner_ids[0] or False
131131
132def get_company_bank_account(pool, cursor, uid, account_number, currency,132def get_company_bank_account(pool, cr, uid, account_number, currency,
133 company, log):133 company, log):
134 '''134 '''
135 Get the matching bank account for this company. Currency is the ISO code135 Get the matching bank account for this company. Currency is the ISO code
136 for the requested currency.136 for the requested currency.
137 '''137 '''
138 results = struct()138 results = struct()
139 bank_accounts = get_bank_accounts(pool, cursor, uid, account_number, log,139 bank_accounts = get_bank_accounts(pool, cr, uid, account_number, log,
140 fail=True)140 fail=True)
141 if not bank_accounts:141 if not bank_accounts:
142 return False142 return False
@@ -159,12 +159,12 @@
159159
160 # Find matching journal for currency160 # Find matching journal for currency
161 journal_obj = pool.get('account.journal')161 journal_obj = pool.get('account.journal')
162 journal_ids = journal_obj.search(cursor, uid, [162 journal_ids = journal_obj.search(cr, uid, [
163 ('type', '=', 'bank'),163 ('type', '=', 'bank'),
164 ('currency.name', '=', currency or company.currency_id.name)164 ('currency.name', '=', currency or company.currency_id.name)
165 ])165 ])
166 if currency == company.currency_id.name:166 if currency == company.currency_id.name:
167 journal_ids_no_curr = journal_obj.search(cursor, uid, [167 journal_ids_no_curr = journal_obj.search(cr, uid, [
168 ('type', '=', 'bank'), ('currency', '=', False)168 ('type', '=', 'bank'), ('currency', '=', False)
169 ])169 ])
170 journal_ids.extend(journal_ids_no_curr)170 journal_ids.extend(journal_ids_no_curr)
@@ -172,9 +172,9 @@
172 criteria.append(('journal_id', 'in', journal_ids))172 criteria.append(('journal_id', 'in', journal_ids))
173173
174 # Find bank account settings174 # Find bank account settings
175 bank_settings_ids = bank_settings_obj.search(cursor, uid, criteria)175 bank_settings_ids = bank_settings_obj.search(cr, uid, criteria)
176 if bank_settings_ids:176 if bank_settings_ids:
177 settings = bank_settings_obj.browse(cursor, uid, bank_settings_ids)[0]177 settings = bank_settings_obj.browse(cr, uid, bank_settings_ids)[0]
178 results.company_id = company178 results.company_id = company
179 results.journal_id = settings.journal_id179 results.journal_id = settings.journal_id
180180
@@ -192,7 +192,7 @@
192192
193 return results193 return results
194194
195def get_or_create_bank(pool, cursor, uid, bic, online=False, code=None,195def get_or_create_bank(pool, cr, uid, bic, online=False, code=None,
196 name=None):196 name=None):
197 '''197 '''
198 Find or create the bank with the provided BIC code.198 Find or create the bank with the provided BIC code.
@@ -208,27 +208,27 @@
208 if len(bic) < 8:208 if len(bic) < 8:
209 # search key209 # search key
210 bank_ids = bank_obj.search(210 bank_ids = bank_obj.search(
211 cursor, uid, [211 cr, uid, [
212 ('bic', '=', bic[:6])212 ('bic', '=', bic[:6])
213 ])213 ])
214 if not bank_ids:214 if not bank_ids:
215 bank_ids = bank_obj.search(215 bank_ids = bank_obj.search(
216 cursor, uid, [216 cr, uid, [
217 ('bic', 'ilike', bic + '%')217 ('bic', 'ilike', bic + '%')
218 ])218 ])
219 else:219 else:
220 bank_ids = bank_obj.search(220 bank_ids = bank_obj.search(
221 cursor, uid, [221 cr, uid, [
222 ('bic', '=', bic)222 ('bic', '=', bic)
223 ])223 ])
224224
225 if bank_ids and len(bank_ids) == 1:225 if bank_ids and len(bank_ids) == 1:
226 banks = bank_obj.browse(cursor, uid, bank_ids)226 banks = bank_obj.browse(cr, uid, bank_ids)
227 return banks[0].id, banks[0].country.id227 return banks[0].id, banks[0].country.id
228228
229 country_obj = pool.get('res.country')229 country_obj = pool.get('res.country')
230 country_ids = country_obj.search(230 country_ids = country_obj.search(
231 cursor, uid, [('code', '=', bic[4:6])]231 cr, uid, [('code', '=', bic[4:6])]
232 )232 )
233 country_id = country_ids and country_ids[0] or False233 country_id = country_ids and country_ids[0] or False
234 bank_id = False234 bank_id = False
@@ -236,7 +236,7 @@
236 if online:236 if online:
237 info, address = sepa.online.bank_info(bic)237 info, address = sepa.online.bank_info(bic)
238 if info:238 if info:
239 bank_id = bank_obj.create(cursor, uid, dict(239 bank_id = bank_obj.create(cr, uid, dict(
240 code = info.code,240 code = info.code,
241 name = info.name,241 name = info.name,
242 street = address.street,242 street = address.street,
@@ -250,7 +250,7 @@
250 info = struct(name=name, code=code)250 info = struct(name=name, code=code)
251251
252 if not online or not bank_id:252 if not online or not bank_id:
253 bank_id = bank_obj.create(cursor, uid, dict(253 bank_id = bank_obj.create(cr, uid, dict(
254 code = info.code or 'UNKNOW',254 code = info.code or 'UNKNOW',
255 name = info.name or _('Unknown Bank'),255 name = info.name or _('Unknown Bank'),
256 country = country_id,256 country = country_id,
257257
=== modified file 'account_banking_nl_clieop/__openerp__.py'
--- account_banking_nl_clieop/__openerp__.py 2013-04-15 14:14:27 +0000
+++ account_banking_nl_clieop/__openerp__.py 2013-06-26 21:16:23 +0000
@@ -37,5 +37,5 @@
37 ClieOp format is used by Dutch banks to batch national bank transfers.37 ClieOp format is used by Dutch banks to batch national bank transfers.
38 This module uses the account_banking logic.38 This module uses the account_banking logic.
39 ''',39 ''',
40 'installable': False,40 'installable': True,
41}41}
4242
=== modified file 'account_banking_nl_clieop/account_banking_nl_clieop.py'
--- account_banking_nl_clieop/account_banking_nl_clieop.py 2013-04-15 13:59:50 +0000
+++ account_banking_nl_clieop/account_banking_nl_clieop.py 2013-06-26 21:16:23 +0000
@@ -1,6 +1,7 @@
1##############################################################################1##############################################################################
2#2#
3# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).3# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
4# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
4# All Rights Reserved5# All Rights Reserved
5#6#
6# This program is free software: you can redistribute it and/or modify7# This program is free software: you can redistribute it and/or modify
@@ -18,11 +19,12 @@
18#19#
19##############################################################################20##############################################################################
2021
21from osv import osv, fields
22from datetime import date22from datetime import date
23from tools.translate import _23from openerp.osv import orm, fields
2424from openerp.tools.translate import _
25class clieop_export(osv.osv):25
26
27class clieop_export(orm.Model):
26 '''ClieOp3 Export'''28 '''ClieOp3 Export'''
27 _name = 'banking.export.clieop'29 _name = 'banking.export.clieop'
28 _description = __doc__30 _description = __doc__
@@ -80,7 +82,7 @@
80 last = 182 last = 1
81 last_ids = self.search(cr, uid, [83 last_ids = self.search(cr, uid, [
82 ('date_generated', '=', 84 ('date_generated', '=',
83 fields.date.context_today(cr,uid,context))85 fields.date.context_today(self, cr,uid,context))
84 ], context=context)86 ], context=context)
85 if last_ids:87 if last_ids:
86 last = 1 + max([x['daynumber'] for x in self.read(88 last = 1 + max([x['daynumber'] for x in self.read(
@@ -94,6 +96,3 @@
94 'state': 'draft',96 'state': 'draft',
95 'daynumber': get_daynr,97 'daynumber': get_daynr,
96 }98 }
97clieop_export()
98
99# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
10099
=== modified file 'account_banking_nl_clieop/account_banking_nl_clieop.xml'
--- account_banking_nl_clieop/account_banking_nl_clieop.xml 2013-01-02 15:14:53 +0000
+++ account_banking_nl_clieop/account_banking_nl_clieop.xml 2013-06-26 21:16:23 +0000
@@ -11,7 +11,6 @@
11 <record id="view_banking_export_clieop_form" model="ir.ui.view">11 <record id="view_banking_export_clieop_form" model="ir.ui.view">
12 <field name="name">account.banking.export.clieop.form</field>12 <field name="name">account.banking.export.clieop.form</field>
13 <field name="model">banking.export.clieop</field>13 <field name="model">banking.export.clieop</field>
14 <field name="type">form</field>
15 <field name="arch" type="xml">14 <field name="arch" type="xml">
16 <form string="Client Opdrachten Export">15 <form string="Client Opdrachten Export">
17 <notebook>16 <notebook>
@@ -48,7 +47,6 @@
48 <record id="view_banking_export_clieop_tree" model="ir.ui.view">47 <record id="view_banking_export_clieop_tree" model="ir.ui.view">
49 <field name="name">account.banking.export.clieop.tree</field>48 <field name="name">account.banking.export.clieop.tree</field>
50 <field name="model">banking.export.clieop</field>49 <field name="model">banking.export.clieop</field>
51 <field name="type">tree</field>
52 <field name="arch" type="xml">50 <field name="arch" type="xml">
53 <tree string="Client Opdrachten Export">51 <tree string="Client Opdrachten Export">
54 <field name="filetype" />52 <field name="filetype" />
5553
=== modified file 'account_banking_nl_clieop/wizard/export_clieop.py'
--- account_banking_nl_clieop/wizard/export_clieop.py 2013-04-15 13:59:50 +0000
+++ account_banking_nl_clieop/wizard/export_clieop.py 2013-06-26 21:16:23 +0000
@@ -2,6 +2,7 @@
2##############################################################################2##############################################################################
3#3#
4# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).4# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
5# 2011 - 2013 Therp BV (<http://therp.nl>).
5# All Rights Reserved6# All Rights Reserved
6#7#
7# This program is free software: you can redistribute it and/or modify8# This program is free software: you can redistribute it and/or modify
@@ -21,21 +22,22 @@
2122
22import base6423import base64
23from datetime import datetime, date, timedelta24from datetime import datetime, date, timedelta
24from osv import osv, fields25from openerp.osv import orm, fields
25from tools.translate import _26from openerp.tools.translate import _
26import netsvc27from openerp import netsvc
27from account_banking import sepa28from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
28import clieop29from openerp.addons.account_banking import sepa
2930from openerp.addons.account_banking_nl_clieop.wizard import clieop
30def strpdate(arg, format='%Y-%m-%d'):31
31 '''shortcut'''32def strpdate(arg):
32 return datetime.strptime(arg, format).date()33 '''shortcut'''
3334 return datetime.strptime(arg, DEFAULT_SERVER_DATE_FORMAT).date()
34def strfdate(arg, format='%Y-%m-%d'):35
35 '''shortcut'''36def strfdate(arg):
36 return arg.strftime(format)37 '''shortcut'''
3738 return arg.strftime(DEFAULT_SERVER_DATE_FORMAT)
38class banking_export_clieop_wizard(osv.osv_memory):39
40class banking_export_clieop_wizard(orm.TransientModel):
39 _name = 'banking.export.clieop.wizard'41 _name = 'banking.export.clieop.wizard'
40 _description = 'Client Opdrachten Export'42 _description = 'Client Opdrachten Export'
41 _columns = {43 _columns = {
@@ -151,21 +153,17 @@
151 ),153 ),
152 }154 }
153155
154 _defaults = {156 def create(self, cr, uid, vals, context=None):
155 'test': True,
156 }
157
158 def create(self, cursor, uid, vals, context=None):
159 '''157 '''
160 Retrieve a sane set of default values based on the payment orders158 Retrieve a sane set of default values based on the payment orders
161 from the context.159 from the context.
162 '''160 '''
163 if 'batchtype' not in vals:161 if 'batchtype' not in vals:
164 self.check_orders(cursor, uid, vals, context)162 self.check_orders(cr, uid, vals, context)
165 return super(banking_export_clieop_wizard, self).create(163 return super(banking_export_clieop_wizard, self).create(
166 cursor, uid, vals, context)164 cr, uid, vals, context)
167165
168 def check_orders(self, cursor, uid, vals, context):166 def check_orders(self, cr, uid, vals, context):
169 '''167 '''
170 Check payment type for all orders.168 Check payment type for all orders.
171169
@@ -177,14 +175,14 @@
177 Also mind that rates for batches are way higher than those for175 Also mind that rates for batches are way higher than those for
178 transactions. It pays to limit the number of batches.176 transactions. It pays to limit the number of batches.
179 '''177 '''
180 today = date.today()178 today = strpdate(fields.date.context_today(self, cr, uid, context=context))
181 payment_order_obj = self.pool.get('payment.order')179 payment_order_obj = self.pool.get('payment.order')
182180
183 # Payment order ids are provided in the context181 # Payment order ids are provided in the context
184 payment_order_ids = context.get('active_ids', [])182 payment_order_ids = context.get('active_ids', [])
185 runs = {}183 runs = {}
186 # Only orders of same type can be combined184 # Only orders of same type can be combined
187 payment_orders = payment_order_obj.browse(cursor, uid, payment_order_ids)185 payment_orders = payment_order_obj.browse(cr, uid, payment_order_ids)
188 for payment_order in payment_orders:186 for payment_order in payment_orders:
189187
190 payment_type = payment_order.mode.type.code188 payment_type = payment_order.mode.type.code
@@ -194,8 +192,8 @@
194 runs[payment_type] = [payment_order]192 runs[payment_type] = [payment_order]
195193
196 if payment_order.date_prefered == 'fixed':194 if payment_order.date_prefered == 'fixed':
197 if payment_order.date_planned:195 if payment_order.date_scheduled:
198 execution_date = strpdate(payment_order.date_planned)196 execution_date = strpdate(payment_order.date_scheduled)
199 else:197 else:
200 execution_date = today198 execution_date = today
201 elif payment_order.date_prefered == 'now':199 elif payment_order.date_prefered == 'now':
@@ -212,12 +210,12 @@
212 else:210 else:
213 execution_date = today211 execution_date = today
214 if execution_date and execution_date >= max_date:212 if execution_date and execution_date >= max_date:
215 raise osv.except_osv(213 raise orm.except_orm(
216 _('Error'),214 _('Error'),
217 _('You can\'t create ClieOp orders more than 30 days in advance.')215 _('You can\'t create ClieOp orders more than 30 days in advance.')
218 )216 )
219 if len(runs) != 1:217 if len(runs) != 1:
220 raise osv.except_osv(218 raise orm.except_orm(
221 _('Error'),219 _('Error'),
222 _('You can only combine payment orders of the same type')220 _('You can only combine payment orders of the same type')
223 )221 )
@@ -231,12 +229,12 @@
231 'state': 'create',229 'state': 'create',
232 })230 })
233231
234 def create_clieop(self, cursor, uid, ids, context):232 def create_clieop(self, cr, uid, ids, context):
235 '''233 '''
236 Wizard to actually create the ClieOp3 file234 Wizard to actually create the ClieOp3 file
237 '''235 '''
238 payment_order_obj = self.pool.get('payment.order')236 payment_order_obj = self.pool.get('payment.order')
239 clieop_export = self.browse(cursor, uid, ids, context)[0]237 clieop_export = self.browse(cr, uid, ids, context)[0]
240 clieopfile = None238 clieopfile = None
241 for payment_order in clieop_export.payment_order_ids:239 for payment_order in clieop_export.payment_order_ids:
242 if not clieopfile:240 if not clieopfile:
@@ -253,7 +251,7 @@
253 else:251 else:
254 our_account_nr = payment_order.mode.bank_id.acc_number252 our_account_nr = payment_order.mode.bank_id.acc_number
255 if not our_account_nr:253 if not our_account_nr:
256 raise osv.except_osv(254 raise orm.except_orm(
257 _('Error'),255 _('Error'),
258 _('Your bank account has to have a valid account number')256 _('Your bank account has to have a valid account number')
259 )257 )
@@ -267,7 +265,7 @@
267 accountno_sender = our_account_nr,265 accountno_sender = our_account_nr,
268 seqno = self.pool.get(266 seqno = self.pool.get(
269 'banking.export.clieop').get_daynr(267 'banking.export.clieop').get_daynr(
270 cursor, uid, context=context),268 cr, uid, context=context),
271 test = clieop_export['test']269 test = clieop_export['test']
272 )270 )
273271
@@ -291,7 +289,7 @@
291 for line in payment_order.line_ids:289 for line in payment_order.line_ids:
292 # Check on missing partner of bank account (this can happen!)290 # Check on missing partner of bank account (this can happen!)
293 if not line.bank_id or not line.bank_id.partner_id:291 if not line.bank_id or not line.bank_id.partner_id:
294 raise osv.except_osv(292 raise orm.except_orm(
295 _('Error'),293 _('Error'),
296 _('There is insufficient information.\r\n'294 _('There is insufficient information.\r\n'
297 'Both destination address and account '295 'Both destination address and account '
@@ -314,7 +312,7 @@
314 # Is this an IBAN account?312 # Is this an IBAN account?
315 if iban.valid:313 if iban.valid:
316 if iban.countrycode != 'NL':314 if iban.countrycode != 'NL':
317 raise osv.except_osv(315 raise orm.except_orm(
318 _('Error'),316 _('Error'),
319 _('You cannot send international bank transfers '317 _('You cannot send international bank transfers '
320 'through ClieOp3!')318 'through ClieOp3!')
@@ -331,7 +329,7 @@
331 # Generate the specifics of this clieopfile329 # Generate the specifics of this clieopfile
332 order = clieopfile.order330 order = clieopfile.order
333 file_id = self.pool.get('banking.export.clieop').create(331 file_id = self.pool.get('banking.export.clieop').create(
334 cursor, uid, dict(332 cr, uid, dict(
335 filetype = order.name_transactioncode,333 filetype = order.name_transactioncode,
336 identification = order.identification,334 identification = order.identification,
337 prefered_date = strfdate(order.preferred_execution_date),335 prefered_date = strfdate(order.preferred_execution_date),
@@ -346,7 +344,7 @@
346 [6, 0, [x.id for x in clieop_export['payment_order_ids']]]344 [6, 0, [x.id for x in clieop_export['payment_order_ids']]]
347 ],345 ],
348 ), context)346 ), context)
349 self.write(cursor, uid, [ids[0]], dict(347 self.write(cr, uid, [ids[0]], dict(
350 filetype = order.name_transactioncode,348 filetype = order.name_transactioncode,
351 testcode = order.testcode,349 testcode = order.testcode,
352 file_id = file_id,350 file_id = file_id,
@@ -364,31 +362,27 @@
364 'res_id': ids[0] or False,362 'res_id': ids[0] or False,
365 }363 }
366364
367 def cancel_clieop(self, cursor, uid, ids, context):365 def cancel_clieop(self, cr, uid, ids, context):
368 '''366 '''
369 Cancel the ClieOp: just drop the file367 Cancel the ClieOp: just drop the file
370 '''368 '''
371 clieop_export = self.read(cursor, uid, ids, ['file_id'], context)[0]369 clieop_export = self.read(cr, uid, ids, ['file_id'], context)[0]
372 self.pool.get('banking.export.clieop').unlink(cursor, uid, clieop_export['file_id'][0])370 self.pool.get('banking.export.clieop').unlink(cr, uid, clieop_export['file_id'][0])
373 return {'type': 'ir.actions.act_window_close'}371 return {'type': 'ir.actions.act_window_close'}
374372
375 def save_clieop(self, cursor, uid, ids, context):373 def save_clieop(self, cr, uid, ids, context):
376 '''374 '''
377 Save the ClieOp: mark all payments in the file as 'sent', if not a test375 Save the ClieOp: mark all payments in the file as 'sent', if not a test
378 '''376 '''
379 clieop_export = self.browse(377 clieop_export = self.browse(
380 cursor, uid, ids, context)[0]378 cr, uid, ids, context)[0]
381 if not clieop_export['test']:379 if not clieop_export['test']:
382 clieop_obj = self.pool.get('banking.export.clieop')380 clieop_obj = self.pool.get('banking.export.clieop')
383 payment_order_obj = self.pool.get('payment.order')381 payment_order_obj = self.pool.get('payment.order')
384 clieop_file = clieop_obj.write(382 clieop_file = clieop_obj.write(
385 cursor, uid, clieop_export['file_id'].id, {'state': 'sent'}383 cr, uid, clieop_export['file_id'].id, {'state': 'sent'}
386 )384 )
387 wf_service = netsvc.LocalService('workflow')385 wf_service = netsvc.LocalService('workflow')
388 for order in clieop_export['payment_order_ids']:386 for order in clieop_export['payment_order_ids']:
389 wf_service.trg_validate(uid, 'payment.order', order.id, 'sent', cursor)387 wf_service.trg_validate(uid, 'payment.order', order.id, 'sent', cr)
390 return {'type': 'ir.actions.act_window_close'}388 return {'type': 'ir.actions.act_window_close'}
391
392banking_export_clieop_wizard()
393
394# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
395389
=== modified file 'account_banking_nl_clieop/wizard/export_clieop_view.xml'
--- account_banking_nl_clieop/wizard/export_clieop_view.xml 2013-01-02 15:14:53 +0000
+++ account_banking_nl_clieop/wizard/export_clieop_view.xml 2013-06-26 21:16:23 +0000
@@ -4,7 +4,6 @@
4 <record id="banking_export_clieop_wizard_view" model="ir.ui.view">4 <record id="banking_export_clieop_wizard_view" model="ir.ui.view">
5 <field name="name">banking.export.clieop.wizard.view</field>5 <field name="name">banking.export.clieop.wizard.view</field>
6 <field name="model">banking.export.clieop.wizard</field>6 <field name="model">banking.export.clieop.wizard</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">7 <field name="arch" type="xml">
9 <form string="Client Opdrachten Export">8 <form string="Client Opdrachten Export">
10 <field name="state" invisible="True"/>9 <field name="state" invisible="True"/>
1110
=== modified file 'account_banking_nl_girotel/girotel.py'
--- account_banking_nl_girotel/girotel.py 2013-04-15 13:59:50 +0000
+++ account_banking_nl_girotel/girotel.py 2013-06-26 21:16:23 +0000
@@ -45,6 +45,7 @@
45from account_banking.parsers import models45from account_banking.parsers import models
46from account_banking.parsers.convert import str2date, to_swift46from account_banking.parsers.convert import str2date, to_swift
47from tools.translate import _47from tools.translate import _
48import re
48import csv49import csv
4950
50bt = models.mem_bank_transaction51bt = models.mem_bank_transaction
@@ -105,6 +106,13 @@
105 self.date = str2date(self.date, '%Y%m%d')106 self.date = str2date(self.date, '%Y%m%d')
106 if self.direction == 'A':107 if self.direction == 'A':
107 self.transferred_amount = -float(self.transferred_amount)108 self.transferred_amount = -float(self.transferred_amount)
109 if (self.transfer_type == 'VZ'
110 and (not self.remote_account or self.remote_account == '0')
111 and (not self.message or re.match('^\s*$', self.message))
112 and self.remote_owner.startswith('TOTAAL ')):
113 self.transfer_type = 'PB'
114 self.message = self.remote_owner
115 self.remove_owner = False
108 else:116 else:
109 self.transferred_amount = float(self.transferred_amount)117 self.transferred_amount = float(self.transferred_amount)
110 self.local_account = self.local_account.zfill(10)118 self.local_account = self.local_account.zfill(10)
@@ -140,7 +148,8 @@
140 'GT': bt.ORDER,148 'GT': bt.ORDER,
141 'IC': bt.DIRECT_DEBIT,149 'IC': bt.DIRECT_DEBIT,
142 'OV': bt.ORDER,150 'OV': bt.ORDER,
143 'VZ': bt.PAYMENT_BATCH,151 'VZ': bt.ORDER,
152 'PB': bt.PAYMENT_BATCH,
144 }153 }
145154
146 def __init__(self, line, *args, **kwargs):155 def __init__(self, line, *args, **kwargs):
@@ -171,11 +180,14 @@
171 4. Cash withdrawals from banks are too not seen as a transfer between180 4. Cash withdrawals from banks are too not seen as a transfer between
172 two accounts - the cash exits the banking system. These withdrawals181 two accounts - the cash exits the banking system. These withdrawals
173 have their transfer_type set to 'GM'.182 have their transfer_type set to 'GM'.
183 5. Aggregated payment batches. These transactions have transfer type
184 'VZ' natively but are changed to 'PB' while parsing. These transactions
185 have no remote account.
174 '''186 '''
175 return bool(self.transferred_amount and self.execution_date and (187 return bool(self.transferred_amount and self.execution_date and (
176 self.remote_account or188 self.remote_account or
177 self.transfer_type in [189 self.transfer_type in [
178 'DV', 'BT', 'BA', 'GM',190 'DV', 'PB', 'BT', 'BA', 'GM',
179 ]))191 ]))
180192
181 def refold_message(self, message):193 def refold_message(self, message):
182194
=== modified file 'account_banking_payment/__openerp__.py'
--- account_banking_payment/__openerp__.py 2013-03-17 12:53:37 +0000
+++ account_banking_payment/__openerp__.py 2013-06-26 21:16:23 +0000
@@ -37,6 +37,7 @@
37 'data': [37 'data': [
38 'view/account_payment.xml',38 'view/account_payment.xml',
39 'view/banking_transaction_wizard.xml',39 'view/banking_transaction_wizard.xml',
40 'view/payment_mode.xml',
40 'view/payment_mode_type.xml',41 'view/payment_mode_type.xml',
41 'view/bank_payment_manual.xml',42 'view/bank_payment_manual.xml',
42 'data/payment_mode_type.xml',43 'data/payment_mode_type.xml',
@@ -53,5 +54,5 @@
53 account_banking_nl_clieop54 account_banking_nl_clieop
54 ''',55 ''',
55 'auto_install': True,56 'auto_install': True,
56 'installable': False,57 'installable': True,
57}58}
5859
=== modified file 'account_banking_payment/model/__init__.py'
--- account_banking_payment/model/__init__.py 2013-03-16 19:00:59 +0000
+++ account_banking_payment/model/__init__.py 2013-06-26 21:16:23 +0000
@@ -4,7 +4,6 @@
4import payment_mode_type4import payment_mode_type
5import payment_order_create5import payment_order_create
6import banking_import_transaction6import banking_import_transaction
7import account_bank_statement_line
8import banking_transaction_wizard7import banking_transaction_wizard
9import bank_payment_manual8import bank_payment_manual
10import banking_import_line9import banking_import_line
1110
=== removed file 'account_banking_payment/model/account_bank_statement_line.py'
--- account_banking_payment/model/account_bank_statement_line.py 2013-03-17 09:10:15 +0000
+++ account_banking_payment/model/account_bank_statement_line.py 1970-01-01 00:00:00 +0000
@@ -1,40 +0,0 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
5# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
6#
7# All other contributions are (C) by their respective contributors
8#
9# All Rights Reserved
10#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU Affero General Public License as
13# published by the Free Software Foundation, either version 3 of the
14# License, or (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU Affero General Public License for more details.
20#
21# You should have received a copy of the GNU Affero General Public License
22# along with this program. If not, see <http://www.gnu.org/licenses/>.
23#
24##############################################################################
25
26from openerp.osv import orm, fields
27
28
29class account_bank_statement_line(orm.Model):
30 _inherit = 'account.bank.statement.line'
31 _columns = {
32 'match_type': fields.related(
33 # Add payment and storno types
34 'import_transaction_id', 'match_type', type='selection',
35 selection=[('manual', 'Manual'), ('move','Move'),
36 ('invoice', 'Invoice'), ('payment', 'Payment'),
37 ('payment_order', 'Payment order'),
38 ('storno', 'Storno')],
39 string='Match type', readonly=True,),
40 }
410
=== modified file 'account_banking_payment/model/account_payment.py'
--- account_banking_payment/model/account_payment.py 2013-04-06 05:02:18 +0000
+++ account_banking_payment/model/account_payment.py 2013-06-26 21:16:23 +0000
@@ -73,6 +73,8 @@
73 'line_ids': fields.one2many(73 'line_ids': fields.one2many(
74 'payment.line', 'order_id', 'Payment lines',74 'payment.line', 'order_id', 'Payment lines',
75 states={75 states={
76 'open': [('readonly', True)],
77 'cancel': [('readonly', True)],
76 'sent': [('readonly', True)],78 'sent': [('readonly', True)],
77 'rejected': [('readonly', True)],79 'rejected': [('readonly', True)],
78 'done': [('readonly', True)]80 'done': [('readonly', True)]
@@ -172,32 +174,10 @@
172 ])174 ])
173 payment_line_obj.write(cr, uid, line_ids, kwargs)175 payment_line_obj.write(cr, uid, line_ids, kwargs)
174176
175 def set_to_draft(self, cr, uid, ids, *args):
176 '''
177 Set both self and payment lines to state 'draft'.
178 '''
179 self._write_payment_lines(cr, uid, ids, export_state='draft')
180 return super(payment_order, self).set_to_draft(
181 cr, uid, ids, *args
182 )
183
184 def action_sent(self, cr, uid, ids, context=None):
185 '''
186 Set both self and payment lines to state 'sent'.
187 '''
188 self._write_payment_lines(cr, uid, ids, export_state='sent')
189 self.write(cr, uid, ids, {
190 'state': 'sent',
191 'date_sent': fields.date.context_today(
192 self, cr, uid, context=context),
193 }, context=context)
194 return True
195
196 def action_rejected(self, cr, uid, ids, *args):177 def action_rejected(self, cr, uid, ids, *args):
197 '''178 '''
198 Set both self and payment lines to state 'rejected'.179 Set both self and payment lines to state 'rejected'.
199 '''180 '''
200 self._write_payment_lines(cr, uid, ids, export_state='rejected')
201 wf_service = netsvc.LocalService('workflow')181 wf_service = netsvc.LocalService('workflow')
202 for id in ids:182 for id in ids:
203 wf_service.trg_validate(uid, 'payment.order', id, 'rejected', cr)183 wf_service.trg_validate(uid, 'payment.order', id, 'rejected', cr)
@@ -209,32 +189,172 @@
209 '''189 '''
210 self._write_payment_lines(190 self._write_payment_lines(
211 cr, uid, ids,191 cr, uid, ids,
212 export_state='done',
213 date_done=fields.date.context_today(self, cr, uid))192 date_done=fields.date.context_today(self, cr, uid))
214 return super(payment_order, self).set_done(193 return super(payment_order, self).set_done(
215 cr, uid, ids, *args194 cr, uid, ids, *args
216 )195 )
217196
218 """197 def debit_reconcile_transfer(self, cr, uid, payment_order_id,
219 Hooks for processing direct debit orders, such as implemented in198 amount, currency, context=None):
220 account_direct_debit module.199 """
221 """200 During import of bank statements, create the reconcile on the transfer
222 def debit_reconcile_transfer(201 account containing all the open move lines on the transfer account.
223 self, cr, uid, payment_order_id, amount, currency, context=None):202 """
224 """203 move_line_obj = self.pool.get('account.move.line')
225 Reconcile the payment order if the amount is correct. Return the 204 order = self.browse(cr, uid, payment_order_id, context)
226 id of the reconciliation.205 line_ids = []
227 """206 reconcile_id = False
228 raise orm.except_orm(207 if not order.line_ids[0].transit_move_line_id:
229 _("Cannot reconcile"),208 wf_service = netsvc.LocalService('workflow')
230 _("Cannot reconcile debit order: "+209 wf_service.trg_validate(
231 "Not implemented."))210 uid, 'payment.order', payment_order_id, 'done', cr)
232211 return False
233 def debit_unreconcile_transfer(212 for order_line in order.line_ids:
234 self, cr, uid, payment_order_id, reconcile_id, amount, currency,213 for line in order_line.transit_move_line_id.move_id.line_id:
235 context=None):214 if line.account_id.type == 'other' and not line.reconcile_id:
236 """ Unreconcile the payment_order if at all possible """215 line_ids.append(line.id)
237 raise orm.except_orm(216 if self.pool.get('res.currency').is_zero(
238 _("Cannot unreconcile"),217 cr, uid, currency,
239 _("Cannot unreconcile debit order: "+218 move_line_obj.get_balance(cr, uid, line_ids) - amount):
240 "Not implemented."))219 reconcile_id = self.pool.get('account.move.reconcile').create(
220 cr, uid,
221 {'type': 'auto', 'line_id': [(6, 0, line_ids)]},
222 context)
223 # set direct debit order to finished state
224 wf_service = netsvc.LocalService('workflow')
225 wf_service.trg_validate(
226 uid, 'payment.order', payment_order_id, 'done', cr)
227 return reconcile_id
228
229 def debit_unreconcile_transfer(self, cr, uid, payment_order_id, reconcile_id,
230 amount, currency, context=None):
231 """
232 Due to a cancelled bank statements import, unreconcile the move on
233 the transfer account. Delegate the conditions to the workflow.
234 Raise on failure for rollback.
235
236 Workflow appears to return False even on success so we just check
237 the order's state that we know to be set to 'sent' in that case.
238 """
239 self.pool.get('account.move.reconcile').unlink(
240 cr, uid, [reconcile_id], context=context)
241 netsvc.LocalService('workflow').trg_validate(
242 uid, 'payment.order', payment_order_id, 'undo_done', cr)
243 state = self.pool.get('payment.order').read(
244 cr, uid, payment_order_id, ['state'], context=context)['state']
245 if state != 'sent':
246 raise orm.except_orm(
247 _("Cannot unreconcile"),
248 _("Cannot unreconcile payment order: "+
249 "Workflow will not allow it."))
250 return True
251
252 def test_undo_done(self, cr, uid, ids, context=None):
253 """
254 Called from the workflow. Used to unset done state on
255 payment orders that were reconciled with bank transfers
256 which are being cancelled.
257
258 Test if the payment order has not been reconciled. Depends
259 on the restriction that transit move lines should use an
260 account of type 'other', and on the restriction of payment
261 and debit orders that they only take moves on accounts
262 payable/receivable.
263 """
264 for order in self.browse(cr, uid, ids, context=context):
265 for order_line in order.line_ids:
266 if order_line.transit_move_line_id.move_id:
267 for line in order_line.transit_move_line_id.move_id.line_id:
268 if (line.account_id.type == 'other' and
269 line.reconcile_id):
270 return False
271 return True
272
273 def action_sent(self, cr, uid, ids, context=None):
274 """
275 Create the moves that pay off the move lines from
276 the debit order. This happens when the debit order file is
277 generated.
278 """
279 account_move_obj = self.pool.get('account.move')
280 account_move_line_obj = self.pool.get('account.move.line')
281 payment_line_obj = self.pool.get('payment.line')
282 labels = {
283 'payment': _('Payment order'),
284 'debit': _('Direct debit order'),
285 }
286 for order in self.browse(cr, uid, ids, context=context):
287 for line in order.line_ids:
288 # basic checks
289 if not line.move_line_id:
290 raise orm.except_orm(
291 _('Error'),
292 _('No move line provided for line %s') % line.name)
293 if line.move_line_id.reconcile_id:
294 raise orm.except_orm(
295 _('Error'),
296 _('Move line %s has already been paid/reconciled') %
297 line.move_line_id.name
298 )
299
300 move_id = account_move_obj.create(cr, uid, {
301 'journal_id': order.mode.transfer_journal_id.id,
302 'name': '%s %s' % (labels[order.payment_order_type],
303 line.move_line_id.move_id.name),
304 'reference': '%s%s' % (order.payment_order_type[:3].upper(),
305 line.move_line_id.move_id.name),
306 }, context=context)
307
308 # TODO: take multicurrency into account
309
310 # create the debit move line on the transfer account
311 vals = {
312 'name': _('%s for %s') % (
313 labels[order.payment_order_type],
314 line.move_line_id.invoice and
315 line.move_line_id.invoice.number or
316 line.move_line_id.name),
317 'move_id': move_id,
318 'partner_id': line.partner_id.id,
319 'account_id': order.mode.transfer_account_id.id,
320 'credit': (order.payment_order_type == 'payment'
321 and line.amount or 0.0),
322 'debit': (order.payment_order_type == 'debit'
323 and line.amount or 0.0),
324 'date': fields.date.context_today(
325 self, cr, uid, context=context),
326 }
327 transfer_move_line_id = account_move_line_obj.create(
328 cr, uid, vals, context=context)
329
330 # create the debit move line on the receivable account
331 vals.update({
332 'account_id': line.move_line_id.account_id.id,
333 'credit': (order.payment_order_type == 'debit'
334 and line.amount or 0.0),
335 'debit': (order.payment_order_type == 'payment'
336 and line.amount or 0.0),
337 })
338 reconcile_move_line_id = account_move_line_obj.create(
339 cr, uid, vals, context=context)
340
341 # register the debit move line on the payment line
342 # and call reconciliation on it
343 payment_line_obj.write(
344 cr, uid, line.id,
345 {'transit_move_line_id': reconcile_move_line_id},
346 context=context)
347
348 payment_line_obj.debit_reconcile(
349 cr, uid, line.id, context=context)
350 account_move_obj.post(cr, uid, [move_id], context=context)
351
352 # State field is written by act_sent_wait
353 self.write(cr, uid, ids, {
354 'date_sent': fields.date.context_today(
355 self, cr, uid, context=context),
356 }, context=context)
357
358 return True
359
360
241361
=== modified file 'account_banking_payment/model/banking_import_transaction.py'
--- account_banking_payment/model/banking_import_transaction.py 2013-06-03 09:47:11 +0000
+++ account_banking_payment/model/banking_import_transaction.py 2013-06-26 21:16:23 +0000
@@ -27,37 +27,44 @@
27from openerp import netsvc27from openerp import netsvc
28from openerp.tools.translate import _28from openerp.tools.translate import _
29from openerp.addons.decimal_precision import decimal_precision as dp29from openerp.addons.decimal_precision import decimal_precision as dp
30from openerp.addons.account_banking.parsers.models import mem_bank_transaction as bt
3031
3132
32class banking_import_transaction(orm.Model):33class banking_import_transaction(orm.Model):
33 _inherit = 'banking.import.transaction'34 _inherit = 'banking.import.transaction'
3435
35 def _match_debit_order(36 def _match_payment_order(
36 self, cr, uid, trans, log, context=None):37 self, cr, uid, trans, log, order_type='payment', context=None):
3738
38 def is_zero(total):39 def equals_order_amount(payment_order, transferred_amount):
40 if (not hasattr(payment_order, 'payment_order_type')
41 or payment_order.payment_order_type == 'payment'):
42 sign = 1
43 else:
44 sign = -1
45 total = payment_order.total + sign * transferred_amount
39 return self.pool.get('res.currency').is_zero(46 return self.pool.get('res.currency').is_zero(
40 cr, uid, trans.statement_id.currency, total)47 cr, uid, trans.statement_line_id.statement_id.currency, total)
4148
42 payment_order_obj = self.pool.get('payment.order')49 payment_order_obj = self.pool.get('payment.order')
4350
44 order_ids = payment_order_obj.search(51 order_ids = payment_order_obj.search(
45 cr, uid, [('payment_order_type', '=', 'debit'),52 cr, uid, [('payment_order_type', '=', order_type),
46 ('state', '=', 'sent'),53 ('state', '=', 'sent'),
47 ('date_sent', '<=', trans.execution_date),54 ('date_sent', '<=', trans.execution_date),
48 ],55 ],
49 limit=0, context=context)56 limit=0, context=context)
50 orders = payment_order_obj.browse(cr, uid, order_ids, context)57 orders = payment_order_obj.browse(cr, uid, order_ids, context)
51 candidates = [x for x in orders if58 candidates = [x for x in orders if
52 is_zero(x.total - trans.transferred_amount) and59 equals_order_amount(x, trans.statement_line_id.amount)]
53 x.line_ids and x.line_ids[0].debit_move_line_id]
54 if len(candidates) > 0:60 if len(candidates) > 0:
55 # retrieve the common account_id, if any61 # retrieve the common account_id, if any
56 account_id = False62 account_id = False
57 for line in candidates[0].line_ids[0].debit_move_line_id.move_id.line_id:63 if (candidates[0].line_ids[0].transit_move_line_id):
58 if line.account_id.type == 'other':64 for line in candidates[0].line_ids[0].transit_move_line_id.move_id.line_id:
59 account_id = line.account_id.id65 if line.account_id.type == 'other':
60 break66 account_id = line.account_id.id
67 break
61 return dict(68 return dict(
62 move_line_ids = False,69 move_line_ids = False,
63 match_type = 'payment_order',70 match_type = 'payment_order',
@@ -82,7 +89,7 @@
82 # stornos MUST have an exact match89 # stornos MUST have an exact match
83 if len(line_ids) == 1:90 if len(line_ids) == 1:
84 account_id = payment_line_obj.get_storno_account_id(91 account_id = payment_line_obj.get_storno_account_id(
85 cr, uid, line_ids[0], trans.transferred_amount,92 cr, uid, line_ids[0], trans.statement_line_id.amount,
86 trans.statement_id.currency, context=None)93 trans.statement_id.currency, context=None)
87 if account_id:94 if account_id:
88 return dict(95 return dict(
@@ -114,7 +121,7 @@
114 x for x in payment_lines121 x for x in payment_lines
115 if x.communication == trans.reference 122 if x.communication == trans.reference
116 and round(x.amount, digits) == -round(123 and round(x.amount, digits) == -round(
117 trans.transferred_amount, digits)124 trans.statement_line_id.amount, digits)
118 and trans.remote_account in (x.bank_id.acc_number,125 and trans.remote_account in (x.bank_id.acc_number,
119 x.bank_id.acc_number_domestic)126 x.bank_id.acc_number_domestic)
120 ]127 ]
@@ -171,10 +178,6 @@
171 raise orm.except_orm(178 raise orm.except_orm(
172 _("Cannot reconcile"),179 _("Cannot reconcile"),
173 _("Cannot reconcile: no direct debit order"))180 _("Cannot reconcile: no direct debit order"))
174 if transaction.payment_order_id.payment_order_type != 'debit':
175 raise orm.except_orm(
176 _("Cannot reconcile"),
177 _("Reconcile payment order not implemented"))
178 reconcile_id = payment_order_obj.debit_reconcile_transfer(181 reconcile_id = payment_order_obj.debit_reconcile_transfer(
179 cr, uid,182 cr, uid,
180 transaction.payment_order_id.id,183 transaction.payment_order_id.id,
@@ -195,7 +198,6 @@
195 payment_line_obj = self.pool.get('payment.line')198 payment_line_obj = self.pool.get('payment.line')
196 payment_line_obj.write(199 payment_line_obj.write(
197 cr, uid, transaction.payment_line_id.id, {200 cr, uid, transaction.payment_line_id.id, {
198 'export_state': 'done',
199 'date_done': transaction.statement_line_id.date,201 'date_done': transaction.statement_line_id.date,
200 }202 }
201 )203 )
@@ -232,11 +234,12 @@
232 if not transaction.payment_order_id:234 if not transaction.payment_order_id:
233 raise orm.except_orm(235 raise orm.except_orm(
234 _("Cannot unreconcile"),236 _("Cannot unreconcile"),
235 _("Cannot unreconcile: no direct debit order"))237 _("Cannot unreconcile: no payment or direct debit order"))
236 if transaction.payment_order_id.payment_order_type != 'debit':238 if not transaction.statement_line_id.reconcile_id:
237 raise orm.except_orm(239 raise orm.except_orm(
238 _("Cannot unreconcile"),240 _("Cannot unreconcile"),
239 _("Unreconcile payment order not implemented"))241 _("Payment orders without transfer move lines cannot be "
242 "unreconciled this way"))
240 return payment_order_obj.debit_unreconcile_transfer(243 return payment_order_obj.debit_unreconcile_transfer(
241 cr, uid, transaction.payment_order_id.id,244 cr, uid, transaction.payment_order_id.id,
242 transaction.statement_line_id.reconcile_id.id,245 transaction.statement_line_id.reconcile_id.id,
@@ -302,17 +305,6 @@
302 cr, uid, transaction.payment_line_id.id, context)305 cr, uid, transaction.payment_line_id.id, context)
303306
304 _columns = {307 _columns = {
305 'match_type': fields.selection(
306 # Add payment and storno types
307 [
308 ('manual', 'Manual'),
309 ('move','Move'),
310 ('invoice', 'Invoice'),
311 ('payment', 'Payment'),
312 ('payment_order', 'Payment order'),
313 ('storno', 'Storno'),
314 ],
315 'Match type'),
316 'payment_order_ids': fields.many2many(308 'payment_order_ids': fields.many2many(
317 'payment.order', 'banking_transaction_payment_order_rel',309 'payment.order', 'banking_transaction_payment_order_rel',
318 'order_id', 'transaction_id', 'Payment orders'),310 'order_id', 'transaction_id', 'Payment orders'),
@@ -334,14 +326,14 @@
334 return res326 return res
335327
336 def clear_and_write(self, cr, uid, ids, vals=None, context=None):328 def clear_and_write(self, cr, uid, ids, vals=None, context=None):
337 super(banking_import_transaction, self).clear_and_write(329 write_vals = {
330 'payment_line_id': False,
331 'payment_order_id': False,
332 'payment_order_ids': [(6, 0, [])],
333 }
334 write_vals.update(vals or {})
335 return super(banking_import_transaction, self).clear_and_write(
338 cr, uid, ids, vals=vals, context=context)336 cr, uid, ids, vals=vals, context=context)
339 return self.write(
340 cr, uid, ids, {
341 'payment_line_id': False,
342 'payment_order_ids': [(6, 0, [])],
343 },
344 context=context)
345337
346 def move_info2values(self, move_info):338 def move_info2values(self, move_info):
347 vals = super(banking_import_transaction, self).move_info2values(339 vals = super(banking_import_transaction, self).move_info2values(
@@ -356,11 +348,25 @@
356 )348 )
357 return vals349 return vals
358350
359 def match(self, cr, uid, ids, results=None, context=None):351 def hook_match_payment(self, cr, uid, transaction, log, context=None):
360 res = super(banking_import_transaction, self).match(352 """
361 cr, uid, ids, results=results, context=context)353 Called from match() in the core module.
362354 Match payment batches, direct debit orders and stornos
363 return res355 """
356 move_info = False
357 if transaction.type == bt.PAYMENT_BATCH:
358 move_info = self._match_payment_order(
359 cr, uid, transaction, log,
360 order_type='payment', context=context)
361 elif transaction.type == bt.DIRECT_DEBIT:
362 move_info = self._match_payment_order(
363 cr, uid, transaction, log,
364 order_type='debit', context=context)
365 elif transaction.type == bt.STORNO:
366 move_info = self._match_storno(
367 cr, uid, transaction, log,
368 context=context)
369 return move_info
364370
365 def __init__(self, pool, cr):371 def __init__(self, pool, cr):
366 """372 """
@@ -369,14 +375,18 @@
369 """375 """
370 super(banking_import_transaction, self).__init__(pool, cr)376 super(banking_import_transaction, self).__init__(pool, cr)
371377
372 banking_import_transaction.confirm_map.update({378 self.confirm_map.update({
373 'storno': banking_import_transaction._confirm_storno,379 'storno': banking_import_transaction._confirm_storno,
374 'payment_order': banking_import_transaction._confirm_payment_order,380 'payment_order': banking_import_transaction._confirm_payment_order,
375 'payment': banking_import_transaction._confirm_payment,381 'payment': banking_import_transaction._confirm_payment,
382 'payment_order_manual': banking_import_transaction._confirm_payment_order,
383 'payment_manual': banking_import_transaction._confirm_payment,
376 })384 })
377385
378 banking_import_transaction.cancel_map.update({386 self.cancel_map.update({
379 'storno': banking_import_transaction._cancel_storno,387 'storno': banking_import_transaction._cancel_storno,
380 'payment_order': banking_import_transaction._cancel_payment_order,388 'payment_order': banking_import_transaction._cancel_payment_order,
381 'payment': banking_import_transaction._cancel_payment,389 'payment': banking_import_transaction._cancel_payment,
390 'payment_order_manual': banking_import_transaction._cancel_payment_order,
391 'payment_manual': banking_import_transaction._cancel_payment,
382 })392 })
383393
=== modified file 'account_banking_payment/model/banking_transaction_wizard.py'
--- account_banking_payment/model/banking_transaction_wizard.py 2013-03-17 09:10:15 +0000
+++ account_banking_payment/model/banking_transaction_wizard.py 2013-06-26 21:16:23 +0000
@@ -24,10 +24,59 @@
24##############################################################################24##############################################################################
2525
26from openerp.osv import orm, fields26from openerp.osv import orm, fields
27from openerp.tools.translate import _
2728
2829
29class banking_transaction_wizard(orm.TransientModel):30class banking_transaction_wizard(orm.TransientModel):
30 _inherit = 'banking.transaction.wizard'31 _inherit = 'banking.transaction.wizard'
32
33 def write(self, cr, uid, ids, vals, context=None):
34 """
35 Check for manual payment orders or lines
36 """
37 if not vals or not ids:
38 return True
39 manual_payment_order_id = vals.pop('manual_payment_order_id', False)
40 manual_payment_line_id = vals.pop('manual_payment_line_id', False)
41 res = super(banking_transaction_wizard, self).write(
42 cr, uid, ids, vals, context=context)
43 if manual_payment_order_id or manual_payment_line_id:
44 transaction_id = self.browse(
45 cr, uid, ids[0],
46 context=context).import_transaction_id
47 write_vals = {}
48 if manual_payment_order_id:
49 payment_order = self.pool.get('payment.order').browse(
50 cr, uid, manual_payment_order_id,
51 context=context)
52 if payment_order.payment_order_type == 'payment':
53 sign = 1
54 else:
55 sign = -1
56 total = (payment_order.total + sign *
57 transaction_id.statement_line_id.amount)
58 if not self.pool.get('res.currency').is_zero(
59 cr, uid, transaction_id.statement_line_id.statement_id.currency, total):
60 raise orm.except_orm(
61 _('Error'),
62 _('When matching a payment order, the amounts have to '
63 'match exactly'))
64
65 if payment_order.mode and payment_order.mode.transfer_account_id:
66 transaction_id.statement_line_id.write({
67 'account_id': payment_order.mode.transfer_account_id.id,
68 })
69 write_vals.update(
70 {'payment_order_id': manual_payment_order_id,
71 'match_type': 'payment_order_manual'})
72 else:
73 write_vals.update(
74 {'payment_line_id': manual_payment_line_id,
75 'match_type': 'payment_manual'})
76 self.pool.get('banking.import.transaction').clear_and_write(
77 cr, uid, transaction_id.id, write_vals, context=context)
78 return res
79
31 _columns = {80 _columns = {
32 'payment_line_id': fields.related(81 'payment_line_id': fields.related(
33 'import_transaction_id', 'payment_line_id',82 'import_transaction_id', 'payment_line_id',
@@ -42,4 +91,13 @@
42 'import_transaction_id', 'payment_order_id',91 'import_transaction_id', 'payment_order_id',
43 string="Payment order to reconcile", 92 string="Payment order to reconcile",
44 type='many2one', relation='payment.order'),93 type='many2one', relation='payment.order'),
94 'manual_payment_order_id': fields.many2one(
95 'payment.order', 'Match this payment order',
96 domain=[('state', '=', 'sent')]),
97 'manual_payment_line_id': fields.many2one(
98 'payment.line', 'Match this payment line',
99 domain=[
100 ('order_id.state', '=', 'sent'),
101 ('date_done', '=', False),
102 ]),
45 }103 }
46104
=== modified file 'account_banking_payment/model/payment_line.py'
--- account_banking_payment/model/payment_line.py 2013-03-17 09:10:15 +0000
+++ account_banking_payment/model/payment_line.py 2013-06-26 21:16:23 +0000
@@ -24,11 +24,12 @@
24##############################################################################24##############################################################################
2525
26from openerp.osv import orm, fields26from openerp.osv import orm, fields
2727from openerp import netsvc
28from openerp.tools.translate import _
2829
29class payment_line(orm.Model):30class payment_line(orm.Model):
30 '''31 '''
31 Add extra export_state and date_done fields; make destination bank account32 Add some fields; make destination bank account
32 mandatory, as it makes no sense to send payments into thin air.33 mandatory, as it makes no sense to send payments into thin air.
33 Edit: Payments can be by cash too, which is prohibited by mandatory bank34 Edit: Payments can be by cash too, which is prohibited by mandatory bank
34 accounts.35 accounts.
@@ -36,146 +37,34 @@
36 _inherit = 'payment.line'37 _inherit = 'payment.line'
37 _columns = {38 _columns = {
38 # New fields39 # New fields
39 'export_state': fields.selection([
40 ('draft', 'Draft'),
41 ('open','Confirmed'),
42 ('cancel','Cancelled'),
43 ('sent', 'Sent'),
44 ('rejected', 'Rejected'),
45 ('done','Done'),
46 ], 'State', select=True
47 ),
48 'msg': fields.char('Message', size=255, required=False, readonly=True),40 'msg': fields.char('Message', size=255, required=False, readonly=True),
4941 'date_done': fields.date(
50 # Redefined fields: added states42 'Date Confirmed', select=True, readonly=True),
51 'date_done': fields.datetime('Date Confirmed', select=True,43 # Communication: required is dependend on the mode
52 readonly=True),
53 'name': fields.char(
54 'Your Reference', size=64, required=True,
55 states={
56 'sent': [('readonly', True)],
57 'rejected': [('readonly', True)],
58 'done': [('readonly', True)]
59 },
60 ),
61 'communication': fields.char(44 'communication': fields.char(
62 'Communication', size=64, required=False, 45 'Communication', size=64, required=False,
63 help=("Used as the message between ordering customer and current "46 help=("Used as the message between ordering customer and current "
64 "company. Depicts 'What do you want to say to the recipient"47 "company. Depicts 'What do you want to say to the recipient"
65 " about this order ?'"48 " about this order ?'"
66 ),49 ),
67 states={
68 'sent': [('readonly', True)],
69 'rejected': [('readonly', True)],
70 'done': [('readonly', True)]
71 },
72 ),50 ),
51 # Communication2: enlarge to 128
73 'communication2': fields.char(52 'communication2': fields.char(
74 'Communication 2', size=128,53 'Communication 2', size=128,
75 help='The successor message of Communication.',54 help='The successor message of Communication.',
76 states={55 ),
77 'sent': [('readonly', True)],56 'transit_move_line_id': fields.many2one(
78 'rejected': [('readonly', True)],57 # this line is part of the credit side of move 2a
79 'done': [('readonly', True)]58 # from the documentation
80 },59 'account.move.line', 'Debit move line',
81 ),60 readonly=True,
82 'move_line_id': fields.many2one(61 help="Move line through which the debit order pays the invoice",
83 'account.move.line', 'Entry line',62 ),
84 domain=[('reconcile_id','=', False),63 }
85 ('account_id.type', '=','payable')64
86 ],
87 help=('This Entry Line will be referred for the information of '
88 'the ordering customer.'
89 ),
90 states={
91 'sent': [('readonly', True)],
92 'rejected': [('readonly', True)],
93 'done': [('readonly', True)]
94 },
95 ),
96 'amount_currency': fields.float(
97 'Amount in Partner Currency', digits=(16,2),
98 required=True,
99 help='Payment amount in the partner currency',
100 states={
101 'sent': [('readonly', True)],
102 'rejected': [('readonly', True)],
103 'done': [('readonly', True)]
104 },
105 ),
106 'currency': fields.many2one(
107 'res.currency', 'Partner Currency', required=True,
108 states={
109 'sent': [('readonly', True)],
110 'rejected': [('readonly', True)],
111 'done': [('readonly', True)]
112 },
113 ),
114 'bank_id': fields.many2one(
115 'res.partner.bank', 'Destination Bank account',
116 states={
117 'sent': [('readonly', True)],
118 'rejected': [('readonly', True)],
119 'done': [('readonly', True)]
120 },
121 ),
122 'order_id': fields.many2one(
123 'payment.order', 'Order', required=True,
124 ondelete='cascade', select=True,
125 states={
126 'sent': [('readonly', True)],
127 'rejected': [('readonly', True)],
128 'done': [('readonly', True)]
129 },
130 ),
131 'partner_id': fields.many2one(
132 'res.partner', string="Partner", required=True,
133 help='The Ordering Customer',
134 states={
135 'sent': [('readonly', True)],
136 'rejected': [('readonly', True)],
137 'done': [('readonly', True)]
138 },
139 ),
140 'date': fields.date(
141 'Payment Date',
142 help=("If no payment date is specified, the bank will treat this "
143 "payment line directly"
144 ),
145 states={
146 'sent': [('readonly', True)],
147 'rejected': [('readonly', True)],
148 'done': [('readonly', True)]
149 },
150 ),
151 'state': fields.selection([
152 ('normal','Free'),
153 ('structured','Structured')
154 ], 'Communication Type', required=True,
155 states={
156 'sent': [('readonly', True)],
157 'rejected': [('readonly', True)],
158 'done': [('readonly', True)]
159 },
160 ),
161 }
162 _defaults = {65 _defaults = {
163 'export_state': 'draft',
164 'date_done': False,
165 'msg': '',66 'msg': '',
166 }67 }
167
168 def fields_get(self, cr, uid, fields=None, context=None):
169 res = super(payment_line, self).fields_get(cr, uid, fields, context)
170 if 'communication' in res:
171 res['communication'].setdefault('states', {})
172 res['communication']['states']['structured'] = [('required', True)]
173 if 'communication2' in res:
174 res['communication2'].setdefault('states', {})
175 res['communication2']['states']['structured'] = [('readonly', True)]
176 res['communication2']['states']['normal'] = [('readonly', False)]
177
178 return res
17968
180 """69 """
181 Hooks for processing direct debit orders, such as implemented in70 Hooks for processing direct debit orders, such as implemented in
@@ -216,3 +105,76 @@
216 """105 """
217106
218 return False107 return False
108
109 def debit_reconcile(self, cr, uid, payment_line_id, context=None):
110 """
111 Reconcile a debit order's payment line with the the move line
112 that it is based on. Called from payment_order.action_sent().
113 As the amount is derived directly from the counterpart move line,
114 we do not expect a write off. Take partially reconcilions into
115 account though.
116
117 :param payment_line_id: the single id of the canceled payment line
118 """
119
120 if isinstance(payment_line_id, (list, tuple)):
121 payment_line_id = payment_line_id[0]
122 reconcile_obj = self.pool.get('account.move.reconcile')
123 move_line_obj = self.pool.get('account.move.line')
124 payment_line = self.browse(cr, uid, payment_line_id, context=context)
125
126 transit_move_line = payment_line.transit_move_line_id
127 torec_move_line = payment_line.move_line_id
128
129 if (not transit_move_line or not torec_move_line):
130 raise orm.except_orm(
131 _('Can not reconcile'),
132 _('No move line for line %s') % payment_line.name)
133 if torec_move_line.reconcile_id: # torec_move_line.reconcile_partial_id:
134 raise orm.except_orm(
135 _('Error'),
136 _('Move line %s has already been reconciled') %
137 torec_move_line.name
138 )
139 if transit_move_line.reconcile_id or transit_move_line.reconcile_partial_id:
140 raise orm.except_orm(
141 _('Error'),
142 _('Move line %s has already been reconciled') %
143 transit_move_line.name
144 )
145
146 def is_zero(total):
147 return self.pool.get('res.currency').is_zero(
148 cr, uid, transit_move_line.company_id.currency_id, total)
149
150 line_ids = [transit_move_line.id, torec_move_line.id]
151 if torec_move_line.reconcile_partial_id:
152 line_ids = [
153 x.id for x in
154 transit_move_line.reconcile_partial_id.line_partial_ids
155 ] + [torec_move_line.id]
156
157 total = move_line_obj.get_balance(cr, uid, line_ids)
158 vals = {
159 'type': 'auto',
160 'line_id': is_zero(total) and [(6, 0, line_ids)] or [(6, 0, [])],
161 'line_partial_ids': is_zero(total) and [(6, 0, [])] or [(6, 0, line_ids)],
162 }
163
164 if torec_move_line.reconcile_partial_id:
165 reconcile_obj.write(
166 cr, uid, transit_move_line.reconcile_partial_id.id,
167 vals, context=context)
168 else:
169 reconcile_obj.create(
170 cr, uid, vals, context=context)
171 for line_id in line_ids:
172 netsvc.LocalService("workflow").trg_trigger(
173 uid, 'account.move.line', line_id, cr)
174
175 # If a bank transaction of a storno was first confirmed
176 # and now canceled (the invoice is now in state 'debit_denied'
177 if torec_move_line.invoice:
178 netsvc.LocalService("workflow").trg_validate(
179 uid, 'account.invoice', torec_move_line.invoice.id,
180 'undo_debit_denied', cr)
219181
=== modified file 'account_banking_payment/model/payment_mode.py'
--- account_banking_payment/model/payment_mode.py 2013-03-17 09:10:15 +0000
+++ account_banking_payment/model/payment_mode.py 2013-06-26 21:16:23 +0000
@@ -46,6 +46,27 @@
46 _columns = {46 _columns = {
47 'type': fields.many2one(47 'type': fields.many2one(
48 'payment.mode.type', 'Payment type',48 'payment.mode.type', 'Payment type',
49 required=True,
49 help='Select the Payment Type for the Payment Mode.'50 help='Select the Payment Type for the Payment Mode.'
50 ),51 ),
52 'transfer_account_id': fields.many2one(
53 'account.account', 'Transfer account',
54 domain=[('type', '=', 'other'),
55 ('reconcile', '=', True)],
56 help=('Pay off lines in sent orders with a '
57 'move on this account. For debit type modes only. '
58 'You can only select accounts of type regular that '
59 'are marked for reconciliation'),
60 ),
61 'transfer_journal_id': fields.many2one(
62 'account.journal', 'Transfer journal',
63 help=('Journal to write payment entries when confirming '
64 'a debit order of this mode'),
65 ),
66 'payment_term_ids': fields.many2many(
67 'account.payment.term', 'account_payment_order_terms_rel',
68 'mode_id', 'term_id', 'Payment terms',
69 help=('Limit selected invoices to invoices with these payment '
70 'terms')
71 ),
51 }72 }
5273
=== modified file 'account_banking_payment/model/payment_order_create.py'
--- account_banking_payment/model/payment_order_create.py 2013-06-04 21:19:18 +0000
+++ account_banking_payment/model/payment_order_create.py 2013-06-26 21:16:23 +0000
@@ -26,11 +26,77 @@
26from datetime import datetime26from datetime import datetime
27from openerp.osv import orm, fields27from openerp.osv import orm, fields
28from openerp.tools import DEFAULT_SERVER_DATE_FORMAT28from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
29from openerp.tools.translate import _
2930
3031
31class payment_order_create(orm.TransientModel):32class payment_order_create(orm.TransientModel):
32 _inherit = 'payment.order.create'33 _inherit = 'payment.order.create'
3334
35 def extend_payment_order_domain(
36 self, cr, uid, payment_order, domain, context=None):
37 if payment_order.payment_order_type == 'payment':
38 domain += [
39 ('account_id.type', '=', 'payable'),
40 ('amount_to_pay', '>', 0)
41 ]
42 return True
43
44 def search_entries(self, cr, uid, ids, context=None):
45 """
46 This method taken from account_payment module.
47 We adapt the domain based on the payment_order_type
48 """
49 line_obj = self.pool.get('account.move.line')
50 mod_obj = self.pool.get('ir.model.data')
51 if context is None:
52 context = {}
53 data = self.read(cr, uid, ids, ['duedate'], context=context)[0]
54 search_due_date = data['duedate']
55
56 ### start account_banking_payment ###
57 payment = self.pool.get('payment.order').browse(
58 cr, uid, context['active_id'], context=context)
59 # Search for move line to pay:
60 domain = [
61 ('move_id.state', '=', 'posted'),
62 ('reconcile_id', '=', False),
63 ('company_id', '=', payment.mode.company_id.id),
64 ]
65 # apply payment term filter
66 if payment.mode.payment_term_ids:
67 domain += [
68 ('invoice.payment_term', 'in',
69 [term.id for term in payment.mode.payment_term_ids]
70 )
71 ]
72 self.extend_payment_order_domain(
73 cr, uid, payment, domain, context=context)
74 ### end account_direct_debit ###
75
76 domain = domain + [
77 '|', ('date_maturity', '<=', search_due_date),
78 ('date_maturity', '=', False)
79 ]
80 line_ids = line_obj.search(cr, uid, domain, context=context)
81 context.update({'line_ids': line_ids})
82 model_data_ids = mod_obj.search(
83 cr, uid,[
84 ('model', '=', 'ir.ui.view'),
85 ('name', '=', 'view_create_payment_order_lines')],
86 context=context)
87 resource_id = mod_obj.read(
88 cr, uid, model_data_ids, fields=['res_id'],
89 context=context)[0]['res_id']
90 return {'name': _('Entry Lines'),
91 'context': context,
92 'view_type': 'form',
93 'view_mode': 'form',
94 'res_model': 'payment.order.create',
95 'views': [(resource_id, 'form')],
96 'type': 'ir.actions.act_window',
97 'target': 'new',
98 }
99
34 def create_payment(self, cr, uid, ids, context=None):100 def create_payment(self, cr, uid, ids, context=None):
35 '''101 '''
36 This method is a slightly modified version of the existing method on this102 This method is a slightly modified version of the existing method on this
@@ -51,7 +117,8 @@
51 if not line_ids:117 if not line_ids:
52 return {'type': 'ir.actions.act_window_close'}118 return {'type': 'ir.actions.act_window_close'}
53119
54 payment = order_obj.browse(cr, uid, context['active_id'], context=context)120 payment = order_obj.browse(
121 cr, uid, context['active_id'], context=context)
55 ### account banking122 ### account banking
56 # t = None123 # t = None
57 # line2bank = line_obj.line2bank(cr, uid, line_ids, t, context)124 # line2bank = line_obj.line2bank(cr, uid, line_ids, t, context)
@@ -75,10 +142,10 @@
75 ### end account banking142 ### end account banking
76 elif payment.date_prefered == 'fixed':143 elif payment.date_prefered == 'fixed':
77 ### account_banking144 ### account_banking
78 # date_to_pay = payment.date_planned145 # date_to_pay = payment.date_scheduled
79 date_to_pay = (146 date_to_pay = (
80 payment.date_planned147 payment.date_scheduled
81 if payment.date_planned and payment.date_planned > _today148 if payment.date_scheduled and payment.date_scheduled > _today
82 else False)149 else False)
83 ### end account banking150 ### end account banking
84151
@@ -125,6 +192,8 @@
125 'state': state,192 'state': state,
126 ### end account banking193 ### end account banking
127 'date': date_to_pay,194 'date': date_to_pay,
128 'currency': line.invoice and line.invoice.currency_id.id or line.journal_id.currency.id or line.journal_id.company_id.currency_id.id,195 'currency': (line.invoice and line.invoice.currency_id.id
196 or line.journal_id.currency.id
197 or line.journal_id.company_id.currency_id.id),
129 }, context=context)198 }, context=context)
130 return {'type': 'ir.actions.act_window_close'}199 return {'type': 'ir.actions.act_window_close'}
131200
=== modified file 'account_banking_payment/view/account_payment.xml'
--- account_banking_payment/view/account_payment.xml 2013-05-01 14:40:54 +0000
+++ account_banking_payment/view/account_payment.xml 2013-06-26 21:16:23 +0000
@@ -9,33 +9,28 @@
9 <field name="name">account.payment.order.form.banking-1</field>9 <field name="name">account.payment.order.form.banking-1</field>
10 <field name="inherit_id" ref="account_payment.view_payment_order_form" />10 <field name="inherit_id" ref="account_payment.view_payment_order_form" />
11 <field name="model">payment.order</field>11 <field name="model">payment.order</field>
12 <field name="type">form</field>
13 <field name="arch" type="xml">12 <field name="arch" type="xml">
14 <data>13 <data>
15 <xpath expr="/form/group/button[@string='Select Invoices to Pay']"14 <xpath expr="//button[@string='Select Invoices to Pay']"
16 position="attributes">15 position="attributes">
17 <attribute name="attrs">{'invisible':[('state','!=','draft')]}</attribute>16 <attribute name="attrs">{
18 </xpath>17 'invisible':[('state','!=','draft')]
19 <xpath expr="/form/group/button[@string='Make Payments']"18 }</attribute>
20 position="replace">19 </xpath>
21 <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>20 <xpath expr="//button[@string='Make Payments']"
22 <newline/>21 position="attributes">
22 <attribute name="name">launch_wizard</attribute>
23 </xpath>
24 <!-- Communication only used for 'structured' communication -->
25 <xpath expr="//field[@name='line_ids']/form//field[@name='communication']"
26 position="attributes">
27 <attribute name="attrs">{
28 'readonly': [('state', '=', 'normal')]
29 }</attribute>
23 </xpath>30 </xpath>
24 </data>31 </data>
25 </field>32 </field>
26 </record>33 </record>
2734
28 <record id="view_banking_payment_order_tree_1" model="ir.ui.view">
29 <field name="name">account.payment.order.tree.banking-1</field>
30 <field name="inherit_id" ref="account_payment.view_payment_order_tree" />
31 <field name="model">payment.order</field>
32 <field name="type">tree</field>
33 <field name="arch" type="xml">
34 <button string="Make Payments" position="replace">
35 <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
36 </button>
37 </field>
38 </record>
39
40 </data>35 </data>
41</openerp>36</openerp>
4237
=== modified file 'account_banking_payment/view/bank_payment_manual.xml'
--- account_banking_payment/view/bank_payment_manual.xml 2013-03-17 20:04:17 +0000
+++ account_banking_payment/view/bank_payment_manual.xml 2013-06-26 21:16:23 +0000
@@ -4,9 +4,8 @@
4 <record id="view_payment_manual_form" model="ir.ui.view">4 <record id="view_payment_manual_form" model="ir.ui.view">
5 <field name="name">Form for manual payment wizard</field>5 <field name="name">Form for manual payment wizard</field>
6 <field name="model">payment.manual</field>6 <field name="model">payment.manual</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">7 <field name="arch" type="xml">
9 <form>8 <form string="Manual payment">
10 <label string="Payment order(s) have been set to 'sent'"/>9 <label string="Payment order(s) have been set to 'sent'"/>
11 <button special="cancel" icon="gtk-ok" string="OK"/>10 <button special="cancel" icon="gtk-ok" string="OK"/>
12 </form>11 </form>
1312
=== modified file 'account_banking_payment/view/banking_transaction_wizard.xml'
--- account_banking_payment/view/banking_transaction_wizard.xml 2013-03-17 20:04:17 +0000
+++ account_banking_payment/view/banking_transaction_wizard.xml 2013-06-26 21:16:23 +0000
@@ -6,7 +6,6 @@
6 <field name="model">banking.transaction.wizard</field>6 <field name="model">banking.transaction.wizard</field>
7 <field name="inherit_id"7 <field name="inherit_id"
8 ref="account_banking.transaction_wizard_first" />8 ref="account_banking.transaction_wizard_first" />
9 <field name="type">form</field>
10 <field name="arch" type="xml">9 <field name="arch" type="xml">
11 <field name="invoice_ids" position="before">10 <field name="invoice_ids" position="before">
12 <field name="payment_order_ids" invisible="True"/>11 <field name="payment_order_ids" invisible="True"/>
@@ -14,20 +13,23 @@
14 <xpath expr="//group/separator[@string='Multiple matches']/.."13 <xpath expr="//group/separator[@string='Multiple matches']/.."
15 position="after">14 position="after">
16 <field name='payment_line_id'15 <field name='payment_line_id'
17 attrs="{'invisible': [16 attrs="{'invisible': [('match_type', 'not in',
18 ('match_type', '!=', 'storno'),17 ('storno', 'payment', 'payment_manual'))]}"
19 ('match_type', '!=', 'payment')]18 />
20 }" />
21 </xpath>19 </xpath>
22 <field name="move_line_id" position="after">20 <field name="move_line_id" position="after">
23 <field name='payment_order_id'21 <field name='payment_order_id'
24 attrs="{'readonly': [22 attrs="{'readonly': [('match_multi', '=', False)],
25 ('match_multi', '=', False)],23 'invisible': [('match_type', 'not in',
26 'invisible': [24 ('payment_order', 'payment_order_manual'))]
27 ('match_type', '!=', 'payment_order')]}"25 }"
28 domain="[('id', 'in', payment_order_ids[0][2])]"26 domain="[('id', 'in', payment_order_ids[0][2])]"
29 />27 />
30 </field>28 </field>
29 <field name="manual_move_line_id" position="after">
30 <field name="manual_payment_line_id"/>
31 <field name="manual_payment_order_id"/>
32 </field>
31 </field>33 </field>
32 </record>34 </record>
33 </data>35 </data>
3436
=== added file 'account_banking_payment/view/payment_mode.xml'
--- account_banking_payment/view/payment_mode.xml 1970-01-01 00:00:00 +0000
+++ account_banking_payment/view/payment_mode.xml 2013-06-26 21:16:23 +0000
@@ -0,0 +1,43 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <!--
6 Add the payment mode type and transfer settings
7 -->
8 <record id="view_payment_mode_form_inherit" model="ir.ui.view">
9 <field name="name">payment.mode.form.inherit</field>
10 <field name="model">payment.mode</field>
11 <field name="inherit_id" ref="account_payment.view_payment_mode_form"/>
12 <field name="arch" type="xml">
13 <field name="company_id" position="after">
14 <field name="type"/>
15 <group colspan="4" col="4">
16 <group colspan="2">
17 <separator colspan="2"
18 string="Transfer move settings" />
19 <field name="transfer_account_id"
20 domain="[('type', '=', 'other'),
21 ('reconcile', '=', True),
22 ('company_id', '=', company_id)]"
23 context="{
24 'default_type': 'other',
25 'default_reconcile': True,
26 'default_company_id': company_id}"
27 />
28 <field name="transfer_journal_id"
29 domain="[('company_id', '=', company_id)]"
30 />
31 </group>
32 <group colspan="2">
33 <separator colspan="2"
34 string="Optional filter by payment term" />
35 <field name="payment_term_ids" nolabel="1" colspan="2"/>
36 </group>
37 </group>
38 </field>
39 </field>
40 </record>
41
42 </data>
43</openerp>
044
=== modified file 'account_banking_payment/view/payment_mode_type.xml'
--- account_banking_payment/view/payment_mode_type.xml 2013-03-16 16:44:19 +0000
+++ account_banking_payment/view/payment_mode_type.xml 2013-06-26 21:16:23 +0000
@@ -2,24 +2,10 @@
2<openerp>2<openerp>
3 <data>3 <data>
44
5 <!-- Add the payment mode type to the payment mode views -->
6 <record id="view_payment_mode_form_inherit" model="ir.ui.view">
7 <field name="name">payment.mode.form.inherit</field>
8 <field name="model">payment.mode</field>
9 <field name="inherit_id" ref="account_payment.view_payment_mode_form"/>
10 <field name="type">form</field>
11 <field name="arch" type="xml">
12 <field name="company_id" position="after">
13 <field name="type"/>
14 </field>
15 </field>
16 </record>
17
18 <record id="view_payment_mode_tree_inherit" model="ir.ui.view">5 <record id="view_payment_mode_tree_inherit" model="ir.ui.view">
19 <field name="name">payment.mode.tree.inherit</field>6 <field name="name">payment.mode.tree.inherit</field>
20 <field name="model">payment.mode</field>7 <field name="model">payment.mode</field>
21 <field name="inherit_id" ref="account_payment.view_payment_mode_tree"/>8 <field name="inherit_id" ref="account_payment.view_payment_mode_tree"/>
22 <field name="type">tree</field>
23 <field name="arch" type="xml">9 <field name="arch" type="xml">
24 <field name="company_id" position="after">10 <field name="company_id" position="after">
25 <field name="type"/>11 <field name="type"/>
@@ -31,9 +17,8 @@
31 <record model="ir.ui.view" id="view_payment_mode_type_form">17 <record model="ir.ui.view" id="view_payment_mode_type_form">
32 <field name="name">view.payment.mode.type.form</field>18 <field name="name">view.payment.mode.type.form</field>
33 <field name="model">payment.mode.type</field>19 <field name="model">payment.mode.type</field>
34 <field name="type">form</field>
35 <field name="arch" type="xml">20 <field name="arch" type="xml">
36 <form>21 <form string="Payment mode">
37 <field name="name" />22 <field name="name" />
38 <field name="code" />23 <field name="code" />
39 <field name="suitable_bank_types"/>24 <field name="suitable_bank_types"/>
4025
=== modified file 'account_banking_payment/workflow/account_payment.xml'
--- account_banking_payment/workflow/account_payment.xml 2013-03-16 16:44:19 +0000
+++ account_banking_payment/workflow/account_payment.xml 2013-06-26 21:16:23 +0000
@@ -8,6 +8,13 @@
8 <field name="action">action_sent()</field>8 <field name="action">action_sent()</field>
9 <field name="kind">function</field>9 <field name="kind">function</field>
10 </record>10 </record>
11 <!-- New activity for workflow payment order: sent -->
12 <record id="account_banking.act_sent_wait" model="workflow.activity">
13 <field name="name">sent_wait</field>
14 <field name="wkf_id" ref="account_payment.wkf_payment_order"/>
15 <field name="action">write({'state': 'sent'})</field>
16 <field name="kind">function</field>
17 </record>
11 <!-- New activity for workflow payment order: rejected -->18 <!-- New activity for workflow payment order: rejected -->
12 <record id="account_banking.act_rejected" model="workflow.activity">19 <record id="account_banking.act_rejected" model="workflow.activity">
13 <field name="name">rejected</field>20 <field name="name">rejected</field>
@@ -16,23 +23,47 @@
16write({'state':'rejected'})</field>23write({'state':'rejected'})</field>
17 <field name="kind">function</field>24 <field name="kind">function</field>
18 </record>25 </record>
19 <!-- Add new transition sent -> done -->26 <!-- Rewrite existing open -> done transition to include 'sent' stage -->
27 <record id="account_payment.trans_open_done" model="workflow.transition">
28 <field name="act_from" ref="account_payment.act_open"/>
29 <field name="act_to" ref="account_banking.act_sent"/>
30 <field name="signal">sent</field>
31 </record>
32 <!-- From sent straight to sent_wait -->
33 <record id="account_banking.trans_sent_sent_wait" model="workflow.transition">
34 <field name="act_from" ref="account_banking.act_sent"/>
35 <field name="act_to" ref="account_banking.act_sent_wait"/>
36 </record>
37 <!-- Reconciliation from the banking statement leads to done state -->
20 <record id="account_banking.trans_sent_done" model="workflow.transition">38 <record id="account_banking.trans_sent_done" model="workflow.transition">
21 <field name="act_from" ref="account_banking.act_sent"/>39 <field name="act_from" ref="account_banking.act_sent_wait"/>
22 <field name="act_to" ref="account_payment.act_done"/>40 <field name="act_to" ref="account_payment.act_done"/>
23 <field name="signal">done</field>41 <field name="signal">done</field>
24 </record>42 </record>
25 <!-- Add new transition sent -> rejected -->43 <!-- Rejected by the bank -->
26 <record id="account_banking.trans_sent_rejected" model="workflow.transition">44 <record id="account_banking.trans_sent_rejected" model="workflow.transition">
27 <field name="act_from" ref="account_banking.act_sent"/>45 <field name="act_from" ref="account_banking.act_sent"/>
28 <field name="act_to" ref="account_banking.act_rejected"/>46 <field name="act_to" ref="account_banking.act_rejected"/>
29 <field name="signal">rejected</field>47 <field name="signal">rejected</field>
30 </record>48 </record>
31 <!-- Rewrite existing open -> done transition to include 'sent' -->49 <!--
32 <record id="account_payment.trans_open_done" model="workflow.transition">50 Transition to undo the payment order and reset to
33 <field name="act_from" ref="account_payment.act_open"/>51 sent, triggered by cancelling a bank transaction
34 <field name="act_to" ref="account_banking.act_sent"/>52 with which the order was reconciled.
35 <field name="signal">sent</field>53 For this, we need to cancel the flow stop on the done state,
36 </record>54 unfortunately.
55 -->
56 <record id="account_payment.act_done" model="workflow.activity">
57 <field name="flow_stop" eval="False"/>
58 </record>
59
60 <!-- Cancel the reconciled payment order -->
61 <record id="trans_done_sent" model="workflow.transition">
62 <field name="act_from" ref="account_payment.act_done"/>
63 <field name="act_to" ref="account_banking.act_sent_wait"/>
64 <field name="condition">test_undo_done()</field>
65 <field name="signal">undo_done</field>
66 </record>
67
37 </data>68 </data>
38</openerp>69</openerp>
3970
=== modified file 'account_banking_uk_hsbc/__openerp__.py'
--- account_banking_uk_hsbc/__openerp__.py 2013-04-15 14:14:27 +0000
+++ account_banking_uk_hsbc/__openerp__.py 2013-06-26 21:16:23 +0000
@@ -25,7 +25,7 @@
25 'author': 'credativ Ltd',25 'author': 'credativ Ltd',
26 'website': 'http://www.credativ.co.uk',26 'website': 'http://www.credativ.co.uk',
27 'category': 'Account Banking',27 'category': 'Account Banking',
28 'depends': ['account_banking'],28 'depends': ['account_banking_payment'],
29 'data': [29 'data': [
30 'account_banking_uk_hsbc.xml',30 'account_banking_uk_hsbc.xml',
31 'hsbc_clientid_view.xml',31 'hsbc_clientid_view.xml',
3232
=== modified file 'account_direct_debit/__openerp__.py'
--- account_direct_debit/__openerp__.py 2013-04-15 14:14:27 +0000
+++ account_direct_debit/__openerp__.py 2013-06-26 21:16:23 +0000
@@ -1,6 +1,6 @@
1##############################################################################1##############################################################################
2#2#
3# Copyright (C) 2011 Therp BV (<http://therp.nl>).3# Copyright (C) 2011 - 2013 Therp BV (<http://therp.nl>).
4# Copyright (C) 2011 Smile (<http://smile.fr>).4# Copyright (C) 2011 Smile (<http://smile.fr>).
5# All Rights Reserved5# All Rights Reserved
6#6#
@@ -20,9 +20,9 @@
20##############################################################################20##############################################################################
21{21{
22 'name': 'Direct Debit',22 'name': 'Direct Debit',
23 'version': '6.1.1.134',23 'version': '7.0.2.134',
24 'license': 'AGPL-3',24 'license': 'AGPL-3',
25 'author': 'Therp BV / Smile',25 'author': ['Therp BV', 'Smile'],
26 'website': 'https://launchpad.net/banking-addons',26 'website': 'https://launchpad.net/banking-addons',
27 'category': 'Banking addons',27 'category': 'Banking addons',
28 'depends': ['account_banking'],28 'depends': ['account_banking'],
@@ -30,7 +30,6 @@
30 'view/account_payment.xml',30 'view/account_payment.xml',
31 'view/account_invoice.xml',31 'view/account_invoice.xml',
32 'workflow/account_invoice.xml',32 'workflow/account_invoice.xml',
33 'workflow/account_payment.xml',
34 'data/account_payment_term.xml',33 'data/account_payment_term.xml',
35 ],34 ],
36 'description': '''35 'description': '''
@@ -49,5 +48,5 @@
49banking institutions. The banking addons are a continuation of Account Banking48banking institutions. The banking addons are a continuation of Account Banking
50Framework by Edusense BV. See https://launchpad.net/banking-addons.49Framework by Edusense BV. See https://launchpad.net/banking-addons.
51 ''',50 ''',
52 'installable': False,51 'installable': True,
53}52}
5453
=== modified file 'account_direct_debit/i18n/nl.po'
--- account_direct_debit/i18n/nl.po 2012-08-08 10:32:52 +0000
+++ account_direct_debit/i18n/nl.po 2013-06-26 21:16:23 +0000
@@ -175,7 +175,7 @@
175msgstr "De betaalregelnaam moet uniek zijn!"175msgstr "De betaalregelnaam moet uniek zijn!"
176176
177#. module: account_direct_debit177#. module: account_direct_debit
178#: field:payment.line,debit_move_line_id:0178#: field:payment.line,transit_move_line_id:0
179msgid "Debit move line"179msgid "Debit move line"
180msgstr "Debetboeking"180msgstr "Debetboeking"
181181
@@ -200,7 +200,7 @@
200msgstr "Factuur"200msgstr "Factuur"
201201
202#. module: account_direct_debit202#. module: account_direct_debit
203#: help:payment.line,debit_move_line_id:0203#: help:payment.line,transit_move_line_id:0
204msgid "Move line through which the debit order pays the invoice"204msgid "Move line through which the debit order pays the invoice"
205msgstr "Dagboekregel waarmee de incasso-opdracht de factuur voldoet"205msgstr "Dagboekregel waarmee de incasso-opdracht de factuur voldoet"
206206
207207
=== added directory 'account_direct_debit/migrations'
=== added directory 'account_direct_debit/migrations/7.0.2'
=== added file 'account_direct_debit/migrations/7.0.2/pre-migration.py'
--- account_direct_debit/migrations/7.0.2/pre-migration.py 1970-01-01 00:00:00 +0000
+++ account_direct_debit/migrations/7.0.2/pre-migration.py 2013-06-26 21:16:23 +0000
@@ -0,0 +1,57 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2013 Therp BV (<http://therp.nl>).
5#
6# All other contributions are (C) by their respective contributors
7#
8# All Rights Reserved
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU Affero General Public License as
12# published by the Free Software Foundation, either version 3 of the
13# License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU Affero General Public License for more details.
19#
20# You should have received a copy of the GNU Affero General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
23##############################################################################
24
25def rename_columns(cr, column_spec):
26 """
27 Rename table columns. Taken from OpenUpgrade.
28
29 :param column_spec: a hash with table keys, with lists of tuples as values. \
30 Tuples consist of (old_name, new_name).
31
32 """
33 for table in column_spec.keys():
34 for (old, new) in column_spec[table]:
35 logger.info("table %s, column %s: renaming to %s",
36 table, old, new)
37 cr.execute('ALTER TABLE "%s" RENAME "%s" TO "%s"' % (table, old, new,))
38 cr.execute('DROP INDEX IF EXISTS "%s_%s_index"' % (table, old))
39
40def migrate(cr, version):
41 if not version:
42 return
43
44 # workflow state moved to another module
45 cr.execute(
46 """
47 UPDATE ir_model_data
48 SET module = 'account_banking_payment'
49 WHERE name = 'trans_done_sent'
50 AND module = 'account_direct_debit'
51 """)
52
53 # rename field debit_move_line_id
54 rename_columns(cr, {
55 'payment_line': [
56 ('debit_move_line_id', 'transit_move_line_id'),
57 ]})
058
=== modified file 'account_direct_debit/model/__init__.py'
--- account_direct_debit/model/__init__.py 2011-12-11 15:00:41 +0000
+++ account_direct_debit/model/__init__.py 2013-06-26 21:16:23 +0000
@@ -1,3 +1,5 @@
1import account_payment1import account_payment
2import payment_line
2import account_move_line3import account_move_line
3import account_invoice4import account_invoice
5import payment_order_create
46
=== modified file 'account_direct_debit/model/account_invoice.py'
--- account_direct_debit/model/account_invoice.py 2012-01-12 10:58:49 +0000
+++ account_direct_debit/model/account_invoice.py 2013-06-26 21:16:23 +0000
@@ -1,6 +1,29 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2from osv import osv, fields2##############################################################################
3from tools.translate import _3#
4# Copyright (C) 2011 - 2013 Therp BV (<http://therp.nl>).
5#
6# All other contributions are (C) by their respective contributors
7#
8# All Rights Reserved
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU Affero General Public License as
12# published by the Free Software Foundation, either version 3 of the
13# License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU Affero General Public License for more details.
19#
20# You should have received a copy of the GNU Affero General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
23##############################################################################
24
25from openerp.osv import orm, fields
26from openerp.tools.translate import _
427
5"""28"""
6This module adds support for Direct debit orders as applicable29This module adds support for Direct debit orders as applicable
@@ -98,7 +121,7 @@
98 open invoices with a matured invoice- or due date.121 open invoices with a matured invoice- or due date.
99""" 122"""
100123
101class account_invoice(osv.osv):124class account_invoice(orm.Model):
102 _inherit = "account.invoice"125 _inherit = "account.invoice"
103126
104 def __init__(self, pool, cr):127 def __init__(self, pool, cr):
@@ -139,5 +162,3 @@
139 if not invoice['reconciled']:162 if not invoice['reconciled']:
140 return False163 return False
141 return True164 return True
142
143account_invoice()
144165
=== modified file 'account_direct_debit/model/account_move_line.py'
--- account_direct_debit/model/account_move_line.py 2013-04-24 14:36:15 +0000
+++ account_direct_debit/model/account_move_line.py 2013-06-26 21:16:23 +0000
@@ -2,9 +2,8 @@
2##############################################################################2##############################################################################
3#3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).5# This module (C) 2011 - 2013 Therp BV (<http://therp.nl>).
6# This module additional (C) 2011 Therp BV (<http://therp.nl>).6# (C) 2011 Smile Benelux (<http://smile.fr>).
7# (C) 2011 Smile Benelux (<http://smile.fr>).
8#7#
9# This program is free software: you can redistribute it and/or modify8# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU Affero General Public License as9# it under the terms of the GNU Affero General Public License as
@@ -22,10 +21,9 @@
22##############################################################################21##############################################################################
2322
24from operator import itemgetter23from operator import itemgetter
25from osv import fields, osv24from openerp.osv import fields, orm
26from tools.translate import _
2725
28class account_move_line(osv.osv):26class account_move_line(orm.Model):
29 _inherit = "account.move.line"27 _inherit = "account.move.line"
3028
31 def amount_to_receive(self, cr, uid, ids, name, arg={}, context=None):29 def amount_to_receive(self, cr, uid, ids, name, arg={}, context=None):
@@ -55,6 +53,9 @@
55 return r53 return r
5654
57 def _to_receive_search(self, cr, uid, obj, name, args, context=None):55 def _to_receive_search(self, cr, uid, obj, name, args, context=None):
56 """
57 Reverse of account_payment/account_move_line.py:_to_pay_search()
58 """
58 if not args:59 if not args:
59 return []60 return []
60 line_obj = self.pool.get('account.move.line')61 line_obj = self.pool.get('account.move.line')
@@ -86,70 +87,9 @@
86 return [('id', '=', '0')]87 return [('id', '=', '0')]
87 return [('id', 'in', map(lambda x:x[0], res))]88 return [('id', 'in', map(lambda x:x[0], res))]
8889
89 def _dummy(self, cr, user, ids, name, arg, context=None):
90 res = {}
91 if ids:
92 res = dict([(x, False) for x in ids])
93 return res
94
95 def _invoice_payment_term_id_search(
96 self, cr, uid, obj, name, args, context=None):
97 """
98 Allow to search move lines associated with an invoice with
99 a particular payment term
100 """
101 if not args:
102 return []
103 invoice_obj = self.pool.get('account.invoice')
104 invoice_ids = invoice_obj.search(
105 cr, uid, [('payment_term', args[0][1], args[0][2])],
106 context=context)
107 operator = 'in' # (args[0][1] not in ['in', '=', '==', 'like', 'ilike']
108 # and 'not in' or 'in')
109 if not invoice_ids:
110 return [('id', operator, [])]
111 cr.execute('SELECT l.id ' \
112 'FROM account_move_line l, account_invoice i ' \
113 'WHERE l.move_id = i.move_id AND i.id in %s', (tuple(invoice_ids),))
114 res = cr.fetchall()
115 if not res:
116 return [('id', '=', False)]
117 return [('id', operator, [x[0] for x in res])]
118
119 def _invoice_state_search(self, cr, uid, obj, name, args, context=None):
120 if not args:
121 return []
122 invoice_obj = self.pool.get('account.invoice')
123 invoice_ids = invoice_obj.search(
124 cr, uid, [('state', args[0][1], args[0][2])],
125 context=context)
126 operator = 'in' # (args[0][1] not in ['in', '=', '==', 'like', 'ilike']
127 # and 'not in' or 'in')
128 if not invoice_ids:
129 return [('id', operator, [])]
130 cr.execute('SELECT l.id ' \
131 'FROM account_move_line l, account_invoice i ' \
132 'WHERE l.move_id = i.move_id AND i.id in %s', (tuple(invoice_ids),))
133 res = cr.fetchall()
134 if not res:
135 return [('id', '=', False)]
136 return [('id', operator, [x[0] for x in res])]
137
138 _columns = {90 _columns = {
139 'amount_to_receive': fields.function(91 'amount_to_receive': fields.function(
140 amount_to_receive, method=True,92 amount_to_receive, method=True,
141 type='float', string='Amount to receive',93 type='float', string='Amount to receive',
142 fnct_search=_to_receive_search),94 fnct_search=_to_receive_search),
143 'payment_term_id': fields.function(
144 _dummy, method=True,
145 string='Select by invoice payment term',
146 type='many2one', relation='account.payment.term',
147 fnct_search=_invoice_payment_term_id_search),
148 'invoice_state': fields.function(
149 _dummy, method=True,
150 string='Select by invoice state',
151 type='char', size=24,
152 fnct_search=_invoice_state_search),
153 }95 }
154
155account_move_line()
15696
=== modified file 'account_direct_debit/model/account_payment.py'
--- account_direct_debit/model/account_payment.py 2013-01-21 11:30:46 +0000
+++ account_direct_debit/model/account_payment.py 2013-06-26 21:16:23 +0000
@@ -1,36 +1,9 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2import time2from openerp.osv import orm, fields
3from osv import osv, fields
4import netsvc3import netsvc
5from tools.translate import _4from tools.translate import _
65
7class payment_mode(osv.osv):6class payment_order(orm.Model):
8 _inherit = 'payment.mode'
9 _columns = {
10 'transfer_account_id': fields.many2one(
11 'account.account', 'Transfer account',
12 domain=[('type', '=', 'other'),
13 ('reconcile', '=', True)],
14 help=('Pay off lines in sent orders with a ' +
15 'move on this account. For debit type modes only. ' +
16 'You can only select accounts of type regular that ' +
17 'are marked for reconciliation'),
18 ),
19 'transfer_journal_id': fields.many2one(
20 'account.journal', 'Transfer journal',
21 help=('Journal to write payment entries when confirming ' +
22 'a debit order of this mode'),
23 ),
24 'payment_term_ids': fields.many2many(
25 'account.payment.term', 'account_payment_order_terms_rel',
26 'mode_id', 'term_id', 'Payment terms',
27 help=('Limit selected invoices to invoices with these payment ' +
28 'terms')
29 ),
30 }
31payment_mode()
32
33class payment_order(osv.osv):
34 _inherit = 'payment.order'7 _inherit = 'payment.order'
358
36 def fields_view_get(self, cr, user, view_id=None, view_type='form',9 def fields_view_get(self, cr, user, view_id=None, view_type='form',
@@ -56,56 +29,11 @@
56 context['search_payment_order_type'])]29 context['search_payment_order_type'])]
57 # the magic is in the value of the selection30 # the magic is in the value of the selection
58 res['fields']['mode']['selection'] = mode_obj._name_search(31 res['fields']['mode']['selection'] = mode_obj._name_search(
59 cr, user, args=domain)32 cr, user, args=domain, context=context)
60 # also update the domain33 # also update the domain
61 res['fields']['mode']['domain'] = domain34 res['fields']['mode']['domain'] = domain
62 return res35 return res
6336
64 def debit_reconcile_transfer(self, cr, uid, payment_order_id,
65 amount, currency, context=None):
66 """
67 During import of bank statements, create the reconcile on the transfer
68 account containing all the open move lines on the transfer account.
69 """
70 move_line_obj = self.pool.get('account.move.line')
71 order = self.browse(cr, uid, payment_order_id, context)
72 line_ids = []
73 reconcile_id = False
74 for order_line in order.line_ids:
75 for line in order_line.debit_move_line_id.move_id.line_id:
76 if line.account_id.type == 'other' and not line.reconcile_id:
77 line_ids.append(line.id)
78 if self.pool.get('res.currency').is_zero(
79 cr, uid, currency,
80 move_line_obj.get_balance(cr, uid, line_ids) - amount):
81 reconcile_id = self.pool.get('account.move.reconcile').create(
82 cr, uid,
83 {'type': 'auto', 'line_id': [(6, 0, line_ids)]},
84 context)
85 # set direct debit order to finished state
86 wf_service = netsvc.LocalService('workflow')
87 wf_service.trg_validate(
88 uid, 'payment.order', payment_order_id, 'done', cr)
89 return reconcile_id
90
91 def debit_unreconcile_transfer(self, cr, uid, payment_order_id, reconcile_id,
92 amount, currency, context=None):
93 """
94 Due to a cancelled bank statements import, unreconcile the move on
95 the transfer account. Delegate the conditions to the workflow.
96 Raise on failure for rollback.
97 """
98 self.pool.get('account.move.reconcile').unlink(
99 cr, uid, reconcile_id, context=context)
100 wkf_ok = netsvc.LocalService('workflow').trg_validate(
101 uid, 'payment.order', payment_order_id, 'undo_done', cr)
102 if not wkf_ok:
103 raise osv.except_osv(
104 _("Cannot unreconcile"),
105 _("Cannot unreconcile debit order: "+
106 "Workflow will not allow it."))
107 return True
108
109 def test_undo_done(self, cr, uid, ids, context=None):37 def test_undo_done(self, cr, uid, ids, context=None):
110 """ 38 """
111 Called from the workflow. Used to unset done state on39 Called from the workflow. Used to unset done state on
@@ -117,362 +45,5 @@
117 for line in order.line_ids:45 for line in order.line_ids:
118 if line.storno:46 if line.storno:
119 return False47 return False
120 else:48 return super(payment_order, self).test_undo_done(
121 # TODO: define conditions for 'payment' orders49 cr, uid, ids, context=context)
122 return False
123 return True
124
125 def action_sent(self, cr, uid, ids, context=None):
126 """
127 Create the moves that pay off the move lines from
128 the debit order. This happens when the debit order file is
129 generated.
130 """
131 res = super(payment_order, self).action_sent(
132 cr, uid, ids, context)
133
134 account_move_obj = self.pool.get('account.move')
135 account_move_line_obj = self.pool.get('account.move.line')
136 payment_line_obj = self.pool.get('payment.line')
137 for order in self.browse(cr, uid, ids, context=context):
138 if order.payment_order_type != 'debit':
139 continue
140 for line in order.line_ids:
141 # basic checks
142 if not line.move_line_id:
143 raise osv.except_osv(
144 _('Error'),
145 _('No move line provided for line %s') % line.name)
146 if line.move_line_id.reconcile_id:
147 raise osv.except_osv(
148 _('Error'),
149 _('Move line %s has already been paid/reconciled') %
150 line.move_line_id.name
151 )
152
153 move_id = account_move_obj.create(cr, uid, {
154 'journal_id': order.mode.transfer_journal_id.id,
155 'name': 'Debit order %s' % line.move_line_id.move_id.name,
156 'reference': 'DEB%s' % line.move_line_id.move_id.name,
157 }, context=context)
158
159 # TODO: take multicurrency into account
160
161 # create the debit move line on the transfer account
162 vals = {
163 'name': 'Debit order for %s' % (
164 line.move_line_id.invoice and
165 line.move_line_id.invoice.number or
166 line.move_line_id.name),
167 'move_id': move_id,
168 'partner_id': line.partner_id.id,
169 'account_id': order.mode.transfer_account_id.id,
170 'credit': 0.0,
171 'debit': line.amount,
172 'date': time.strftime('%Y-%m-%d'),
173 }
174 transfer_move_line_id = account_move_line_obj.create(
175 cr, uid, vals, context=context)
176
177 # create the debit move line on the receivable account
178 vals.update({
179 'account_id': line.move_line_id.account_id.id,
180 'credit': line.amount,
181 'debit': 0.0,
182 })
183 reconcile_move_line_id = account_move_line_obj.create(
184 cr, uid, vals, context=context)
185
186 # register the debit move line on the payment line
187 # and call reconciliation on it
188 payment_line_obj.write(
189 cr, uid, line.id,
190 {'debit_move_line_id': reconcile_move_line_id},
191 context=context)
192
193 payment_line_obj.debit_reconcile(
194 cr, uid, line.id, context=context)
195 account_move_obj.post(cr, uid, [move_id], context=context)
196 return res
197
198payment_order()
199
200class payment_line(osv.osv):
201 _inherit = 'payment.line'
202
203 def debit_storno(self, cr, uid, payment_line_id, amount,
204 currency, storno_retry=True, context=None):
205 """
206 The processing of a storno is triggered by a debit
207 transfer on one of the company's bank accounts.
208 This method offers to re-reconcile the original debit
209 payment. For this purpose, we have registered that
210 payment move on the payment line.
211
212 Return the (now incomplete) reconcile id. The caller MUST
213 re-reconcile this reconcile with the bank transfer and
214 re-open the associated invoice.
215
216 :param payment_line_id: the single payment line id
217 :param amount: the (signed) amount debited from the bank account
218 :param currency: the bank account's currency *browse object*
219 :param boolean storno_retry: when True, attempt to reopen the invoice, \
220 set the invoice to 'Debit denied' otherwise.
221 :return: an incomplete reconcile for the caller to fill
222 :rtype: database id of an account.move.reconcile resource.
223 """
224
225 move_line_obj = self.pool.get('account.move.line')
226 reconcile_obj = self.pool.get('account.move.reconcile')
227 line = self.browse(cr, uid, payment_line_id)
228 reconcile_id = False
229 if (line.debit_move_line_id and not line.storno and
230 self.pool.get('res.currency').is_zero(
231 cr, uid, currency, (
232 (line.debit_move_line_id.credit or 0.0) -
233 (line.debit_move_line_id.debit or 0.0) + amount))):
234 # Two different cases, full and partial
235 # Both cases differ subtly in the procedure to follow
236 # Needs refractoring, but why is this not in the OpenERP API?
237 # Actually, given the nature of a direct debit order and storno,
238 # we should not need to take partial into account on the side of
239 # the debit_move_line.
240 if line.debit_move_line_id.reconcile_partial_id:
241 reconcile_id = line.debit_move_line_id.reconcile_partial_id.id
242 attribute = 'reconcile_partial_id'
243 if len(line.debit_move_line_id.reconcile_id.line_partial_ids) == 2:
244 # reuse the simple reconcile for the storno transfer
245 reconcile_obj.write(
246 cr, uid, reconcile_id, {
247 'line_id': [(6, 0, line.debit_move_line_id.id)],
248 'line_partial_ids': [(6, 0, [])],
249 }, context=context)
250 else:
251 # split up the original reconcile in a partial one
252 # and a new one for reconciling the storno transfer
253 reconcile_obj.write(
254 cr, uid, reconcile_id, {
255 'line_partial_ids': [(3, line.debit_move_line_id.id)],
256 }, context=context)
257 reconcile_id = reconcile_obj.create(
258 cr, uid, {
259 'type': 'auto',
260 'line_id': [(6, 0, line.debit_move_line_id.id)],
261 }, context=context)
262 elif line.debit_move_line_id.reconcile_id:
263 reconcile_id = line.debit_move_line_id.reconcile_id.id
264 if len(line.debit_move_line_id.reconcile_id.line_id) == 2:
265 # reuse the simple reconcile for the storno transfer
266 reconcile_obj.write(
267 cr, uid, reconcile_id, {
268 'line_id': [(6, 0, [line.debit_move_line_id.id])]
269 }, context=context)
270 else:
271 # split up the original reconcile in a partial one
272 # and a new one for reconciling the storno transfer
273 partial_ids = [
274 x.id for x in line.debit_move_line_id.reconcile_id.line_id
275 if x.id != line.debit_move_line_id.id
276 ]
277 reconcile_obj.write(
278 cr, uid, reconcile_id, {
279 'line_partial_ids': [(6, 0, partial_ids)],
280 'line_id': [(6, 0, [])],
281 }, context=context)
282 reconcile_id = reconcile_obj.create(
283 cr, uid, {
284 'type': 'auto',
285 'line_id': [(6, 0, line.debit_move_line_id.id)],
286 }, context=context)
287 # mark the payment line for storno processed
288 if reconcile_id:
289 self.write(cr, uid, [payment_line_id],
290 {'storno': True}, context=context)
291 # put forth the invoice workflow
292 if line.move_line_id.invoice:
293 activity = (storno_retry and 'open_test'
294 or 'invoice_debit_denied')
295 netsvc.LocalService("workflow").trg_validate(
296 uid, 'account.invoice', line.move_line_id.invoice.id,
297 activity, cr)
298 return reconcile_id
299
300 def get_storno_account_id(self, cr, uid, payment_line_id, amount,
301 currency, context=None):
302 """
303 Check the match of the arguments, and return the account associated
304 with the storno.
305 Used in account_banking interactive mode
306
307 :param payment_line_id: the single payment line id
308 :param amount: the (signed) amount debited from the bank account
309 :param currency: the bank account's currency *browse object*
310 :return: an account if there is a full match, False otherwise
311 :rtype: database id of an account.account resource.
312 """
313
314 line = self.browse(cr, uid, payment_line_id)
315 account_id = False
316 if (line.debit_move_line_id and not line.storno and
317 self.pool.get('res.currency').is_zero(
318 cr, uid, currency, (
319 (line.debit_move_line_id.credit or 0.0) -
320 (line.debit_move_line_id.debit or 0.0) + amount))):
321 account_id = line.debit_move_line_id.account_id.id
322 return account_id
323
324 def debit_reconcile(self, cr, uid, payment_line_id, context=None):
325 """
326 Reconcile a debit order's payment line with the the move line
327 that it is based on. Called from payment_order.action_sent().
328 As the amount is derived directly from the counterpart move line,
329 we do not expect a write off. Take partially reconcilions into
330 account though.
331
332 :param payment_line_id: the single id of the canceled payment line
333 """
334
335 if isinstance(payment_line_id, (list, tuple)):
336 payment_line_id = payment_line_id[0]
337 reconcile_obj = self.pool.get('account.move.reconcile')
338 move_line_obj = self.pool.get('account.move.line')
339 payment_line = self.browse(cr, uid, payment_line_id, context=context)
340
341 debit_move_line = payment_line.debit_move_line_id
342 torec_move_line = payment_line.move_line_id
343
344 if payment_line.storno:
345 raise osv.except_osv(
346 _('Can not reconcile'),
347 _('Cancelation of payment line \'%s\' has already been ' +
348 'processed') % payment_line.name)
349 if (not debit_move_line or not torec_move_line):
350 raise osv.except_osv(
351 _('Can not reconcile'),
352 _('No move line for line %s') % payment_line.name)
353 if torec_move_line.reconcile_id: # torec_move_line.reconcile_partial_id:
354 raise osv.except_osv(
355 _('Error'),
356 _('Move line %s has already been reconciled') %
357 torec_move_line.name
358 )
359 if debit_move_line.reconcile_id or debit_move_line.reconcile_partial_id:
360 raise osv.except_osv(
361 _('Error'),
362 _('Move line %s has already been reconciled') %
363 debit_move_line.name
364 )
365
366 def is_zero(total):
367 return self.pool.get('res.currency').is_zero(
368 cr, uid, debit_move_line.company_id.currency_id, total)
369
370 line_ids = [debit_move_line.id, torec_move_line.id]
371 if torec_move_line.reconcile_partial_id:
372 line_ids = [
373 x.id for x in debit_move_line.reconcile_partial_id.line_partial_ids] + [torec_move_line_id]
374
375 total = move_line_obj.get_balance(cr, uid, line_ids)
376 vals = {
377 'type': 'auto',
378 'line_id': is_zero(total) and [(6, 0, line_ids)] or [(6, 0, [])],
379 'line_partial_ids': is_zero(total) and [(6, 0, [])] or [(6, 0, line_ids)],
380 }
381
382 if torec_move_line.reconcile_partial_id:
383 reconcile_obj.write(
384 cr, uid, debit_move_line.reconcile_partial_id.id,
385 vals, context=context)
386 else:
387 reconcile_obj.create(
388 cr, uid, vals, context=context)
389 for line_id in line_ids:
390 netsvc.LocalService("workflow").trg_trigger(
391 uid, 'account.move.line', line_id, cr)
392
393 # If a bank transaction of a storno was first confirmed
394 # and now canceled (the invoice is now in state 'debit_denied'
395 if torec_move_line.invoice:
396 netsvc.LocalService("workflow").trg_validate(
397 uid, 'account.invoice', torec_move_line.invoice.id,
398 'undo_debit_denied', cr)
399
400
401
402 _columns = {
403 'debit_move_line_id': fields.many2one(
404 # this line is part of the credit side of move 2a
405 # from the documentation
406 'account.move.line', 'Debit move line',
407 readonly=True,
408 help="Move line through which the debit order pays the invoice"),
409 'storno': fields.boolean(
410 'Storno',
411 readonly=True,
412 help=("If this is true, the debit order has been canceled " +
413 "by the bank or by the customer")),
414 }
415payment_line()
416
417
418class payment_order_create(osv.osv_memory):
419 _inherit = 'payment.order.create'
420
421 def search_entries(self, cr, uid, ids, context=None):
422 """
423 This method taken from account_payment module.
424 We adapt the domain based on the payment_order_type
425 """
426 line_obj = self.pool.get('account.move.line')
427 mod_obj = self.pool.get('ir.model.data')
428 if context is None:
429 context = {}
430 data = self.read(cr, uid, ids, [], context=context)[0]
431 search_due_date = data['duedate']
432
433 ### start account_direct_debit ###
434 payment = self.pool.get('payment.order').browse(
435 cr, uid, context['active_id'], context=context)
436 # Search for move line to pay:
437 if payment.payment_order_type == 'debit':
438 domain = [
439 ('reconcile_id', '=', False),
440 ('account_id.type', '=', 'receivable'),
441 ('invoice_state', '!=', 'debit_denied'),
442 ('amount_to_receive', '>', 0),
443 ]
444 else:
445 domain = [
446 ('reconcile_id', '=', False),
447 ('account_id.type', '=', 'payable'),
448 ('amount_to_pay', '>', 0)
449 ]
450 domain.append(('company_id', '=', payment.mode.company_id.id))
451 # apply payment term filter
452 if payment.mode.payment_term_ids:
453 domain = domain + [
454 ('payment_term_id', 'in',
455 [term.id for term in payment.mode.payment_term_ids]
456 )
457 ]
458 # domain = [('reconcile_id', '=', False), ('account_id.type', '=', 'payable'), ('amount_to_pay', '>', 0)]
459 ### end account_direct_debit ###
460
461 domain = domain + ['|', ('date_maturity', '<=', search_due_date), ('date_maturity', '=', False)]
462 line_ids = line_obj.search(cr, uid, domain, context=context)
463 context.update({'line_ids': line_ids})
464 model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'view_create_payment_order_lines')], context=context)
465 resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
466 return {'name': ('Entry Lines'),
467 'context': context,
468 'view_type': 'form',
469 'view_mode': 'form',
470 'res_model': 'payment.order.create',
471 'views': [(resource_id,'form')],
472 'type': 'ir.actions.act_window',
473 'target': 'new',
474 }
475payment_order_create()
476
477
478
47950
=== added file 'account_direct_debit/model/payment_line.py'
--- account_direct_debit/model/payment_line.py 1970-01-01 00:00:00 +0000
+++ account_direct_debit/model/payment_line.py 2013-06-26 21:16:23 +0000
@@ -0,0 +1,152 @@
1# -*- coding: utf-8 -*-
2from openerp.osv import orm, fields
3import netsvc
4from tools.translate import _
5
6class payment_line(orm.Model):
7 _inherit = 'payment.line'
8
9 def debit_storno(self, cr, uid, payment_line_id, amount,
10 currency, storno_retry=True, context=None):
11 """
12 The processing of a storno is triggered by a debit
13 transfer on one of the company's bank accounts.
14 This method offers to re-reconcile the original debit
15 payment. For this purpose, we have registered that
16 payment move on the payment line.
17
18 Return the (now incomplete) reconcile id. The caller MUST
19 re-reconcile this reconcile with the bank transfer and
20 re-open the associated invoice.
21
22 :param payment_line_id: the single payment line id
23 :param amount: the (signed) amount debited from the bank account
24 :param currency: the bank account's currency *browse object*
25 :param boolean storno_retry: when True, attempt to reopen the invoice, \
26 set the invoice to 'Debit denied' otherwise.
27 :return: an incomplete reconcile for the caller to fill
28 :rtype: database id of an account.move.reconcile resource.
29 """
30
31 move_line_obj = self.pool.get('account.move.line')
32 reconcile_obj = self.pool.get('account.move.reconcile')
33 line = self.browse(cr, uid, payment_line_id)
34 reconcile_id = False
35 if (line.transit_move_line_id and not line.storno and
36 self.pool.get('res.currency').is_zero(
37 cr, uid, currency, (
38 (line.transit_move_line_id.credit or 0.0) -
39 (line.transit_move_line_id.debit or 0.0) + amount))):
40 # Two different cases, full and partial
41 # Both cases differ subtly in the procedure to follow
42 # Needs refractoring, but why is this not in the OpenERP API?
43 # Actually, given the nature of a direct debit order and storno,
44 # we should not need to take partial into account on the side of
45 # the transit_move_line.
46 if line.transit_move_line_id.reconcile_partial_id:
47 reconcile_id = line.transit_move_line_id.reconcile_partial_id.id
48 attribute = 'reconcile_partial_id'
49 if len(line.transit_move_line_id.reconcile_id.line_partial_ids) == 2:
50 # reuse the simple reconcile for the storno transfer
51 reconcile_obj.write(
52 cr, uid, reconcile_id, {
53 'line_id': [(6, 0, line.transit_move_line_id.id)],
54 'line_partial_ids': [(6, 0, [])],
55 }, context=context)
56 else:
57 # split up the original reconcile in a partial one
58 # and a new one for reconciling the storno transfer
59 reconcile_obj.write(
60 cr, uid, reconcile_id, {
61 'line_partial_ids': [(3, line.transit_move_line_id.id)],
62 }, context=context)
63 reconcile_id = reconcile_obj.create(
64 cr, uid, {
65 'type': 'auto',
66 'line_id': [(6, 0, line.transit_move_line_id.id)],
67 }, context=context)
68 elif line.transit_move_line_id.reconcile_id:
69 reconcile_id = line.transit_move_line_id.reconcile_id.id
70 if len(line.transit_move_line_id.reconcile_id.line_id) == 2:
71 # reuse the simple reconcile for the storno transfer
72 reconcile_obj.write(
73 cr, uid, reconcile_id, {
74 'line_id': [(6, 0, [line.transit_move_line_id.id])]
75 }, context=context)
76 else:
77 # split up the original reconcile in a partial one
78 # and a new one for reconciling the storno transfer
79 partial_ids = [
80 x.id for x in line.transit_move_line_id.reconcile_id.line_id
81 if x.id != line.transit_move_line_id.id
82 ]
83 reconcile_obj.write(
84 cr, uid, reconcile_id, {
85 'line_partial_ids': [(6, 0, partial_ids)],
86 'line_id': [(6, 0, [])],
87 }, context=context)
88 reconcile_id = reconcile_obj.create(
89 cr, uid, {
90 'type': 'auto',
91 'line_id': [(6, 0, line.transit_move_line_id.id)],
92 }, context=context)
93 # mark the payment line for storno processed
94 if reconcile_id:
95 self.write(cr, uid, [payment_line_id],
96 {'storno': True}, context=context)
97 # put forth the invoice workflow
98 if line.move_line_id.invoice:
99 activity = (storno_retry and 'open_test'
100 or 'invoice_debit_denied')
101 netsvc.LocalService("workflow").trg_validate(
102 uid, 'account.invoice', line.move_line_id.invoice.id,
103 activity, cr)
104 return reconcile_id
105
106 def get_storno_account_id(self, cr, uid, payment_line_id, amount,
107 currency, context=None):
108 """
109 Check the match of the arguments, and return the account associated
110 with the storno.
111 Used in account_banking interactive mode
112
113 :param payment_line_id: the single payment line id
114 :param amount: the (signed) amount debited from the bank account
115 :param currency: the bank account's currency *browse object*
116 :return: an account if there is a full match, False otherwise
117 :rtype: database id of an account.account resource.
118 """
119
120 line = self.browse(cr, uid, payment_line_id)
121 account_id = False
122 if (line.transit_move_line_id and not line.storno and
123 self.pool.get('res.currency').is_zero(
124 cr, uid, currency, (
125 (line.transit_move_line_id.credit or 0.0) -
126 (line.transit_move_line_id.debit or 0.0) + amount))):
127 account_id = line.transit_move_line_id.account_id.id
128 return account_id
129
130 def debit_reconcile(self, cr, uid, payment_line_id, context=None):
131 """
132 Raise if a payment line is passed for which storno is True
133 """
134 if isinstance(payment_line_id, (list, tuple)):
135 payment_line_id = payment_line_id[0]
136 payment_line = self.read(
137 cr, uid, payment_line_id, ['storno', 'name'], context=context)
138 if payment_line['storno']:
139 raise orm.except_orm(
140 _('Can not reconcile'),
141 _('Cancelation of payment line \'%s\' has already been '
142 'processed') % payment_line['name'])
143 return super(self, payment_line).debit_reconcile(
144 cr, uid, payment_line_id, context=context)
145
146 _columns = {
147 'storno': fields.boolean(
148 'Storno',
149 readonly=True,
150 help=("If this is true, the debit order has been canceled "
151 "by the bank or by the customer")),
152 }
0153
=== added file 'account_direct_debit/model/payment_order_create.py'
--- account_direct_debit/model/payment_order_create.py 1970-01-01 00:00:00 +0000
+++ account_direct_debit/model/payment_order_create.py 2013-06-26 21:16:23 +0000
@@ -0,0 +1,41 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2013 Therp BV (<http://therp.nl>).
5#
6# All other contributions are (C) by their respective contributors
7#
8# All Rights Reserved
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU Affero General Public License as
12# published by the Free Software Foundation, either version 3 of the
13# License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU Affero General Public License for more details.
19#
20# You should have received a copy of the GNU Affero General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
23##############################################################################
24
25from openerp.osv import orm
26
27
28class payment_order_create(orm.TransientModel):
29 _inherit = 'payment.order.create'
30
31 def extend_payment_order_domain(
32 self, cr, uid, payment_order, domain, context=None):
33 super(payment_order_create, self).extend_payment_order_domain(
34 cr, uid, payment_order, domain, context=context)
35 if payment_order.payment_order_type == 'debit':
36 domain += [
37 ('account_id.type', '=', 'receivable'),
38 ('invoice.state', '!=', 'debit_denied'),
39 ('amount_to_receive', '>', 0),
40 ]
41 return True
042
=== modified file 'account_direct_debit/view/account_invoice.xml'
--- account_direct_debit/view/account_invoice.xml 2012-05-01 20:36:44 +0000
+++ account_direct_debit/view/account_invoice.xml 2013-06-26 21:16:23 +0000
@@ -4,7 +4,6 @@
4 <record id="invoice_form" model="ir.ui.view">4 <record id="invoice_form" model="ir.ui.view">
5 <field name="name">account.invoice.form</field>5 <field name="name">account.invoice.form</field>
6 <field name="model">account.invoice</field>6 <field name="model">account.invoice</field>
7 <field name="type">form</field>
8 <field name="inherit_id" ref="account.invoice_form"/>7 <field name="inherit_id" ref="account.invoice_form"/>
9 <field name="arch" type="xml">8 <field name="arch" type="xml">
10 <data>9 <data>
@@ -16,14 +15,6 @@
16 <!-- button name="invoice_open" position="attributes">15 <!-- button name="invoice_open" position="attributes">
17 <attribute name="states">draft,proforma2,debit_denied</attribute>16 <attribute name="states">draft,proforma2,debit_denied</attribute>
18 </button -->17 </button -->
19 <button string='Re-Open' position="attributes">
20 <attribute name="states">paid,debit_denied</attribute>
21 <!--
22 unintentional fix of
23 https://bugs.launchpad.net/openobject-addons/+bug/807543
24 -->
25 <attribute name="groups"/>
26 </button>
27 <button name="invoice_open" position="after">18 <button name="invoice_open" position="after">
28 <button name="invoice_debit_denied" states="paid"19 <button name="invoice_debit_denied" states="paid"
29 string="Debit Denied" icon="gtk-cancel"/>20 string="Debit Denied" icon="gtk-cancel"/>
@@ -38,7 +29,11 @@
38 <field name="inherit_id" ref="account.view_account_invoice_filter"/>29 <field name="inherit_id" ref="account.view_account_invoice_filter"/>
39 <field name="arch" type="xml">30 <field name="arch" type="xml">
40 <filter name="invoices" position="after">31 <filter name="invoices" position="after">
41 <filter name="debit_denied" icon="terp-dolar_ok!" string="Debit denied" domain="[('state','=','debit_denied')]" help="Show only invoices with state Debit denied"/>32 <filter name="debit_denied" icon="terp-dolar_ok!"
33 string="Debit denied"
34 domain="[('state','=','debit_denied')]"
35 help="Show only invoices with state Debit denied"
36 />
42 </filter>37 </filter>
43 </field>38 </field>
44 </record>39 </record>
4540
=== modified file 'account_direct_debit/view/account_payment.xml'
--- account_direct_debit/view/account_payment.xml 2013-01-21 11:19:04 +0000
+++ account_direct_debit/view/account_payment.xml 2013-06-26 21:16:23 +0000
@@ -1,6 +1,7 @@
1<?xml version="1.0" encoding="utf-8"?>1<?xml version="1.0" encoding="utf-8"?>
2<openerp>2<openerp>
3 <data>3 <data>
4
4 <!-- distinguish between payment orders and debit orders in the menu -->5 <!-- distinguish between payment orders and debit orders in the menu -->
5 <record id="account_payment.action_payment_order_tree" model="ir.actions.act_window">6 <record id="account_payment.action_payment_order_tree" model="ir.actions.act_window">
6 <field name="domain">[('payment_order_type', '=', 'payment')]</field>7 <field name="domain">[('payment_order_type', '=', 'payment')]</field>
@@ -24,7 +25,6 @@
24 <record id="view_payment_order_form" model="ir.ui.view">25 <record id="view_payment_order_form" model="ir.ui.view">
25 <field name="name">payment.order.form</field>26 <field name="name">payment.order.form</field>
26 <field name="model">payment.order</field>27 <field name="model">payment.order</field>
27 <field name="type">form</field>
28 <field name="inherit_id" ref="account_payment.view_payment_order_form"/>28 <field name="inherit_id" ref="account_payment.view_payment_order_form"/>
29 <field name="priority" eval="60"/>29 <field name="priority" eval="60"/>
30 <field name="arch" type="xml">30 <field name="arch" type="xml">
@@ -46,40 +46,13 @@
46 icon="gtk-find"46 icon="gtk-find"
47 />47 />
48 </xpath>48 </xpath>
49 <!-- the attrs do not work like this, apparently
50 <xpath expr="//tree[@string='Payment Line']" position="inside">
51 <field name="storno" attrs="{'invisible': [(parent.payment_order_type, '!=', 'debit')]}"/>
52 </xpath>
53 -->
54 </data>49 </data>
55 </field>50 </field>
56 </record>51 </record>
5752
58 <!-- Add transfer account for debit type modes -->
59 <record model="ir.ui.view" id="view_payment_mode_form">
60 <field name="name">payment.mode.form add transfer account</field>
61 <field name="model">payment.mode</field>
62 <field name="inherit_id" ref="account_banking.view_payment_mode_form_inherit"/>
63 <field name="type">form</field>
64 <field name="arch" type="xml">
65 <field name="type" position="after">
66 <field name="transfer_account_id"
67 domain="[('type', '=', 'other'),
68 ('reconcile', '=', True),
69 ('company_id', '=', company_id)]"
70 />
71 <field name="transfer_journal_id"
72 domain="[('company_id', '=', company_id)]"
73 />
74 <field name="payment_term_ids"/>
75 </field>
76 </field>
77 </record>
78
79 <record id="view_payment_line_tree" model="ir.ui.view">53 <record id="view_payment_line_tree" model="ir.ui.view">
80 <field name="name">Payment Lines</field>54 <field name="name">Payment Lines</field>
81 <field name="model">payment.line</field>55 <field name="model">payment.line</field>
82 <field name="type">tree</field>
83 <field name="inherit_id" ref="account_payment.view_payment_line_tree"/>56 <field name="inherit_id" ref="account_payment.view_payment_line_tree"/>
84 <field eval="4" name="priority"/>57 <field eval="4" name="priority"/>
85 <field name="arch" type="xml">58 <field name="arch" type="xml">
@@ -88,5 +61,6 @@
88 </field>61 </field>
89 </field>62 </field>
90 </record>63 </record>
64
91 </data>65 </data>
92</openerp>66</openerp>
9367
=== removed file 'account_direct_debit/workflow/account_payment.xml'
--- account_direct_debit/workflow/account_payment.xml 2013-01-02 14:45:02 +0000
+++ account_direct_debit/workflow/account_payment.xml 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <!--
5 Transition to undo the payment order and reset to
6 sent, triggered by
7 cancelling a bank transaction with which the order
8 was reconciled.
9 For this, we need to cancel the flow stop on the done state,
10 unfortunately.
11 TODO: what is below is not enough. We need to inject
12 another state, 'sent_wait' between sent and done.
13 -->
14 <record id="account_payment.act_done" model="workflow.activity">
15 <field name="flow_stop" eval="False"/>
16 </record>
17
18 <record id="trans_done_sent" model="workflow.transition">
19 <field name="act_from" ref="account_payment.act_done"/>
20 <field name="act_to" ref="account_banking.act_sent"/>
21 <field name="condition">test_undo_done()</field>
22 <field name="signal">undo_done</field>
23 </record>
24 </data>
25</openerp>
260
=== modified file 'account_payment_shortcut/__init__.py'
--- account_payment_shortcut/__init__.py 2011-12-09 13:07:52 +0000
+++ account_payment_shortcut/__init__.py 2013-06-26 21:16:23 +0000
@@ -1,1 +1,2 @@
1# -*- coding: utf-8 -*-
1import payment_order2import payment_order
23
=== modified file 'account_payment_shortcut/payment_order.py'
--- account_payment_shortcut/payment_order.py 2011-12-09 13:07:52 +0000
+++ account_payment_shortcut/payment_order.py 2013-06-26 21:16:23 +0000
@@ -1,8 +1,30 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2from osv import osv, fields2##############################################################################
33#
4class payment_order_create(osv.osv_memory):4# Copyright (C) 2011 - 2013 Therp BV (<http://therp.nl>).
55#
6# All other contributions are (C) by their respective contributors
7#
8# All Rights Reserved
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU Affero General Public License as
12# published by the Free Software Foundation, either version 3 of the
13# License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU Affero General Public License for more details.
19#
20# You should have received a copy of the GNU Affero General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22#
23##############################################################################
24
25from osv import orm
26
27class payment_order_create(orm.TransientModel):
6 _inherit = 'payment.order.create'28 _inherit = 'payment.order.create'
729
8 def default_get(self, cr, uid, fields_list, context=None):30 def default_get(self, cr, uid, fields_list, context=None):
@@ -27,5 +49,3 @@
27 res['entries'] = context['line_ids']49 res['entries'] = context['line_ids']
2850
29 return res51 return res
30
31payment_order_create()
3252
=== modified file 'bank_statement_instant_voucher/model/account_bank_statement_line.py'
--- bank_statement_instant_voucher/model/account_bank_statement_line.py 2012-12-05 20:16:14 +0000
+++ bank_statement_instant_voucher/model/account_bank_statement_line.py 2013-06-26 21:16:23 +0000
@@ -2,7 +2,7 @@
2##############################################################################2##############################################################################
3#3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# This module copyright (C) 2012 Therp BV (<http://therp.nl>).5# This module copyright (C) 2012 - 2013 Therp BV (<http://therp.nl>).
6#6#
7# This program is free software: you can redistribute it and/or modify7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as8# it under the terms of the GNU Affero General Public License as
@@ -19,10 +19,10 @@
19#19#
20##############################################################################20##############################################################################
2121
22from openerp.osv import osv, fields22from openerp.osv import orm, fields
2323
2424
25class account_bank_statement_line(osv.Model):25class account_bank_statement_line(orm.Model):
26 _inherit = 'account.bank.statement.line'26 _inherit = 'account.bank.statement.line'
27 def create_instant_voucher(self, cr, uid, ids, context=None):27 def create_instant_voucher(self, cr, uid, ids, context=None):
28 res = False28 res = False
2929
=== modified file 'bank_statement_instant_voucher/model/account_voucher_instant.py'
--- bank_statement_instant_voucher/model/account_voucher_instant.py 2012-12-05 20:16:14 +0000
+++ bank_statement_instant_voucher/model/account_voucher_instant.py 2013-06-26 21:16:23 +0000
@@ -2,7 +2,7 @@
2##############################################################################2##############################################################################
3#3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# This module copyright (C) 2012 Therp BV (<http://therp.nl>).5# This module copyright (C) 2012 - 2013 Therp BV (<http://therp.nl>).
6#6#
7# This program is free software: you can redistribute it and/or modify7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as8# it under the terms of the GNU Affero General Public License as
@@ -19,12 +19,12 @@
19#19#
20##############################################################################20##############################################################################
2121
22from openerp.osv import osv, fields22from openerp.osv import orm, fields
23from openerp.tools.translate import _23from openerp.tools.translate import _
24from openerp.addons.decimal_precision import decimal_precision as dp24from openerp.addons.decimal_precision import decimal_precision as dp
2525
2626
27class instant_voucher(osv.TransientModel):27class instant_voucher(orm.TransientModel):
28 _name = 'account.voucher.instant'28 _name = 'account.voucher.instant'
29 _description = 'Instant Voucher'29 _description = 'Instant Voucher'
3030
@@ -76,7 +76,7 @@
76 cr, uid, [('company_id', '=', line.company_id.id),76 cr, uid, [('company_id', '=', line.company_id.id),
77 ('type', '=', voucher_type)])77 ('type', '=', voucher_type)])
78 if not journal_ids:78 if not journal_ids:
79 osv.exept_osv(79 orm.exept_orm(
80 _('Error'),80 _('Error'),
81 _('No %s journal defined') % voucher_type)81 _('No %s journal defined') % voucher_type)
82 82
@@ -156,7 +156,7 @@
156 context.get('active_id') or156 context.get('active_id') or
157 context.get('active_ids') and context.get('active_ids')[0])157 context.get('active_ids') and context.get('active_ids')[0])
158 if not res['statement_line_id']:158 if not res['statement_line_id']:
159 raise osv.except_osv(159 raise orm.except_orm(
160 _('Error'),160 _('Error'),
161 _('Cannot determine statement line'))161 _('Cannot determine statement line'))
162 line = self.pool.get('account.bank.statement.line').browse(162 line = self.pool.get('account.bank.statement.line').browse(
@@ -212,7 +212,7 @@
212 instant.voucher_id.company_id.currency_id)212 instant.voucher_id.company_id.currency_id)
213 if (instant.statement_line_id.statement_id.currency.id !=213 if (instant.statement_line_id.statement_id.currency.id !=
214 voucher_currency.id):214 voucher_currency.id):
215 raise osv.except_osv(215 raise orm.except_orm(
216 _("Error"),216 _("Error"),
217 _("Currency on the bank statement line needs to be the "217 _("Currency on the bank statement line needs to be the "
218 "same as on the voucher. Currency conversion is not yet "218 "same as on the voucher. Currency conversion is not yet "
@@ -222,7 +222,7 @@
222 cr, uid, [instant.voucher_id.id], context=context)222 cr, uid, [instant.voucher_id.id], context=context)
223 instant.refresh()223 instant.refresh()
224 if instant.voucher_id.state != 'posted':224 if instant.voucher_id.state != 'posted':
225 raise osv.except_osv(225 raise orm.except_orm(
226 _("Error"),226 _("Error"),
227 _("The voucher could not be posted."))227 _("The voucher could not be posted."))
228 if instant.voucher_id.move_id.state != 'posted':228 if instant.voucher_id.move_id.state != 'posted':
@@ -230,12 +230,12 @@
230 cr, uid, [instant.voucher_id.move_id.id], context=context)230 cr, uid, [instant.voucher_id.move_id.id], context=context)
231 instant.refresh()231 instant.refresh()
232 if instant.voucher_id.move_id.state != 'posted':232 if instant.voucher_id.move_id.state != 'posted':
233 raise osv.except_osv(233 raise orm.except_orm(
234 _("Error"),234 _("Error"),
235 _("The voucher's move line could not be posted."))235 _("The voucher's move line could not be posted."))
236 if not self.pool.get('res.currency').is_zero(236 if not self.pool.get('res.currency').is_zero(
237 cr, uid, voucher_currency, instant.balance):237 cr, uid, voucher_currency, instant.balance):
238 raise osv.except_osv(238 raise orm.except_orm(
239 _("Error"),239 _("Error"),
240 _("The amount on the bank statement line needs to be the "240 _("The amount on the bank statement line needs to be the "
241 "same as on the voucher. Write-off is not yet "241 "same as on the voucher. Write-off is not yet "
@@ -245,7 +245,7 @@
245 # and trigger its posting and reconciliation.245 # and trigger its posting and reconciliation.
246 if 'import_transaction_id' in statement_line_obj._columns:246 if 'import_transaction_id' in statement_line_obj._columns:
247 if instant.statement_line_id.state == 'confirmed':247 if instant.statement_line_id.state == 'confirmed':
248 raise osv.except_osv(248 raise orm.except_orm(
249 _("Error"),249 _("Error"),
250 _("Cannot match a confirmed statement line"))250 _("Cannot match a confirmed statement line"))
251 if not instant.statement_line_id.import_transaction_id:251 if not instant.statement_line_id.import_transaction_id:
252252
=== modified file 'bank_statement_instant_voucher/view/account_bank_statement_line.xml'
--- bank_statement_instant_voucher/view/account_bank_statement_line.xml 2012-11-28 13:49:36 +0000
+++ bank_statement_instant_voucher/view/account_bank_statement_line.xml 2013-06-26 21:16:23 +0000
@@ -5,7 +5,6 @@
5 <field name="name">Add instant voucher button to bank statement line on statement form</field>5 <field name="name">Add instant voucher button to bank statement line on statement form</field>
6 <field name="inherit_id" ref="account.view_bank_statement_form" />6 <field name="inherit_id" ref="account.view_bank_statement_form" />
7 <field name="model">account.bank.statement</field>7 <field name="model">account.bank.statement</field>
8 <field name="type">form</field>
9 <field name="priority" eval="30"/>8 <field name="priority" eval="30"/>
10 <field name="arch" type="xml">9 <field name="arch" type="xml">
11 <xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='voucher_id']"10 <xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='voucher_id']"
1211
=== modified file 'bank_statement_instant_voucher/view/account_voucher_instant.xml'
--- bank_statement_instant_voucher/view/account_voucher_instant.xml 2012-11-28 13:49:36 +0000
+++ bank_statement_instant_voucher/view/account_voucher_instant.xml 2013-06-26 21:16:23 +0000
@@ -4,7 +4,6 @@
4 <record id="instant_voucher_form" model="ir.ui.view">4 <record id="instant_voucher_form" model="ir.ui.view">
5 <field name="name">Instant voucher form view</field>5 <field name="name">Instant voucher form view</field>
6 <field name="model">account.voucher.instant</field>6 <field name="model">account.voucher.instant</field>
7 <field name="type">form</field>
8 <field name="arch" type="xml">7 <field name="arch" type="xml">
9 <form>8 <form>
10 <field name="state" invisible="1" readonly="1"/>9 <field name="state" invisible="1" readonly="1"/>

Subscribers

People subscribed via source and target branches

to status/vote changes: