Merge lp:~openerp-dev/openobject-addons/trunk-bank-reconciliation-ama into lp:openobject-addons

Proposed by Martin Trigaux (OpenERP)
Status: Work in progress
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-bank-reconciliation-ama
Merge into: lp:openobject-addons
Diff against target: 5080 lines (+3418/-810)
38 files modified
account/__openerp__.py (+3/-0)
account/account.py (+5/-0)
account/account_bank_statement.py (+370/-197)
account/account_invoice.py (+1/-1)
account/account_move_line.py (+7/-5)
account/account_unit_test.xml (+2/-2)
account/account_view.xml (+126/-42)
account/demo/account_bank_statement.xml (+85/-0)
account/demo/account_invoice_demo.xml (+130/-0)
account/security/ir.model.access.csv (+101/-100)
account/static/src/css/account_bank_statement_reconciliation.css (+264/-0)
account/static/src/css/account_bank_statement_reconciliation.scss (+447/-0)
account/static/src/js/account_widgets.js (+1468/-0)
account/static/src/xml/account_bank_statement_reconciliation.xml (+194/-0)
account/views/account.xml (+2/-1)
account/wizard/__init__.py (+2/-4)
account/wizard/account_statement_from_invoice.py (+4/-43)
account/wizard/pos_box.py (+0/-2)
account_analytic_plans/__openerp__.py (+1/-0)
account_analytic_plans/account_analytic_plans_view.xml (+20/-52)
account_analytic_plans/static/src/js/account_bank_reconciliation.js (+35/-0)
account_analytic_plans/views/account_analytic_plans.xml (+12/-0)
account_bank_statement_extensions/account_bank_statement_view.xml (+2/-10)
account_payment/wizard/account_payment_populate_statement.py (+0/-3)
account_voucher/__init__.py (+0/-1)
account_voucher/__openerp__.py (+0/-1)
account_voucher/account_voucher.py (+0/-110)
account_voucher/account_voucher_view.xml (+1/-53)
account_voucher/wizard/__init__.py (+0/-24)
l10n_be_coda/__openerp__.py (+29/-29)
l10n_be_coda/l10n_be_coda_demo.xml (+36/-0)
l10n_be_coda/l10n_be_coda_view.xml (+1/-9)
l10n_be_coda/l10n_be_coda_wizard.xml (+0/-1)
l10n_be_coda/wizard/account_coda_import.py (+51/-77)
point_of_sale/point_of_sale.py (+1/-19)
point_of_sale/point_of_sale_view.xml (+0/-7)
point_of_sale/test/account_statement_reports.yml (+16/-15)
stock/stock.py (+2/-2)
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/trunk-bank-reconciliation-ama
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+218970@code.launchpad.net
To post a comment you must log in.
9282. By Arthur Maniet

[FIX] reconciliation persistance logic

9283. By Arthur Maniet

[MERGE] with trunk

9284. By Arthur Maniet

[IMP] the form in bankStatementReconciliationLine is now fully extensible

9285. By Arthur Maniet

[add] partial reconciliation

9286. By Arthur Maniet

[ADD] to account_analytic_plans files to extend account.bankStatementReconciliationLine widget
[FIX] temporary account in coda import wizard removed
[IMP] move lines unicity in reconciliation more gracefully enforced

9287. By Arthur Maniet

merged with self, somehow

9288. By Arthur Maniet

a

9289. By Arthur Maniet

[IMP] fields in the create line form can be hidden depending on group ; account_analytic_plans correctly updates the form

9290. By Arthur Maniet

[FIX] bank statement can be closed
[FIX] tests depending on bank statement (line)

9291. By Arthur Maniet

[FIX] point_of_sale/test/account_statement_reports.yml

9292. By Arthur Maniet

idem

9293. By Arthur Maniet

bis repetita

9294. By Arthur Maniet

ad nauseam

9295. By Arthur Maniet

nauseam

9296. By Arthur Maniet

a

9297. By Arthur Maniet

a

9298. By Arthur Maniet

a

9299. By Arthur Maniet

a

9300. By Arthur Maniet

a

9301. By Arthur Maniet

a

9302. By Arthur Maniet

[IMP] first batch of reconciliations now fetched in one request

9303. By Arthur Maniet

a

9304. By Arthur Maniet

a

9305. By Arthur Maniet

[FIX] point_of_sale/test/account_statement_reports.yml seems to be ok now, finally

9306. By Arthur Maniet

a

9307. By Arthur Maniet

a

9308. By Arthur Maniet

a

9309. By Arthur Maniet

[FIX] partner change went buggy

9310. By Arthur Maniet

[FIX] field Analytic Distribution added to reconciliation widget by account_analytic_plan

9311. By Arthur Maniet

[IMP] progress bar includes previous reconciliations

9312. By Arthur Maniet

[ADD] class account_bank_reconciliation_move_preset
[IMP] form to create line and presets are totally extensible

9313. By Arthur Maniet

[ADD] Tax on a created line now appears as a separate line

9314. By Arthur Maniet

[ADD]ed a menu to edit presets ; accessible with technical features

9315. By Arthur Maniet

[IMP] needaction badge updated whichever menu item is selected
[ADD] multicurrency fields to bank statement lines form
[FIX] javascript float precision === 0 fail
[FIX] widget consistency about no_match

9316. By Arthur Maniet

[IMP] account_bank_reconciliation_move_preset and many misc improvements

9317. By Arthur Maniet

[IMP] account.bank.reconciliation.move.preset usage

9318. By Arthur Maniet

[ADD] access rights
[FIX] bak.statement.move.preset renamed in statement.operation.template

9319. By Arthur Maniet

[IMP] account_statement_operation_template's form view
[FIX] misc

9320. By Arthur Maniet

[ADD] demo data

9321. By Quentin (OpenERP) <email address hidden>

[MERGE] trunk

9322. By Quentin (OpenERP) <email address hidden>

[FIX/IMP] fixes/improvements made during the code review

9323. By Arthur Maniet

[FIX] small stuff

9324. By Quentin (OpenERP) <email address hidden>

[FIX] fixed error in statement form view

9325. By Quentin (OpenERP) <email address hidden>

[FIX] import invoice button in bank statement

9326. By Quentin (OpenERP) <email address hidden>

[REF] moved the wizard to import invoices on bank statements in account from account_voucher because it doesn't need the vouchers anymore for the reconciliation process

9327. By Quentin (OpenERP) <email address hidden>

[REF] merged account_move_reconciliation.js and account_bank_statement_reconciliation.js into accont_widgets.js as they both were defining openerp.account (which lead to overriding and only the last was succesfully loaded)

9328. By Quentin (OpenERP) <email address hidden>

[FIX] installation of account module

9329. By Quentin (OpenERP) <email address hidden>

[IMP] account: invoice order improved

9330. By Quentin (OpenERP) <email address hidden>

[FIX] account: error in unit_test data

9331. By Quentin (OpenERP) <email address hidden>

[REF] account: reordered demo data + fixed error in bank statement balance

9332. By Quentin (OpenERP) <email address hidden>

[FIX] account: set the good group on analytic field

9333. By Quentin (OpenERP) <email address hidden>

[IMP] account: formated the monetary field accordingly to the currency symbol and position for initial and counterpart lines (created and open balance lines are still to do)

9334. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: display the amount of proposed counterparts in the statement currency

9335. By Quentin (OpenERP) <email address hidden>

[REF] account, bank statement reconciliation: refactoring on accounting entries creation

9336. By Quentin (OpenERP) <email address hidden>

[REF] account: removed uneeded code

9337. By Quentin (OpenERP) <email address hidden>

[IMP] l10n_be_coda: added demo data in order to be able to import the coda test file embedded in the module

9338. By Arthur Maniet

[FIX] currency format in the widget

9339. By Quentin (OpenERP) <email address hidden>

[FIX] account: tax computation doesn't accept context (hu?)

9340. By Quentin (OpenERP) <email address hidden>

[FIX] account: mising arguments

9341. By Arthur Maniet

[IMP] success message

9342. By Quentin (OpenERP) <email address hidden>

[FIX] account, reconciliation on bank statement process: accounting entries creation in multi-currency + do not filter lines created by previous bank statement

9343. By Arthur Maniet

[FIX] partial reconciliation showing when there are created lines

9344. By Arthur Maniet

[FIX] stupidity

9345. By Quentin (OpenERP) <email address hidden>

[IMP] account

9346. By Quentin (OpenERP) <email address hidden>

[FIX] account: bug introduced in previous revision

9347. By Arthur Maniet

[FIX] popover (hopefully) don't stay freezed when their originator is destroyed
      amount formatting
      use correct account for tax move lines
      (probably fixed) : open balance rounding error

9348. By Arthur Maniet

[FIX] event handlers on UI that went buggy when the UI was not up to date to the model because of async calls (tested on raspberry pi ; experienced pain).

9349. By Arthur Maniet

[FIX] do not use a value where a list is expected
      removed empty account_bank_statement_reconciliation.js
   can't validate a reconciliation while changing the partner

9350. By Arthur Maniet

[FIX] when changing a reconciliation line's partner, the move lines selected weren't freed for other reconciliations

9351. By Quentin (OpenERP) <email address hidden>

[FIX] account: preserve sign of amounts when applying presets

9352. By Quentin (OpenERP) <email address hidden>

[IMP] account: usabiltiy in bank statement form view

9353. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: multi currency issue fixed

9354. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: fixed filter on change partner field

9355. By Quentin (OpenERP) <email address hidden>

[IMP] account, bank statement reconciliation: improved demo data for operation templates

9356. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: display only one of the lines that are already partially reconciled together

9357. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: hopefully, the last fix related to muli-currency issues

Unmerged revisions

9357. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: hopefully, the last fix related to muli-currency issues

9356. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: display only one of the lines that are already partially reconciled together

9355. By Quentin (OpenERP) <email address hidden>

[IMP] account, bank statement reconciliation: improved demo data for operation templates

9354. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: fixed filter on change partner field

9353. By Quentin (OpenERP) <email address hidden>

[FIX] account, bank statement reconciliation: multi currency issue fixed

9352. By Quentin (OpenERP) <email address hidden>

[IMP] account: usabiltiy in bank statement form view

9351. By Quentin (OpenERP) <email address hidden>

[FIX] account: preserve sign of amounts when applying presets

9350. By Arthur Maniet

[FIX] when changing a reconciliation line's partner, the move lines selected weren't freed for other reconciliations

9349. By Arthur Maniet

[FIX] do not use a value where a list is expected
      removed empty account_bank_statement_reconciliation.js
   can't validate a reconciliation while changing the partner

9348. By Arthur Maniet

[FIX] event handlers on UI that went buggy when the UI was not up to date to the model because of async calls (tested on raspberry pi ; experienced pain).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account/__openerp__.py'
2--- account/__openerp__.py 2014-04-29 15:41:04 +0000
3+++ account/__openerp__.py 2014-05-30 16:18:57 +0000
4@@ -65,6 +65,7 @@
5 'wizard/account_period_close_view.xml',
6 'wizard/account_reconcile_view.xml',
7 'wizard/account_unreconcile_view.xml',
8+ 'wizard/account_statement_from_invoice_view.xml',
9 'account_view.xml',
10 'account_report.xml',
11 'account_financial_report_data.xml',
12@@ -144,6 +145,7 @@
13 'qweb' : [
14 "static/src/xml/account_move_reconciliation.xml",
15 "static/src/xml/account_move_line_quickadd.xml",
16+ "static/src/xml/account_bank_statement_reconciliation.xml",
17 ],
18 'demo': [
19 'demo/account_demo.xml',
20@@ -151,6 +153,7 @@
21 'project/analytic_account_demo.xml',
22 'demo/account_minimal.xml',
23 'demo/account_invoice_demo.xml',
24+ 'demo/account_bank_statement.xml',
25 'account_unit_test.xml',
26 ],
27 'test': [
28
29=== modified file 'account/account.py'
30--- account/account.py 2014-04-24 13:45:33 +0000
31+++ account/account.py 2014-05-30 16:18:57 +0000
32@@ -2073,6 +2073,11 @@
33 cur_price_unit+=amount2
34 return res
35
36+ def compute_for_bank_reconciliation(self, cr, uid, tax_id, amount, context=None):
37+ """ Called by RPC by the bank statement reconciliation widget """
38+ tax = self.browse(cr, uid, tax_id, context=context)
39+ return self.compute_all(cr, uid, [tax], amount, 1) # TOCHECK may use force_exclude parameter
40+
41 def compute_all(self, cr, uid, taxes, price_unit, quantity, product=None, partner=None, force_excluded=False):
42 """
43 :param force_excluded: boolean used to say that we don't want to consider the value of field price_include of
44
45=== modified file 'account/account_bank_statement.py'
46--- account/account_bank_statement.py 2014-02-10 06:46:42 +0000
47+++ account/account_bank_statement.py 2014-05-30 16:18:57 +0000
48@@ -19,11 +19,10 @@
49 #
50 ##############################################################################
51
52-import time
53-
54 from openerp.osv import fields, osv
55 from openerp.tools.translate import _
56 import openerp.addons.decimal_precision as dp
57+from openerp.report import report_sxw
58
59 class account_bank_statement(osv.osv):
60 def create(self, cr, uid, vals, context=None):
61@@ -66,6 +65,18 @@
62 return periods[0]
63 return False
64
65+ def _compute_default_statement_name(self, cr, uid, context=None):
66+ if context is None:
67+ context = {}
68+ obj_seq = self.pool.get('ir.sequence')
69+ default_journal_id = self._default_journal_id(cr, uid, context=context)
70+ if default_journal_id != False:
71+ period = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, context=context), context=context)
72+ context['fiscalyear_id'] = period.fiscalyear_id.id
73+ journal = self.pool.get('account.journal').browse(cr, uid, default_journal_id, None)
74+ return obj_seq.next_by_id(cr, uid, journal.sequence_id.id, context=context)
75+ return obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=context)
76+
77 def _currency(self, cursor, user, ids, name, args, context=None):
78 res = {}
79 res_currency_obj = self.pool.get('res.currency')
80@@ -92,12 +103,18 @@
81 result[line.statement_id.id] = True
82 return result.keys()
83
84+ def _all_lines_reconciled(self, cr, uid, ids, name, args, context=None):
85+ res = {}
86+ for statement in self.browse(cr, uid, ids, context=context):
87+ res[statement.id] = all([line.journal_entry_id.id for line in statement.line_ids])
88+ return res
89+
90 _order = "date desc, id desc"
91 _name = "account.bank.statement"
92 _description = "Bank Statement"
93 _inherit = ['mail.thread']
94 _columns = {
95- 'name': fields.char('Reference', size=64, required=True, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'), # readonly for account_cash_statement
96+ 'name': fields.char('Reference', size=64, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'), # readonly for account_cash_statement
97 'date': fields.date('Date', required=True, states={'confirm': [('readonly', True)]}, select=True),
98 'journal_id': fields.many2one('account.journal', 'Journal', required=True,
99 readonly=True, states={'draft':[('readonly',False)]}),
100@@ -129,10 +146,11 @@
101 type='many2one', relation='res.currency'),
102 'account_id': fields.related('journal_id', 'default_debit_account_id', type='many2one', relation='account.account', string='Account used in this journal', readonly=True, help='used in statement reconciliation domain, but shouldn\'t be used elswhere.'),
103 'cash_control': fields.related('journal_id', 'cash_control' , type='boolean', relation='account.journal',string='Cash control'),
104+ 'all_lines_reconciled': fields.function(_all_lines_reconciled, string='All lines reconciled', type='boolean'),
105 }
106
107 _defaults = {
108- 'name': "/",
109+ 'name': _compute_default_statement_name,
110 'date': fields.date.context_today,
111 'state': 'draft',
112 'journal_id': _default_journal_id,
113@@ -193,37 +211,6 @@
114 'ref': st_line.ref,
115 }
116
117- def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id,
118- context=None):
119- """Compute the args to build the dict of values to create the bank move line from a
120- statement line by calling the _prepare_move_line_vals. This method may be
121- overridden to implement custom move generation (making sure to call super() to
122- establish a clean extension chain).
123-
124- :param browse_record st_line: account.bank.statement.line record to
125- create the move from.
126- :param int/long move_id: ID of the account.move to link the move line
127- :param float amount: amount of the move line
128- :param int/long company_currency_id: ID of currency of the concerned company
129- :return: dict of value to create() the bank account.move.line
130- """
131- anl_id = st_line.analytic_account_id and st_line.analytic_account_id.id or False
132- debit = ((amount<0) and -amount) or 0.0
133- credit = ((amount>0) and amount) or 0.0
134- cur_id = False
135- amt_cur = False
136- if st_line.statement_id.currency.id <> company_currency_id:
137- cur_id = st_line.statement_id.currency.id
138- if st_line.account_id and st_line.account_id.currency_id and st_line.account_id.currency_id.id <> company_currency_id:
139- cur_id = st_line.account_id.currency_id.id
140- if cur_id:
141- res_currency_obj = self.pool.get('res.currency')
142- amt_cur = -res_currency_obj.compute(cr, uid, company_currency_id, cur_id, amount, context=context)
143-
144- res = self._prepare_move_line_vals(cr, uid, st_line, move_id, debit, credit,
145- amount_currency=amt_cur, currency_id=cur_id, analytic_id=anl_id, context=context)
146- return res
147-
148 def _get_counter_part_account(sefl, cr, uid, st_line, context=None):
149 """Retrieve the account to use in the counterpart move.
150 This method may be overridden to implement custom move generation (making sure to
151@@ -248,8 +235,7 @@
152 """
153 return st_line.partner_id and st_line.partner_id.id or False
154
155- def _prepare_counterpart_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id,
156- context=None):
157+ def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id, context=None):
158 """Compute the args to build the dict of values to create the counter part move line from a
159 statement line by calling the _prepare_move_line_vals. This method may be
160 overridden to implement custom move generation (making sure to call super() to
161@@ -266,19 +252,22 @@
162 account_id = self._get_counter_part_account(cr, uid, st_line, context=context)
163 partner_id = self._get_counter_part_partner(cr, uid, st_line, context=context)
164 debit = ((amount > 0) and amount) or 0.0
165- credit = ((amount < 0) and -amount) or 0.0
166+ credit = ((amount < 0) and -amount) or 0.0
167 cur_id = False
168 amt_cur = False
169- if st_line.statement_id.currency.id <> company_currency_id:
170+ if st_line.statement_id.currency.id != company_currency_id:
171 amt_cur = st_line.amount
172- cur_id = st_line.statement_id.currency.id
173+ cur_id = st_line.currency_id or st_line.statement_id.currency.id
174+ # TODO : FIXME the amount should be in the journal currency
175+ if st_line.currency_id and st_line.amount_currency:
176+ amt_cur = st_line.amount_currency
177+ cur_id = st_line.currency_id.id
178 return self._prepare_move_line_vals(cr, uid, st_line, move_id, debit, credit,
179- amount_currency = amt_cur, currency_id = cur_id, account_id = account_id,
180- partner_id = partner_id, context=context)
181+ amount_currency=amt_cur, currency_id=cur_id, account_id=account_id,
182+ partner_id=partner_id, context=context)
183
184- def _prepare_move_line_vals(self, cr, uid, st_line, move_id, debit, credit, currency_id = False,
185- amount_currency= False, account_id = False, analytic_id = False,
186- partner_id = False, context=None):
187+ def _prepare_move_line_vals(self, cr, uid, st_line, move_id, debit, credit, currency_id=False,
188+ amount_currency=False, account_id=False, partner_id=False, context=None):
189 """Prepare the dict of values to create the move line from a
190 statement line. All non-mandatory args will replace the default computed one.
191 This method may be overridden to implement custom move generation (making sure to
192@@ -293,7 +282,6 @@
193 :param float amount_currency: amount of the debit/credit expressed in the currency_id
194 :param int/long account_id: ID of the account to use in the move line if different
195 from the statement line account ID
196- :param int/long analytic_id: ID of analytic account to put on the move line
197 :param int/long partner_id: ID of the partner to put on the move line
198 :return: dict of value to create() the account.move.line
199 """
200@@ -314,67 +302,8 @@
201 'period_id': st_line.statement_id.period_id.id,
202 'currency_id': amount_currency and cur_id,
203 'amount_currency': amount_currency,
204- 'analytic_account_id': analytic_id,
205 }
206
207- def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None):
208- """Create the account move from the statement line.
209-
210- :param int/long st_line_id: ID of the account.bank.statement.line to create the move from.
211- :param int/long company_currency_id: ID of the res.currency of the company
212- :param char st_line_number: will be used as the name of the generated account move
213- :return: ID of the account.move created
214- """
215-
216- if context is None:
217- context = {}
218- res_currency_obj = self.pool.get('res.currency')
219- account_move_obj = self.pool.get('account.move')
220- account_move_line_obj = self.pool.get('account.move.line')
221- account_bank_statement_line_obj = self.pool.get('account.bank.statement.line')
222- st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id, context=context)
223- st = st_line.statement_id
224-
225- context.update({'date': st_line.date})
226-
227- move_vals = self._prepare_move(cr, uid, st_line, st_line_number, context=context)
228- move_id = account_move_obj.create(cr, uid, move_vals, context=context)
229- account_bank_statement_line_obj.write(cr, uid, [st_line.id], {
230- 'move_ids': [(4, move_id, False)]
231- })
232- torec = []
233- acc_cur = ((st_line.amount<=0) and st.journal_id.default_debit_account_id) or st_line.account_id
234-
235- context.update({
236- 'res.currency.compute.account': acc_cur,
237- })
238- amount = res_currency_obj.compute(cr, uid, st.currency.id,
239- company_currency_id, st_line.amount, context=context)
240-
241- bank_move_vals = self._prepare_bank_move_line(cr, uid, st_line, move_id, amount,
242- company_currency_id, context=context)
243- move_line_id = account_move_line_obj.create(cr, uid, bank_move_vals, context=context)
244- torec.append(move_line_id)
245-
246- counterpart_move_vals = self._prepare_counterpart_move_line(cr, uid, st_line, move_id,
247- amount, company_currency_id, context=context)
248- account_move_line_obj.create(cr, uid, counterpart_move_vals, context=context)
249-
250- for line in account_move_line_obj.browse(cr, uid, [x.id for x in
251- account_move_obj.browse(cr, uid, move_id,
252- context=context).line_id],
253- context=context):
254- if line.state <> 'valid':
255- raise osv.except_osv(_('Error!'),
256- _('Journal item "%s" is not valid.') % line.name)
257-
258- # Bank statements will not consider boolean on journal entry_posted
259- account_move_obj.post(cr, uid, [move_id], context=context)
260- return move_id
261-
262- def get_next_st_line_number(self, cr, uid, st_number, st_line, context=None):
263- return st_number + '/' + str(st_line.sequence)
264-
265 def balance_check(self, cr, uid, st_id, journal_type='bank', context=None):
266 st = self.browse(cr, uid, st_id, context=context)
267 if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001)):
268@@ -389,49 +318,30 @@
269 return state in ('draft','open')
270
271 def button_confirm_bank(self, cr, uid, ids, context=None):
272- obj_seq = self.pool.get('ir.sequence')
273 if context is None:
274 context = {}
275
276 for st in self.browse(cr, uid, ids, context=context):
277 j_type = st.journal_id.type
278- company_currency_id = st.journal_id.company_id.currency_id.id
279 if not self.check_status_condition(cr, uid, st.state, journal_type=j_type):
280 continue
281
282 self.balance_check(cr, uid, st.id, journal_type=j_type, context=context)
283 if (not st.journal_id.default_credit_account_id) \
284 or (not st.journal_id.default_debit_account_id):
285- raise osv.except_osv(_('Configuration Error!'),
286- _('Please verify that an account is defined in the journal.'))
287-
288- if not st.name == '/':
289- st_number = st.name
290- else:
291- c = {'fiscalyear_id': st.period_id.fiscalyear_id.id}
292- if st.journal_id.sequence_id:
293- st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c)
294- else:
295- st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c)
296-
297+ raise osv.except_osv(_('Configuration Error!'), _('Please verify that an account is defined in the journal.'))
298 for line in st.move_line_ids:
299 if line.state <> 'valid':
300- raise osv.except_osv(_('Error!'),
301- _('The account entries lines are not in valid state.'))
302+ raise osv.except_osv(_('Error!'), _('The account entries lines are not in valid state.'))
303+ move_ids = []
304 for st_line in st.line_ids:
305- if st_line.analytic_account_id:
306- if not st.journal_id.analytic_journal_id:
307- raise osv.except_osv(_('No Analytic Journal!'),_("You have to assign an analytic journal on the '%s' journal!") % (st.journal_id.name,))
308 if not st_line.amount:
309 continue
310- st_line_number = self.get_next_st_line_number(cr, uid, st_number, st_line, context)
311- self.create_move_from_st_line(cr, uid, st_line.id, company_currency_id, st_line_number, context)
312-
313- self.write(cr, uid, [st.id], {
314- 'name': st_number,
315- 'balance_end_real': st.balance_end
316- }, context=context)
317- self.message_post(cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st_number,), context=context)
318+ if not st_line.journal_entry_id.id:
319+ raise osv.except_osv(_('Error!'), _('All the account entries lines must be processed in order to close the statement.'))
320+ move_ids.append(st_line.journal_entry_id.id)
321+ self.pool.get('account.move').post(cr, uid, move_ids, context=context)
322+ self.message_post(cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st.name,), context=context)
323 return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
324
325 def button_cancel(self, cr, uid, ids, context=None):
326@@ -492,93 +402,356 @@
327 return super(account_bank_statement, self).copy(cr, uid, id, default, context=context)
328
329 def button_journal_entries(self, cr, uid, ids, context=None):
330- ctx = (context or {}).copy()
331- ctx['journal_id'] = self.browse(cr, uid, ids[0], context=context).journal_id.id
332- return {
333- 'name': _('Journal Items'),
334- 'view_type':'form',
335- 'view_mode':'tree',
336- 'res_model':'account.move.line',
337- 'view_id':False,
338- 'type':'ir.actions.act_window',
339- 'domain':[('statement_id','in',ids)],
340- 'context':ctx,
341- }
342-
343+ ctx = (context or {}).copy()
344+ ctx['journal_id'] = self.browse(cr, uid, ids[0], context=context).journal_id.id
345+ return {
346+ 'name': _('Journal Items'),
347+ 'view_type':'form',
348+ 'view_mode':'tree',
349+ 'res_model':'account.move.line',
350+ 'view_id':False,
351+ 'type':'ir.actions.act_window',
352+ 'domain':[('statement_id','in',ids)],
353+ 'context':ctx,
354+ }
355+
356+ def number_of_lines_reconciled(self, cr, uid, id, context=None):
357+ bsl_obj = self.pool.get('account.bank.statement.line')
358+ return bsl_obj.search_count(cr, uid, [('statement_id','=',id), ('journal_entry_id','!=',False)], context=context)
359+
360+ def get_format_currency_js_function(self, cr, uid, id, context=None):
361+ """ Returns a string that can be used to instanciate a javascript function.
362+ That function formats a number according to the statement's journal currency """
363+ company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id
364+ currency_obj = id and self.browse(cr, uid, id, context=context).journal_id.currency or company_currency
365+ digits = 2 # TODO : from currency_obj
366+ if currency_obj.position == 'after':
367+ return "return amount.toFixed("+str(digits)+") + ' "+currency_obj.symbol+"';"
368+ elif currency_obj.position == 'before':
369+ return "return '"+currency_obj.symbol+" ' + amount.toFixed("+str(digits)+");"
370
371 class account_bank_statement_line(osv.osv):
372
373- def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
374- obj_partner = self.pool.get('res.partner')
375- if context is None:
376- context = {}
377- if not partner_id:
378- return {}
379- part = obj_partner.browse(cr, uid, partner_id, context=context)
380- if not part.supplier and not part.customer:
381- type = 'general'
382- elif part.supplier and part.customer:
383- type = 'general'
384- else:
385- if part.supplier == True:
386- type = 'supplier'
387- if part.customer == True:
388- type = 'customer'
389- res_type = self.onchange_type(cr, uid, ids, partner_id=partner_id, type=type, context=context)
390- if res_type['value'] and res_type['value'].get('account_id', False):
391- return {'value': {'type': type, 'account_id': res_type['value']['account_id']}}
392- return {'value': {'type': type}}
393-
394- def onchange_type(self, cr, uid, line_id, partner_id, type, context=None):
395- res = {'value': {}}
396- obj_partner = self.pool.get('res.partner')
397- if context is None:
398- context = {}
399- if not partner_id:
400- return res
401- account_id = False
402- line = self.browse(cr, uid, line_id, context=context)
403- if not line or (line and not line[0].account_id):
404- part = obj_partner.browse(cr, uid, partner_id, context=context)
405- if type == 'supplier':
406- account_id = part.property_account_payable.id
407- else:
408- account_id = part.property_account_receivable.id
409- res['value']['account_id'] = account_id
410- return res
411+ def get_data_for_reconciliations(self, cr, uid, ids, context=None):
412+ """ Used to instanciate a batch of reconciliations in a single request """
413+ # Build a list of reconciliations data
414+ ret = []
415+ mv_line_ids_selected = []
416+ for st_line_id in ids:
417+ reconciliation_data = {
418+ 'st_line': self.get_statement_line_for_reconciliation(cr, uid, st_line_id, context),
419+ 'reconciliation_proposition': self.get_reconciliation_proposition(cr, uid, st_line_id, mv_line_ids_selected, context)
420+ }
421+ for mv_line in reconciliation_data['reconciliation_proposition']:
422+ mv_line_ids_selected.append(mv_line['id'])
423+ ret.append(reconciliation_data);
424+
425+ # Check if, now that 'candidate' move lines were selected, there are moves left for statement lines
426+ for reconciliation_data in ret:
427+ if not reconciliation_data['st_line']['has_no_partner']:
428+ if self.get_move_lines_counterparts(cr, uid, reconciliation_data['st_line']['id'], excluded_ids=mv_line_ids_selected, count=True, context=context) == 0:
429+ reconciliation_data['st_line']['no_match'] = True
430+ return ret
431+
432+ def get_statement_line_for_reconciliation(self, cr, uid, id, context=None):
433+ """ Returns the data required by the bank statement reconciliation use case """
434+ line = self.browse(cr, uid, id, context=context)
435+ statement_currency = line.journal_id.currency or line.journal_id.company_id.currency_id
436+ rml_parser = report_sxw.rml_parse(cr, uid, 'statement_line_widget', context=context)
437+ amount_str = line.amount > 0 and line.amount or -line.amount
438+ amount_str = rml_parser.formatLang(amount_str, currency_obj=statement_currency)
439+ amount_currency_str = ""
440+ if line.amount_currency and line.currency_id:
441+ amount_currency_str = rml_parser.formatLang(line.amount_currency, currency_obj=line.currency_id)
442+
443+ dict = {
444+ 'id': line.id,
445+ 'ref': line.ref,
446+ 'note': line.note or "",
447+ 'name': line.name,
448+ 'date': line.date,
449+ 'amount': line.amount,
450+ 'amount_str': amount_str,
451+ 'no_match': self.get_move_lines_counterparts(cr, uid, id, count=True, context=context) == 0 and line.partner_id.id,
452+ 'partner_id': line.partner_id.id,
453+ 'statement_id': line.statement_id.id,
454+ 'account_code': line.journal_id.default_debit_account_id.code,
455+ 'account_name': line.journal_id.default_debit_account_id.name,
456+ 'partner_name': line.partner_id.name,
457+ 'amount_currency_str': amount_currency_str,
458+ 'has_no_partner': not line.partner_id.id,
459+ }
460+ if line.partner_id.id:
461+ if line.amount > 0:
462+ dict['open_balance_account_id'] = line.partner_id.property_account_receivable.id
463+ else:
464+ dict['open_balance_account_id'] = line.partner_id.property_account_payable.id
465+ return dict
466+
467+ def get_reconciliation_proposition(self, cr, uid, id, excluded_ids=[], context=None):
468+ """ Returns move lines that constitute the best guess to reconcile a statement line. """
469+ st_line = self.browse(cr, uid, id, context=context)
470+ company_currency = st_line.journal_id.company_id.currency_id.id
471+ statement_currency = st_line.journal_id.currency.id or company_currency
472+
473+ # either use the unsigned debit/credit fields or the signed amount_currency field
474+ sign = 1
475+ if statement_currency == company_currency:
476+ if st_line.amount > 0:
477+ amount_field = 'debit'
478+ else:
479+ amount_field = 'credit'
480+ else:
481+ amount_field = 'amount_currency'
482+ if st_line.amount < 0:
483+ sign = -1
484+
485+ # look for exact match
486+ exact_match_id = self.get_move_lines_counterparts(cr, uid, id, excluded_ids=excluded_ids, limit=1, additional_domain=[(amount_field,'=',(sign*st_line.amount))])
487+ if exact_match_id:
488+ return exact_match_id
489+
490+ # select oldest move lines
491+ if sign == -1:
492+ mv_lines = self.get_move_lines_counterparts(cr, uid, id, excluded_ids=excluded_ids, limit=50, additional_domain=[(amount_field,'<',0)])
493+ else:
494+ mv_lines = self.get_move_lines_counterparts(cr, uid, id, excluded_ids=excluded_ids, limit=50, additional_domain=[(amount_field,'>',0)])
495+ ret = []
496+ total = 0
497+ # get_move_lines_counterparts inverts debit and credit
498+ amount_field = 'debit' if amount_field == 'credit' else 'credit'
499+ for line in mv_lines:
500+ if total + line[amount_field] <= st_line.amount:
501+ ret.append(line)
502+ total += line[amount_field]
503+ else:
504+ break
505+
506+ return ret
507+
508+ def get_move_lines_counterparts(self, cr, uid, id, excluded_ids=[], str="", offset=0, limit=None, count=False, additional_domain=[], context=None):
509+ """ Find the move lines that could be used to reconcile a statement line and returns the counterpart that could be created to reconcile them
510+ If count is true, only returns the count.
511+
512+ :param integer id: the id of the statement line
513+ :param integers list excluded_ids: ids of move lines that should not be fetched
514+ :param string str: string to filter lines
515+ :param integer offset: offset of the request
516+ :param integer limit: number of lines to fetch
517+ :param boolean count: just return the number of records
518+ :param tuples list domain: additional domain restrictions
519+ """
520+ if context is None:
521+ context = {}
522+
523+ rml_parser = report_sxw.rml_parse(cr, uid, 'statement_line_counterpart_widget', context=context)
524+ st_line = self.browse(cr, uid, id, context=context)
525+ company_currency = st_line.journal_id.company_id.currency_id
526+ statement_currency = st_line.journal_id.currency or company_currency
527+ mv_line_pool = self.pool.get('account.move.line')
528+ currency_obj = self.pool.get('res.currency')
529+
530+ domain = additional_domain + [
531+ ('partner_id', '=', st_line.partner_id.id),
532+ ('reconcile_id', '=', False),
533+ ('state','=','valid'),
534+ '|',('account_id.type', '=', 'receivable'),
535+ ('account_id.type', '=', 'payable'), #Let the front-end warn the user if he tries to mix payable and receivable in the same reconciliation
536+ ]
537+ if excluded_ids:
538+ domain.append(('id', 'not in', excluded_ids))
539+ if str:
540+ domain += ['|', ('move_id.name', 'ilike', str), ('move_id.ref', 'ilike', str)]
541+ #partially reconciled lines can be displayed only once
542+ reconcile_partial_ids = []
543+ ids = mv_line_pool.search(cr, uid, domain, offset=offset, limit=limit, order="date_maturity asc, id asc", context=context)
544+
545+ if count:
546+ nb_lines = 0
547+ for line in mv_line_pool.browse(cr, uid, ids, context=context):
548+ if line.reconcile_partial_id and line.reconcile_partial_id.id in reconcile_partial_ids:
549+ continue
550+ nb_lines += 1
551+ if line.reconcile_partial_id:
552+ reconcile_partial_ids.append(line.reconcile_partial_id.id)
553+ return nb_lines
554+ else:
555+ ret = []
556+ for line in mv_line_pool.browse(cr, uid, ids, context=context):
557+ if line.reconcile_partial_id and line.reconcile_partial_id.id in reconcile_partial_ids:
558+ continue
559+ amount_currency_str = ""
560+ if line.currency_id and line.amount_currency:
561+ amount_currency_str = rml_parser.formatLang(line.amount_currency, currency_obj=line.currency_id)
562+ ret_line = {
563+ 'id': line.id,
564+ 'name': line.move_id.name,
565+ 'ref': line.move_id.ref,
566+ 'account_code': line.account_id.code,
567+ 'account_name': line.account_id.name,
568+ 'account_type': line.account_id.type,
569+ 'date_maturity': line.date_maturity,
570+ 'date': line.date,
571+ 'period_name': line.period_id.name,
572+ 'journal_name': line.journal_id.name,
573+ 'amount_currency_str': amount_currency_str,
574+ }
575+ if statement_currency.id != company_currency.id and line.currency_id and line.currency_id.id == statement_currency.id:
576+ if line.amount_residual_currency < 0:
577+ ret_line['debit'] = 0
578+ ret_line['credit'] = -line.amount_residual_currency
579+ else:
580+ ret_line['debit'] = line.amount_residual_currency if line.credit != 0 else 0
581+ ret_line['credit'] = line.amount_residual_currency if line.debit != 0 else 0
582+ ret_line['amount_currency_str'] = rml_parser.formatLang(line.amount_residual, currency_obj=company_currency)
583+ else:
584+ if line.amount_residual < 0:
585+ ret_line['debit'] = 0
586+ ret_line['credit'] = -line.amount_residual
587+ else:
588+ ret_line['debit'] = line.amount_residual if line.credit != 0 else 0
589+ ret_line['credit'] = line.amount_residual if line.debit != 0 else 0
590+ ctx = context.copy()
591+ ctx.update({'date': st_line.date})
592+ ret_line['debit'] = currency_obj.compute(cr, uid, statement_currency.id, company_currency.id, ret_line['debit'], context=ctx)
593+ ret_line['credit'] = currency_obj.compute(cr, uid, statement_currency.id, company_currency.id, ret_line['credit'], context=ctx)
594+ ret_line['debit_str'] = rml_parser.formatLang(ret_line['debit'], currency_obj=statement_currency)
595+ ret_line['credit_str'] = rml_parser.formatLang(ret_line['credit'], currency_obj=statement_currency)
596+ ret.append(ret_line)
597+ if line.reconcile_partial_id:
598+ reconcile_partial_ids.append(line.reconcile_partial_id.id)
599+ return ret
600+
601+ def process_reconciliation(self, cr, uid, id, mv_line_dicts, context=None):
602+ """ Creates a move line for each item of mv_line_dicts and for the statement line. Reconcile a new move line with its counterpart_move_line_id if specified. Finally, mark the statement line as reconciled by putting the newly created move id in the column journal_entry_id.
603+
604+ :param int id: id of the bank statement line
605+ :param list of dicts mv_line_dicts: move lines to create. If counterpart_move_line_id is specified, reconcile with it
606+ """
607+ st_line = self.browse(cr, uid, id, context=context)
608+ company_currency = st_line.journal_id.company_id.currency_id
609+ statement_currency = st_line.journal_id.currency or company_currency
610+ bs_obj = self.pool.get('account.bank.statement')
611+ am_obj = self.pool.get('account.move')
612+ aml_obj = self.pool.get('account.move.line')
613+ currency_obj = self.pool.get('res.currency')
614+
615+ # Checks
616+ if st_line.journal_entry_id.id != False:
617+ raise osv.except_osv(_('Error!'), _('The bank statement line was already reconciled.'))
618+ for mv_line_dict in mv_line_dicts:
619+ for field in ['debit', 'credit', 'amount_currency']:
620+ if field not in mv_line_dict:
621+ mv_line_dict[field] = 0.0
622+ if mv_line_dict.get('counterpart_move_line_id'):
623+ mv_line = aml_obj.browse(cr, uid, mv_line_dict.get('counterpart_move_line_id'), context=context)
624+ if mv_line.reconcile_id:
625+ raise osv.except_osv(_('Error!'), _('A selected move line was already reconciled.'))
626+
627+ # Create the move
628+ move_name = st_line.statement_id.name + "/" + str(st_line.sequence)
629+ move_vals = bs_obj._prepare_move(cr, uid, st_line, move_name, context=context)
630+ move_id = am_obj.create(cr, uid, move_vals, context=context)
631+
632+ # Create the move line for the statement line
633+ amount = currency_obj.compute(cr, uid, st_line.statement_id.currency.id, company_currency.id, st_line.amount, context=context)
634+ bank_st_move_vals = bs_obj._prepare_bank_move_line(cr, uid, st_line, move_id, amount, company_currency.id, context=context)
635+ aml_obj.create(cr, uid, bank_st_move_vals, context=context)
636+ st_line_currency_rate = bank_st_move_vals['amount_currency'] and statement_currency.id == company_currency.id and (bank_st_move_vals['amount_currency'] / st_line.amount) or False
637+ st_line_currency = bank_st_move_vals['currency_id']
638+ # Complete the dicts
639+ st_line_statement_id = st_line.statement_id.id
640+ st_line_journal_id = st_line.journal_id.id
641+ st_line_partner_id = st_line.partner_id.id
642+ st_line_company_id = st_line.company_id.id
643+ st_line_period_id = st_line.statement_id.period_id.id
644+ for mv_line_dict in mv_line_dicts:
645+ mv_line_dict['ref'] = move_name
646+ mv_line_dict['move_id'] = move_id
647+ mv_line_dict['period_id'] = st_line_period_id
648+ mv_line_dict['journal_id'] = st_line_journal_id
649+ mv_line_dict['partner_id'] = st_line_partner_id
650+ mv_line_dict['company_id'] = st_line_company_id
651+ mv_line_dict['statement_id'] = st_line_statement_id
652+ if mv_line_dict.get('counterpart_move_line_id'):
653+ mv_line = aml_obj.browse(cr, uid, mv_line_dict['counterpart_move_line_id'], context=context)
654+ mv_line_dict['account_id'] = mv_line.account_id.id
655+ if statement_currency.id != company_currency.id:
656+ mv_line_dict['amount_currency'] = mv_line_dict['debit'] - mv_line_dict['credit']
657+ mv_line_dict['currency_id'] = statement_currency.id
658+ mv_line_dict['debit'] = currency_obj.compute(cr, uid, statement_currency.id, company_currency.id, mv_line_dict['debit'])
659+ mv_line_dict['credit'] = currency_obj.compute(cr, uid, statement_currency.id, company_currency.id, mv_line_dict['credit'])
660+ elif st_line_currency and st_line_currency_rate:
661+ mv_line_dict['amount_currency'] = self.pool.get('res.currency').round(cr, uid, st_line.currency_id, (mv_line_dict['debit'] - mv_line_dict['credit']) * st_line_currency_rate)
662+ mv_line_dict['currency_id'] = st_line_currency
663+
664+ # Create move lines
665+ move_line_pairs_to_reconcile = []
666+ for mv_line_dict in mv_line_dicts:
667+ counterpart_move_line_id = None # NB : this attribute is irrelevant for aml_obj.create() and needs to be removed from the dict
668+ if mv_line_dict.get('counterpart_move_line_id'):
669+ counterpart_move_line_id = mv_line_dict['counterpart_move_line_id']
670+ del mv_line_dict['counterpart_move_line_id']
671+ new_aml_id = aml_obj.create(cr, uid, mv_line_dict, context=context)
672+ if counterpart_move_line_id != None:
673+ move_line_pairs_to_reconcile.append([new_aml_id, counterpart_move_line_id])
674+
675+ # Reconcile
676+ for pair in move_line_pairs_to_reconcile:
677+ # TODO : too slow
678+ aml_obj.reconcile_partial(cr, uid, pair, context=context)
679+
680+ # Mark the statement line as reconciled
681+ self.write(cr, uid, id, {'journal_entry_id': move_id}, context=context)
682+
683+ # FIXME : if it wasn't for the multicompany security settings in account_security.xml, the method would just
684+ # return [('journal_entry_id', '=', False)]
685+ # Unfortunately, that spawns a "no access rights" error ; it shouldn't.
686+ def _needaction_domain_get(self, cr, uid, context=None):
687+ user = self.pool.get("res.users").browse(cr, uid, uid)
688+ return ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id]),('journal_entry_id', '=', False)]
689
690 _order = "statement_id desc, sequence"
691 _name = "account.bank.statement.line"
692 _description = "Bank Statement Line"
693+ _inherit = ['ir.needaction_mixin']
694 _columns = {
695 'name': fields.char('Description', required=True),
696 'date': fields.date('Date', required=True),
697 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),
698- 'type': fields.selection([
699- ('supplier','Supplier'),
700- ('customer','Customer'),
701- ('general','General')
702- ], 'Type', required=True),
703 'partner_id': fields.many2one('res.partner', 'Partner'),
704- 'account_id': fields.many2one('account.account','Account',
705- required=True),
706- 'statement_id': fields.many2one('account.bank.statement', 'Statement',
707- select=True, required=True, ondelete='cascade'),
708+ 'bank_account_id': fields.many2one('res.partner.bank','Bank Account'),
709+ 'statement_id': fields.many2one('account.bank.statement', 'Statement', select=True, required=True, ondelete='cascade'),
710 'journal_id': fields.related('statement_id', 'journal_id', type='many2one', relation='account.journal', string='Journal', store=True, readonly=True),
711- 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account'),
712- 'move_ids': fields.many2many('account.move',
713- 'account_bank_statement_line_move_rel', 'statement_line_id','move_id',
714- 'Moves'),
715 'ref': fields.char('Reference', size=32),
716 'note': fields.text('Notes'),
717 'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of bank statement lines."),
718 'company_id': fields.related('statement_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
719+ 'journal_entry_id': fields.many2one('account.move', 'Journal Entry'),
720+ 'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optional other currency if it is a multi-currency entry.", digits_compute=dp.get_precision('Account')),
721+ 'currency_id': fields.many2one('res.currency', 'Currency', help="The optional other currency if it is a multi-currency entry."),
722 }
723 _defaults = {
724 'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement.line'),
725 'date': lambda self,cr,uid,context={}: context.get('date', fields.date.context_today(self,cr,uid,context=context)),
726- 'type': 'general',
727 }
728
729+class account_statement_operation_template(osv.osv):
730+ _name = "account.statement.operation.template"
731+ _description = "Preset for the lines that can be created in a bank statement reconciliation"
732+ _columns = {
733+ 'name': fields.char('Button Label', required=True),
734+ 'account_id': fields.many2one('account.account', 'Account', ondelete='cascade', domain=[('type','!=','view')]),
735+ 'label': fields.char('Label'),
736+ 'amount_type': fields.selection([('fixed', 'Fixed'),('percentage_of_total','Percentage of total amount'),('percentage_of_balance', 'Percentage of open balance')],
737+ 'Amount type', required=True),
738+ 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account'), help="Leave to 0 to ignore."),
739+ 'tax_id': fields.many2one('account.tax', 'Tax', ondelete='cascade'),
740+ 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account', ondelete='cascade'),
741+ }
742+ _defaults = {
743+ 'amount_type': 'fixed',
744+ 'amount': 0.0
745+ }
746
747 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
748
749=== modified file 'account/account_invoice.py'
750--- account/account_invoice.py 2014-05-07 17:01:12 +0000
751+++ account/account_invoice.py 2014-05-30 16:18:57 +0000
752@@ -216,7 +216,7 @@
753 _name = "account.invoice"
754 _inherit = ['mail.thread']
755 _description = 'Invoice'
756- _order = "id desc"
757+ _order = "number desc, id desc"
758 _track = {
759 'type': {
760 },
761
762=== modified file 'account/account_move_line.py'
763--- account/account_move_line.py 2014-05-07 17:01:12 +0000
764+++ account/account_move_line.py 2014-05-30 16:18:57 +0000
765@@ -430,7 +430,7 @@
766 elif line.reconcile_partial_id:
767 res[line.id] = str(line.reconcile_partial_id.name)
768 return res
769-
770+
771 def _get_move_from_reconcile(self, cr, uid, ids, context=None):
772 move = {}
773 for r in self.pool.get('account.move.reconcile').browse(cr, uid, ids, context=context):
774@@ -491,7 +491,7 @@
775 type='many2one', relation='account.invoice', fnct_search=_invoice_search),
776 'account_tax_id':fields.many2one('account.tax', 'Tax'),
777 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account'),
778- 'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company',
779+ 'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company',
780 string='Company', store=True, readonly=True)
781 }
782
783@@ -765,7 +765,7 @@
784 WHERE debit > 0 AND credit > 0 AND (last_reconciliation_date IS NULL OR max_date > last_reconciliation_date)
785 ORDER BY last_reconciliation_date""")
786 ids = [x[0] for x in cr.fetchall()]
787- if not ids:
788+ if not ids:
789 return []
790
791 # To apply the ir_rules
792@@ -793,9 +793,11 @@
793 else:
794 currency_id = line.company_id.currency_id
795 if line.reconcile_id:
796- raise osv.except_osv(_('Warning'), _("Journal Item '%s' (id: %s), Move '%s' is already reconciled!") % (line.name, line.id, line.move_id.name))
797+ raise osv.except_osv(_('Warning'), _("Journal Item '%s' (id: %s), Move '%s' is already reconciled!") % (line.name, line.id, line.move_id.name))
798 if line.reconcile_partial_id:
799 for line2 in line.reconcile_partial_id.line_partial_ids:
800+ if line2.state != 'valid':
801+ raise osv.except_osv(_('Warning'), _("Journal Item '%s' (id: %s) cannot be used in a reconciliation as it is not balanced!") % (line2.name, line2.id))
802 if not line2.reconcile_id:
803 if line2.id not in merges:
804 merges.append(line2.id)
805@@ -1119,7 +1121,7 @@
806 period = period_obj.browse(cr, uid, period_id, context=context)
807 for (state,) in result:
808 if state == 'done':
809- raise osv.except_osv(_('Error!'), _('You can not add/modify entries in a closed period %s of journal %s.' % (period.name,journal.name)))
810+ raise osv.except_osv(_('Error!'), _('You can not add/modify entries in a closed period %s of journal %s.' % (period.name,journal.name)))
811 if not result:
812 jour_period_obj.create(cr, uid, {
813 'name': (journal.code or journal.name)+':'+(period.name or ''),
814
815=== modified file 'account/account_unit_test.xml'
816--- account/account_unit_test.xml 2013-11-13 13:01:07 +0000
817+++ account/account_unit_test.xml 2014-05-30 16:18:57 +0000
818@@ -6,10 +6,10 @@
819 <field name="currency_id" ref="base.EUR"/>
820 <field name="company_id" ref="base.main_company"/>
821 <field name="partner_id" ref="base.res_partner_1"/>
822- <field name="journal_id" ref="account.sales_journal"/>
823+ <field name="journal_id" ref="account.expenses_journal"/>
824 <field name="state">draft</field>
825 <field name="type">in_invoice</field>
826- <field name="account_id" ref="account.a_recv"/>
827+ <field name="account_id" ref="account.a_pay"/>
828 <field name="name">Test invoice 1</field>
829 </record>
830 <record id="test_tax_line" model="account.invoice.tax">
831
832=== modified file 'account/account_view.xml'
833--- account/account_view.xml 2014-05-02 13:07:53 +0000
834+++ account/account_view.xml 2014-05-30 16:18:57 +0000
835@@ -489,6 +489,13 @@
836 src_model="account.journal"/>
837
838 <!-- Bank statement -->
839+
840+ <record id="action_bank_reconcile_bank_statements" model="ir.actions.client">
841+ <field name="name">Reconciliation on Bank Statements</field>
842+ <field name="tag">bank_statement_reconciliation_view</field>
843+ <field name="context">{'statement_id': active_id}</field>
844+ </record>
845+
846 <record id="view_account_bank_statement_filter" model="ir.ui.view">
847 <field name="name">account.cash.statement.select</field>
848 <field name="model">account.bank.statement</field>
849@@ -525,6 +532,7 @@
850 </tree>
851 </field>
852 </record>
853+
854 <record id="view_bank_statement_search" model="ir.ui.view">
855 <field name="name">account.bank.statement.search</field>
856 <field name="model">account.bank.statement</field>
857@@ -544,6 +552,7 @@
858 </search>
859 </field>
860 </record>
861+
862 <record id="view_bank_statement_form" model="ir.ui.view">
863 <field name="name">account.bank.statement.form</field>
864 <field name="model">account.bank.statement</field>
865@@ -551,14 +560,21 @@
866 <field name="arch" type="xml">
867 <form string="Bank Statement" version="7.0">
868 <header>
869- <button name="button_confirm_bank" states="draft" string="Confirm" type="object" class="oe_highlight"/>
870- <button name="button_dummy" states="draft" string="Compute" type="object" class="oe_highlight"/>
871+ <field name="all_lines_reconciled" invisible="1" />
872+ <span attrs="{'invisible':['|',('all_lines_reconciled','=',True),('line_ids','=',[])]}">
873+ <button name="%(action_bank_reconcile_bank_statements)d" states="draft" string="Reconcile" type="action" class="oe_highlight"/>
874+ </span>
875+ <span attrs="{'invisible':[('all_lines_reconciled','=',False)]}">
876+ <button name="button_confirm_bank" states="draft" string="Close" type="object" class="oe_highlight"/>
877+ </span>
878 <button name="button_cancel" states="confirm" string="Cancel Statement" type="object"/>
879 <field name="state" widget="statusbar" statusbar_visible="draft,confirm"/>
880 </header>
881 <sheet>
882 <div class="oe_right oe_button_box" name="import_buttons">
883- <!-- Put here related buttons -->
884+ <button class="oe_inline oe_stat_button" name="%(action_view_account_statement_from_invoice_lines)d"
885+ string="Import Invoice" type="action"
886+ attrs="{'invisible':[('state','=','confirm')]}" widget="statinfo" icon="fa-pencil-square-o"/>
887 </div>
888 <label for="name" class="oe_edit_only"/>
889 <h1><field name="name"/></h1>
890@@ -581,41 +597,30 @@
891 <notebook>
892 <page string="Transactions" name="statement_line_ids">
893 <field name="line_ids" context="{'date':date}">
894- <tree editable="bottom" string="Statement lines">
895+ <tree editable="bottom" string="Statement lines" colors="grey:journal_entry_id!=False">
896 <field name="sequence" readonly="1" invisible="1"/>
897- <field name="date"/>
898- <field name="name"/>
899- <field name="ref"/>
900- <field name="partner_id" on_change="onchange_partner_id(partner_id)" domain="[
901+ <field name="journal_entry_id" invisible="1"/>
902+ <field name="date" attrs="{'readonly' : [('journal_entry_id', '!=', False)] }"/>
903+ <field name="name" attrs="{'readonly' : [('journal_entry_id', '!=', False)] }"/>
904+ <field name="ref" attrs="{'readonly' : [('journal_entry_id', '!=', False)] }"/>
905+ <field name="partner_id" domain="[
906 '&amp;',
907 '|',('parent_id','=',False),('is_company','=',True),
908- '|',('customer','=',True),('supplier','=',True)]" context="{'default_supplier': 1}"/>
909- <field name="type" on_change="onchange_type(partner_id, type)"/>
910- <field name="account_id" options='{"no_open":True}' domain="[('journal_id','=',parent.journal_id), ('company_id', '=', parent.company_id)]"/>
911- <field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '&lt;&gt;', 'view')]"/>
912- <field name="amount"/>
913+ '|',('customer','=',True),('supplier','=',True)]"
914+ context="{'default_supplier': 1}"
915+ attrs="{'readonly' : [('journal_entry_id', '!=', False)] }"/>
916+ <field name="amount" attrs="{'readonly' : [('journal_entry_id', '!=', False)] }"/>
917+ <field name="amount_currency" groups="base.group_multi_currency" attrs="{'readonly' : [('journal_entry_id', '!=', False)] }"/>
918+ <field name="currency_id" groups="base.group_multi_currency" attrs="{'readonly' : [('journal_entry_id', '!=', False)] }"/>
919+ <field name="bank_account_id" groups="base.group_no_one"/>
920 </tree>
921- <form string="Statement lines" version="7.0">
922- <group col="4">
923- <field name="date"/>
924- <field name="name"/>
925- <field name="ref"/>
926- <field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
927- <field name="type" on_change="onchange_type(partner_id, type)"/>
928- <field name="account_id" domain="[('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view'), ('company_id', '=', parent.company_id)]"/>
929- <field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('company_id', '=', parent.company_id), ('type', '&lt;&gt;', 'view')]"/>
930- <field name="amount"/>
931- <field name="sequence" readonly="0"/>
932- </group>
933- <separator string="Notes"/>
934- <field name="note"/>
935- </form>
936 </field>
937 </page>
938 </notebook>
939 <group class="oe_subtotal_footer oe_right" colspan="2" name="sale_total">
940 <div class="oe_subtotal_footer_separator oe_inline">
941 <label for="balance_end" />
942+ <button name="button_dummy" states="draft" string="(update)" type="object" class="oe_edit_only oe_link"/>
943 </div>
944 <field name="balance_end" nolabel="1" class="oe_subtotal_footer_separator" widget='monetary' options="{'currency_field': 'currency_id'}"/>
945 </group>
946@@ -682,6 +687,85 @@
947 <field name="domain">[('state','=','draft')]</field>
948 <field name="filter" eval="True"/>
949 </record>
950+
951+ <record id="action_bank_reconcile" model="ir.actions.client">
952+ <field name="name">Reconciliation on Bank Statements</field>
953+ <field name="res_model">account.bank.statement.line</field>
954+ <field name="tag">bank_statement_reconciliation_view</field>
955+ </record>
956+
957+ <!-- because of the needaction badge, groups needs to be specified -->
958+ <menuitem id="menu_bank_reconcile_bank_statements" name="Reconciliation on Bank Statements" parent="account.periodical_processing_reconciliation" groups="group_account_user" action="action_bank_reconcile" sequence="20"/>
959+
960+ <record id="view_account_statement_operation_template_form" model="ir.ui.view">
961+ <field name="name">account.statement.operation.template.form</field>
962+ <field name="model">account.statement.operation.template</field>
963+ <field name="arch" type="xml">
964+ <form string="Statement Operation Templates" version="7.0">
965+ <sheet>
966+ <div class="oe_title">
967+ <label for="name" class="oe_edit_only"/>
968+ <h1>
969+ <field name="name"/>
970+ </h1>
971+ </div>
972+ <group>
973+ <group>
974+ <field name="account_id"/>
975+ <field name="amount_type"/>
976+ <field name="tax_id"/>
977+ </group>
978+ <group>
979+ <field name="label"/>
980+ <label for="amount"/>
981+ <div>
982+ <field name="amount" class="oe_inline" />
983+ <label string="%" class="oe_inline" attrs="{'invisible':[('amount_type','not in',('percentage_of_total', 'percentage_of_balance'))]}" />
984+ </div>
985+ <field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
986+ </group>
987+ </group>
988+ </sheet>
989+ </form>
990+ </field>
991+ </record>
992+ <record id="view_account_statement_operation_template_tree" model="ir.ui.view">
993+ <field name="name">account.statement.operation.template.tree</field>
994+ <field name="model">account.statement.operation.template</field>
995+ <field name="arch" type="xml">
996+ <tree string="Bank Reconciliation Move Presets">
997+ <field name="name"/>
998+ <field name="account_id"/>
999+ <field name="amount_type"/>
1000+ </tree>
1001+ </field>
1002+ </record>
1003+ <record id="view_account_statement_operation_template_search" model="ir.ui.view">
1004+ <field name="name">account.statement.operation.template.search</field>
1005+ <field name="model">account.statement.operation.template</field>
1006+ <field name="arch" type="xml">
1007+ <search string="Bank Reconciliation Move preset">
1008+ <filter string="With tax" domain="[('tax_id','!=',False)]"/>
1009+ <field name="amount_type"/>
1010+ </search>
1011+ </field>
1012+ </record>
1013+ <record id="action_account_statement_operation_template" model="ir.actions.act_window">
1014+ <field name="name">Statement Operation Templates</field>
1015+ <field name="res_model">account.statement.operation.template</field>
1016+ <field name="view_type">form</field>
1017+ <field name="view_mode">tree,form</field>
1018+ <field name="search_view_id" ref="view_account_statement_operation_template_search"/>
1019+ <field name="help" type="html">
1020+ <p class="oe_view_nocontent_create">
1021+ Click to create a statement operation template.
1022+ </p><p>
1023+ Those can be used to quickly create a move line when reconciling
1024+ your bank statements.
1025+ </p>
1026+ </field>
1027+ </record>
1028+ <menuitem action="action_account_statement_operation_template" id="menu_action_account_statement_operation_template" parent="menu_configuration_misc" name="Statement Operation Templates" sequence="22"/>
1029
1030 <!-- Account Types -->
1031 <record id="view_account_type_search" model="ir.ui.view">
1032@@ -1603,11 +1687,11 @@
1033 <form string="Payment Term" version="7.0">
1034 <group>
1035 <group string="Amount Computation">
1036- <field name="value"/>
1037- <label for="value_amount" string="Amount To Pay" attrs="{'invisible':[('value','=','balance')]}"/>
1038- <div attrs="{'invisible':[('value','=','balance')]}">
1039- <field name="value_amount" class="oe_inline"/>
1040- </div>
1041+ <field name="value"/>
1042+ <label for="value_amount" string="Amount To Pay" attrs="{'invisible':[('value','=','balance')]}"/>
1043+ <div attrs="{'invisible':[('value','=','balance')]}">
1044+ <field name="value_amount" class="oe_inline"/>
1045+ </div>
1046 </group>
1047 <group string="Due Date Computation">
1048 <field name="days"/>
1049@@ -2259,7 +2343,13 @@
1050 <field name="arch" type="xml">
1051 <form string="Statement" version="7.0">
1052 <header>
1053- <button name="button_confirm_cash" states="open" string="Close CashBox" type="object" class="oe_highlight"/>
1054+ <field name="all_lines_reconciled" invisible="1" />
1055+ <span attrs="{'invisible':['|',('all_lines_reconciled','=',True),('line_ids','=',[])]}">
1056+ <button name="%(action_bank_reconcile_bank_statements)d" states="open" string="Reconcile" type="action" class="oe_highlight"/>
1057+ </span>
1058+ <span attrs="{'invisible':[('all_lines_reconciled','=',False)]}">
1059+ <button name="button_confirm_cash" states="open" string="Close CashBox" type="object" class="oe_highlight"/>
1060+ </span>
1061 <button name="button_open" states="draft" string="Open CashBox" type="object" class="oe_highlight"/>
1062 <button name="button_cancel" states="confirm,open" string="Cancel CashBox" type="object"/>
1063 <field name="state" widget="statusbar" nolabel="1" statusbar_visible="draft,confirm"/>
1064@@ -2289,10 +2379,7 @@
1065 <field name="date"/>
1066 <field name="name"/>
1067 <field name="ref"/>
1068- <field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
1069- <field name="type" on_change="onchange_type(partner_id, type)"/>
1070- <field domain="[('journal_id','=',parent.journal_id), ('company_id', '=', parent.company_id)]" name="account_id"/>
1071- <field name="analytic_account_id" domain="[('company_id', '=', parent.company_id), ('type', '&lt;&gt;', 'view')]" groups="analytic.group_analytic_accounting" />
1072+ <field name="partner_id"/>
1073 <field name="amount"/>
1074 </tree>
1075 <form string="Statement lines" version="7.0">
1076@@ -2300,10 +2387,7 @@
1077 <field name="date"/>
1078 <field name="name"/>
1079 <field name="ref"/>
1080- <field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
1081- <field name="type" on_change="onchange_type(partner_id, type)"/>
1082- <field domain="[('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view'), ('company_id', '=', parent.company_id)]" name="account_id"/>
1083- <field name="analytic_account_id" domain="[('company_id', '=', parent.company_id), ('type', '&lt;&gt;', 'view')]" groups="analytic.group_analytic_accounting" />
1084+ <field name="partner_id"/>
1085 <field name="amount"/>
1086 <field name="sequence"/>
1087 </group>
1088
1089=== added file 'account/demo/account_bank_statement.xml'
1090--- account/demo/account_bank_statement.xml 1970-01-01 00:00:00 +0000
1091+++ account/demo/account_bank_statement.xml 2014-05-30 16:18:57 +0000
1092@@ -0,0 +1,85 @@
1093+<?xml version="1.0" encoding="utf-8"?>
1094+<openerp>
1095+ <data>
1096+ <!-- A bank statement -->
1097+ <record id="demo_bank_statement_1" model="account.bank.statement">
1098+ <field name="journal_id" ref="account.bank_journal"/>
1099+ <field name="period_id" ref="account.period_5"/>
1100+ <field name="date" eval="time.strftime('%Y')+'-01-01'"/>
1101+ <field name="user_id" ref="base.user_demo"/>
1102+ <field name="reference_type">none</field>
1103+ <field name="name">BNK/2014/001</field>
1104+ <field name="balance_end" eval="2040.0"/>
1105+ <field name="company_id" ref="base.main_company"/>
1106+ <field name="state">draft</field>
1107+ <field name="balance_start" eval="0.0"/>
1108+ <field name="balance_end_real" eval="3707.58"/>
1109+ </record>
1110+ <record id="demo_bank_statement_line_1" model="account.bank.statement.line">
1111+ <field name="ref">001</field>
1112+ <field name="statement_id" ref="demo_bank_statement_1"/>
1113+ <field name="sequence" eval="1"/>
1114+ <field name="company_id" ref="base.main_company"/>
1115+ <field name="name">First 2000 € of SAJ/2014/001</field>
1116+ <field name="journal_id" ref="account.bank_journal"/>
1117+ <field name="amount" eval="2000.0"/>
1118+ <field name="date" eval="time.strftime('%Y')+'-01-01'"/>
1119+ <field name="partner_id" ref="base.res_partner_9"/>
1120+ </record>
1121+ <record id="demo_bank_statement_line_2" model="account.bank.statement.line">
1122+ <field name="ref">002</field>
1123+ <field name="statement_id" ref="demo_bank_statement_1"/>
1124+ <field name="sequence" eval="2"/>
1125+ <field name="company_id" ref="base.main_company"/>
1126+ <field name="name">SAJ/2014/002</field>
1127+ <field name="journal_id" ref="account.bank_journal"/>
1128+ <field name="amount" eval="650.0"/>
1129+ <field name="date" eval="time.strftime('%Y')+'-01-01'"/>
1130+ <field name="partner_id" ref="base.res_partner_9"/>
1131+ </record>
1132+ <record id="demo_bank_statement_line_3" model="account.bank.statement.line">
1133+ <field name="ref">003</field>
1134+ <field name="statement_id" ref="demo_bank_statement_1"/>
1135+ <field name="sequence" eval="3"/>
1136+ <field name="company_id" ref="base.main_company"/>
1137+ <field name="name">Bank fees</field>
1138+ <field name="journal_id" ref="account.bank_journal"/>
1139+ <field name="amount" eval="32.58"/>
1140+ <field name="date" eval="time.strftime('%Y')+'-01-01'"/>
1141+ </record>
1142+ <record id="demo_bank_statement_line_4" model="account.bank.statement.line">
1143+ <field name="ref">004</field>
1144+ <field name="statement_id" ref="demo_bank_statement_1"/>
1145+ <field name="sequence" eval="4"/>
1146+ <field name="company_id" ref="base.main_company"/>
1147+ <field name="name">SAJ/2014/003 and SAJ/2014/004</field>
1148+ <field name="journal_id" ref="account.bank_journal"/>
1149+ <field name="amount" eval="1025.0"/>
1150+ <field name="date" eval="time.strftime('%Y')+'-01-01'"/>
1151+ <field name="partner_id" ref="base.res_partner_2"/>
1152+ </record>
1153+
1154+ <!-- Statement operation templates -->
1155+ <record id="statement_operation_template_1" model="account.statement.operation.template">
1156+ <field name="name">Discount For Early Payment</field>
1157+ <field name="account_id" ref="a_expense"></field>
1158+ <field name="label">Discount</field>
1159+ <field name="amount_type">percentage_of_total</field>
1160+ <field name="amount">-7</field>
1161+ </record>
1162+ <record id="statement_operation_template_2" model="account.statement.operation.template">
1163+ <field name="name">Bank Fees</field>
1164+ <field name="account_id" ref="a_expense"></field>
1165+ <field name="label">Bank Fees</field>
1166+ <field name="amount_type">fixed</field>
1167+ <field name="amount"></field>
1168+ </record>
1169+ <record id="statement_operation_template_3" model="account.statement.operation.template">
1170+ <field name="name">Profit / Loss</field>
1171+ <field name="account_id" ref="a_sale"></field>
1172+ <field name="label">Profit / Loss</field>
1173+ <field name="amount_type">fixed</field>
1174+ <field name="amount"></field>
1175+ </record>
1176+ </data>
1177+</openerp>
1178
1179=== modified file 'account/demo/account_invoice_demo.xml'
1180--- account/demo/account_invoice_demo.xml 2012-11-29 22:26:45 +0000
1181+++ account/demo/account_invoice_demo.xml 2014-05-30 16:18:57 +0000
1182@@ -44,5 +44,135 @@
1183 <field name="partner_id" ref="base.res_partner_17"/>
1184 <field name="name">Zed+ Antivirus</field>
1185 </record>
1186+
1187+ <!-- Some customer invoices used to show the reconciliation process on the bank statement -->
1188+ <record id="invoice_1" model="account.invoice">
1189+ <field name="currency_id" ref="base.EUR"/>
1190+ <field name="company_id" ref="base.main_company"/>
1191+ <field name="journal_id" ref="account.sales_journal"/>
1192+ <field name="state">draft</field>
1193+ <field name="type">out_invoice</field>
1194+ <field name="account_id" ref="a_recv"/>
1195+ <field name="partner_id" ref="base.res_partner_9"/>
1196+ </record>
1197+ <record id="invoice_1_line_1" model="account.invoice.line">
1198+ <field name="name">Otpez Laptop without OS</field>
1199+ <field name="invoice_id" ref="invoice_1"/>
1200+ <field name="price_unit">642</field>
1201+ <field name="quantity">5</field>
1202+ <field name="account_id" ref="a_sale"/>
1203+ </record>
1204+ <record id="invoice_1_line_2" model="account.invoice.line">
1205+ <field name="name">Linutop</field>
1206+ <field name="invoice_id" ref="invoice_1"/>
1207+ <field name="price_unit">280</field>
1208+ <field name="quantity">5</field>
1209+ <field name="account_id" ref="a_sale"/>
1210+ </record>
1211+ <workflow action="invoice_open" model="account.invoice" ref="invoice_1"/>
1212+
1213+ <record id="invoice_2" model="account.invoice">
1214+ <field name="currency_id" ref="base.EUR"/>
1215+ <field name="company_id" ref="base.main_company"/>
1216+ <field name="journal_id" ref="account.sales_journal"/>
1217+ <field name="state">draft</field>
1218+ <field name="type">out_invoice</field>
1219+ <field name="account_id" ref="a_recv"/>
1220+ <field name="partner_id" ref="base.res_partner_9"/>
1221+ <field eval="time.strftime('%Y-%m') + '-01'" name="date_invoice"/>
1222+ </record>
1223+ <record id="invoice_2_line_1" model="account.invoice.line">
1224+ <field name="name">8-port Switch</field>
1225+ <field name="invoice_id" ref="invoice_2"/>
1226+ <field name="price_unit">50</field>
1227+ <field name="quantity">3</field>
1228+ <field name="account_id" ref="a_sale"/>
1229+ </record>
1230+ <record id="invoice_2_line_2" model="account.invoice.line">
1231+ <field name="name">30m RJ45 wire</field>
1232+ <field name="invoice_id" ref="invoice_2"/>
1233+ <field name="price_unit">25</field>
1234+ <field name="quantity">20</field>
1235+ <field name="account_id" ref="a_sale"/>
1236+ </record>
1237+ <workflow action="invoice_open" model="account.invoice" ref="invoice_2"/>
1238+
1239+ <record id="invoice_3" model="account.invoice">
1240+ <field name="currency_id" ref="base.EUR"/>
1241+ <field name="company_id" ref="base.main_company"/>
1242+ <field name="journal_id" ref="account.sales_journal"/>
1243+ <field name="state">draft</field>
1244+ <field name="type">out_invoice</field>
1245+ <field name="account_id" ref="a_recv"/>
1246+ <field name="partner_id" ref="base.res_partner_2"/>
1247+ <field eval="time.strftime('%Y-%m') + '-08'" name="date_invoice"/>
1248+ </record>
1249+ <record id="invoice_3_line_1" model="account.invoice.line">
1250+ <field name="name">TypeMatrix Dvorak Keyboard</field>
1251+ <field name="invoice_id" ref="invoice_3"/>
1252+ <field name="price_unit">90</field>
1253+ <field name="quantity">5</field>
1254+ <field name="account_id" ref="a_sale"/>
1255+ </record>
1256+ <record id="invoice_3_line_2" model="account.invoice.line">
1257+ <field name="name">Ergonomic Mouse</field>
1258+ <field name="invoice_id" ref="invoice_3"/>
1259+ <field name="price_unit">15</field>
1260+ <field name="quantity">5</field>
1261+ <field name="account_id" ref="a_sale"/>
1262+ </record>
1263+ <workflow action="invoice_open" model="account.invoice" ref="invoice_3"/>
1264+
1265+ <record id="invoice_4" model="account.invoice">
1266+ <field name="currency_id" ref="base.EUR"/>
1267+ <field name="company_id" ref="base.main_company"/>
1268+ <field name="journal_id" ref="account.sales_journal"/>
1269+ <field name="state">draft</field>
1270+ <field name="type">out_invoice</field>
1271+ <field name="account_id" ref="a_recv"/>
1272+ <field name="partner_id" ref="base.res_partner_2"/>
1273+ <field eval="time.strftime('%Y-%m') + '-15'" name="date_invoice"/>
1274+ </record>
1275+ <record id="invoice_4_line_1" model="account.invoice.line">
1276+ <field name="name">Desktop Computer Table</field>
1277+ <field name="invoice_id" ref="invoice_4"/>
1278+ <field name="price_unit">80</field>
1279+ <field name="quantity">5</field>
1280+ <field name="account_id" ref="a_sale"/>
1281+ </record>
1282+ <record id="invoice_4_line_2" model="account.invoice.line">
1283+ <field name="name">Desktop Lamp</field>
1284+ <field name="invoice_id" ref="invoice_4"/>
1285+ <field name="price_unit">20</field>
1286+ <field name="quantity">5</field>
1287+ <field name="account_id" ref="a_sale"/>
1288+ </record>
1289+ <workflow action="invoice_open" model="account.invoice" ref="invoice_4"/>
1290+
1291+ <record id="invoice_5" model="account.invoice">
1292+ <field name="currency_id" ref="base.EUR"/>
1293+ <field name="company_id" ref="base.main_company"/>
1294+ <field name="journal_id" ref="account.sales_journal"/>
1295+ <field name="state">draft</field>
1296+ <field name="type">out_invoice</field>
1297+ <field name="account_id" ref="a_recv"/>
1298+ <field name="partner_id" ref="base.res_partner_9"/>
1299+ <field eval="time.strftime('%Y-%m') + '-08'" name="date_invoice"/>
1300+ </record>
1301+ <record id="invoice_5_line_1" model="account.invoice.line">
1302+ <field name="name">TypeMatrix Dvorak Keyboard</field>
1303+ <field name="invoice_id" ref="invoice_5"/>
1304+ <field name="price_unit">90</field>
1305+ <field name="quantity">5</field>
1306+ <field name="account_id" ref="a_sale"/>
1307+ </record>
1308+ <record id="invoice_5_line_2" model="account.invoice.line">
1309+ <field name="name">Ergonomic Mouse</field>
1310+ <field name="invoice_id" ref="invoice_5"/>
1311+ <field name="price_unit">15</field>
1312+ <field name="quantity">5</field>
1313+ <field name="account_id" ref="a_sale"/>
1314+ </record>
1315+ <workflow action="invoice_open" model="account.invoice" ref="invoice_5"/>
1316 </data>
1317 </openerp>
1318
1319=== modified file 'account/security/ir.model.access.csv'
1320--- account/security/ir.model.access.csv 2013-10-27 12:31:04 +0000
1321+++ account/security/ir.model.access.csv 2014-05-30 16:18:57 +0000
1322@@ -1,100 +1,101 @@
1323-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
1324-access_product_product_account_user,product.product.account.user,product.model_product_product,group_account_user,1,0,0,0
1325-access_account_payment_term,account.payment.term,model_account_payment_term,account.group_account_user,1,0,0,0
1326-access_account_payment_term_line,account.payment.term.line,model_account_payment_term_line,account.group_account_user,1,0,0,0
1327-access_account_account_type,account.account.type,model_account_account_type,account.group_account_user,1,0,0,0
1328-access_account_tax_internal_user,account.tax internal user,model_account_tax,base.group_user,1,0,0,0
1329-access_account_account,account.account,model_account_account,account.group_account_user,1,0,0,0
1330-access_account_account_user,account.account user,model_account_account,base.group_user,1,0,0,0
1331-access_account_account_partner_manager,account.account partner manager,model_account_account,base.group_partner_manager,1,0,0,0
1332-access_account_journal_period_manager,account.journal.period manager,model_account_journal_period,account.group_account_manager,1,0,0,0
1333-access_account_tax_code,account.tax.code,model_account_tax_code,account.group_account_invoice,1,0,0,0
1334-access_account_tax,account.tax,model_account_tax,account.group_account_invoice,1,0,0,0
1335-access_account_model,account.model,model_account_model,account.group_account_user,1,1,1,1
1336-access_account_model_line,account.model.line,model_account_model_line,account.group_account_user,1,1,1,1
1337-access_account_subscription,account.subscription,model_account_subscription,account.group_account_user,1,1,1,1
1338-access_account_subscription_line,account.subscription.line,model_account_subscription_line,account.group_account_user,1,1,1,1
1339-access_account_subscription_manager,account.subscription manager,model_account_subscription,account.group_account_manager,1,0,0,0
1340-access_account_subscription_line_manager,account.subscription.line manager,model_account_subscription_line,account.group_account_manager,1,0,0,0
1341-access_account_account_template,account.account.template,model_account_account_template,account.group_account_manager,1,1,1,1
1342-access_account_tax_code_template,account.tax.code.template,model_account_tax_code_template,account.group_account_manager,1,1,1,1
1343-access_account_chart_template,account.chart.template,model_account_chart_template,account.group_account_manager,1,1,1,1
1344-access_account_tax_template,account.tax.template,model_account_tax_template,account.group_account_manager,1,1,1,1
1345-access_account_bank_statement,account.bank.statement,model_account_bank_statement,account.group_account_user,1,1,1,1
1346-access_account_bank_statement_line,account.bank.statement.line,model_account_bank_statement_line,account.group_account_user,1,1,1,1
1347-access_account_analytic_line_manager,account.analytic.line manager,model_account_analytic_line,account.group_account_manager,1,0,0,0
1348-access_account_analytic_account,account.analytic.account,analytic.model_account_analytic_account,base.group_user,1,0,0,0
1349-access_account_analytic_journal,account.analytic.journal,model_account_analytic_journal,account.group_account_user,1,0,0,0
1350-access_account_analytic_journal_user,account.analytic.journal,model_account_analytic_journal,base.group_user,1,1,1,0
1351-access_account_invoice_uinvoice,account.invoice,model_account_invoice,account.group_account_invoice,1,1,1,1
1352-access_account_invoice_line_uinvoice,account.invoice.line,model_account_invoice_line,account.group_account_invoice,1,1,1,1
1353-access_account_invoice_tax_uinvoice,account.invoice.tax,model_account_invoice_tax,account.group_account_invoice,1,1,1,1
1354-access_account_move_uinvoice,account.move,model_account_move,account.group_account_invoice,1,1,1,1
1355-access_account_move_line_uinvoice,account.move.line invoice,model_account_move_line,account.group_account_invoice,1,1,1,1
1356-access_account_move_reconcile_uinvoice,account.move.reconcile,model_account_move_reconcile,account.group_account_invoice,1,1,1,1
1357-access_account_journal_period_uinvoice,account.journal.period,model_account_journal_period,account.group_account_invoice,1,1,1,1
1358-access_account_payment_term_manager,account.payment.term,model_account_payment_term,account.group_account_manager,1,1,1,1
1359-access_account_payment_term_line_manager,account.payment.term.line,model_account_payment_term_line,account.group_account_manager,1,1,1,1
1360-access_account_tax_manager,account.tax,model_account_tax,account.group_account_manager,1,1,1,1
1361-access_account_journal_manager,account.journal,model_account_journal,account.group_account_manager,1,1,1,1
1362-access_account_journal_invoice,account.journal invoice,model_account_journal,account.group_account_invoice,1,0,0,0
1363-access_account_period_manager,account.period,model_account_period,account.group_account_manager,1,1,1,1
1364-access_account_period_invoice,account.period invoice,model_account_period,account.group_account_invoice,1,0,0,0
1365-access_account_invoice_group_invoice,account.invoice group invoice,model_account_invoice,account.group_account_invoice,1,1,1,1
1366-access_account_analytic_journal_manager,account.analytic.journal,model_account_analytic_journal,account.group_account_manager,1,1,1,1
1367-access_account_fiscalyear,account.fiscalyear,model_account_fiscalyear,account.group_account_manager,1,1,1,1
1368-access_account_fiscalyear_invoice,account.fiscalyear.invoice,model_account_fiscalyear,account.group_account_invoice,1,0,0,0
1369-access_account_fiscalyear_partner_manager,account.fiscalyear.partnermanager,model_account_fiscalyear,base.group_partner_manager,1,0,0,0
1370-access_account_fiscalyear_employee,account.fiscalyear employee,model_account_fiscalyear,base.group_user,1,0,0,0
1371-access_res_currency_account_manager,res.currency account manager,base.model_res_currency,group_account_manager,1,1,1,1
1372-access_res_currency_rate_account_manager,res.currency.rate account manager,base.model_res_currency_rate,group_account_manager,1,1,1,1
1373-access_res_currency_rate_type_account_manager,res.currency.rate.type account manager,base.model_res_currency_rate_type,group_account_manager,1,1,1,1
1374-access_account_invoice_user,account.invoice user,model_account_invoice,base.group_user,1,0,0,0
1375-access_account_invoice_user,account.invoice.line user,model_account_invoice_line,base.group_user,1,0,0,0
1376-access_account_payment_term_partner_manager,account.payment.term partner manager,model_account_payment_term,base.group_user,1,0,0,0
1377-access_account_payment_term_line_partner_manager,account.payment.term.line partner manager,model_account_payment_term_line,base.group_user,1,0,0,0
1378-access_account_account_sale_manager,account.account sale manager,model_account_account,base.group_sale_manager,1,0,0,0
1379-access_account_fiscal_position_product_manager,account.fiscal.position account.manager,model_account_fiscal_position,account.group_account_manager,1,1,1,1
1380-access_account_fiscal_position_tax_product_manager,account.fiscal.position.tax account.manager,model_account_fiscal_position_tax,account.group_account_manager,1,1,1,1
1381-access_account_fiscal_position_account_product_manager,account.fiscal.position account.manager,model_account_fiscal_position_account,account.group_account_manager,1,1,1,1
1382-access_account_fiscal_position,account.fiscal.position all,model_account_fiscal_position,base.group_user,1,0,0,0
1383-access_account_fiscal_position_tax,account.fiscal.position.tax all,model_account_fiscal_position_tax,base.group_user,1,0,0,0
1384-access_account_fiscal_position_account,account.fiscal.position all,model_account_fiscal_position_account,base.group_user,1,0,0,0
1385-access_account_fiscal_position_template,account.fiscal.position.template,model_account_fiscal_position_template,account.group_account_manager,1,1,1,1
1386-access_account_fiscal_position_tax_template,account.fiscal.position.tax.template,model_account_fiscal_position_tax_template,account.group_account_manager,1,1,1,1
1387-access_account_fiscal_position_account_template,account.fiscal.position.account.template,model_account_fiscal_position_account_template,account.group_account_manager,1,1,1,1
1388-access_account_sequence_fiscal_year_user,account.sequence.fiscalyear user,model_account_sequence_fiscalyear,base.group_user,1,0,0,0
1389-access_temp_range,temp.range,model_temp_range,account.group_account_manager,1,0,0,0
1390-access_report_aged_receivable,report.aged.receivable,model_report_aged_receivable,account.group_account_manager,1,1,1,1
1391-access_report_invoice_created,report.invoice.created,model_report_invoice_created,account.group_account_manager,1,1,1,1
1392-access_report_account_type_sales,report.account_type.sales,model_report_account_type_sales,account.group_account_manager,1,1,1,1
1393-access_report_account_sales,report.account.sales,model_report_account_sales,account.group_account_manager,1,1,1,1
1394-access_account_invoice_report,account.invoice.report,model_account_invoice_report,account.group_account_manager,1,1,1,1
1395-access_res_partner_group_account_manager,res_partner group_account_manager,model_res_partner,account.group_account_manager,1,0,0,0
1396-access_account_invoice_accountant,account.invoice accountant,model_account_invoice,account.group_account_user,1,0,0,0
1397-access_account_tax_code_accountant,account.tax.code accountant,model_account_tax_code,account.group_account_user,1,1,1,1
1398-access_account_move_line_manager,account.move.line manager,model_account_move_line,account.group_account_manager,1,0,0,0
1399-access_account_move_manager,account.move manager,model_account_move,account.group_account_manager,1,0,0,0
1400-access_account_entries_report_manager,account.entries.report,model_account_entries_report,account.group_account_manager,1,1,1,1
1401-access_account_entries_report_invoice,account.entries.report,model_account_entries_report,account.group_account_invoice,1,0,0,0
1402-access_account_entries_report_employee,account.entries.report employee,model_account_entries_report,base.group_user,1,0,0,0
1403-access_analytic_entries_report_manager,analytic.entries.report,model_analytic_entries_report,account.group_account_manager,1,0,0,0
1404-access_account_cashbox_line,account.cashbox.line,model_account_cashbox_line,account.group_account_user,1,1,1,1
1405-access_account_journal_cashbox_line,account.journal.cashbox.line,model_account_journal_cashbox_line,account.group_account_user,1,1,1,0
1406-access_account_invoice_tax_accountant,account.invoice.tax accountant,model_account_invoice_tax,account.group_account_user,1,0,0,0
1407-access_account_move_reconcile_manager,account.move.reconcile manager,model_account_move_reconcile,account.group_account_manager,1,0,0,0
1408-access_account_analytic_line_invoice,account.analytic.line invoice,model_account_analytic_line,account.group_account_invoice,1,1,1,1
1409-access_account_invoice_line_accountant,account.invoice.line accountant,model_account_invoice_line,account.group_account_user,1,0,0,0
1410-access_account_account_invoice,account.account invoice,model_account_account,account.group_account_invoice,1,1,1,1
1411-access_account_analytic_accountant,account.analytic.account accountant,analytic.model_account_analytic_account,account.group_account_user,1,1,1,1
1412-access_account_account_type_invoice,account.account.type invoice,model_account_account_type,account.group_account_invoice,1,1,1,1
1413-access_report_account_receivable_invoice,report.account.receivable.invoice,model_report_account_receivable,account.group_account_invoice,1,1,1,1
1414-access_account_sequence_fiscal_year_invoice,account.sequence.fiscalyear invoice,model_account_sequence_fiscalyear,account.group_account_invoice,1,1,1,1
1415-access_account_tax_sale_manager,account.tax sale manager,model_account_tax,base.group_sale_salesman,1,0,0,0
1416-access_account_journal_sale_manager,account.journal sale manager,model_account_journal,base.group_sale_salesman,1,0,0,0
1417-access_account_invoice_tax_sale_manager,account.invoice.tax sale manager,model_account_invoice_tax,base.group_sale_salesman,1,0,0,0
1418-access_account_sequence_fiscal_year_sale_user,account.sequence.fiscalyear.sale.user,model_account_sequence_fiscalyear,base.group_sale_salesman,1,1,1,0
1419-access_account_sequence_fiscal_year_sale_manager,account.sequence.fiscalyear.sale.manager,model_account_sequence_fiscalyear,base.group_sale_manager,1,1,1,1
1420-access_account_treasury_report_manager,account.treasury.report.manager,model_account_treasury_report,account.group_account_manager,1,0,0,0
1421-access_account_financial_report,account.financial.report,model_account_financial_report,account.group_account_user,1,1,1,1
1422-access_account_financial_report_invoice,account.financial.report invoice,model_account_financial_report,account.group_account_invoice,1,0,0,0
1423+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
1424+access_product_product_account_user,product.product.account.user,product.model_product_product,group_account_user,1,0,0,0
1425+access_account_payment_term,account.payment.term,model_account_payment_term,account.group_account_user,1,0,0,0
1426+access_account_payment_term_line,account.payment.term.line,model_account_payment_term_line,account.group_account_user,1,0,0,0
1427+access_account_account_type,account.account.type,model_account_account_type,account.group_account_user,1,0,0,0
1428+access_account_tax_internal_user,account.tax internal user,model_account_tax,base.group_user,1,0,0,0
1429+access_account_account,account.account,model_account_account,account.group_account_user,1,0,0,0
1430+access_account_account_user,account.account user,model_account_account,base.group_user,1,0,0,0
1431+access_account_account_partner_manager,account.account partner manager,model_account_account,base.group_partner_manager,1,0,0,0
1432+access_account_journal_period_manager,account.journal.period manager,model_account_journal_period,account.group_account_manager,1,0,0,0
1433+access_account_tax_code,account.tax.code,model_account_tax_code,account.group_account_invoice,1,0,0,0
1434+access_account_tax,account.tax,model_account_tax,account.group_account_invoice,1,0,0,0
1435+access_account_model,account.model,model_account_model,account.group_account_user,1,1,1,1
1436+access_account_model_line,account.model.line,model_account_model_line,account.group_account_user,1,1,1,1
1437+access_account_subscription,account.subscription,model_account_subscription,account.group_account_user,1,1,1,1
1438+access_account_subscription_line,account.subscription.line,model_account_subscription_line,account.group_account_user,1,1,1,1
1439+access_account_subscription_manager,account.subscription manager,model_account_subscription,account.group_account_manager,1,0,0,0
1440+access_account_subscription_line_manager,account.subscription.line manager,model_account_subscription_line,account.group_account_manager,1,0,0,0
1441+access_account_account_template,account.account.template,model_account_account_template,account.group_account_manager,1,1,1,1
1442+access_account_tax_code_template,account.tax.code.template,model_account_tax_code_template,account.group_account_manager,1,1,1,1
1443+access_account_chart_template,account.chart.template,model_account_chart_template,account.group_account_manager,1,1,1,1
1444+access_account_tax_template,account.tax.template,model_account_tax_template,account.group_account_manager,1,1,1,1
1445+access_account_bank_statement,account.bank.statement,model_account_bank_statement,account.group_account_user,1,1,1,1
1446+access_account_bank_statement_line,account.bank.statement.line,model_account_bank_statement_line,account.group_account_user,1,1,1,1
1447+access_account_analytic_line_manager,account.analytic.line manager,model_account_analytic_line,account.group_account_manager,1,0,0,0
1448+access_account_analytic_account,account.analytic.account,analytic.model_account_analytic_account,base.group_user,1,0,0,0
1449+access_account_analytic_journal,account.analytic.journal,model_account_analytic_journal,account.group_account_user,1,0,0,0
1450+access_account_analytic_journal_user,account.analytic.journal,model_account_analytic_journal,base.group_user,1,1,1,0
1451+access_account_invoice_uinvoice,account.invoice,model_account_invoice,account.group_account_invoice,1,1,1,1
1452+access_account_invoice_line_uinvoice,account.invoice.line,model_account_invoice_line,account.group_account_invoice,1,1,1,1
1453+access_account_invoice_tax_uinvoice,account.invoice.tax,model_account_invoice_tax,account.group_account_invoice,1,1,1,1
1454+access_account_move_uinvoice,account.move,model_account_move,account.group_account_invoice,1,1,1,1
1455+access_account_move_line_uinvoice,account.move.line invoice,model_account_move_line,account.group_account_invoice,1,1,1,1
1456+access_account_move_reconcile_uinvoice,account.move.reconcile,model_account_move_reconcile,account.group_account_invoice,1,1,1,1
1457+access_account_journal_period_uinvoice,account.journal.period,model_account_journal_period,account.group_account_invoice,1,1,1,1
1458+access_account_payment_term_manager,account.payment.term,model_account_payment_term,account.group_account_manager,1,1,1,1
1459+access_account_payment_term_line_manager,account.payment.term.line,model_account_payment_term_line,account.group_account_manager,1,1,1,1
1460+access_account_tax_manager,account.tax,model_account_tax,account.group_account_manager,1,1,1,1
1461+access_account_journal_manager,account.journal,model_account_journal,account.group_account_manager,1,1,1,1
1462+access_account_journal_invoice,account.journal invoice,model_account_journal,account.group_account_invoice,1,0,0,0
1463+access_account_period_manager,account.period,model_account_period,account.group_account_manager,1,1,1,1
1464+access_account_period_invoice,account.period invoice,model_account_period,account.group_account_invoice,1,0,0,0
1465+access_account_invoice_group_invoice,account.invoice group invoice,model_account_invoice,account.group_account_invoice,1,1,1,1
1466+access_account_analytic_journal_manager,account.analytic.journal,model_account_analytic_journal,account.group_account_manager,1,1,1,1
1467+access_account_fiscalyear,account.fiscalyear,model_account_fiscalyear,account.group_account_manager,1,1,1,1
1468+access_account_fiscalyear_invoice,account.fiscalyear.invoice,model_account_fiscalyear,account.group_account_invoice,1,0,0,0
1469+access_account_fiscalyear_partner_manager,account.fiscalyear.partnermanager,model_account_fiscalyear,base.group_partner_manager,1,0,0,0
1470+access_account_fiscalyear_employee,account.fiscalyear employee,model_account_fiscalyear,base.group_user,1,0,0,0
1471+access_res_currency_account_manager,res.currency account manager,base.model_res_currency,group_account_manager,1,1,1,1
1472+access_res_currency_rate_account_manager,res.currency.rate account manager,base.model_res_currency_rate,group_account_manager,1,1,1,1
1473+access_res_currency_rate_type_account_manager,res.currency.rate.type account manager,base.model_res_currency_rate_type,group_account_manager,1,1,1,1
1474+access_account_invoice_user,account.invoice user,model_account_invoice,base.group_user,1,0,0,0
1475+access_account_invoice_user,account.invoice.line user,model_account_invoice_line,base.group_user,1,0,0,0
1476+access_account_payment_term_partner_manager,account.payment.term partner manager,model_account_payment_term,base.group_user,1,0,0,0
1477+access_account_payment_term_line_partner_manager,account.payment.term.line partner manager,model_account_payment_term_line,base.group_user,1,0,0,0
1478+access_account_account_sale_manager,account.account sale manager,model_account_account,base.group_sale_manager,1,0,0,0
1479+access_account_fiscal_position_product_manager,account.fiscal.position account.manager,model_account_fiscal_position,account.group_account_manager,1,1,1,1
1480+access_account_fiscal_position_tax_product_manager,account.fiscal.position.tax account.manager,model_account_fiscal_position_tax,account.group_account_manager,1,1,1,1
1481+access_account_fiscal_position_account_product_manager,account.fiscal.position account.manager,model_account_fiscal_position_account,account.group_account_manager,1,1,1,1
1482+access_account_fiscal_position,account.fiscal.position all,model_account_fiscal_position,base.group_user,1,0,0,0
1483+access_account_fiscal_position_tax,account.fiscal.position.tax all,model_account_fiscal_position_tax,base.group_user,1,0,0,0
1484+access_account_fiscal_position_account,account.fiscal.position all,model_account_fiscal_position_account,base.group_user,1,0,0,0
1485+access_account_fiscal_position_template,account.fiscal.position.template,model_account_fiscal_position_template,account.group_account_manager,1,1,1,1
1486+access_account_fiscal_position_tax_template,account.fiscal.position.tax.template,model_account_fiscal_position_tax_template,account.group_account_manager,1,1,1,1
1487+access_account_fiscal_position_account_template,account.fiscal.position.account.template,model_account_fiscal_position_account_template,account.group_account_manager,1,1,1,1
1488+access_account_sequence_fiscal_year_user,account.sequence.fiscalyear user,model_account_sequence_fiscalyear,base.group_user,1,0,0,0
1489+access_temp_range,temp.range,model_temp_range,account.group_account_manager,1,0,0,0
1490+access_report_aged_receivable,report.aged.receivable,model_report_aged_receivable,account.group_account_manager,1,1,1,1
1491+access_report_invoice_created,report.invoice.created,model_report_invoice_created,account.group_account_manager,1,1,1,1
1492+access_report_account_type_sales,report.account_type.sales,model_report_account_type_sales,account.group_account_manager,1,1,1,1
1493+access_report_account_sales,report.account.sales,model_report_account_sales,account.group_account_manager,1,1,1,1
1494+access_account_invoice_report,account.invoice.report,model_account_invoice_report,account.group_account_manager,1,1,1,1
1495+access_res_partner_group_account_manager,res_partner group_account_manager,model_res_partner,account.group_account_manager,1,0,0,0
1496+access_account_invoice_accountant,account.invoice accountant,model_account_invoice,account.group_account_user,1,0,0,0
1497+access_account_tax_code_accountant,account.tax.code accountant,model_account_tax_code,account.group_account_user,1,1,1,1
1498+access_account_move_line_manager,account.move.line manager,model_account_move_line,account.group_account_manager,1,0,0,0
1499+access_account_move_manager,account.move manager,model_account_move,account.group_account_manager,1,0,0,0
1500+access_account_entries_report_manager,account.entries.report,model_account_entries_report,account.group_account_manager,1,1,1,1
1501+access_account_entries_report_invoice,account.entries.report,model_account_entries_report,account.group_account_invoice,1,0,0,0
1502+access_account_entries_report_employee,account.entries.report employee,model_account_entries_report,base.group_user,1,0,0,0
1503+access_analytic_entries_report_manager,analytic.entries.report,model_analytic_entries_report,account.group_account_manager,1,0,0,0
1504+access_account_cashbox_line,account.cashbox.line,model_account_cashbox_line,account.group_account_user,1,1,1,1
1505+access_account_journal_cashbox_line,account.journal.cashbox.line,model_account_journal_cashbox_line,account.group_account_user,1,1,1,0
1506+access_account_invoice_tax_accountant,account.invoice.tax accountant,model_account_invoice_tax,account.group_account_user,1,0,0,0
1507+access_account_move_reconcile_manager,account.move.reconcile manager,model_account_move_reconcile,account.group_account_manager,1,0,0,0
1508+access_account_analytic_line_invoice,account.analytic.line invoice,model_account_analytic_line,account.group_account_invoice,1,1,1,1
1509+access_account_invoice_line_accountant,account.invoice.line accountant,model_account_invoice_line,account.group_account_user,1,0,0,0
1510+access_account_account_invoice,account.account invoice,model_account_account,account.group_account_invoice,1,1,1,1
1511+access_account_analytic_accountant,account.analytic.account accountant,analytic.model_account_analytic_account,account.group_account_user,1,1,1,1
1512+access_account_account_type_invoice,account.account.type invoice,model_account_account_type,account.group_account_invoice,1,1,1,1
1513+access_report_account_receivable_invoice,report.account.receivable.invoice,model_report_account_receivable,account.group_account_invoice,1,1,1,1
1514+access_account_sequence_fiscal_year_invoice,account.sequence.fiscalyear invoice,model_account_sequence_fiscalyear,account.group_account_invoice,1,1,1,1
1515+access_account_tax_sale_manager,account.tax sale manager,model_account_tax,base.group_sale_salesman,1,0,0,0
1516+access_account_journal_sale_manager,account.journal sale manager,model_account_journal,base.group_sale_salesman,1,0,0,0
1517+access_account_invoice_tax_sale_manager,account.invoice.tax sale manager,model_account_invoice_tax,base.group_sale_salesman,1,0,0,0
1518+access_account_sequence_fiscal_year_sale_user,account.sequence.fiscalyear.sale.user,model_account_sequence_fiscalyear,base.group_sale_salesman,1,1,1,0
1519+access_account_sequence_fiscal_year_sale_manager,account.sequence.fiscalyear.sale.manager,model_account_sequence_fiscalyear,base.group_sale_manager,1,1,1,1
1520+access_account_treasury_report_manager,account.treasury.report.manager,model_account_treasury_report,account.group_account_manager,1,0,0,0
1521+access_account_financial_report,account.financial.report,model_account_financial_report,account.group_account_user,1,1,1,1
1522+access_account_financial_report_invoice,account.financial.report invoice,model_account_financial_report,account.group_account_invoice,1,0,0,0
1523+access_account_statement_operation_template,account.statement.operation.template,model_account_statement_operation_template,account.group_account_user,1,1,1,1
1524
1525=== added file 'account/static/src/css/account_bank_statement_reconciliation.css'
1526--- account/static/src/css/account_bank_statement_reconciliation.css 1970-01-01 00:00:00 +0000
1527+++ account/static/src/css/account_bank_statement_reconciliation.css 2014-05-30 16:18:57 +0000
1528@@ -0,0 +1,264 @@
1529+.openerp .oe_bank_statement_reconciliation {
1530+ font-size: 12px;
1531+ -webkit-user-select: none;
1532+ -moz-user-select: none;
1533+ -ms-user-select: none;
1534+ -o-user-select: none;
1535+ user-select: none;
1536+ cursor: default;
1537+ /* icons */ }
1538+ .openerp .oe_bank_statement_reconciliation h1 {
1539+ width: 48%;
1540+ padding: 0 0 0 15px;
1541+ margin: 0 0 35px 0;
1542+ float: left;
1543+ font-size: 2.3em; }
1544+ .openerp .oe_bank_statement_reconciliation h2 {
1545+ font-size: 1.8em; }
1546+ .openerp .oe_bank_statement_reconciliation .progress {
1547+ width: 49%;
1548+ margin: 6px 15px 0 0;
1549+ float: right;
1550+ position: relative;
1551+ display: inline-block; }
1552+ .openerp .oe_bank_statement_reconciliation .progress .progress-text {
1553+ text-align: center;
1554+ position: absolute;
1555+ width: 100%;
1556+ left: 0;
1557+ top: 2px;
1558+ z-index: 10;
1559+ text-shadow: -1px -1px 0 #f5f5f5, 1px -1px 0 #f5f5f5, -1px 1px 0 #f5f5f5, 1px 1px 0 #f5f5f5; }
1560+ .openerp .oe_bank_statement_reconciliation .oe_form_sheet {
1561+ position: relative;
1562+ padding-bottom: 30px; }
1563+ .openerp .oe_bank_statement_reconciliation .protip {
1564+ margin: 0;
1565+ position: absolute;
1566+ bottom: 7px;
1567+ right: 15px;
1568+ text-align: right;
1569+ color: #bbb; }
1570+ .openerp .oe_bank_statement_reconciliation .done_message {
1571+ width: 100%;
1572+ padding: 0 20%;
1573+ margin-top: 50px;
1574+ margin-bottom: 50px; }
1575+ .openerp .oe_bank_statement_reconciliation .done_message h2 {
1576+ margin-bottom: 30px; }
1577+ .openerp .oe_bank_statement_reconciliation .done_message h2 .congrats_icon {
1578+ float: right;
1579+ font-size: 2em;
1580+ position: relative;
1581+ top: -0.25em; }
1582+ .openerp .oe_bank_statement_reconciliation .done_message .achievements {
1583+ margin-top: 30px;
1584+ text-align: center;
1585+ position: relative; }
1586+ .openerp .oe_bank_statement_reconciliation .done_message .achievements .achievement {
1587+ font-size: 4em;
1588+ margin: 0 0.3em;
1589+ position: relative;
1590+ vertical-align: middle;
1591+ text-shadow: 2px 2px 0px rgba(0, 0, 0, 0.2); }
1592+ .openerp .oe_bank_statement_reconciliation .done_message .achievements .achievement i {
1593+ font-size: 0.5em;
1594+ color: white;
1595+ position: absolute;
1596+ top: 50%;
1597+ margin-top: -0.55em;
1598+ left: 0;
1599+ width: 100%;
1600+ text-align: center; }
1601+ .openerp .oe_bank_statement_reconciliation .done_message .action_buttons {
1602+ text-align: center; }
1603+ .openerp .oe_bank_statement_reconciliation .glyphicon {
1604+ font-size: 12px !important; }
1605+ .openerp .oe_bank_statement_reconciliation .glyphicon.line_info_button {
1606+ color: #ccc !important; }
1607+ .openerp .oe_bank_statement_reconciliation .accounting_view .glyphicon-add-remove:before {
1608+ content: "\2212"; }
1609+ .openerp .oe_bank_statement_reconciliation .match .glyphicon-add-remove:before {
1610+ content: "\2b"; }
1611+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line {
1612+ margin-bottom: 30px;
1613+ /* gap between accounting_view and action view */
1614+ /* popover */
1615+ /* arrays of move lines */
1616+ /* Partie infos */
1617+ /* Match view */
1618+ /* Action create */ }
1619+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line table {
1620+ width: 100%; }
1621+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .toggle_match, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .toggle_create {
1622+ -webkit-transition-property: -webkit-transform;
1623+ -moz-transition-property: -moz-transform;
1624+ -ms-transition-property: -ms-transform;
1625+ -o-transition-property: -o-transform;
1626+ transition-property: transform;
1627+ -webkit-transform: rotate(0deg);
1628+ -moz-transform: rotate(0deg);
1629+ -ms-transform: rotate(0deg);
1630+ -o-transform: rotate(0deg);
1631+ transform: rotate(0deg); }
1632+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .visible_toggle, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line[data-mode="match"] .toggle_match, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line[data-mode="create"] .toggle_create {
1633+ visibility: visible !important;
1634+ -webkit-transform: rotate(90deg);
1635+ -moz-transform: rotate(90deg);
1636+ -ms-transform: rotate(90deg);
1637+ -o-transform: rotate(90deg);
1638+ transform: rotate(90deg); }
1639+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .change_partner_container {
1640+ width: 200px;
1641+ display: none;
1642+ position: relative !important; }
1643+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line[data-mode="inactive"] .initial_line > td {
1644+ background-color: #f8f8f8 !important; }
1645+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line.no_match:not(.no_partner) .initial_line {
1646+ cursor: default !important; }
1647+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line.no_match:not(.no_partner) .initial_line .line_info_button {
1648+ cursor: pointer; }
1649+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line.no_match:not(.no_partner) .toggle_match {
1650+ visibility: hidden !important; }
1651+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line.no_partner .partner_name, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line.no_partner .line_open_balance {
1652+ display: none !important; }
1653+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line > table > tbody > tr:nth-child(1) > td table {
1654+ margin-bottom: 10px; }
1655+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line table.details td:first-child {
1656+ padding-right: 10px;
1657+ font-weight: bold; }
1658+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table {
1659+ width: 100%; }
1660+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr {
1661+ cursor: pointer; }
1662+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.created_line, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr.created_line {
1663+ cursor: default !important; }
1664+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.created_line .line_remove_button, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr.created_line .line_remove_button {
1665+ cursor: pointer; }
1666+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td {
1667+ padding: 1px 8px;
1668+ vertical-align: middle; }
1669+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(1), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(7), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td:nth-child(1), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td:nth-child(7) {
1670+ width: 15px;
1671+ padding: 0; }
1672+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(1), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td:nth-child(1) {
1673+ text-align: left; }
1674+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(2), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td:nth-child(2) {
1675+ width: 80px;
1676+ padding-left: 3px; }
1677+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(3), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td:nth-child(3) {
1678+ width: 100px; }
1679+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(5), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td:nth-child(5) {
1680+ text-align: right;
1681+ width: 15%; }
1682+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(6), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td:nth-child(6) {
1683+ width: 15%;
1684+ text-align: right;
1685+ padding-right: 3px; }
1686+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(7), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td:nth-child(7) {
1687+ text-align: right; }
1688+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.line_open_balance, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr.line_open_balance {
1689+ color: #bbb; }
1690+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr .glyphicon:not(.line_info_button), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr .glyphicon:not(.line_info_button) {
1691+ visibility: hidden;
1692+ color: #555; }
1693+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr:hover .glyphicon, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.active .glyphicon, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr:hover .glyphicon, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr.active .glyphicon {
1694+ visibility: visible; }
1695+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr .do_partial_reconcile_button, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr .do_partial_reconcile_button {
1696+ color: #f0ad4e;
1697+ padding-right: 5px; }
1698+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr .undo_partial_reconcile_button, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr .undo_partial_reconcile_button {
1699+ color: #555;
1700+ padding-right: 5px; }
1701+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view .initial_line > td {
1702+ border-top: 1px solid #bbbbbb;
1703+ padding-top: 4px;
1704+ padding-bottom: 5px;
1705+ background-color: #f0f0f0;
1706+ -webkit-transition-property: background-color;
1707+ -moz-transition-property: background-color;
1708+ -ms-transition-property: background-color;
1709+ transition-property: background-color; }
1710+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view .initial_line > td:nth-child(1), .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view .initial_line > td:nth-child(7) {
1711+ border-top: none;
1712+ background: white !important;
1713+ padding-top: 6px;
1714+ padding-bottom: 3px; }
1715+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption {
1716+ text-align: left;
1717+ font-size: 1.1em;
1718+ font-weight: bold;
1719+ height: 26px;
1720+ margin: 0 15px 4px 15px; }
1721+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption .button_ok {
1722+ float: right; }
1723+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption .button_ok:disabled {
1724+ opacity: 0.5; }
1725+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption > span, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption > input {
1726+ position: relative;
1727+ top: 7px;
1728+ /* meh */
1729+ font-weight: bold;
1730+ cursor: pointer; }
1731+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(6) {
1732+ border-left: 1px solid black; }
1733+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.initial_line > td:nth-child(5) {
1734+ border-top: 1px solid black; }
1735+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.initial_line > td:nth-child(6) {
1736+ border-top: 1px solid black; }
1737+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls {
1738+ padding: 0 0 5px 18px; }
1739+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls .filter {
1740+ width: 240px; }
1741+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls .pager_control_left, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls .pager_control_right {
1742+ display: inline-block;
1743+ cursor: pointer; }
1744+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls .pager_control_left {
1745+ margin-right: 10px; }
1746+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls .pager_control_left.disabled, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls .pager_control_right.disabled {
1747+ color: #ddd;
1748+ cursor: default; }
1749+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .show_more {
1750+ display: inline-block;
1751+ margin-left: 18px;
1752+ margin-top: 5px; }
1753+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create {
1754+ margin: 0 15px;
1755+ border: 1px solid #d5d5d5;
1756+ border-radius: 5px;
1757+ padding: 10px; }
1758+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .quick_add {
1759+ margin-bottom: 10px;
1760+ clear: both; }
1761+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .quick_add:empty {
1762+ display: none; }
1763+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .quick_add:empty {
1764+ display: none; }
1765+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table {
1766+ width: 49%;
1767+ height: 26px; }
1768+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table:nth-child(2n+1) {
1769+ float: left; }
1770+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table:nth-child(2n) {
1771+ float: right; }
1772+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table th {
1773+ font-weight: bold;
1774+ line-height: 26px;
1775+ padding-right: 8px;
1776+ min-width: 100px;
1777+ border-right: 1px solid #ddd;
1778+ white-space: nowrap;
1779+ width: 1%; }
1780+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table td {
1781+ width: 99%;
1782+ padding-left: 8px; }
1783+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table input, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table select {
1784+ width: 100%; }
1785+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table.add_line_container:nth-child(2n+1) {
1786+ width: 98%;
1787+ float: none;
1788+ margin: auto; }
1789+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table.add_line_container td {
1790+ text-align: center; }
1791+ .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .create .oe_form > table.add_line_container .add_line {
1792+ line-height: 26px; }
1793
1794=== added file 'account/static/src/css/account_bank_statement_reconciliation.scss'
1795--- account/static/src/css/account_bank_statement_reconciliation.scss 1970-01-01 00:00:00 +0000
1796+++ account/static/src/css/account_bank_statement_reconciliation.scss 2014-05-30 16:18:57 +0000
1797@@ -0,0 +1,447 @@
1798+$actionColWidth: 15px;
1799+$mainTableBordersPadding: 3px;
1800+$lightBorder: 1px solid #bbb;
1801+$accountingBorder: 1px solid #000;
1802+$initialLineBackground: #f0f0f0;
1803+
1804+
1805+.openerp .oe_bank_statement_reconciliation {
1806+ font-size: 12px;
1807+ -webkit-user-select: none;
1808+ -moz-user-select: none;
1809+ -ms-user-select: none;
1810+ -o-user-select: none;
1811+ user-select: none;
1812+ cursor: default;
1813+
1814+ h1 {
1815+ width: 48%;
1816+ padding: 0 0 0 $actionColWidth;
1817+ margin: 0 0 35px 0;
1818+ float: left;
1819+ font-size: 2.3em;
1820+ }
1821+
1822+ h2 {
1823+ font-size: 1.8em;
1824+ }
1825+
1826+ .progress {
1827+ width: 49%;
1828+ margin: 6px $actionColWidth 0 0;
1829+ float: right;
1830+ position: relative;
1831+ display: inline-block;
1832+
1833+ .progress-text {
1834+ text-align: center;
1835+ position: absolute;
1836+ width: 100%;
1837+ left: 0;
1838+ top: 2px;
1839+ z-index: 10;
1840+ text-shadow:
1841+ -1px -1px 0 #f5f5f5,
1842+ 1px -1px 0 #f5f5f5,
1843+ -1px 1px 0 #f5f5f5,
1844+ 1px 1px 0 #f5f5f5;
1845+ }
1846+ }
1847+
1848+ .oe_form_sheet {
1849+ position: relative;
1850+ padding-bottom: 30px;
1851+ }
1852+
1853+ .protip {
1854+ margin: 0;
1855+ position: absolute;
1856+ bottom: 7px;
1857+ right: 15px;
1858+ text-align: right;
1859+ color: #bbb;
1860+ }
1861+
1862+ .done_message {
1863+ width: 100%;
1864+ padding: 0 20%;
1865+ margin-top: 50px;
1866+ margin-bottom: 50px;
1867+
1868+ h2 {
1869+ margin-bottom: 30px;
1870+
1871+ .congrats_icon {
1872+ float: right;
1873+ font-size: 2em;
1874+ position: relative;
1875+ top: -0.25em;
1876+ }
1877+ }
1878+
1879+ .achievements {
1880+ margin-top: 30px;
1881+ text-align: center;
1882+ position: relative;
1883+
1884+ .achievement {
1885+ font-size: 4em;
1886+ margin: 0 0.3em;
1887+ position: relative;
1888+ vertical-align: middle;
1889+ text-shadow: 2px 2px 0px rgba(0,0,0,0.2);
1890+
1891+ i {
1892+ font-size: 0.5em;
1893+ color: white;
1894+ position: absolute;
1895+ top: 50%;
1896+ margin-top: -0.55em;
1897+ left: 0;
1898+ width: 100%;
1899+ text-align: center;
1900+ //text-shadow: 1px 1px 0 black;
1901+ }
1902+ }
1903+ }
1904+
1905+ .action_buttons {
1906+ text-align: center;
1907+ }
1908+ }
1909+
1910+ /* icons */
1911+ .glyphicon {
1912+ font-size: 12px !important;
1913+
1914+ &.line_info_button {
1915+ color: #ccc !important;
1916+ }
1917+ }
1918+ .accounting_view .glyphicon-add-remove:before {
1919+ content: "\2212";
1920+ }
1921+ .match .glyphicon-add-remove:before {
1922+ content: "\2b";
1923+ }
1924+
1925+ // bankStatementReconciliationLine widget
1926+ .oe_bank_statement_reconciliation_line {
1927+ margin-bottom: 30px;
1928+
1929+ table {
1930+ width: 100%;
1931+ }
1932+
1933+ // modes : default
1934+ .toggle_match, .toggle_create {
1935+ -webkit-transition-property: -webkit-transform;
1936+ -moz-transition-property: -moz-transform;
1937+ -ms-transition-property: -ms-transform;
1938+ -o-transition-property: -o-transform;
1939+ transition-property: transform;
1940+ -webkit-transform: rotate(0deg);
1941+ -moz-transform: rotate(0deg);
1942+ -ms-transform: rotate(0deg);
1943+ -o-transform: rotate(0deg);
1944+ transform: rotate(0deg);
1945+ }
1946+
1947+ .visible_toggle {
1948+ visibility: visible !important;
1949+ -webkit-transform: rotate(90deg);
1950+ -moz-transform: rotate(90deg);
1951+ -ms-transform: rotate(90deg);
1952+ -o-transform: rotate(90deg);
1953+ transform: rotate(90deg);
1954+ }
1955+
1956+ .change_partner_container {
1957+ width: 200px;
1958+ display: none;
1959+ position: relative !important;
1960+ }
1961+
1962+ // modes : specific
1963+ &[data-mode="match"] {
1964+ .toggle_match {
1965+ @extend .visible_toggle;
1966+ }
1967+ }
1968+
1969+ &[data-mode="create"] {
1970+ .toggle_create {
1971+ @extend .visible_toggle;
1972+ }
1973+ }
1974+
1975+ &[data-mode="inactive"] {
1976+ .initial_line > td {
1977+ background-color: ($initialLineBackground + #080808) !important;
1978+ }
1979+ }
1980+
1981+ &.no_match:not(.no_partner) {
1982+ .initial_line {
1983+ cursor: default !important;
1984+
1985+ .line_info_button {
1986+ cursor: pointer;
1987+ }
1988+ }
1989+ .toggle_match {
1990+ visibility: hidden !important;
1991+ }
1992+ }
1993+
1994+ &.no_partner {
1995+ .partner_name, .line_open_balance {
1996+ display: none !important;
1997+ }
1998+ }
1999+
2000+ /* gap between accounting_view and action view */
2001+ > table > tbody > tr:nth-child(1) > td table {
2002+ margin-bottom: 10px;
2003+ }
2004+
2005+ /* popover */
2006+ table.details {
2007+ td:first-child {
2008+ padding-right: 10px;
2009+ font-weight: bold;
2010+ }
2011+ }
2012+
2013+ /* arrays of move lines */
2014+ .accounting_view, .match table {
2015+ width: 100%;
2016+
2017+ tr {
2018+ cursor: pointer;
2019+
2020+ &.created_line {
2021+ cursor: default !important;
2022+
2023+ .line_remove_button {
2024+ cursor: pointer;
2025+ }
2026+ }
2027+ }
2028+
2029+ td {
2030+ padding: 1px 8px;
2031+ vertical-align: middle;
2032+ }
2033+
2034+ td:nth-child(1), td:nth-child(7) {
2035+ width: $actionColWidth;
2036+ padding: 0;
2037+ }
2038+
2039+ td:nth-child(1) {
2040+ text-align: left;
2041+ }
2042+
2043+ td:nth-child(2) {
2044+ width: 80px;
2045+ padding-left: $mainTableBordersPadding;
2046+ }
2047+
2048+ td:nth-child(3) {
2049+ width: 100px;
2050+ }
2051+
2052+ td:nth-child(4) {
2053+
2054+ }
2055+
2056+ td:nth-child(5) {
2057+ text-align: right;
2058+ width: 15%;
2059+ }
2060+
2061+ td:nth-child(6) {
2062+ width: 15%;
2063+ text-align: right;
2064+ padding-right: $mainTableBordersPadding;
2065+ }
2066+
2067+ td:nth-child(7) {
2068+ text-align: right;
2069+ }
2070+
2071+ tr.line_open_balance {
2072+ color: #bbb;
2073+ }
2074+
2075+ tr .glyphicon:not(.line_info_button) {
2076+ visibility: hidden;
2077+ color: #555;
2078+ }
2079+
2080+ tr:hover .glyphicon, tr.active .glyphicon {
2081+ visibility: visible;
2082+ }
2083+
2084+ tr .do_partial_reconcile_button {
2085+ color: #f0ad4e;
2086+ padding-right: 5px;
2087+ }
2088+
2089+ tr .undo_partial_reconcile_button {
2090+ color: #555;
2091+ padding-right: 5px;
2092+ }
2093+ }
2094+
2095+ /* Partie infos */
2096+ .accounting_view {
2097+
2098+ .initial_line > td {
2099+ border-top: $lightBorder;
2100+ padding-top: 4px;
2101+ padding-bottom: 5px;
2102+ background-color: $initialLineBackground;
2103+ -webkit-transition-property: background-color;
2104+ -moz-transition-property: background-color;
2105+ -ms-transition-property: background-color;
2106+ transition-property: background-color;
2107+
2108+ &:nth-child(1), &:nth-child(7) {
2109+ border-top: none;
2110+ background: white !important;
2111+ // Hack pour l'alignement au px près
2112+ padding-top: 6px;
2113+ padding-bottom: 3px;
2114+ }
2115+ }
2116+
2117+ caption {
2118+ text-align: left;
2119+ font-size: 1.1em;
2120+ font-weight: bold;
2121+ height: 26px;
2122+ margin: 0 $actionColWidth 4px $actionColWidth;
2123+
2124+ .button_ok {
2125+ float: right;
2126+
2127+ &:disabled {
2128+ opacity: 0.5;
2129+ }
2130+ }
2131+
2132+ > span, > input {
2133+ position: relative; top: 7px; /* meh */
2134+ font-weight: bold;
2135+ cursor: pointer;
2136+ }
2137+ }
2138+
2139+ // accounting "T"
2140+ td:nth-child(6) { border-left: $accountingBorder; }
2141+ tr.initial_line > td {
2142+ &:nth-child(5) { border-top: $accountingBorder; }
2143+ &:nth-child(6) { border-top: $accountingBorder; }
2144+ }
2145+ }
2146+
2147+
2148+ /* Match view */
2149+ .match {
2150+
2151+ .match_controls {
2152+ padding: 0 0 5px ($actionColWidth+$mainTableBordersPadding);
2153+
2154+ .filter {
2155+ width: 240px;
2156+ }
2157+
2158+ .pager_control_left, .pager_control_right {
2159+ display: inline-block;
2160+ cursor: pointer;
2161+ }
2162+
2163+ .pager_control_left {
2164+ margin-right: 10px;
2165+ }
2166+
2167+ .pager_control_left.disabled, .pager_control_right.disabled {
2168+ color: #ddd;
2169+ cursor: default;
2170+ }
2171+ }
2172+
2173+ .show_more {
2174+ display: inline-block;
2175+ margin-left: ($actionColWidth+$mainTableBordersPadding);
2176+ margin-top: 5px;
2177+ }
2178+ }
2179+
2180+
2181+ /* Action create */
2182+ .create {
2183+ margin: 0 $actionColWidth;
2184+ border: 1px solid #d5d5d5;
2185+ border-radius: 5px;
2186+ padding: 10px;
2187+
2188+ .quick_add {
2189+ margin-bottom: 10px;
2190+ clear: both;
2191+
2192+ &:empty {
2193+ display: none;
2194+ }
2195+ }
2196+ .quick_add:empty {
2197+ display: none;
2198+ }
2199+
2200+ .oe_form > table {
2201+ width: 49%;
2202+ height: 26px;
2203+
2204+ &:nth-child(2n+1) { float: left; }
2205+ &:nth-child(2n) { float: right; }
2206+
2207+ th {
2208+ font-weight: bold;
2209+ line-height: 26px;
2210+ padding-right: 8px;
2211+ min-width: 100px;
2212+ border-right: 1px solid #ddd;
2213+ white-space: nowrap;
2214+ width: 1%;
2215+ }
2216+
2217+ td {
2218+ width: 99%;
2219+ padding-left: 8px;
2220+ }
2221+
2222+ input, select {
2223+ width: 100%;
2224+ }
2225+
2226+ &.add_line_container {
2227+ &:nth-child(2n+1) {
2228+ width: 98%;
2229+ float: none;
2230+ margin: auto;
2231+ }
2232+
2233+ td {
2234+ text-align: center;
2235+ }
2236+
2237+ .add_line {
2238+ line-height: 26px;
2239+ }
2240+ }
2241+ }
2242+ }
2243+ }
2244+}
2245
2246=== renamed file 'account/static/src/js/account_move_reconciliation.js' => 'account/static/src/js/account_widgets.js'
2247--- account/static/src/js/account_move_reconciliation.js 2014-04-11 12:28:40 +0000
2248+++ account/static/src/js/account_widgets.js 2014-05-30 16:18:57 +0000
2249@@ -6,6 +6,1474 @@
2250
2251 instance.web.account = instance.web.account || {};
2252
2253+ instance.web.client_actions.add('bank_statement_reconciliation_view', 'instance.web.account.bankStatementReconciliation');
2254+ instance.web.account.bankStatementReconciliation = instance.web.Widget.extend({
2255+ className: 'oe_bank_statement_reconciliation',
2256+
2257+ init: function(parent, context) {
2258+ this._super(parent);
2259+ this.max_reconciliations_displayed = 10;
2260+ this.statement_id = context.context.statement_id;
2261+ this.title = context.context.title || _t("Reconciliation");
2262+ this.st_lines = [];
2263+ this.last_displayed_reconciliation_index = undefined; // Flow control
2264+ this.reconciled_lines = 0; // idem
2265+ this.already_reconciled_lines = 0; // Number of lines of the statement which were already reconciled
2266+ this.model_bank_statement = new instance.web.Model("account.bank.statement");
2267+ this.model_bank_statement_line = new instance.web.Model("account.bank.statement.line");
2268+ this.reconciliation_menu_id = false; // Used to update the needaction badge
2269+ this.formatCurrency; // Method that formats the currency ; loaded from the server
2270+
2271+ // Only for statistical purposes
2272+ this.lines_reconciled_with_ctrl_enter = 0;
2273+ this.time_widget_loaded = Date.now();
2274+
2275+ // Stuff used by the children bankStatementReconciliationLine
2276+ this.max_move_lines_displayed = 5;
2277+ this.animation_speed = 100; // "Blocking" animations
2278+ this.aestetic_animation_speed = 300; // eye candy
2279+ this.map_tax_id_amount = {};
2280+ this.presets = {};
2281+ // We'll need to get the code of an account selected in a many2one (whose value is the id)
2282+ this.map_account_id_code = {};
2283+ // The same move line cannot be selected for multiple resolutions
2284+ this.excluded_move_lines_ids = {};
2285+ // Description of the fields to initialize in the "create new line" form
2286+ // NB : for presets to work correctly, a field id must be the same string as a preset field
2287+ this.create_form_fields = {
2288+ account_id: {
2289+ id: "account_id",
2290+ index: 0,
2291+ corresponding_property: "account_id", // a account.move field name
2292+ label: _t("Account"),
2293+ required: true,
2294+ tabindex: 10,
2295+ constructor: instance.web.form.FieldMany2One,
2296+ field_properties: {
2297+ relation: "account.account",
2298+ string: _t("Account"),
2299+ type: "many2one",
2300+ domain: [['type','!=','view']],
2301+ },
2302+ },
2303+ label: {
2304+ id: "label",
2305+ index: 1,
2306+ corresponding_property: "label",
2307+ label: _t("Label"),
2308+ required: true,
2309+ tabindex: 11,
2310+ constructor: instance.web.form.FieldChar,
2311+ field_properties: {
2312+ string: _t("Label"),
2313+ type: "char",
2314+ },
2315+ },
2316+ tax_id: {
2317+ id: "tax_id",
2318+ index: 2,
2319+ corresponding_property: "tax_id",
2320+ label: _t("Tax"),
2321+ required: false,
2322+ tabindex: 12,
2323+ constructor: instance.web.form.FieldMany2One,
2324+ field_properties: {
2325+ relation: "account.tax",
2326+ string: _t("Tax"),
2327+ type: "many2one",
2328+ },
2329+ },
2330+ amount: {
2331+ id: "amount",
2332+ index: 3,
2333+ corresponding_property: "amount",
2334+ label: _t("Amount"),
2335+ required: true,
2336+ tabindex: 13,
2337+ constructor: instance.web.form.FieldFloat,
2338+ field_properties: {
2339+ string: _t("Amount"),
2340+ type: "float",
2341+ },
2342+ },
2343+ analytic_account_id: {
2344+ id: "analytic_account_id",
2345+ index: 4,
2346+ corresponding_property: "analytic_account_id",
2347+ label: _t("Analytic Acc."),
2348+ required: false,
2349+ tabindex: 14,
2350+ group:"analytic.group_analytic_accounting",
2351+ constructor: instance.web.form.FieldMany2One,
2352+ field_properties: {
2353+ relation: "account.analytic.account",
2354+ string: _t("Analytic Acc."),
2355+ type: "many2one",
2356+ },
2357+ },
2358+ };
2359+ },
2360+
2361+ start: function() {
2362+ this._super();
2363+ var self = this;
2364+
2365+ // Inject variable styles
2366+ var style = document.createElement("style");
2367+ style.appendChild(document.createTextNode(""));
2368+ document.head.appendChild(style);
2369+ var css_selector = ".oe_bank_statement_reconciliation_line .toggle_match, .oe_bank_statement_reconciliation_line .toggle_create, .oe_bank_statement_reconciliation_line .initial_line > td";
2370+ if(style.sheet.insertRule) {
2371+ style.sheet.insertRule(css_selector + " { -webkit-transition-duration: "+self.aestetic_animation_speed+"ms; }", 0);
2372+ style.sheet.insertRule(css_selector + " { -moz-transition-duration: "+self.aestetic_animation_speed+"ms; }", 0);
2373+ style.sheet.insertRule(css_selector + " { -ms-transition-duration: "+self.aestetic_animation_speed+"ms; }", 0);
2374+ style.sheet.insertRule(css_selector + " { -o-transition-duration: "+self.aestetic_animation_speed+"ms; }", 0);
2375+ style.sheet.insertRule(css_selector + " { transition-duration: "+self.aestetic_animation_speed+"ms; }", 0);
2376+ } else {
2377+ style.sheet.addRule(css_selector, "-webkit-transition-duration: "+self.aestetic_animation_speed+"ms;");
2378+ style.sheet.addRule(css_selector, "-moz-transition-duration: "+self.aestetic_animation_speed+"ms;");
2379+ style.sheet.addRule(css_selector, "-ms-transition-duration: "+self.aestetic_animation_speed+"ms;");
2380+ style.sheet.addRule(css_selector, "-o-transition-duration: "+self.aestetic_animation_speed+"ms;");
2381+ style.sheet.addRule(css_selector, "-webkit-transition-duration: "+self.aestetic_animation_speed+"ms;");
2382+ }
2383+
2384+ // Retreive statement infos and reconciliation data from the model
2385+ var lines_filter = [['journal_entry_id', '=', false]];
2386+ var deferred_promises = [];
2387+
2388+ if (self.statement_id) {
2389+ lines_filter.push(['statement_id', '=', self.statement_id]);
2390+ deferred_promises.push(self.model_bank_statement
2391+ .query(["name"])
2392+ .filter([['id', '=', self.statement_id]])
2393+ .first()
2394+ .then(function(title){
2395+ self.title = title.name;
2396+ })
2397+ );
2398+ deferred_promises.push(self.model_bank_statement
2399+ .call("number_of_lines_reconciled", [self.statement_id])
2400+ .then(function(num) {
2401+ self.already_reconciled_lines = num;
2402+ })
2403+ );
2404+ }
2405+
2406+ deferred_promises.push(new instance.web.Model("account.statement.operation.template")
2407+ .query(['id','name','account_id','label','amount_type','amount','tax_id','analytic_account_id'])
2408+ .all().then(function (data) {
2409+ _(data).each(function(preset){
2410+ self.presets[preset.id] = preset;
2411+ });
2412+ })
2413+ );
2414+
2415+ deferred_promises.push(self.model_bank_statement
2416+ .call("get_format_currency_js_function", [self.statement_id])
2417+ .then(function(data){
2418+ self.formatCurrency = new Function("amount", data);
2419+ })
2420+ );
2421+
2422+ deferred_promises.push(self.model_bank_statement_line
2423+ .query(['id'])
2424+ .filter(lines_filter)
2425+ .order_by('id')
2426+ .all().then(function (data) {
2427+ self.st_lines = _(data).map(function(o){ return o.id });
2428+ })
2429+ );
2430+
2431+ // When queries are done, render template and reconciliation lines
2432+ return $.when.apply($, deferred_promises).then(function(){
2433+
2434+ // If there is no statement line to reconcile, stop here
2435+ if (self.st_lines.length === 0) {
2436+ self.$el.prepend(QWeb.render("bank_statement_nothing_to_reconcile"));
2437+ return;
2438+ }
2439+
2440+ // Create a dict account id -> account code for display facilities
2441+ new instance.web.Model("account.account")
2442+ .query(['id', 'code'])
2443+ .all().then(function(data) {
2444+ _.each(data, function(o) { self.map_account_id_code[o.id] = o.code });
2445+ });
2446+
2447+ // Create a dict tax id -> amount
2448+ new instance.web.Model("account.tax")
2449+ .query(['id', 'amount'])
2450+ .all().then(function(data) {
2451+ _.each(data, function(o) { self.map_tax_id_amount[o.id] = o.amount });
2452+ });
2453+
2454+ new instance.web.Model("ir.model.data")
2455+ .call("xmlid_to_res_id", ["account.menu_bank_reconcile_bank_statements"])
2456+ .then(function(data) {
2457+ self.reconciliation_menu_id = data;
2458+ self.doReloadMenuReconciliation();
2459+ });
2460+
2461+ // Bind keyboard events TODO : méthode standard ?
2462+ $("body").on("keypress", function (e) {
2463+ self.keyboardShortcutsHandler(e);
2464+ });
2465+
2466+ // Render and display
2467+ self.$el.prepend(QWeb.render("bank_statement_reconciliation", {title: self.title, total_lines: self.already_reconciled_lines+self.st_lines.length}));
2468+ self.updateProgressbar();
2469+ var reconciliations_to_show = self.st_lines.slice(0, self.max_reconciliations_displayed);
2470+ self.last_displayed_reconciliation_index = reconciliations_to_show.length;
2471+ self.$(".reconciliation_lines_container").css("opacity", 0);
2472+
2473+ // Display the reconciliations
2474+ return self.model_bank_statement_line
2475+ .call("get_data_for_reconciliations", [reconciliations_to_show])
2476+ .then(function (data) {
2477+ var child_promises = [];
2478+ _.each(reconciliations_to_show, function(st_line_id){
2479+ var datum = data.shift();
2480+ child_promises.push(self.displayReconciliation(st_line_id, 'inactive', false, true, datum.st_line, datum.reconciliation_proposition));
2481+ });
2482+ $.when.apply($, child_promises).then(function(){
2483+ self.getChildren()[0].set("mode", "match");
2484+ self.$(".reconciliation_lines_container").animate({opacity: 1}, self.aestetic_animation_speed);
2485+ });
2486+ });
2487+ });
2488+ },
2489+
2490+ keyboardShortcutsHandler: function(e) {
2491+ var self = this;
2492+ if (e.which === 13 && (e.ctrlKey || e.metaKey)) {
2493+ $.each(self.getChildren(), function(i, o){
2494+ if (o.is_valid && o.persistAndDestroy()) {
2495+ self.lines_reconciled_with_ctrl_enter++;
2496+ }
2497+ });
2498+ }
2499+ },
2500+
2501+ // Adds move line ids to the list of move lines not to fetch for a given partner
2502+ // This is required because the same move line cannot be selected for multiple reconciliation
2503+ excludeMoveLines: function(source_child, partner_id, line_ids) {
2504+ var self = this;
2505+
2506+ var excluded_ids = this.excluded_move_lines_ids[partner_id];
2507+ var excluded_move_lines_changed = false;
2508+ _.each(line_ids, function(line_id){
2509+ if (excluded_ids.indexOf(line_id) === -1) {
2510+ excluded_ids.push(line_id);
2511+ excluded_move_lines_changed = true;
2512+ }
2513+ });
2514+ if (! excluded_move_lines_changed)
2515+ return;
2516+
2517+ // Function that finds if an array of line objects contains at least a line identified by its id
2518+ var contains_lines = function(lines_array, line_ids) {
2519+ for (var i = 0; i < lines_array.length; i++)
2520+ for (var j = 0; j < line_ids.length; j++)
2521+ if (lines_array[i].id === line_ids[j])
2522+ return true;
2523+ return false;
2524+ };
2525+
2526+ // Update children if needed
2527+ _.each(self.getChildren(), function(child){
2528+ if (child.partner_id === partner_id && child !== source_child) {
2529+ if (contains_lines(child.get("mv_lines_selected"), line_ids)) {
2530+ child.set("mv_lines_selected", _.filter(child.get("mv_lines_selected"), function(o){ return line_ids.indexOf(o.id) === -1 }));
2531+ } else if (contains_lines(child.mv_lines_deselected, line_ids)) {
2532+ child.mv_lines_deselected = _.filter(child.mv_lines_deselected, function(o){ return line_ids.indexOf(o.id) === -1 });
2533+ child.updateMatches();
2534+ } else if (contains_lines(child.get("mv_lines"), line_ids)) {
2535+ child.updateMatches();
2536+ }
2537+ }
2538+ });
2539+ },
2540+
2541+ unexcludeMoveLines: function(source_child, partner_id, line_ids) {
2542+ var self = this;
2543+
2544+ var initial_excluded_lines_num = this.excluded_move_lines_ids[partner_id].length;
2545+ this.excluded_move_lines_ids[partner_id] = _.difference(this.excluded_move_lines_ids[partner_id], line_ids);
2546+ if (this.excluded_move_lines_ids[partner_id].length === initial_excluded_lines_num)
2547+ return;
2548+
2549+ // Update children if needed
2550+ _.each(self.getChildren(), function(child){
2551+ if (child.partner_id === partner_id && child !== source_child && (child.get("mode") === "match" || child.$el.hasClass("no_match")))
2552+ child.updateMatches();
2553+ });
2554+ },
2555+
2556+ displayReconciliation: function(st_line_id, mode, animate_entrance, initial_data_provided, st_line, reconciliation_proposition) {
2557+ var self = this;
2558+ animate_entrance = (animate_entrance === undefined ? true : animate_entrance);
2559+ initial_data_provided = (initial_data_provided === undefined ? false : initial_data_provided);
2560+
2561+ var context = {
2562+ st_line_id: st_line_id,
2563+ mode: mode,
2564+ animate_entrance: animate_entrance,
2565+ initial_data_provided: initial_data_provided,
2566+ st_line: initial_data_provided ? st_line : undefined,
2567+ reconciliation_proposition: initial_data_provided ? reconciliation_proposition : undefined,
2568+ };
2569+ var widget = new instance.web.account.bankStatementReconciliationLine(self, context);
2570+ return widget.appendTo(self.$(".reconciliation_lines_container"));
2571+ },
2572+
2573+ childValidated: function(child) {
2574+ var self = this;
2575+
2576+ self.reconciled_lines++;
2577+ self.updateProgressbar();
2578+ self.doReloadMenuReconciliation();
2579+
2580+ // Display new line if there are left
2581+ if (self.last_displayed_reconciliation_index < self.st_lines.length) {
2582+ self.displayReconciliation(self.st_lines[self.last_displayed_reconciliation_index++], 'inactive');
2583+ }
2584+ // Put the first line in match mode
2585+ if (self.reconciled_lines !== self.st_lines.length) {
2586+ var first_child = self.getChildren()[0];
2587+ if (first_child.get("mode") === "inactive") {
2588+ first_child.set("mode", "match");
2589+ }
2590+ }
2591+ // Congratulate the user if the work is done
2592+ if (self.reconciled_lines === self.st_lines.length) {
2593+ self.displayDoneMessage();
2594+ }
2595+ },
2596+
2597+ displayDoneMessage: function() {
2598+ var self = this;
2599+
2600+ var sec_taken = Math.round((Date.now()-self.time_widget_loaded)/1000);
2601+ var sec_per_item = Math.round(sec_taken/self.reconciled_lines);
2602+ var achievements = [];
2603+
2604+ var time_taken;
2605+ if (sec_taken/60 >= 1) time_taken = Math.floor(sec_taken/60) +"' "+ sec_taken%60 +"''";
2606+ else time_taken = sec_taken%60 +" seconds";
2607+
2608+ var title;
2609+ if (sec_per_item < 5) title = _t("Whew, that was fast !") + " <i class='fa fa-trophy congrats_icon'></i>";
2610+ else title = _t("Congrats, you're all done !") + " <i class='fa fa-thumbs-o-up congrats_icon'></i>";
2611+
2612+ if (self.lines_reconciled_with_ctrl_enter === self.reconciled_lines)
2613+ achievements.push({
2614+ title: _t("Efficiency at its finest"),
2615+ desc: _t("Only use the ctrl-enter shortcut to validate reconciliations."),
2616+ icon: "fa-keyboard-o"}
2617+ );
2618+
2619+ if (sec_per_item < 5)
2620+ achievements.push({
2621+ title: _t("Fast reconciler"),
2622+ desc: _t("Take on average less than 5 seconds to reconcile a transaction."),
2623+ icon: "fa-bolt"}
2624+ );
2625+
2626+ // Render it
2627+ self.$(".protip").hide();
2628+ self.$(".oe_form_sheet").append(QWeb.render("bank_statement_reconciliation_done_message", {
2629+ title: title,
2630+ time_taken: time_taken,
2631+ sec_per_item: sec_per_item,
2632+ transactions_done: self.reconciled_lines,
2633+ done_with_ctrl_enter: self.lines_reconciled_with_ctrl_enter,
2634+ achievements: achievements,
2635+ has_statement_id: self.statement_id !== undefined,
2636+ }));
2637+
2638+ // Animate it
2639+ var container = $("<div style='overflow: hidden;' />");
2640+ self.$(".done_message").wrap(container).css("opacity", 0).css("position", "relative").css("left", "-50%");
2641+ self.$(".done_message").animate({opacity: 1, left: 0}, self.aestetic_animation_speed*2, "easeOutCubic");
2642+ self.$(".done_message").animate({opacity: 1}, self.aestetic_animation_speed*3, "easeOutCubic");
2643+
2644+ // Make it interactive
2645+ self.$(".achievement").popover({'placement': 'top', 'container': self.el, 'trigger': 'hover'});
2646+
2647+ self.$(".button_back_to_statement").click(function() {
2648+ self.do_action({
2649+ type: 'ir.actions.client',
2650+ tag: 'history_back',
2651+ });
2652+ });
2653+
2654+ if (self.$(".button_close_statement").length !== 0) {
2655+ self.$(".button_close_statement").hide();
2656+ self.model_bank_statement
2657+ .query(["balance_end_real", "balance_end"])
2658+ .filter([['id', '=', self.statement_id]])
2659+ .first()
2660+ .then(function(data){
2661+ if (data.balance_end_real === data.balance_end) {
2662+ self.$(".button_close_statement").show();
2663+ self.$(".button_close_statement").click(function() {
2664+ self.$(".button_close_statement").attr("disabled", "disabled");
2665+ self.model_bank_statement
2666+ .call("button_confirm_bank", [[self.statement_id]])
2667+ .then(function () {
2668+ self.do_action({
2669+ type: 'ir.actions.client',
2670+ tag: 'history_back',
2671+ });
2672+ }, function() {
2673+ self.$(".button_close_statement").removeAttr("disabled");
2674+ });
2675+ });
2676+ }
2677+ });
2678+ }
2679+ },
2680+
2681+ updateProgressbar: function() {
2682+ var self = this;
2683+ var done = self.already_reconciled_lines + self.reconciled_lines;
2684+ var total = self.already_reconciled_lines + self.st_lines.length;
2685+ var prog_bar = self.$(".progress .progress-bar");
2686+ prog_bar.attr("aria-valuenow", done);
2687+ prog_bar.css("width", (done/total*100)+"%");
2688+ self.$(".progress .progress-text .valuenow").text(done);
2689+ },
2690+
2691+ /* reloads the needaction badge */
2692+ doReloadMenuReconciliation: function () {
2693+ var menu = instance.webclient.menu;
2694+ if (!menu || !this.reconciliation_menu_id) {
2695+ return $.when();
2696+ }
2697+ return menu.rpc("/web/menu/load_needaction", {'menu_ids': [this.reconciliation_menu_id]}).done(function(r) {
2698+ menu.on_needaction_loaded(r);
2699+ }).then(function () {
2700+ menu.trigger("need_action_reloaded");
2701+ });
2702+ },
2703+ });
2704+
2705+ instance.web.account.bankStatementReconciliationLine = instance.web.Widget.extend({
2706+ className: 'oe_bank_statement_reconciliation_line',
2707+
2708+ events: {
2709+ "click .partner_name": "partnerNameClickHandler",
2710+ "click .button_ok": "persistAndDestroy",
2711+ "click .mv_line": "moveLineClickHandler",
2712+ "click .initial_line": "initialLineClickHandler",
2713+ "click .line_open_balance": "lineOpenBalanceClickHandler",
2714+ "click .pager_control_left:not(.disabled)": "pagerControlLeftHandler",
2715+ "click .pager_control_right:not(.disabled)": "pagerControlRightHandler",
2716+ "keyup .filter": "filterHandler",
2717+ "click .line_info_button": function(e){e.stopPropagation()}, // small usability hack
2718+ "click .add_line": "addLineBeingEdited",
2719+ "click .preset": "presetClickHandler",
2720+ "click .do_partial_reconcile_button": "doPartialReconcileButtonClickHandler",
2721+ "click .undo_partial_reconcile_button": "undoPartialReconcileButtonClickHandler",
2722+ },
2723+
2724+ init: function(parent, context) {
2725+ this._super(parent);
2726+
2727+ if (context.initial_data_provided) {
2728+ // Process data
2729+ _(context.reconciliation_proposition).each(this.decorateMoveLine.bind(this));
2730+ this.set("mv_lines_selected", context.reconciliation_proposition);
2731+ this.st_line = context.st_line;
2732+ this.partner_id = context.st_line.partner_id;
2733+ this.decorateStatementLine(this.st_line);
2734+
2735+ // Exclude selected move lines
2736+ var selected_line_ids = _(context.reconciliation_proposition).map(function(o){ return o.id });
2737+ if (this.getParent().excluded_move_lines_ids[this.partner_id] === undefined)
2738+ this.getParent().excluded_move_lines_ids[this.partner_id] = [];
2739+ this.getParent().excludeMoveLines(this, this.partner_id, selected_line_ids);
2740+ } else {
2741+ this.set("mv_lines_selected", []);
2742+ this.st_line = undefined;
2743+ this.partner_id = undefined;
2744+ }
2745+
2746+ this.context = context;
2747+ this.st_line_id = context.st_line_id;
2748+ this.max_move_lines_displayed = this.getParent().max_move_lines_displayed;
2749+ this.animation_speed = this.getParent().animation_speed;
2750+ this.aestetic_animation_speed = this.getParent().aestetic_animation_speed;
2751+ this.model_bank_statement_line = new instance.web.Model("account.bank.statement.line");
2752+ this.model_res_users = new instance.web.Model("res.users");
2753+ this.model_tax = new instance.web.Model("account.tax");
2754+ this.map_account_id_code = this.getParent().map_account_id_code;
2755+ this.map_tax_id_amount = this.getParent().map_tax_id_amount;
2756+ this.formatCurrency = this.getParent().formatCurrency;
2757+ this.presets = this.getParent().presets;
2758+ this.is_valid = true;
2759+ this.is_consistent = true; // Used to prevent bad server requests
2760+ this.total_move_lines_num = undefined; // Used for pagers
2761+ this.filter = "";
2762+
2763+ this.set("balance", undefined); // Debit is +, credit is -
2764+ this.on("change:balance", this, this.balanceChanged);
2765+ this.set("mode", undefined);
2766+ this.on("change:mode", this, this.modeChanged);
2767+ this.set("pager_index", 0);
2768+ this.on("change:pager_index", this, this.pagerChanged);
2769+ // NB : mv_lines represent the counterpart that will be created to reconcile existing move lines, so debit and credit are inverted
2770+ this.set("mv_lines", []);
2771+ this.on("change:mv_lines", this, this.mvLinesChanged);
2772+ this.mv_lines_deselected = []; // deselected lines are displayed on top of the match table
2773+ this.on("change:mv_lines_selected", this, this.mvLinesSelectedChanged);
2774+ this.set("lines_created", []);
2775+ this.set("line_created_being_edited", [{'id': 0}]);
2776+ this.on("change:lines_created", this, this.createdLinesChanged);
2777+ this.on("change:line_created_being_edited", this, this.createdLinesChanged);
2778+ },
2779+
2780+ start: function() {
2781+ var self = this;
2782+ return self._super().then(function() {
2783+ // no animation while loading
2784+ self.animation_speed = 0;
2785+ self.aestetic_animation_speed = 0;
2786+
2787+ self.is_consistent = false;
2788+ if (self.context.animate_entrance) self.$el.css("opacity", "0");
2789+
2790+ // Fetch data
2791+ var deferred_fetch_data = new $.Deferred();
2792+ if (! self.context.initial_data_provided) {
2793+ // Load statement line
2794+ self.model_bank_statement_line
2795+ .call("get_statement_line_for_reconciliation", [self.st_line_id])
2796+ .then(function (data) {
2797+ self.st_line = data;
2798+ self.decorateStatementLine(self.st_line);
2799+ self.partner_id = data.partner_id;
2800+ if (self.getParent().excluded_move_lines_ids[self.partner_id] === undefined)
2801+ self.getParent().excluded_move_lines_ids[self.partner_id] = [];
2802+ // load and display move lines
2803+ $.when(self.loadReconciliationProposition()).then(function(){
2804+ deferred_fetch_data.resolve();
2805+ });
2806+ });
2807+ } else {
2808+ deferred_fetch_data.resolve();
2809+ }
2810+
2811+ // Display the widget
2812+ return $.when(deferred_fetch_data).then(function(){
2813+ // Render template
2814+ var presets_array = [];
2815+ for (var id in self.presets)
2816+ if (self.presets.hasOwnProperty(id))
2817+ presets_array.push(self.presets[id]);
2818+ self.$el.prepend(QWeb.render("bank_statement_reconciliation_line", {line: self.st_line, mode: self.context.mode, presets: presets_array}));
2819+
2820+ // Stuff that require the template to be rendered
2821+ self.$(".match").slideUp(0);
2822+ self.$(".create").slideUp(0);
2823+ if (self.st_line.no_match) self.$el.addClass("no_match");
2824+ if (self.context.mode !== "match") self.updateMatches();
2825+ self.bindPopoverTo(self.$(".line_info_button"));
2826+ self.createFormWidgets();
2827+
2828+ // Special case hack : no identified partner
2829+ if (self.st_line.has_no_partner) {
2830+ self.$el.css("opacity", "0");
2831+ self.updateBalance();
2832+ self.$(".change_partner_container").show(0);
2833+ self.change_partner_field.$el.find("input").attr("placeholder", _t("Select Partner"));
2834+ self.$(".match").slideUp(0);
2835+ self.$el.addClass("no_partner");
2836+ self.set("mode", self.context.mode);
2837+ self.animation_speed = self.getParent().animation_speed;
2838+ self.aestetic_animation_speed = self.getParent().aestetic_animation_speed;
2839+ self.$el.animate({opacity: 1}, self.aestetic_animation_speed);
2840+ self.is_consistent = true;
2841+ return;
2842+ }
2843+
2844+ // TODO : the .on handler's returned deferred is lost
2845+ return $.when(self.set("mode", self.context.mode)).then(function(){
2846+ self.is_consistent = true;
2847+
2848+ // Make sure the display is OK
2849+ self.balanceChanged();
2850+ self.createdLinesChanged();
2851+ self.updateAccountingViewMatchedLines();
2852+
2853+ // Make an entrance
2854+ self.animation_speed = self.getParent().animation_speed;
2855+ self.aestetic_animation_speed = self.getParent().aestetic_animation_speed;
2856+ if (self.context.animate_entrance) return self.$el.animate({opacity: 1}, self.aestetic_animation_speed);
2857+ });
2858+ });
2859+ });
2860+ },
2861+
2862+ restart: function(mode) {
2863+ var self = this;
2864+ mode = (mode === undefined ? 'inactive' : mode);
2865+ self.$el.css("height", self.$el.outerHeight());
2866+ // Destroy everything
2867+ _.each(self.getChildren(), function(o){ o.destroy() });
2868+ self.is_consistent = false;
2869+ return $.when(self.$el.animate({opacity: 0}, self.animation_speed)).then(function() {
2870+ self.getParent().unexcludeMoveLines(self, self.partner_id, _.map(self.get("mv_lines_selected"), function(o){ return o.id }));
2871+ $.each(self.$(".bootstrap_popover"), function(){ $(this).popover('destroy') });
2872+ self.$el.empty();
2873+ self.$el.removeClass("no_partner");
2874+ self.context.mode = mode;
2875+ self.context.initial_data_provided = false;
2876+ self.is_valid = true;
2877+ self.is_consistent = true;
2878+ self.filter = "";
2879+ self.set("balance", undefined, {silent: true});
2880+ self.set("mode", undefined, {silent: true});
2881+ self.set("pager_index", 0, {silent: true});
2882+ self.set("mv_lines", [], {silent: true});
2883+ self.set("mv_lines_selected", [], {silent: true});
2884+ self.mv_lines_deselected = [];
2885+ self.set("lines_created", [], {silent: true});
2886+ self.set("line_created_being_edited", [{'id': 0}], {silent: true});
2887+ // Rebirth
2888+ return $.when(self.start()).then(function() {
2889+ self.$el.css("height", "auto");
2890+ self.is_consistent = true;
2891+ self.$el.animate({opacity: 1}, self.animation_speed);
2892+ });
2893+ });
2894+ },
2895+
2896+ /* create form widgets, append them to the dom and bind their events handlers */
2897+ createFormWidgets: function() {
2898+ var self = this;
2899+ var create_form_fields = self.getParent().create_form_fields;
2900+ var create_form_fields_arr = [];
2901+ for (var key in create_form_fields)
2902+ if (create_form_fields.hasOwnProperty(key))
2903+ create_form_fields_arr.push(create_form_fields[key]);
2904+ create_form_fields_arr.sort(function(a, b){ return b.index - a.index });
2905+
2906+ // field_manager
2907+ var dataset = new instance.web.DataSet(this, "account.account", self.context);
2908+ dataset.ids = [];
2909+ dataset.arch = {
2910+ attrs: { string: "Stéphanie de Monaco", version: "7.0", class: "oe_form_container" },
2911+ children: [],
2912+ tag: "form"
2913+ };
2914+
2915+ var field_manager = new instance.web.FormView (
2916+ this, dataset, false, {
2917+ initial_mode: 'edit',
2918+ disable_autofocus: false,
2919+ $buttons: $(),
2920+ $pager: $()
2921+ });
2922+
2923+ field_manager.load_form(dataset);
2924+
2925+ // fields default properties
2926+ var Default_field = function() {
2927+ this.context = {};
2928+ this.domain = [];
2929+ this.help = "";
2930+ this.readonly = false;
2931+ this.required = true;
2932+ this.selectable = true;
2933+ this.states = {};
2934+ this.views = {};
2935+ };
2936+ var Default_node = function(field_name) {
2937+ this.tag = "field";
2938+ this.children = [];
2939+ this.required = true;
2940+ this.attrs = {
2941+ invisible: "False",
2942+ modifiers: '{"required":true}',
2943+ name: field_name,
2944+ nolabel: "True",
2945+ };
2946+ };
2947+
2948+ // Append fields to the field_manager
2949+ field_manager.fields_view.fields = {};
2950+ for (var i=0; i<create_form_fields_arr.length; i++) {
2951+ field_manager.fields_view.fields[create_form_fields_arr[i].id] = _.extend(new Default_field(), create_form_fields_arr[i].field_properties);
2952+ }
2953+ field_manager.fields_view.fields["change_partner"] = _.extend(new Default_field(), {
2954+ relation: "res.partner",
2955+ string: _t("Partner"),
2956+ type: "many2one",
2957+ domain: [['parent_id','=',false], '|', ['customer','=',true], ['supplier','=',true]],
2958+ });
2959+
2960+ // Returns a function that serves as a xhr response handler
2961+ var hideGroupResponseClosureFactory = function(field_widget, $container, obj_key){
2962+ return function(has_group){
2963+ if (has_group) $container.show();
2964+ else {
2965+ field_widget.destroy();
2966+ $container.remove();
2967+ delete self[obj_key];
2968+ }
2969+ };
2970+ };
2971+
2972+ // generate the create "form"
2973+ self.create_form = [];
2974+ for (var i=0; i<create_form_fields_arr.length; i++) {
2975+ var field_data = create_form_fields_arr[i];
2976+
2977+ // create widgets
2978+ var node = new Default_node(field_data.id);
2979+ if (! field_data.required) node.attrs.modifiers = "";
2980+ var field = new field_data.constructor(field_manager, node);
2981+ self[field_data.id+"_field"] = field;
2982+ self.create_form.push(field);
2983+
2984+ // on update : change the last created line
2985+ field.corresponding_property = field_data.corresponding_property;
2986+ field.on("change:value", self, self.formCreateInputChanged);
2987+
2988+ // append to DOM
2989+ var $field_container = $(QWeb.render("form_create_field", {id: field_data.id, label: field_data.label}));
2990+ field.appendTo($field_container.find("td"));
2991+ self.$(".create_form").prepend($field_container);
2992+
2993+ // now that widget's dom has been created (appendTo does that), bind events and adds tabindex
2994+ if (field_data.field_properties.type != "many2one") {
2995+ // Triggers change:value TODO : moche bind ?
2996+ field.$el.find("input").keyup(function(e, field){ field.commit_value(); }.bind(null, null, field));
2997+ }
2998+ field.$el.find("input").attr("tabindex", field_data.tabindex);
2999+
3000+ // Hide the field if group not OK
3001+ if (field_data.group !== undefined) {
3002+ var target = $field_container;
3003+ target.hide();
3004+ self.model_res_users
3005+ .call("has_group", [field_data.group])
3006+ .then(hideGroupResponseClosureFactory(field, target, (field_data.id+"_field")));
3007+ }
3008+ }
3009+
3010+ // generate the change partner "form"
3011+ var change_partner_node = new Default_node("change_partner"); change_partner_node.attrs.modifiers = "";
3012+ self.change_partner_field = new instance.web.form.FieldMany2One(field_manager, change_partner_node);
3013+ self.change_partner_field.appendTo(self.$(".change_partner_container"));
3014+ self.change_partner_field.on("change:value", self.change_partner_field, function() {
3015+ self.changePartner(this.get_value());
3016+ });
3017+
3018+ field_manager.do_show();
3019+ },
3020+
3021+ /** Utils */
3022+
3023+ /* TODO : if t-call for attr, all in qweb */
3024+ decorateStatementLine: function(line){
3025+ line.q_popover = QWeb.render("bank_statement_reconciliation_line_details", {line: line});
3026+ },
3027+
3028+ // adds fields, prefixed with q_, to the move line for qweb rendering
3029+ decorateMoveLine: function(line){
3030+ line.partial_reconcile = false;
3031+ line.propose_partial_reconcile = false;
3032+ line.q_due_date = (line.date_maturity === false ? line.date : line.date_maturity);
3033+ line.q_amount = (line.debit !== 0 ? "- "+line.q_debit : "") + (line.credit !== 0 ? line.q_credit : "");
3034+ line.q_popover = QWeb.render("bank_statement_reconciliation_move_line_details", {line: line});
3035+ line.q_label = line.name;
3036+
3037+ // WARNING : pretty much of a ugly hack
3038+ // The value of account_move.ref is either the move's communication or it's name without the slashes
3039+ if (line.ref && line.ref !== line.name.replace(/\//g,''))
3040+ line.q_label += " : " + line.ref;
3041+ },
3042+
3043+ bindPopoverTo: function(el) {
3044+ var self = this;
3045+ $(el).addClass("bootstrap_popover");
3046+ el.popover({
3047+ 'placement': 'left',
3048+ 'container': self.el,
3049+ 'html': true,
3050+ 'trigger': 'hover',
3051+ 'animation': false,
3052+ 'toggle': 'popover'
3053+ });
3054+ },
3055+
3056+ islineCreatedBeingEditedValid: function() {
3057+ var line = this.get("line_created_being_edited")[0];
3058+ return line.amount // must be defined and not 0
3059+ && line.account_id // must be defined (and will never be 0)
3060+ && line.label; // must be defined and not empty
3061+ },
3062+
3063+ /* returns the created lines, plus the ones being edited if valid */
3064+ getCreatedLines: function() {
3065+ var self = this;
3066+ var created_lines = self.get("lines_created").slice();
3067+ if (self.islineCreatedBeingEditedValid())
3068+ return created_lines.concat(self.get("line_created_being_edited"));
3069+ else
3070+ return created_lines;
3071+ },
3072+
3073+ /** Matching */
3074+
3075+ moveLineClickHandler: function(e) {
3076+ var self = this;
3077+ if (e.currentTarget.dataset.selected === "true") self.deselectMoveLine(e.currentTarget);
3078+ else self.selectMoveLine(e.currentTarget);
3079+ },
3080+
3081+ // Takes a move line from the match view and adds it to the mv_lines_selected array
3082+ selectMoveLine: function(mv_line) {
3083+ var self = this;
3084+ var line_id = mv_line.dataset.lineid;
3085+
3086+ // find the line in mv_lines or mv_lines_deselected
3087+ var line = _.find(self.get("mv_lines"), function(o){ return o.id == line_id });
3088+ if (! line) {
3089+ line = _.find(self.mv_lines_deselected, function(o){ return o.id == line_id });
3090+ self.mv_lines_deselected = _.filter(self.mv_lines_deselected, function(o) { return o.id != line_id });
3091+ }
3092+ // If no line found, the view is probably not up to date to the model (asynchronous fun)
3093+ if (! line) return;
3094+
3095+ // Warn the user if he's selecting lines from both a payable and a receivable account
3096+ var last_selected_line = _.last(self.get("mv_lines_selected"));
3097+ if (last_selected_line && last_selected_line.account_type != line.account_type) {
3098+ // TODO : web client API
3099+ alert(_.str.sprintf(_t("You are selecting transactions from both a payable and a receivable account.\n\nIn order to proceed, you first need to deselect the %s transactions."), last_selected_line.account_type));
3100+ return;
3101+ }
3102+
3103+ self.set("mv_lines_selected", self.get("mv_lines_selected").concat(line));
3104+ },
3105+
3106+ // Removes a move line from the mv_lines_selected array
3107+ deselectMoveLine: function(mv_line) {
3108+ var self = this;
3109+ var line_id = mv_line.dataset.lineid;
3110+ var line = _.find(self.get("mv_lines_selected"), function(o) { return o.id == line_id });
3111+ // If no line found, the view is probably not up to date to the model (asynchronous fun)
3112+ if (! line) return;
3113+
3114+ // add the line to mv_lines_deselected and remove it from mv_lines_selected
3115+ self.mv_lines_deselected.unshift(line);
3116+ var mv_lines_selected = _.filter(self.get("mv_lines_selected"), function(o) { return o.id != line_id });
3117+
3118+ // remove partial reconciliation stuff if necessary
3119+ if (line.partial_reconcile === true) self.unpartialReconcileLine(line);
3120+ if (line.propose_partial_reconcile === true) line.propose_partial_reconcile = false;
3121+
3122+ self.$el.removeClass("no_match");
3123+ self.set("mode", "match");
3124+ self.set("mv_lines_selected", mv_lines_selected);
3125+ },
3126+
3127+
3128+ /** Matches pagination */
3129+
3130+ pagerControlLeftHandler: function() {
3131+ var self = this;
3132+ if (self.$(".pager_control_left").hasClass("disabled")) { return; /* shouldn't happen, anyway*/ }
3133+ if (self.total_move_lines_num < 0) { return; }
3134+ self.set("pager_index", self.get("pager_index")-1 );
3135+ },
3136+
3137+ pagerControlRightHandler: function() {
3138+ var self = this;
3139+ var new_index = self.get("pager_index")+1;
3140+ if (self.$(".pager_control_right").hasClass("disabled")) { return; /* shouldn't happen, anyway*/ }
3141+ if ((new_index * self.max_move_lines_displayed) >= self.total_move_lines_num) { return; }
3142+ self.set("pager_index", new_index );
3143+ },
3144+
3145+ filterHandler: function() {
3146+ var self = this;
3147+ self.set("pager_index", 0);
3148+ self.filter = self.$(".filter").val();
3149+ window.clearTimeout(self.apply_filter_timeout);
3150+ self.apply_filter_timeout = window.setTimeout(self.proxy('updateMatches'), 200);
3151+ },
3152+
3153+
3154+ /** Creating */
3155+
3156+ initializeCreateForm: function() {
3157+ var self = this;
3158+
3159+ _.each(self.create_form, function(field) {
3160+ field.set("value", false);
3161+ });
3162+ self.amount_field.set("value", -1*self.get("balance"));
3163+ self.account_id_field.focus();
3164+ },
3165+
3166+ addLineBeingEdited: function() {
3167+ var self = this;
3168+ if (! self.islineCreatedBeingEditedValid()) return;
3169+
3170+ self.set("lines_created", self.get("lines_created").concat(self.get("line_created_being_edited")));
3171+ // Add empty created line
3172+ var new_id = self.get("line_created_being_edited")[0].id + 1;
3173+ self.set("line_created_being_edited", [{'id': new_id}]);
3174+
3175+ self.initializeCreateForm();
3176+ },
3177+
3178+ removeLine: function($line) {
3179+ var self = this;
3180+ var line_id = $line.data("lineid");
3181+
3182+ // if deleting the created line that is being edited, validate it before
3183+ if (line_id === self.get("line_created_being_edited")[0].id) {
3184+ self.addLineBeingEdited();
3185+ }
3186+ self.set("lines_created", _.filter(self.get("lines_created"), function(o) { return o.id != line_id }));
3187+ self.amount_field.set("value", -1*self.get("balance"));
3188+ },
3189+
3190+ presetClickHandler: function(e) {
3191+ var self = this;
3192+ self.initializeCreateForm();
3193+ var preset = self.presets[e.currentTarget.dataset.presetid];
3194+ for (var key in preset) {
3195+ if (! preset.hasOwnProperty(key) || key === "amount") continue;
3196+ if (self.hasOwnProperty(key+"_field"))
3197+ self[key+"_field"].set_value(preset[key]);
3198+ }
3199+ var sign = self.amount_field.get_value() < 0 ? -1 : 1;
3200+ if (preset.amount && self.amount_field) {
3201+ if (preset.amount_type === "fixed")
3202+ self.amount_field.set_value(sign * preset.amount);
3203+ else if (preset.amount_type === "percentage_of_total")
3204+ self.amount_field.set_value(sign * self.st_line.amount * preset.amount / 100);
3205+ else if (preset.amount_type === "percentage_of_balance") {
3206+ self.amount_field.set_value(0);
3207+ self.updateBalance();
3208+ self.amount_field.set_value(sign * Math.abs(self.get("balance")) * preset.amount / 100);
3209+ }
3210+ }
3211+ },
3212+
3213+
3214+ /** Display */
3215+
3216+ initialLineClickHandler: function() {
3217+ var self = this;
3218+ if (self.get("mode") === "match") {
3219+ self.set("mode", "inactive");
3220+ } else {
3221+ self.set("mode", "match");
3222+ }
3223+ },
3224+
3225+ lineOpenBalanceClickHandler: function() {
3226+ var self = this;
3227+ if (self.get("mode") === "create") {
3228+ self.set("mode", "match");
3229+ } else {
3230+ self.set("mode", "create");
3231+ }
3232+ },
3233+
3234+ partnerNameClickHandler: function() {
3235+ var self = this;
3236+ self.$(".partner_name").hide();
3237+ self.change_partner_field.$el.find("input").attr("placeholder", self.st_line.partner_name);
3238+ self.$(".change_partner_container").show();
3239+ },
3240+
3241+
3242+ /** Views updating */
3243+
3244+ updateAccountingViewMatchedLines: function() {
3245+ var self = this;
3246+ $.each(self.$(".tbody_matched_lines .bootstrap_popover"), function(){ $(this).popover('destroy') });
3247+ self.$(".tbody_matched_lines").empty();
3248+
3249+ _(self.get("mv_lines_selected")).each(function(line){
3250+ var $line = $(QWeb.render("bank_statement_reconciliation_move_line", {line: line, selected: true}));
3251+ self.bindPopoverTo($line.find(".line_info_button"));
3252+ if (line.propose_partial_reconcile) self.bindPopoverTo($line.find(".do_partial_reconcile_button"));
3253+ if (line.partial_reconcile) self.bindPopoverTo($line.find(".undo_partial_reconcile_button"));
3254+ self.$(".tbody_matched_lines").append($line);
3255+ });
3256+ },
3257+
3258+ updateAccountingViewCreatedLines: function() {
3259+ var self = this;
3260+ $.each(self.$(".tbody_created_lines .bootstrap_popover"), function(){ $(this).popover('destroy') });
3261+ self.$(".tbody_created_lines").empty();
3262+
3263+ _(self.getCreatedLines()).each(function(line){
3264+ var $line = $(QWeb.render("bank_statement_reconciliation_created_line", {line: line}));
3265+ $line.find(".line_remove_button").click(function(){ self.removeLine($(this).closest(".created_line")) });
3266+ self.$(".tbody_created_lines").append($line);
3267+ if (line.no_remove_action) {
3268+ // Then the previous line's remove button deletes this line too
3269+ $line.hover(function(){ $(this).prev().addClass("active") },function(){ $(this).prev().removeClass("active") });
3270+ }
3271+ });
3272+ },
3273+
3274+ updateMatchView: function() {
3275+ var self = this;
3276+ var table = self.$(".match table");
3277+ var nothing_displayed = true;
3278+
3279+ // Display move lines
3280+ $.each(self.$(".match table .bootstrap_popover"), function(){ $(this).popover('destroy') });
3281+ table.empty();
3282+ var slice_start = self.get("pager_index") * self.max_move_lines_displayed;
3283+ var slice_end = (self.get("pager_index")+1) * self.max_move_lines_displayed;
3284+ _( _.filter(self.mv_lines_deselected, function(o){
3285+ return o.name.indexOf(self.filter) !== -1 || o.ref.indexOf(self.filter) !== -1 })
3286+ .slice(slice_start, slice_end)).each(function(line){
3287+ var $line = $(QWeb.render("bank_statement_reconciliation_move_line", {line: line, selected: false}));
3288+ self.bindPopoverTo($line.find(".line_info_button"));
3289+ table.append($line);
3290+ nothing_displayed = false;
3291+ });
3292+ _(self.get("mv_lines")).each(function(line){
3293+ var $line = $(QWeb.render("bank_statement_reconciliation_move_line", {line: line, selected: false}));
3294+ self.bindPopoverTo($line.find(".line_info_button"));
3295+ table.append($line);
3296+ nothing_displayed = false;
3297+ });
3298+ if (nothing_displayed)
3299+ table.append(QWeb.render("filter_no_match", {filter_str: self.filter}));
3300+ },
3301+
3302+ updatePagerControls: function() {
3303+ var self = this;
3304+
3305+ if (self.get("pager_index") === 0)
3306+ self.$(".pager_control_left").addClass("disabled");
3307+ else
3308+ self.$(".pager_control_left").removeClass("disabled");
3309+ if (self.total_move_lines_num <= ((self.get("pager_index")+1) * self.max_move_lines_displayed))
3310+ self.$(".pager_control_right").addClass("disabled");
3311+ else
3312+ self.$(".pager_control_right").removeClass("disabled");
3313+ },
3314+
3315+
3316+ /** Properties changed */
3317+
3318+ // Updates the validation button and the "open balance" line
3319+ balanceChanged: function() {
3320+ var self = this;
3321+ var balance = self.get("balance");
3322+
3323+ // Special case hack : no identified partner
3324+ if (self.st_line.has_no_partner) {
3325+ if (Math.abs(balance).toFixed(3) === "0.000") {
3326+ self.$(".button_ok").addClass("oe_highlight");
3327+ self.$(".button_ok").removeAttr("disabled");
3328+ self.$(".button_ok").text("OK");
3329+ self.is_valid = true;
3330+ } else {
3331+ self.$(".button_ok").removeClass("oe_highlight");
3332+ self.$(".button_ok").attr("disabled", "disabled");
3333+ self.$(".button_ok").text("OK");
3334+ self.is_valid = false;
3335+ }
3336+ return;
3337+ }
3338+
3339+ self.$(".tbody_open_balance").empty();
3340+ if (Math.abs(balance).toFixed(3) === "0.000") {
3341+ self.$(".button_ok").addClass("oe_highlight");
3342+ self.$(".button_ok").text("OK");
3343+ } else {
3344+ self.$(".button_ok").removeClass("oe_highlight");
3345+ self.$(".button_ok").text("Keep open");
3346+ var debit = (balance > 0 ? self.formatCurrency(balance) : "");
3347+ var credit = (balance < 0 ? self.formatCurrency(-1*balance) : "");
3348+ var $line = $(QWeb.render("bank_statement_reconciliation_line_open_balance", {debit: debit, credit: credit, account_code: self.map_account_id_code[self.st_line.open_balance_account_id]}));
3349+ self.$(".tbody_open_balance").append($line);
3350+ }
3351+ },
3352+
3353+ modeChanged: function() {
3354+ var self = this;
3355+
3356+ self.$(".action_pane.active").removeClass("active");
3357+
3358+ // Special case hack : if no_partner, either inactive or create
3359+ if (self.st_line.has_no_partner) {
3360+ if (self.get("mode") === "inactive") {
3361+ self.$(".match").slideUp(self.animation_speed);
3362+ self.$(".create").slideUp(self.animation_speed);
3363+ self.$(".toggle_match").removeClass("visible_toggle");
3364+ self.el.dataset.mode = "inactive";
3365+ } else {
3366+ self.initializeCreateForm();
3367+ self.$(".match").slideUp(self.animation_speed);
3368+ self.$(".create").slideDown(self.animation_speed);
3369+ self.$(".toggle_match").addClass("visible_toggle");
3370+ self.el.dataset.mode = "create";
3371+ }
3372+ return;
3373+ }
3374+
3375+ if (self.get("mode") === "inactive") {
3376+ self.$(".match").slideUp(self.animation_speed);
3377+ self.$(".create").slideUp(self.animation_speed);
3378+ self.el.dataset.mode = "inactive";
3379+
3380+ } else if (self.get("mode") === "match") {
3381+ return $.when(self.updateMatches()).then(function() {
3382+ if (self.$el.hasClass("no_match")) {
3383+ self.set("mode", "inactive");
3384+ return;
3385+ }
3386+ self.$(".match").slideDown(self.animation_speed);
3387+ self.$(".create").slideUp(self.animation_speed);
3388+ self.el.dataset.mode = "match";
3389+ });
3390+
3391+ } else if (self.get("mode") === "create") {
3392+ self.initializeCreateForm();
3393+ self.$(".match").slideUp(self.animation_speed);
3394+ self.$(".create").slideDown(self.animation_speed);
3395+ self.el.dataset.mode = "create";
3396+ }
3397+ },
3398+
3399+ pagerChanged: function() {
3400+ var self = this;
3401+ self.updateMatches();
3402+ },
3403+
3404+ mvLinesChanged: function() {
3405+ var self = this;
3406+ // If pager_index is out of range, set it to display the last page
3407+ if (self.get("pager_index") !== 0 && self.total_move_lines_num <= (self.get("pager_index") * self.max_move_lines_displayed)) {
3408+ self.set("pager_index", Math.ceil(self.total_move_lines_num/self.max_move_lines_displayed)-1);
3409+ }
3410+
3411+ // If there is no match to display, disable match view and pass in mode inactive
3412+ if (self.total_move_lines_num + self.mv_lines_deselected.length === 0 && self.filter === "") {
3413+ self.$el.addClass("no_match");
3414+ if (self.get("mode") === "match") {
3415+ self.set("mode", "inactive");
3416+ }
3417+ } else {
3418+ self.$el.removeClass("no_match");
3419+ }
3420+
3421+ self.updateMatchView();
3422+ self.updatePagerControls();
3423+ },
3424+
3425+ mvLinesSelectedChanged: function(elt, val) {
3426+ var self = this;
3427+
3428+ var added_lines_ids = _.map(_.difference(val.newValue, val.oldValue), function(o){ return o.id });
3429+ var removed_lines_ids = _.map(_.difference(val.oldValue, val.newValue), function(o){ return o.id });
3430+
3431+ self.getParent().excludeMoveLines(self, self.partner_id, added_lines_ids);
3432+ self.getParent().unexcludeMoveLines(self, self.partner_id, removed_lines_ids);
3433+
3434+ $.when(self.updateMatches()).then(function(){
3435+ self.updateAccountingViewMatchedLines();
3436+ self.updateBalance();
3437+ });
3438+ },
3439+
3440+ // Generic function for updating the line_created_being_edited
3441+ formCreateInputChanged: function(elt, val) {
3442+ var self = this;
3443+ var line_created_being_edited = self.get("line_created_being_edited");
3444+ line_created_being_edited[0][elt.corresponding_property] = val.newValue;
3445+
3446+ // Specific cases
3447+ if (elt === self.account_id_field)
3448+ line_created_being_edited[0].account_num = self.map_account_id_code[elt.get("value")];
3449+
3450+ // Update tax line
3451+ var deferred_tax = new $.Deferred();
3452+ if (elt === self.tax_id_field || elt === self.amount_field) {
3453+ var amount = self.amount_field.get("value");
3454+ var tax = self.map_tax_id_amount[self.tax_id_field.get("value")];
3455+ if (amount && tax) {
3456+ deferred_tax = $.when(self.model_tax
3457+ .call("compute_for_bank_reconciliation", [self.tax_id_field.get("value"), amount]))
3458+ .then(function(data){
3459+ var tax = data.taxes[0];
3460+ var tax_account_id = (amount > 0 ? tax.account_collected_id : tax.account_paid_id)
3461+ line_created_being_edited[0].amount = (data.total.toFixed(3) === amount.toFixed(3) ? amount : data.total);
3462+ line_created_being_edited[1] = {id: line_created_being_edited[0].id, account_id: tax_account_id, account_num: self.map_account_id_code[tax_account_id], label: tax.name, amount: tax.amount, no_remove_action: true};
3463+ }
3464+ );
3465+ } else {
3466+ line_created_being_edited[0].amount = amount;
3467+ delete line_created_being_edited[1];
3468+ deferred_tax.resolve();
3469+ }
3470+ } else { deferred_tax.resolve(); }
3471+
3472+ $.when(deferred_tax).then(function(){
3473+ // Format amounts
3474+ if (line_created_being_edited[0].amount)
3475+ line_created_being_edited[0].amount_str = self.formatCurrency(Math.abs(line_created_being_edited[0].amount));
3476+ if (line_created_being_edited[1] && line_created_being_edited[1].amount)
3477+ line_created_being_edited[1].amount_str = self.formatCurrency(Math.abs(line_created_being_edited[1].amount));
3478+
3479+ self.set("line_created_being_edited", line_created_being_edited);
3480+ self.createdLinesChanged(); // TODO For some reason, previous line doesn't trigger change handler
3481+ });
3482+ },
3483+
3484+ createdLinesChanged: function() {
3485+ var self = this;
3486+ self.updateAccountingViewCreatedLines();
3487+ self.updateBalance();
3488+
3489+ if (self.islineCreatedBeingEditedValid()) self.$(".add_line").show();
3490+ else self.$(".add_line").hide();
3491+ },
3492+
3493+
3494+ /** Model */
3495+
3496+ doPartialReconcileButtonClickHandler: function(e) {
3497+ var self = this;
3498+
3499+ var line_id = $(e.currentTarget).closest("tr").data("lineid");
3500+ var line = _.find(self.get("mv_lines_selected"), function(o) { return o.id == line_id });
3501+ self.partialReconcileLine(line);
3502+
3503+ $(e.currentTarget).popover('destroy');
3504+ self.updateAccountingViewMatchedLines();
3505+ self.updateBalance();
3506+ e.stopPropagation();
3507+ },
3508+
3509+ partialReconcileLine: function(line) {
3510+ var self = this;
3511+ var balance = self.get("balance");
3512+ line.initial_amount = line.debit !== 0 ? line.debit : -1 * line.credit;
3513+ if (balance < 0) {
3514+ line.debit -= balance;
3515+ line.debit_str = self.formatCurrency(line.debit);
3516+ } else {
3517+ line.credit -= balance;
3518+ line.credit_str = self.formatCurrency(line.credit);
3519+ }
3520+ line.propose_partial_reconcile = false;
3521+ line.partial_reconcile = true;
3522+ },
3523+
3524+ undoPartialReconcileButtonClickHandler: function(e) {
3525+ var self = this;
3526+
3527+ var line_id = $(e.currentTarget).closest("tr").data("lineid");
3528+ var line = _.find(self.get("mv_lines_selected"), function(o) { return o.id == line_id });
3529+ self.unpartialReconcileLine(line);
3530+
3531+ $(e.currentTarget).popover('destroy');
3532+ self.updateAccountingViewMatchedLines();
3533+ self.updateBalance();
3534+ e.stopPropagation();
3535+ },
3536+
3537+ unpartialReconcileLine: function(line) {
3538+ if (line.initial_amount > 0) {
3539+ line.debit = line.initial_amount;
3540+ line.debit_str = this.formatCurrency(line.debit);
3541+ } else {
3542+ line.credit = -1 * line.initial_amount;
3543+ line.credit_str = this.formatCurrency(line.credit);
3544+ }
3545+ line.propose_partial_reconcile = true;
3546+ line.partial_reconcile = false;
3547+ },
3548+
3549+ updateBalance: function() {
3550+ var self = this;
3551+ var mv_lines_selected = self.get("mv_lines_selected");
3552+ var balance = 0;
3553+ balance -= self.st_line.amount;
3554+ _.each(mv_lines_selected, function(o) {
3555+ balance = balance - o.debit + o.credit;
3556+ });
3557+ _.each(self.getCreatedLines(), function(o) {
3558+ balance += o.amount;
3559+ });
3560+ self.set("balance", balance);
3561+
3562+ // Propose partial reconciliation if necessary
3563+ var lines_selected_num = mv_lines_selected.length;
3564+ var lines_created_num = self.getCreatedLines().length;
3565+ if (lines_selected_num === 1 && lines_created_num === 0 && self.st_line.amount * balance > 0) {
3566+ mv_lines_selected[0].propose_partial_reconcile = true;
3567+ self.updateAccountingViewMatchedLines();
3568+ }
3569+ if (lines_selected_num !== 1 || lines_created_num !== 0) {
3570+ // remove partial reconciliation stuff if necessary
3571+ _.each(mv_lines_selected, function(line) {
3572+ if (line.partial_reconcile === true) self.unpartialReconcileLine(line);
3573+ if (line.propose_partial_reconcile === true) line.propose_partial_reconcile = false;
3574+ });
3575+ self.updateAccountingViewMatchedLines();
3576+ }
3577+ },
3578+
3579+ loadReconciliationProposition: function() {
3580+ var self = this;
3581+ return self.model_bank_statement_line
3582+ .call("get_reconciliation_proposition", [self.st_line.id, self.getParent().excluded_move_lines_ids[self.partner_id]])
3583+ .then(function (lines) {
3584+ _(lines).each(self.decorateMoveLine.bind(self));
3585+ self.set("mv_lines_selected", self.get("mv_lines_selected").concat(lines));
3586+ });
3587+ },
3588+
3589+ // Loads move lines according to the widget's state
3590+ updateMatches: function() {
3591+ var self = this;
3592+ var deselected_lines_num = self.mv_lines_deselected.length;
3593+ var move_lines = {};
3594+ var move_lines_num = 0;
3595+ var offset = self.get("pager_index") * self.max_move_lines_displayed - deselected_lines_num;
3596+ if (offset < 0) offset = 0;
3597+ var limit = (self.get("pager_index")+1) * self.max_move_lines_displayed - deselected_lines_num;
3598+ if (limit > self.max_move_lines_displayed) limit = self.max_move_lines_displayed;
3599+ var excluded_ids = _.collect(self.get("mv_lines_selected").concat(self.mv_lines_deselected), function(o){ return o.id });
3600+ excluded_ids = excluded_ids.concat(self.getParent().excluded_move_lines_ids[self.partner_id]);
3601+
3602+ var deferred_move_lines;
3603+ if (limit > 0) {
3604+ // Load move lines
3605+ deferred_move_lines = self.model_bank_statement_line
3606+ .call("get_move_lines_counterparts", [self.st_line.id, excluded_ids, self.filter, offset, limit])
3607+ .then(function (lines) {
3608+ _(lines).each(self.decorateMoveLine.bind(self));
3609+ move_lines = lines;
3610+ });
3611+ }
3612+
3613+ // Fetch the number of move lines corresponding to this statement line and this filter
3614+ var deferred_total_move_lines_num = self.model_bank_statement_line
3615+ .call("get_move_lines_counterparts", [self.st_line.id, excluded_ids, self.filter, offset, limit, true])
3616+ .then(function(num){
3617+ move_lines_num = num;
3618+ });
3619+
3620+ return $.when(deferred_move_lines, deferred_total_move_lines_num).then(function(){
3621+ self.total_move_lines_num = move_lines_num + deselected_lines_num;
3622+ self.set("mv_lines", move_lines);
3623+ });
3624+ },
3625+
3626+ // Changes the partner_id of the statement_line in the DB and reloads the widget
3627+ changePartner: function(partner_id) {
3628+ var self = this;
3629+ self.is_consistent = false;
3630+ return self.model_bank_statement_line
3631+ // Update model
3632+ .call("write", [[self.st_line_id], {'partner_id': partner_id}])
3633+ .then(function () {
3634+ return $.when(self.restart(self.get("mode"))).then(function(){
3635+ self.is_consistent = true;
3636+ });
3637+ });
3638+ },
3639+
3640+ // Returns an object that can be passed to process_reconciliation()
3641+ prepareSelectedMoveLineForPersisting: function(line) {
3642+ return {
3643+ name: line.name,
3644+ debit: line.debit,
3645+ credit: line.credit,
3646+ counterpart_move_line_id: line.id,
3647+ };
3648+ },
3649+
3650+ // idem
3651+ prepareCreatedMoveLineForPersisting: function(line) {
3652+ var dict = {};
3653+
3654+ if (dict['account_id'] === undefined)
3655+ dict['account_id'] = line.account_id;
3656+ dict['name'] = line.label;
3657+ if (line.amount > 0) dict['credit'] = line.amount;
3658+ if (line.amount < 0) dict['debit'] = -1*line.amount;
3659+ if (line.tax_id) dict['tax_code_id'] = line.tax_id;
3660+ if (line.analytic_account_id) dict['analytic_account_id'] = line.analytic_account_id;
3661+
3662+ return dict;
3663+ },
3664+
3665+ // idem
3666+ prepareOpenBalanceForPersisting: function() {
3667+ var balance = this.get("balance");
3668+ var dict = {};
3669+
3670+ dict['account_id'] = this.st_line.open_balance_account_id;
3671+ dict['name'] = _t("Open balance");
3672+ if (balance > 0) dict['debit'] = balance;
3673+ if (balance < 0) dict['credit'] = -1*balance;
3674+
3675+ return dict;
3676+ },
3677+
3678+ // Persist data, notify parent view and terminate widget
3679+ persistAndDestroy: function() {
3680+ var self = this;
3681+ if (! self.is_consistent) return;
3682+
3683+ self.getParent().unexcludeMoveLines(self, self.partner_id, _.map(self.get("mv_lines_selected"), function(o){ return o.id }));
3684+
3685+ // Prepare data
3686+ var mv_line_dicts = [];
3687+ _.each(self.get("mv_lines_selected"), function(o) { mv_line_dicts.push(self.prepareSelectedMoveLineForPersisting(o)) });
3688+ _.each(self.getCreatedLines(), function(o) { mv_line_dicts.push(self.prepareCreatedMoveLineForPersisting(o)) });
3689+ if (Math.abs(self.get("balance")).toFixed(3) !== "0.000") mv_line_dicts.push(self.prepareOpenBalanceForPersisting());
3690+
3691+ // Sliding animation
3692+ var height = self.$el.outerHeight();
3693+ var container = $("<div />");
3694+ container.css("height", height)
3695+ .css("marginTop", self.$el.css("marginTop"))
3696+ .css("marginBottom", self.$el.css("marginBottom"));
3697+ self.$el.wrap(container);
3698+ var deferred_animation = self.$el.parent().slideUp(self.animation_speed*height/150);
3699+
3700+ // RPC
3701+ return self.model_bank_statement_line
3702+ .call("process_reconciliation", [self.st_line_id, mv_line_dicts])
3703+ .then(function () {
3704+ $.each(self.$(".bootstrap_popover"), function(){ $(this).popover('destroy') });
3705+ return $.when(deferred_animation).then(function(){
3706+ self.$el.parent().remove();
3707+ var parent = self.getParent();
3708+ return $.when(self.destroy()).then(function() {
3709+ parent.childValidated(self);
3710+ });
3711+ });
3712+ }, function(){
3713+ self.$el.parent().slideDown(self.animation_speed*height/150, function(){
3714+ self.$el.unwrap();
3715+ });
3716+ });
3717+
3718+ },
3719+ });
3720+
3721 instance.web.views.add('tree_account_reconciliation', 'instance.web.account.ReconciliationListView');
3722 instance.web.account.ReconciliationListView = instance.web.ListView.extend({
3723 init: function() {
3724
3725=== added file 'account/static/src/xml/account_bank_statement_reconciliation.xml'
3726--- account/static/src/xml/account_bank_statement_reconciliation.xml 1970-01-01 00:00:00 +0000
3727+++ account/static/src/xml/account_bank_statement_reconciliation.xml 2014-05-30 16:18:57 +0000
3728@@ -0,0 +1,194 @@
3729+<?xml version="1.0" encoding="UTF-8"?>
3730+
3731+<templates xml:space="preserve">
3732+
3733+ <t t-name="bank_statement_nothing_to_reconcile">
3734+ <div class="oe_form_sheetbg"><div class="oe_form_sheet oe_form_sheet_width">
3735+ <div class="oe_view_nocontent"><p>
3736+ <b>Good Job!</b> Bank statements are fully reconciled.</p>
3737+ <p>This page displays all the bank transactions that are to be reconciled and provides with a neat interface to do so.</p>
3738+ </div>
3739+ </div></div>
3740+ </t>
3741+
3742+ <t t-name="bank_statement_reconciliation">
3743+ <div class="oe_form_sheetbg"><div class="oe_form_sheet oe_form_sheet_width">
3744+ <h1><t t-esc="title"/></h1>
3745+ <div class="progress progress-striped">
3746+ <div class="progress-text"><span class="valuenow">0</span> / <span class="valuemax"><t t-esc="total_lines"/></span></div>
3747+ <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" t-att-aria-valuemax="total_lines" style="width: 0%;">
3748+ </div>
3749+ </div>
3750+ <div class="oe_clear"></div>
3751+ <div class="reconciliation_lines_container"></div>
3752+ <p class='protip'>Tip : Hit ctrl-enter to validate the whole sheet.</p>
3753+ </div></div>
3754+ </t>
3755+
3756+ <t t-name="bank_statement_reconciliation_done_message">
3757+ <div class='done_message'>
3758+ <h2><t t-raw="title" /></h2>
3759+ <p>It took you <strong><t t-esc="time_taken" /></strong> to reconcile <strong><t t-esc="transactions_done" /> transactions.<br/></strong> That's on average <t t-esc="sec_per_item" /> seconds per transaction.</p>
3760+ <t t-if="done_with_ctrl_enter !== 0">
3761+ <p>You validated <t t-esc="done_with_ctrl_enter" /> reconciliations with the ctrl-enter shortcut.</p>
3762+ </t>
3763+ <p class='achievements'>
3764+ <t t-foreach="achievements" t-as="achievement">
3765+ <i class='fa fa-certificate achievement' t-att-data-title='achievement.title' t-att-data-content='achievement.desc'><i t-att-class="'fa '+achievement.icon"></i></i>
3766+ </t>
3767+ </p>
3768+ <p class="action_buttons">
3769+ <t t-if="has_statement_id">
3770+ <button class="button_back_to_statement">Back to statement</button>
3771+ <button class="button_close_statement">Close the statement</button>
3772+ </t>
3773+ </p>
3774+ </div>
3775+ </t>
3776+
3777+ <t t-name="bank_statement_reconciliation_line">
3778+ <table t-att-data-mode="mode">
3779+ <tr>
3780+ <td>
3781+ <table class="accounting_view">
3782+ <caption>
3783+ <button class="button_ok"></button>
3784+ <span class="partner_name"><t t-esc="line.partner_name"/></span>
3785+ <div class="change_partner_container oe_form"></div>
3786+ </caption>
3787+ <tbody class="tbody_initial_line">
3788+ <tr class="initial_line">
3789+ <td><span class="toggle_match glyphicon glyphicon-cog"></span></td>
3790+ <td><t t-esc="line.account_code"/></td>
3791+ <td><t t-esc="line.date"/></td>
3792+ <td><t t-esc="line.name"/>
3793+ <t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str"/>)</t></td>
3794+ <td><t t-if="line.amount &gt; 0">
3795+ <t t-esc="line.amount_str"/></t></td>
3796+ <td><t t-if="line.amount &lt; 0">
3797+ <t t-esc="line.amount_str"/></t></td>
3798+ <td><span class="line_info_button glyphicon glyphicon-info-sign" t-att-data-content="line.q_popover"></span></td>
3799+ </tr>
3800+ </tbody>
3801+ <tbody class="tbody_matched_lines"></tbody>
3802+ <tbody class="tbody_created_lines"></tbody>
3803+ <tbody class="tbody_open_balance"></tbody>
3804+ </table>
3805+ </td>
3806+ </tr>
3807+ <tr>
3808+ <td>
3809+ <div class="action_pane match">
3810+ <div class="match_controls">
3811+ <input type="text" class="filter" placeholder="Filter" value="" />
3812+ <span class="pager_control_right pull-right glyphicon glyphicon-chevron-right"></span>
3813+ <span class="pager_control_left pull-right glyphicon glyphicon-chevron-left"></span>
3814+ </div>
3815+ <table></table>
3816+ </div>
3817+
3818+ <div class="action_pane create">
3819+ <!-- NB : I use a .quick_add:empty selector. whitespace characters being a node, there shall be none -->
3820+ <div class="quick_add btn-group btn-group-sm"><t t-foreach="presets" t-as="preset"><button type='button' class='btn btn-default preset' t-att-data-presetid="preset.id"><t t-esc="preset.name"/></button></t></div>
3821+ <div class="oe_form create_form">
3822+ <!-- here come some form_create_field -->
3823+ <table class="create_field add_line_container"><tr><td><a href="javascript:void(0)" class="add_line">New</a></td></tr></table>
3824+ </div>
3825+ </div>
3826+ </td>
3827+ </tr>
3828+ </table>
3829+ </t>
3830+
3831+ <t t-name="filter_no_match">
3832+ <tr><td style='text-align: center;'>No result matching '<t t-esc="filter_str" />'</td></tr>
3833+ </t>
3834+
3835+ <t t-name="form_create_field">
3836+ <table t-att-class='"create_field create_"+id'><tr>
3837+ <th><t t-esc="label"/></th>
3838+ <td class="create_account_container" t-att-class='"create_"+id+"_container"'></td>
3839+ </tr></table>
3840+ </t>
3841+
3842+ <t t-name="bank_statement_reconciliation_line_details">
3843+ <table class='details'>
3844+ <tr><td>Date</td><td><t t-esc="line.date"/></td></tr>
3845+ <tr><td>Partner</td><td><t t-esc="line.partner_name"/></td></tr>
3846+ <tr t-if="line.ref"><td>Transaction</td><td><t t-esc="line.ref"/></td></tr>
3847+ <tr><td>Description</td><td><t t-esc="line.name"/></td></tr>
3848+ <tr><td>Amount</td><td><t t-esc="line.amount_str"/><t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str"/>)</t></td></tr>
3849+ <tr><td>Account</td><td><t t-esc="line.account_code"/> <t t-esc="line.account_name"/></td></tr>
3850+ </table>
3851+ </t>
3852+
3853+
3854+ <t t-name="bank_statement_reconciliation_move_line">
3855+ <tr class="mv_line" t-att-data-lineid="line.id" t-att-data-selected="selected">
3856+ <td><span class="glyphicon glyphicon-add-remove"></span></td>
3857+ <td><t t-esc="line.account_code"/></td>
3858+ <td><t t-esc="line.q_due_date"/></td>
3859+ <td><t t-esc="line.q_label"/></td>
3860+
3861+ <td><t t-if="line.debit !== 0">
3862+ <t t-if="line.propose_partial_reconcile" t-call="icon_do_partial_reconciliation"></t>
3863+ <t t-if="line.partial_reconcile" t-call="icon_undo_partial_reconciliation"></t>
3864+ <t t-esc="line.debit_str"/>
3865+ </t></td>
3866+ <td><t t-if="line.credit !== 0">
3867+ <t t-if="line.propose_partial_reconcile"><t t-call="icon_do_partial_reconciliation" /></t>
3868+ <t t-if="line.partial_reconcile"><t t-call="icon_undo_partial_reconciliation" /></t>
3869+ <t t-esc="line.credit_str"/>
3870+ </t></td>
3871+ <td><span class="line_info_button glyphicon glyphicon-info-sign" t-att-data-content="line.q_popover"></span></td>
3872+ </tr>
3873+ </t>
3874+
3875+ <t t-name="icon_do_partial_reconciliation">
3876+ <i class="do_partial_reconcile_button fa fa-exclamation-triangle" data-content="This move's amount is higher than the transaction's amount. Click to do a partial reconciliation"></i>
3877+ </t>
3878+
3879+ <t t-name="icon_undo_partial_reconciliation">
3880+ <i class="undo_partial_reconcile_button fa fa-exclamation-triangle" data-content="Undo the partial reconciliation."></i>
3881+ </t>
3882+
3883+ <t t-name="bank_statement_reconciliation_move_line_details">
3884+ <table class='details'>
3885+ <tr><td>ID</td><td><t t-esc="line.id"/></td></tr>
3886+ <tr><td>Account</td><td><t t-esc="line.account_code"/> <t t-esc="line.account_name"/></td></tr>
3887+ <tr><td>Journal</td><td><t t-esc="line.journal_name"/></td></tr>
3888+ <tr><td>Period</td><td><t t-esc="line.period_name"/></td></tr>
3889+ <tr><td>Date</td><td><t t-esc="line.date"/></td></tr>
3890+ <tr><td>Due Date</td><td><t t-esc="line.q_due_date"/></td></tr>
3891+ <tr><td>Amount</td>
3892+ <td><t t-if="line.debit !== 0" t-esc="line.debit_str"/><t t-if="line.credit !== 0" t-esc="line.credit_str"/>
3893+ <t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str"/>)</t>
3894+ </td></tr>
3895+ </table>
3896+ </t>
3897+
3898+
3899+ <t t-name="bank_statement_reconciliation_created_line">
3900+ <tr class="created_line" t-att-data-lineid="line.id">
3901+ <td><t t-if="! line.no_remove_action"><span class="line_remove_button glyphicon glyphicon-remove"></span></t></td>
3902+ <td><t t-esc="line.account_num"/></td>
3903+ <td></td>
3904+ <td><t t-esc="line.label"/></td>
3905+ <td><t t-if="line.amount &lt; 0"><t t-esc="line.amount_str"/></t></td>
3906+ <td><t t-if="line.amount &gt; 0"><t t-esc="line.amount_str"/></t></td>
3907+ <td></td>
3908+ </tr>
3909+ </t>
3910+
3911+ <t t-name="bank_statement_reconciliation_line_open_balance">
3912+ <tr class="line_open_balance">
3913+ <td><span class="toggle_create glyphicon glyphicon-play"></span></td>
3914+ <td><t t-esc="account_code"/></td>
3915+ <td></td>
3916+ <td>Open balance</td>
3917+ <td><t t-esc="debit"/></td>
3918+ <td><t t-esc="credit"/></td>
3919+ <td></td>
3920+ </tr>
3921+ </t>
3922+</templates>
3923
3924=== modified file 'account/views/account.xml'
3925--- account/views/account.xml 2014-04-24 17:21:29 +0000
3926+++ account/views/account.xml 2014-05-30 16:18:57 +0000
3927@@ -8,7 +8,8 @@
3928 <link rel="stylesheet" href="/account/static/src/css/account_move_reconciliation.css"/>
3929 <link rel="stylesheet" href="/account/static/src/css/account_move_line_quickadd.css"/>
3930 <link rel="stylesheet" href="/account/static/src/css/account_bank_and_cash.css"/>
3931- <script type="text/javascript" src="/account/static/src/js/account_move_reconciliation.js"></script>
3932+ <link rel="stylesheet" href="/account/static/src/css/account_bank_statement_reconciliation.css"/>
3933+ <script type="text/javascript" src="/account/static/src/js/account_widgets.js"></script>
3934 <script type="text/javascript" src="/account/static/src/js/account_move_line_quickadd.js"></script>
3935 </xpath>
3936 </template>
3937
3938=== modified file 'account/wizard/__init__.py'
3939--- account/wizard/__init__.py 2012-11-29 22:26:45 +0000
3940+++ account/wizard/__init__.py 2014-05-30 16:18:57 +0000
3941@@ -63,8 +63,6 @@
3942
3943 import account_change_currency
3944
3945-import pos_box;
3946-
3947+import pos_box
3948+import account_statement_from_invoice
3949 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
3950-
3951-
3952
3953=== renamed file 'account_voucher/wizard/account_statement_from_invoice.py' => 'account/wizard/account_statement_from_invoice.py'
3954--- account_voucher/wizard/account_statement_from_invoice.py 2014-02-12 17:51:41 +0000
3955+++ account/wizard/account_statement_from_invoice.py 2014-05-30 16:18:57 +0000
3956@@ -22,7 +22,6 @@
3957 import time
3958
3959 from openerp.osv import fields, osv
3960-from openerp.tools.translate import _
3961
3962 class account_statement_from_invoice_lines(osv.osv_memory):
3963 """
3964@@ -35,12 +34,13 @@
3965 }
3966
3967 def populate_statement(self, cr, uid, ids, context=None):
3968+ #TODO: can be moved in account module
3969 if context is None:
3970 context = {}
3971 statement_id = context.get('statement_id', False)
3972 if not statement_id:
3973 return {'type': 'ir.actions.act_window_close'}
3974- data = self.read(cr, uid, ids, context=context)[0]
3975+ data = self.read(cr, uid, ids, context=context)[0]
3976 line_ids = data['line_ids']
3977 if not line_ids:
3978 return {'type': 'ir.actions.act_window_close'}
3979@@ -49,14 +49,11 @@
3980 statement_obj = self.pool.get('account.bank.statement')
3981 statement_line_obj = self.pool.get('account.bank.statement.line')
3982 currency_obj = self.pool.get('res.currency')
3983- voucher_obj = self.pool.get('account.voucher')
3984- voucher_line_obj = self.pool.get('account.voucher.line')
3985 line_date = time.strftime('%Y-%m-%d')
3986 statement = statement_obj.browse(cr, uid, statement_id, context=context)
3987
3988 # for each selected move lines
3989 for line in line_obj.browse(cr, uid, line_ids, context=context):
3990- voucher_res = {}
3991 ctx = context.copy()
3992 # take the date for computation of currency => use payment date
3993 ctx['date'] = line_date
3994@@ -70,55 +67,19 @@
3995 if line.amount_currency:
3996 amount = currency_obj.compute(cr, uid, line.currency_id.id,
3997 statement.currency.id, line.amount_currency, context=ctx)
3998- elif (line.invoice and line.invoice.currency_id.id <> statement.currency.id):
3999+ elif (line.invoice and line.invoice.currency_id.id != statement.currency.id):
4000 amount = currency_obj.compute(cr, uid, line.invoice.currency_id.id,
4001 statement.currency.id, amount, context=ctx)
4002
4003 context.update({'move_line_ids': [line.id],
4004 'invoice_id': line.invoice.id})
4005- type = 'general'
4006- ttype = amount < 0 and 'payment' or 'receipt'
4007- sign = 1
4008- if line.journal_id.type in ('sale', 'sale_refund'):
4009- type = 'customer'
4010- ttype = 'receipt'
4011- elif line.journal_id.type in ('purchase', 'purhcase_refund'):
4012- type = 'supplier'
4013- ttype = 'payment'
4014- sign = -1
4015- result = voucher_obj.onchange_partner_id(cr, uid, [], partner_id=line.partner_id.id, journal_id=statement.journal_id.id, amount=sign*amount, currency_id= statement.currency.id, ttype=ttype, date=line_date, context=context)
4016- voucher_res = { 'type': ttype,
4017- 'name': line.name,
4018- 'partner_id': line.partner_id.id,
4019- 'journal_id': statement.journal_id.id,
4020- 'account_id': result['value'].get('account_id', statement.journal_id.default_credit_account_id.id),
4021- 'company_id': statement.company_id.id,
4022- 'currency_id': statement.currency.id,
4023- 'date': statement.date,
4024- 'amount': sign*amount,
4025- 'payment_rate': result['value']['payment_rate'],
4026- 'payment_rate_currency_id': result['value']['payment_rate_currency_id'],
4027- 'period_id':statement.period_id.id}
4028- voucher_id = voucher_obj.create(cr, uid, voucher_res, context=context)
4029-
4030- voucher_line_dict = {}
4031- for line_dict in result['value']['line_cr_ids'] + result['value']['line_dr_ids']:
4032- move_line = line_obj.browse(cr, uid, line_dict['move_line_id'], context)
4033- if line.move_id.id == move_line.move_id.id:
4034- voucher_line_dict = line_dict
4035-
4036- if voucher_line_dict:
4037- voucher_line_dict.update({'voucher_id': voucher_id})
4038- voucher_line_obj.create(cr, uid, voucher_line_dict, context=context)
4039+
4040 statement_line_obj.create(cr, uid, {
4041 'name': line.name or '?',
4042 'amount': amount,
4043- 'type': type,
4044 'partner_id': line.partner_id.id,
4045- 'account_id': line.account_id.id,
4046 'statement_id': statement_id,
4047 'ref': line.ref,
4048- 'voucher_id': voucher_id,
4049 'date': statement.date,
4050 }, context=context)
4051 return {'type': 'ir.actions.act_window_close'}
4052
4053=== renamed file 'account_voucher/wizard/account_statement_from_invoice_view.xml' => 'account/wizard/account_statement_from_invoice_view.xml'
4054=== modified file 'account/wizard/pos_box.py'
4055--- account/wizard/pos_box.py 2013-12-27 15:35:17 +0000
4056+++ account/wizard/pos_box.py 2014-05-30 16:18:57 +0000
4057@@ -56,7 +56,6 @@
4058 return {
4059 'statement_id' : record.id,
4060 'journal_id' : record.journal_id.id,
4061- 'account_id' : record.journal_id.internal_account_id.id,
4062 'amount' : box.amount or 0.0,
4063 'ref' : '%s' % (box.ref or ''),
4064 'name' : box.name,
4065@@ -73,7 +72,6 @@
4066 return {
4067 'statement_id' : record.id,
4068 'journal_id' : record.journal_id.id,
4069- 'account_id' : record.journal_id.internal_account_id.id,
4070 'amount' : -amount if amount > 0.0 else amount,
4071 'name' : box.name,
4072 }
4073
4074=== modified file 'account_analytic_plans/__openerp__.py'
4075--- account_analytic_plans/__openerp__.py 2014-04-02 16:40:53 +0000
4076+++ account_analytic_plans/__openerp__.py 2014-05-30 16:18:57 +0000
4077@@ -74,6 +74,7 @@
4078 'wizard/analytic_plan_create_model_view.xml',
4079 'wizard/account_crossovered_analytic_view.xml',
4080 'views/report_crossoveredanalyticplans.xml',
4081+ 'views/account_analytic_plans.xml',
4082 ],
4083 'demo': [],
4084 'test': ['test/acount_analytic_plans_report.yml'],
4085
4086=== modified file 'account_analytic_plans/account_analytic_plans_view.xml'
4087--- account_analytic_plans/account_analytic_plans_view.xml 2014-02-10 05:26:55 +0000
4088+++ account_analytic_plans/account_analytic_plans_view.xml 2014-05-30 16:18:57 +0000
4089@@ -233,57 +233,25 @@
4090
4091 <!-- add property field on default analytic account-->
4092
4093- <record model="ir.ui.view" id="view_default_inherit_form">
4094- <field name="name">account.analytic.default.form.plans</field>
4095- <field name="model">account.analytic.default</field>
4096- <field name="inherit_id" ref="account_analytic_default.view_account_analytic_default_form"/>
4097- <field name="arch" type="xml">
4098- <field name="analytic_id" required="1" position="replace">
4099- <field name="analytics_id" required="1"/>
4100- </field>
4101- </field>
4102- </record>
4103- <record model="ir.ui.view" id="view_default_inherit_tree">
4104- <field name="name">account.analytic.default.tree.plans</field>
4105- <field name="model">account.analytic.default</field>
4106- <field name="inherit_id" ref="account_analytic_default.view_account_analytic_default_tree"/>
4107- <field name="arch" type="xml">
4108- <xpath expr="//field[@name='analytic_id']" position="attributes">
4109- <attribute name="invisible">1</attribute>
4110- </xpath>
4111- <xpath expr="//field[@name='analytic_id']" position="after">
4112- <field name="analytics_id" required="1"/>
4113- </xpath>
4114- </field>
4115- </record>
4116-
4117- <record id="view_bank_statement_inherit_form" model="ir.ui.view">
4118- <field name="name">account.bank.statement.form.inherit</field>
4119- <field name="model">account.bank.statement</field>
4120- <field name="inherit_id" ref="account.view_bank_statement_form"/>
4121- <field name="arch" type="xml">
4122- <xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/tree/field[@name='analytic_account_id']" position="replace">
4123- <field name="analytics_id" groups="analytic.group_analytic_accounting"/>
4124- </xpath>
4125- <xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/form/group/field[@name='analytic_account_id']" position="replace">
4126- <field name="analytics_id" groups="analytic.group_analytic_accounting"/>
4127- </xpath>
4128- </field>
4129- </record>
4130-
4131- <record id="view_bank_statement_inherit_form2" model="ir.ui.view">
4132- <field name="name">account.bank.statement.form.inherit</field>
4133- <field name="model">account.bank.statement</field>
4134- <field name="inherit_id" ref="account.view_bank_statement_form2"/>
4135- <field name="arch" type="xml">
4136- <xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/tree/field[@name='analytic_account_id']" position="replace">
4137- <field name="analytics_id" groups="analytic.group_analytic_accounting"/>
4138- </xpath>
4139- <xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/form/group/field[@name='analytic_account_id']" position="replace">
4140- <field name="analytics_id" groups="analytic.group_analytic_accounting"/>
4141- </xpath>
4142- </field>
4143- </record>
4144-
4145+ <record model="ir.ui.view" id="view_default_inherit_form">
4146+ <field name="name">account.analytic.default.form.plans</field>
4147+ <field name="model">account.analytic.default</field>
4148+ <field name="inherit_id" ref="account_analytic_default.view_account_analytic_default_form"/>
4149+ <field name="arch" type="xml">
4150+ <field name="analytic_id" required="1" position="replace">
4151+ <field name="analytics_id" required="1"/>
4152+ </field>
4153+ </field>
4154+ </record>
4155+ <record model="ir.ui.view" id="view_default_inherit_tree">
4156+ <field name="name">account.analytic.default.tree.plans</field>
4157+ <field name="model">account.analytic.default</field>
4158+ <field name="inherit_id" ref="account_analytic_default.view_account_analytic_default_tree"/>
4159+ <field name="arch" type="xml">
4160+ <xpath expr="//field[@name='analytic_id']" position="replace">
4161+ <field name="analytics_id" required="1"/>
4162+ </xpath>
4163+ </field>
4164+ </record>
4165 </data>
4166 </openerp>
4167
4168=== added directory 'account_analytic_plans/static'
4169=== added directory 'account_analytic_plans/static/src'
4170=== added directory 'account_analytic_plans/static/src/js'
4171=== added file 'account_analytic_plans/static/src/js/account_bank_reconciliation.js'
4172--- account_analytic_plans/static/src/js/account_bank_reconciliation.js 1970-01-01 00:00:00 +0000
4173+++ account_analytic_plans/static/src/js/account_bank_reconciliation.js 2014-05-30 16:18:57 +0000
4174@@ -0,0 +1,35 @@
4175+openerp.account_analytic_plans = function(instance) {
4176+
4177+var _t = instance.web._t,
4178+ _lt = instance.web._lt;
4179+var QWeb = instance.web.qweb;
4180+
4181+instance.web.account.bankStatementReconciliation.include({
4182+
4183+ init: function(parent, context) {
4184+ this._super(parent, context);
4185+ delete this.create_form_fields.analytic_account_id;
4186+ this.create_form_fields["analytic_plan"] = {
4187+ id: "analytic_plan",
4188+ index: 4,
4189+ corresponding_property: "analytics_id",
4190+ label: _t("Analytic Distribution"),
4191+ required: false,
4192+ tabindex: 14,
4193+ group: "analytic.group_analytic_accounting",
4194+ constructor: instance.web.form.FieldMany2One,
4195+ field_properties: {
4196+ relation: "account.analytic.plan.instance",
4197+ string: _t("Analytic Distribution"),
4198+ type: "many2one",
4199+ }
4200+ };
4201+ },
4202+
4203+ start: function() {
4204+ return this._super().then(function() {
4205+ });
4206+ },
4207+
4208+});
4209+};
4210
4211=== added file 'account_analytic_plans/views/account_analytic_plans.xml'
4212--- account_analytic_plans/views/account_analytic_plans.xml 1970-01-01 00:00:00 +0000
4213+++ account_analytic_plans/views/account_analytic_plans.xml 2014-05-30 16:18:57 +0000
4214@@ -0,0 +1,12 @@
4215+<?xml version="1.0" encoding="utf-8"?>
4216+<!-- vim:fdn=3:
4217+-->
4218+<openerp>
4219+ <data>
4220+ <template id="assets_backend" name="account analytic plans assets" inherit_id="web.assets_backend">
4221+ <xpath expr="." position="inside">
4222+ <script type="text/javascript" src="/account_analytic_plans/static/src/js/account_bank_reconciliation.js"></script>
4223+ </xpath>
4224+ </template>
4225+ </data>
4226+</openerp>
4227
4228=== modified file 'account_bank_statement_extensions/account_bank_statement_view.xml'
4229--- account_bank_statement_extensions/account_bank_statement_view.xml 2012-11-29 22:26:45 +0000
4230+++ account_bank_statement_extensions/account_bank_statement_view.xml 2014-05-30 16:18:57 +0000
4231@@ -74,10 +74,7 @@
4232 <field name="name"/>
4233 <field name="statement_id"/>
4234 <field name="ref" readonly="1"/>
4235- <field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
4236- <field name="type" on_change="onchange_type(partner_id, type)"/>
4237- <field name="account_id"/>
4238- <field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('type', '&lt;&gt;', 'view')]"/>
4239+ <field name="partner_id"/>
4240 <field name="amount" readonly="1" sum="Total Amount"/>
4241 <field name="globalisation_id" string="Glob. Id"/>
4242 <field name="globalisation_amount" string="Glob. Am."/>
4243@@ -98,10 +95,7 @@
4244 <field name="val_date"/>
4245 <field name="name"/>
4246 <field name="ref" readonly="0"/>
4247- <field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
4248- <field name="type" on_change="onchange_type(partner_id, type)"/>
4249- <field domain="[('type', '&lt;&gt;', 'view')]" name="account_id"/>
4250- <field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('type', '&lt;&gt;', 'view')]"/>
4251+ <field name="partner_id"/>
4252 <field name="amount"/>
4253 <field name="globalisation_id"/>
4254 <field name="sequence" readonly="0"/>
4255@@ -129,7 +123,6 @@
4256 <field name="statement_id"/>
4257 <field name="globalisation_id" string="Glob. Id"/>
4258 <group string="Extended Filters..." expand="0">
4259- <field name="account_id"/>
4260 <field name="partner_id"/>
4261 <field name="amount"/>
4262 <field name="globalisation_amount" string="Glob. Amount"/>
4263@@ -138,7 +131,6 @@
4264 <group string="Group By..." expand="1">
4265 <filter string="Journal" context="{'group_by':'journal_id'}" icon="terp-folder-green"/>
4266 <filter string="Statement" context="{'group_by':'statement_id'}" icon="terp-folder-orange"/>
4267- <filter string="Fin.Account" context="{'group_by':'account_id'}" icon="terp-folder-yellow"/>
4268 </group>
4269 </search>
4270 </field>
4271
4272=== modified file 'account_payment/wizard/account_payment_populate_statement.py'
4273--- account_payment/wizard/account_payment_populate_statement.py 2013-10-27 12:31:04 +0000
4274+++ account_payment/wizard/account_payment_populate_statement.py 2014-05-30 16:18:57 +0000
4275@@ -107,12 +107,9 @@
4276 st_line_id = statement_line_obj.create(cr, uid, {
4277 'name': line.order_id.reference or '?',
4278 'amount': - amount,
4279- 'type': 'supplier',
4280 'partner_id': line.partner_id.id,
4281- 'account_id': line.move_line_id.account_id.id,
4282 'statement_id': statement.id,
4283 'ref': line.communication,
4284- 'voucher_id': voucher_id,
4285 }, context=context)
4286
4287 line_obj.write(cr, uid, [line.id], {'bank_statement_line_id': st_line_id})
4288
4289=== modified file 'account_voucher/__init__.py'
4290--- account_voucher/__init__.py 2012-11-29 22:26:45 +0000
4291+++ account_voucher/__init__.py 2014-05-30 16:18:57 +0000
4292@@ -22,6 +22,5 @@
4293 import account_voucher
4294 import invoice
4295 import report
4296-import wizard
4297
4298 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
4299
4300=== modified file 'account_voucher/__openerp__.py'
4301--- account_voucher/__openerp__.py 2014-04-02 16:40:53 +0000
4302+++ account_voucher/__openerp__.py 2014-05-30 16:18:57 +0000
4303@@ -49,7 +49,6 @@
4304 'security/ir.model.access.csv',
4305 'account_voucher_sequence.xml',
4306 'account_voucher_workflow.xml',
4307- 'wizard/account_statement_from_invoice_view.xml',
4308 'account_voucher_view.xml',
4309 'voucher_payment_receipt_view.xml',
4310 'voucher_sales_purchase_view.xml',
4311
4312=== modified file 'account_voucher/account_voucher.py'
4313--- account_voucher/account_voucher.py 2014-05-02 13:03:52 +0000
4314+++ account_voucher/account_voucher.py 2014-05-30 16:18:57 +0000
4315@@ -327,7 +327,6 @@
4316 }
4317
4318 _columns = {
4319- 'active': fields.boolean('Active', help="By default, reconciliation vouchers made on draft bank statements are set as inactive, which allow to hide the customer/supplier payment while the bank statement isn't confirmed."),
4320 'type':fields.selection([
4321 ('sale','Sale'),
4322 ('purchase','Purchase'),
4323@@ -389,7 +388,6 @@
4324 'currency_help_label': fields.function(_fnct_currency_help_label, type='text', string="Helping Sentence", help="This sentence helps you to know how to specify the payment rate by giving you the direct effect it has"),
4325 }
4326 _defaults = {
4327- 'active': True,
4328 'period_id': _get_period,
4329 'partner_id': _get_partner,
4330 'journal_id':_get_journal,
4331@@ -1583,114 +1581,6 @@
4332 })
4333 return values
4334
4335-class account_bank_statement(osv.osv):
4336- _inherit = 'account.bank.statement'
4337-
4338- def button_confirm_bank(self, cr, uid, ids, context=None):
4339- voucher_obj = self.pool.get('account.voucher')
4340- voucher_ids = []
4341- for statement in self.browse(cr, uid, ids, context=context):
4342- voucher_ids += [line.voucher_id.id for line in statement.line_ids if line.voucher_id]
4343- if voucher_ids:
4344- voucher_obj.write(cr, uid, voucher_ids, {'active': True}, context=context)
4345- return super(account_bank_statement, self).button_confirm_bank(cr, uid, ids, context=context)
4346-
4347- def button_cancel(self, cr, uid, ids, context=None):
4348- voucher_obj = self.pool.get('account.voucher')
4349- for st in self.browse(cr, uid, ids, context=context):
4350- voucher_ids = []
4351- for line in st.line_ids:
4352- if line.voucher_id:
4353- voucher_ids.append(line.voucher_id.id)
4354- voucher_obj.cancel_voucher(cr, uid, voucher_ids, context)
4355- return super(account_bank_statement, self).button_cancel(cr, uid, ids, context=context)
4356-
4357- def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, next_number, context=None):
4358- voucher_obj = self.pool.get('account.voucher')
4359- move_line_obj = self.pool.get('account.move.line')
4360- bank_st_line_obj = self.pool.get('account.bank.statement.line')
4361- st_line = bank_st_line_obj.browse(cr, uid, st_line_id, context=context)
4362- if st_line.voucher_id:
4363- voucher_obj.write(cr, uid, [st_line.voucher_id.id],
4364- {'number': next_number,
4365- 'date': st_line.date,
4366- 'period_id': st_line.statement_id.period_id.id},
4367- context=context)
4368- if st_line.voucher_id.state == 'cancel':
4369- voucher_obj.action_cancel_draft(cr, uid, [st_line.voucher_id.id], context=context)
4370- voucher_obj.signal_proforma_voucher(cr, uid, [st_line.voucher_id.id])
4371-
4372- v = voucher_obj.browse(cr, uid, st_line.voucher_id.id, context=context)
4373- bank_st_line_obj.write(cr, uid, [st_line_id], {
4374- 'move_ids': [(4, v.move_id.id, False)]
4375- })
4376-
4377- return move_line_obj.write(cr, uid, [x.id for x in v.move_ids], {'statement_id': st_line.statement_id.id}, context=context)
4378- return super(account_bank_statement, self).create_move_from_st_line(cr, uid, st_line.id, company_currency_id, next_number, context=context)
4379-
4380- def write(self, cr, uid, ids, vals, context=None):
4381- # Restrict to modify the journal if we already have some voucher of reconciliation created/generated.
4382- # Because the voucher keeps in memory the journal it was created with.
4383- for bk_st in self.browse(cr, uid, ids, context=context):
4384- if vals.get('journal_id') and bk_st.line_ids:
4385- if any([x.voucher_id and True or False for x in bk_st.line_ids]):
4386- raise osv.except_osv(_('Unable to Change Journal!'), _('You can not change the journal as you already reconciled some statement lines!'))
4387- return super(account_bank_statement, self).write(cr, uid, ids, vals, context=context)
4388-
4389-
4390-class account_bank_statement_line(osv.osv):
4391- _inherit = 'account.bank.statement.line'
4392-
4393- def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
4394- res = super(account_bank_statement_line, self).onchange_partner_id(cr, uid, ids, partner_id, context=context)
4395- if 'value' not in res:
4396- res['value'] = {}
4397- res['value'].update({'voucher_id' : False})
4398- return res
4399-
4400- def onchange_amount(self, cr, uid, ids, amount, context=None):
4401- return {'value' : {'voucher_id' : False}}
4402-
4403- def _amount_reconciled(self, cursor, user, ids, name, args, context=None):
4404- if not ids:
4405- return {}
4406- res = {}
4407- for line in self.browse(cursor, user, ids, context=context):
4408- if line.voucher_id:
4409- res[line.id] = line.voucher_id.amount#
4410- else:
4411- res[line.id] = 0.0
4412- return res
4413-
4414- def _check_amount(self, cr, uid, ids, context=None):
4415- for obj in self.browse(cr, uid, ids, context=context):
4416- if obj.voucher_id:
4417- diff = abs(obj.amount) - abs(obj.voucher_id.amount)
4418- if not self.pool.get('res.currency').is_zero(cr, uid, obj.statement_id.currency, diff):
4419- return False
4420- return True
4421-
4422- _constraints = [
4423- (_check_amount, 'The amount of the voucher must be the same amount as the one on the statement line.', ['amount']),
4424- ]
4425-
4426- _columns = {
4427- 'amount_reconciled': fields.function(_amount_reconciled,
4428- string='Amount reconciled', type='float'),
4429- 'voucher_id': fields.many2one('account.voucher', 'Reconciliation'),
4430- }
4431-
4432- def unlink(self, cr, uid, ids, context=None):
4433- voucher_obj = self.pool.get('account.voucher')
4434- statement_line = self.browse(cr, uid, ids, context=context)
4435- unlink_ids = []
4436- for st_line in statement_line:
4437- if st_line.voucher_id:
4438- unlink_ids.append(st_line.voucher_id.id)
4439- voucher_obj.unlink(cr, uid, unlink_ids, context=context)
4440- return super(account_bank_statement_line, self).unlink(cr, uid, ids, context=context)
4441-
4442-
4443 def resolve_o2m_operations(cr, uid, target_osv, operations, fields, context):
4444 results = []
4445 for operation in operations:
4446
4447=== modified file 'account_voucher/account_voucher_view.xml'
4448--- account_voucher/account_voucher_view.xml 2014-04-10 14:51:31 +0000
4449+++ account_voucher/account_voucher_view.xml 2014-05-30 16:18:57 +0000
4450@@ -193,59 +193,7 @@
4451 <field name="context">{'state':'posted'}</field>
4452 <field name="search_view_id" ref="view_voucher_filter"/>
4453 </record>
4454-
4455- <record id="view_bank_statement_form_invoice" model="ir.ui.view">
4456- <field name="name">account.bank.statement.invoice.form.inherit</field>
4457- <field name="model">account.bank.statement</field>
4458- <field name="inherit_id" ref="account.view_bank_statement_form"/>
4459- <field name="arch" type="xml">
4460- <xpath expr="//div[@name='import_buttons']" position="inside">
4461- <button class="oe_inline oe_stat_button" name="%(action_view_account_statement_from_invoice_lines)d"
4462- string="Import Invoice" type="action"
4463- attrs="{'invisible':[('state','=','confirm')]}" widget="statinfo" icon="fa-pencil-square-o"/>
4464- </xpath>
4465- </field>
4466- </record>
4467-
4468- <record id="view_bank_statement_form_voucher" model="ir.ui.view">
4469- <field name="name">account.bank.statement.voucher.tree.inherit</field>
4470- <field name="model">account.bank.statement</field>
4471- <field name="inherit_id" ref="account.view_bank_statement_form"/>
4472- <field name="arch" type="xml">
4473- <xpath expr="//page[@name='statement_line_ids']/field[@name='line_ids']/tree/field[@name='amount']" position="after">
4474- <field name="voucher_id" string="" widget="many2onebutton" options="{'label':{'create':'Reconcile','edit':'Edit Reconciliation'}}" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name, 'default_active': False, 'account_id': account_id}"/>
4475- </xpath>
4476- <xpath expr="//page[@name='statement_line_ids']/field[@name='line_ids']/form/group/field[@name='sequence']" position="before">
4477- <field name="voucher_id" widget="many2onebutton" options="{'label':{'create':'Reconcile','edit':'Edit Reconciliation'}}" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name, 'default_active': False, 'account_id': account_id}"/>
4478- </xpath>
4479- <field name="amount" position="attributes">
4480- <attribute name="on_change">onchange_amount(amount)</attribute>
4481- </field>
4482- </field>
4483- </record>
4484-
4485- <record id="view_cash_statement_tree_voucher" model="ir.ui.view">
4486- <field name="name">account.cash.statement.voucher.tree.inherit</field>
4487- <field name="model">account.bank.statement</field>
4488- <field name="inherit_id" ref="account.view_bank_statement_form2"/>
4489- <field name="arch" type="xml">
4490- <xpath expr="//page/field[@name='line_ids']/tree/field[@name='amount']" position="after">
4491- <field name="voucher_id" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name, 'account_id': account_id}"/>
4492- </xpath>
4493- </field>
4494- </record>
4495-
4496- <record id="view_cash_statement_form_voucher" model="ir.ui.view">
4497- <field name="name">account.cash.statement.voucher.form.inherit</field>
4498- <field name="model">account.bank.statement</field>
4499- <field name="inherit_id" ref="account.view_bank_statement_form2"/>
4500- <field name="arch" type="xml">
4501- <xpath expr="//page/field[@name='line_ids']/form/group/field[@name='amount']" position="after">
4502- <field name="voucher_id" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name, 'account_id': account_id}"/>
4503- </xpath>
4504- </field>
4505- </record>
4506-
4507+
4508 <!-- res.config form view -->
4509 <record model="ir.ui.view" id="view_account_settings_currency_xchange_form">
4510 <field name="name">account.config.settings.inherit</field>
4511
4512=== removed directory 'account_voucher/wizard'
4513=== removed file 'account_voucher/wizard/__init__.py'
4514--- account_voucher/wizard/__init__.py 2012-11-29 22:26:45 +0000
4515+++ account_voucher/wizard/__init__.py 1970-01-01 00:00:00 +0000
4516@@ -1,24 +0,0 @@
4517-# -*- coding: utf-8 -*-
4518-##############################################################################
4519-#
4520-# OpenERP, Open Source Management Solution
4521-# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
4522-#
4523-# This program is free software: you can redistribute it and/or modify
4524-# it under the terms of the GNU Affero General Public License as
4525-# published by the Free Software Foundation, either version 3 of the
4526-# License, or (at your option) any later version.
4527-#
4528-# This program is distributed in the hope that it will be useful,
4529-# but WITHOUT ANY WARRANTY; without even the implied warranty of
4530-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4531-# GNU Affero General Public License for more details.
4532-#
4533-# You should have received a copy of the GNU Affero General Public License
4534-# along with this program. If not, see <http://www.gnu.org/licenses/>.
4535-#
4536-##############################################################################
4537-
4538-import account_statement_from_invoice
4539-
4540-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
4541
4542=== modified file 'l10n_be_coda/__openerp__.py'
4543--- l10n_be_coda/__openerp__.py 2012-12-06 11:18:16 +0000
4544+++ l10n_be_coda/__openerp__.py 2014-05-30 16:18:57 +0000
4545@@ -2,9 +2,9 @@
4546 ##############################################################################
4547 #
4548 # OpenERP, Open Source Management Solution
4549-#
4550+#
4551 # Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved.
4552-#
4553+#
4554 # This program is free software: you can redistribute it and/or modify
4555 # it under the terms of the GNU Affero General Public License as
4556 # published by the Free Software Foundation, either version 3 of the
4557@@ -34,64 +34,64 @@
4558 * CODA v2.2 support.
4559 * Foreign Currency support.
4560 * Support for all data record types (0, 1, 2, 3, 4, 8, 9).
4561- * Parsing & logging of all Transaction Codes and Structured Format
4562+ * Parsing & logging of all Transaction Codes and Structured Format
4563 Communications.
4564 * Automatic Financial Journal assignment via CODA configuration parameters.
4565 * Support for multiple Journals per Bank Account Number.
4566- * Support for multiple statements from different bank accounts in a single
4567+ * Support for multiple statements from different bank accounts in a single
4568 CODA file.
4569- * Support for 'parsing only' CODA Bank Accounts (defined as type='info' in
4570+ * Support for 'parsing only' CODA Bank Accounts (defined as type='info' in
4571 the CODA Bank Account configuration records).
4572- * Multi-language CODA parsing, parsing configuration data provided for EN,
4573+ * Multi-language CODA parsing, parsing configuration data provided for EN,
4574 NL, FR.
4575
4576-The machine readable CODA Files are parsed and stored in human readable format in
4577-CODA Bank Statements. Also Bank Statements are generated containing a subset of
4578-the CODA information (only those transaction lines that are required for the
4579-creation of the Financial Accounting records). The CODA Bank Statement is a
4580+The machine readable CODA Files are parsed and stored in human readable format in
4581+CODA Bank Statements. Also Bank Statements are generated containing a subset of
4582+the CODA information (only those transaction lines that are required for the
4583+creation of the Financial Accounting records). The CODA Bank Statement is a
4584 'read-only' object, hence remaining a reliable representation of the original
4585-CODA file whereas the Bank Statement will get modified as required by accounting
4586+CODA file whereas the Bank Statement will get modified as required by accounting
4587 business processes.
4588
4589 CODA Bank Accounts configured as type 'Info' will only generate CODA Bank Statements.
4590
4591-A removal of one object in the CODA processing results in the removal of the
4592-associated objects. The removal of a CODA File containing multiple Bank
4593+A removal of one object in the CODA processing results in the removal of the
4594+associated objects. The removal of a CODA File containing multiple Bank
4595 Statements will also remove those associated statements.
4596
4597 The following reconciliation logic has been implemented in the CODA processing:
4598 -------------------------------------------------------------------------------
4599- 1) The Company's Bank Account Number of the CODA statement is compared against
4600- the Bank Account Number field of the Company's CODA Bank Account
4601- configuration records (whereby bank accounts defined in type='info'
4602+ 1) The Company's Bank Account Number of the CODA statement is compared against
4603+ the Bank Account Number field of the Company's CODA Bank Account
4604+ configuration records (whereby bank accounts defined in type='info'
4605 configuration records are ignored). If this is the case an 'internal transfer'
4606- transaction is generated using the 'Internal Transfer Account' field of the
4607+ transaction is generated using the 'Internal Transfer Account' field of the
4608 CODA File Import wizard.
4609 2) As a second step the 'Structured Communication' field of the CODA transaction
4610- line is matched against the reference field of in- and outgoing invoices
4611+ line is matched against the reference field of in- and outgoing invoices
4612 (supported : Belgian Structured Communication Type).
4613- 3) When the previous step doesn't find a match, the transaction counterparty is
4614- located via the Bank Account Number configured on the OpenERP Customer and
4615+ 3) When the previous step doesn't find a match, the transaction counterparty is
4616+ located via the Bank Account Number configured on the OpenERP Customer and
4617 Supplier records.
4618- 4) In case the previous steps are not successful, the transaction is generated
4619- by using the 'Default Account for Unrecognized Movement' field of the CODA
4620+ 4) In case the previous steps are not successful, the transaction is generated
4621+ by using the 'Default Account for Unrecognized Movement' field of the CODA
4622 File Import wizard in order to allow further manual processing.
4623
4624-In stead of a manual adjustment of the generated Bank Statements, you can also
4625-re-import the CODA after updating the OpenERP database with the information that
4626+In stead of a manual adjustment of the generated Bank Statements, you can also
4627+re-import the CODA after updating the OpenERP database with the information that
4628 was missing to allow automatic reconciliation.
4629
4630 Remark on CODA V1 support:
4631 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4632-In some cases a transaction code, transaction category or structured
4633+In some cases a transaction code, transaction category or structured
4634 communication code has been given a new or clearer description in CODA V2.The
4635-description provided by the CODA configuration tables is based upon the CODA
4636+description provided by the CODA configuration tables is based upon the CODA
4637 V2.2 specifications.
4638 If required, you can manually adjust the descriptions via the CODA configuration menu.
4639 ''',
4640- 'images' : ['images/coda_logs.jpeg','images/import_coda_logs.jpeg'],
4641- 'depends': ['account_voucher','base_iban', 'l10n_be_invoice_bba',],
4642- 'demo': [],
4643+ 'images': ['images/coda_logs.jpeg', 'images/import_coda_logs.jpeg'],
4644+ 'depends': ['account_voucher', 'base_iban', 'l10n_be_invoice_bba'],
4645+ 'demo': ['l10n_be_coda_demo.xml'],
4646 'data': [
4647 'l10n_be_coda_wizard.xml',
4648 'l10n_be_coda_view.xml',
4649
4650=== added file 'l10n_be_coda/l10n_be_coda_demo.xml'
4651--- l10n_be_coda/l10n_be_coda_demo.xml 1970-01-01 00:00:00 +0000
4652+++ l10n_be_coda/l10n_be_coda_demo.xml 2014-05-30 16:18:57 +0000
4653@@ -0,0 +1,36 @@
4654+<?xml version="1.0" ?>
4655+<openerp>
4656+ <data>
4657+ <record id="demo_bank_account" model="res.partner.bank">
4658+ <field name="state">bank</field>
4659+ <field name="acc_number">BE33737018595246</field>
4660+ <field name="bank_bic">KREDBEBB</field>
4661+ <field name="journal_id" ref="account.bank_journal"/>
4662+ <field name="partner_id" ref="base.main_partner"/>
4663+ </record>
4664+ <!--
4665+ Fiscal year
4666+ -->
4667+
4668+ <record id="data_fiscalyear_2011" model="account.fiscalyear">
4669+ <field eval="'Fiscal Year X 2011'" name="name"/>
4670+ <field eval="'FY2011'" name="code"/>
4671+ <field eval="'2011-01-01'" name="date_start"/>
4672+ <field eval="'2011-12-31'" name="date_stop"/>
4673+ <field name="company_id" ref="base.main_company"/>
4674+ </record>
4675+
4676+ <!--
4677+ Fiscal Periods
4678+ -->
4679+
4680+ <record id="period_1_2011" model="account.period">
4681+ <field eval="'01/2011'" name="code"/>
4682+ <field eval="'X 01/2011'" name="name"/>
4683+ <field name="fiscalyear_id" ref="data_fiscalyear_2011"/>
4684+ <field eval="'2011-01-01'" name="date_start"/>
4685+ <field eval="'2011-01-31'" name="date_stop"/>
4686+ <field name="company_id" ref="base.main_company"/>
4687+ </record>
4688+ </data>
4689+</openerp>
4690
4691=== modified file 'l10n_be_coda/l10n_be_coda_view.xml'
4692--- l10n_be_coda/l10n_be_coda_view.xml 2013-10-27 12:31:04 +0000
4693+++ l10n_be_coda/l10n_be_coda_view.xml 2014-05-30 16:18:57 +0000
4694@@ -25,8 +25,6 @@
4695 <field name="name"/>
4696 <field name="ref" readonly="0"/>
4697 <field name="partner_id"/>
4698- <field name="type" />
4699- <field domain="[('type', '&lt;&gt;', 'view')]" name="account_id"/>
4700 <field name="amount"/>
4701 <field name="sequence" readonly="0"/>
4702 </group>
4703@@ -46,10 +44,7 @@
4704 <field name="date"/>
4705 <field name="name"/>
4706 <field name="ref"/>
4707- <field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
4708- <field name="type" on_change="onchange_type(partner_id, type)"/>
4709- <field name="account_id" options='{"no_open":True}' domain="[('type', '&lt;&gt;', 'view')]"/>
4710- <field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('type', '&lt;&gt;', 'view')]"/>
4711+ <field name="partner_id"/>
4712 <field name="amount"/>
4713 <field name="note"/>
4714 </tree>
4715@@ -66,17 +61,14 @@
4716 <filter name="credit" string="Credit" domain="[('amount','&lt;',0)]" icon="terp-folder-orange" help="Credit Transactions."/>
4717 <field name="statement_id"/>
4718 <group expand="0" string="Extended Filters...">
4719- <field name="account_id"/>
4720 <field name="partner_id"/>
4721 <field name="amount"/>
4722- <field name="type"/>
4723 <field name="note"/>
4724 </group>
4725 <newline/>
4726 <group string="Group By..." expand="0">
4727 <filter string="Partner" context="{'group_by':'partner_id'}" icon="terp-folder-green"/>
4728 <filter string="Statement" context="{'group_by':'statement_id'}" icon="terp-folder-orange"/>
4729- <filter string="Fin.Account" context="{'group_by':'account_id'}" icon="terp-folder-yellow"/>
4730 </group>
4731 </search>
4732 </field>
4733
4734=== modified file 'l10n_be_coda/l10n_be_coda_wizard.xml'
4735--- l10n_be_coda/l10n_be_coda_wizard.xml 2012-12-20 14:52:27 +0000
4736+++ l10n_be_coda/l10n_be_coda_wizard.xml 2014-05-30 16:18:57 +0000
4737@@ -10,7 +10,6 @@
4738 <form string="Import CODA File" version="7.0">
4739 <group col="2">
4740 <field name="coda_data" filename="coda_fname"/>
4741- <field name="temporary_account_id" />
4742 </group>
4743 <footer>
4744 <button name="coda_parsing" string="_Import" type="object" class="oe_highlight"/>
4745
4746=== modified file 'l10n_be_coda/wizard/account_coda_import.py'
4747--- l10n_be_coda/wizard/account_coda_import.py 2013-10-27 12:31:04 +0000
4748+++ l10n_be_coda/wizard/account_coda_import.py 2014-05-30 16:18:57 +0000
4749@@ -37,20 +37,10 @@
4750 'coda_data': fields.binary('CODA File', required=True),
4751 'coda_fname': fields.char('CODA Filename', size=128, required=True),
4752 'note': fields.text('Log'),
4753- 'temporary_account_id': fields.many2one('account.account', 'Temporary Account', domain="[('type','!=','view')]", help="It acts as a temporary account for general amount", required=True),
4754 }
4755
4756- def _get_default_tmp_account(self, cr, uid, context):
4757- tmp_accounts = self.pool.get('account.account').search(cr, uid, [('code', '=', '490000')])
4758- if tmp_accounts and len(tmp_accounts) > 0:
4759- tmp_account_id = tmp_accounts[0]
4760- else:
4761- tmp_account_id = False
4762- return tmp_account_id
4763-
4764 _defaults = {
4765 'coda_fname': lambda *a: '',
4766- 'temporary_account_id': _get_default_tmp_account,
4767 }
4768
4769 def coda_parsing(self, cr, uid, ids, context=None, batch=False, codafile=None, codafilename=None):
4770@@ -64,7 +54,6 @@
4771 try:
4772 codafile = data.coda_data
4773 codafilename = data.coda_fname
4774- temporaryaccount = data.temporary_account_id.id
4775 except:
4776 raise osv.except_osv(_('Error'), _('Wizard in incorrect state. Please hit the Cancel button'))
4777 return {}
4778@@ -149,7 +138,6 @@
4779 statementLine['amount'] = float(rmspaces(line[32:47])) / 1000
4780 if statementLine['debit'] == '1':
4781 statementLine['amount'] = - statementLine['amount']
4782- statementLine['transaction_type'] = line[53]
4783 statementLine['transactionDate'] = time.strftime(tools.DEFAULT_SERVER_DATE_FORMAT, time.strptime(rmspaces(line[47:53]), '%d%m%y'))
4784 statementLine['transaction_family'] = rmspaces(line[54:56])
4785 statementLine['transaction_code'] = rmspaces(line[56:58])
4786@@ -211,7 +199,6 @@
4787 infoLine['sequence'] = len(statement['lines']) + 1
4788 infoLine['ref'] = rmspaces(line[2:10])
4789 infoLine['transactionRef'] = rmspaces(line[10:31])
4790- infoLine['transaction_type'] = line[31]
4791 infoLine['transaction_family'] = rmspaces(line[32:34])
4792 infoLine['transaction_code'] = rmspaces(line[34:36])
4793 infoLine['transaction_category'] = rmspaces(line[36:39])
4794@@ -304,91 +291,78 @@
4795 if 'counterpartyAddress' in line and line['counterpartyAddress'] != '':
4796 note.append(_('Counter Party Address') + ': ' + line['counterpartyAddress'])
4797 line['name'] = "\n".join(filter(None, [line['counterpartyName'], line['communication']]))
4798- line['transaction_type'] = 'general'
4799 partner = None
4800 partner_id = None
4801 invoice = False
4802 if line['communication_struct'] and 'communication_type' in line and line['communication_type'] == '101':
4803 ids = self.pool.get('account.invoice').search(cr, uid, [('reference', '=', line['communication']), ('reference_type', '=', 'bba')])
4804- if ids:
4805- invoice = self.pool.get('account.invoice').browse(cr, uid, ids[0])
4806- partner = invoice.partner_id
4807- partner_id = partner.id
4808- if invoice.type in ['in_invoice', 'in_refund'] and line['debit'] == '1':
4809- line['transaction_type'] = 'supplier'
4810- elif invoice.type in ['out_invoice', 'out_refund'] and line['debit'] == '0':
4811- line['transaction_type'] = 'customer'
4812- line['account'] = invoice.account_id.id
4813- line['reconcile'] = False
4814- if invoice.type in ['in_invoice', 'out_invoice']:
4815- iml_ids = self.pool.get('account.move.line').search(cr, uid, [('move_id', '=', invoice.move_id.id), ('reconcile_id', '=', False), ('account_id.reconcile', '=', True)])
4816- if iml_ids:
4817- line['reconcile'] = iml_ids[0]
4818- if line['reconcile']:
4819- voucher_vals = {
4820- 'type': line['transaction_type'] == 'supplier' and 'payment' or 'receipt',
4821- 'name': line['name'],
4822- 'partner_id': partner_id,
4823- 'journal_id': statement['journal_id'].id,
4824- 'account_id': statement['journal_id'].default_credit_account_id.id,
4825- 'company_id': statement['journal_id'].company_id.id,
4826- 'currency_id': statement['journal_id'].company_id.currency_id.id,
4827- 'date': line['entryDate'],
4828- 'amount': abs(line['amount']),
4829- 'period_id': statement['period_id'],
4830- 'invoice_id': invoice.id,
4831- }
4832- context['invoice_id'] = invoice.id
4833- voucher_vals.update(self.pool.get('account.voucher').onchange_partner_id(cr, uid, [],
4834- partner_id=partner_id,
4835- journal_id=statement['journal_id'].id,
4836- amount=abs(line['amount']),
4837- currency_id=statement['journal_id'].company_id.currency_id.id,
4838- ttype=line['transaction_type'] == 'supplier' and 'payment' or 'receipt',
4839- date=line['transactionDate'],
4840- context=context
4841- )['value'])
4842- line_drs = []
4843- for line_dr in voucher_vals['line_dr_ids']:
4844- line_drs.append((0, 0, line_dr))
4845- voucher_vals['line_dr_ids'] = line_drs
4846- line_crs = []
4847- for line_cr in voucher_vals['line_cr_ids']:
4848- line_crs.append((0, 0, line_cr))
4849- voucher_vals['line_cr_ids'] = line_crs
4850- line['voucher_id'] = self.pool.get('account.voucher').create(cr, uid, voucher_vals, context=context)
4851+
4852+# Gère les communications structurées
4853+# TODO : à faire primer sur resolution_proposition : si la communication indique une facture, on la sélectionne
4854+
4855+# if ids:
4856+# invoice = self.pool.get('account.invoice').browse(cr, uid, ids[0])
4857+# partner = invoice.partner_id
4858+# partner_id = partner.id
4859+# if invoice.type in ['in_invoice', 'in_refund'] and line['debit'] == '1':
4860+# line['transaction_type'] = 'supplier'
4861+# elif invoice.type in ['out_invoice', 'out_refund'] and line['debit'] == '0':
4862+# line['transaction_type'] = 'customer'
4863+# line['account'] = invoice.account_id.id
4864+# line['reconcile'] = False
4865+# if invoice.type in ['in_invoice', 'out_invoice']:
4866+# iml_ids = self.pool.get('account.move.line').search(cr, uid, [('move_id', '=', invoice.move_id.id), ('reconcile_id', '=', False), ('account_id.reconcile', '=', True)])
4867+# if iml_ids:
4868+# line['reconcile'] = iml_ids[0]
4869+# if line['reconcile']:
4870+# voucher_vals = {
4871+# 'type': line['transaction_type'] == 'supplier' and 'payment' or 'receipt',
4872+# 'name': line['name'],
4873+# 'partner_id': partner_id,
4874+# 'journal_id': statement['journal_id'].id,
4875+# 'account_id': statement['journal_id'].default_credit_account_id.id,
4876+# 'company_id': statement['journal_id'].company_id.id,
4877+# 'currency_id': statement['journal_id'].company_id.currency_id.id,
4878+# 'date': line['entryDate'],
4879+# 'amount': abs(line['amount']),
4880+# 'period_id': statement['period_id'],
4881+# 'invoice_id': invoice.id,
4882+# }
4883+# context['invoice_id'] = invoice.id
4884+# voucher_vals.update(self.pool.get('account.voucher').onchange_partner_id(cr, uid, [],
4885+# partner_id=partner_id,
4886+# journal_id=statement['journal_id'].id,
4887+# amount=abs(line['amount']),
4888+# currency_id=statement['journal_id'].company_id.currency_id.id,
4889+# ttype=line['transaction_type'] == 'supplier' and 'payment' or 'receipt',
4890+# date=line['transactionDate'],
4891+# context=context
4892+# )['value'])
4893+# line_drs = []
4894+# for line_dr in voucher_vals['line_dr_ids']:
4895+# line_drs.append((0, 0, line_dr))
4896+# voucher_vals['line_dr_ids'] = line_drs
4897+# line_crs = []
4898+# for line_cr in voucher_vals['line_cr_ids']:
4899+# line_crs.append((0, 0, line_cr))
4900+# voucher_vals['line_cr_ids'] = line_crs
4901+# line['voucher_id'] = self.pool.get('account.voucher').create(cr, uid, voucher_vals, context=context)
4902 if 'counterpartyNumber' in line and line['counterpartyNumber']:
4903 ids = self.pool.get('res.partner.bank').search(cr, uid, [('acc_number', '=', str(line['counterpartyNumber']))])
4904 if ids and len(ids) > 0:
4905 partner = self.pool.get('res.partner.bank').browse(cr, uid, ids[0], context=context).partner_id
4906 partner_id = partner.id
4907- if not invoice:
4908- if line['debit'] == '0':
4909- line['account'] = partner.property_account_receivable.id
4910- if partner.customer:
4911- line['transaction_type'] = 'customer'
4912- elif line['debit'] == '1':
4913- line['account'] = partner.property_account_payable.id
4914- if partner.supplier:
4915- line['transaction_type'] = 'supplier'
4916- if not partner and not invoice:
4917- line['account'] = temporaryaccount
4918 if 'communication' in line and line['communication'] != '':
4919 note.append(_('Communication') + ': ' + line['communication'])
4920- if 'voucher_id' not in line:
4921- line['voucher_id'] = None
4922 data = {
4923 'name': line['name'],
4924 'note': "\n".join(note),
4925 'date': line['entryDate'],
4926 'amount': line['amount'],
4927- 'type': line['transaction_type'],
4928 'partner_id': partner_id,
4929- 'account_id': line['account'],
4930 'statement_id': statement['id'],
4931 'ref': line['ref'],
4932 'sequence': line['sequence'],
4933- 'voucher_id': line['voucher_id'],
4934 'coda_account_number': line['counterpartyNumber'],
4935 }
4936 self.pool.get('account.bank.statement.line').create(cr, uid, data, context=context)
4937
4938=== modified file 'point_of_sale/point_of_sale.py'
4939--- point_of_sale/point_of_sale.py 2014-05-08 14:39:40 +0000
4940+++ point_of_sale/point_of_sale.py 2014-05-30 16:18:57 +0000
4941@@ -457,19 +457,13 @@
4942 if st.difference and st.journal_id.cash_control == True:
4943 if st.difference > 0.0:
4944 name= _('Point of Sale Profit')
4945- account_id = st.journal_id.profit_account_id.id
4946 else:
4947- account_id = st.journal_id.loss_account_id.id
4948 name= _('Point of Sale Loss')
4949- if not account_id:
4950- raise osv.except_osv( _('Error!'),
4951- _("Please set your profit and loss accounts on your payment method '%s'. This will allow OpenERP to post the difference of %.2f in your ending balance. To close this session, you can update the 'Closing Cash Control' to avoid any difference.") % (st.journal_id.name,st.difference))
4952 bsl.create(cr, uid, {
4953 'statement_id': st.id,
4954 'amount': st.difference,
4955 'ref': record.name,
4956 'name': name,
4957- 'account_id': account_id
4958 }, context=context)
4959
4960 if st.journal_id.type == 'bank':
4961@@ -822,20 +816,9 @@
4962 'amount': data['amount'],
4963 'date': data.get('payment_date', time.strftime('%Y-%m-%d')),
4964 'name': order.name + ': ' + (data.get('payment_name', '') or ''),
4965+ 'partner_id': order.partner_id and order.partner_id.id or None,
4966 }
4967
4968- account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=context)
4969- args['account_id'] = (order.partner_id and order.partner_id.property_account_receivable \
4970- and order.partner_id.property_account_receivable.id) or (account_def and account_def.id) or False
4971- args['partner_id'] = order.partner_id and order.partner_id.id or None
4972-
4973- if not args['account_id']:
4974- if not args['partner_id']:
4975- msg = _('There is no receivable account defined to make payment.')
4976- else:
4977- msg = _('There is no receivable account defined to make payment for the partner: "%s" (id:%d).') % (order.partner_id.name, order.partner_id.id,)
4978- raise osv.except_osv(_('Configuration Error!'), msg)
4979-
4980 context.pop('pos_session_id', False)
4981
4982 journal_id = data.get('journal', False)
4983@@ -857,7 +840,6 @@
4984 'statement_id' : statement_id,
4985 'pos_statement_id' : order_id,
4986 'journal_id' : journal_id,
4987- 'type' : 'customer',
4988 'ref' : order.session_id.name,
4989 })
4990
4991
4992=== modified file 'point_of_sale/point_of_sale_view.xml'
4993--- point_of_sale/point_of_sale_view.xml 2014-05-07 18:29:17 +0000
4994+++ point_of_sale/point_of_sale_view.xml 2014-05-30 16:18:57 +0000
4995@@ -68,13 +68,6 @@
4996 <field name="statement_id"/>
4997 <field name="amount"/>
4998 </tree>
4999- <form string="Statement lines" version="7.0">
5000- <group col="4">
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: