~unifield-team/unifield-wm/us-826

« back to all changes in this revision

Viewing changes to account_subscription/account_model.py

  • Committer: Quentin THEURET
  • Date: 2011-11-30 13:31:37 UTC
  • mto: This revision was merged to the branch mainline in revision 515.
  • Revision ID: qt@tempo-consulting.fr-20111130133137-mdf2fp6hkqmwbppn
UF-647 [ADD] Added a line in Purchase Order to have information about international transport costs

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
# -*- coding: utf-8 -*-
3
 
##############################################################################
4
 
#
5
 
#    OpenERP, Open Source Management Solution
6
 
#    Copyright (C) 2011 TeMPO Consulting, MSF. All Rights Reserved
7
 
#
8
 
#    This program is free software: you can redistribute it and/or modify
9
 
#    it under the terms of the GNU Affero General Public License as
10
 
#    published by the Free Software Foundation, either version 3 of the
11
 
#    License, or (at your option) any later version.
12
 
#
13
 
#    This program is distributed in the hope that it will be useful,
14
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
#    GNU Affero General Public License for more details.
17
 
#
18
 
#    You should have received a copy of the GNU Affero General Public License
19
 
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 
#
21
 
##############################################################################
22
 
from osv import fields, osv
23
 
import time
24
 
from datetime import datetime
25
 
from dateutil.relativedelta import relativedelta
26
 
from tools.translate import _
27
 
 
28
 
class account_model_line(osv.osv):
29
 
    _name = "account.model.line"
30
 
    _inherit = "account.model.line"
31
 
 
32
 
    def _get_distribution_state(self, cr, uid, ids, name, args, context=None):
33
 
        """
34
 
        Get state of distribution:
35
 
         - if compatible with the invoice line, then "valid"
36
 
         - if no distribution, take a tour of invoice distribution, if compatible, then "valid"
37
 
         - if no distribution on invoice line and invoice, then "none"
38
 
         - all other case are "invalid"
39
 
        """
40
 
        # Some verifications
41
 
        if not context:
42
 
            context = {}
43
 
        if isinstance(ids, (int, long)):
44
 
            ids = [ids]
45
 
        # Prepare some values
46
 
        res = {}
47
 
        # Browse all given lines
48
 
        for line in self.browse(cr, uid, ids, context=context):
49
 
            res[line.id] = self.pool.get('analytic.distribution')._get_distribution_state(cr, uid, line.analytic_distribution_id.id, line.model_id.analytic_distribution_id.id, line.account_id.id)
50
 
        return res
51
 
 
52
 
    def _have_analytic_distribution_from_header(self, cr, uid, ids, name, arg, context=None):
53
 
        """
54
 
        If model has an analytic distribution, return False, else return True
55
 
        """
56
 
        # Some verifications
57
 
        if not context:
58
 
            context = {}
59
 
        if isinstance(ids, (int, long)):
60
 
            ids = [ids]
61
 
        res = {}
62
 
        for model in self.browse(cr, uid, ids, context=context):
63
 
            res[model.id] = True
64
 
            if model.analytic_distribution_id:
65
 
                res[model.id] = False
66
 
        return res
67
 
 
68
 
    def _get_is_allocatable(self, cr, uid, ids, name, arg, context=None):
69
 
        """
70
 
        If analytic-a-holic account, then this account is allocatable.
71
 
        """
72
 
        if isinstance(ids, (int, long)):
73
 
            ids = [ids]
74
 
        res = {}
75
 
        for model_line in self.browse(cr, uid, ids):
76
 
            res[model_line.id] = True
77
 
            if model_line.account_id and not model_line.account_id.is_analytic_addicted:
78
 
                res[model_line.id] = False
79
 
        return res
80
 
 
81
 
    def _get_distribution_state_recap(self, cr, uid, ids, name, arg, context=None):
82
 
        """
83
 
        Get a recap from analytic distribution state and if it come from header or not.
84
 
        """
85
 
        if isinstance(ids, (int, long)):
86
 
            ids = [ids]
87
 
        res = {}
88
 
        for model_line in self.browse(cr, uid, ids):
89
 
            res[model_line.id] = ''
90
 
            if not model_line.is_allocatable:
91
 
                continue
92
 
            from_header = ''
93
 
            if model_line.have_analytic_distribution_from_header:
94
 
                from_header = _(' (from header)')
95
 
            ana_distri_state = self.pool.get('ir.model.fields').get_browse_selection(cr, uid, model_line, 'analytic_distribution_state', context)
96
 
            res[model_line.id] = "%s%s" % (ana_distri_state, from_header)
97
 
        return res
98
 
 
99
 
    def _get_exp_in_line_state(self, cr, uid, ids, name, args, context=None):
100
 
        res = {}
101
 
        if not ids:
102
 
            return res
103
 
        if isinstance(ids, (int, long)):
104
 
            ids = [ids]
105
 
        for line in self.browse(cr, uid, ids, context=context):
106
 
            if line.account_id.user_type.code in ('expense', 'income'):
107
 
                if line.have_analytic_distribution_from_header \
108
 
                    and not line.model_id.analytic_distribution_id:
109
 
                    # line has no AD
110
 
                    res[line.id] = 'no_header'
111
 
                else:
112
 
                    # get line AD state
113
 
                    res[line.id] = line.analytic_distribution_state
114
 
            else:
115
 
                res[line.id] = 'no_exp_in'
116
 
        return res
117
 
 
118
 
    _columns = {
119
 
        'analytic_distribution_state': fields.function(_get_distribution_state, method=True, type='selection',
120
 
            selection=[('none', 'None'), ('valid', 'Valid'), ('invalid', 'Invalid')],
121
 
            string="Distribution state", help="Informs from distribution state among 'none', 'valid', 'invalid."),
122
 
        'have_analytic_distribution_from_header': fields.function(_have_analytic_distribution_from_header, method=True, type='boolean',
123
 
            string='Header Distrib.?'),
124
 
        'is_allocatable': fields.function(_get_is_allocatable, method=True, type='boolean', string="Is allocatable?", readonly=True, store=False),
125
 
        'analytic_distribution_state_recap': fields.function(_get_distribution_state_recap, method=True, type='char', size=30,
126
 
            string="Distribution",
127
 
            help="Informs you about analaytic distribution state among 'none', 'valid', 'invalid', from header or not, or no analytic distribution"),
128
 
        'sequence': fields.integer('Sequence', readonly=True, help="The sequence field is used to order the resources from lower sequences to higher ones"),
129
 
        'analytic_distribution_id': fields.many2one('analytic.distribution', 'Analytic Distribution'),
130
 
        'exp_in_ad_state': fields.function(_get_exp_in_line_state, method=True, type='selection',
131
 
             selection=[('no_exp_in', 'Not expense/income'), ('no_header', 'No header'), ('valid', 'Valid'), ('invalid', 'Invalid')],
132
 
             string='Expense/income line status'),  # UFTP-103
133
 
    }
134
 
 
135
 
    _defaults = {
136
 
        'have_analytic_distribution_from_header': lambda *a: True,
137
 
        'is_allocatable': lambda *a: True,
138
 
        'analytic_distribution_state_recap': lambda *a: '',
139
 
    }
140
 
 
141
 
    def create(self, cr, uid, vals, context=None):
142
 
        model = self.pool.get('account.model').browse(cr, uid, vals['model_id'], context=context)
143
 
        # just add the next line
144
 
        vals['sequence'] = len(model.lines_id) + 1
145
 
        return super(account_model_line, self).create(cr, uid, vals, context=context)
146
 
 
147
 
    def button_analytic_distribution(self, cr, uid, ids, context=None):
148
 
        """
149
 
        Launch analytic distribution wizard on an invoice line
150
 
        """
151
 
        # Some verifications
152
 
        if not context:
153
 
            context = {}
154
 
        if isinstance(ids, (int, long)):
155
 
            ids = [ids]
156
 
        if not ids:
157
 
            raise osv.except_osv(_('Error'), _('No model line given. Please save your model line before.'))
158
 
        model_line = self.browse(cr, uid, ids[0], context=context)
159
 
        distrib_id = False
160
 
        amount = abs(model_line.debit - model_line.credit)
161
 
        company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
162
 
        currency = model_line.model_id and  model_line.model_id.currency_id and  model_line.model_id.currency_id.id or company_currency
163
 
        # Get analytic distribution id from this line
164
 
        distrib_id = model_line.analytic_distribution_id and model_line.analytic_distribution_id.id or False
165
 
        # Prepare values for wizard
166
 
        vals = {
167
 
            'total_amount': amount,
168
 
            'model_line_id': model_line.id,
169
 
            'currency_id': currency or False,
170
 
            'state': 'dispatch',
171
 
            'account_id': model_line.account_id.id,
172
 
        }
173
 
        if distrib_id:
174
 
            vals.update({'distribution_id': distrib_id,})
175
 
        # Create the wizard
176
 
        wiz_obj = self.pool.get('analytic.distribution.wizard')
177
 
        wiz_id = wiz_obj.create(cr, uid, vals, context=context)
178
 
        # Update some context values
179
 
        context.update({
180
 
            'active_id': ids[0],
181
 
            'active_ids': ids,
182
 
        })
183
 
        # Open it!
184
 
        return {
185
 
                'name': _('Analytic distribution'),
186
 
                'type': 'ir.actions.act_window',
187
 
                'res_model': 'analytic.distribution.wizard',
188
 
                'view_type': 'form',
189
 
                'view_mode': 'form',
190
 
                'target': 'new',
191
 
                'res_id': [wiz_id],
192
 
                'context': context,
193
 
        }
194
 
 
195
 
    def copy_data(self, cr, uid, id, default=None, context=None):
196
 
        """
197
 
        Copy global distribution and give it to new model line
198
 
        """
199
 
        # Some verifications
200
 
        if not context:
201
 
            context = {}
202
 
        if not default:
203
 
            default = {}
204
 
        # Copy analytic distribution
205
 
        model_line = self.browse(cr, uid, [id], context=context)[0]
206
 
        if model_line.analytic_distribution_id:
207
 
            new_distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, model_line.analytic_distribution_id.id, {}, context=context)
208
 
            if new_distrib_id:
209
 
                default.update({'analytic_distribution_id': new_distrib_id})
210
 
        return super(account_model_line, self).copy_data(cr, uid, id, default, context)
211
 
 
212
 
account_model_line()
213
 
 
214
 
class account_model(osv.osv):
215
 
    _name = "account.model"
216
 
    _inherit = "account.model"
217
 
 
218
 
    def _has_any_bad_ad_line_exp_in(self, cr, uid, ids, name, args, context=None):
219
 
        res = {}
220
 
        if not ids:
221
 
            return res
222
 
        if isinstance(ids, (int, long)):
223
 
            ids = [ids]
224
 
        for model in self.browse(cr, uid, ids, context=context):
225
 
            res[model.id] = False
226
 
            for line in model.lines_id:
227
 
                if line.exp_in_ad_state and line.exp_in_ad_state in ('no_header', 'invalid'):
228
 
                    res[model.id] = True
229
 
                    break
230
 
        return res
231
 
 
232
 
    _columns = {
233
 
        'currency_id': fields.many2one('res.currency', 'Currency', required=True),
234
 
        'analytic_distribution_id': fields.many2one('analytic.distribution', 'Analytic Distribution'),
235
 
        'has_any_bad_ad_line_exp_in': fields.function(_has_any_bad_ad_line_exp_in,
236
 
             method=True, type='boolean',
237
 
             string='Has bad analytic distribution on expense/income lines',
238
 
             help='There is lines with expense or income accounts with invalid analytic distribution or using header AD that is not defined or not compatible.'),  # UFTP-103
239
 
    }
240
 
 
241
 
    _defaults = {
242
 
        'currency_id': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id,
243
 
        'has_any_bad_ad_line_exp_in': False,
244
 
    }
245
 
 
246
 
    # @@@override@account.account_model.generate()
247
 
    def generate(self, cr, uid, ids, datas={}, context=None):
248
 
        move_ids = []
249
 
        entry = {}
250
 
        account_move_obj = self.pool.get('account.move')
251
 
        account_move_line_obj = self.pool.get('account.move.line')
252
 
        pt_obj = self.pool.get('account.payment.term')
253
 
        ana_obj = self.pool.get('analytic.distribution')
254
 
 
255
 
        if context is None:
256
 
            context = {}
257
 
 
258
 
        if datas.get('date', False):
259
 
            context.update({'date': datas['date']})
260
 
 
261
 
        period_id = self.pool.get('account.period').find(cr, uid, dt=context.get('date', False))
262
 
        if not period_id:
263
 
            raise osv.except_osv(_('No period found !'), _('Unable to find a valid period !'))
264
 
        period_id = period_id[0]
265
 
 
266
 
        for model in self.browse(cr, uid, ids, context=context):
267
 
            entry['name'] = model.name%{'year':time.strftime('%Y'), 'month':time.strftime('%m'), 'date':time.strftime('%Y-%m')}
268
 
            move_id = account_move_obj.create(cr, uid, {
269
 
                'ref': entry['name'],
270
 
                'period_id': period_id,
271
 
                'journal_id': model.journal_id.id,
272
 
                'date': context.get('date',time.strftime('%Y-%m-%d'))
273
 
            })
274
 
            move_ids.append(move_id)
275
 
            for line in model.lines_id:
276
 
                val = {
277
 
                    'move_id': move_id,
278
 
                    'journal_id': model.journal_id.id,
279
 
                    'period_id': period_id,
280
 
                }
281
 
                if line.account_id.is_analytic_addicted:
282
 
                    if line.analytic_distribution_state == 'invalid':
283
 
                        raise osv.except_osv(_('Invalid Analytic Distribution !'),_("Please define a valid analytic distribution for the recurring model '%s'!") % (line.name))
284
 
                    if not model.journal_id.analytic_journal_id:
285
 
                        raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (model.journal_id.name,))
286
 
                    if line.analytic_distribution_id:
287
 
                        new_distribution_id = ana_obj.copy(cr, uid, line.analytic_distribution_id.id, {}, context=context)
288
 
                        val.update({'analytic_distribution_id': new_distribution_id})
289
 
                    elif model.analytic_distribution_id:
290
 
                        new_distribution_id = ana_obj.copy(cr, uid, model.analytic_distribution_id.id, {}, context=context)
291
 
                        val.update({'analytic_distribution_id': new_distribution_id})
292
 
 
293
 
                date_maturity = time.strftime('%Y-%m-%d')
294
 
                if line.date_maturity == 'partner':
295
 
                    if not line.partner_id:
296
 
                        raise osv.except_osv(_('Error !'), _("Maturity date of entry line generated by model line '%s' of model '%s' is based on partner payment term!" \
297
 
                                                                "\nPlease define partner on it!")%(line.name, model.name))
298
 
                    if line.partner_id.property_payment_term:
299
 
                        payment_term_id = line.partner_id.property_payment_term.id
300
 
                        pterm_list = pt_obj.compute(cr, uid, payment_term_id, value=1, date_ref=date_maturity)
301
 
                        if pterm_list:
302
 
                            pterm_list = [l[0] for l in pterm_list]
303
 
                            pterm_list.sort()
304
 
                            date_maturity = pterm_list[-1]
305
 
 
306
 
                val.update({
307
 
                    'name': line.name,
308
 
                    'quantity': line.quantity,
309
 
                    'debit_currency': line.debit, # UF-1535: set this value as the booking currency, and not functional currency
310
 
                    'credit_currency': line.credit, # UF-1535: set this value as the booking currency, and not functional currency
311
 
                    'account_id': line.account_id.id,
312
 
                    'move_id': move_id,
313
 
                    'partner_id': line.partner_id.id,
314
 
                    'date': context.get('date',time.strftime('%Y-%m-%d')),
315
 
                    'document_date': context.get('date',time.strftime('%Y-%m-%d')),
316
 
                    'date_maturity': date_maturity,
317
 
                    'currency_id': model.currency_id.id,
318
 
                    'is_recurring': True,
319
 
                })
320
 
                c = context.copy()
321
 
                c.update({'journal_id': model.journal_id.id,'period_id': period_id})
322
 
                account_move_line_obj.create(cr, uid, val, context=c)
323
 
 
324
 
        return move_ids
325
 
 
326
 
    def button_analytic_distribution(self, cr, uid, ids, context=None):
327
 
        """
328
 
        Launch analytic distribution wizard on a model
329
 
        """
330
 
        # Some verifications
331
 
        if not context:
332
 
            context = {}
333
 
        if isinstance(ids, (int, long)):
334
 
            ids = [ids]
335
 
        # Prepare some values
336
 
        model = self.browse(cr, uid, ids[0], context=context)
337
 
        amount = 0.0
338
 
        # Search elements for currency
339
 
        company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
340
 
        currency = model.currency_id and model.currency_id.id or company_currency
341
 
        for line in model.lines_id:
342
 
            amount += (line.debit - line.credit)
343
 
        amount = abs(amount)
344
 
        # Get analytic_distribution_id
345
 
        distrib_id = model.analytic_distribution_id and model.analytic_distribution_id.id
346
 
        # Prepare values for wizard
347
 
        vals = {
348
 
            'total_amount': amount,
349
 
            'model_id': model.id,
350
 
            'currency_id': currency or False,
351
 
            'state': 'dispatch',
352
 
        }
353
 
        if distrib_id:
354
 
            vals.update({'distribution_id': distrib_id,})
355
 
        # Create the wizard
356
 
        wiz_obj = self.pool.get('analytic.distribution.wizard')
357
 
        wiz_id = wiz_obj.create(cr, uid, vals, context=context)
358
 
        # Update some context values
359
 
        context.update({
360
 
            'active_id': ids[0],
361
 
            'active_ids': ids,
362
 
        })
363
 
        # Open it!
364
 
        return {
365
 
                'name': _('Global analytic distribution'),
366
 
                'type': 'ir.actions.act_window',
367
 
                'res_model': 'analytic.distribution.wizard',
368
 
                'view_type': 'form',
369
 
                'view_mode': 'form',
370
 
                'target': 'new',
371
 
                'res_id': [wiz_id],
372
 
                'context': context,
373
 
        }
374
 
 
375
 
    def button_reset_distribution(self, cr, uid, ids, context=None):
376
 
        """
377
 
        Reset analytic distribution on all recurring lines.
378
 
        To do this, just delete the analytic_distribution id link on each recurring line.
379
 
        """
380
 
        if context is None:
381
 
            context = {}
382
 
        if isinstance(ids, (int, long)):
383
 
            ids = [ids]
384
 
        # Prepare some values
385
 
        recurring_obj = self.pool.get(self._name + '.line')
386
 
        # Search recurring lines
387
 
        to_reset = recurring_obj.search(cr, uid, [('model_id', 'in', ids)])
388
 
        recurring_obj.write(cr, uid, to_reset, {'analytic_distribution_id': False})
389
 
        return True
390
 
 
391
 
account_model()
392
 
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: