banking-addons-team team mailing list archive
-
banking-addons-team team
-
Mailing list archive
-
Message #00510
[Merge] lp:~therp-nl/banking-addons/ba7.0-RFR-split_off_payment_part into lp:banking-addons/banking-addons-70
Stefan Rijnhart (Therp) has proposed merging lp:~therp-nl/banking-addons/ba7.0-RFR-split_off_payment_part into lp:banking-addons/banking-addons-70 with lp:~banking-addons-team/banking-addons/ba70-mig_account_iban_preserve_domestic as a prerequisite.
Requested reviews:
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c): code review, no test
For more details, see:
https://code.launchpad.net/~therp-nl/banking-addons/ba7.0-RFR-split_off_payment_part/+merge/153680
This change is a conceptually simple refactoring: the account_banking module has always containted code for importing bank statements as well as exporting payment orders. I have now split off the latter part in a separate module.
Unfortunately, the implementation of this simple concept has lead to a horrendous diff of 3000 lines, stretching what can be possibly expected from a community based review structure. Most of this is just copied code. You might want to focus on the following, actual changes:
l.927 introduction of move_info2values replacing l.1005-1022, so that it can be overridden in the new module (in l.2136)
l.949,965-973,982,986 conditionally using functionality from account_payment (if it is installed)
l.1037-1064 Do not attempt to trigger workflow when *recognizing* a payment order line but after confirmation of the match (in l.1994-2003)
l.1688,1729 Replacing wizard interface object with transient model (and actually calling the workflow instead of overwriting the state field)
l.2157-2179 Akwardly updating a pre-existing function map with functions to deal with additional match types added by the split off module
l.2615-2619,2636,2639,2647-2652,2657-2662 Compare dates from database with UTC date
l.2869-2906 Preserve original module name in xml ids for migration purposes
Note that although the target branch is 7.0, the code is still only compatible with 6.1. The actual migration of the code will be presented in another MP. I do not want to jeopardize the mature 6.1 branch with such large changes. Because I needed to test the code in 6.1, I made sure not to introduce any incompatiblities with this release (meaning: the view type *will* eventually be removed from the xml view definitions).
--
https://code.launchpad.net/~therp-nl/banking-addons/ba7.0-RFR-split_off_payment_part/+merge/153680
Your team Banking Addons Team is subscribed to branch lp:~banking-addons-team/banking-addons/ba70-mig_account_iban_preserve_domestic.
=== modified file 'account_banking/__openerp__.py'
--- account_banking/__openerp__.py 2013-02-26 21:06:36 +0000
+++ account_banking/__openerp__.py 2013-04-06 05:04:22 +0000
@@ -35,15 +35,16 @@
'author': 'Banking addons community',
'website': 'https://launchpad.net/banking-addons',
'category': 'Banking addons',
- 'depends': ['base', 'account', 'base_iban', 'account_payment',
- 'account_iban_preserve_domestic'],
+ 'depends': [
+ 'account_voucher',
+ 'account_iban_preserve_domestic',
+ ],
'init_xml': [],
'update_xml': [
'security/ir.model.access.csv',
'data/account_banking_data.xml',
'wizard/bank_import_view.xml',
'account_banking_view.xml',
- 'account_banking_workflow.xml',
'wizard/banking_transaction_wizard.xml',
'workflow/account_invoice.xml',
],
=== modified file 'account_banking/account_banking.py'
--- account_banking/account_banking.py 2013-03-20 19:25:57 +0000
+++ account_banking/account_banking.py 2013-04-06 05:04:22 +0000
@@ -272,68 +272,6 @@
}
account_banking_imported_file()
-class payment_mode_type(osv.osv):
- _name= 'payment.mode.type'
- _description= 'Payment Mode Type'
- _columns= {
- 'name': fields.char(
- 'Name', size=64, required=True,
- help='Payment Type'
- ),
- 'code': fields.char(
- 'Code', size=64, required=True,
- help='Specify the Code for Payment Type'
- ),
- # Setting suitable_bank_types to required pending
- # https://bugs.launchpad.net/openobject-addons/+bug/786845
- 'suitable_bank_types': fields.many2many(
- 'res.partner.bank.type',
- 'bank_type_payment_type_rel',
- 'pay_type_id','bank_type_id',
- 'Suitable bank types', required=True),
- 'ir_model_id': fields.many2one(
- 'ir.model', 'Payment wizard',
- help=('Select the Payment Wizard for payments of this type. '
- 'Leave empty for manual processing'),
- domain=[('osv_memory', '=', True)],
- ),
- 'payment_order_type': fields.selection(
- [('payment', 'Payment'),('debit', 'Direct debit')],
- 'Payment order type', required=True,
- ),
- }
-
- _defaults = {
- 'payment_order_type': lambda *a: 'payment',
- }
-
-payment_mode_type()
-
-class payment_mode(osv.osv):
- ''' Restoring the payment type from version 5,
- used to select the export wizard (if any) '''
- _inherit = "payment.mode"
-
- def suitable_bank_types(self, cr, uid, payment_mode_id=None, context=None):
- """ Reinstates functional code for suitable bank type filtering.
- Current code in account_payment is disfunctional.
- """
- res = []
- payment_mode = self.browse(
- cr, uid, payment_mode_id, context)
- if (payment_mode and payment_mode.type and
- payment_mode.type.suitable_bank_types):
- res = [type.code for type in payment_mode.type.suitable_bank_types]
- return res
-
- _columns = {
- 'type': fields.many2one(
- 'payment.mode.type', 'Payment type',
- help='Select the Payment Type for the Payment Mode.'
- ),
- }
-payment_mode()
-
class account_bank_statement(osv.osv):
'''
Extensions from account_bank_statement:
@@ -785,419 +723,6 @@
account_bank_statement_line()
-class payment_line(osv.osv):
- '''
- Add extra export_state and date_done fields; make destination bank account
- mandatory, as it makes no sense to send payments into thin air.
- Edit: Payments can be by cash too, which is prohibited by mandatory bank
- accounts.
- '''
- _inherit = 'payment.line'
- _columns = {
- # New fields
- 'export_state': fields.selection([
- ('draft', 'Draft'),
- ('open','Confirmed'),
- ('cancel','Cancelled'),
- ('sent', 'Sent'),
- ('rejected', 'Rejected'),
- ('done','Done'),
- ], 'State', select=True
- ),
- 'msg': fields.char('Message', size=255, required=False, readonly=True),
-
- # Redefined fields: added states
- 'date_done': fields.datetime('Date Confirmed', select=True,
- readonly=True),
- 'name': fields.char(
- 'Your Reference', size=64, required=True,
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'communication': fields.char(
- 'Communication', size=64, required=False,
- help=("Used as the message between ordering customer and current "
- "company. Depicts 'What do you want to say to the recipient"
- " about this order ?'"
- ),
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'communication2': fields.char(
- 'Communication 2', size=128,
- help='The successor message of Communication.',
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'move_line_id': fields.many2one(
- 'account.move.line', 'Entry line',
- domain=[('reconcile_id','=', False),
- ('account_id.type', '=','payable')
- ],
- help=('This Entry Line will be referred for the information of '
- 'the ordering customer.'
- ),
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'amount_currency': fields.float(
- 'Amount in Partner Currency', digits=(16,2),
- required=True,
- help='Payment amount in the partner currency',
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'currency': fields.many2one(
- 'res.currency', 'Partner Currency', required=True,
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'bank_id': fields.many2one(
- 'res.partner.bank', 'Destination Bank account',
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'order_id': fields.many2one(
- 'payment.order', 'Order', required=True,
- ondelete='cascade', select=True,
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'partner_id': fields.many2one(
- 'res.partner', string="Partner", required=True,
- help='The Ordering Customer',
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'date': fields.date(
- 'Payment Date',
- help=("If no payment date is specified, the bank will treat this "
- "payment line directly"
- ),
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'state': fields.selection([
- ('normal','Free'),
- ('structured','Structured')
- ], 'Communication Type', required=True,
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- }
- _defaults = {
- 'export_state': lambda *a: 'draft',
- 'date_done': lambda *a: False,
- 'msg': lambda *a: '',
- }
-
- def fields_get(self, cr, uid, fields=None, context=None):
- res = super(payment_line, self).fields_get(cr, uid, fields, context)
- if 'communication' in res:
- res['communication'].setdefault('states', {})
- res['communication']['states']['structured'] = [('required', True)]
- if 'communication2' in res:
- res['communication2'].setdefault('states', {})
- res['communication2']['states']['structured'] = [('readonly', True)]
- res['communication2']['states']['normal'] = [('readonly', False)]
-
- return res
-
- """
- Hooks for processing direct debit orders, such as implemented in
- account_direct_debit module.
- """
- def get_storno_account_id(self, cr, uid, payment_line_id, amount,
- currency_id, context=None):
- """
- Hook for verifying a match of the payment line with the amount.
- Return the account associated with the storno.
- Used in account_banking interactive mode
- :param payment_line_id: the single payment line id
- :param amount: the (signed) amount debited from the bank account
- :param currency: the bank account's currency *browse object*
- :return: an account if there is a full match, False otherwise
- :rtype: database id of an account.account resource.
- """
-
- return False
-
- def debit_storno(self, cr, uid, payment_line_id, amount,
- currency_id, storno_retry=True, context=None):
- """
- Hook for handling a canceled item of a direct debit order.
- Presumably called from a bank statement import routine.
-
- Decide on the direction that the invoice's workflow needs to take.
- You may optionally return an incomplete reconcile for the caller
- to reconcile the now void payment.
-
- :param payment_line_id: the single payment line id
- :param amount: the (negative) amount debited from the bank account
- :param currency: the bank account's currency *browse object*
- :param boolean storno_retry: whether the storno is considered fatal \
- or not.
- :return: an incomplete reconcile for the caller to fill
- :rtype: database id of an account.move.reconcile resource.
- """
-
- return False
-
-payment_line()
-
-class payment_order(osv.osv):
- '''
- Enable extra states for payment exports
- '''
- _inherit = 'payment.order'
-
- _columns = {
- 'date_scheduled': fields.date(
- 'Scheduled date if fixed',
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- help='Select a date if you have chosen Preferred Date to be fixed.'
- ),
- 'reference': fields.char(
- 'Reference', size=128, required=True,
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'mode': fields.many2one(
- 'payment.mode', 'Payment mode', select=True, required=True,
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- help='Select the Payment Mode to be applied.',
- ),
- 'state': fields.selection([
- ('draft', 'Draft'),
- ('open','Confirmed'),
- ('cancel','Cancelled'),
- ('sent', 'Sent'),
- ('rejected', 'Rejected'),
- ('done','Done'),
- ], 'State', select=True
- ),
- 'line_ids': fields.one2many(
- 'payment.line', 'order_id', 'Payment lines',
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'user_id': fields.many2one(
- 'res.users','User', required=True,
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- ),
- 'date_prefered': fields.selection([
- ('now', 'Directly'),
- ('due', 'Due date'),
- ('fixed', 'Fixed date')
- ], "Preferred date", change_default=True, required=True,
- states={
- 'sent': [('readonly', True)],
- 'rejected': [('readonly', True)],
- 'done': [('readonly', True)]
- },
- help=("Choose an option for the Payment Order:'Fixed' stands for a "
- "date specified by you.'Directly' stands for the direct "
- "execution.'Due date' stands for the scheduled date of "
- "execution."
- )
- ),
- 'payment_order_type': fields.selection(
- [('payment', 'Payment'),('debit', 'Direct debit')],
- 'Payment order type', required=True,
- ),
- 'date_sent': fields.date('Send date', readonly=True),
- }
-
- _defaults = {
- 'payment_order_type': lambda *a: 'payment',
- }
-
- def launch_wizard(self, cr, uid, ids, context=None):
- """
- Search for a wizard to launch according to the type.
- If type is manual. just confirm the order.
- Previously (pre-v6) in account_payment/wizard/wizard_pay.py
- """
- if context == None:
- context = {}
- result = {}
- orders = self.browse(cr, uid, ids, context)
- order = orders[0]
- # check if a wizard is defined for the first order
- if order.mode.type and order.mode.type.ir_model_id:
- context['active_ids'] = ids
- wizard_model = order.mode.type.ir_model_id.model
- wizard_obj = self.pool.get(wizard_model)
- wizard_id = wizard_obj.create(cr, uid, {}, context)
- result = {
- 'name': wizard_obj._description or 'Payment Order Export',
- 'view_type': 'form',
- 'view_mode': 'form',
- 'res_model': wizard_model,
- 'domain': [],
- 'context': context,
- 'type': 'ir.actions.act_window',
- 'target': 'new',
- 'res_id': wizard_id,
- 'nodestroy': True,
- }
- else:
- # should all be manual orders without type or wizard model
- for order in orders[1:]:
- if order.mode.type and order.mode.type.ir_model_id:
- raise osv.except_osv(
- _('Error'),
- _('You can only combine payment orders of the same type')
- )
- # process manual payments
- wf_service = netsvc.LocalService('workflow')
- for order_id in ids:
- wf_service.trg_validate(uid, 'payment.order', order_id, 'sent', cr)
- return result
-
- def _write_payment_lines(self, cursor, uid, ids, **kwargs):
- '''
- ORM method for setting attributes of corresponding payment.line objects.
- Note that while this is ORM compliant, it is also very ineffecient due
- to the absence of filters on writes and hence the requirement to
- filter on the client(=OpenERP server) side.
- '''
- if not hasattr(ids, '__iter__'):
- ids = [ids]
- payment_line_obj = self.pool.get('payment.line')
- line_ids = payment_line_obj.search(
- cursor, uid, [
- ('order_id', 'in', ids)
- ])
- payment_line_obj.write(cursor, uid, line_ids, kwargs)
-
- def set_to_draft(self, cursor, uid, ids, *args):
- '''
- Set both self and payment lines to state 'draft'.
- '''
- self._write_payment_lines(cursor, uid, ids, export_state='draft')
- return super(payment_order, self).set_to_draft(
- cursor, uid, ids, *args
- )
-
- def action_sent(self, cursor, uid, ids, *args):
- '''
- Set both self and payment lines to state 'sent'.
- '''
- self._write_payment_lines(cursor, uid, ids, export_state='sent')
- self.write(cursor, uid, ids, {'state':'sent',
- 'date_sent': time.strftime('%Y-%m-%d')})
- return True
-
- def action_rejected(self, cursor, uid, ids, *args):
- '''
- Set both self and payment lines to state 'rejected'.
- '''
- self._write_payment_lines(cursor, uid, ids, export_state='rejected')
- wf_service = netsvc.LocalService('workflow')
- for id in ids:
- wf_service.trg_validate(uid, 'payment.order', id, 'rejected', cursor)
- return True
-
- def set_done(self, cursor, uid, ids, *args):
- '''
- Extend standard transition to update children as well.
- '''
- self._write_payment_lines(cursor, uid, ids,
- export_state='done',
- date_done=time.strftime('%Y-%m-%d')
- )
- return super(payment_order, self).set_done(
- cursor, uid, ids, *args
- )
-
- def get_wizard(self, type):
- '''
- Intercept manual bank payments to include 'sent' state. Default
- 'manual' payments are flagged 'done' immediately.
- '''
- if type == 'BANKMAN':
- # Note that self._module gets overwritten by inheriters, so make
- # the module name hard coded.
- return 'account_banking', 'wizard_account_banking_payment_manual'
- return super(payment_order, self).get_wizard(type)
-
- """
- Hooks for processing direct debit orders, such as implemented in
- account_direct_debit module.
- """
- def debit_reconcile_transfer(
- self, cr, uid, payment_order_id, amount, currency, context=None):
- """
- Reconcile the payment order if the amount is correct. Return the
- id of the reconciliation.
- """
- raise osv.except_osv(
- _("Cannot reconcile"),
- _("Cannot reconcile debit order: "+
- "Not implemented."))
-
- def debit_unreconcile_transfer(
- self, cr, uid, payment_order_id, reconcile_id, amount, currency,
- context=None):
- """ Unreconcile the payment_order if at all possible """
- raise osv.except_osv(
- _("Cannot unreconcile"),
- _("Cannot unreconcile debit order: "+
- "Not implemented."))
-
-payment_order()
class res_partner_bank(osv.osv):
'''
=== modified file 'account_banking/account_banking_view.xml'
--- account_banking/account_banking_view.xml 2013-01-30 11:34:58 +0000
+++ account_banking/account_banking_view.xml 2013-04-06 05:04:22 +0000
@@ -330,45 +330,6 @@
</field>
</record>
- <!-- Make buttons on payment order sensitive for extra states,
- restore wizard functionality when making payments
- -->
-
- <record id="view_banking_payment_order_form_1" model="ir.ui.view">
- <field name="name">account.payment.order.form.banking-1</field>
- <field name="inherit_id" ref="account_payment.view_payment_order_form" />
- <field name="model">payment.order</field>
- <field name="type">form</field>
- <field name="arch" type="xml">
- <data>
- <xpath expr="/form/group/button[@string='Select Invoices to Pay']"
- position="replace">
- <button colspan="2" name="%(account_payment.action_create_payment_order)s"
- string="Select Invoices to Pay" type="action"
- attrs="{'invisible':[('state','!=','draft')]}"
- icon="gtk-find"
- />
- </xpath>
- <xpath expr="/form/group/button[@string='Make Payments']"
- position="replace">
- <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
- <newline/>
- </xpath>
- </data>
- </field>
- </record>
- <record id="view_banking_payment_order_tree_1" model="ir.ui.view">
- <field name="name">account.payment.order.tree.banking-1</field>
- <field name="inherit_id" ref="account_payment.view_payment_order_tree" />
- <field name="model">payment.order</field>
- <field name="type">tree</field>
- <field name="arch" type="xml">
- <button string="Make Payments" position="replace">
- <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
- </button>
- </field>
- </record>
-
<!-- Set trigger on IBAN and acc_number fields in res_partner_bank form -->
<!--record id="view_partner_bank_account_banking_form_1" model="ir.ui.view">
<field name="name">res.partner.bank.form.banking-1</field>
@@ -459,54 +420,6 @@
</field>
</record>
- <!-- Insert payment_mode.type -->
- <record id="view_payment_mode_form_inherit" model="ir.ui.view">
- <field name="name">payment.mode.form.inherit</field>
- <field name="model">payment.mode</field>
- <field name="inherit_id" ref="account_payment.view_payment_mode_form"/>
- <field name="type">form</field>
- <field name="arch" type="xml">
- <field name="company_id" position="after">
- <field name="type"/>
- </field>
- </field>
- </record>
- <record id="view_payment_mode_tree_inherit" model="ir.ui.view">
- <field name="name">payment.mode.tree.inherit</field>
- <field name="model">payment.mode</field>
- <field name="inherit_id" ref="account_payment.view_payment_mode_tree"/>
- <field name="type">tree</field>
- <field name="arch" type="xml">
- <field name="company_id" position="after">
- <field name="type"/>
- </field>
- </field>
- </record>
-
- <!-- basic view for payment mode type -->
- <record model="ir.ui.view" id="view_payment_mode_type_form">
- <field name="name">view.payment.mode.type.form</field>
- <field name="model">payment.mode.type</field>
- <field name="type">form</field>
- <field name="arch" type="xml">
- <form>
- <field name="name" />
- <field name="code" />
- <field name="suitable_bank_types"/>
- <field name="payment_order_type"/>
- <field name="ir_model_id"/>
- </form>
- </field>
- </record>
-
- <!-- fixes https://bugs.launchpad.net/openobject-addons/+bug/903156 for 6.0
- Note that 6.1 does not suffer from the problem
- -->
- <record id="account_payment.action_create_payment_order" model="ir.actions.act_window">
- <field name="view_id" ref="account_payment.view_create_payment_order"/>
- </record>
-
-
<record model="ir.ui.view" id="view_bank_statement_line_tree">
<field name="name">Bank statement line tree view</field>
<field name="model">account.bank.statement.line</field>
=== modified file 'account_banking/banking_import_transaction.py'
--- account_banking/banking_import_transaction.py 2013-02-07 09:56:06 +0000
+++ account_banking/banking_import_transaction.py 2013-04-06 05:04:22 +0000
@@ -123,43 +123,6 @@
# return move_lines to mix with the rest
return [x for x in invoice.move_id.line_id if x.account_id.reconcile]
- def _match_debit_order(
- self, cr, uid, trans, log, context=None):
-
- def is_zero(total):
- return self.pool.get('res.currency').is_zero(
- cr, uid, trans.statement_id.currency, total)
-
- payment_order_obj = self.pool.get('payment.order')
- order_ids = payment_order_obj.search(
- cr, uid, [('payment_order_type', '=', 'debit'),
- ('state', '=', 'sent'),
- ('date_sent', '<=', str2date(trans.execution_date,
- '%Y-%m-%d'))
- ],
- limit=0, context=context)
- orders = payment_order_obj.browse(cr, uid, order_ids, context)
- candidates = [x for x in orders if
- is_zero(x.total - trans.transferred_amount)]
- if len(candidates) > 0:
- # retrieve the common account_id, if any
- account_id = False
- for line in candidates[0].line_ids[0].debit_move_line_id.move_id.line_id:
- if line.account_id.type == 'other':
- account_id = line.account_id.id
- break
- return dict(
- move_line_ids = False,
- match_type = 'payment_order',
- payment_order_ids = [x.id for x in candidates],
- account_id = account_id,
- partner_id = False,
- partner_bank_id = False,
- reference = False,
- type='general',
- )
- return False
-
def _match_invoice(self, cr, uid, trans, move_lines,
partner_ids, bank_account_ids,
log, linked_invoices,
@@ -542,101 +505,6 @@
{'voucher_id': voucher_id}, context=context)
transaction.refresh()
- def _confirm_storno(
- self, cr, uid, transaction_id, context=None):
- """
- Creation of the reconciliation has been delegated to
- *a* direct debit module, to allow for various direct debit styles
- """
- payment_line_pool = self.pool.get('payment.line')
- statement_line_pool = self.pool.get('account.bank.statement.line')
- transaction = self.browse(cr, uid, transaction_id, context=context)
- if not transaction.payment_line_id:
- raise osv.except_osv(
- _("Cannot link with storno"),
- _("No direct debit order item"))
- reconcile_id = payment_line_pool.debit_storno(
- cr, uid,
- transaction.payment_line_id.id,
- transaction.statement_line_id.amount,
- transaction.statement_line_id.currency,
- transaction.storno_retry,
- context=context)
- statement_line_pool.write(
- cr, uid, transaction.statement_line_id.id,
- {'reconcile_id': reconcile_id}, context=context)
- transaction.refresh()
-
- def _confirm_payment_order(
- self, cr, uid, transaction_id, context=None):
- """
- Creation of the reconciliation has been delegated to
- *a* direct debit module, to allow for various direct debit styles
- """
- payment_order_obj = self.pool.get('payment.order')
- statement_line_pool = self.pool.get('account.bank.statement.line')
- transaction = self.browse(cr, uid, transaction_id, context=context)
- if not transaction.payment_order_id:
- raise osv.except_osv(
- _("Cannot reconcile"),
- _("Cannot reconcile: no direct debit order"))
- if transaction.payment_order_id.payment_order_type != 'debit':
- raise osv.except_osv(
- _("Cannot reconcile"),
- _("Reconcile payment order not implemented"))
- reconcile_id = payment_order_obj.debit_reconcile_transfer(
- cr, uid,
- transaction.payment_order_id.id,
- transaction.statement_line_id.amount,
- transaction.statement_line_id.currency,
- context=context)
- statement_line_pool.write(
- cr, uid, transaction.statement_line_id.id,
- {'reconcile_id': reconcile_id}, context=context)
-
- def _confirm_payment(
- self, cr, uid, transaction_id, context=None):
- """
- Do some housekeeping on the payment line
- then pass on to _reconcile_move
- """
- transaction = self.browse(cr, uid, transaction_id, context=context)
- payment_line_obj = self.pool.get('payment.line')
- payment_line_obj.write(
- cr, uid, transaction.payment_line_id.id, {
- 'export_state': 'done',
- 'date_done': transaction.statement_line_id.date,
- }
- )
- self._confirm_move(cr, uid, transaction_id, context=context)
-
- def _cancel_payment(
- self, cr, uid, transaction_id, context=None):
- raise osv.except_osv(
- _("Cannot unreconcile"),
- _("Cannot unreconcile: this operation is not yet supported for "
- "match type 'payment'"))
-
- def _cancel_payment_order(
- self, cr, uid, transaction_id, context=None):
- """
- """
- payment_order_obj = self.pool.get('payment.order')
- transaction = self.browse(cr, uid, transaction_id, context=context)
- if not transaction.payment_order_id:
- raise osv.except_osv(
- _("Cannot unreconcile"),
- _("Cannot unreconcile: no direct debit order"))
- if transaction.payment_order_id.payment_order_type != 'debit':
- raise osv.except_osv(
- _("Cannot unreconcile"),
- _("Unreconcile payment order not implemented"))
- return payment_order_obj.debit_unreconcile_transfer(
- cr, uid, transaction.payment_order_id.id,
- transaction.statement_line_id.reconcile_id.id,
- transaction.statement_line_id.amount,
- transaction.statement_line_id.currency)
-
def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None):
"""
Legacy method. Allow for canceling bank statement lines that
@@ -768,70 +636,10 @@
return True
- def _cancel_storno(
- self, cr, uid, transaction_id, context=None):
- """
- TODO: delegate unreconciliation to the direct debit module,
- to allow for various direct debit styles
- """
- payment_line_obj = self.pool.get('payment.line')
- reconcile_obj = self.pool.get('account.move.reconcile')
- transaction = self.browse(cr, uid, transaction_id, context=context)
-
- if not transaction.payment_line_id:
- raise osv.except_osv(
- _("Cannot cancel link with storno"),
- _("No direct debit order item"))
- if not transaction.payment_line_id.storno:
- raise osv.except_osv(
- _("Cannot cancel link with storno"),
- _("The direct debit order item is not marked for storno"))
-
- journal = transaction.statement_line_id.statement_id.journal_id
- if transaction.statement_line_id.amount >= 0:
- account_id = journal.default_credit_account_id.id
- else:
- account_id = journal.default_debit_account_id.id
- cancel_line = False
- move_lines = []
- for move in transaction.statement_line_id.move_ids:
- # There should usually be just one move, I think
- move_lines += move.line_id
- for line in move_lines:
- if line.account_id.id != account_id:
- cancel_line = line
- break
- if not cancel_line:
- raise osv.except_osv(
- _("Cannot cancel link with storno"),
- _("Line id not found"))
- reconcile = cancel_line.reconcile_id or cancel_line.reconcile_partial_id
- lines_reconcile = reconcile.line_id or reconcile.line_partial_ids
- if len(lines_reconcile) < 3:
- # delete the full reconciliation
- reconcile_obj.unlink(cr, uid, reconcile.id, context)
- else:
- # we are left with a partial reconciliation
- reconcile_obj.write(
- cr, uid, reconcile.id,
- {'line_partial_ids':
- [(6, 0, [x.id for x in lines_reconcile if x.id != cancel_line.id])],
- 'line_id': [(6, 0, [])],
- }, context)
- # redo the original payment line reconciliation with the invoice
- payment_line_obj.write(
- cr, uid, transaction.payment_line_id.id,
- {'storno': False}, context)
- payment_line_obj.debit_reconcile(
- cr, uid, transaction.payment_line_id.id, context)
-
cancel_map = {
- 'storno': _cancel_storno,
'invoice': _cancel_voucher,
'manual': _cancel_voucher,
'move': _cancel_voucher,
- 'payment_order': _cancel_payment_order,
- 'payment': _cancel_payment,
}
def cancel(self, cr, uid, ids, context=None):
@@ -850,11 +658,8 @@
return True
confirm_map = {
- 'storno': _confirm_storno,
'invoice': _confirm_move,
'manual': _confirm_move,
- 'payment_order': _confirm_payment_order,
- 'payment': _confirm_payment,
'move': _confirm_move,
}
@@ -892,66 +697,6 @@
"""
return True
- def _match_storno(
- self, cr, uid, trans, log, context=None):
- payment_line_obj = self.pool.get('payment.line')
- line_ids = payment_line_obj.search(
- cr, uid, [
- ('order_id.payment_order_type', '=', 'debit'),
- ('order_id.state', 'in', ['sent', 'done']),
- ('communication', '=', trans.reference)
- ], context=context)
- # stornos MUST have an exact match
- if len(line_ids) == 1:
- account_id = payment_line_obj.get_storno_account_id(
- cr, uid, line_ids[0], trans.transferred_amount,
- trans.statement_id.currency, context=None)
- if account_id:
- return dict(
- account_id = account_id,
- match_type = 'storno',
- payment_line_id = line_ids[0],
- move_line_ids=False,
- partner_id=False,
- partner_bank_id=False,
- reference=False,
- type='customer',
- )
- # TODO log the reason why there is no result for transfers marked
- # as storno
- return False
-
- def _match_payment(self, cr, uid, trans, payment_lines,
- partner_ids, bank_account_ids, log, linked_payments):
- '''
- Find the payment order belonging to this reference - if there is one
- This is the easiest part: when sending payments, the returned bank info
- should be identical to ours.
- This also means that we do not allow for multiple candidates.
- '''
- # TODO: Not sure what side effects are created when payments are done
- # for credited customer invoices, which will be matched later on too.
- digits = dp.get_precision('Account')(cr)[1]
- candidates = [x for x in payment_lines
- if x.communication == trans.reference
- and round(x.amount, digits) == -round(trans.transferred_amount, digits)
- and trans.remote_account in (x.bank_id.acc_number,
- x.bank_id.acc_number_domestic)
- ]
- if len(candidates) == 1:
- candidate = candidates[0]
- # Check cache to prevent multiple matching of a single payment
- if candidate.id not in linked_payments:
- linked_payments[candidate.id] = True
- move_info = self._get_move_info(cr, uid, [candidate.move_line_id.id])
- move_info.update({
- 'match_type': 'payment',
- 'payment_line_id': candidate.id,
- })
- return move_info
-
- return False
-
signal_duplicate_keys = [
# does not include float values
# such as transferred_amount
@@ -1059,6 +804,22 @@
retval['invoice_ids'] = [x.invoice.id for x in move_lines]
retval['type'] = type_map[move_lines[0].invoice.type]
return retval
+
+ def move_info2values(self, move_info):
+ vals = {}
+ vals['match_type'] = move_info['match_type']
+ vals['move_line_ids'] = [(6, 0, move_info.get('move_line_ids') or [])]
+ vals['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])]
+ vals['move_line_id'] = (move_info.get('move_line_ids', False) and
+ len(move_info['move_line_ids']) == 1 and
+ move_info['move_line_ids'][0]
+ )
+ if move_info['match_type'] == 'invoice':
+ vals['invoice_id'] = (move_info.get('invoice_ids', False) and
+ len(move_info['invoice_ids']) == 1 and
+ move_info['invoice_ids'][0]
+ )
+ return vals
def match(self, cr, uid, ids, results=None, context=None):
if not ids:
@@ -1069,6 +830,7 @@
journal_obj = self.pool.get('account.journal')
move_line_obj = self.pool.get('account.move.line')
payment_line_obj = self.pool.get('payment.line')
+ has_payment = bool(payment_line_obj)
statement_line_obj = self.pool.get('account.bank.statement.line')
statement_obj = self.pool.get('account.bank.statement')
payment_order_obj = self.pool.get('payment.order')
@@ -1098,14 +860,15 @@
# communication. Most likely there are much less sent payments
# than reconciled and open/draft payments.
# Strangely, payment_orders still do not have company_id
- cr.execute("SELECT l.id FROM payment_order o, payment_line l "
- "WHERE l.order_id = o.id AND "
- "o.state = 'sent' AND "
- "l.date_done IS NULL"
- )
- payment_line_ids = [x[0] for x in cr.fetchall()]
- if payment_line_ids:
- payment_lines = payment_line_obj.browse(cr, uid, payment_line_ids)
+ if has_payment:
+ payment_line_ids = payment_line_obj.search(
+ cr, uid, [
+ ('order_id.state', '=', 'sent'),
+ ('date_done', '=', False)], context=context)
+ payment_lines = payment_line_obj.browse(
+ cr, uid, payment_line_ids)
+ else:
+ payment_lines = False
# Start the loop over the transactions requested to match
transactions = self.browse(cr, uid, ids, context)
@@ -1270,10 +1033,10 @@
# rebrowse the current record after writing
transaction = self.browse(cr, uid, transaction.id, context=context)
# Match full direct debit orders
- if transaction.type == bt.DIRECT_DEBIT:
+ if transaction.type == bt.DIRECT_DEBIT and has_payment:
move_info = self._match_debit_order(
cr, uid, transaction, results['log'], context)
- if transaction.type == bt.STORNO:
+ if transaction.type == bt.STORNO and has_payment:
move_info = self._match_storno(
cr, uid, transaction, results['log'], context)
# Allow inclusion of generated bank invoices
@@ -1340,6 +1103,10 @@
if (not move_info
and transaction.transferred_amount < 0 and payment_lines):
# Link open payment - if any
+ # Note that _match_payment is defined in the
+ # account_banking_payment module which should be installed
+ # automatically if account_payment is. And if account_payment
+ # is not installed, then payment_lines will be empty.
move_info = self._match_payment(
cr, uid, transaction,
payment_lines, partner_ids,
@@ -1385,28 +1152,12 @@
self_values = {}
if move_info:
results['trans_matched_cnt'] += 1
- self_values['match_type'] = move_info['match_type']
- self_values['payment_line_id'] = move_info.get('payment_line_id', False)
- self_values['move_line_ids'] = [(6, 0, move_info.get('move_line_ids') or [])]
- self_values['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])]
- self_values['payment_order_ids'] = [(6, 0, move_info.get('payment_order_ids') or [])]
- self_values['payment_order_id'] = (move_info.get('payment_order_ids', False) and
- len(move_info['payment_order_ids']) == 1 and
- move_info['payment_order_ids'][0]
- )
- self_values['move_line_id'] = (move_info.get('move_line_ids', False) and
- len(move_info['move_line_ids']) == 1 and
- move_info['move_line_ids'][0]
- )
- if move_info['match_type'] == 'invoice':
- self_values['invoice_id'] = (move_info.get('invoice_ids', False) and
- len(move_info['invoice_ids']) == 1 and
- move_info['invoice_ids'][0]
- )
+ self_values.update(
+ self.move_info2values(move_info))
+ # values['match_type'] = move_info['match_type']
values['partner_id'] = move_info['partner_id']
values['partner_bank_id'] = move_info['partner_bank_id']
values['type'] = move_info['type']
- # values['match_type'] = move_info['match_type']
else:
values['partner_id'] = values['partner_bank_id'] = False
if not values['partner_id'] and partner_ids and len(partner_ids) == 1:
@@ -1446,34 +1197,6 @@
statement_obj.button_dummy(
cr, uid, imported_statement_ids, context=context)
- if payment_lines:
- # As payments lines are treated as individual transactions, the
- # batch as a whole is only marked as 'done' when all payment lines
- # have been reconciled.
- cr.execute(
- "SELECT DISTINCT o.id "
- "FROM payment_order o, payment_line l "
- "WHERE o.state = 'sent' "
- "AND o.id = l.order_id "
- "AND o.id NOT IN ("
- "SELECT DISTINCT order_id AS id "
- "FROM payment_line "
- "WHERE date_done IS NULL "
- "AND id IN (%s)"
- ")" % (','.join([str(x) for x in payment_line_ids]))
- )
- order_ids = [x[0] for x in cr.fetchall()]
- if order_ids:
- # Use workflow logics for the orders. Recode logic from
- # account_payment, in order to increase efficiency.
- payment_order_obj.set_done(cr, uid, order_ids,
- {'state': 'done'}
- )
- wf_service = netsvc.LocalService('workflow')
- for id in order_ids:
- wf_service.trg_validate(
- uid, 'payment.order', id, 'done', cr)
-
def _get_residual(self, cr, uid, ids, name, args, context=None):
"""
Calculate the residual against the candidate reconciliation.
@@ -1518,10 +1241,6 @@
elif transaction.match_type == 'invoice':
if transaction.invoice_ids and not transaction.invoice_id:
res[transaction.id] = True
- elif transaction.match_type == 'payment_order':
- if (transaction.payment_order_ids and not
- transaction.payment_order_id):
- res[transaction.id] = True
return res
def clear_and_write(self, cr, uid, ids, vals=None, context=None):
@@ -1535,12 +1254,10 @@
'invoice_id',
'manual_invoice_id',
'manual_move_line_id',
- 'payment_line_id',
]] +
[(x, [(6, 0, [])]) for x in [
'move_line_ids',
'invoice_ids',
- 'payment_order_ids',
]]))
write_vals.update(vals or {})
return self.write(cr, uid, ids, write_vals, context=context)
@@ -1645,23 +1362,15 @@
# match fields
'match_type': fields.selection(
[('manual', 'Manual'), ('move','Move'), ('invoice', 'Invoice'),
- ('payment', 'Payment'), ('payment_order', 'Payment order'),
- ('storno', 'Storno')],
- 'Match type'),
+ ], 'Match type'),
'match_multi': fields.function(
_get_match_multi, method=True, string='Multi match',
type='boolean'),
- 'payment_order_ids': fields.many2many(
- 'payment.order', 'banking_transaction_payment_order_rel',
- 'order_id', 'transaction_id', 'Payment orders'),
- 'payment_order_id': fields.many2one(
- 'payment.order', 'Payment order to reconcile'),
'move_line_ids': fields.many2many(
'account.move.line', 'banking_transaction_move_line_rel',
'move_line_id', 'transaction_id', 'Matching entries'),
'move_line_id': fields.many2one(
'account.move.line', 'Entry to reconcile'),
- 'payment_line_id': fields.many2one('payment.line', 'Payment line'),
'invoice_ids': fields.many2many(
'account.invoice', 'banking_transaction_invoice_rel',
'invoice_id', 'transaction_id', 'Matching invoices'),
@@ -1722,9 +1431,8 @@
'match_type': fields.related(
'import_transaction_id', 'match_type', type='selection',
selection=[('manual', 'Manual'), ('move','Move'),
- ('invoice', 'Invoice'), ('payment', 'Payment'),
- ('payment_order', 'Payment order'),
- ('storno', 'Storno')],
+ ('invoice', 'Invoice'),
+ ],
string='Match type', readonly=True,),
'state': fields.selection(
[('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',
=== modified file 'account_banking/data/account_banking_data.xml'
--- account_banking/data/account_banking_data.xml 2012-04-14 08:58:58 +0000
+++ account_banking/data/account_banking_data.xml 2013-04-06 05:04:22 +0000
@@ -20,12 +20,5 @@
<record id="base_iban.bank_swift_field" model="res.partner.bank.type.field">
<field eval="False" name="required"/>
</record>
- <!-- Add manual bank transfer as default payment option -->
- <record model="payment.mode.type" id="account_banking.manual_bank_tranfer">
- <field name="name">Manual Bank Transfer</field>
- <field name="code">BANKMAN</field>
- <field name="suitable_bank_types"
- eval="[(6,0,[ref('base.bank_normal'),ref('base_iban.bank_iban'),])]" />
- </record>
</data>
</openerp>
=== modified file 'account_banking/security/ir.model.access.csv'
--- account_banking/security/ir.model.access.csv 2011-12-21 15:49:58 +0000
+++ account_banking/security/ir.model.access.csv 2013-04-06 05:04:22 +0000
@@ -2,6 +2,5 @@
"access_account_banking_settings","account.banking.account.settings","model_account_banking_account_settings","account.group_account_manager",1,1,1,1
"access_account_banking_settings_user","account.banking.account.settings user","model_account_banking_account_settings","account.group_account_user",1,0,0,0
"access_account_banking_import","account.bankimport","model_account_banking_imported_file","account.group_account_user",1,1,1,1
-"access_payment_mode_type","payment.mode.type","model_payment_mode_type","account_payment.group_account_payment",1,1,1,1
"access_banking_import_transaction","Banking addons - Bank import transaction","model_banking_import_transaction","account.group_account_user",1,1,1,1
"access_banking_transaction_wizard","Banking addons - Transaction wizard","model_banking_transaction_wizard","account.group_account_user",1,1,1,1
=== modified file 'account_banking/wizard/__init__.py'
--- account_banking/wizard/__init__.py 2011-12-19 12:03:32 +0000
+++ account_banking/wizard/__init__.py 2013-04-06 05:04:22 +0000
@@ -19,8 +19,6 @@
#
##############################################################################
import bank_import
-import bank_payment_manual
-import account_payment_order
import banking_transaction_wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
=== modified file 'account_banking/wizard/bank_import.py'
--- account_banking/wizard/bank_import.py 2012-07-11 10:37:31 +0000
+++ account_banking/wizard/bank_import.py 2013-04-06 05:04:22 +0000
@@ -85,13 +85,10 @@
'invoice_ids': fields.many2many(
'account.invoice', 'banking_import_line_invoice_rel',
'line_id', 'invoice_id'),
- 'payment_order_id': fields.many2one('payment.order', 'Payment order'),
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'),
'transaction_type': fields.selection([
# TODO: payment terminal etc...
('invoice', 'Invoice payment'),
- ('payment_order_line', 'Payment from a payment order'),
- ('payment_order', 'Aggregate payment order'),
('storno', 'Canceled debit order'),
('bank_costs', 'Bank costs'),
('unknown', 'Unknown'),
=== modified file 'account_banking/wizard/banking_transaction_wizard.py'
--- account_banking/wizard/banking_transaction_wizard.py 2012-12-01 18:31:34 +0000
+++ account_banking/wizard/banking_transaction_wizard.py 2013-04-06 05:04:22 +0000
@@ -320,15 +320,6 @@
'import_transaction_id', 'writeoff_journal_id',
type='many2one', relation='account.journal',
string='Write-off journal'),
- 'payment_line_id': fields.related(
- 'import_transaction_id', 'payment_line_id', string="Matching payment or storno",
- type='many2one', relation='payment.line', readonly=True),
- 'payment_order_ids': fields.related(
- 'import_transaction_id', 'payment_order_ids', string="Matching payment orders",
- type='many2many', relation='payment.order'),
- 'payment_order_id': fields.related(
- 'import_transaction_id', 'payment_order_id', string="Payment order to reconcile",
- type='many2one', relation='payment.order'),
'invoice_ids': fields.related(
'import_transaction_id', 'invoice_ids', string="Matching invoices",
type='many2many', relation='account.invoice'),
=== modified file 'account_banking/wizard/banking_transaction_wizard.xml'
--- account_banking/wizard/banking_transaction_wizard.xml 2013-01-13 14:11:44 +0000
+++ account_banking/wizard/banking_transaction_wizard.xml 2013-04-06 05:04:22 +0000
@@ -8,7 +8,6 @@
<field name="arch" type="xml">
<form string="Match transaction">
<!-- fields used for form logic -->
- <field name="payment_order_ids" invisible="True"/>
<field name="invoice_ids" invisible="True"/>
<field name="move_line_ids" invisible="True"/>
<field name="match_multi" invisible="True"/>
@@ -36,9 +35,6 @@
<separator string="Multiple matches" colspan="2"/>
<label colspan="2" string="Multiple matches were found for this bank transfer. You must pick one of the matches or select a match manually below." />
</group>
- <field name='payment_line_id'
- attrs="{'invisible': [('match_type', '!=', 'storno'),('match_type', '!=', 'payment')]}"
- />
<group attrs="{'readonly': [('match_multi', '!=', True)]}" col="8">
<!-- show if we have an invoice type match (but the user may need to select from multiple options)
or whenever there is an invoice_id (e.g. in case of a manual match)
@@ -53,10 +49,6 @@
attrs="{'readonly': [('match_multi', '=', False)], 'invisible': [('match_type', '!=', 'move'),('invoice_id', '=', False)]}"
domain="[('id', 'in', move_line_ids[0][2])]"
/>
- <field name='payment_order_id'
- attrs="{'readonly': [('match_multi', '=', False)], 'invisible': [('match_type', '!=', 'payment_order')]}"
- domain="[('id', 'in', payment_order_ids[0][2])]"
- />
<field name='analytic_account_id' />
</group>
<button colspan="1"
=== modified file 'account_banking_nl_clieop/__terp__.py'
--- account_banking_nl_clieop/__terp__.py 2011-12-27 12:00:52 +0000
+++ account_banking_nl_clieop/__terp__.py 2013-04-06 05:04:22 +0000
@@ -30,7 +30,7 @@
'author': 'EduSense BV',
'website': 'http://www.edusense.nl',
'category': 'Account Banking',
- 'depends': ['account_banking'],
+ 'depends': ['account_banking_payment'],
'init_xml': [],
'update_xml': [
'account_banking_nl_clieop.xml',
=== added directory 'account_banking_payment'
=== added file 'account_banking_payment/__init__.py'
--- account_banking_payment/__init__.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/__init__.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,1 @@
+import model
=== added file 'account_banking_payment/__openerp__.py'
--- account_banking_payment/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/__openerp__.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+ 'name': 'Account Banking - Payments',
+ 'version': '0.1.164',
+ 'license': 'AGPL-3',
+ 'author': 'Banking addons community',
+ 'website': 'https://launchpad.net/banking-addons',
+ 'category': 'Banking addons',
+ 'depends': [
+ 'account_banking',
+ 'account_payment',
+ ],
+ 'data': [
+ 'view/account_payment.xml',
+ 'view/banking_transaction_wizard.xml',
+ 'view/payment_mode_type.xml',
+ 'view/bank_payment_manual.xml',
+ 'data/payment_mode_type.xml',
+ 'workflow/account_payment.xml',
+ 'security/ir.model.access.csv',
+ ],
+ 'description': '''
+ This addon adds payment infrastructure to the Banking Addons.
+
+ * Extends payments for digital banking:
+ + Adapted workflow in payments to reflect banking operations
+ + Relies on account_payment mechanics to extend with export generators.
+ - ClieOp3 (NL) payment and direct debit orders files available as
+ account_banking_nl_clieop
+ ''',
+ 'auto_install': True,
+ 'installable': False,
+}
=== added directory 'account_banking_payment/data'
=== added file 'account_banking_payment/data/payment_mode_type.xml'
--- account_banking_payment/data/payment_mode_type.xml 1970-01-01 00:00:00 +0000
+++ account_banking_payment/data/payment_mode_type.xml 2013-04-06 05:04:22 +0000
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <!-- Add manual bank transfer as default payment option -->
+ <record model="payment.mode.type" id="account_banking.manual_bank_tranfer">
+ <field name="name">Manual Bank Transfer</field>
+ <field name="code">BANKMAN</field>
+ <field name="suitable_bank_types"
+ eval="[(6,0,[ref('base.bank_normal'),ref('base_iban.bank_iban'),])]" />
+ <field name="ir_model_id"
+ ref="account_banking_payment.model_payment_manual"/>
+ </record>
+ </data>
+</openerp>
=== added directory 'account_banking_payment/model'
=== added file 'account_banking_payment/model/__init__.py'
--- account_banking_payment/model/__init__.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/__init__.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,10 @@
+import account_payment
+import payment_line
+import payment_mode
+import payment_mode_type
+import payment_order_create
+import banking_import_transaction
+import account_bank_statement_line
+import banking_transaction_wizard
+import bank_payment_manual
+import banking_import_line
=== added file 'account_banking_payment/model/account_bank_statement_line.py'
--- account_banking_payment/model/account_bank_statement_line.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/account_bank_statement_line.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class account_bank_statement_line(orm.Model):
+ _inherit = 'account.bank.statement.line'
+ _columns = {
+ 'match_type': fields.related(
+ # Add payment and storno types
+ 'import_transaction_id', 'match_type', type='selection',
+ selection=[('manual', 'Manual'), ('move','Move'),
+ ('invoice', 'Invoice'), ('payment', 'Payment'),
+ ('payment_order', 'Payment order'),
+ ('storno', 'Storno')],
+ string='Match type', readonly=True,),
+ }
=== added file 'account_banking_payment/model/account_payment.py'
--- account_banking_payment/model/account_payment.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/account_payment.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,240 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+from openerp.tools.translate import _
+from openerp import netsvc
+
+
+class payment_order(orm.Model):
+ '''
+ Enable extra states for payment exports
+ '''
+ _inherit = 'payment.order'
+
+ _columns = {
+ 'date_scheduled': fields.date(
+ 'Scheduled date if fixed',
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ help='Select a date if you have chosen Preferred Date to be fixed.'
+ ),
+ 'reference': fields.char(
+ 'Reference', size=128, required=True,
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'mode': fields.many2one(
+ 'payment.mode', 'Payment mode', select=True, required=True,
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ help='Select the Payment Mode to be applied.',
+ ),
+ 'state': fields.selection([
+ ('draft', 'Draft'),
+ ('open','Confirmed'),
+ ('cancel','Cancelled'),
+ ('sent', 'Sent'),
+ ('rejected', 'Rejected'),
+ ('done','Done'),
+ ], 'State', select=True
+ ),
+ 'line_ids': fields.one2many(
+ 'payment.line', 'order_id', 'Payment lines',
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'user_id': fields.many2one(
+ 'res.users','User', required=True,
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'date_prefered': fields.selection([
+ ('now', 'Directly'),
+ ('due', 'Due date'),
+ ('fixed', 'Fixed date')
+ ], "Preferred date", change_default=True, required=True,
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ help=("Choose an option for the Payment Order:'Fixed' stands for a "
+ "date specified by you.'Directly' stands for the direct "
+ "execution.'Due date' stands for the scheduled date of "
+ "execution."
+ )
+ ),
+ 'payment_order_type': fields.selection(
+ [('payment', 'Payment'),('debit', 'Direct debit')],
+ 'Payment order type', required=True,
+ ),
+ 'date_sent': fields.date('Send date', readonly=True),
+ }
+
+ _defaults = {
+ 'payment_order_type': 'payment',
+ }
+
+ def launch_wizard(self, cr, uid, ids, context=None):
+ """
+ Search for a wizard to launch according to the type.
+ If type is manual. just confirm the order.
+ Previously (pre-v6) in account_payment/wizard/wizard_pay.py
+ """
+ if context == None:
+ context = {}
+ result = {}
+ orders = self.browse(cr, uid, ids, context)
+ order = orders[0]
+ # check if a wizard is defined for the first order
+ if order.mode.type and order.mode.type.ir_model_id:
+ context['active_ids'] = ids
+ wizard_model = order.mode.type.ir_model_id.model
+ wizard_obj = self.pool.get(wizard_model)
+ wizard_id = wizard_obj.create(cr, uid, {}, context)
+ result = {
+ 'name': wizard_obj._description or _('Payment Order Export'),
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': wizard_model,
+ 'domain': [],
+ 'context': context,
+ 'type': 'ir.actions.act_window',
+ 'target': 'new',
+ 'res_id': wizard_id,
+ 'nodestroy': True,
+ }
+ else:
+ # should all be manual orders without type or wizard model
+ for order in orders[1:]:
+ if order.mode.type and order.mode.type.ir_model_id:
+ raise orm.except_orm(
+ _('Error'),
+ _('You can only combine payment orders of the same type')
+ )
+ # process manual payments
+ wf_service = netsvc.LocalService('workflow')
+ for order_id in ids:
+ wf_service.trg_validate(uid, 'payment.order', order_id, 'sent', cr)
+ return result
+
+ def _write_payment_lines(self, cr, uid, ids, **kwargs):
+ '''
+ ORM method for setting attributes of corresponding payment.line objects.
+ Note that while this is ORM compliant, it is also very ineffecient due
+ to the absence of filters on writes and hence the requirement to
+ filter on the client(=OpenERP server) side.
+ '''
+ if not hasattr(ids, '__iter__'):
+ ids = [ids]
+ payment_line_obj = self.pool.get('payment.line')
+ line_ids = payment_line_obj.search(
+ cr, uid, [
+ ('order_id', 'in', ids)
+ ])
+ payment_line_obj.write(cr, uid, line_ids, kwargs)
+
+ def set_to_draft(self, cr, uid, ids, *args):
+ '''
+ Set both self and payment lines to state 'draft'.
+ '''
+ self._write_payment_lines(cr, uid, ids, export_state='draft')
+ return super(payment_order, self).set_to_draft(
+ cr, uid, ids, *args
+ )
+
+ def action_sent(self, cr, uid, ids, context=None):
+ '''
+ Set both self and payment lines to state 'sent'.
+ '''
+ self._write_payment_lines(cr, uid, ids, export_state='sent')
+ self.write(cr, uid, ids, {
+ 'state': 'sent',
+ 'date_sent': fields.date.context_today(
+ self, cr, uid, context=context),
+ }, context=context)
+ return True
+
+ def action_rejected(self, cr, uid, ids, *args):
+ '''
+ Set both self and payment lines to state 'rejected'.
+ '''
+ self._write_payment_lines(cr, uid, ids, export_state='rejected')
+ wf_service = netsvc.LocalService('workflow')
+ for id in ids:
+ wf_service.trg_validate(uid, 'payment.order', id, 'rejected', cr)
+ return True
+
+ def set_done(self, cr, uid, ids, *args):
+ '''
+ Extend standard transition to update children as well.
+ '''
+ self._write_payment_lines(
+ cr, uid, ids,
+ export_state='done',
+ date_done=fields.date.context_today(self, cr, uid))
+ return super(payment_order, self).set_done(
+ cr, uid, ids, *args
+ )
+
+ """
+ Hooks for processing direct debit orders, such as implemented in
+ account_direct_debit module.
+ """
+ def debit_reconcile_transfer(
+ self, cr, uid, payment_order_id, amount, currency, context=None):
+ """
+ Reconcile the payment order if the amount is correct. Return the
+ id of the reconciliation.
+ """
+ raise orm.except_orm(
+ _("Cannot reconcile"),
+ _("Cannot reconcile debit order: "+
+ "Not implemented."))
+
+ def debit_unreconcile_transfer(
+ self, cr, uid, payment_order_id, reconcile_id, amount, currency,
+ context=None):
+ """ Unreconcile the payment_order if at all possible """
+ raise orm.except_orm(
+ _("Cannot unreconcile"),
+ _("Cannot unreconcile debit order: "+
+ "Not implemented."))
=== renamed file 'account_banking/wizard/bank_payment_manual.py' => 'account_banking_payment/model/bank_payment_manual.py'
--- account_banking/wizard/bank_payment_manual.py 2010-12-20 10:58:51 +0000
+++ account_banking_payment/model/bank_payment_manual.py 2013-04-06 05:04:22 +0000
@@ -1,20 +1,24 @@
-# -*- encoding: utf-8 -*-
+# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# GNU Affero General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
+# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -24,30 +28,26 @@
bank transfers.
'''
-import wizard
-import pooler
-
-class payment_manual(wizard.interface):
- def _action_set_state_sent(self, cursor, uid, data, context):
- '''
- Set the payment order in state 'sent' to reflect money in transfer.
- '''
- payment_order_obj = pooler.get_pool(cursor.dbname)\
- .get('payment.order')
- payment_order_obj.action_sent(cursor, uid, [data['id']], context)
- return {}
-
- states= {
- 'init' : {
- 'actions': [],
- 'result': {
- 'type':'action',
- 'action': _action_set_state_sent,
- 'state': 'end'
- }
+from openerp.osv import orm, fields
+from openerp import netsvc
+
+
+class payment_manual(orm.TransientModel):
+ _name = 'payment.manual'
+ _description = 'Set payment orders to \'sent\' manually'
+
+ def default_get(self, cr, uid, fields_list, context=None):
+ if context and context.get('active_ids'):
+ payment_order_obj = self.pool.get('payment.order')
+ wf_service = netsvc.LocalService('workflow')
+ for order_id in context['active_ids']:
+ wf_service.trg_validate(
+ uid, 'payment.order', order_id, 'sent', cr)
+ return super(payment_manual, self).default_get(
+ cr, uid, fields_list, context=None)
+
+ _columns = {
+ # dummy field, to trigger a call to default_get
+ 'name': fields.char('Name', size=1),
}
- }
-
-payment_manual('account_banking.payment_manual')
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
=== added file 'account_banking_payment/model/banking_import_line.py'
--- account_banking_payment/model/banking_import_line.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/banking_import_line.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class banking_import_line(orm.TransientModel):
+ _inherit = 'banking.import.line'
+ _columns = {
+ 'payment_order_id': fields.many2one(
+ 'payment.order', 'Payment order'),
+ 'transaction_type': fields.selection([
+ # Add payment order related transaction types
+ ('invoice', 'Invoice payment'),
+ ('payment_order_line', 'Payment from a payment order'),
+ ('payment_order', 'Aggregate payment order'),
+ ('storno', 'Canceled debit order'),
+ ('bank_costs', 'Bank costs'),
+ ('unknown', 'Unknown'),
+ ], 'Transaction type'),
+ }
+
+
=== added file 'account_banking_payment/model/banking_import_transaction.py'
--- account_banking_payment/model/banking_import_transaction.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/banking_import_transaction.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,388 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+from openerp import netsvc
+from openerp.tools.translate import _
+from openerp.addons.decimal_precision import decimal_precision as dp
+
+
+class banking_import_transaction(orm.Model):
+ _inherit = 'banking.import.transaction'
+
+ def _match_debit_order(
+ self, cr, uid, trans, log, context=None):
+
+ def is_zero(total):
+ return self.pool.get('res.currency').is_zero(
+ cr, uid, trans.statement_id.currency, total)
+
+ payment_order_obj = self.pool.get('payment.order')
+
+ order_ids = payment_order_obj.search(
+ cr, uid, [('payment_order_type', '=', 'debit'),
+ ('state', '=', 'sent'),
+ ('date_sent', '<=', trans.execution_date),
+ ],
+ limit=0, context=context)
+ orders = payment_order_obj.browse(cr, uid, order_ids, context)
+ candidates = [x for x in orders if
+ is_zero(x.total - trans.transferred_amount)]
+ if len(candidates) > 0:
+ # retrieve the common account_id, if any
+ account_id = False
+ for line in candidates[0].line_ids[0].debit_move_line_id.move_id.line_id:
+ if line.account_id.type == 'other':
+ account_id = line.account_id.id
+ break
+ return dict(
+ move_line_ids = False,
+ match_type = 'payment_order',
+ payment_order_ids = [x.id for x in candidates],
+ account_id = account_id,
+ partner_id = False,
+ partner_bank_id = False,
+ reference = False,
+ type='general',
+ )
+ return False
+
+ def _match_storno(
+ self, cr, uid, trans, log, context=None):
+ payment_line_obj = self.pool.get('payment.line')
+ line_ids = payment_line_obj.search(
+ cr, uid, [
+ ('order_id.payment_order_type', '=', 'debit'),
+ ('order_id.state', 'in', ['sent', 'done']),
+ ('communication', '=', trans.reference)
+ ], context=context)
+ # stornos MUST have an exact match
+ if len(line_ids) == 1:
+ account_id = payment_line_obj.get_storno_account_id(
+ cr, uid, line_ids[0], trans.transferred_amount,
+ trans.statement_id.currency, context=None)
+ if account_id:
+ return dict(
+ account_id = account_id,
+ match_type = 'storno',
+ payment_line_id = line_ids[0],
+ move_line_ids=False,
+ partner_id=False,
+ partner_bank_id=False,
+ reference=False,
+ type='customer',
+ )
+ # TODO log the reason why there is no result for transfers marked
+ # as storno
+ return False
+
+ def _match_payment(self, cr, uid, trans, payment_lines,
+ partner_ids, bank_account_ids, log, linked_payments):
+ '''
+ Find the payment order belonging to this reference - if there is one
+ This is the easiest part: when sending payments, the returned bank info
+ should be identical to ours.
+ This also means that we do not allow for multiple candidates.
+ '''
+ # TODO: Not sure what side effects are created when payments are done
+ # for credited customer invoices, which will be matched later on too.
+ digits = dp.get_precision('Account')(cr)[1]
+ candidates = [
+ x for x in payment_lines
+ if x.communication == trans.reference
+ and round(x.amount, digits) == -round(
+ trans.transferred_amount, digits)
+ and trans.remote_account in (x.bank_id.acc_number,
+ x.bank_id.acc_number_domestic)
+ ]
+ if len(candidates) == 1:
+ candidate = candidates[0]
+ # Check cache to prevent multiple matching of a single payment
+ if candidate.id not in linked_payments:
+ linked_payments[candidate.id] = True
+ move_info = self._get_move_info(
+ cr, uid, [candidate.move_line_id.id])
+ move_info.update({
+ 'match_type': 'payment',
+ 'payment_line_id': candidate.id,
+ })
+ return move_info
+
+ return False
+
+ def _confirm_storno(
+ self, cr, uid, transaction_id, context=None):
+ """
+ Creation of the reconciliation has been delegated to
+ *a* direct debit module, to allow for various direct debit styles
+ """
+ payment_line_pool = self.pool.get('payment.line')
+ statement_line_pool = self.pool.get('account.bank.statement.line')
+ transaction = self.browse(cr, uid, transaction_id, context=context)
+ if not transaction.payment_line_id:
+ raise orm.except_orm(
+ _("Cannot link with storno"),
+ _("No direct debit order item"))
+ reconcile_id = payment_line_pool.debit_storno(
+ cr, uid,
+ transaction.payment_line_id.id,
+ transaction.statement_line_id.amount,
+ transaction.statement_line_id.currency,
+ transaction.storno_retry,
+ context=context)
+ statement_line_pool.write(
+ cr, uid, transaction.statement_line_id.id,
+ {'reconcile_id': reconcile_id}, context=context)
+ transaction.refresh()
+
+ def _confirm_payment_order(
+ self, cr, uid, transaction_id, context=None):
+ """
+ Creation of the reconciliation has been delegated to
+ *a* direct debit module, to allow for various direct debit styles
+ """
+ payment_order_obj = self.pool.get('payment.order')
+ statement_line_pool = self.pool.get('account.bank.statement.line')
+ transaction = self.browse(cr, uid, transaction_id, context=context)
+ if not transaction.payment_order_id:
+ raise orm.except_orm(
+ _("Cannot reconcile"),
+ _("Cannot reconcile: no direct debit order"))
+ if transaction.payment_order_id.payment_order_type != 'debit':
+ raise orm.except_orm(
+ _("Cannot reconcile"),
+ _("Reconcile payment order not implemented"))
+ reconcile_id = payment_order_obj.debit_reconcile_transfer(
+ cr, uid,
+ transaction.payment_order_id.id,
+ transaction.statement_line_id.amount,
+ transaction.statement_line_id.currency,
+ context=context)
+ statement_line_pool.write(
+ cr, uid, transaction.statement_line_id.id,
+ {'reconcile_id': reconcile_id}, context=context)
+
+ def _confirm_payment(
+ self, cr, uid, transaction_id, context=None):
+ """
+ Do some housekeeping on the payment line
+ then pass on to _reconcile_move
+ """
+ transaction = self.browse(cr, uid, transaction_id, context=context)
+ payment_line_obj = self.pool.get('payment.line')
+ payment_line_obj.write(
+ cr, uid, transaction.payment_line_id.id, {
+ 'export_state': 'done',
+ 'date_done': transaction.statement_line_id.date,
+ }
+ )
+ self._confirm_move(cr, uid, transaction_id, context=context)
+ # Check if the payment order is 'done'
+ order_id = transaction.payment_line_id.order_id.id
+ other_lines = payment_line_obj.search(
+ cr, uid, [
+ ('order_id', '=', order_id),
+ ('date_done', '=', False),
+ ], context=context)
+ if not other_lines:
+ wf_service = netsvc.LocalService('workflow')
+ wf_service.trg_validate(
+ uid, 'payment.order', order_id, 'done', cr)
+
+ def _cancel_payment(
+ self, cr, uid, transaction_id, context=None):
+ """
+ Do not support cancelling individual lines yet, because the workflow
+ of the payment order does not support reopening.
+ """
+ raise orm.except_orm(
+ _("Cannot unreconcile"),
+ _("Cannot unreconcile: this operation is not yet supported for "
+ "match type 'payment'"))
+
+ def _cancel_payment_order(
+ self, cr, uid, transaction_id, context=None):
+ """
+ """
+ payment_order_obj = self.pool.get('payment.order')
+ transaction = self.browse(cr, uid, transaction_id, context=context)
+ if not transaction.payment_order_id:
+ raise orm.except_orm(
+ _("Cannot unreconcile"),
+ _("Cannot unreconcile: no direct debit order"))
+ if transaction.payment_order_id.payment_order_type != 'debit':
+ raise orm.except_orm(
+ _("Cannot unreconcile"),
+ _("Unreconcile payment order not implemented"))
+ return payment_order_obj.debit_unreconcile_transfer(
+ cr, uid, transaction.payment_order_id.id,
+ transaction.statement_line_id.reconcile_id.id,
+ transaction.statement_line_id.amount,
+ transaction.statement_line_id.currency)
+
+ def _cancel_storno(
+ self, cr, uid, transaction_id, context=None):
+ """
+ TODO: delegate unreconciliation to the direct debit module,
+ to allow for various direct debit styles
+ """
+ payment_line_obj = self.pool.get('payment.line')
+ reconcile_obj = self.pool.get('account.move.reconcile')
+ transaction = self.browse(cr, uid, transaction_id, context=context)
+
+ if not transaction.payment_line_id:
+ raise orm.except_orm(
+ _("Cannot cancel link with storno"),
+ _("No direct debit order item"))
+ if not transaction.payment_line_id.storno:
+ raise orm.except_orm(
+ _("Cannot cancel link with storno"),
+ _("The direct debit order item is not marked for storno"))
+
+ journal = transaction.statement_line_id.statement_id.journal_id
+ if transaction.statement_line_id.amount >= 0:
+ account_id = journal.default_credit_account_id.id
+ else:
+ account_id = journal.default_debit_account_id.id
+ cancel_line = False
+ move_lines = []
+ for move in transaction.statement_line_id.move_ids:
+ # There should usually be just one move, I think
+ move_lines += move.line_id
+ for line in move_lines:
+ if line.account_id.id != account_id:
+ cancel_line = line
+ break
+ if not cancel_line:
+ raise orm.except_orm(
+ _("Cannot cancel link with storno"),
+ _("Line id not found"))
+ reconcile = cancel_line.reconcile_id or cancel_line.reconcile_partial_id
+ lines_reconcile = reconcile.line_id or reconcile.line_partial_ids
+ if len(lines_reconcile) < 3:
+ # delete the full reconciliation
+ reconcile_obj.unlink(cr, uid, reconcile.id, context)
+ else:
+ # we are left with a partial reconciliation
+ reconcile_obj.write(
+ cr, uid, reconcile.id,
+ {'line_partial_ids':
+ [(6, 0, [x.id for x in lines_reconcile
+ if x.id != cancel_line.id])],
+ 'line_id': [(6, 0, [])],
+ }, context)
+ # redo the original payment line reconciliation with the invoice
+ payment_line_obj.write(
+ cr, uid, transaction.payment_line_id.id,
+ {'storno': False}, context)
+ payment_line_obj.debit_reconcile(
+ cr, uid, transaction.payment_line_id.id, context)
+
+ _columns = {
+ 'match_type': fields.selection(
+ # Add payment and storno types
+ [
+ ('manual', 'Manual'),
+ ('move','Move'),
+ ('invoice', 'Invoice'),
+ ('payment', 'Payment'),
+ ('payment_order', 'Payment order'),
+ ('storno', 'Storno'),
+ ],
+ 'Match type'),
+ 'payment_order_ids': fields.many2many(
+ 'payment.order', 'banking_transaction_payment_order_rel',
+ 'order_id', 'transaction_id', 'Payment orders'),
+ 'payment_order_id': fields.many2one(
+ 'payment.order', 'Payment order to reconcile'),
+ 'payment_line_id': fields.many2one('payment.line', 'Payment line'),
+ }
+
+ def _get_match_multi(self, cr, uid, ids, name, args, context=None):
+ if not ids:
+ return {}
+ res = super(banking_import_transaction, self)._get_match_multi(
+ cr, uid, ids, name, args, context=context)
+ for transaction in self.browse(cr, uid, ids, context):
+ if transaction.match_type == 'payment_order':
+ if (transaction.payment_order_ids and not
+ transaction.payment_order_id):
+ res[transaction.id] = True
+ return res
+
+ def clear_and_write(self, cr, uid, ids, vals=None, context=None):
+ super(banking_import_transaction, self).clear_and_write(
+ cr, uid, ids, vals=vals, context=context)
+ return self.write(
+ cr, uid, ids, {
+ 'payment_line_id': False,
+ 'payment_order_ids': [(6, 0, [])],
+ },
+ context=context)
+
+ def move_info2values(self, move_info):
+ vals = super(banking_import_transaction, self).move_info2values(
+ move_info)
+ vals['payment_line_id'] = move_info.get('payment_line_id', False)
+ vals['payment_order_ids'] = [
+ (6, 0, move_info.get('payment_order_ids') or [])]
+ vals['payment_order_id'] = (
+ move_info.get('payment_order_ids', False) and
+ len(move_info['payment_order_ids']) == 1 and
+ move_info['payment_order_ids'][0]
+ )
+ return vals
+
+ def match(self, cr, uid, ids, results=None, context=None):
+ res = super(banking_import_transaction, self).match(
+ cr, uid, ids, results=results, context=context)
+
+ return res
+
+ def __init__(self, pool, cr):
+ """
+ Updating the function maps to handle the match types that this
+ module adds. While creating the map in the super object was
+ straightforward, the fact that these are now functions rather than
+ method requires the awkward way of updating it with the methods'
+ function objects.
+
+ As noted above, another implication is that any addon that inherits
+ one of these methods needs to overwrite the entry in the function
+ maps in the same way as is done below.
+ """
+ super(banking_import_transaction, self).__init__(pool, cr)
+
+ self.confirm_map.update({
+ 'storno': self._confirm_storno.__func__,
+ 'payment_order': self._confirm_payment_order.__func__,
+ 'payment': self._confirm_payment.__func__,
+ })
+
+ self.cancel_map.update({
+ 'storno': self._cancel_storno.__func__,
+ 'payment_order': self._cancel_payment_order.__func__,
+ 'payment': self._cancel_payment.__func__,
+ })
=== added file 'account_banking_payment/model/banking_transaction_wizard.py'
--- account_banking_payment/model/banking_transaction_wizard.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/banking_transaction_wizard.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class banking_transaction_wizard(orm.TransientModel):
+ _inherit = 'banking.transaction.wizard'
+ _columns = {
+ 'payment_line_id': fields.related(
+ 'import_transaction_id', 'payment_line_id',
+ string="Matching payment or storno",
+ type='many2one', relation='payment.line',
+ readonly=True),
+ 'payment_order_ids': fields.related(
+ 'import_transaction_id', 'payment_order_ids',
+ string="Matching payment orders",
+ type='many2many', relation='payment.order'),
+ 'payment_order_id': fields.related(
+ 'import_transaction_id', 'payment_order_id',
+ string="Payment order to reconcile",
+ type='many2one', relation='payment.order'),
+ }
=== added file 'account_banking_payment/model/payment_line.py'
--- account_banking_payment/model/payment_line.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/payment_line.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,218 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class payment_line(orm.Model):
+ '''
+ Add extra export_state and date_done fields; make destination bank account
+ mandatory, as it makes no sense to send payments into thin air.
+ Edit: Payments can be by cash too, which is prohibited by mandatory bank
+ accounts.
+ '''
+ _inherit = 'payment.line'
+ _columns = {
+ # New fields
+ 'export_state': fields.selection([
+ ('draft', 'Draft'),
+ ('open','Confirmed'),
+ ('cancel','Cancelled'),
+ ('sent', 'Sent'),
+ ('rejected', 'Rejected'),
+ ('done','Done'),
+ ], 'State', select=True
+ ),
+ 'msg': fields.char('Message', size=255, required=False, readonly=True),
+
+ # Redefined fields: added states
+ 'date_done': fields.datetime('Date Confirmed', select=True,
+ readonly=True),
+ 'name': fields.char(
+ 'Your Reference', size=64, required=True,
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'communication': fields.char(
+ 'Communication', size=64, required=False,
+ help=("Used as the message between ordering customer and current "
+ "company. Depicts 'What do you want to say to the recipient"
+ " about this order ?'"
+ ),
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'communication2': fields.char(
+ 'Communication 2', size=128,
+ help='The successor message of Communication.',
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'move_line_id': fields.many2one(
+ 'account.move.line', 'Entry line',
+ domain=[('reconcile_id','=', False),
+ ('account_id.type', '=','payable')
+ ],
+ help=('This Entry Line will be referred for the information of '
+ 'the ordering customer.'
+ ),
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'amount_currency': fields.float(
+ 'Amount in Partner Currency', digits=(16,2),
+ required=True,
+ help='Payment amount in the partner currency',
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'currency': fields.many2one(
+ 'res.currency', 'Partner Currency', required=True,
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'bank_id': fields.many2one(
+ 'res.partner.bank', 'Destination Bank account',
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'order_id': fields.many2one(
+ 'payment.order', 'Order', required=True,
+ ondelete='cascade', select=True,
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'partner_id': fields.many2one(
+ 'res.partner', string="Partner", required=True,
+ help='The Ordering Customer',
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'date': fields.date(
+ 'Payment Date',
+ help=("If no payment date is specified, the bank will treat this "
+ "payment line directly"
+ ),
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ 'state': fields.selection([
+ ('normal','Free'),
+ ('structured','Structured')
+ ], 'Communication Type', required=True,
+ states={
+ 'sent': [('readonly', True)],
+ 'rejected': [('readonly', True)],
+ 'done': [('readonly', True)]
+ },
+ ),
+ }
+ _defaults = {
+ 'export_state': 'draft',
+ 'date_done': False,
+ 'msg': '',
+ }
+
+ def fields_get(self, cr, uid, fields=None, context=None):
+ res = super(payment_line, self).fields_get(cr, uid, fields, context)
+ if 'communication' in res:
+ res['communication'].setdefault('states', {})
+ res['communication']['states']['structured'] = [('required', True)]
+ if 'communication2' in res:
+ res['communication2'].setdefault('states', {})
+ res['communication2']['states']['structured'] = [('readonly', True)]
+ res['communication2']['states']['normal'] = [('readonly', False)]
+
+ return res
+
+ """
+ Hooks for processing direct debit orders, such as implemented in
+ account_direct_debit module.
+ """
+ def get_storno_account_id(self, cr, uid, payment_line_id, amount,
+ currency_id, context=None):
+ """
+ Hook for verifying a match of the payment line with the amount.
+ Return the account associated with the storno.
+ Used in account_banking interactive mode
+ :param payment_line_id: the single payment line id
+ :param amount: the (signed) amount debited from the bank account
+ :param currency: the bank account's currency *browse object*
+ :return: an account if there is a full match, False otherwise
+ :rtype: database id of an account.account resource.
+ """
+
+ return False
+
+ def debit_storno(self, cr, uid, payment_line_id, amount,
+ currency_id, storno_retry=True, context=None):
+ """
+ Hook for handling a canceled item of a direct debit order.
+ Presumably called from a bank statement import routine.
+
+ Decide on the direction that the invoice's workflow needs to take.
+ You may optionally return an incomplete reconcile for the caller
+ to reconcile the now void payment.
+
+ :param payment_line_id: the single payment line id
+ :param amount: the (negative) amount debited from the bank account
+ :param currency: the bank account's currency *browse object*
+ :param boolean storno_retry: whether the storno is considered fatal \
+ or not.
+ :return: an incomplete reconcile for the caller to fill
+ :rtype: database id of an account.move.reconcile resource.
+ """
+
+ return False
=== added file 'account_banking_payment/model/payment_mode.py'
--- account_banking_payment/model/payment_mode.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/payment_mode.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class payment_mode(orm.Model):
+ ''' Restoring the payment type from version 5,
+ used to select the export wizard (if any) '''
+ _inherit = "payment.mode"
+
+ def suitable_bank_types(self, cr, uid, payment_mode_id=None, context=None):
+ """ Reinstates functional code for suitable bank type filtering.
+ Current code in account_payment is disfunctional.
+ """
+ res = []
+ payment_mode = self.browse(
+ cr, uid, payment_mode_id, context)
+ if (payment_mode and payment_mode.type and
+ payment_mode.type.suitable_bank_types):
+ res = [type.code for type in payment_mode.type.suitable_bank_types]
+ return res
+
+ _columns = {
+ 'type': fields.many2one(
+ 'payment.mode.type', 'Payment type',
+ help='Select the Payment Type for the Payment Mode.'
+ ),
+ }
=== added file 'account_banking_payment/model/payment_mode_type.py'
--- account_banking_payment/model/payment_mode_type.py 1970-01-01 00:00:00 +0000
+++ account_banking_payment/model/payment_mode_type.py 2013-04-06 05:04:22 +0000
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class payment_mode_type(orm.Model):
+ _name = 'payment.mode.type'
+ _description = 'Payment Mode Type'
+ _columns = {
+ 'name': fields.char(
+ 'Name', size=64, required=True,
+ help='Payment Type'
+ ),
+ 'code': fields.char(
+ 'Code', size=64, required=True,
+ help='Specify the Code for Payment Type'
+ ),
+ # Setting suitable_bank_types to required pending
+ # https://bugs.launchpad.net/openobject-addons/+bug/786845
+ 'suitable_bank_types': fields.many2many(
+ 'res.partner.bank.type',
+ 'bank_type_payment_type_rel',
+ 'pay_type_id','bank_type_id',
+ 'Suitable bank types', required=True),
+ 'ir_model_id': fields.many2one(
+ 'ir.model', 'Payment wizard',
+ help=('Select the Payment Wizard for payments of this type. '
+ 'Leave empty for manual processing'),
+ domain=[('osv_memory', '=', True)],
+ ),
+ 'payment_order_type': fields.selection(
+ [('payment', 'Payment'),('debit', 'Direct debit')],
+ 'Payment order type', required=True,
+ ),
+ }
+
+ _defaults = {
+ 'payment_order_type': 'payment',
+ }
=== renamed file 'account_banking/wizard/account_payment_order.py' => 'account_banking_payment/model/payment_order_create.py'
--- account_banking/wizard/account_payment_order.py 2013-01-21 20:25:00 +0000
+++ account_banking_payment/model/payment_order_create.py 2013-04-06 05:04:22 +0000
@@ -2,35 +2,33 @@
##############################################################################
#
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# (C) 2011 - 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# GNU Affero General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
+# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-import datetime
-from osv import osv
-from account_banking.struct import struct
-from account_banking.parsers import convert
-
-today = datetime.date.today
-
-def str2date(str):
- dt = convert.str2date(str, '%Y-%m-%d')
- return datetime.date(dt.year, dt.month, dt.day)
-
-class payment_order_create(osv.osv_memory):
+from datetime import datetime
+from openerp.osv import orm, fields
+from openerp.misc import DEFAULT_SERVER_DATE_FORMAT
+
+
+class payment_order_create(orm.TransientModel):
_inherit = 'payment.order.create'
def create_payment(self, cr, uid, ids, context=None):
@@ -57,8 +55,9 @@
### account banking
# t = None
# line2bank = line_obj.line2bank(cr, uid, line_ids, t, context)
- line2bank = line_obj.line2bank(cr, uid, line_ids, payment.mode.id, context)
- _today = today()
+ line2bank = line_obj.line2bank(
+ cr, uid, line_ids, payment.mode.id, context)
+ _today = fields.date.context_today(self, cr, uid, context=context)
### end account banking
## Finally populate the current payment with new lines:
@@ -69,16 +68,18 @@
elif payment.date_prefered == 'due':
### account_banking
# date_to_pay = line.date_maturity
- date_to_pay = line.date_maturity and \
- str2date(line.date_maturity) > _today\
- and line.date_maturity or False
+ date_to_pay = (
+ line.date_maturity
+ if line.date_maturity and line.date_maturity > _today
+ else False)
### end account banking
elif payment.date_prefered == 'fixed':
### account_banking
# date_to_pay = payment.date_planned
- date_to_pay = payment.date_planned and \
- str2date(payment.date_planned) > _today\
- and payment.date_planned or False
+ date_to_pay = (
+ payment.date_planned
+ if payment.date_planned and payment.date_planned > _today
+ else False)
### end account banking
### account_banking
@@ -107,7 +108,7 @@
amount_currency = line.amount_to_pay
### end account_banking
- payment_obj.create(cr, uid,{
+ payment_obj.create(cr, uid, {
'move_line_id': line.id,
'amount_currency': amount_currency,
'bank_id': line2bank.get(line.id),
@@ -123,5 +124,3 @@
'currency': line.invoice and line.invoice.currency_id.id or line.journal_id.currency.id or line.journal_id.company_id.currency_id.id,
}, context=context)
return {'type': 'ir.actions.act_window_close'}
-
-payment_order_create()
=== added directory 'account_banking_payment/security'
=== added file 'account_banking_payment/security/ir.model.access.csv'
--- account_banking_payment/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ account_banking_payment/security/ir.model.access.csv 2013-04-06 05:04:22 +0000
@@ -0,0 +1,2 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+"access_payment_mode_type","payment.mode.type","model_payment_mode_type","account_payment.group_account_payment",1,1,1,1
=== added directory 'account_banking_payment/view'
=== added file 'account_banking_payment/view/account_payment.xml'
--- account_banking_payment/view/account_payment.xml 1970-01-01 00:00:00 +0000
+++ account_banking_payment/view/account_payment.xml 2013-04-06 05:04:22 +0000
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <!-- Make buttons on payment order sensitive for extra states,
+ restore wizard functionality when making payments
+ -->
+
+ <record id="view_banking_payment_order_form_1" model="ir.ui.view">
+ <field name="name">account.payment.order.form.banking-1</field>
+ <field name="inherit_id" ref="account_payment.view_payment_order_form" />
+ <field name="model">payment.order</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="/form/group/button[@string='Select Invoices to Pay']"
+ position="replace">
+ <button colspan="2" name="%(account_payment.action_create_payment_order)s"
+ string="Select Invoices to Pay" type="action"
+ attrs="{'invisible':[('state','!=','draft')]}"
+ icon="gtk-find"
+ />
+ </xpath>
+ <xpath expr="/form/group/button[@string='Make Payments']"
+ position="replace">
+ <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
+ <newline/>
+ </xpath>
+ </data>
+ </field>
+ </record>
+
+ <record id="view_banking_payment_order_tree_1" model="ir.ui.view">
+ <field name="name">account.payment.order.tree.banking-1</field>
+ <field name="inherit_id" ref="account_payment.view_payment_order_tree" />
+ <field name="model">payment.order</field>
+ <field name="type">tree</field>
+ <field name="arch" type="xml">
+ <button string="Make Payments" position="replace">
+ <button name="launch_wizard" states="open" string="Make Payments" type="object" icon="gtk-execute"/>
+ </button>
+ </field>
+ </record>
+
+ </data>
+</openerp>
=== added file 'account_banking_payment/view/bank_payment_manual.xml'
--- account_banking_payment/view/bank_payment_manual.xml 1970-01-01 00:00:00 +0000
+++ account_banking_payment/view/bank_payment_manual.xml 2013-04-06 05:04:22 +0000
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <record id="view_payment_manual_form" model="ir.ui.view">
+ <field name="name">Form for manual payment wizard</field>
+ <field name="model">payment.manual</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form>
+ <label string="Payment order(s) have been set to 'sent'"/>
+ <button special="cancel" icon="gtk-ok" string="OK"/>
+ </form>
+ </field>
+ </record>
+ </data>
+</openerp>
=== added file 'account_banking_payment/view/banking_transaction_wizard.xml'
--- account_banking_payment/view/banking_transaction_wizard.xml 1970-01-01 00:00:00 +0000
+++ account_banking_payment/view/banking_transaction_wizard.xml 2013-04-06 05:04:22 +0000
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <record model="ir.ui.view" id="transaction_wizard">
+ <field name="name">transaction.wizard</field>
+ <field name="model">banking.transaction.wizard</field>
+ <field name="inherit_id"
+ ref="account_banking.transaction_wizard_first" />
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <field name="invoice_ids" position="before">
+ <field name="payment_order_ids" invisible="True"/>
+ </field>
+ <xpath expr="//group/separator[@string='Multiple matches']/.."
+ position="after">
+ <field name='payment_line_id'
+ attrs="{'invisible': [
+ ('match_type', '!=', 'storno'),
+ ('match_type', '!=', 'payment')]
+ }" />
+ </xpath>
+ <field name="move_line_id" position="after">
+ <field name='payment_order_id'
+ attrs="{'readonly': [
+ ('match_multi', '=', False)],
+ 'invisible': [
+ ('match_type', '!=', 'payment_order')]}"
+ domain="[('id', 'in', payment_order_ids[0][2])]"
+ />
+ </field>
+ </field>
+ </record>
+ </data>
+</openerp>
+
+
=== added file 'account_banking_payment/view/payment_mode_type.xml'
--- account_banking_payment/view/payment_mode_type.xml 1970-01-01 00:00:00 +0000
+++ account_banking_payment/view/payment_mode_type.xml 2013-04-06 05:04:22 +0000
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+ <!-- Add the payment mode type to the payment mode views -->
+ <record id="view_payment_mode_form_inherit" model="ir.ui.view">
+ <field name="name">payment.mode.form.inherit</field>
+ <field name="model">payment.mode</field>
+ <field name="inherit_id" ref="account_payment.view_payment_mode_form"/>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <field name="company_id" position="after">
+ <field name="type"/>
+ </field>
+ </field>
+ </record>
+
+ <record id="view_payment_mode_tree_inherit" model="ir.ui.view">
+ <field name="name">payment.mode.tree.inherit</field>
+ <field name="model">payment.mode</field>
+ <field name="inherit_id" ref="account_payment.view_payment_mode_tree"/>
+ <field name="type">tree</field>
+ <field name="arch" type="xml">
+ <field name="company_id" position="after">
+ <field name="type"/>
+ </field>
+ </field>
+ </record>
+
+ <!-- basic view for payment mode type -->
+ <record model="ir.ui.view" id="view_payment_mode_type_form">
+ <field name="name">view.payment.mode.type.form</field>
+ <field name="model">payment.mode.type</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form>
+ <field name="name" />
+ <field name="code" />
+ <field name="suitable_bank_types"/>
+ <field name="payment_order_type"/>
+ <field name="ir_model_id"/>
+ </form>
+ </field>
+ </record>
+
+ </data>
+</openerp>
=== added directory 'account_banking_payment/workflow'
=== renamed file 'account_banking/account_banking_workflow.xml' => 'account_banking_payment/workflow/account_payment.xml'
--- account_banking/account_banking_workflow.xml 2011-12-12 15:00:03 +0000
+++ account_banking_payment/workflow/account_payment.xml 2013-04-06 05:04:22 +0000
@@ -1,20 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) EduSense BV <http://www.edusense.nl>
- All rights reserved.
- The licence is in the file __terp__.py
--->
<openerp>
<data>
<!-- New activity for workflow payment order: sent -->
- <record id="act_sent" model="workflow.activity">
+ <record id="account_banking.act_sent" model="workflow.activity">
<field name="name">sent</field>
<field name="wkf_id" ref="account_payment.wkf_payment_order"/>
<field name="action">action_sent()</field>
<field name="kind">function</field>
</record>
<!-- New activity for workflow payment order: rejected -->
- <record id="act_rejected" model="workflow.activity">
+ <record id="account_banking.act_rejected" model="workflow.activity">
<field name="name">rejected</field>
<field name="wkf_id" ref="account_payment.wkf_payment_order"/>
<field name="action">action_rejected()
@@ -22,21 +17,21 @@
<field name="kind">function</field>
</record>
<!-- Add new transition sent -> done -->
- <record id="trans_sent_done" model="workflow.transition">
- <field name="act_from" ref="act_sent"/>
+ <record id="account_banking.trans_sent_done" model="workflow.transition">
+ <field name="act_from" ref="account_banking.act_sent"/>
<field name="act_to" ref="account_payment.act_done"/>
<field name="signal">done</field>
</record>
<!-- Add new transition sent -> rejected -->
- <record id="trans_sent_rejected" model="workflow.transition">
- <field name="act_from" ref="act_sent"/>
- <field name="act_to" ref="act_rejected"/>
+ <record id="account_banking.trans_sent_rejected" model="workflow.transition">
+ <field name="act_from" ref="account_banking.act_sent"/>
+ <field name="act_to" ref="account_banking.act_rejected"/>
<field name="signal">rejected</field>
</record>
<!-- Rewrite existing open -> done transition to include 'sent' -->
<record id="account_payment.trans_open_done" model="workflow.transition">
<field name="act_from" ref="account_payment.act_open"/>
- <field name="act_to" ref="act_sent"/>
+ <field name="act_to" ref="account_banking.act_sent"/>
<field name="signal">sent</field>
</record>
</data>
Follow ups