~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: 2016-03-04 12:15:00 UTC
  • Revision ID: qt@tempo-consulting.fr-20160304121500-u2ay8zrf83ih9fu3
US-826 [IMP] Change the way to check if products is not consistent on add multiple line wizard

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
##############################################################################
22
22
from osv import fields, osv
23
23
import time
24
 
from datetime import datetime
25
 
from dateutil.relativedelta import relativedelta
26
24
from tools.translate import _
27
25
 
28
26
class account_model_line(osv.osv):
29
27
    _name = "account.model.line"
30
28
    _inherit = "account.model.line"
31
 
    
 
29
 
 
30
    def _get_distribution_state(self, cr, uid, ids, name, args, context=None):
 
31
        """
 
32
        Get state of distribution:
 
33
         - if compatible with the invoice line, then "valid"
 
34
         - if no distribution, take a tour of invoice distribution, if compatible, then "valid"
 
35
         - if no distribution on invoice line and invoice, then "none"
 
36
         - all other case are "invalid"
 
37
        """
 
38
        # Some verifications
 
39
        if not context:
 
40
            context = {}
 
41
        if isinstance(ids, (int, long)):
 
42
            ids = [ids]
 
43
        # Prepare some values
 
44
        res = {}
 
45
        # Browse all given lines
 
46
        for line in self.browse(cr, uid, ids, context=context):
 
47
            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)
 
48
        return res
 
49
 
 
50
    def _have_analytic_distribution_from_header(self, cr, uid, ids, name, arg, context=None):
 
51
        """
 
52
        If model has an analytic distribution, return False, else return True
 
53
        """
 
54
        # Some verifications
 
55
        if not context:
 
56
            context = {}
 
57
        if isinstance(ids, (int, long)):
 
58
            ids = [ids]
 
59
        res = {}
 
60
        for model in self.browse(cr, uid, ids, context=context):
 
61
            res[model.id] = True
 
62
            if model.analytic_distribution_id:
 
63
                res[model.id] = False
 
64
        return res
 
65
 
 
66
    def _get_is_allocatable(self, cr, uid, ids, name, arg, context=None):
 
67
        """
 
68
        If analytic-a-holic account, then this account is allocatable.
 
69
        """
 
70
        if isinstance(ids, (int, long)):
 
71
            ids = [ids]
 
72
        res = {}
 
73
        for model_line in self.browse(cr, uid, ids):
 
74
            res[model_line.id] = True
 
75
            if model_line.account_id and not model_line.account_id.is_analytic_addicted:
 
76
                res[model_line.id] = False
 
77
        return res
 
78
 
 
79
    def _get_distribution_state_recap(self, cr, uid, ids, name, arg, context=None):
 
80
        """
 
81
        Get a recap from analytic distribution state and if it come from header or not.
 
82
        """
 
83
        if isinstance(ids, (int, long)):
 
84
            ids = [ids]
 
85
        res = {}
 
86
        for model_line in self.browse(cr, uid, ids):
 
87
            res[model_line.id] = ''
 
88
            if not model_line.is_allocatable:
 
89
                continue
 
90
            from_header = ''
 
91
            if model_line.have_analytic_distribution_from_header:
 
92
                from_header = _(' (from header)')
 
93
            ana_distri_state = self.pool.get('ir.model.fields').get_browse_selection(cr, uid, model_line, 'analytic_distribution_state', context)
 
94
            res[model_line.id] = "%s%s" % (ana_distri_state, from_header)
 
95
        return res
 
96
 
 
97
    def _get_exp_in_line_state(self, cr, uid, ids, name, args, context=None):
 
98
        res = {}
 
99
        if not ids:
 
100
            return res
 
101
        if isinstance(ids, (int, long)):
 
102
            ids = [ids]
 
103
        for line in self.browse(cr, uid, ids, context=context):
 
104
            if line.account_id.user_type.code in ('expense', 'income'):
 
105
                if line.have_analytic_distribution_from_header \
 
106
                    and not line.model_id.analytic_distribution_id:
 
107
                    # line has no AD
 
108
                    res[line.id] = 'no_header'
 
109
                else:
 
110
                    # get line AD state
 
111
                    res[line.id] = line.analytic_distribution_state
 
112
            else:
 
