banking-addons-team team mailing list archive
-
banking-addons-team team
-
Mailing list archive
-
Message #01655
[Merge] lp:~therp-nl/banking-addons/6.1-cust10-girotel_sepa_payment_batches into lp:banking-addons
Holger Brunn (Therp) has proposed merging lp:~therp-nl/banking-addons/6.1-cust10-girotel_sepa_payment_batches into lp:banking-addons.
Requested reviews:
Banking Addons Core Editors (banking-addons-team)
For more details, see:
https://code.launchpad.net/~therp-nl/banking-addons/6.1-cust10-girotel_sepa_payment_batches/+merge/209683
--
https://code.launchpad.net/~therp-nl/banking-addons/6.1-cust10-girotel_sepa_payment_batches/+merge/209683
Your team Banking Addons Core Editors is requested to review the proposed merge of lp:~therp-nl/banking-addons/6.1-cust10-girotel_sepa_payment_batches into lp:banking-addons.
=== modified file 'account_banking/__init__.py'
=== modified file 'account_banking/__openerp__.py'
--- account_banking/__openerp__.py 2013-12-10 07:06:28 +0000
+++ account_banking/__openerp__.py 2014-03-06 13:49:10 +0000
@@ -44,9 +44,16 @@
'wizard/link_partner.xml',
'workflow/account_invoice.xml',
],
- 'js': [
- 'static/src/js/account_banking.js',
- ],
+<<<<<<< TREE
+ 'js': [
+ 'static/src/js/account_banking.js',
+ ],
+=======
+ 'js': [
+ 'static/src/js/account_banking.js',
+ ],
+ 'demo_xml': [],
+>>>>>>> MERGE-SOURCE
'external_dependencies': {
'python' : ['BeautifulSoup'],
},
=== modified file 'account_banking/account_banking.py'
--- account_banking/account_banking.py 2014-02-10 20:21:08 +0000
+++ account_banking/account_banking.py 2014-03-06 13:49:10 +0000
@@ -327,8 +327,15 @@
'''
Find matching period for date, not meant for _defaults.
'''
+ if context is None:
+ context = {}
period_obj = self.pool.get('account.period')
+<<<<<<< TREE
periods = period_obj.find(cr, uid, dt=date, context=context)
+=======
+ context['account_period_prefer_normal'] = True
+ periods = period_obj.find(cursor, uid, dt=date, context=context)
+>>>>>>> MERGE-SOURCE
return periods and periods[0] or False
def _prepare_move(
@@ -395,9 +402,36 @@
st_line.refresh()
if st_line.voucher_id:
if not st_line.voucher_id.journal_id.entry_posted:
+<<<<<<< TREE
account_move_obj.post(
cr, uid, [st_line.voucher_id.move_id.id], context={})
+=======
+ account_move_obj.post(cr, uid, [st_line.voucher_id.move_id.id], context={})
+ return True
+
+ st = st_line.statement_id
+
+ context.update({'date': st_line.date})
+ ctxt = context.copy() # AB
+ ctxt['company_id'] = st_line.company_id.id # AB
+
+ move_id = account_move_obj.create(cr, uid, {
+ 'journal_id': st.journal_id.id,
+ 'period_id': period_id, # AB
+ 'date': st_line.date,
+ 'name': st_line_number,
+ 'ref': st_line.ref,
+ }, context=context)
+ account_bank_statement_line_obj.write(cr, uid, [st_line.id], {
+ 'move_ids': [(4, move_id, False)]
+ })
+
+ torec = []
+ if st_line.amount >= 0:
+ account_id = st.journal_id.default_credit_account_id.id
+>>>>>>> MERGE-SOURCE
else:
+<<<<<<< TREE
# Write stored reconcile_id and pay invoices through workflow
if st_line.reconcile_id:
move_ids = [move.id for move in st_line.move_ids]
@@ -415,6 +449,107 @@
netsvc.LocalService("workflow").trg_trigger(
uid, 'account.move.line', move_line.id, cr)
return res
+=======
+ account_id = st.journal_id.default_debit_account_id.id
+
+ acc_cur = ((st_line.amount <= 0 and
+ st.journal_id.default_debit_account_id) or
+ st_line.account_id)
+ context.update({
+ 'res.currency.compute.account': acc_cur,
+ })
+ amount = res_currency_obj.compute(cr, uid, st.currency.id,
+ company_currency_id, st_line.amount, context=context)
+
+ val = {
+ 'name': st_line.name,
+ 'date': st_line.date,
+ 'move_id': move_id,
+ 'partner_id': (((st_line.partner_id) and st_line.partner_id.id) or
+ False),
+ 'account_id': (st_line.account_id) and st_line.account_id.id,
+ 'credit': ((amount>0) and amount) or 0.0,
+ 'debit': ((amount<0) and -amount) or 0.0,
+ 'statement_id': st.id,
+ 'journal_id': st.journal_id.id,
+ 'period_id': period_id, # AB
+ 'currency_id': st.currency.id,
+ 'analytic_account_id': (st_line.analytic_account_id and
+ st_line.analytic_account_id.id or
+ False),
+ }
+
+ if st.currency.id <> company_currency_id:
+ amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
+ st.currency.id, amount, context=context)
+ val['amount_currency'] = -amount_cur
+
+ if (st_line.account_id and st_line.account_id.currency_id and
+ st_line.account_id.currency_id.id <> company_currency_id):
+ val['currency_id'] = st_line.account_id.currency_id.id
+ amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
+ st_line.account_id.currency_id.id, amount, context=context)
+ val['amount_currency'] = -amount_cur
+
+ move_line_id = account_move_line_obj.create(
+ cr, uid, val, context=context)
+ torec.append(move_line_id)
+
+ # Fill the secondary amount/currency
+ # if currency is not the same than the company
+ amount_currency = False
+ currency_id = False
+ if st.currency.id <> company_currency_id:
+ amount_currency = st_line.amount
+ currency_id = st.currency.id
+ account_move_line_obj.create(cr, uid, {
+ 'name': st_line.name,
+ 'date': st_line.date,
+ 'move_id': move_id,
+ 'partner_id': (((st_line.partner_id) and st_line.partner_id.id) or
+ False),
+ 'account_id': account_id,
+ 'credit': ((amount < 0) and -amount) or 0.0,
+ 'debit': ((amount > 0) and amount) or 0.0,
+ 'statement_id': st.id,
+ 'journal_id': st.journal_id.id,
+ 'period_id': period_id, # AB
+ 'amount_currency': amount_currency,
+ 'currency_id': currency_id,
+ }, context=context)
+
+ for line in account_move_line_obj.browse(cr, uid, [x.id for x in
+ account_move_obj.browse(cr, uid, move_id,
+ context=context).line_id],
+ context=context):
+ if line.state <> 'valid':
+ raise osv.except_osv(_('Error !'),
+ _('Journal Item "%s" is not valid') % line.name)
+
+ # Bank statements will not consider boolean on journal entry_posted
+ account_move_obj.post(cr, uid, [move_id], context=context)
+
+ """
+ Account-banking:
+ - Write stored reconcile_id
+ - Pay invoices through workflow
+
+ Does not apply to voucher integration, but only to
+ payments and payment orders
+ """
+ if st_line.reconcile_id:
+ account_move_line_obj.write(cr, uid, torec, {
+ (st_line.reconcile_id.line_partial_ids and
+ 'reconcile_partial_id' or 'reconcile_id'):
+ st_line.reconcile_id.id }, context=context)
+ for move_line in (st_line.reconcile_id.line_id or []) + (
+ st_line.reconcile_id.line_partial_ids or []):
+ netsvc.LocalService("workflow").trg_trigger(
+ uid, 'account.move.line', move_line.id, cr)
+ #""" End account-banking """
+
+ return move_id
+>>>>>>> MERGE-SOURCE
def button_confirm_bank(self, cr, uid, ids, context=None):
"""
@@ -879,11 +1014,18 @@
values['acc_number_domestic'] = str(acc_number_fmt)
else:
result.update(warning(
+<<<<<<< TREE
_('Invalid format'),
_('The account number has the wrong format '
'for %(country)s')
% {'country': country.name}
))
+=======
+ _('Invalid format'),
+ _('The account number has the wrong format for %(country)s')
+ % {'country': country.name}
+ ))
+>>>>>>> MERGE-SOURCE
return result
def onchange_iban(
@@ -915,6 +1057,21 @@
_("The IBAN number doesn't seem to be correct")
)
+<<<<<<< TREE
+=======
+ def _check_bank(self, cr, uid, ids, context=None):
+ #suppress base_iban's constraint to enforce BICs for IBANs
+ #workaround for lp:933472
+ return True
+
+ _constraints = [
+ # Cannot have this as a constraint as it is rejecting valid numbers from GB and DE
+ # It works much better without this constraint!
+ #(check_iban, _("The IBAN number doesn't seem to be correct"), ["acc_number"])
+ (_check_bank, '\nPlease define BIC/Swift code on bank for bank type IBAN Account to make valid payments', ['bic'])
+ ]
+
+>>>>>>> MERGE-SOURCE
res_partner_bank()
=== modified file 'account_banking/account_banking_view.xml'
--- account_banking/account_banking_view.xml 2014-03-03 11:21:17 +0000
+++ account_banking/account_banking_view.xml 2014-03-06 13:49:10 +0000
@@ -209,6 +209,7 @@
position="attributes">
<attribute name="colors">black:state == 'confirmed';darkmagenta:match_multi == True;crimson:duplicate == True;grey:state == 'draft';</attribute>
</xpath>
+<<<<<<< TREE
<xpath expr="//field[@name='line_ids']/tree/field[@name='name']"
position="attributes">
@@ -241,6 +242,93 @@
type="object"
attrs="{'invisible': [('link_partner_ok', '=', False)]}"
/>
+=======
+ <xpath expr="/form/notebook/page[@string='Transaction']/field/tree/field[@name='name']" position="replace">
+ <field name="name" required="1"/>
+ </xpath>
+ <xpath expr="/form/notebook/page[@string='Transaction']/field/form/field[@name='name']" position="replace">
+ <field name="name" required="1"/>
+ </xpath>
+ </data>
+ </field>
+ </record>
+ <record id="view_banking_bank_statement_form_2" model="ir.ui.view">
+ <field name="name">account.bank.statement.form.banking-2</field>
+ <field name="inherit_id" ref="account.view_bank_statement_form" />
+ <field name="model">account.bank.statement</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <xpath expr="/form/notebook/page[@string='Transaction']/field/tree/field[@name='ref']" position="after">
+ <field name="period_id"/>
+ </xpath>
+ </field>
+ </record>
+ <record id="view_banking_bank_statement_form_3" model="ir.ui.view">
+ <field name="name">account.bank.statement.form.banking-3</field>
+ <field name="inherit_id" ref="account.view_bank_statement_form" />
+ <field name="model">account.bank.statement</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="/form/notebook/page[@string='Transaction']/field/form/field[@name='ref']" position="after">
+ <field name="period_id"/>
+ <field name="match_type"/>
+ <field name="match_multi"/>
+ <field name="duplicate"/>
+ </xpath>
+ </data>
+ </field>
+ </record>
+
+ <!-- Add invisible column on bank statements tree for identification
+ of import file
+ -->
+ <record id="view_banking_bank_statement_tree_2" model="ir.ui.view">
+ <field name="name">account.bank.statement.tree.banking-2</field>
+ <field name="inherit_id" ref="account.view_bank_statement_tree" />
+ <field name="model">account.bank.statement</field>
+ <field name="type">tree</field>
+ <field name="arch" type="xml">
+ <field name="state" position="after">
+ <field name="banking_id" invisible="True" />
+ </field>
+ </field>
+ </record>
+
+ <!-- Add invisible field for identification of import file on bank statements
+ -->
+ <record id="view_banking_bank_statement_form_4" model="ir.ui.view">
+ <field name="name">account.bank.statement.form.banking-4</field>
+ <field name="inherit_id" ref="account.view_bank_statement_form" />
+ <field name="model">account.bank.statement</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <field name="balance_end_real" position="after">
+ <field name="banking_id" invisible="True"/>
+ </field>
+ </field>
+ </record>
+
+ <!-- Show bank accounts in account_bank_statement_line to enable manual
+ coupling of bank account numbers to statement lines and harvest info
+ for future matching in the process.
+ -->
+ <record id="view_banking_bank_statement_form_5" model="ir.ui.view">
+ <field name="name">account.bank.statement.form.banking-5</field>
+ <field name="inherit_id" ref="account.view_bank_statement_form" />
+ <field name="model">account.bank.statement</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="/form/notebook/page/field[@name='line_ids']/tree/field[@name='partner_id']" position="after">
+ <field name="link_partner_ok" invisible="1" />
+ <button name="link_partner"
+ string="Link partner"
+ icon="terp-partner"
+ type="object"
+ attrs="{'invisible': [('link_partner_ok', '=', False)]}"
+ />
+>>>>>>> MERGE-SOURCE
<!-- TODO set partner_id when partner_bank_id changes -->
<field name="partner_bank_id"/>
</xpath>
@@ -260,10 +348,16 @@
<button name="match_wizard"
string="Match"
icon="terp-gtk-jump-to-ltr"
+<<<<<<< TREE
attrs="{'invisible': ['|', ('parent_id', '!=', False),
('state', '!=', 'draft')]}"
type="object"
/>
+=======
+ attrs="{'invisible': ['|', ('parent_id', '!=', False),
+ ('state', '!=', 'draft')]}"
+ type="object"/>
+>>>>>>> MERGE-SOURCE
<field name="match_multi" invisible="1"/>
<field name="duplicate" invisible="1"/>
<field name="state"/>
@@ -288,7 +382,69 @@
</data>
</field>
</record>
-
+<<<<<<< TREE
+
+=======
+ <record id="view_banking_bank_statement_form_6" model="ir.ui.view">
+ <field name="name">account.bank.statement.form.banking-6</field>
+ <field name="inherit_id" ref="account.view_bank_statement_form" />
+ <field name="model">account.bank.statement</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <xpath expr="/form/notebook/page/field[@name='line_ids']/form/field[@name='partner_id']" position="after">
+ <field name="partner_bank_id"/>
+ </xpath>
+ </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="attributes">
+ <attribute name="attrs">{'invisible':[('state','!=','draft')]}</attribute>
+ </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>
+ <field name="model">res.partner.bank</field>
+ <field name="inherit_id" ref="base_iban.view_partner_bank_iban_form"/>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <field name="iban" position="replace">
+ <field name="iban" on_change="onchange_iban(iban)" />
+ </field>
+ </field>
+ </record-->
+>>>>>>> MERGE-SOURCE
<record id="view_partner_bank_account_banking_form_2" model="ir.ui.view">
<field name="name">res.partner.bank.form.banking-2</field>
<field name="model">res.partner.bank</field>
@@ -343,6 +499,7 @@
attrs="{'readonly': ['|', ('state', '!=', 'draft'), ('match_type', '!=', '')]}" name="account_id"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '<>', 'view')]"/>
<field name="amount"/>
+<<<<<<< TREE
<field name="match_type"/>
<field name="residual"/>
<field name="parent_id" invisible="1" />
@@ -366,6 +523,30 @@
type="object"/>
<field name="invoice_id"/>
<field name="reconcile_id"/>
+=======
+ <field name="match_type"/>
+ <field name="residual"/>
+ <field name="parent_id" invisible="1" />
+ <button name="match_wizard"
+ string="Match"
+ icon="terp-gtk-jump-to-ltr"
+ attrs="{'invisible': ['|', ('parent_id', '!=', False),
+ ('state', '!=', 'draft')]}"
+ type="object"/>
+ <field name="match_multi" invisible="1"/>
+ <field name="duplicate" invisible="1"/>
+ <field name="state"/>
+ <button name="confirm" states="draft"
+ string="Confirm transaction"
+ icon="gtk-ok"
+ type="object"/>
+ <button name="cancel" states="confirmed"
+ string="Cancel transaction"
+ icon="gtk-cancel"
+ type="object"/>
+ <field name="invoice_id"/>
+ <field name="reconcile_id"/>
+>>>>>>> MERGE-SOURCE
</tree>
</field>
</record>
=== modified file 'account_banking/banking_import_transaction.py'
--- account_banking/banking_import_transaction.py 2014-01-21 07:55:55 +0000
+++ account_banking/banking_import_transaction.py 2014-03-06 13:49:10 +0000
@@ -23,6 +23,12 @@
#
##############################################################################
+<<<<<<< TREE
+=======
+from osv import orm, osv, fields
+import netsvc
+import base64
+>>>>>>> MERGE-SOURCE
import datetime
from openerp.osv import orm, fields
from openerp import netsvc
@@ -120,6 +126,54 @@
# return move_lines to mix with the rest
return [x for x in invoice.move_id.line_id if x.account_id.reconcile]
+<<<<<<< TREE
+=======
+ def _match_payment_order(
+ self, cr, uid, trans, log, order_type = 'payment', context=None):
+
+ def equals_order_amount(payment_order, transferred_amount):
+ if (not hasattr(payment_order, 'payment_order_type')
+ or payment_order.payment_order_type == 'payment'):
+ sign = 1
+ else:
+ sign = -1
+ total = payment_order.total + sign * transferred_amount
+ 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', '=', order_type),
+ ('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
+ equals_order_amount(x, trans.transferred_amount)]
+
+ if len(candidates) > 0:
+ # retrieve the common account_id, if any
+ account_id = False
+ if (candidates[0].line_ids[0].debit_move_line_id):
+ 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
+
+>>>>>>> MERGE-SOURCE
def _match_invoice(self, cr, uid, trans, move_lines,
partner_ids, bank_account_ids,
log, linked_invoices,
@@ -409,10 +463,12 @@
journal = st_line.statement_id.journal_id
if st_line.amount < 0.0:
voucher_type = 'payment'
+ voucher_line_type = 'dr'
account_id = (journal.default_debit_account_id and
journal.default_debit_account_id.id or False)
else:
voucher_type = 'receipt'
+ voucher_line_type = 'cr'
account_id = (journal.default_credit_account_id and
journal.default_credit_account_id.id or False)
@@ -473,7 +529,7 @@
'reconcile': True,
'amount': line_amount,
'account_id': transaction.move_line_id.account_id.id,
- 'type': transaction.move_line_id.credit and 'dr' or 'cr',
+ 'type': voucher_line_type,
}
voucher['line_ids'] = [(0, 0, vch_line)]
voucher_id = self.pool.get('account.voucher').create(
@@ -483,6 +539,101 @@
{'voucher_id': voucher_id}, context=context)
transaction.refresh()
+<<<<<<< TREE
+=======
+ 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"))
+ 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 payment or direct debit order"))
+ if not transaction.statement_line_id.reconcile_id:
+ raise orm.except_orm(
+ _("Cannot unreconcile"),
+ _("Payment orders without transfer move lines cannot be "
+ "unreconciled this way"))
+ 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)
+
+>>>>>>> MERGE-SOURCE
def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None):
"""
Legacy method. Allow for canceling bank statement lines that
@@ -618,6 +769,12 @@
'invoice': _cancel_voucher,
'manual': _cancel_voucher,
'move': _cancel_voucher,
+<<<<<<< TREE
+=======
+ 'payment_order': _cancel_payment_order,
+ 'payment_order_manual': _cancel_payment_order,
+ 'payment': _cancel_payment,
+>>>>>>> MERGE-SOURCE
}
def cancel(self, cr, uid, ids, context=None):
@@ -638,6 +795,12 @@
confirm_map = {
'invoice': _confirm_move,
'manual': _confirm_move,
+<<<<<<< TREE
+=======
+ 'payment_order': _confirm_payment_order,
+ 'payment_order_manual': _confirm_payment_order,
+ 'payment': _confirm_payment,
+>>>>>>> MERGE-SOURCE
'move': _confirm_move,
}
@@ -732,49 +895,40 @@
'account_id': False,
}
move_lines = self.pool.get('account.move.line').browse(cr, uid, move_line_ids)
- for move_line in move_lines:
- if move_line.partner_id:
- if retval['partner_id']:
- if retval['partner_id'] != move_line.partner_id.id:
- retval['partner_id'] = False
- break
- else:
- retval['partner_id'] = move_line.partner_id.id
- else:
- if retval['partner_id']:
- retval['partner_id'] = False
- break
- for move_line in move_lines:
- if move_line.account_id:
- if retval['account_id']:
- if retval['account_id'] != move_line.account_id.id:
- retval['account_id'] = False
- break
- else:
- retval['account_id'] = move_line.account_id.id
- else:
- if retval['account_id']:
- retval['account_id'] = False
- break
- for move_line in move_lines:
- if move_line.invoice:
- if retval['match_type']:
- if retval['match_type'] != 'invoice':
- retval['match_type'] = False
- break
- else:
- retval['match_type'] = 'invoice'
- else:
- if retval['match_type']:
- retval['match_type'] = False
- break
- if move_lines and not retval['match_type']:
+
+ if not move_lines:
+ return retval
+
+ if move_lines[0].partner_id and all(
+ [move_line.partner_id == move_lines[0].partner_id
+ for move_line in move_lines]):
+ retval['partner_id'] = move_lines[0].partner_id.id
+
+ if move_lines[0].account_id and all(
+ [move_line.account_id == move_lines[0].account_id
+ for move_line in move_lines]):
+ retval['account_id'] = move_lines[0].account_id.id
+
+ if move_lines[0].invoice and all(
+ [move_line.invoice == move_lines[0].invoice
+ for move_line in move_lines]):
+ retval['match_type'] = 'invoice'
+ retval['type'] = type_map[move_lines[0].invoice.type]
+ retval['invoice_ids'] = list(
+ set([x.invoice.id for x in move_lines]))
+
+ if not retval['match_type']:
retval['match_type'] = 'move'
- if move_lines and len(move_lines) == 1:
+
+ if len(move_lines) == 1:
retval['reference'] = move_lines[0].ref
+<<<<<<< TREE
if retval['match_type'] == 'invoice':
retval['invoice_ids'] = list(set([x.invoice.id for x in move_lines]))
retval['type'] = type_map[move_lines[0].invoice.type]
+=======
+
+>>>>>>> MERGE-SOURCE
return retval
def move_info2values(self, move_info):
@@ -1029,6 +1183,7 @@
), context=context)
# rebrowse the current record after writing
transaction = self.browse(cr, uid, transaction.id, context=context)
+<<<<<<< TREE
# Match payment and direct debit orders
move_info_payment = self.hook_match_payment(
@@ -1036,6 +1191,21 @@
if move_info_payment:
move_info = move_info_payment
+=======
+ if transaction.type == bt.PAYMENT_BATCH:
+ move_info = self._match_payment_order(
+ cr, uid, transaction, results['log'],
+ order_type='payment', context=context)
+ # Match full direct debit orders
+ if transaction.type == bt.DIRECT_DEBIT:
+ move_info = self._match_payment_order(
+ cr, uid, transaction, results['log'],
+ order_type='debit', context=context)
+ if transaction.type == bt.STORNO:
+ move_info = self._match_storno(
+ cr, uid, transaction, results['log'], context)
+
+>>>>>>> MERGE-SOURCE
# Allow inclusion of generated bank invoices
if transaction.type == bt.BANK_COSTS:
lines = self._match_costs(
@@ -1056,13 +1226,20 @@
if partner_banks:
partner_ids = [x.partner_id.id for x in partner_banks]
elif transaction.remote_owner:
+<<<<<<< TREE
country_id = banktools.get_country_id(
self.pool, cr, uid, transaction, context=context)
partner_id = banktools.get_partner(
+=======
+ country_id = get_country_id(
+ self.pool, cr, uid, transaction, context=context)
+ partner_id = get_partner(
+>>>>>>> MERGE-SOURCE
self.pool, cr, uid, transaction.remote_owner,
transaction.remote_owner_address,
transaction.remote_owner_postalcode,
transaction.remote_owner_city,
+<<<<<<< TREE
country_id, results['log'],
context=context)
if partner_id:
@@ -1078,6 +1255,23 @@
context=context)
partner_banks = partner_bank_obj.browse(
cr, uid, [partner_bank_id], context=context)
+=======
+ country_id, results['log'], context=context)
+ if partner_id:
+ partner_ids = [partner_id]
+ if transaction.remote_account:
+ partner_bank_id = create_bank_account(
+ self.pool, cr, uid, partner_id,
+ transaction.remote_account,
+ transaction.remote_owner,
+ transaction.remote_owner_address,
+ transaction.remote_owner_city,
+ country_id, bic=transaction.remote_bank_bic,
+ )
+ partner_banks = partner_bank_obj.browse(
+ cr, uid, [partner_bank_id]
+ )
+>>>>>>> MERGE-SOURCE
# Credit means payment... isn't it?
if (not move_info
@@ -1109,6 +1303,7 @@
account_id = move_info and move_info.get('account_id', False)
if not account_id:
# Use the default settings, but allow individual partner
+<<<<<<< TREE
# settings to overrule this.
bank_partner = (
partner_banks[0].partner_id if len(partner_banks) == 1
@@ -1119,7 +1314,23 @@
def_journal_account_bank_decr()[bank_partner.id]
else:
account_id = account_info.default_credit_account_id.id
+=======
+ # settings to overrule this. Note that you need to change
+ # the internal type of these accounts to either 'payable'
+ # or 'receivable' to enable usage like this.
+ bank_partner = (
+ partner_banks[0].partner_id if len(partner_banks) == 1
+ else False)
+ if transaction.transferred_amount < 0:
+ if bank_partner:
+ account_id = bank_partner.\
+ def_journal_account_bank_decr()[bank_partner.id]
+ if not account_id:
+ account_id = (account_info.default_credit_account_id and
+ account_info.default_credit_account_id.id)
+>>>>>>> MERGE-SOURCE
else:
+<<<<<<< TREE
if bank_partner:
account_id = bank_partner.\
@@ -1128,6 +1339,15 @@
account_id = account_info.default_debit_account_id.id
values = {'account_id': account_id}
+=======
+ if bank_partner:
+ account_id = bank_partner.\
+ def_journal_account_bank_incr()[bank_partner.id]
+ if not account_id:
+ account_id = (account_info.default_debit_account_id and
+ account_info.default_debit_account_id.id)
+ values = {}
+>>>>>>> MERGE-SOURCE
self_values = {}
if move_info:
results['trans_matched_cnt'] += 1
@@ -1260,21 +1480,40 @@
return res
- def unlink(self, cr, uid, ids, context=None):
- """
- Unsplit if this if a split transaction
- """
- for this in self.browse(cr, uid, ids, context):
- if this.parent_id:
- this.parent_id.write(
- {'transferred_amount':
- this.parent_id.transferred_amount + \
- this.transferred_amount,
- })
- this.parent_id.refresh()
- return super(banking_import_transaction, self).unlink(
- cr, uid, ids, context=context)
-
+<<<<<<< TREE
+ def unlink(self, cr, uid, ids, context=None):
+ """
+ Unsplit if this if a split transaction
+ """
+ for this in self.browse(cr, uid, ids, context):
+ if this.parent_id:
+ this.parent_id.write(
+ {'transferred_amount':
+ this.parent_id.transferred_amount + \
+ this.transferred_amount,
+ })
+ this.parent_id.refresh()
+ return super(banking_import_transaction, self).unlink(
+ cr, uid, ids, context=context)
+
+=======
+ def unlink(self, cr, uid, ids, context=None):
+ """
+ Unsplit if this if a split transaction
+ """
+ for this in self.browse(cr, uid, ids, context):
+ if this.parent_id:
+ this.parent_id.write(
+ {'transferred_amount':
+ this.parent_id.transferred_amount + \
+ this.transferred_amount,
+ })
+ this.parent_id.refresh()
+ return super(banking_import_transaction, self).unlink(
+ cr, uid, ids, context=context)
+
+
+>>>>>>> MERGE-SOURCE
column_map = {
# used in bank_import.py, converting non-osv transactions
'statement_id': 'statement',
@@ -1326,13 +1565,20 @@
'duplicate': fields.boolean('duplicate'),
'statement_line_id': fields.many2one(
'account.bank.statement.line', 'Statement line',
+<<<<<<< TREE
ondelete='cascade'),
'statement_id': fields.many2one(
'account.bank.statement', 'Statement',
ondelete='CASCADE'),
+=======
+ ondelete='cascade'),
+ 'statement_id': fields.many2one(
+ 'account.bank.statement', 'Statement'),
+>>>>>>> MERGE-SOURCE
'parent_id': fields.many2one(
'banking.import.transaction', 'Split off from this transaction'),
# match fields
+<<<<<<< TREE
'match_type': fields.selection([
('move','Move'),
('invoice', 'Invoice'),
@@ -1343,6 +1589,14 @@
('payment_manual', 'Payment line (manual)'),
('payment_order_manual', 'Payment order (manual)'),
], 'Match type'),
+=======
+ 'match_type': fields.selection(
+ [('manual', 'Manual'), ('move','Move'), ('invoice', 'Invoice'),
+ ('payment', 'Payment'), ('payment_order', 'Payment order'),
+ ('payment_order_manual', 'Payment order (manual)'),
+ ('storno', 'Storno')],
+ 'Match type'),
+>>>>>>> MERGE-SOURCE
'match_multi': fields.function(
_get_match_multi, method=True, string='Multi match',
type='boolean'),
@@ -1395,23 +1649,44 @@
class account_bank_statement_line(orm.Model):
_inherit = 'account.bank.statement.line'
-
- def _get_link_partner_ok(
- self, cr, uid, ids, name, args, context=None):
- """
- Deliver the values of the function field that
- determines if the 'link partner' wizard is show on the
- bank statement line
- """
- res = {}
- for line in self.browse(cr, uid, ids, context):
- res[line.id] = bool(
- line.state == 'draft'
- and not line.partner_id
- and line.import_transaction_id
- and line.import_transaction_id.remote_account)
- return res
-
+<<<<<<< TREE
+
+ def _get_link_partner_ok(
+ self, cr, uid, ids, name, args, context=None):
+ """
+ Deliver the values of the function field that
+ determines if the 'link partner' wizard is show on the
+ bank statement line
+ """
+ res = {}
+ for line in self.browse(cr, uid, ids, context):
+ res[line.id] = bool(
+ line.state == 'draft'
+ and not line.partner_id
+ and line.import_transaction_id
+ and line.import_transaction_id.remote_account)
+ return res
+
+=======
+
+ def _get_link_partner_ok(
+ self, cr, uid, ids, name, args, context=None):
+ """
+ Deliver the values of the function field that
+ determines if the 'link partner' wizard is show on the
+ bank statement line
+ """
+ res = {}
+ for line in self.browse(cr, uid, ids, context):
+ res[line.id] = bool(
+ line.state == 'draft'
+ and not line.partner_id
+ and line.import_transaction_id
+ and line.import_transaction_id.remote_owner
+ and line.import_transaction_id.remote_account)
+ return res
+
+>>>>>>> MERGE-SOURCE
_columns = {
'import_transaction_id': fields.many2one(
'banking.import.transaction',
@@ -1428,6 +1703,7 @@
string='Possible duplicate import', readonly=True),
'match_type': fields.related(
'import_transaction_id', 'match_type', type='selection',
+<<<<<<< TREE
selection=[
('move','Move'),
('invoice', 'Invoice'),
@@ -1438,15 +1714,30 @@
('payment_manual', 'Payment line (manual)'),
('payment_order_manual', 'Payment order (manual)'),
],
+=======
+ selection=[('manual', 'Manual'), ('move','Move'),
+ ('invoice', 'Invoice'), ('payment', 'Payment'),
+ ('payment_order', 'Payment order'),
+ ('payment_order_manual', 'Payment order (manual)'),
+ ('storno', 'Storno')],
+>>>>>>> MERGE-SOURCE
string='Match type', readonly=True,),
'state': fields.selection(
[('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',
readonly=True, required=True),
- 'parent_id': fields.many2one('account.bank.statement.line',
- 'Parent'),
- 'link_partner_ok': fields.function(
- _get_link_partner_ok, type='boolean',
- string='Can link partner'),
+<<<<<<< TREE
+ 'parent_id': fields.many2one('account.bank.statement.line',
+ 'Parent'),
+ 'link_partner_ok': fields.function(
+ _get_link_partner_ok, type='boolean',
+ string='Can link partner'),
+=======
+ 'link_partner_ok': fields.function(
+ _get_link_partner_ok, type='boolean',
+ string='Can link partner'),
+ 'parent_id': fields.many2one('account.bank.statement.line',
+ 'Parent'),
+>>>>>>> MERGE-SOURCE
}
_defaults = {
@@ -1467,6 +1758,7 @@
res = wizard_obj.create_act_window(cr, uid, res_id, context=context)
return res
+<<<<<<< TREE
def link_partner(self, cr, uid, ids, context=None):
"""
Get the appropriate partner or fire a wizard to create
@@ -1527,6 +1819,68 @@
cr, uid, {'statement_line_id': ids[0]}, context=context)
return wizard_obj.create_act_window(cr, uid, res_id, context=context)
+=======
+ def link_partner(self, cr, uid, ids, context=None):
+ """
+ Get the appropriate partner or fire a wizard to create
+ or link one
+ """
+ if not ids:
+ return False
+
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+
+ # Check if the partner is already known but not shown
+ # because the screen was not refreshed yet
+ statement_line = self.browse(
+ cr, uid, ids[0], context=context)
+ if statement_line.partner_id:
+ return True
+
+ # Reuse the bank's partner if any
+ if (statement_line.partner_bank_id and
+ statement_line.partner_bank_id.partner_id):
+ statement_line.write(
+ {'partner_id': statement_line.partner_bank_id.partner_id.id})
+ return True
+
+ if (not statement_line.import_transaction_id or
+ not statement_line.import_transaction_id.remote_account):
+ raise osv.except_osv(
+ _("Error"),
+ _("No bank account available to link partner to"))
+
+ # Check if the bank account was already been linked
+ # manually to another transaction
+ remote_account = statement_line.import_transaction_id.remote_account
+ source_line_ids = self.search(
+ cr, uid,
+ [('import_transaction_id.remote_account', '=', remote_account),
+ ('partner_bank_id.partner_id', '!=', False),
+ ], limit=1, context=context)
+ if source_line_ids:
+ source_line = self.browse(
+ cr, uid, source_line_ids[0], context=context)
+ target_line_ids = self.search(
+ cr, uid,
+ [('import_transaction_id.remote_account', '=', remote_account),
+ ('partner_bank_id', '=', False),
+ ('state', '=', 'draft')], context=context)
+ self.write(
+ cr, uid, target_line_ids,
+ {'partner_bank_id': source_line.partner_bank_id.id,
+ 'partner_id': source_line.partner_bank_id.partner_id.id,
+ }, context=context)
+ return True
+
+ # Or fire the wizard to link partner and account
+ wizard_obj = self.pool.get('banking.link_partner')
+ res_id = wizard_obj.create(
+ cr, uid, {'statement_line_id': ids[0]}, context=context)
+ return wizard_obj.create_act_window(cr, uid, res_id, context=context)
+
+>>>>>>> MERGE-SOURCE
def _convert_currency(
self, cr, uid, from_curr_id, to_curr_id, from_amount,
round=False, date=None, context=None):
@@ -1595,7 +1949,13 @@
if st_line.import_transaction_id:
import_transaction_obj.confirm(
cr, uid, st_line.import_transaction_id.id, context)
- st_line.refresh()
+ # Workaround for
+ # https://bugs.launchpad.net/openobject-server/+bug/1238042
+ # Need to rebrowse instead of refresh, because any parent company
+ # will be in the browse record's id cache after the first pass, and
+ # accessing the actual company will then trigger a read attempt on
+ # the inaccessible parent company too, leading to an access error.
+ st_line = self.browse(cr, uid, st_line.id, context=context)
st_line_number = statement_pool.get_next_st_line_number(
cr, uid, st_number, st_line, context)
company_currency_id = st.journal_id.company_id.currency_id.id
@@ -1657,6 +2017,7 @@
raise orm.except_orm(
_('Confirmed Statement Line'),
_("You cannot delete a confirmed Statement Line"
+<<<<<<< TREE
": '%s'") % line.name)
if line.parent_id:
line.parent_id.write(
@@ -1664,6 +2025,15 @@
'amount': line.parent_id.amount + line.amount,
})
line.parent_id.refresh()
+=======
+ ": '%s'" % line.name))
+ if line.parent_id:
+ line.parent_id.write(
+ {
+ 'amount': line.parent_id.amount + line.amount,
+ })
+ line.parent_id.refresh()
+>>>>>>> MERGE-SOURCE
return super(account_bank_statement_line, self).unlink(
cr, uid, ids, context=context)
@@ -1703,6 +2073,7 @@
'import_transaction_id': res},
context=context)
+<<<<<<< TREE
def split_off(self, cr, uid, ids, amount, context=None):
"""
Create a child statement line with amount, deduce that from this line,
@@ -1749,6 +2120,55 @@
class account_bank_statement(orm.Model):
+=======
+ def split_off(self, cr, uid, ids, amount, context=None):
+ """
+ Create a child statement line with amount, deduce that from this line,
+ change transactions accordingly
+ """
+ if context is None:
+ context = {}
+
+ transaction_pool = self.pool.get('banking.import.transaction')
+
+ child_statement_ids = []
+ for this in self.browse(cr, uid, ids, context):
+ transaction_data = transaction_pool.copy_data(
+ cr, uid, this.import_transaction_id.id)
+ transaction_data['transferred_amount'] = amount
+ transaction_data['message'] = (
+ (transaction_data['message'] or '') + _(' (split)'))
+ transaction_data['parent_id'] = this.import_transaction_id.id
+ transaction_id = transaction_pool.create(
+ cr,
+ uid,
+ transaction_data,
+ context=dict(
+ context, transaction_no_duplicate_search=True))
+
+ statement_line_data = self.copy_data(
+ cr, uid, this.id)
+ statement_line_data['amount'] = amount
+ statement_line_data['name'] = (
+ (statement_line_data['name'] or '') + _(' (split)'))
+ statement_line_data['import_transaction_id'] = transaction_id
+ statement_line_data['parent_id'] = this.id
+ statement_line_id = self.create(
+ cr, uid, statement_line_data, context=context)
+
+ child_statement_ids.append(statement_line_id)
+ transaction_pool.write(
+ cr, uid, transaction_id, {
+ 'statement_line_id': statement_line_id,
+ }, context=context)
+ this.write({'amount': this.amount - amount})
+
+ return child_statement_ids
+
+account_bank_statement_line()
+
+class account_bank_statement(osv.osv):
+>>>>>>> MERGE-SOURCE
_inherit = 'account.bank.statement'
def _end_balance(self, cr, uid, ids, name, attr, context=None):
=== modified file 'account_banking/i18n/nl.po'
--- account_banking/i18n/nl.po 2014-02-11 06:47:45 +0000
+++ account_banking/i18n/nl.po 2014-03-06 13:49:10 +0000
@@ -134,6 +134,7 @@
msgstr "remote_bank_bic"
#. module: account_banking
+<<<<<<< TREE
#: code:addons/account_banking/banking_import_transaction.py:399
#, python-format
msgid "Cannot link transaction %s with accounting entry"
@@ -157,6 +158,21 @@
#, python-format
msgid "Cannot link transaction %s with invoice"
msgstr "Niet mogelijk transactie %s te koppelen met een factuur"
+=======
+#: field:banking.transaction.wizard,manual_invoice_ids:0
+msgid "Match one or more invoices"
+msgstr "Match een of meerdere facturen"
+
+#. module: account_banking
+#: field:banking.import.transaction,remote_bank_ibei:0
+msgid "remote_bank_ibei"
+msgstr "remote_bank_ibei"
+
+#. module: account_banking
+#: field:account.banking.account.settings,bank_partner_id:0
+msgid "Bank Partner"
+msgstr "Relatie bank"
+>>>>>>> MERGE-SOURCE
#. module: account_banking
#: model:ir.model,name:account_banking.model_account_banking_account_settings
@@ -967,6 +983,7 @@
msgstr "Herzien"
#. module: account_banking
+<<<<<<< TREE
#: selection:banking.import.transaction,payment_option:0
#: selection:banking.transaction.wizard,payment_option:0
msgid "Reconcile Payment Balance"
@@ -974,6 +991,19 @@
#. module: account_banking
#: code:addons/account_banking/account_banking.py:845
+=======
+#: field:banking.transaction.wizard,manual_move_line_ids:0
+msgid "Or match one or more entries"
+msgstr "Of koppel deze boekingsregel(s)"
+
+#. module: account_banking
+#: help:payment.mode.type,name:0
+msgid "Payment Type"
+msgstr "Betaaltype"
+
+#. module: account_banking
+#: code:addons/account_banking/account_banking.py:1281
+>>>>>>> MERGE-SOURCE
#, python-format
msgid "Insufficient data"
msgstr "Onvoldoende gegevens"
=== modified file 'account_banking/parsers/models.py'
--- account_banking/parsers/models.py 2014-01-05 02:07:34 +0000
+++ account_banking/parsers/models.py 2014-03-06 13:49:10 +0000
@@ -19,8 +19,13 @@
#
##############################################################################
+<<<<<<< TREE
import re
from openerp.tools.translate import _
+=======
+import re
+from tools.translate import _
+>>>>>>> MERGE-SOURCE
class mem_bank_statement(object):
'''
=== modified file 'account_banking/security/ir.model.access.csv'
=== modified file 'account_banking/sepa/iban.py'
=== modified file 'account_banking/static/src/js/account_banking.js'
--- account_banking/static/src/js/account_banking.js 2013-05-01 15:15:41 +0000
+++ account_banking/static/src/js/account_banking.js 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
/*############################################################################
#
# Copyright (C) 2013 Therp BV (<http://therp.nl>).
@@ -49,3 +50,56 @@
},
});
}
+=======
+/*############################################################################
+#
+# Copyright (C) 2013 Therp BV (<http://therp.nl>).
+#
+# All other contributions are (C) by their respective contributors
+#
+# All Rights Reserved
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract EduSense BV
+#
+# 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.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+############################################################################*/
+
+openerp.account_banking = function(openerp)
+{
+ var _t = openerp.web._t;
+ openerp.web.Dialog.include(
+ {
+ on_close: function()
+ {
+ this._super.apply(this, arguments);
+ if(this.dialog_title == _t("Match transaction"))
+ {
+ if(this.widget_parent.widget_children[0].views.form.controller)
+ {
+ this.widget_parent.widget_children[0].views.form.controller.reload();
+ }
+ if(this.widget_parent.widget_children[0].views.page.controller)
+ {
+ this.widget_parent.widget_children[0].views.page.controller.reload();
+ }
+ }
+ },
+ });
+}
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking/wizard/__init__.py'
=== added file 'account_banking/wizard/account_payment_order.py.OTHER'
--- account_banking/wizard/account_payment_order.py.OTHER 1970-01-01 00:00:00 +0000
+++ account_banking/wizard/account_payment_order.py.OTHER 2014-03-06 13:49:10 +0000
@@ -0,0 +1,131 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
+# 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.
+#
+# 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.
+#
+# You should have received a copy of the GNU 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):
+ _inherit = 'payment.order.create'
+
+ def create_payment(self, cr, uid, ids, context=None):
+ '''
+ This method is a slightly modified version of the existing method on this
+ model in account_payment.
+ - pass the payment mode to line2bank()
+ - allow invoices to create influence on the payment process: not only 'Free'
+ references are allowed, but others as well
+ - check date_to_pay is not in the past.
+ '''
+
+ order_obj = self.pool.get('payment.order')
+ line_obj = self.pool.get('account.move.line')
+ payment_obj = self.pool.get('payment.line')
+ if context is None:
+ context = {}
+ data = self.read(cr, uid, ids, [], context=context)[0]
+ line_ids = data['entries']
+ if not line_ids:
+ return {'type': 'ir.actions.act_window_close'}
+
+ payment = order_obj.browse(cr, uid, context['active_id'], context=context)
+ ### 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()
+ ### end account banking
+
+ ## Finally populate the current payment with new lines:
+ for line in line_obj.browse(cr, uid, line_ids, context=context):
+ if payment.date_prefered == "now":
+ #no payment date => immediate payment
+ date_to_pay = False
+ 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
+ ### 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
+ ### end account banking
+
+ ### account_banking
+ state = communication2 = False
+ communication = line.ref or '/'
+ if line.invoice:
+ if line.invoice.type in ('in_invoice', 'in_refund'):
+ if line.invoice.reference_type == 'structured':
+ state = 'structured'
+ communication = line.invoice.reference
+ else:
+ state = 'normal'
+ communication2 = line.invoice.reference
+ else:
+ # Make sure that the communication includes the
+ # customer invoice number (in the case of debit order)
+ communication = line.invoice.number.replace('/', '')
+ state = 'structured'
+ if line.invoice.number != line.ref:
+ communication2 = line.ref
+ else:
+ state = 'normal'
+ communication2 = line.ref
+
+ # support debit orders when enabled
+ if (payment.payment_order_type == 'debit' and
+ 'amount_to_receive' in line):
+ amount_currency = line.amount_to_receive
+ else:
+ amount_currency = line.amount_to_pay
+ ### end account_banking
+
+ payment_obj.create(cr, uid,{
+ 'move_line_id': line.id,
+ 'amount_currency': amount_currency,
+ 'bank_id': line2bank.get(line.id),
+ 'order_id': payment.id,
+ 'partner_id': line.partner_id and line.partner_id.id or False,
+ ### account banking
+ # 'communication': line.ref or '/'
+ 'communication': communication,
+ 'communication2': communication2,
+ 'state': state,
+ ### end account banking
+ 'date': date_to_pay,
+ '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()
=== modified file 'account_banking/wizard/banking_transaction_wizard.py'
--- account_banking/wizard/banking_transaction_wizard.py 2014-01-06 12:00:16 +0000
+++ account_banking/wizard/banking_transaction_wizard.py 2014-03-06 13:49:10 +0000
@@ -20,8 +20,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
+<<<<<<< TREE
from openerp.osv import orm, fields
+=======
+from osv import orm, osv, fields
+>>>>>>> MERGE-SOURCE
from openerp.tools.translate import _
"""
@@ -92,18 +96,84 @@
if not vals or not ids:
return True
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+
+ wiz = self.browse(cr, uid, ids[0], context=context)
wiz = self.browse(cr, uid, ids[0], context=context)
# The following fields get never written
# they are just triggers for manual matching
# which populates regular fields on the transaction
- manual_invoice_ids = vals.pop('manual_invoice_ids', [])
- manual_move_line_ids = vals.pop('manual_move_line_ids', [])
-
+<<<<<<< TREE
+ manual_invoice_ids = vals.pop('manual_invoice_ids', [])
+ manual_move_line_ids = vals.pop('manual_move_line_ids', [])
+
+=======
+ manual_invoice_ids = vals.pop('manual_invoice_ids', [])
+ manual_move_line_ids = vals.pop('manual_move_line_ids', [])
+ manual_payment_order_id = vals.pop('manual_payment_order_id', False)
+
+ if manual_payment_order_id:
+ payment_order = self.pool.get('payment.order').browse(
+ cr, uid, manual_payment_order_id,
+ context=context)
+ if (not hasattr(payment_order, 'payment_order_type')
+ or payment_order.payment_order_type == 'payment'):
+ sign = 1
+ else:
+ sign = -1
+ total = (payment_order.total + sign *
+ wiz.import_transaction_id.transferred_amount)
+ if not self.pool.get('res.currency').is_zero(
+ cr, uid, wiz.import_transaction_id.statement_id.currency, total):
+ raise orm.except_orm(
+ _('Error'),
+ _('When matching a payment order, the amounts have to '
+ 'match exactly'))
+
+ vals.update(
+ {
+ 'payment_order_id': manual_payment_order_id,
+ 'match_type': 'payment_order_manual',
+ })
+
+ if payment_order.mode and payment_order.mode.transfer_account_id:
+ statement_line_obj.write(
+ cr, uid, wiz.import_transaction_id.statement_line_id.id,
+ {'account_id': payment_order.mode.transfer_account_id.id},
+ context=context)
+
+ # Support for writing fields.related is still flakey:
+ # https://bugs.launchpad.net/openobject-server/+bug/915975
+ # Will do so myself.
+
+ # Separate the related fields
+ transaction_vals = {}
+ wizard_vals = vals.copy()
+ for key in vals.keys():
+ field = self._columns[key]
+ if (isinstance(field, fields.related) and
+ field._arg[0] == 'import_transaction_id'):
+ transaction_vals[field._arg[1]] = vals[key]
+ del wizard_vals[key]
+
+ # write the related fields on the transaction model
+ transaction_obj.write(
+ cr, uid, wiz.import_transaction_id.id,
+ transaction_vals, context=context)
+
+ # write other fields to the wizard model
+>>>>>>> MERGE-SOURCE
res = super(banking_transaction_wizard, self).write(
+<<<<<<< TREE
cr, uid, ids, vals, context=context)
wiz.refresh()
+=======
+ cr, uid, ids, wizard_vals, context=context)
+ wiz.refresh()
+>>>>>>> MERGE-SOURCE
# Process the logic of the written values
@@ -111,12 +181,20 @@
if vals and 'invoice_id' in vals:
if (wiz.import_transaction_id.match_type == 'invoice' and
wiz.import_transaction_id.invoice_id):
+<<<<<<< TREE
found = False
# the current value might apply
if (wiz.move_line_id and wiz.move_line_id.invoice and
wiz.move_line_id.invoice == wiz.invoice_id):
found = True
else:
+=======
+ # the current value might apply
+ if (wiz.move_line_id and wiz.move_line_id.invoice and
+ wiz.move_line_id.invoice.id == wiz.invoice_id.id):
+ found = True
+ else:
+>>>>>>> MERGE-SOURCE
# Otherwise, retrieve the move line for this invoice
# Given the arity of the relation, there is are always
# multiple possibilities but the move lines here are
@@ -124,8 +202,13 @@
# and the regular invoice workflow should only come up with
# one of those only.
for move_line in wiz.import_transaction_id.move_line_ids:
+<<<<<<< TREE
if (move_line.invoice ==
wiz.import_transaction_id.invoice_id):
+=======
+ if (move_line.invoice.id ==
+ wiz.import_transaction_id.invoice_id.id):
+>>>>>>> MERGE-SOURCE
transaction_obj.write(
cr, uid, wiz.import_transaction_id.id,
{ 'move_line_id': move_line.id, }, context=context)
@@ -136,17 +219,27 @@
}, context=context)
found = True
break
+<<<<<<< TREE
# Cannot match the invoice
if not found:
orm.except_orm(
_("No entry found for the selected invoice"),
_("No entry found for the selected invoice. " +
"Try manual reconciliation."))
+=======
+ # Cannot match the invoice
+ if not found:
+ osv.except_osv(
+ _("No entry found for the selected invoice"),
+ _("No entry found for the selected invoice. " +
+ "Try manual reconciliation."))
+>>>>>>> MERGE-SOURCE
if manual_move_line_ids or manual_invoice_ids:
move_line_obj = self.pool.get('account.move.line')
invoice_obj = self.pool.get('account.invoice')
statement_line_obj = self.pool.get('account.bank.statement.line')
+<<<<<<< TREE
# Rewrite *2many directive notation
if manual_invoice_ids:
manual_invoice_ids = (
@@ -169,16 +262,43 @@
for invoice in invoice_obj.browse(
cr, uid, manual_invoice_ids, context=context):
found_move_line = False
+=======
+ manual_invoice_ids = (
+ [i[1] for i in manual_invoice_ids if i[0]==4] +
+ [j for i in manual_invoice_ids if i[0]==6 for j in i[2]])
+ manual_move_line_ids = (
+ [i[1] for i in manual_move_line_ids if i[0]==4] +
+ [j for i in manual_move_line_ids if i[0]==6 for j in i[2]])
+ for wiz in self.browse(cr, uid, ids, context=context):
+ #write can be called multiple times for the same values
+ #that doesn't hurt above, but it does here
+ if wiz.match_type and (
+ len(manual_move_line_ids) > 1 or
+ len(manual_invoice_ids) > 1):
+ continue
+
+ todo = []
+
+ for invoice in invoice_obj.browse(
+ cr, uid, manual_invoice_ids, context=context):
+ found_move_line = False
+>>>>>>> MERGE-SOURCE
if invoice.move_id:
for line in invoice.move_id.line_id:
if line.account_id.type in ('receivable', 'payable'):
todo.append((invoice.id, line.id))
found_move_line = True
break
+<<<<<<< TREE
if not found_move_line:
raise orm.except_orm(
+=======
+ if not found_move_line:
+ raise osv.except_osv(
+>>>>>>> MERGE-SOURCE
_("Cannot select for reconcilion"),
_("No entry found for the selected invoice. "))
+<<<<<<< TREE
for move_line_id in manual_move_line_ids:
todo_entry = [False, move_line_id]
move_line=move_line_obj.read(
@@ -233,6 +353,62 @@
statement_line_obj.write(
cr, uid, statement_line_id,
st_line_vals, context=context)
+=======
+ for move_line_id in manual_move_line_ids:
+ todo_entry = [False, move_line_id]
+ move_line=move_line_obj.read(
+ cr,
+ uid,
+ move_line_id,
+ ['invoice'],
+ context=context)
+ if move_line['invoice']:
+ todo_entry[0] = move_line['invoice'][0]
+ todo.append(todo_entry)
+
+ while todo:
+ todo_entry = todo.pop()
+ move_line = move_line_obj.browse(
+ cr, uid, todo_entry[1], context)
+ transaction_id = wiz.import_transaction_id.id
+ statement_line_id = wiz.statement_line_id.id
+
+ if len(todo) > 0:
+ statement_line_id = wiz.statement_line_id.split_off(
+ move_line.debit or -move_line.credit)[0]
+ transaction_id = statement_line_obj.browse(
+ cr,
+ uid,
+ statement_line_id,
+ context=context).import_transaction_id.id
+
+ vals = {
+ 'move_line_id': todo_entry[1],
+ 'move_line_ids': [(6, 0, [todo_entry[1]])],
+ 'invoice_id': todo_entry[0],
+ 'invoice_ids': [(6, 0,
+ [todo_entry[0]] if todo_entry[0] else [])],
+ 'match_type': 'manual',
+ }
+
+ transaction_obj.clear_and_write(
+ cr, uid, transaction_id, vals, context=context)
+
+ st_line_vals = {
+ 'account_id': move_line_obj.read(
+ cr, uid, todo_entry[1],
+ ['account_id'], context=context)['account_id'][0],
+ }
+
+ if todo_entry[0]:
+ st_line_vals['partner_id'] = invoice_obj.read(
+ cr, uid, todo_entry[0],
+ ['partner_id'], context=context)['partner_id'][0]
+
+ statement_line_obj.write(
+ cr, uid, statement_line_id,
+ st_line_vals, context=context)
+>>>>>>> MERGE-SOURCE
return res
def trigger_write(self, cr, uid, ids, context=None):
@@ -256,6 +432,7 @@
account_id = False
journal_id = wiz.statement_line_id.statement_id.journal_id.id
setting_ids = settings_pool.find(cr, uid, journal_id, context=context)
+<<<<<<< TREE
# Restore partner id from the bank account or else reset
partner_id = False
@@ -307,6 +484,54 @@
wiz.import_transaction_id.clear_and_write()
return self.create_act_window(cr, uid, ids, context=None)
+=======
+
+ # Restore partner id from the bank account or else reset
+ partner_id = False
+ if (wiz.statement_line_id.partner_bank_id and
+ wiz.statement_line_id.partner_bank_id.partner_id):
+ partner_id = wiz.statement_line_id.partner_bank_id.partner_id.id
+ wiz.write({'partner_id': partner_id})
+
+ # Select account type by parter customer or supplier,
+ # or default based on amount sign
+ bank_partner = False
+ if partner_id:
+ bank_partner = wiz.statement_line_id.partner_bank_id.partner_id
+ if wiz.amount < 0:
+ if bank_partner:
+ account_id = bank_partner.\
+ def_journal_account_bank_decr()[bank_partner.id]
+ elif setting_ids:
+ account_id = settings_pool.browse(
+ cr, uid, setting_ids[0],
+ context=context).default_credit_account_id.id
+ else:
+ if bank_partner:
+ account_id = bank_partner.\
+ def_journal_account_bank_incr()[bank_partner.id]
+ elif setting_ids:
+ account_id = settings_pool.browse(
+ cr, uid, setting_ids[0],
+ context=context).default_debit_account_id.id
+
+ if account_id:
+ wiz.statement_line_id.write({'account_id': account_id})
+
+ if wiz.statement_line_id:
+ #delete splits causing an unsplit if this is a split
+ #transaction
+ statement_pool.unlink(cr, uid,
+ statement_pool.search(cr, uid,
+ [('parent_id', '=', wiz.statement_line_id.id)],
+ context=context),
+ context=context)
+
+ if wiz.import_transaction_id:
+ wiz.import_transaction_id.clear_and_write()
+
+ return True
+>>>>>>> MERGE-SOURCE
def reverse_duplicate(self, cr, uid, ids, context=None):
if isinstance(ids, (int, long)):
@@ -321,7 +546,15 @@
return self.create_act_window(cr, uid, ids, context=None)
def button_done(self, cr, uid, ids, context=None):
- return {'type': 'ir.actions.act_window_close'}
+<<<<<<< TREE
+ return {'type': 'ir.actions.act_window_close'}
+=======
+ return {'type': 'ir.actions.act_window_close'}
+
+ _defaults = {
+# 'match_type': _get_default_match_type,
+ }
+>>>>>>> MERGE-SOURCE
_columns = {
'name': fields.char('Name', size=64),
@@ -378,6 +611,7 @@
'import_transaction_id', 'match_multi',
type="boolean", string='Multiple matches'),
'match_type': fields.related(
+<<<<<<< TREE
'import_transaction_id', 'match_type', type='selection',
selection=[
('move','Move'),
@@ -394,13 +628,29 @@
'account.invoice',
'banking_transaction_wizard_account_invoice_rel',
'wizard_id', 'invoice_id', string='Match one or more invoices',
+=======
+ 'import_transaction_id', 'match_type',
+ type="char", size=16, string='Match type', readonly=True),
+ 'manual_invoice_ids': fields.many2many(
+ 'account.invoice',
+ 'banking_transaction_wizard_account_invoice_rel',
+ 'wizard_id', 'invoice_id', string='Match one or more invoices',
+>>>>>>> MERGE-SOURCE
domain=[('reconciled', '=', False)]),
'manual_move_line_ids': fields.many2many(
'account.move.line',
'banking_transaction_wizard_account_move_line_rel',
'wizard_id', 'move_line_id', string='Or match one or more entries',
domain=[('account_id.reconcile', '=', True),
- ('reconcile_id', '=', False)]),
+<<<<<<< TREE
+ ('reconcile_id', '=', False)]),
+=======
+ ('reconcile_id', '=', False)]),
+ 'manual_payment_order_id': fields.many2one(
+ 'payment.order', 'Match this payment order',
+ domain=[('state', '=', 'sent')],
+ ),
+>>>>>>> MERGE-SOURCE
'payment_option': fields.related('import_transaction_id','payment_option', string='Payment Difference', type='selection', required=True,
selection=[('without_writeoff', 'Keep Open'),('with_writeoff', 'Reconcile Payment Balance')]),
'writeoff_analytic_id': fields.related(
=== modified file 'account_banking/wizard/banking_transaction_wizard.xml'
--- account_banking/wizard/banking_transaction_wizard.xml 2014-01-06 12:01:01 +0000
+++ account_banking/wizard/banking_transaction_wizard.xml 2014-03-06 13:49:10 +0000
@@ -7,7 +7,12 @@
<field name="arch" type="xml">
<form string="Match transaction" version="7.0">
<!-- fields used for form logic -->
- <field name="statement_line_parent_id" invisible="True"/>
+<<<<<<< TREE
+ <field name="statement_line_parent_id" invisible="True"/>
+=======
+ <field name="payment_order_ids" invisible="True"/>
+ <field name="statement_line_parent_id" invisible="True"/>
+>>>>>>> MERGE-SOURCE
<field name="invoice_ids" invisible="True"/>
<field name="move_line_ids" invisible="True"/>
<field name="match_multi" invisible="True"/>
@@ -88,6 +93,7 @@
</page>
<!-- Manual selection -->
<page string="Manual match">
+<<<<<<< TREE
<separator string="Match one or more invoices" colspan="4"/>
<field name="manual_invoice_ids" colspan="4"
context="{'search_default_partner_id': partner_id}"
@@ -97,6 +103,17 @@
context="{'search_default_partner_id': partner_id}"
/>
<button name="trigger_write"
+=======
+ <field name="manual_invoice_ids" colspan="4"
+ context="{'search_default_partner_id': partner_id}"
+ />
+ <field name="manual_move_line_ids" colspan="4"
+ context="{'search_default_partner_id': partner_id}"
+ />
+ <field name="manual_payment_order_id"/>
+ <group colspan="2"/>
+ <button name="trigger_write"
+>>>>>>> MERGE-SOURCE
type="object"
string="Match" />
</page>
@@ -125,10 +142,18 @@
</group>
</page>
</notebook>
+<<<<<<< TREE
<footer>
<button icon="gtk-ok" string="Close" special="cancel"/>
</footer>
+=======
+ <group colspan="2">
+ <separator/>
+ <button icon="gtk-ok" string="Close" special="cancel"/>
+ </group>
+ </group>
+>>>>>>> MERGE-SOURCE
</form>
</field>
</record>
=== modified file 'account_banking/wizard/banktools.py'
--- account_banking/wizard/banktools.py 2013-09-14 11:54:23 +0000
+++ account_banking/wizard/banktools.py 2014-03-06 13:49:10 +0000
@@ -19,9 +19,17 @@
#
##############################################################################
+<<<<<<< TREE
from openerp.tools.translate import _
from openerp.addons.account_banking import sepa
from openerp.addons.account_banking.struct import struct
+=======
+import datetime
+from tools.translate import _
+from account_banking.parsers import convert
+from account_banking import sepa
+from account_banking.struct import struct
+>>>>>>> MERGE-SOURCE
__all__ = [
'get_period',
@@ -75,8 +83,13 @@
_('Bank account %(account_no)s was not found in the database')
% dict(account_no=account_number)
)
+<<<<<<< TREE
return []
return partner_bank_obj.browse(cr, uid, bank_account_ids)
+=======
+ return []
+ return partner_bank_obj.browse(cursor, uid, bank_account_ids)
+>>>>>>> MERGE-SOURCE
def _has_attr(obj, attr):
# Needed for dangling addresses and a weird exception scheme in
@@ -97,19 +110,35 @@
TODO: revive the search by lines from the address argument
'''
partner_obj = pool.get('res.partner')
+<<<<<<< TREE
partner_ids = partner_obj.search(
cr, uid, [
'|', ('is_company', '=', True), ('parent_id', '=', False),
('name', 'ilike', name),
], context=context)
+=======
+ partner_ids = partner_obj.search(cr, uid, [('name', 'ilike', name)],
+ context=context)
+>>>>>>> MERGE-SOURCE
if not partner_ids:
# Try brute search on address and then match reverse
+<<<<<<< TREE
criteria = []
if country_id:
criteria.append(('country_id', '=', country_id))
+=======
+ criteria = []
+ if country_id:
+ criteria.append(('address.country_id', '=', country_id))
+>>>>>>> MERGE-SOURCE
if city:
+<<<<<<< TREE
criteria.append(('city', 'ilike', city))
+=======
+ criteria.append(('address.city', 'ilike', city))
+>>>>>>> MERGE-SOURCE
if postal_code:
+<<<<<<< TREE
criteria.append(('zip', 'ilike', postal_code))
partner_search_ids = partner_obj.search(
cr, uid, criteria, context=context)
@@ -118,7 +147,18 @@
criteria[0] = ('country_id', '=', False)
partner_search_ids = partner_obj.search(
cr, uid, criteria, context=context)
+=======
+ criteria.append(('address.zip', 'ilike', postal_code))
+ partner_search_ids = partner_obj.search(
+ cr, uid, criteria, context=context)
+ if (not partner_search_ids and country_id):
+ # Try again with country_id = False
+ criteria[0] = ('address.country_id', '=', False)
+ partner_search_ids = partner_obj.search(
+ cr, uid, criteria, context=context)
+>>>>>>> MERGE-SOURCE
key = name.lower()
+<<<<<<< TREE
partners = []
for partner in partner_obj.read(
cr, uid, partner_search_ids, ['name', 'commercial_partner_id'], context=context):
@@ -133,6 +173,22 @@
return partner_ids and partner_ids[0] or False
def get_company_bank_account(pool, cr, uid, account_number, currency,
+=======
+ partners = []
+ for partner in partner_obj.read(
+ cr, uid, partner_search_ids, ['name'], context=context):
+ if (len(partner['name']) > 3 and partner['name'].lower() in key):
+ partners.append(partner)
+ partners.sort(key=lambda x: len(x['name']), reverse=True)
+ partner_ids = [x['id'] for x in partners]
+ if len(partner_ids) > 1:
+ log.append(
+ _('More than one possible match found for partner with '
+ 'name %(name)s') % {'name': name})
+ return partner_ids and partner_ids[0] or False
+
+def get_company_bank_account(pool, cursor, uid, account_number, currency,
+>>>>>>> MERGE-SOURCE
company, log):
'''
Get the matching bank account for this company. Currency is the ISO code
=== modified file 'account_banking/wizard/link_partner.py'
--- account_banking/wizard/link_partner.py 2014-01-21 07:55:55 +0000
+++ account_banking/wizard/link_partner.py 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# -*- coding: utf-8 -*-
##############################################################################
#
@@ -207,3 +208,162 @@
}
+=======
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2013 Therp BV (<http://therp.nl>).
+# 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.
+#
+# 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.
+#
+# You should have received a copy of the GNU 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.addons.account_banking.wizard import banktools
+
+class link_partner(orm.TransientModel):
+ _name = 'banking.link_partner'
+ _inherit = 'res.partner.address'
+ _description = 'Link partner'
+
+ _columns = {
+ 'name': fields.char(
+ 'Create partner with name', size=128, required=True),
+ 'supplier': fields.boolean('Supplier'),
+ 'customer': fields.boolean('Customer'),
+ 'partner_id': fields.many2one(
+ 'res.partner', 'or link existing partner'),
+ 'statement_line_id': fields.many2one(
+ 'account.bank.statement.line',
+ 'Statement line', required=True),
+ 'remote_account': fields.char(
+ 'Account number', size=24, readonly=True),
+ }
+
+ def create(self, cr, uid, vals, context=None):
+ """
+ Get default values from the transaction data
+ on the statement line
+ """
+ if vals and vals.get('statement_line_id'):
+ statement_line_obj = self.pool.get('account.bank.statement.line')
+ statement_line = statement_line_obj.browse(
+ cr, uid, vals['statement_line_id'], context=context)
+ transaction = statement_line.import_transaction_id
+
+ if statement_line.partner_bank_id:
+ raise orm.except_orm(
+ _('Error'),
+ _('Statement line is already linked to a bank account '))
+
+ if not(transaction and transaction.remote_owner
+ and transaction.remote_account):
+ raise orm.except_orm(
+ _('Error'),
+ _('No transaction data on statement line'))
+
+ if 'supplier' not in vals and statement_line.amount < 0:
+ vals['supplier'] = True
+ if 'customer' not in vals and statement_line.amount > 0:
+ vals['customer'] = True
+
+ if not vals.get('street'):
+ vals['street'] = transaction.remote_owner_address
+ if not vals.get('street'):
+ vals['city'] = transaction.remote_owner_city
+ if not vals.get('country_id'):
+ vals['country_id'] = banktools.get_country_id(
+ self.pool, cr, uid, transaction, context=context)
+ if not vals.get('name'):
+ vals['name'] = transaction.remote_owner
+ if not vals.get('remote_account'):
+ vals['remote_account'] = transaction.remote_account
+
+ return super(link_partner, self).create(
+ cr, uid, vals, context=context)
+
+ def link_partner(self, cr, uid, ids, context=None):
+ statement_line_obj = self.pool.get(
+ 'account.bank.statement.line')
+ wiz = self.browse(cr, uid, ids[0], context=context)
+
+ if wiz.partner_id:
+ partner_id = wiz.partner_id.id
+ else:
+ partner_id = self.pool.get('res.partner').create(
+ cr, uid, {
+ 'name': wiz.name,
+ 'customer': wiz.customer,
+ 'supplier': wiz.supplier,
+ }, context=context)
+ wiz_read = self.read(
+ cr, uid, ids[0], context=context, load='_classic_write')
+ address_fields = self.pool.get(
+ 'res.partner.address')._columns.keys()
+ address_vals = {}
+ for field in self._columns.keys():
+ # NB: wizard model contains 'partner_id' like the address
+ # but in this code path it is False
+ if field in address_fields:
+ address_vals[field] = wiz_read[field]
+ address_vals.update({
+ 'partner_id': partner_id,
+ 'type': 'default',
+ })
+ self.pool.get('res.partner.address').create(
+ cr, uid, address_vals, context=context)
+
+ partner_bank_id = banktools.create_bank_account(
+ self.pool, cr, uid, partner_id,
+ wiz.remote_account, wiz.name,
+ wiz.street, wiz.city,
+ wiz.country_id and wiz.country_id.id or False,
+ bic=wiz.statement_line_id.import_transaction_id.remote_bank_bic
+ )
+
+ statement_line_ids = statement_line_obj.search(
+ cr, uid,
+ [('import_transaction_id.remote_account', '=', wiz.remote_account),
+ ('partner_bank_id', '=', False),
+ ('state', '=', 'draft')], context=context)
+ statement_line_obj.write(
+ cr, uid, statement_line_ids,
+ {'partner_bank_id': partner_bank_id,
+ 'partner_id': partner_id}, context=context)
+
+ return {'type': 'ir.actions.act_window_close'}
+
+ def create_act_window(self, cr, uid, ids, nodestroy=True, context=None):
+ """
+ Return a popup window for this model
+ """
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ return {
+ 'name': self._description,
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': self._name,
+ 'domain': [],
+ 'context': context,
+ 'type': 'ir.actions.act_window',
+ 'target': 'new',
+ 'res_id': ids[0],
+ 'nodestroy': nodestroy,
+ }
+
+
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking/wizard/link_partner.xml'
--- account_banking/wizard/link_partner.xml 2013-10-31 07:33:46 +0000
+++ account_banking/wizard/link_partner.xml 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
@@ -59,3 +60,52 @@
</record>
</data>
</openerp>
+=======
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <record model="ir.ui.view" id="link_partner_view">
+ <field name="name">Link partner wizard view</field>
+ <field name="type">form</field>
+ <field name="model">banking.link_partner</field>
+ <field name="arch" type="xml">
+ <form string="Link partner">
+ <group colspan="4" col="6">
+ <field name="name"
+ attrs="{'readonly': [('partner_id', '!=', False)]}" />
+ <field name="partner_id"/>
+ <field name="remote_account" />
+ </group>
+ <group colspan="4"
+ string="Address"
+ attrs="{'invisible': [('partner_id', '!=', False)]}">
+ <group colspan="2" col="2">
+ <field name="street"/>
+ <field name="street2"/>
+ <field name="zip"/>
+ <field name="city"/>
+ <field name="country_id"/>
+ <field name="state_id"/>
+ </group>
+ <group colspan="2" col="2">
+ <field name="phone"/>
+ <field name="fax"/>
+ <field name="mobile"/>
+ <field name="email" widget="email"/>
+ </group>
+ </group>
+ <button icon="gtk-cancel" string="Cancel" special="cancel" />
+ <button icon="gtk-ok" string="Create partner"
+ name="link_partner" type="object"
+ attrs="{'invisible': [('partner_id', '!=', False)]}"
+ />
+ <button icon="gtk-ok" string="Link existing partner"
+ name="link_partner" type="object"
+ attrs="{'invisible': [('partner_id', '==', False)]}"
+ />
+ </form>
+ </field>
+ </record>
+ </data>
+</openerp>
+>>>>>>> MERGE-SOURCE
=== added directory 'account_banking_aggregate_payment'
=== added file 'account_banking_aggregate_payment/__init__.py'
--- account_banking_aggregate_payment/__init__.py 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/__init__.py 2014-03-06 13:49:10 +0000
@@ -0,0 +1,1 @@
+import model
=== added file 'account_banking_aggregate_payment/__openerp__.py'
--- account_banking_aggregate_payment/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/__openerp__.py 2014-03-06 13:49:10 +0000
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
+#
+# 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 Aggregate Payment',
+ 'version': '0.1.173',
+ 'license': 'AGPL-3',
+ 'author': 'Therp BV',
+ 'website': 'https://launchpad.net/banking-addons',
+ 'category': 'Banking addons',
+ 'depends': ['account_direct_debit'],
+ 'data': [
+ 'data/payment_mode_type.xml',
+ 'view/payment_mode.xml',
+ 'view/export_aggregate.xml',
+ ],
+ 'description': '''
+ This module allows for aggregating payments for various creditors
+ and making them payable to a single partner. This is practiced in
+ certain purchasing consortia.
+
+ After collection of the payable invoices on a payment order of type
+ 'Aggregate payment', the move lines in the payment order are
+ reconciled by a move on a transit account, the total amount of which
+ is then transferred onto the designated partner's account payable
+ (upon confirmation of the aggregate payment order).
+
+ The payment order wizard then proceeds to create a new payment order
+ of a user chosen payment mode with only the aggregate move line in it.
+ ''',
+ 'active': False,
+}
=== added directory 'account_banking_aggregate_payment/data'
=== added file 'account_banking_aggregate_payment/data/payment_mode_type.xml'
--- account_banking_aggregate_payment/data/payment_mode_type.xml 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/data/payment_mode_type.xml 2014-03-06 13:49:10 +0000
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+ <record model="payment.mode.type"
+ id="type_aggregate">
+ <field name="name">Aggregate payment</field>
+ <field name="code">AGGR</field>
+ <field name="suitable_bank_types"
+ eval="[(6, 0, (ref('base_iban.bank_iban'),
+ ref('base.bank_normal')))]" />
+ <field name="ir_model_id"
+ ref="model_banking_export_aggregate"/>
+ </record>
+
+ </data>
+</openerp>
=== added directory 'account_banking_aggregate_payment/i18n'
=== added file 'account_banking_aggregate_payment/i18n/account_banking_aggregate_payment.pot'
--- account_banking_aggregate_payment/i18n/account_banking_aggregate_payment.pot 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/i18n/account_banking_aggregate_payment.pot 2014-03-06 13:49:10 +0000
@@ -0,0 +1,175 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_banking_aggregate_payment
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 6.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-06-13 19:35+0000\n"
+"PO-Revision-Date: 2013-06-13 19:35+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_banking_aggregate_payment
+#: view:payment.mode:0
+msgid "Aggregate payment"
+msgstr "Aggregate payment"
+
+#. module: account_banking_aggregate_payment
+#: view:banking.export.aggregate:0
+msgid "Create"
+msgstr "Create"
+
+#. module: account_banking_aggregate_payment
+#: help:payment.mode,aggregate_partner_id:0
+msgid "The single partner on the chained payment order"
+msgstr "The single partner on the chained payment order"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:134
+#, python-format
+msgid "Aggregate Payment Order %s"
+msgstr "Aggregate Payment Order %s"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:230
+#, python-format
+msgid "Payment order workflow does not go into state \"done\""
+msgstr "Payment order workflow does not go into state \"done\""
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:143
+#, python-format
+msgid "No move line provided for line %s"
+msgstr "No move line provided for line %s"
+
+#. module: account_banking_aggregate_payment
+#: model:ir.model,name:account_banking_aggregate_payment.model_payment_mode
+msgid "Payment Mode"
+msgstr "Payment Mode"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:48
+#, python-format
+msgid "Please only select a single payment order"
+msgstr "Please only select a single payment order"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:147
+#, python-format
+msgid "Move line %s has already been paid/reconciled"
+msgstr "Move line %s has already been paid/reconciled"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:44
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:121
+#, python-format
+msgid "Please select a payment order"
+msgstr "Please select a payment order"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:125
+#, python-format
+msgid "This operation can only be performed on a single payment order"
+msgstr "This operation can only be performed on a single payment order"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:155
+#, python-format
+msgid "Transit %s"
+msgstr "Transit %s"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:191
+#, python-format
+msgid "Transit reconciliation"
+msgstr "Transit reconciliation"
+
+#. module: account_banking_aggregate_payment
+#: view:banking.export.aggregate:0
+msgid "Export aggregate payment order"
+msgstr "Export aggregate payment order"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:208
+#, python-format
+msgid "Amount payable"
+msgstr "Amount payable"
+
+#. module: account_banking_aggregate_payment
+#: field:payment.mode,aggregate_partner_id:0
+msgid "Aggregate payment beneficiary"
+msgstr "Aggregate payment beneficiary"
+
+#. module: account_banking_aggregate_payment
+#: help:payment.mode,chained_mode_id:0
+msgid "The payment type of the chained payment order"
+msgstr "The payment type of the chained payment order"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:43
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:47
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:65
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:71
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:120
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:124
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:142
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:146
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:229
+#, python-format
+msgid "Error"
+msgstr "Error"
+
+#. module: account_banking_aggregate_payment
+#: model:ir.model,name:account_banking_aggregate_payment.model_banking_export_aggregate
+msgid "Execute aggregate payment"
+msgstr "Execute aggregate payment"
+
+#. module: account_banking_aggregate_payment
+#: view:banking.export.aggregate:0
+msgid "When you confirm this order, the total amount will be made payable to the partner that has been set on the payment mode. A new payment order will open in your screen with this one payment."
+msgstr "When you confirm this order, the total amount will be made payable to the partner that has been set on the payment mode. A new payment order will open in your screen with this one payment."
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:172
+#, python-format
+msgid "Reconciliation %s"
+msgstr "Reconciliation %s"
+
+#. module: account_banking_aggregate_payment
+#: field:banking.export.aggregate,reference:0
+msgid "Reference"
+msgstr "Reference"
+
+#. module: account_banking_aggregate_payment
+#: field:banking.export.aggregate,payment_order_id:0
+msgid "Payment order"
+msgstr "Payment order"
+
+#. module: account_banking_aggregate_payment
+#: field:payment.mode,chained_mode_id:0
+msgid "Chained payment mode"
+msgstr "Chained payment mode"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:66
+#, python-format
+msgid "Cannot reconcile between different accounts"
+msgstr "Cannot reconcile between different accounts"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:72
+#, python-format
+msgid "Line is already fully reconciled"
+msgstr "Line is already fully reconciled"
+
+#. module: account_banking_aggregate_payment
+#: view:banking.export.aggregate:0
+msgid "Cancel"
+msgstr "Cancel"
+
=== added file 'account_banking_aggregate_payment/i18n/nl.po'
--- account_banking_aggregate_payment/i18n/nl.po 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/i18n/nl.po 2014-03-06 13:49:10 +0000
@@ -0,0 +1,170 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_banking_aggregate_payment
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 6.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-06-13 19:35+0000\n"
+"PO-Revision-Date: 2013-06-13 19:35+0000\n"
+"Last-Translator: <stefan@xxxxxxxx>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_banking_aggregate_payment
+#: view:payment.mode:0
+msgid "Aggregate payment"
+msgstr "Verzamelbetaalopdracht"
+
+#. module: account_banking_aggregate_payment
+#: view:banking.export.aggregate:0
+msgid "Create"
+msgstr "Aanmaken"
+
+#. module: account_banking_aggregate_payment
+#: help:payment.mode,aggregate_partner_id:0
+msgid "The single partner on the chained payment order"
+msgstr "De relatie die geldt als crediteur van het verzameld bedrag"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:134
+#, python-format
+msgid "Aggregate Payment Order %s"
+msgstr "Verzamelbetaling %s"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:230
+#, python-format
+msgid "Payment order workflow does not go into state \"done\""
+msgstr "De workflow van de betaalopdracht komt niet in de status \"verwerkt\""
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:143
+#, python-format
+msgid "No move line provided for line %s"
+msgstr "Er is geen boeking voor regel %s"
+
+#. module: account_banking_aggregate_payment
+#: model:ir.model,name:account_banking_aggregate_payment.model_payment_mode
+msgid "Payment Mode"
+msgstr "Betaalwijze"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:48
+#, python-format
+msgid "Please only select a single payment order"
+msgstr "Er kan maar één betaalopdracht worden geselecteerd"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:147
+#, python-format
+msgid "Move line %s has already been paid/reconciled"
+msgstr "Boekingsregel %s is al afgeletterd"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:44
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:121
+#, python-format
+msgid "Please select a payment order"
+msgstr "Selecteer alstublieft een betaalopdracht"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:125
+#, python-format
+msgid "This operation can only be performed on a single payment order"
+msgstr "Deze bewerking kan alleen worden uitgevoerd op een enkele betaalopdracht"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:155
+#, python-format
+msgid "Transit %s"
+msgstr "Tussenboeking %s"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:191
+#, python-format
+msgid "Transit reconciliation"
+msgstr "Aflettering tussenboeking"
+
+#. module: account_banking_aggregate_payment
+#: view:banking.export.aggregate:0
+msgid "Export aggregate payment order"
+msgstr "Verwerken een verzamelbetalingsopdracht"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:208
+#, python-format
+msgid "Amount payable"
+msgstr "Verschuldigd bedrag"
+
+#. module: account_banking_aggregate_payment
+#: field:payment.mode,aggregate_partner_id:0
+msgid "Aggregate payment beneficiary"
+msgstr "Begunstigde van de verzamelbetaling"
+
+#. module: account_banking_aggregate_payment
+#: help:payment.mode,chained_mode_id:0
+msgid "The payment type of the chained payment order"
+msgstr "De betaalwijze van de gekoppelde betaalopdracht"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:43
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:47
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:65
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:71
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:120
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:124
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:142
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:146
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:229
+#, python-format
+msgid "Error"
+msgstr "Fout"
+
+#. module: account_banking_aggregate_payment
+#: model:ir.model,name:account_banking_aggregate_payment.model_banking_export_aggregate
+msgid "Execute aggregate payment"
+msgstr "Verzamelbetaling boeken"
+
+#. module: account_banking_aggregate_payment
+#: view:banking.export.aggregate:0
+msgid "When you confirm this order, the total amount will be made payable to the partner that has been set on the payment mode. A new payment order will open in your screen with this one payment."
+msgstr "Als u deze betaalopdracht bevestigd, dan wordt het totaalbedrag betaalbaar gemaakt aan de relatie die op de betaalwijze aangegeven staat. In het scherm wordt een nieuwe betaalopdracht geopend met alleen dit totaalbedrag."
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:172
+#, python-format
+msgid "Reconciliation %s"
+msgstr "Aflettering %s"
+
+#. module: account_banking_aggregate_payment
+#: field:banking.export.aggregate,payment_order_id:0
+msgid "Payment order"
+msgstr "Betaalopdracht"
+
+#. module: account_banking_aggregate_payment
+#: field:payment.mode,chained_mode_id:0
+msgid "Chained payment mode"
+msgstr "Gekoppelde betaalwijze"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:66
+#, python-format
+msgid "Cannot reconcile between different accounts"
+msgstr "Kan niet afletteren tussen verschillende grootboekrekeningen"
+
+#. module: account_banking_aggregate_payment
+#: code:addons/account_banking_aggregate_payment/model/export_aggregate.py:72
+#, python-format
+msgid "Line is already fully reconciled"
+msgstr "De regel is al afgeletterd"
+
+#. module: account_banking_aggregate_payment
+#: view:banking.export.aggregate:0
+msgid "Cancel"
+msgstr "Annuleer"
+
=== added directory 'account_banking_aggregate_payment/model'
=== added file 'account_banking_aggregate_payment/model/__init__.py'
--- account_banking_aggregate_payment/model/__init__.py 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/model/__init__.py 2014-03-06 13:49:10 +0000
@@ -0,0 +1,2 @@
+import payment_mode
+import export_aggregate
=== added file 'account_banking_aggregate_payment/model/export_aggregate.py'
--- account_banking_aggregate_payment/model/export_aggregate.py 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/model/export_aggregate.py 2014-03-06 13:49:10 +0000
@@ -0,0 +1,268 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
+#
+# 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 banking_export_aggregate(orm.TransientModel):
+ _name = 'banking.export.aggregate'
+ _description = 'Execute aggregate payment order'
+ _rec_name = 'payment_order_id'
+
+ _columns = {
+ 'payment_order_id': fields.many2one(
+ 'payment.order', 'Payment order',
+ required=True),
+ }
+
+ def create(self, cr, uid, vals, context=None):
+ if context is None:
+ context = {}
+ if not vals.get('payment_order_id'):
+ if not context.get('active_ids'):
+ raise orm.except_orm(
+ _('Error'),
+ _('Please select a payment order'))
+ if len(context['active_ids']) > 1:
+ raise orm.except_orm(
+ _('Error'),
+ _('Please only select a single payment order'))
+ vals['payment_order_id'] = context['active_ids'][0]
+ return super(banking_export_aggregate, self).create(
+ cr, uid, vals, context=context)
+
+ def reconcile_lines(self, cr, uid, move_line_ids, context=None):
+ """
+ Reconcile move lines lines, really. ERP core functionality.
+ """
+ reconcile_obj = self.pool.get('account.move.reconcile')
+ account_move_line_obj = self.pool.get('account.move.line')
+ currency_obj = self.pool.get('res.currency')
+ lines = account_move_line_obj.browse(cr, uid, move_line_ids, context=context)
+
+ for line in lines[1:]:
+ if line.account_id != lines[0].account_id:
+ raise orm.except_orm(
+ _('Error'),
+ _('Cannot reconcile between different accounts'))
+
+ if any([line.reconcile_id and line.reconcile_id.line_id
+ for line in lines]):
+ raise orm.except_orm(
+ _('Error'),
+ _('Line is already fully reconciled'))
+
+ currency = lines[0].company_id.currency_id
+
+ partials = []
+ line_ids = []
+ for line in lines:
+ if line.id not in line_ids:
+ line_ids.append(line.id)
+ if line.reconcile_partial_id:
+ line_ids += line.reconcile_partial_id.line_partial_ids
+ if line.reconcile_partial_id.id not in partials:
+ partials.append(line.reconcile_partial_id.id)
+
+ total = account_move_line_obj.get_balance(cr, uid, line_ids)
+ is_zero = currency_obj.is_zero(cr, uid, currency, total)
+
+ vals = {
+ 'type': 'auto',
+ 'line_id': is_zero and [(6, 0, line_ids)] or [(6, 0, [])],
+ 'line_partial_ids': is_zero and [(6, 0, [])] or [(6, 0, line_ids)],
+ }
+
+ if partials:
+ if len(partials) > 1:
+ reconcile_obj.unlink(
+ cr, uid, partials[1:], context=context)
+ reconcile_obj.write(
+ cr, uid, partials[0],
+ vals, context=context)
+ else:
+ reconcile_obj.create(
+ cr, uid, vals, context=context)
+
+ for line_id in line_ids:
+ netsvc.LocalService("workflow").trg_trigger(
+ uid, 'account.move.line', line_id, cr)
+ return True
+
+ def create_aggregate_order(self, cr, uid, ids, context=None):
+ wiz = self.browse(cr, uid, ids[0], context=context)
+ account_move_line_obj = self.pool.get('account.move.line')
+ account_move_obj = self.pool.get('account.move')
+ payment_order_obj = self.pool.get('payment.order')
+ payment_order_line_obj = self.pool.get('payment.line')
+ payment_order_ids = context.get('active_ids', [])
+ if not payment_order_ids:
+ raise orm.except_orm(
+ _('Error'),
+ _('Please select a payment order'))
+ if len(payment_order_ids) > 1:
+ raise orm.except_orm(
+ _('Error'),
+ _('This operation can only be performed on a single '
+ 'payment order'))
+
+ today = fields.date.context_today(self, cr, uid, context=context)
+ order = payment_order_obj.browse(
+ cr, uid, payment_order_ids[0], context=context)
+
+ move_id = account_move_obj.create(cr, uid, {
+ 'journal_id': order.mode.transfer_journal_id.id,
+ 'ref': _('Aggregate Payment Order %s') % order.reference,
+ }, context=context)
+
+ counter_move_line_ids = []
+ for line in order.line_ids:
+ # basic checks
+ if not line.move_line_id:
+ raise orm.except_orm(
+ _('Error'),
+ _('No move line provided for line %s') % line.name)
+ if line.move_line_id.reconcile_id:
+ raise orm.except_orm(
+ _('Error'),
+ _('Move line %s has already been paid/reconciled') %
+ line.move_line_id.name
+ )
+
+ # TODO: take multicurrency into account?
+
+ # create the move line on the transfer account
+ vals = {
+ 'name': _('Transit %s') % (
+ line.move_line_id.invoice and
+ line.move_line_id.invoice.number or
+ line.move_line_id.ref),
+ 'move_id': move_id,
+ 'partner_id': line.partner_id and line.partner_id.id or False,
+ 'account_id': order.mode.transfer_account_id.id,
+ 'credit': line.amount,
+ 'debit': 0.0,
+ 'date': today,
+ }
+ counter_move_line_id = account_move_line_obj.create(
+ cr, uid, vals, context=context)
+ counter_move_line_ids.append(counter_move_line_id)
+
+ # create the debit move line on the receivable account
+ vals.update({
+ 'name': _('Reconciliation %s') % (
+ line.move_line_id.invoice and
+ line.move_line_id.invoice.number or
+ line.move_line_id.name),
+ 'account_id': line.move_line_id.account_id.id,
+ 'credit': 0.0,
+ 'debit': line.amount,
+ })
+ reconcile_move_line_id = account_move_line_obj.create(
+ cr, uid, vals, context=context)
+
+ self.reconcile_lines(
+ cr, uid, [reconcile_move_line_id, line.move_line_id.id],
+ context=context)
+
+ total = account_move_line_obj.get_balance(
+ cr, uid, counter_move_line_ids)
+
+ vals = {
+ 'name': _('Transit reconciliation'),
+ 'move_id': move_id,
+ 'partner_id': order.mode.aggregate_partner_id.id,
+ 'account_id': order.mode.transfer_account_id.id,
+ 'debit': total < 0 and -total or 0.0,
+ 'credit': total >= 0 and total or 0.0,
+ 'date': today,
+ }
+ aggregate_move_line_id = account_move_line_obj.create(
+ cr, uid, vals, context=context)
+
+ self.reconcile_lines(
+ cr, uid, counter_move_line_ids + [aggregate_move_line_id],
+ context=context)
+
+ # create the credit move line on the aggregate partner
+ vals.update({
+ 'name': _('Amount payable'),
+ 'account_id': order.mode.aggregate_partner_id.property_account_payable.id,
+ 'partner_id': order.mode.aggregate_partner_id.id,
+ 'debit': total >= 0 and total or 0.0,
+ 'credit': total < 0 and -total or 0.0,
+ })
+
+ payable_move_line = account_move_line_obj.browse(
+ cr, uid,
+ account_move_line_obj.create(
+ cr, uid, vals, context=context),
+ context=context)
+
+ account_move_obj.post(cr, uid, [move_id], context=context)
+
+ wf_service = netsvc.LocalService('workflow')
+ wf_service.trg_validate(uid, 'payment.order', order.id, 'sent', cr)
+ wf_service.trg_validate(uid, 'payment.order', order.id, 'done', cr)
+ order.refresh()
+ if order.state != 'done':
+ raise orm.except_orm(
+ _('Error'),
+ _('Payment order workflow does not go into state "done"'))
+
+ payment_order_id = payment_order_obj.create(
+ cr, uid, {
+ 'company_id': order.company_id.id,
+ 'mode': order.mode.chained_mode_id.id,
+ }, context=context)
+
+ lines2bank = account_move_line_obj.line2bank(
+ cr, uid, [payable_move_line.id], order.mode.id, context)
+
+ payment_order_line_obj.create(cr, uid,{
+ 'move_line_id': payable_move_line.id,
+ 'amount_currency': payable_move_line.amount_to_pay,
+ 'bank_id': lines2bank.get(payable_move_line.id),
+ 'order_id': payment_order_id,
+ 'partner_id': order.mode.aggregate_partner_id.id,
+ 'communication': order.reference.replace('/', ''),
+ 'communication2': False,
+ 'state': 'structured',
+ 'date': today,
+ 'currency': (
+ line.move_line_id.journal_id.currency.id or
+ line.move_line_id.journal_id.company_id.currency_id.id),
+ }, context=context)
+
+ return {
+ 'name': payment_order_obj._description,
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': payment_order_obj._name,
+ 'domain': [],
+ 'context': context,
+ 'type': 'ir.actions.act_window',
+ 'target': 'current',
+ 'res_id': payment_order_id,
+ 'nodestroy': True,
+ }
=== added file 'account_banking_aggregate_payment/model/payment_mode.py'
--- account_banking_aggregate_payment/model/payment_mode.py 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/model/payment_mode.py 2014-03-06 13:49:10 +0000
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# This module copyright (C) 2013 Therp BV (<http://therp.nl>).
+#
+# 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):
+ _inherit = "payment.mode"
+ _columns = {
+ 'aggregate_partner_id': fields.many2one(
+ 'res.partner', 'Aggregate payment beneficiary',
+ help="The single partner on the chained payment order",
+ ),
+ 'chained_mode_id': fields.many2one(
+ 'payment.mode', 'Chained payment mode',
+ help="The payment type of the chained payment order"),
+ }
=== added directory 'account_banking_aggregate_payment/view'
=== added file 'account_banking_aggregate_payment/view/export_aggregate.xml'
--- account_banking_aggregate_payment/view/export_aggregate.xml 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/view/export_aggregate.xml 2014-03-06 13:49:10 +0000
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <record id="banking_export_aggregate_view" model="ir.ui.view">
+ <field name="name">Export aggregate payment order</field>
+ <field name="model">banking.export.aggregate</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form string="Export aggregate payment order">
+ <label string="When you confirm this order, the total
+ amount will be made payable to the partner
+ that has been set on the payment mode. A
+ new payment order will open in your screen
+ with this one payment."/>
+ <group col="2" colspan="1">
+ <button icon="gtk-close"
+ special="cancel"
+ string="Cancel"
+ />
+ <button icon="gtk-ok"
+ string="Create"
+ name="create_aggregate_order"
+ type="object"
+ />
+ </group>
+ </form>
+ </field>
+ </record>
+ </data>
+</openerp>
=== added file 'account_banking_aggregate_payment/view/payment_mode.xml'
--- account_banking_aggregate_payment/view/payment_mode.xml 1970-01-01 00:00:00 +0000
+++ account_banking_aggregate_payment/view/payment_mode.xml 2014-03-06 13:49:10 +0000
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+ <record id="view_payment_mode_form" model="ir.ui.view">
+ <field name="name">Adaptations for aggregate payment modes</field>
+ <field name="model">payment.mode</field>
+ <field name="inherit_id"
+ ref="account_direct_debit.view_payment_mode_form"/>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <field name="payment_term_ids" position="after">
+ <group colspan="2" col="2" string="Aggregate payment"
+ attrs="{
+ 'invisible': [
+ ('type', '!=',
+ %(account_banking_aggregate_payment.type_aggregate)d
+ )]}">
+ <field name="aggregate_partner_id"
+ attrs="{'required': [
+ ('type', '=',
+ %(account_banking_aggregate_payment.type_aggregate)d
+ )]}"
+ />
+ <field name="chained_mode_id"
+ attrs="{'required': [
+ ('type', '=',
+ %(account_banking_aggregate_payment.type_aggregate)d
+ )]}"
+ />
+ </group>
+ </field>
+
+ <field name="transfer_account_id" position="attributes">
+ <attribute name="attrs">{
+ 'required': [
+ ('type', '=',
+ %(account_banking_aggregate_payment.type_aggregate)d
+ )]}</attribute>
+ </field>
+
+ <field name="transfer_journal_id" position="attributes">
+ <attribute name="attrs">{
+ 'required': [
+ ('type', '=',
+ %(account_banking_aggregate_payment.type_aggregate)d
+ )]}</attribute>
+ </field>
+
+ </field>
+ </record>
+ </data>
+</openerp>
=== modified file 'account_banking_nl_abnamro/abnamro.py'
=== modified file 'account_banking_nl_clieop/wizard/clieop.py'
=== modified file 'account_banking_nl_girotel/girotel.py'
--- account_banking_nl_girotel/girotel.py 2013-08-02 12:51:00 +0000
+++ account_banking_nl_girotel/girotel.py 2014-03-06 13:49:10 +0000
@@ -47,6 +47,7 @@
from tools.translate import _
import re
import csv
+import re
bt = models.mem_bank_transaction
@@ -106,13 +107,32 @@
self.date = str2date(self.date, '%Y%m%d')
if self.direction == 'A':
self.transferred_amount = -float(self.transferred_amount)
- if (self.transfer_type == 'VZ'
- and (not self.remote_account or self.remote_account == '0')
- and (not self.message or re.match('^\s*$', self.message))
- and self.remote_owner.startswith('TOTAAL ')):
- self.transfer_type = 'PB'
- self.message = self.remote_owner
- self.remove_owner = False
+<<<<<<< TREE
+ if (self.transfer_type == 'VZ'
+ and (not self.remote_account or self.remote_account == '0')
+ and (not self.message or re.match('^\s*$', self.message))
+ and self.remote_owner.startswith('TOTAAL ')):
+ self.transfer_type = 'PB'
+ self.message = self.remote_owner
+ self.remove_owner = False
+=======
+ #payment batch done via clieop
+ if (self.transfer_type == 'VZ'
+ and (not self.remote_account or self.remote_account == '0')
+ and (not self.message or re.match('^\s*$', self.message))
+ and self.remote_owner.startswith('TOTAAL ')):
+ self.transfer_type = 'PB'
+ self.message = self.remote_owner
+ self.remove_owner = False
+ #payment batch done via sepa
+ if self.transfer_type == 'VZ'\
+ and not self.remote_account\
+ and not self.remote_owner\
+ and re.match(
+ '^Verzamel Eurobetaling .* TOTAAL \d+ POSTEN\s*$',
+ self.message):
+ self.transfer_type = 'PB'
+>>>>>>> MERGE-SOURCE
else:
self.transferred_amount = float(self.transferred_amount)
self.local_account = self.local_account.zfill(10)
@@ -152,6 +172,10 @@
'PB': bt.PAYMENT_BATCH,
}
+ structured_description_regex = re.compile(
+ '^IBAN: (?P<iban>\w+) BIC: (?P<bic>\w+) Naam: (?P<name>.+) '
+ 'Omschrijving: (?P<desc>.+)$')
+
def __init__(self, line, *args, **kwargs):
'''
Initialize own dict with read values.
@@ -290,6 +314,11 @@
# Normal transaction, but remote_owner can contain city, depending
# on length of total. As there is no clear pattern, leave it as
# is.
+ structured_description = self.structured_description_regex.match(
+ ''.join(self.message.split('\n')))
+ if structured_description:
+ values = structured_description.groupdict()
+ self.reference = values['desc']
self.message = self.refold_message(self.message)
else:
=== modified file 'account_banking_nl_triodos/__openerp__.py'
--- account_banking_nl_triodos/__openerp__.py 2013-04-15 14:14:27 +0000
+++ account_banking_nl_triodos/__openerp__.py 2014-03-06 13:49:10 +0000
@@ -20,9 +20,15 @@
##############################################################################
{
'name': 'Triodos (NL) Bank Statements Import',
+<<<<<<< TREE
'version': '0.92',
'license': 'AGPL-3',
'author': ['Therp BV', 'EduSense BV'],
+=======
+ 'version': '0.168',
+ 'license': 'GPL-3',
+ 'author': 'Therp BV / EduSense BV',
+>>>>>>> MERGE-SOURCE
'website': 'https://launchpad.net/account-banking',
'category': 'Account Banking',
'depends': ['account_banking'],
=== modified file 'account_banking_nl_triodos/triodos.py'
=== modified file 'account_banking_partner_journal_account/i18n/nl.po'
--- account_banking_partner_journal_account/i18n/nl.po 2014-02-11 06:47:45 +0000
+++ account_banking_partner_journal_account/i18n/nl.po 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * account_banking_partner_journal_account
@@ -48,3 +49,46 @@
#: field:res.partner,account_receivable_bank_id:0
msgid "Default bank debit account"
msgstr "Standaardrekening bankbijschrijvingen"
+=======
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_banking_partner_journal_account
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 6.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-11-26 19:34+0000\n"
+"PO-Revision-Date: 2013-11-26 19:34+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_banking_partner_journal_account
+#: model:ir.model,name:account_banking_partner_journal_account.model_res_partner
+msgid "Partner"
+msgstr "Relatie"
+
+#. module: account_banking_partner_journal_account
+#: help:res.partner,property_account_receivable_bank_id:0
+msgid "Optional default journal account on bank statements for debits from this partner. Overrides the default debit account."
+msgstr "Optionele standaard grootboekrekening voor geïmporteerde bankbijschrijvingen, in plaats van de standaard debiteurenrekening."
+
+#. module: account_banking_partner_journal_account
+#: field:res.partner,property_account_payable_bank_id:0
+msgid "Default bank credit account"
+msgstr "Standaardrekening bankafschrijvingen"
+
+#. module: account_banking_partner_journal_account
+#: help:res.partner,property_account_payable_bank_id:0
+msgid "Optional default journal account on bank statements for credits from this partner. Overrides the default credit account."
+msgstr "Optionele standaard grootboekrekening voor geïmporteerde bankafschrijvingen, in plaats van de standaard crediteurenrekening."
+
+#. module: account_banking_partner_journal_account
+#: field:res.partner,property_account_receivable_bank_id:0
+msgid "Default bank debit account"
+msgstr "Standaardrekening bankbijschrijvingen"
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/__init__.py'
--- account_banking_sepa_credit_transfer/__init__.py 2013-11-07 11:50:36 +0000
+++ account_banking_sepa_credit_transfer/__init__.py 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# -*- encoding: utf-8 -*-
##############################################################################
#
@@ -22,3 +23,30 @@
from . import wizard
from . import account_banking_sepa
+=======
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# SEPA Credit Transfer module for OpenERP
+# Copyright (C) 2010-2013 Akretion (http://www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@xxxxxxxxxxxx>
+#
+# 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/>.
+#
+##############################################################################
+
+import wizard
+import account_banking_sepa
+
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/__openerp__.py'
--- account_banking_sepa_credit_transfer/__openerp__.py 2014-02-16 14:01:09 +0000
+++ account_banking_sepa_credit_transfer/__openerp__.py 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
##############################################################################
#
# SEPA Credit Transfer module for OpenERP
@@ -51,3 +52,56 @@
'active': False,
'installable': True,
}
+=======
+##############################################################################
+#
+# SEPA Credit Transfer module for OpenERP
+# Copyright (C) 2010-2013 Akretion (http://www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@xxxxxxxxxxxx>
+#
+# 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 SEPA Credit Transfer',
+ 'summary': 'Create SEPA XML files for Credit Transfers',
+ 'version': '0.1',
+ 'license': 'AGPL-3',
+ 'author': 'Akretion',
+ 'website': 'http://www.akretion.com',
+ 'category': 'Banking addons',
+ 'depends': ['account_banking'],
+ 'init_xml': [],
+ 'update_xml': [
+ 'account_banking_sepa_view.xml',
+ 'wizard/export_sepa_view.xml',
+ 'data/payment_type_sepa_sct.xml',
+ 'security/ir.model.access.csv',
+ ],
+ 'demo_xml': [],
+ 'description': '''
+Module to export payment orders in SEPA XML file format.
+
+SEPA PAIN (PAyment INitiation) is the new european standard for Customer-to-Bank payment instructions. This module implements SEPA Credit Transfer (SCT), more specifically PAIN versions 001.001.02, 001.001.03 and 001.001.04. It is part of the ISO 20022 standard, available on http://www.iso20022.org.
+
+The Implementation Guidelines for SEPA Credit Transfer published by the European Payments Council (http://http://www.europeanpaymentscouncil.eu) use PAIN version 001.001.03, so it's probably the version of PAIN that you should try first.
+
+This module uses the framework provided by the banking addons, cf https://launchpad.net/banking-addons
+
+Please contact Alexis de Lattre from Akretion <alexis.delattre@xxxxxxxxxxxx> for any help or question about this module.
+ ''',
+ 'active': False,
+ 'installable': True,
+}
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/account_banking_sepa.py'
--- account_banking_sepa_credit_transfer/account_banking_sepa.py 2013-12-24 00:01:04 +0000
+++ account_banking_sepa_credit_transfer/account_banking_sepa.py 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
##############################################################################
#
# SEPA Credit Transfer module for OpenERP
@@ -88,3 +89,85 @@
_defaults = {
'state': 'draft',
}
+=======
+##############################################################################
+#
+# SEPA Credit Transfer module for OpenERP
+# Copyright (C) 2010-2013 Akretion (http://www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@xxxxxxxxxxxx>
+#
+# 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 osv import osv, fields
+import time
+from tools.translate import _
+import decimal_precision as dp
+
+
+class banking_export_sepa(osv.osv):
+ '''SEPA export'''
+ _name = 'banking.export.sepa'
+ _description = __doc__
+ _rec_name = 'msg_identification'
+
+ def _generate_filename(self, cr, uid, ids, name, arg, context=None):
+ res = {}
+ for sepa_file in self.browse(cr, uid, ids, context=context):
+ res[sepa_file.id] = 'sepa_' + (sepa_file.msg_identification or '') + '.xml'
+ return res
+
+ _columns = {
+ 'payment_order_ids': fields.many2many(
+ 'payment.order',
+ 'account_payment_order_sepa_rel',
+ 'banking_export_sepa_id', 'account_order_id',
+ 'Payment orders',
+ readonly=True),
+ 'prefered_exec_date': fields.date('Prefered execution date', readonly=True),
+ 'nb_transactions': fields.integer('Number of transactions', readonly=True),
+ 'total_amount': fields.float('Total amount',
+ digits_compute=dp.get_precision('Account'), readonly=True),
+ 'msg_identification': fields.char('Message identification', size=35,
+ readonly=True),
+ 'batch_booking': fields.boolean('Batch booking', readonly=True,
+ help="If true, the bank statement will display only one debit line for all the wire transfers of the SEPA XML file ; if false, the bank statement will display one debit line per wire transfer of the SEPA XML file."),
+ 'charge_bearer': fields.selection([
+ ('SHAR', 'Shared'),
+ ('CRED', 'Borne by creditor'),
+ ('DEBT', 'Borne by debtor'),
+ ('SLEV', 'Following service level'),
+ ], 'Charge bearer', readonly=True,
+ help='Shared : transaction charges on the sender side are to be borne by the debtor, transaction charges on the receiver side are to be borne by the creditor (most transfers use this). Borne by creditor : all transaction charges are to be borne by the creditor. Borne by debtor : all transaction charges are to be borne by the debtor. Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme.'),
+ 'generation_date': fields.datetime('Generation date',
+ readonly=True),
+ 'file': fields.binary('SEPA XML file', readonly=True),
+ 'filename': fields.function(_generate_filename, type='char', size=256,
+ method=True, string='Filename', readonly=True),
+ 'state': fields.selection([
+ ('draft', 'Draft'),
+ ('sent', 'Sent'),
+ ('done', 'Reconciled'),
+ ], 'State', readonly=True),
+ }
+
+ _defaults = {
+ 'generation_date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
+ 'state': 'draft',
+ }
+
+banking_export_sepa()
+
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/account_banking_sepa_view.xml'
--- account_banking_sepa_credit_transfer/account_banking_sepa_view.xml 2013-11-21 23:41:32 +0000
+++ account_banking_sepa_credit_transfer/account_banking_sepa_view.xml 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010-2013 Akretion (http://www.akretion.com)
@@ -78,3 +79,90 @@
</data>
</openerp>
+=======
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2010-2013 Akretion (http://www.akretion.com)
+ @author: Alexis de Lattre <alexis.delattre@xxxxxxxxxxxx>
+ The licence is in the file __openerp__.py
+-->
+<openerp>
+<data>
+
+<record id="view_banking_export_sepa_form" model="ir.ui.view">
+ <field name="name">account.banking.export.sepa.form</field>
+ <field name="model">banking.export.sepa</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form string="SEPA Credit Transfer">
+ <notebook>
+ <page string="General Information">
+ <field name="msg_identification" select="1" />
+ <field name="total_amount" />
+ <field name="nb_transactions" />
+ <field name="prefered_exec_date" />
+ <field name="batch_booking" />
+ <field name="charge_bearer"/>
+ <field name="generation_date" />
+ <newline />
+ <field name="file" filename="filename"/>
+ <field name="filename" invisible="True"/>
+ </page>
+ <page string="Payment Orders">
+ <field name="payment_order_ids" colspan="4" nolabel="1">
+ <tree colors="blue:state in ('draft');gray:state in ('cancel','done');black:state in ('open')" string="Payment order">
+ <field name="reference"/>
+ <field name="date_created"/>
+ <field name="date_done"/>
+ <field name="total"/>
+ <field name="state"/>
+ </tree>
+ </field>
+ </page>
+ </notebook>
+ </form>
+ </field>
+</record>
+
+
+<record id="view_banking_export_sepa_tree" model="ir.ui.view">
+ <field name="name">account.banking.export.sepa.tree</field>
+ <field name="model">banking.export.sepa</field>
+ <field name="type">tree</field>
+ <field name="arch" type="xml">
+ <tree string="SEPA Credit Transfer">
+ <field name="msg_identification"/>
+ <field name="prefered_exec_date"/>
+ <field name="generation_date"/>
+ <field name="nb_transactions"/>
+ </tree>
+ </field>
+</record>
+
+
+<record id="action_account_banking_sepa" model="ir.actions.act_window">
+ <field name="name">Generated SEPA Credit Transfer XML files</field>
+ <field name="res_model">banking.export.sepa</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">tree,form</field>
+</record>
+
+
+<menuitem id="menu_account_banking_sepa"
+ parent="account_banking.menu_finance_banking_actions"
+ action="action_account_banking_sepa"
+ sequence="15"
+ />
+
+<act_window id="act_banking_export_sepa_payment_order"
+ name="Generated SEPA Credit Transfer files"
+ domain="[('payment_order_ids', '=', active_id)]"
+ res_model="banking.export.sepa"
+ src_model="payment.order"
+ view_type="form"
+ view_mode="tree,form"
+/>
+
+</data>
+</openerp>
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml'
--- account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml 2013-11-13 08:19:50 +0000
+++ account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
@@ -39,3 +40,41 @@
</data>
</openerp>
+=======
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+<data noupdate="1">
+
+
+<!-- TODO In the suitable_bank_types field, we should restrict to IBAN type and Rib+IBAN of l10n_fr_rib ? -->
+<record id="export_sepa_sct_001_001_04" model="payment.mode.type">
+ <field name="name">SEPA Credit Transfer v04</field>
+ <field name="code">pain.001.001.04</field>
+ <field name="suitable_bank_types"
+ eval="[(6,0,[ref('base_iban.bank_iban')])]" />
+ <field name="ir_model_id" ref="model_banking_export_sepa_wizard"/>
+ <field name="payment_order_type">payment</field>
+</record>
+
+<record id="export_sepa_sct_001_001_03" model="payment.mode.type">
+ <field name="name">SEPA Credit Transfer v03</field>
+ <field name="code">pain.001.001.03</field>
+ <field name="suitable_bank_types"
+ eval="[(6,0,[ref('base_iban.bank_iban')])]" />
+ <field name="ir_model_id" ref="model_banking_export_sepa_wizard"/>
+ <field name="payment_order_type">payment</field>
+</record>
+
+<record id="export_sepa_sct_001_001_02" model="payment.mode.type">
+ <field name="name">SEPA Credit Transfer v02</field>
+ <field name="code">pain.001.001.02</field>
+ <field name="suitable_bank_types"
+ eval="[(6,0,[ref('base_iban.bank_iban')])]" />
+ <field name="ir_model_id" ref="model_banking_export_sepa_wizard"/>
+ <field name="payment_order_type">payment</field>
+</record>
+
+
+</data>
+</openerp>
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot'
--- account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot 2013-12-24 00:01:04 +0000
+++ account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * account_banking_sepa_credit_transfer
@@ -205,3 +206,256 @@
msgid "Generation Date"
msgstr ""
+=======
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_banking_sepa_credit_transfer
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 6.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-06-06 08:01+0000\n"
+"PO-Revision-Date: 2013-06-06 08:01+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,file:0
+#: field:banking.export.sepa.wizard,file_id:0
+msgid "SEPA XML file"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa:0
+msgid "Payment order"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa.wizard,state:0
+msgid "Create"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: help:banking.export.sepa.wizard,msg_identification:0
+msgid "This is the message identification of the entire SEPA XML file. 35 characters max."
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,filename:0
+#: field:banking.export.sepa.wizard,filename:0
+msgid "Filename"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa:0
+msgid "General information"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,state:0
+#: field:banking.export.sepa.wizard,state:0
+msgid "State"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,state:0
+msgid "Draft"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,prefered_exec_date:0
+#: field:banking.export.sepa.wizard,prefered_exec_date:0
+msgid "Prefered execution date"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,charge_bearer:0
+#: selection:banking.export.sepa.wizard,charge_bearer:0
+msgid "Shared"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,generation_date:0
+msgid "Generation date"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa_wizard
+msgid "Export SEPA Credit Transfer XML file"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa:0
+msgid "SEPA Credit Transfer"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa.wizard,state:0
+msgid "Finish"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,state:0
+msgid "Reconciled"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: model:ir.actions.act_window,name:account_banking_sepa_credit_transfer.act_banking_export_sepa_payment_order
+msgid "Generated SEPA files"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: model:ir.actions.act_window,name:account_banking_sepa_credit_transfer.action_account_banking_sepa
+#: model:ir.ui.menu,name:account_banking_sepa_credit_transfer.menu_account_banking_sepa
+msgid "Generated SEPA XML files"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,state:0
+msgid "Sent"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Validate"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Generate"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,msg_identification:0
+#: field:banking.export.sepa.wizard,msg_identification:0
+msgid "Message identification"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:284
+#, python-format
+msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,total_amount:0
+#: field:banking.export.sepa.wizard,total_amount:0
+msgid "Total amount"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: help:banking.export.sepa,charge_bearer:0
+#: help:banking.export.sepa.wizard,charge_bearer:0
+msgid "Shared : transaction charges on the sender side are to be borne by the debtor, transaction charges on the receiver side are to be borne by the creditor (most transfers use this). Borne by creditor : all transaction charges are to be borne by the creditor. Borne by debtor : all transaction charges are to be borne by the debtor. Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme."
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,charge_bearer:0
+#: selection:banking.export.sepa.wizard,charge_bearer:0
+msgid "Borne by creditor"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa:0
+#: field:banking.export.sepa,payment_order_ids:0
+#: field:banking.export.sepa.wizard,payment_order_ids:0
+msgid "Payment orders"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:90
+#, python-format
+msgid "This IBAN is not valid : %s"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "SEPA XML file generation"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Reference for further communication"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Processing details"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa
+msgid "SEPA export"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,charge_bearer:0
+#: selection:banking.export.sepa.wizard,charge_bearer:0
+msgid "Borne by debtor"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,nb_transactions:0
+#: field:banking.export.sepa.wizard,nb_transactions:0
+msgid "Number of transactions"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,charge_bearer:0
+#: selection:banking.export.sepa.wizard,charge_bearer:0
+msgid "Following service level"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,charge_bearer:0
+#: field:banking.export.sepa.wizard,charge_bearer:0
+msgid "Charge bearer"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: help:banking.export.sepa,batch_booking:0
+#: help:banking.export.sepa.wizard,batch_booking:0
+msgid "If true, the bank statement will display only one debit line for all the wire transfers of the SEPA XML file ; if false, the bank statement will display one debit line per wire transfer of the SEPA XML file."
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: help:banking.export.sepa.wizard,prefered_exec_date:0
+msgid "This is the date on which the file should be processed by the bank. Please keep in mind that banks only execute on working days and typically use a delay of two days between execution date and effective transfer date."
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa.wizard,file:0
+msgid "File"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Cancel"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:135
+#, python-format
+msgid "Payment Type Code '%s' is not supported. The only Payment Type Codes supported for SEPA Credit Transfers are 'pain.001.001.02', 'pain.001.001.03' and 'pain.001.001.04'."
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:90
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:135
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:284
+#, python-format
+msgid "Error :"
+msgstr ""
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,batch_booking:0
+#: field:banking.export.sepa.wizard,batch_booking:0
+msgid "Batch booking"
+msgstr ""
+
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/i18n/fr.po'
--- account_banking_sepa_credit_transfer/i18n/fr.po 2014-02-11 06:47:45 +0000
+++ account_banking_sepa_credit_transfer/i18n/fr.po 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * account_banking_sepa_credit_transfer
@@ -363,3 +364,256 @@
#~ msgid "Batch booking"
#~ msgstr "Débit groupé"
+=======
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_banking_sepa_credit_transfer
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 6.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-06-06 08:01+0000\n"
+"PO-Revision-Date: 2013-06-06 08:01+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,file:0
+#: field:banking.export.sepa.wizard,file_id:0
+msgid "SEPA XML file"
+msgstr "Fichier SEPA XML"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa:0
+msgid "Payment order"
+msgstr "Ordre de paiement"
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa.wizard,state:0
+msgid "Create"
+msgstr "Créer"
+
+#. module: account_banking_sepa_credit_transfer
+#: help:banking.export.sepa.wizard,msg_identification:0
+msgid "This is the message identification of the entire SEPA XML file. 35 characters max."
+msgstr "Ceci est le libellé d'identification du fichier SEPA XML. 35 caractères maximum."
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,filename:0
+#: field:banking.export.sepa.wizard,filename:0
+msgid "Filename"
+msgstr "Nom du fichier"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa:0
+msgid "General information"
+msgstr "Informations générales"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,state:0
+#: field:banking.export.sepa.wizard,state:0
+msgid "State"
+msgstr "État"
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,state:0
+msgid "Draft"
+msgstr "Brouillon"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,prefered_exec_date:0
+#: field:banking.export.sepa.wizard,prefered_exec_date:0
+msgid "Prefered execution date"
+msgstr "Date d'exécution demandée"
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,charge_bearer:0
+#: selection:banking.export.sepa.wizard,charge_bearer:0
+msgid "Shared"
+msgstr "Partagé"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,generation_date:0
+msgid "Generation date"
+msgstr "Date de génération"
+
+#. module: account_banking_sepa_credit_transfer
+#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa_wizard
+msgid "Export SEPA Credit Transfer XML file"
+msgstr "Exporte the fichier de virement SEPA XML"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa:0
+msgid "SEPA Credit Transfer"
+msgstr "Virement SEPA"
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa.wizard,state:0
+msgid "Finish"
+msgstr "Finir"
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,state:0
+msgid "Reconciled"
+msgstr "Réconcilié"
+
+#. module: account_banking_sepa_credit_transfer
+#: model:ir.actions.act_window,name:account_banking_sepa_credit_transfer.act_banking_export_sepa_payment_order
+msgid "Generated SEPA files"
+msgstr "Fichiers SEPA générés"
+
+#. module: account_banking_sepa_credit_transfer
+#: model:ir.actions.act_window,name:account_banking_sepa_credit_transfer.action_account_banking_sepa
+#: model:ir.ui.menu,name:account_banking_sepa_credit_transfer.menu_account_banking_sepa
+msgid "Generated SEPA XML files"
+msgstr "Fichiers SEPA XML générés"
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,state:0
+msgid "Sent"
+msgstr "Envoyé"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Validate"
+msgstr "Valider"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Generate"
+msgstr "Générer"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,msg_identification:0
+#: field:banking.export.sepa.wizard,msg_identification:0
+msgid "Message identification"
+msgstr "Libellé d'identification"
+
+#. module: account_banking_sepa_credit_transfer
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:284
+#, python-format
+msgid "The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s"
+msgstr "Le fichier XML généré n'est pas valide par rapport à la Définition du Schéma XML officiel. Le fichier XML généré et le message d'erreur complet ont été écrits dans les logs du serveur. Voici l'erreur, qui vous donnera peut-être une idée sur la cause du problème : %s"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,total_amount:0
+#: field:banking.export.sepa.wizard,total_amount:0
+msgid "Total amount"
+msgstr "Montant total"
+
+#. module: account_banking_sepa_credit_transfer
+#: help:banking.export.sepa,charge_bearer:0
+#: help:banking.export.sepa.wizard,charge_bearer:0
+msgid "Shared : transaction charges on the sender side are to be borne by the debtor, transaction charges on the receiver side are to be borne by the creditor (most transfers use this). Borne by creditor : all transaction charges are to be borne by the creditor. Borne by debtor : all transaction charges are to be borne by the debtor. Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme."
+msgstr "Partagés : les frais bancaires côté émetteur sont à la charge de l'émetteur et les frais bancaires côté destinataire sont à la charge du destinataire (la plupart des virements utilisent cette répartition). Supportés par le destinataire : tous les frais bancaires sont à la charge du destinataire. Supportés par l'émetteur : tous les frais bancaires sont à la charge de l'émetteur. Suivant le niveau de service : la répartition des frais bancaires suit les règles pré-établies dans le contrat avec la banque."
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,charge_bearer:0
+#: selection:banking.export.sepa.wizard,charge_bearer:0
+msgid "Borne by creditor"
+msgstr "Supportés par le destinataire"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa:0
+#: field:banking.export.sepa,payment_order_ids:0
+#: field:banking.export.sepa.wizard,payment_order_ids:0
+msgid "Payment orders"
+msgstr "Ordres de paiement"
+
+#. module: account_banking_sepa_credit_transfer
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:90
+#, python-format
+msgid "This IBAN is not valid : %s"
+msgstr "Cet IBAN n'est pas valide : %s"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "SEPA XML file generation"
+msgstr "Génération du fichier SEPA XML"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Reference for further communication"
+msgstr "Référence pour communication ultérieure"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Processing details"
+msgstr "Paramètres"
+
+#. module: account_banking_sepa_credit_transfer
+#: model:ir.model,name:account_banking_sepa_credit_transfer.model_banking_export_sepa
+msgid "SEPA export"
+msgstr "Export SEPA"
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,charge_bearer:0
+#: selection:banking.export.sepa.wizard,charge_bearer:0
+msgid "Borne by debtor"
+msgstr "Supportés par l'émetteur"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,nb_transactions:0
+#: field:banking.export.sepa.wizard,nb_transactions:0
+msgid "Number of transactions"
+msgstr "Nombre de transactions"
+
+#. module: account_banking_sepa_credit_transfer
+#: selection:banking.export.sepa,charge_bearer:0
+#: selection:banking.export.sepa.wizard,charge_bearer:0
+msgid "Following service level"
+msgstr "Suivant le niveau de service"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,charge_bearer:0
+#: field:banking.export.sepa.wizard,charge_bearer:0
+msgid "Charge bearer"
+msgstr "Répartition des frais"
+
+#. module: account_banking_sepa_credit_transfer
+#: help:banking.export.sepa,batch_booking:0
+#: help:banking.export.sepa.wizard,batch_booking:0
+msgid "If true, the bank statement will display only one debit line for all the wire transfers of the SEPA XML file ; if false, the bank statement will display one debit line per wire transfer of the SEPA XML file."
+msgstr "Si coché, le relevé de compte ne comportera qu'une ligne de débit pour tous les virements du fichier SEPA XML ; si non coché, le relevé de compte comportera une ligne de débit pour chaque virement du fichier SEPA XML."
+
+#. module: account_banking_sepa_credit_transfer
+#: help:banking.export.sepa.wizard,prefered_exec_date:0
+msgid "This is the date on which the file should be processed by the bank. Please keep in mind that banks only execute on working days and typically use a delay of two days between execution date and effective transfer date."
+msgstr "C'est la date à laquelle le fichier doit être traité par la banque. Gardez en tête que les banques réalisent des traitements seulement les jours ouvrés et ont habituellement un délai de 2 jours entre la date de traitement et la date du transfert effectif."
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa.wizard,file:0
+msgid "File"
+msgstr "Fichier"
+
+#. module: account_banking_sepa_credit_transfer
+#: view:banking.export.sepa.wizard:0
+msgid "Cancel"
+msgstr "Annuler"
+
+#. module: account_banking_sepa_credit_transfer
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:135
+#, python-format
+msgid "Payment Type Code '%s' is not supported. The only Payment Type Codes supported for SEPA Credit Transfers are 'pain.001.001.02', 'pain.001.001.03' and 'pain.001.001.04'."
+msgstr "Le code '%s' pour le Type de Paiment n'est pas supporté. Les seuls codes de Types de Paiement supportés pour les virements SEPA sont 'pain.001.001.02', 'pain.001.001.03' et 'pain.001.001.04'."
+
+#. module: account_banking_sepa_credit_transfer
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:90
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:135
+#: code:addons/account_banking_sepa_credit_transfer/wizard/export_sepa.py:284
+#, python-format
+msgid "Error :"
+msgstr "Erreur :"
+
+#. module: account_banking_sepa_credit_transfer
+#: field:banking.export.sepa,batch_booking:0
+#: field:banking.export.sepa.wizard,batch_booking:0
+msgid "Batch booking"
+msgstr "Débit groupé"
+
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/wizard/__init__.py'
--- account_banking_sepa_credit_transfer/wizard/__init__.py 2013-11-07 11:50:36 +0000
+++ account_banking_sepa_credit_transfer/wizard/__init__.py 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# -*- encoding: utf-8 -*-
##############################################################################
#
@@ -21,3 +22,28 @@
##############################################################################
from . import export_sepa
+=======
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# SEPA Credit Transfer module for OpenERP
+# Copyright (C) 2010-2013 Akretion (http://www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@xxxxxxxxxxxx>
+#
+# 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/>.
+#
+##############################################################################
+
+import export_sepa
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/wizard/export_sepa.py'
--- account_banking_sepa_credit_transfer/wizard/export_sepa.py 2014-01-05 23:51:22 +0000
+++ account_banking_sepa_credit_transfer/wizard/export_sepa.py 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# -*- encoding: utf-8 -*-
##############################################################################
#
@@ -297,3 +298,352 @@
for order in sepa_export.payment_order_ids:
wf_service.trg_validate(uid, 'payment.order', order.id, 'done', cr)
return {'type': 'ir.actions.act_window_close'}
+=======
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# SEPA Credit Transfer module for OpenERP
+# Copyright (C) 2010-2013 Akretion (http://www.akretion.com)
+# @author: Alexis de Lattre <alexis.delattre@xxxxxxxxxxxx>
+#
+# 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 osv import osv, fields
+import base64
+from datetime import datetime, timedelta
+from tools.translate import _
+import tools
+from lxml import etree
+import logging
+import netsvc
+
+_logger = logging.getLogger(__name__)
+
+
+class banking_export_sepa_wizard(osv.osv_memory):
+ _name = 'banking.export.sepa.wizard'
+ _description = 'Export SEPA Credit Transfer XML file'
+ _columns = {
+ 'state': fields.selection([('create', 'Create'), ('finish', 'Finish')],
+ 'State', readonly=True),
+ 'msg_identification': fields.char('Message identification', size=35,
+ # Can't set required=True on the field because it blocks
+ # the launch of the wizard -> I set it as required in the view
+ help='This is the message identification of the entire SEPA XML file. 35 characters max.'),
+ 'batch_booking': fields.boolean('Batch booking',
+ help="If true, the bank statement will display only one debit line for all the wire transfers of the SEPA XML file ; if false, the bank statement will display one debit line per wire transfer of the SEPA XML file."),
+ 'prefered_exec_date': fields.date('Prefered execution date',
+ help='This is the date on which the file should be processed by the bank. Please keep in mind that banks only execute on working days and typically use a delay of two days between execution date and effective transfer date.'),
+ 'charge_bearer': fields.selection([
+ ('SHAR', 'Shared'),
+ ('CRED', 'Borne by creditor'),
+ ('DEBT', 'Borne by debtor'),
+ ('SLEV', 'Following service level'),
+ ], 'Charge bearer', required=True,
+ help='Shared : transaction charges on the sender side are to be borne by the debtor, transaction charges on the receiver side are to be borne by the creditor (most transfers use this). Borne by creditor : all transaction charges are to be borne by the creditor. Borne by debtor : all transaction charges are to be borne by the debtor. Following service level : transaction charges are to be applied following the rules agreed in the service level and/or scheme.'),
+ 'nb_transactions': fields.related('file_id', 'nb_transactions',
+ type='integer', string='Number of transactions', readonly=True),
+ 'total_amount': fields.related('file_id', 'total_amount', type='float',
+ string='Total amount', readonly=True),
+ 'file_id': fields.many2one('banking.export.sepa', 'SEPA XML file', readonly=True),
+ 'file': fields.related('file_id', 'file', string="File", type='binary',
+ readonly=True),
+ 'filename': fields.related('file_id', 'filename', string="Filename",
+ type='char', size=256, readonly=True),
+ 'payment_order_ids': fields.many2many('payment.order',
+ 'wiz_sepa_payorders_rel', 'wizard_id', 'payment_order_id',
+ 'Payment orders', readonly=True),
+ }
+
+ _defaults = {
+ 'charge_bearer': 'SLEV',
+ 'state': 'create',
+ }
+
+
+ def _limit_size(self, cr, uid, field, max_size, context=None):
+ '''Limit size of strings to respect the PAIN standard'''
+ max_size = int(max_size)
+ return field[0:max_size]
+
+
+ def _validate_iban(self, cr, uid, iban, context=None):
+ '''if IBAN is valid, returns IBAN
+ if IBAN is NOT valid, raises an error message'''
+ partner_bank_obj = self.pool.get('res.partner.bank')
+ if partner_bank_obj.is_iban_valid(cr, uid, iban, context=context):
+ return iban.replace(' ', '')
+ else:
+ raise osv.except_osv(_('Error :'), _("This IBAN is not valid : %s") % iban)
+
+ def create(self, cr, uid, vals, context=None):
+ payment_order_ids = context.get('active_ids', [])
+ vals.update({
+ 'payment_order_ids': [[6, 0, payment_order_ids]],
+ })
+ return super(banking_export_sepa_wizard, self).create(cr, uid,
+ vals, context=context)
+
+
+ def create_sepa(self, cr, uid, ids, context=None):
+ '''
+ Creates the SEPA Credit Transfer file. That's the important code !
+ '''
+ payment_order_obj = self.pool.get('payment.order')
+
+ sepa_export = self.browse(cr, uid, ids[0], context=context)
+
+ my_company_name = sepa_export.payment_order_ids[0].mode.bank_id.partner_id.name
+ my_company_iban = self._validate_iban(cr, uid, sepa_export.payment_order_ids[0].mode.bank_id.acc_number, context=context)
+ my_company_bic = sepa_export.payment_order_ids[0].mode.bank_id.bank.bic
+ #my_company_country_code = sepa_export.payment_order_ids[0].mode.bank_id.partner_id.address[0].country_id.code
+ #my_company_city = sepa_export.payment_order_ids[0].mode.bank_id.partner_id.address[0].city
+ #my_company_street1 = sepa_export.payment_order_ids[0].mode.bank_id.partner_id.address[0].street
+ pain_flavor = sepa_export.payment_order_ids[0].mode.type.code
+ if pain_flavor == 'pain.001.001.02':
+ bic_xml_tag = 'BIC'
+ name_maxsize = 70
+ root_xml_tag = 'pain.001.001.02'
+ elif pain_flavor == 'pain.001.001.03':
+ bic_xml_tag = 'BIC'
+ # size 70 -> 140 for <Nm> with pain.001.001.03
+ # BUT the European Payment Council, in the document
+ # "SEPA Credit Transfer Scheme Customer-to-bank Implementation guidelines" v6.0
+ # available on http://www.europeanpaymentscouncil.eu/knowledge_bank.cfm
+ # says that 'Nm' should be limited to 70
+ # so we follow the "European Payment Council" and we put 70 and not 140
+ name_maxsize = 70
+ root_xml_tag = 'CstmrCdtTrfInitn'
+ elif pain_flavor == 'pain.001.001.04':
+ bic_xml_tag = 'BICFI'
+ name_maxsize = 140
+ root_xml_tag = 'CstmrCdtTrfInitn'
+ else:
+ raise osv.except_osv(_('Error :'), _("Payment Type Code '%s' is not supported. The only Payment Type Codes supported for SEPA Credit Transfers are 'pain.001.001.02', 'pain.001.001.03' and 'pain.001.001.04'.") % pain_flavor)
+ if sepa_export.batch_booking:
+ my_batch_booking = 'true'
+ else:
+ my_batch_booking = 'false'
+ my_msg_identification = sepa_export.msg_identification
+ if sepa_export.prefered_exec_date:
+ my_requested_exec_date = sepa_export.prefered_exec_date
+ else:
+ my_requested_exec_date = fields.date.context_today(
+ self, cr, uid, context=context)
+
+ pain_ns = {
+ 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
+ None: 'urn:iso:std:iso:20022:tech:xsd:%s' % pain_flavor,
+ }
+
+ root = etree.Element('Document', nsmap=pain_ns)
+ pain_root = etree.SubElement(root, root_xml_tag)
+ # A. Group header
+ group_header = etree.SubElement(pain_root, 'GrpHdr')
+ message_identification = etree.SubElement(group_header, 'MsgId')
+ message_identification.text = self._limit_size(cr, uid, my_msg_identification, 35, context=context)
+ creation_date_time = etree.SubElement(group_header, 'CreDtTm')
+ creation_date_time.text = datetime.strftime(datetime.today(), '%Y-%m-%dT%H:%M:%S')
+ if pain_flavor == 'pain.001.001.02':
+ # batch_booking is in "Group header" with pain.001.001.02
+ # and in "Payment info" in pain.001.001.03/04
+ batch_booking = etree.SubElement(group_header, 'BtchBookg')
+ batch_booking.text = my_batch_booking
+ nb_of_transactions_grphdr = etree.SubElement(group_header, 'NbOfTxs')
+ control_sum_grphdr = etree.SubElement(group_header, 'CtrlSum')
+ # Grpg removed in pain.001.001.03
+ if pain_flavor == 'pain.001.001.02':
+ grouping = etree.SubElement(group_header, 'Grpg')
+ grouping.text = 'GRPD'
+ initiating_party = etree.SubElement(group_header, 'InitgPty')
+ initiating_party_name = etree.SubElement(initiating_party, 'Nm')
+ initiating_party_name.text = self._limit_size(cr, uid, my_company_name, name_maxsize, context=context)
+ # B. Payment info
+ payment_info = etree.SubElement(pain_root, 'PmtInf')
+ payment_info_identification = etree.SubElement(payment_info, 'PmtInfId')
+ payment_info_identification.text = self._limit_size(cr, uid, my_msg_identification, 35, context=context)
+ payment_method = etree.SubElement(payment_info, 'PmtMtd')
+ payment_method.text = 'TRF'
+ if pain_flavor in ['pain.001.001.03', 'pain.001.001.04']:
+ # batch_booking is in "Group header" with pain.001.001.02
+ # and in "Payment info" in pain.001.001.03/04
+ batch_booking = etree.SubElement(payment_info, 'BtchBookg')
+ batch_booking.text = my_batch_booking
+ # It may seem surprising, but the
+ # "SEPA Credit Transfer Scheme Customer-to-bank Implementation guidelines"
+ # v6.0 says that control sum and nb_of_transactions should be present
+ # at both "group header" level and "payment info" level
+ # This seems to be confirmed by the tests carried out at
+ # BNP Paribas in PAIN v001.001.03
+ if pain_flavor in ['pain.001.001.03', 'pain.001.001.04']:
+ nb_of_transactions_pmtinf = etree.SubElement(payment_info, 'NbOfTxs')
+ control_sum_pmtinf = etree.SubElement(payment_info, 'CtrlSum')
+ payment_type_info = etree.SubElement(payment_info, 'PmtTpInf')
+ service_level = etree.SubElement(payment_type_info, 'SvcLvl')
+ service_level_code = etree.SubElement(service_level, 'Cd')
+ service_level_code.text = 'SEPA'
+ requested_exec_date = etree.SubElement(payment_info, 'ReqdExctnDt')
+ requested_exec_date.text = my_requested_exec_date
+ debtor = etree.SubElement(payment_info, 'Dbtr')
+ debtor_name = etree.SubElement(debtor, 'Nm')
+ debtor_name.text = self._limit_size(cr, uid, my_company_name, name_maxsize, context=context)
+# debtor_address = etree.SubElement(debtor, 'PstlAdr')
+# debtor_street = etree.SubElement(debtor_address, 'AdrLine')
+# debtor_street.text = my_company_street1
+# debtor_city = etree.SubElement(debtor_address, 'AdrLine')
+# debtor_city.text = my_company_city
+# debtor_country = etree.SubElement(debtor_address, 'Ctry')
+# debtor_country.text = my_company_country_code
+ debtor_account = etree.SubElement(payment_info, 'DbtrAcct')
+ debtor_account_id = etree.SubElement(debtor_account, 'Id')
+ debtor_account_iban = etree.SubElement(debtor_account_id, 'IBAN')
+ debtor_account_iban.text = my_company_iban
+ debtor_agent = etree.SubElement(payment_info, 'DbtrAgt')
+ debtor_agent_institution = etree.SubElement(debtor_agent, 'FinInstnId')
+ if my_company_bic:
+ debtor_agent_bic = etree.SubElement(debtor_agent_institution, bic_xml_tag)
+ debtor_agent_bic.text = my_company_bic
+ charge_bearer = etree.SubElement(payment_info, 'ChrgBr')
+ charge_bearer.text = sepa_export.charge_bearer
+
+ transactions_count = 0
+ total_amount = 0.0
+ amount_control_sum = 0.0
+ # Iterate on payment orders
+ for payment_order in sepa_export.payment_order_ids:
+ total_amount = total_amount + payment_order.total
+ # Iterate each payment lines
+ for line in payment_order.line_ids:
+ transactions_count += 1
+ # C. Credit Transfer Transaction Info
+ credit_transfer_transaction_info = etree.SubElement(payment_info, 'CdtTrfTxInf')
+ payment_identification = etree.SubElement(credit_transfer_transaction_info, 'PmtId')
+ instruction_identification = etree.SubElement(payment_identification, 'InstrId')
+ instruction_identification.text = self._limit_size(cr, uid, line.communication, 35, context=context) #otherwise, we can reach the invoice fields via ml_inv_ref
+ end2end_identification = etree.SubElement(payment_identification, 'EndToEndId')
+ end2end_identification.text = self._limit_size(cr, uid, line.communication, 35, context=context)
+ amount = etree.SubElement(credit_transfer_transaction_info, 'Amt')
+ instructed_amount = etree.SubElement(amount, 'InstdAmt', Ccy=line.currency.name)
+ instructed_amount.text = '%.2f' % line.amount_currency
+ amount_control_sum += line.amount_currency
+ creditor_agent = etree.SubElement(credit_transfer_transaction_info, 'CdtrAgt')
+ creditor_agent_institution = etree.SubElement(creditor_agent, 'FinInstnId')
+ if not line.bank_id:
+ raise osv.except_osv(_('Error :'), _("Missing Bank Account on invoice '%s' (payment order line reference '%s').") %(line.ml_inv_ref.number, line.name))
+ if line.bank_id.bank.bic:
+ creditor_agent_bic = etree.SubElement(creditor_agent_institution, bic_xml_tag)
+ creditor_agent_bic.text = line.bank_id.bank.bic
+ creditor = etree.SubElement(credit_transfer_transaction_info, 'Cdtr')
+ creditor_name = etree.SubElement(creditor, 'Nm')
+ creditor_name.text = self._limit_size(cr, uid, line.partner_id.name, name_maxsize, context=context)
+# I don't think they want it
+# If they want it, we need to implement full spec p26 appendix
+# creditor_address = etree.SubElement(creditor, 'PstlAdr')
+# creditor_street = etree.SubElement(creditor_address, 'AdrLine')
+# creditor_street.text = line.partner_id.address[0].street
+# creditor_city = etree.SubElement(creditor_address, 'AdrLine')
+# creditor_city.text = line.partner_id.address[0].city
+# creditor_country = etree.SubElement(creditor_address, 'Ctry')
+# creditor_country.text = line.partner_id.address[0].country_id.code
+ creditor_account = etree.SubElement(credit_transfer_transaction_info, 'CdtrAcct')
+ creditor_account_id = etree.SubElement(creditor_account, 'Id')
+ creditor_account_iban = etree.SubElement(creditor_account_id, 'IBAN')
+ creditor_account_iban.text = self._validate_iban(cr, uid, line.bank_id.acc_number, context=context)
+ remittance_info = etree.SubElement(credit_transfer_transaction_info, 'RmtInf')
+ # switch to Structured (Strdr) ? If we do it, beware that the format is not the same between pain 02 and pain 03
+ remittance_info_unstructured = etree.SubElement(remittance_info, 'Ustrd')
+ remittance_info_unstructured.text = self._limit_size(cr, uid, line.communication, 140, context=context)
+
+ if pain_flavor in ['pain.001.001.03', 'pain.001.001.04']:
+ nb_of_transactions_grphdr.text = nb_of_transactions_pmtinf.text = str(transactions_count)
+ control_sum_grphdr.text = control_sum_pmtinf.text = '%.2f' % amount_control_sum
+ else:
+ nb_of_transactions_grphdr.text = str(transactions_count)
+ control_sum_grphdr.text = '%.2f' % amount_control_sum
+
+
+ xml_string = etree.tostring(root, pretty_print=True, encoding='UTF-8', xml_declaration=True)
+ _logger.debug("Generated SEPA XML file below")
+ _logger.debug(xml_string)
+ official_pain_schema = etree.XMLSchema(etree.parse(tools.file_open('account_banking_sepa_credit_transfer/data/%s.xsd' % pain_flavor)))
+
+ try:
+ root_to_validate = etree.fromstring(xml_string)
+ official_pain_schema.assertValid(root_to_validate)
+ except Exception, e:
+ _logger.warning("The XML file is invalid against the XML Schema Definition")
+ _logger.warning(xml_string)
+ _logger.warning(e)
+ raise osv.except_osv(_('Error :'), _('The generated XML file is not valid against the official XML Schema Definition. The generated XML file and the full error have been written in the server logs. Here is the error, which may give you an idea on the cause of the problem : %s') % str(e))
+
+ # CREATE the banking.export.sepa record
+ file_id = self.pool.get('banking.export.sepa').create(cr, uid,
+ {
+ 'msg_identification': my_msg_identification,
+ 'batch_booking': sepa_export.batch_booking,
+ 'charge_bearer': sepa_export.charge_bearer,
+ 'prefered_exec_date': sepa_export.prefered_exec_date,
+ 'total_amount': total_amount,
+ 'nb_transactions': transactions_count,
+ 'file': base64.encodestring(xml_string),
+ 'payment_order_ids': [
+ (6, 0, [x.id for x in sepa_export.payment_order_ids])
+ ],
+ }, context=context)
+
+ self.write(cr, uid, ids, {
+ 'file_id': file_id,
+ 'state': 'finish',
+ }, context=context)
+
+ action = {
+ 'name': 'SEPA XML',
+ 'type': 'ir.actions.act_window',
+ 'view_type': 'form',
+ 'view_mode': 'form,tree',
+ 'res_model': self._name,
+ 'res_id': ids[0],
+ 'target': 'new',
+ }
+ return action
+
+
+ def cancel_sepa(self, cr, uid, ids, context=None):
+ '''
+ Cancel the SEPA PAIN: just drop the file
+ '''
+ sepa_export = self.browse(cr, uid, ids[0], context=context)
+ self.pool.get('banking.export.sepa').unlink(cr, uid, sepa_export.file_id.id, context=context)
+ return {'type': 'ir.actions.act_window_close'}
+
+
+ def save_sepa(self, cr, uid, ids, context=None):
+ '''
+ Save the SEPA PAIN: mark all payments in the file as 'sent'.
+ '''
+ sepa_export = self.browse(cr, uid, ids[0], context=context)
+ sepa_file = self.pool.get('banking.export.sepa').write(cr, uid,
+ sepa_export.file_id.id, {'state': 'sent'}, context=context)
+ wf_service = netsvc.LocalService('workflow')
+ for order in sepa_export.payment_order_ids:
+ wf_service.trg_validate(uid, 'payment.order', order.id, 'sent', cr)
+ return {'type': 'ir.actions.act_window_close'}
+
+
+banking_export_sepa_wizard()
+
+>>>>>>> MERGE-SOURCE
=== modified file 'account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml'
--- account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml 2013-11-21 23:41:32 +0000
+++ account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml 2014-03-06 13:49:10 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010-2013 Akretion (http://www.akretion.com)
@@ -35,3 +36,53 @@
</data>
</openerp>
+=======
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2010-2012 Akretion (http://www.akretion.com)
+ @author: Alexis de Lattre <alexis.delattre@xxxxxxxxxxxx>
+ The licence is in the file __openerp__.py
+-->
+<openerp>
+<data>
+
+<record id="banking_export_sepa_wizard_view" model="ir.ui.view">
+ <field name="name">banking.export.sepa.wizard.view</field>
+ <field name="model">banking.export.sepa.wizard</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form string="SEPA XML file generation">
+ <field name="state" invisible="True"/>
+ <group states="create">
+ <separator colspan="4" string="Processing details" />
+ <field name="batch_booking" />
+ <field name="prefered_exec_date" />
+ <field name="charge_bearer" />
+ <separator colspan="4" string="Reference for further communication" />
+ <field name="msg_identification" required="True" />
+ <newline />
+ <button icon="gtk-close" special="cancel" string="Cancel" colspan="2"/>
+ <button icon="gtk-ok" string="Generate" name="create_sepa" type="object" colspan="2"/>
+ </group>
+ <group states="finish">
+ <field name="total_amount" />
+ <!-- Don't display this field, to avoid this bug :
+ https://bugs.launchpad.net/openobject-client-web/+bug/718989
+ Bug desc : in the Gtk client, you have to clic twice on the
+ "Create" button.
+ <field name="nb_transactions" /> -->
+ <newline />
+ <field name="file_id" />
+ <field name="file" filename="filename" />
+ <field name="filename" invisible="True"/>
+ <newline />
+ <button icon="gtk-cancel" string="Cancel" name="cancel_sepa" type="object" colspan="2"/>
+ <button icon="gtk-ok" string="Validate" name="save_sepa" type="object" colspan="2"/>
+ </group>
+ </form>
+ </field>
+</record>
+
+</data>
+</openerp>
+>>>>>>> MERGE-SOURCE
=== added directory 'account_banking_uk_lloyds_corporate'
=== added file 'account_banking_uk_lloyds_corporate/__init__.py'
--- account_banking_uk_lloyds_corporate/__init__.py 1970-01-01 00:00:00 +0000
+++ account_banking_uk_lloyds_corporate/__init__.py 2014-03-06 13:49:10 +0000
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2013 credativ Ltd (<http://www.credativ.co.uk>).
+# 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/>.
+#
+##############################################################################
+
+import lloydscorporate
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
=== added file 'account_banking_uk_lloyds_corporate/__openerp__.py'
--- account_banking_uk_lloyds_corporate/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_banking_uk_lloyds_corporate/__openerp__.py 2014-03-06 13:49:10 +0000
@@ -0,0 +1,37 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2013 credativ Ltd (<http://www.credativ.co.uk>).
+# 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 Lloyds Corporate CSV import',
+ 'version': '1.0',
+ 'license': 'AGPL-3',
+ 'author': 'credativ Ltd',
+ 'website': 'http://www.credativ.co.uk',
+ 'category': 'Account Banking',
+ 'depends': ['account_banking'],
+ 'init_xml': [],
+ 'update_xml': [],
+ 'demo_xml': [],
+ 'description': '''
+ Module to import bank statement CSV for Bank of Lloyds Corporate.
+ ''',
+ 'active': False,
+ 'installable': True,
+}
=== added file 'account_banking_uk_lloyds_corporate/lloydscorporate.py'
--- account_banking_uk_lloyds_corporate/lloydscorporate.py 1970-01-01 00:00:00 +0000
+++ account_banking_uk_lloyds_corporate/lloydscorporate.py 2014-03-06 13:49:10 +0000
@@ -0,0 +1,157 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (C) 2013 credativ Ltd (<http://www.credativ.co.uk>).
+# 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/>.
+#
+##############################################################################
+# Imports LLoyds Corporate format
+#
+
+from account_banking.parsers import models, convert
+from tools.translate import _
+import re
+import osv
+import logging
+import csv
+from StringIO import StringIO
+from operator import itemgetter
+
+logger = logging.getLogger('lloydscorporate_csv_import')
+
+class CSVTransaction(models.mem_bank_transaction):
+
+ mapping = {
+ 'execution_date' : 'date',
+ 'effective_date': 'date',
+ 'message' : 'description',
+ 'name' : 'description', # Use description as transaction name
+ 'balance' : 'Balance', # Store balance from line for calculating statement balances
+ }
+
+ def __init__(self, record, *args, **kwargs):
+ '''
+ Transaction creation
+ '''
+ super(CSVTransaction, self).__init__(*args, **kwargs)
+
+ # Parse date of format 01APR13
+ record['date'] = convert.str2date(re.sub(r'\W*','',record['Date']), '%d%b%y')
+
+ record['description'] = record['Narrative'].strip()
+
+ # Mapping of simple items
+ for key, value in self.mapping.iteritems():
+ if record.has_key(value):
+ setattr(self, key, record[value])
+
+ # Convert debit/credit to float amount
+ if len(record['Payments'].strip()):
+ self.transferred_amount = record['Payments'] and -float(record['Payments']) or 0.0
+ else:
+ self.transferred_amount = record['Receipts'] and float(record['Receipts']) or 0.0
+
+ # Cheque - set reference
+ transfer_account = re.match(r'\w*\s\d{1,12}$', record['description'])
+ if transfer_account:
+ self.reference = transfer_account.group()
+
+ if not self.is_valid():
+ logger.info("Invalid: %s", record)
+
+ def is_valid(self):
+ '''
+ We don't have remote_account so override base
+ '''
+ return (self.execution_date
+ and self.transferred_amount and True) or False
+
+class Statement(models.mem_bank_statement):
+
+ def import_statement(self, record):
+ self.transactions.append(CSVTransaction(record))
+
+def raise_error(message, line):
+ raise osv.osv.except_osv(_('Import error'),
+ 'Error in import:%s\n\n%s' % (message, line))
+
+class parser(models.parser):
+ code = 'LLOYDSCORPORATE-CSV'
+ name = _('Lloyds Corporate CSV Statement IMPORT')
+ country_code = 'GB'
+ doc = _('''\
+ This format is available through
+ the web interface.
+ ''')
+
+ def parse(self, cr, data):
+ ''' Lloyds corporate CSV parser'''
+
+ data = data.replace('\r','')
+ csv_header = data.split('\n')[0].replace('"', '').split(',')
+ header_list = ['Account', 'Date', 'Type', 'Narrative', 'Value Date', 'Payments', 'Receipts', 'Balance']
+ result = []
+
+ #compare header list and process csv if equal
+ if cmp(csv_header,header_list) != 0:
+ logger.info("Invalid import Statement:")
+ logger.info("Expected Header: %s" %(str(header_list)))
+ logger.info("Header found: %s"%(str(csv_header)))
+ raise osv.osv.except_osv(_('Import error'),
+ 'Error in import:%s\n' % (_('Invalid file format')))
+
+ bankdata = StringIO(data)
+ lines = list(csv.DictReader(bankdata))
+ stmnt = Statement()
+ # lines as they are imported
+ if len(lines):
+ #Store opening balance from first record
+ line = lines[0]
+ stmnt.start_balance = line['Balance']
+ account_number = re.sub('\D', '', line['Account'])
+
+ #Assuming if payment and receipts are both null then its opening balance
+ if not (line['Payments'] and line['Receipts']):
+ lines = lines[1:]
+
+ #Skip records which do not contains transaction type
+ for line in lines[:-int(len(lines)-map(itemgetter('Type'), lines).index(''))]:
+ #create Statement lines from csv records
+ stmnt.import_statement(line)
+
+ #Get statement Closing balance from CSV data list
+ try:
+ stmnt.end_balance = lines[map(itemgetter('Narrative'), lines).\
+ index('Closing Ledger Balance')]['Balance']
+ except ValueError:
+ raise osv.osv.except_osv(_('Closing Balance'),
+ _('Statement Closing Balance not found.'))
+
+
+ #GB account number format stored in ERP
+ stmnt.local_account = account_number[:6] +' '+ account_number[6:]
+
+ # Take date of last line of statement
+ stmnt.date = stmnt.transactions[-1].effective_date
+
+ statement_id = self.get_unique_statement_id(
+ cr, stmnt.date.strftime('%Yw%W'))
+ stmnt.id = statement_id
+ result.append(stmnt)
+ return result
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
=== added file 'account_banking_uk_lloyds_corporate/samplestatement.csv'
--- account_banking_uk_lloyds_corporate/samplestatement.csv 1970-01-01 00:00:00 +0000
+++ account_banking_uk_lloyds_corporate/samplestatement.csv 2014-03-06 13:49:10 +0000
@@ -0,0 +1,14 @@
+"Account","Date","Type","Narrative","Value Date","Payments","Receipts","Balance"
+"210999-40010000 (GBP)",31MAY13,"","Opening Ledger Balance",,,,30000
+"210999-40010000 (GBP)",31MAY13,"BGC","AXELOR 56465463 BGC
+5656546456 30/05","","",20000,50000
+"210999-40010000 (GBP)",31MAY13,"CR","ARGOS
+INVOICES PAID","","",10000,60000
+"210999-40010000 (GBP)",31MAY13,"DR","DEBANHAMS
+EUROS 307.70","",2000,"",58000
+"210999-40010000 (GBP)",31MAY13,"DR","HOTEL HILTON PARKLANE","",2000,"",56000
+"210999-40010000 (GBP)",31MAY13,"DR","TO 30999999999999 TFR","",6000,"",50000
+"210999-40010000 (GBP)",21JUN13,"","Value of Credits (96)","","",30000,
+"210999-40010000 (GBP)",21JUN13,"","Value of Debits (43)","",10000,,
+"210999-40010000 (GBP)",21JUN13,"","Closing Ledger Balance","","","",50000
+"210999-40010000 (GBP)",21JUN13,"","Closing Cleared Balance","","","",50000
=== modified file 'account_direct_debit/model/account_payment.py'
--- account_direct_debit/model/account_payment.py 2013-11-20 23:24:56 +0000
+++ account_direct_debit/model/account_payment.py 2014-03-06 13:49:10 +0000
@@ -6,6 +6,87 @@
class payment_order(orm.Model):
_inherit = 'payment.order'
+<<<<<<< TREE
+=======
+ def fields_view_get(self, cr, user, view_id=None, view_type='form',
+ context=None, toolbar=False, submenu=False):
+ """
+ We use the same form for payment and debit orders, but they
+ are accessible through different menu items. The user should only
+ be allowed to select a payment mode that applies to the type of order
+ i.e. payment or debit.
+
+ A pretty awful workaround is needed for the fact that no dynamic
+ domain is possible on the selection widget. This domain is encoded
+ in the context of the menu item.
+ """
+ if not context:
+ context = {}
+ res = super(payment_order, self).fields_view_get(
+ cr, user, view_id, view_type, context, toolbar, submenu)
+ if context.get('search_payment_order_type', False) and view_type == 'form':
+ if 'mode' in res['fields'] and 'selection' in res['fields']['mode']:
+ mode_obj = self.pool.get('payment.mode')
+ domain = ['|', ('type', '=', False), ('type.payment_order_type', '=',
+ context['search_payment_order_type'])]
+ # the magic is in the value of the selection
+ res['fields']['mode']['selection'] = mode_obj._name_search(
+ cr, user, args=domain)
+ # also update the domain
+ res['fields']['mode']['domain'] = domain
+ return res
+
+ def debit_reconcile_transfer(self, cr, uid, payment_order_id,
+ amount, currency, context=None):
+ """
+ During import of bank statements, create the reconcile on the transfer
+ account containing all the open move lines on the transfer account.
+ """
+ move_line_obj = self.pool.get('account.move.line')
+ order = self.browse(cr, uid, payment_order_id, context)
+ line_ids = []
+ reconcile_id = False
+ if not order.line_ids[0].debit_move_line_id:
+ wf_service = netsvc.LocalService('workflow')
+ wf_service.trg_validate(
+ uid, 'payment.order', payment_order_id, 'done', cr)
+ return False
+ for order_line in order.line_ids:
+ for line in order_line.debit_move_line_id.move_id.line_id:
+ if line.account_id.type == 'other' and not line.reconcile_id:
+ line_ids.append(line.id)
+ if self.pool.get('res.currency').is_zero(
+ cr, uid, currency,
+ move_line_obj.get_balance(cr, uid, line_ids) - amount):
+ reconcile_id = self.pool.get('account.move.reconcile').create(
+ cr, uid,
+ {'type': 'auto', 'line_id': [(6, 0, line_ids)]},
+ context)
+ # set direct debit order to finished state
+ wf_service = netsvc.LocalService('workflow')
+ wf_service.trg_validate(
+ uid, 'payment.order', payment_order_id, 'done', cr)
+ return reconcile_id
+
+ def debit_unreconcile_transfer(self, cr, uid, payment_order_id, reconcile_id,
+ amount, currency, context=None):
+ """
+ Due to a cancelled bank statements import, unreconcile the move on
+ the transfer account. Delegate the conditions to the workflow.
+ Raise on failure for rollback.
+ """
+ self.pool.get('account.move.reconcile').unlink(
+ cr, uid, reconcile_id, context=context)
+ wkf_ok = netsvc.LocalService('workflow').trg_validate(
+ uid, 'payment.order', payment_order_id, 'undo_done', cr)
+ if not wkf_ok:
+ raise osv.except_osv(
+ _("Cannot unreconcile"),
+ _("Cannot unreconcile debit order: "+
+ "Workflow will not allow it."))
+ return True
+
+>>>>>>> MERGE-SOURCE
def test_undo_done(self, cr, uid, ids, context=None):
"""
Called from the workflow. Used to unset done state on
@@ -17,5 +98,372 @@
for line in order.line_ids:
if line.storno:
return False
+<<<<<<< TREE
return super(payment_order, self).test_undo_done(
cr, uid, ids, context=context)
+=======
+ else:
+ # TODO: define conditions for 'payment' orders
+ return True
+ return True
+
+ def action_sent(self, cr, uid, ids, context=None):
+ """
+ Create the moves that pay off the move lines from
+ the debit order. This happens when the debit order file is
+ generated.
+ """
+ res = super(payment_order, self).action_sent(
+ cr, uid, ids, context)
+
+ account_move_obj = self.pool.get('account.move')
+ account_move_line_obj = self.pool.get('account.move.line')
+ payment_line_obj = self.pool.get('payment.line')
+ for order in self.browse(cr, uid, ids, context=context):
+ for line in order.line_ids:
+ # basic checks
+ if not line.move_line_id:
+ raise osv.except_osv(
+ _('Error'),
+ _('No move line provided for line %s') % line.name)
+ if line.move_line_id.reconcile_id:
+ raise osv.except_osv(
+ _('Error'),
+ _('Move line %s has already been paid/reconciled') %
+ line.move_line_id.name
+ )
+
+ move_id = account_move_obj.create(cr, uid, {
+ 'journal_id': order.mode.transfer_journal_id.id,
+ 'name': '%s order %s' % (order.payment_order_type,
+ line.move_line_id.move_id.name),
+ 'ref': '%s%s' % (order.payment_order_type[:3].upper(),
+ line.move_line_id.move_id.name),
+ }, context=context)
+
+ # TODO: take multicurrency into account
+
+ # create the debit move line on the transfer account
+ vals = {
+ 'name': '%s order for %s' % (
+ order.payment_order_type,
+ line.move_line_id.invoice and
+ line.move_line_id.invoice.number or
+ line.move_line_id.name),
+ 'move_id': move_id,
+ 'partner_id': line.partner_id.id,
+ 'account_id': order.mode.transfer_account_id.id,
+ 'credit': (order.payment_order_type == 'payment'
+ and line.amount or 0.0),
+ 'debit': (order.payment_order_type == 'debit'
+ and line.amount or 0.0),
+ 'date': time.strftime('%Y-%m-%d'),
+ }
+ transfer_move_line_id = account_move_line_obj.create(
+ cr, uid, vals, context=context)
+
+ # create the debit move line on the receivable account
+ vals.update({
+ 'account_id': line.move_line_id.account_id.id,
+ 'credit': (order.payment_order_type == 'debit'
+ and line.amount or 0.0),
+ 'debit': (order.payment_order_type == 'payment'
+ and line.amount or 0.0),
+ })
+ reconcile_move_line_id = account_move_line_obj.create(
+ cr, uid, vals, context=context)
+
+ # register the debit move line on the payment line
+ # and call reconciliation on it
+ payment_line_obj.write(
+ cr, uid, line.id,
+ {'debit_move_line_id': reconcile_move_line_id},
+ context=context)
+
+ payment_line_obj.debit_reconcile(
+ cr, uid, line.id, context=context)
+ account_move_obj.post(cr, uid, [move_id], context=context)
+ return res
+
+payment_order()
+
+class payment_line(osv.osv):
+ _inherit = 'payment.line'
+
+ def debit_storno(self, cr, uid, payment_line_id, amount,
+ currency, storno_retry=True, context=None):
+ """
+ The processing of a storno is triggered by a debit
+ transfer on one of the company's bank accounts.
+ This method offers to re-reconcile the original debit
+ payment. For this purpose, we have registered that
+ payment move on the payment line.
+
+ Return the (now incomplete) reconcile id. The caller MUST
+ re-reconcile this reconcile with the bank transfer and
+ re-open the associated invoice.
+
+ :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*
+ :param boolean storno_retry: when True, attempt to reopen the invoice, \
+ set the invoice to 'Debit denied' otherwise.
+ :return: an incomplete reconcile for the caller to fill
+ :rtype: database id of an account.move.reconcile resource.
+ """
+
+ move_line_obj = self.pool.get('account.move.line')
+ reconcile_obj = self.pool.get('account.move.reconcile')
+ line = self.browse(cr, uid, payment_line_id)
+ reconcile_id = False
+ if (line.debit_move_line_id and not line.storno and
+ self.pool.get('res.currency').is_zero(
+ cr, uid, currency, (
+ (line.debit_move_line_id.credit or 0.0) -
+ (line.debit_move_line_id.debit or 0.0) + amount))):
+ # Two different cases, full and partial
+ # Both cases differ subtly in the procedure to follow
+ # Needs refractoring, but why is this not in the OpenERP API?
+ # Actually, given the nature of a direct debit order and storno,
+ # we should not need to take partial into account on the side of
+ # the debit_move_line.
+ if line.debit_move_line_id.reconcile_partial_id:
+ reconcile_id = line.debit_move_line_id.reconcile_partial_id.id
+ attribute = 'reconcile_partial_id'
+ if len(line.debit_move_line_id.reconcile_id.line_partial_ids) == 2:
+ # reuse the simple reconcile for the storno transfer
+ reconcile_obj.write(
+ cr, uid, reconcile_id, {
+ 'line_id': [(6, 0, line.debit_move_line_id.id)],
+ 'line_partial_ids': [(6, 0, [])],
+ }, context=context)
+ else:
+ # split up the original reconcile in a partial one
+ # and a new one for reconciling the storno transfer
+ reconcile_obj.write(
+ cr, uid, reconcile_id, {
+ 'line_partial_ids': [(3, line.debit_move_line_id.id)],
+ }, context=context)
+ reconcile_id = reconcile_obj.create(
+ cr, uid, {
+ 'type': 'auto',
+ 'line_id': [(6, 0, line.debit_move_line_id.id)],
+ }, context=context)
+ elif line.debit_move_line_id.reconcile_id:
+ reconcile_id = line.debit_move_line_id.reconcile_id.id
+ if len(line.debit_move_line_id.reconcile_id.line_id) == 2:
+ # reuse the simple reconcile for the storno transfer
+ reconcile_obj.write(
+ cr, uid, reconcile_id, {
+ 'line_id': [(6, 0, [line.debit_move_line_id.id])]
+ }, context=context)
+ else:
+ # split up the original reconcile in a partial one
+ # and a new one for reconciling the storno transfer
+ partial_ids = [
+ x.id for x in line.debit_move_line_id.reconcile_id.line_id
+ if x.id != line.debit_move_line_id.id
+ ]
+ reconcile_obj.write(
+ cr, uid, reconcile_id, {
+ 'line_partial_ids': [(6, 0, partial_ids)],
+ 'line_id': [(6, 0, [])],
+ }, context=context)
+ reconcile_id = reconcile_obj.create(
+ cr, uid, {
+ 'type': 'auto',
+ 'line_id': [(6, 0, line.debit_move_line_id.id)],
+ }, context=context)
+ # mark the payment line for storno processed
+ if reconcile_id:
+ self.write(cr, uid, [payment_line_id],
+ {'storno': True}, context=context)
+ # put forth the invoice workflow
+ if line.move_line_id.invoice:
+ activity = (storno_retry and 'open_test'
+ or 'invoice_debit_denied')
+ netsvc.LocalService("workflow").trg_validate(
+ uid, 'account.invoice', line.move_line_id.invoice.id,
+ activity, cr)
+ return reconcile_id
+
+ def get_storno_account_id(self, cr, uid, payment_line_id, amount,
+ currency, context=None):
+ """
+ Check the match of the arguments, and 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.
+ """
+
+ line = self.browse(cr, uid, payment_line_id)
+ account_id = False
+ if (line.debit_move_line_id and not line.storno and
+ self.pool.get('res.currency').is_zero(
+ cr, uid, currency, (
+ (line.debit_move_line_id.credit or 0.0) -
+ (line.debit_move_line_id.debit or 0.0) + amount))):
+ account_id = line.debit_move_line_id.account_id.id
+ return account_id
+
+ def debit_reconcile(self, cr, uid, payment_line_id, context=None):
+ """
+ Reconcile a debit order's payment line with the the move line
+ that it is based on. Called from payment_order.action_sent().
+ As the amount is derived directly from the counterpart move line,
+ we do not expect a write off. Take partially reconcilions into
+ account though.
+
+ :param payment_line_id: the single id of the canceled payment line
+ """
+
+ if isinstance(payment_line_id, (list, tuple)):
+ payment_line_id = payment_line_id[0]
+ reconcile_obj = self.pool.get('account.move.reconcile')
+ move_line_obj = self.pool.get('account.move.line')
+ payment_line_record = self.browse(cr, uid, payment_line_id, context=context)
+
+ debit_move_line = payment_line_record.debit_move_line_id
+ torec_move_line = payment_line_record.move_line_id
+
+ if payment_line_record.storno:
+ raise osv.except_osv(
+ _('Can not reconcile'),
+ _('Cancelation of payment line \'%s\' has already been ' +
+ 'processed') % payment_line_record.name)
+ if (not debit_move_line or not torec_move_line):
+ raise osv.except_osv(
+ _('Can not reconcile'),
+ _('No move line for line %s') % payment_line_record.name)
+ if torec_move_line.reconcile_id: # torec_move_line.reconcile_partial_id:
+ raise osv.except_osv(
+ _('Error'),
+ _('Move line %s has already been reconciled') %
+ torec_move_line.name
+ )
+ if debit_move_line.reconcile_id or debit_move_line.reconcile_partial_id:
+ raise osv.except_osv(
+ _('Error'),
+ _('Move line %s has already been reconciled') %
+ debit_move_line.name
+ )
+
+ def is_zero(total):
+ return self.pool.get('res.currency').is_zero(
+ cr, uid, debit_move_line.company_id.currency_id, total)
+
+ line_ids = [debit_move_line.id, torec_move_line.id]
+ if torec_move_line.reconcile_partial_id:
+ line_ids = [
+ x.id for x in torec_move_line.reconcile_partial_id.line_partial_ids] + [debit_move_line.id]
+
+ total = move_line_obj.get_balance(cr, uid, line_ids)
+ vals = {
+ 'type': 'auto',
+ 'line_id': is_zero(total) and [(6, 0, line_ids)] or [(6, 0, [])],
+ 'line_partial_ids': is_zero(total) and [(6, 0, [])] or [(6, 0, line_ids)],
+ }
+
+ if torec_move_line.reconcile_partial_id:
+ reconcile_obj.write(
+ cr, uid, debit_move_line.reconcile_partial_id.id,
+ vals, context=context)
+ else:
+ reconcile_obj.create(
+ cr, uid, vals, context=context)
+ for line_id in line_ids:
+ netsvc.LocalService("workflow").trg_trigger(
+ uid, 'account.move.line', line_id, cr)
+
+ # If a bank transaction of a storno was first confirmed
+ # and now canceled (the invoice is now in state 'debit_denied'
+ if torec_move_line.invoice:
+ netsvc.LocalService("workflow").trg_validate(
+ uid, 'account.invoice', torec_move_line.invoice.id,
+ 'undo_debit_denied', cr)
+
+
+
+ _columns = {
+ 'debit_move_line_id': fields.many2one(
+ # this line is part of the credit side of move 2a
+ # from the documentation
+ 'account.move.line', 'Debit move line',
+ readonly=True,
+ help="Move line through which the debit order pays the invoice"),
+ 'storno': fields.boolean(
+ 'Storno',
+ readonly=True,
+ help=("If this is true, the debit order has been canceled " +
+ "by the bank or by the customer")),
+ }
+payment_line()
+
+
+class payment_order_create(osv.osv_memory):
+ _inherit = 'payment.order.create'
+
+ def search_entries(self, cr, uid, ids, context=None):
+ """
+ This method taken from account_payment module.
+ We adapt the domain based on the payment_order_type
+ """
+ line_obj = self.pool.get('account.move.line')
+ mod_obj = self.pool.get('ir.model.data')
+ if context is None:
+ context = {}
+ data = self.read(cr, uid, ids, [], context=context)[0]
+ search_due_date = data['duedate']
+
+ ### start account_direct_debit ###
+ payment = self.pool.get('payment.order').browse(
+ cr, uid, context['active_id'], context=context)
+ # Search for move line to pay:
+ if payment.payment_order_type == 'debit':
+ domain = [
+ ('reconcile_id', '=', False),
+ ('account_id.type', '=', 'receivable'),
+ ('invoice_state', '!=', 'debit_denied'),
+ ('amount_to_receive', '>', 0),
+ ]
+ else:
+ domain = [
+ ('reconcile_id', '=', False),
+ ('account_id.type', '=', 'payable'),
+ ('amount_to_pay', '>', 0)
+ ]
+ domain.append(('company_id', '=', payment.mode.company_id.id))
+ # apply payment term filter
+ if payment.mode.payment_term_ids:
+ domain = domain + [
+ ('payment_term_id', 'in',
+ [term.id for term in payment.mode.payment_term_ids]
+ )
+ ]
+ # domain = [('reconcile_id', '=', False), ('account_id.type', '=', 'payable'), ('amount_to_pay', '>', 0)]
+ ### end account_direct_debit ###
+
+ domain = domain + ['|', ('date_maturity', '<=', search_due_date), ('date_maturity', '=', False)]
+ line_ids = line_obj.search(cr, uid, domain, context=context)
+ context.update({'line_ids': line_ids})
+ model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'view_create_payment_order_lines')], context=context)
+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
+ return {'name': ('Entry Lines'),
+ 'context': context,
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'payment.order.create',
+ 'views': [(resource_id,'form')],
+ 'type': 'ir.actions.act_window',
+ 'target': 'new',
+ }
+payment_order_create()
+
+
+
+>>>>>>> MERGE-SOURCE