~camptocamp/banking-addons/vre-preserve-manual-partial-reconcile

« back to all changes in this revision

Viewing changes to account_statement_ext/statement.py

  • Committer: Joël Grand-Guillaume
  • Date: 2012-05-30 14:08:58 UTC
  • Revision ID: joel.grandguillaume@camptocamp.com-20120530140858-gjyuatc8f7vpgmkw
[IMP] Quite a huge work on the new intermediate statement stuff as well as on the automatic reconciliation wizard.
(lp:c2c-financial-addons/6.1 rev 24.1.10)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
##############################################################################
 
3
#
 
4
#    Author: Joel Grand-Guillaume
 
5
#    Copyright 2011-2012 Camptocamp SA
 
6
#
 
7
#    This program is free software: you can redistribute it and/or modify
 
8
#    it under the terms of the GNU Affero General Public License as
 
9
#    published by the Free Software Foundation, either version 3 of the
 
10
#    License, or (at your option) any later version.
 
11
#
 
12
#    This program is distributed in the hope that it will be useful,
 
13
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
#    GNU Affero General Public License for more details.
 
16
#
 
17
#    You should have received a copy of the GNU Affero General Public License
 
18
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
#
 
20
##############################################################################
 
21
 
 
22
from osv import fields, osv
 
23
from tools.translate import _
 
24
from account_statement_import.file_parser.parser import FileParser
 
25
import datetime
 
26
import netsvc
 
27
logger = netsvc.Logger()
 
28
 
 
29
 
 
30
class AccountSatement(osv.osv):
 
31
    """Override account bank statement to remove the period on it
 
32
    and compute it for each line."""
 
33
 
 
34
    _inherit = "account.bank.statement"
 
35
    
 
36
    _columns = {
 
37
        'period_id': fields.many2one('account.period', 'Period', required=False, readonly=True),
 
38
    }
 
39
 
 
40
    _defaults = {
 
41
        'period_id': lambda *a: False,
 
42
    }
 
43
   
 
44
    def _get_period(self, cursor, uid, date, context=None):
 
45
        '''
 
46
        Find matching period for date, used in thestatement line creation.
 
47
        '''
 
48
        period_obj = self.pool.get('account.period')
 
49
        periods = period_obj.find(cursor, uid, dt=date, context=context)
 
50
        return periods and periods[0] or False
 
51
        
 
52
    def _check_company_id(self, cr, uid, ids, context=None):
 
53
        """
 
54
        Adapt this constraint method from the account module to reflect the
 
55
        move of period_id to the statement line
 
56
        """
 
57
        for statement in self.browse(cr, uid, ids, context=context):
 
58
            if (statement.period_id and
 
59
                statement.company_id.id != statement.period_id.company_id.id):
 
60
                return False
 
61
            for line in statement.line_ids:
 
62
                if (line.period_id and
 
63
                    statement.company_id.id != line.period_id.company_id.id):
 
64
                    return False
 
65
        return True
 
66
 
 
67
    # Redefine the constraint, or it still refer to the original method
 
68
    _constraints = [
 
69
        (_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']),
 
70
    ]
 
71
    
 
72
    def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None):
 
73
        """Override a large portion of the code to compute the periode for each line instead of
 
74
        taking the period of the whole statement.
 
75
        Remove the entry posting on generated account moves."""
 
76
        if context is None:
 
77
            context = {}
 
78
        res_currency_obj = self.pool.get('res.currency')
 
79
        account_move_obj = self.pool.get('account.move')
 
80
        account_move_line_obj = self.pool.get('account.move.line')
 
81
        account_bank_statement_line_obj = self.pool.get('account.bank.statement.line')
 
82
        st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id, context=context)
 
83
        st = st_line.statement_id
 
84
 
 
85
        context.update({'date': st_line.date})
 
86
        ctx = context.copy()                        # Chg
 
87
        ctx['company_id'] = st_line.company_id.id   # Chg
 
88
        period_id = self._get_period(               # Chg
 
89
            cr, uid, st_line.date, context=ctx)  
 
90
            
 
91
        move_id = account_move_obj.create(cr, uid, {
 
92
            'journal_id': st.journal_id.id,
 
93
            'period_id': period_id,                 # Chg
 
94
            'date': st_line.date,
 
95
            'name': st_line_number,
 
96
            'ref': st_line.ref,
 
97
        }, context=context)
 
98
        account_bank_statement_line_obj.write(cr, uid, [st_line.id], {
 
99
            'move_ids': [(4, move_id, False)]
 
100
        })
 
101
 
 
102
        torec = []
 
103
        if st_line.amount >= 0:
 
104
            account_id = st.journal_id.default_credit_account_id.id
 
105
        else:
 
106
            account_id = st.journal_id.default_debit_account_id.id
 
107
 
 
108
        acc_cur = ((st_line.amount<=0) and st.journal_id.default_debit_account_id) or st_line.account_id
 
109
        context.update({
 
110
                'res.currency.compute.account': acc_cur,
 
111
            })
 
112
        amount = res_currency_obj.compute(cr, uid, st.currency.id,
 
113
                company_currency_id, st_line.amount, context=context)
 
114
 
 
115
        val = {
 
116
            'name': st_line.name,
 
117
            'date': st_line.date,
 
118
            'ref': st_line.ref,
 
119
            'move_id': move_id,
 
120
            'partner_id': ((st_line.partner_id) and st_line.partner_id.id) or False,
 
121
            'account_id': (st_line.account_id) and st_line.account_id.id,
 
122
            'credit': ((amount>0) and amount) or 0.0,
 
123
            'debit': ((amount<0) and -amount) or 0.0,
 
124
            'statement_id': st.id,
 
125
            'journal_id': st.journal_id.id,
 
126
            'period_id': period_id,                 #Chg
 
127
            'currency_id': st.currency.id,
 
128
            'analytic_account_id': st_line.analytic_account_id and st_line.analytic_account_id.id or False
 
129
        }
 
130
 
 
131
        if st.currency.id <> company_currency_id:
 
132
            amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
 
133
                        st.currency.id, amount, context=context)
 
134
            val['amount_currency'] = -amount_cur
 
135
 
 
136
        if st_line.account_id and st_line.account_id.currency_id and st_line.account_id.currency_id.id <> company_currency_id:
 
137
            val['currency_id'] = st_line.account_id.currency_id.id
 
138
            amount_cur = res_currency_obj.compute(cr, uid, company_currency_id,
 
139
                    st_line.account_id.currency_id.id, amount, context=context)
 
140
            val['amount_currency'] = -amount_cur
 
141
 
 
142
        move_line_id = account_move_line_obj.create(cr, uid, val, context=context)
 
143
        torec.append(move_line_id)
 
144
 
 
145
        # Fill the secondary amount/currency
 
146
        # if currency is not the same than the company
 
147
        amount_currency = False
 
148
        currency_id = False
 
149
        if st.currency.id <> company_currency_id:
 
150
            amount_currency = st_line.amount
 
151
            currency_id = st.currency.id
 
152
        account_move_line_obj.create(cr, uid, {
 
153
            'name': st_line.name,
 
154
            'date': st_line.date,
 
155
            'ref': st_line.ref,
 
156
            'move_id': move_id,
 
157
            'partner_id': ((st_line.partner_id) and st_line.partner_id.id) or False,
 
158
            'account_id': account_id,
 
159
            'credit': ((amount < 0) and -amount) or 0.0,
 
160
            'debit': ((amount > 0) and amount) or 0.0,
 
161
            'statement_id': st.id,
 
162
            'journal_id': st.journal_id.id,
 
163
            'period_id': period_id,                 #Chg
 
164
            'amount_currency': amount_currency,
 
165
            'currency_id': currency_id,
 
166
            }, context=context)
 
167
 
 
168
        for line in account_move_line_obj.browse(cr, uid, [x.id for x in
 
169
                account_move_obj.browse(cr, uid, move_id,
 
170
                    context=context).line_id],
 
171
                context=context):
 
172
            if line.state <> 'valid':
 
173
                raise osv.except_osv(_('Error !'),
 
174
                        _('Journal item "%s" is not valid.') % line.name)
 
175
 
 
176
        # Bank statements will not consider boolean on journal entry_posted
 
177
        account_move_obj.post(cr, uid, [move_id], context=context)
 
178
        return move_id
 
179
 
 
180
    def _get_st_number_period(self, cr, uid, date, journal_sequence_id):
 
181
        """Retrieve the name of bank statement from sequence, according to the period 
 
182
        corresponding to the date passed in args"""
 
183
        year = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, date)).fiscalyear_id.id
 
184
        c = {'fiscalyear_id': year}
 
185
        obj_seq = self.pool.get('ir.sequence')
 
186
        if journal_sequence_id:
 
187
            st_number = obj_seq.next_by_id(cr, uid, journal_sequence_id, context=c)
 
188
        else:
 
189
            st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c)
 
190
        return st_number
 
191
 
 
192
    def button_confirm_bank(self, cr, uid, ids, context=None):
 
193
        """Completely override the method in order to have
 
194
           an error message which displays all the messages
 
195
           instead of having them pop one by one.
 
196
           We have to copy paste a big block of code, changing the error
 
197
           stack + managing period from date."""
 
198
        # obj_seq = self.pool.get('irerrors_stack.sequence')
 
199
        if context is None:
 
200
            context = {}
 
201
        for st in self.browse(cr, uid, ids, context=context):
 
202
            
 
203
            j_type = st.journal_id.type
 
204
            company_currency_id = st.journal_id.company_id.currency_id.id
 
205
            if not self.check_status_condition(cr, uid, st.state, journal_type=j_type):
 
206
                continue
 
207
 
 
208
            self.balance_check(cr, uid, st.id, journal_type=j_type, context=context)
 
209
            if (not st.journal_id.default_credit_account_id) \
 
210
                    or (not st.journal_id.default_debit_account_id):
 
211
                raise osv.except_osv(_('Configuration Error !'),
 
212
                        _('Please verify that an account is defined in the journal.'))
 
213
 
 
214
            if not st.name == '/':
 
215
                st_number = st.name
 
216
            else:
 
217
# Begin Changes                
 
218
                seq_id = st.journal_id.sequence_id and st.journal_id.sequence_id.id or False
 
219
                st_number = self._get_st_number_period(cr, uid, st.date, seq_id)
 
220
                # c = {'fiscalyear_id': st.period_id.fiscalyear_id.id}
 
221
                # if st.journal_id.sequence_id:
 
222
                #     st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c)
 
223
                # else:
 
224
                #     st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c)
 
225
# End Changes 
 
226
            for line in st.move_line_ids:
 
227
                if line.state <> 'valid':
 
228
                    raise osv.except_osv(_('Error !'),
 
229
                            _('The account entries lines are not in valid state.'))
 
230
# begin changes
 
231
            errors_stack = []
 
232
            for st_line in st.line_ids:
 
233
                try:
 
234
                    if st_line.analytic_account_id:
 
235
                        if not st.journal_id.analytic_journal_id:
 
236
                            raise osv.except_osv(_('No Analytic Journal !'),
 
237
                                             _("You have to assign an analytic journal on the '%s' journal!") % (st.journal_id.name,))
 
238
                    if not st_line.amount:
 
239
                        continue
 
240
                    st_line_number = self.get_next_st_line_number(cr, uid, st_number, st_line, context)
 
241
                    self.create_move_from_st_line(cr, uid, st_line.id, company_currency_id, st_line_number, context)
 
242
                except osv.except_osv, exc:
 
243
                    msg = "Line ID %s with ref %s had following error: %s" % (st_line.id, st_line.ref, exc.value)
 
244
                    errors_stack.append(msg)
 
245
                except Exception, exc:
 
246
                    msg = "Line ID %s with ref %s had following error: %s" % (st_line.id, st_line.ref, str(exc))
 
247
                    errors_stack.append(msg)
 
248
            if errors_stack:
 
249
                msg = u"\n".join(errors_stack)
 
250
                raise osv.except_osv(_('Error'), msg)
 
251
#end changes
 
252
            self.write(cr, uid, [st.id], {
 
253
                    'name': st_number,
 
254
                    'balance_end_real': st.balance_end
 
255
            }, context=context)
 
256
            self.log(cr, uid, st.id, _('Statement %s is confirmed, journal items are created.') % (st_number,))
 
257
        return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
 
258
 
 
259
class AccountSatementLine(osv.osv):
 
260
    '''
 
261
    Adds the period on line, matched on the date.
 
262
    '''
 
263
    _inherit = 'account.bank.statement.line'
 
264
 
 
265
    def _get_period(self, cursor, user, context=None):
 
266
        date = context.get('date', None)
 
267
        periods = self.pool.get('account.period').find(cursor, user, dt=date)
 
268
        return periods and periods[0] or False
 
269
 
 
270
    _columns = {
 
271
        'period_id': fields.many2one('account.period', 'Period', required=True),
 
272
    }
 
273
 
 
274
    _defaults = {
 
275
        'period_id': _get_period,
 
276
    }