113
                res[line.id] = 'no_exp_in'
 
114
        return res
 
115
 
32
116
    _columns = {
 
117
        'analytic_distribution_state': fields.function(_get_distribution_state, method=True, type='selection',
 
118
            selection=[('none', 'None'), ('valid', 'Valid'), ('invalid', 'Invalid')],
 
119
            string="Distribution state", help="Informs from distribution state among 'none', 'valid', 'invalid."),
 
120
        'have_analytic_distribution_from_header': fields.function(_have_analytic_distribution_from_header, method=True, type='boolean',
 
121
            string='Header Distrib.?'),
 
122
        'is_allocatable': fields.function(_get_is_allocatable, method=True, type='boolean', string="Is allocatable?", readonly=True, store=False),
 
123
        'analytic_distribution_state_recap': fields.function(_get_distribution_state_recap, method=True, type='char', size=30,
 
124
            string="Distribution",
 
125
            help="Informs you about analaytic distribution state among 'none', 'valid', 'invalid', from header or not, or no analytic distribution"),
 
126
        'sequence': fields.integer('Sequence', readonly=True, help="The sequence field is used to order the resources from lower sequences to higher ones"),
33
127
        'analytic_distribution_id': fields.many2one('analytic.distribution', 'Analytic Distribution'),
34
 
        'account_user_type_code': fields.related('account_id', 'user_type_code', type="char", string="Account User Type Code", store=False)
35
 
    }
36
 
    
 
128
        'exp_in_ad_state': fields.function(_get_exp_in_line_state, method=True, type='selection',
 
129
             selection=[('no_exp_in', 'Not expense/income'), ('no_header', 'No header'), ('valid', 'Valid'), ('invalid', 'Invalid')],
 
130
             string='Expense/income line status'),  # UFTP-103
 
131
    }
 
132
 
 
133
    _defaults = {
 
134
        'have_analytic_distribution_from_header': lambda *a: True,
 
135
        'is_allocatable': lambda *a: True,
 
136
        'analytic_distribution_state_recap': lambda *a: '',
 
137
    }
 
138
 
 
139
    def create(self, cr, uid, vals, context=None):
 
140
        model = self.pool.get('account.model').browse(cr, uid, vals['model_id'], context=context)
 
141
        # just add the next line
 
142
        vals['sequence'] = len(model.lines_id) + 1
 
143
        return super(account_model_line, self).create(cr, uid, vals, context=context)
 
144
 
37
145
    def button_analytic_distribution(self, cr, uid, ids, context=None):
38
146
        """
39
147
        Launch analytic distribution wizard on an invoice line
46
154
        if not ids:
47
155
            raise osv.except_osv(_('Error'), _('No model line given. Please save your model line before.'))
48
156
        model_line = self.browse(cr, uid, ids[0], context=context)
49
 
        distrib_id = False
50
157
        amount = abs(model_line.debit - model_line.credit)
51
 
        currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
 
158
        company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
 
159
        currency = model_line.model_id and  model_line.model_id.currency_id and  model_line.model_id.currency_id.id or company_currency
52
160
        # Get analytic distribution id from this line
53
161
        distrib_id = model_line.analytic_distribution_id and model_line.analytic_distribution_id.id or False
54
162
        # Prepare values for wizard
55
163
        vals = {
56
164
            'total_amount': amount,
57
165
            'model_line_id': model_line.id,
58
 
            'currency_id': currency,
 
166
            'currency_id': currency or False,
59
167
            'state': 'dispatch',
60
168
            'account_id': model_line.account_id.id,
61
169
        }
71
179
        })
72
180
        # Open it!
73
181
        return {
74
 
                'name': 'Analytic distribution',
 
182
                'name': _('Analytic distribution'),
75
183
                'type': 'ir.actions.act_window',
76
184
                'res_model': 'analytic.distribution.wizard',
77
185
                'view_type': 'form',
80
188
                'res_id': [wiz_id],
81
189
                'context': context,
82
190
        }
83
 
    
 
191
 
 
192
    def copy_data(self, cr, uid, id, default=None, context=None):
 
193
        """
 
194
        Copy global distribution and give it to new model line
 
195
        """
 
196
        # Some verifications
 
197
        if not context:
 
198
            context = {}
 
199
        if not default:
 
200
            default = {}
 
201
        # Copy analytic distribution
 
202
        model_line = self.browse(cr, uid, [id], context=context)[0]
 
203
        if model_line.analytic_distribution_id:
 
204
            new_distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, model_line.analytic_distribution_id.id, {}, context=context)
 
205
            if new_distrib_id:
 
206
                default.update({'analytic_distribution_id': new_distrib_id})
 
207
        return super(account_model_line, self).copy_data(cr, uid, id, default, context)
 
208
 
84
209
account_model_line()
85
210
 
86
211
class account_model(osv.osv):
87
212
    _name = "account.model"
88
213
    _inherit = "account.model"
89
 
    
 
214
 
 
215
    def _has_any_bad_ad_line_exp_in(self, cr, uid, ids, name, args, context=None):
 
216
        res = {}
 
217
        if not ids:
 
218
            return res
 
219
        if isinstance(ids, (int, long)):
 
220
            ids = [ids]
 
221
        for model in self.browse(cr, uid, ids, context=context):
 
222
            res[model.id] = False
 
223
            for line in model.lines_id:
 
224
                if line.exp_in_ad_state and line.exp_in_ad_state in ('no_header', 'invalid'):
 
225
                    res[model.id] = True
 
226
                    break
 
227
        return res
 
228
 
 
229
    _columns = {
 
230
        'currency_id': fields.many2one('res.currency', 'Currency', required=True),
 
231
        'analytic_distribution_id': fields.many2one('analytic.distribution', 'Analytic Distribution'),
 
232
        'has_any_bad_ad_line_exp_in': fields.function(_has_any_bad_ad_line_exp_in,
 
233
             method=True, type='boolean',
 
234
             string='Has bad analytic distribution on expense/income lines',
 
235
             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
 
236
    }
 
237
 
 
238
    _defaults = {
 
239
        'currency_id': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id,
 
240
        'has_any_bad_ad_line_exp_in': False,
 
241
    }
 
242
 
90
243
    # @@@override@account.account_model.generate()
91
244
    def generate(self, cr, uid, ids, datas={}, context=None):
92
245
        move_ids = []
106
259
        if not period_id:
107
260
            raise osv.except_osv(_('No period found !'), _('Unable to find a valid period !'))
108
261
        period_id = period_id[0]
 
262
        # UFTP-105: Check that period is open. Otherwise raise an error
 
263
        period = self.pool.get('account.period').browse(cr, uid, period_id, context=context)
 
264
        if not period or period.state != 'draft':
 
265
            raise osv.except_osv(_('Warning'), _('This period should be in open state: %s') % (period.name))
109
266
 
110
267
        for model in self.browse(cr, uid, ids, context=context):
111
268
            entry['name'] = model.name%{'year':time.strftime('%Y'), 'month':time.strftime('%m'), 'date':time.strftime('%Y-%m')}
122
279
                    'journal_id': model.journal_id.id,
123
280
                    'period_id': period_id,
124
281
                }
125
 
                if line.account_id.user_type_code == 'expense':
126
 
                    if not line.analytic_distribution_id:
127
 
                        raise osv.except_osv(_('No Analytic Distribution !'),_("You have to define an analytic distribution on the '%s' line!") % (line.name))
 
282
                if line.account_id.is_analytic_addicted:
 
283
                    if line.analytic_distribution_state == 'invalid':
 
284
                        raise osv.except_osv(_('Invalid Analytic Distribution !'),_("Please define a valid analytic distribution for the recurring model '%s'!") % (line.name))
128
285
                    if not model.journal_id.analytic_journal_id:
129
286
                        raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (model.journal_id.name,))
130
 
                    new_distribution_id = ana_obj.copy(cr, uid, line.analytic_distribution_id.id, {}, context=context)
131
 
                    val.update({'analytic_distribution_id': new_distribution_id})
132
 
                    
 
287
                    if line.analytic_distribution_id:
 
288
                        new_distribution_id = ana_obj.copy(cr, uid, line.analytic_distribution_id.id, {}, context=context)
 
289
                        val.update({'analytic_distribution_id': new_distribution_id})
 
290
                    elif model.analytic_distribution_id:
 
291
                        new_distribution_id = ana_obj.copy(cr, uid, model.analytic_distribution_id.id, {}, context=context)
 
292
                        val.update({'analytic_distribution_id': new_distribution_id})
 
293
 
133
294
                date_maturity = time.strftime('%Y-%m-%d')
134
295
                if line.date_maturity == 'partner':
135
296
                    if not line.partner_id:
146
307
                val.update({
147
308
                    'name': line.name,
148
309
                    'quantity': line.quantity,
149
 
                    'debit': line.debit,
150
 
                    'credit': line.credit,
 
310
                    'debit_currency': line.debit, # UF-1535: set this value as the booking currency, and not functional currency
 
311
                    'credit_currency': line.credit, # UF-1535: set this value as the booking currency, and not functional currency
151
312
                    'account_id': line.account_id.id,
152
313
                    'move_id': move_id,
153
314
                    'partner_id': line.partner_id.id,
154
315
                    'date': context.get('date',time.strftime('%Y-%m-%d')),
155
 
                    'date_maturity': date_maturity
 
316
                    'document_date': context.get('date',time.strftime('%Y-%m-%d')),
 
317
                    'date_maturity': date_maturity,
 
318
                    'currency_id': model.currency_id.id,
 
319
                    'is_recurring': True,
156
320
                })
157
321
                c = context.copy()
158
322
                c.update({'journal_id': model.journal_id.id,'period_id': period_id})
160
324
 
161
325
        return move_ids
162
326
 
 
327
    def button_analytic_distribution(self, cr, uid, ids, context=None):
 
328
        """
 
329
        Launch analytic distribution wizard on a model
 
330
        """
 
331
        # Some verifications
 
332
        if not context:
 
333
            context = {}
 
334
        if isinstance(ids, (int, long)):
 
335
            ids = [ids]
 
336
        # Prepare some values
 
337
        model = self.browse(cr, uid, ids[0], context=context)
 
338
        amount = 0.0
 
339
        # Search elements for currency
 
340
        company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
 
341
        currency = model.currency_id and model.currency_id.id or company_currency
 
342
        for line in model.lines_id:
 
343
            amount += (line.debit - line.credit)
 
344
        amount = abs(amount)
 
345
        # Get analytic_distribution_id
 
346
        distrib_id = model.analytic_distribution_id and model.analytic_distribution_id.id
 
347
        # Prepare values for wizard
 
348
        vals = {
 
349
            'total_amount': amount,
 
350
            'model_id': model.id,
 
351
            'currency_id': currency or False,
 
352
            'state': 'dispatch',
 
353
        }
 
354
        if distrib_id:
 
355
            vals.update({'distribution_id': distrib_id,})
 
356
        # Create the wizard
 
357
        wiz_obj = self.pool.get('analytic.distribution.wizard')
 
358
        wiz_id = wiz_obj.create(cr, uid, vals, context=context)
 
359
        # Update some context values
 
360
        context.update({
 
361
            'active_id': ids[0],
 
362
            'active_ids': ids,
 
363
        })
 
364
        # Open it!
 
365
        return {
 
366
                'name': _('Global analytic distribution'),
 
367
                'type': 'ir.actions.act_window',
 
368
                'res_model': 'analytic.distribution.wizard',
 
369
                'view_type': 'form',
 
370
                'view_mode': 'form',
 
371
                'target': 'new',
 
372
                'res_id': [wiz_id],
 
373
                'context': context,
 
374
        }
 
375
 
 
376
    def button_reset_distribution(self, cr, uid, ids, context=None):
 
377
        """
 
378
        Reset analytic distribution on all recurring lines.
 
379
        To do this, just delete the analytic_distribution id link on each recurring line.
 
380
        """
 
381
        if context is None:
 
382
            context = {}
 
383
        if isinstance(ids, (int, long)):
 
384
            ids = [ids]
 
385
        # Prepare some values
 
386
        recurring_obj = self.pool.get(self._name + '.line')
 
387
        # Search recurring lines
 
388
        to_reset = recurring_obj.search(cr, uid, [('model_id', 'in', ids)])
 
389
        recurring_obj.write(cr, uid, to_reset, {'analytic_distribution_id': False})
 
390
        return True
 
391
 
163
392
account_model()
164
 
 
165
393
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: