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

« back to all changes in this revision

Viewing changes to analytic_override/analytic_distribution.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:
 
1
# -*- coding: utf-8 -*-
 
2
##############################################################################
 
3
#
 
4
#    OpenERP, Open Source Management Solution
 
5
#    Copyright (C) MSF, TeMPO Consulting.
 
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 osv
 
23
from osv import fields
 
24
from time import strftime
 
25
import decimal_precision as dp
 
26
 
 
27
class analytic_distribution1(osv.osv):
 
28
    _name = "analytic.distribution"
 
29
 
 
30
    _columns = {
 
31
        'analytic_lines': fields.one2many('account.analytic.line', 'distribution_id', 'Analytic Lines'),
 
32
        'invoice_ids': fields.one2many('account.invoice', 'analytic_distribution_id', string="Invoices"),
 
33
        'invoice_line_ids': fields.one2many('account.invoice.line', 'analytic_distribution_id', string="Invoice Lines"),
 
34
        'register_line_ids': fields.one2many('account.bank.statement.line', 'analytic_distribution_id', string="Register Lines"),
 
35
        'move_line_ids': fields.one2many('account.move.line', 'analytic_distribution_id', string="Move Lines"),
 
36
        'commitment_ids': fields.one2many('account.commitment', 'analytic_distribution_id', string="Commitments voucher"),
 
37
        'commitment_line_ids': fields.one2many('account.commitment.line', 'analytic_distribution_id', string="Commitment voucher lines"),
 
38
    }
 
39
 
 
40
    def copy(self, cr, uid, distrib_id, default=None, context=None):
 
41
        """
 
42
        Copy an analytic distribution without the one2many links
 
43
        """
 
44
        if default is None:
 
45
            default = {}
 
46
        default.update({
 
47
            'analytic_lines': False,
 
48
            'invoice_ids': False,
 
49
            'invoice_line_ids': False,
 
50
            'register_line_ids': False,
 
51
            'move_line_ids': False,
 
52
            'commitment_ids': False,
 
53
            'commitment_line_ids': False,
 
54
        })
 
55
        return super(osv.osv, self).copy(cr, uid, distrib_id, default, context=context)
 
56
 
 
57
    def update_distribution_line_amount(self, cr, uid, ids, amount=False, context=None):
 
58
        """
 
59
        Update amount on distribution lines for given distribution (ids)
 
60
        """
 
61
        # Some verifications
 
62
        if not context:
 
63
            context = {}
 
64
        if isinstance(ids, (int, long)):
 
65
            ids = [ids]
 
66
        if not amount:
 
67
            return False
 
68
        # Process distributions
 
69
        for distrib_id in ids:
 
70
            for dl_name in ['cost.center.distribution.line', 'funding.pool.distribution.line', 'free.1.distribution.line', 'free.2.distribution.line']:
 
71
                dl_obj = self.pool.get(dl_name)
 
72
                dl_ids = dl_obj.search(cr, uid, [('distribution_id', '=', distrib_id)], context=context)
 
73
                for dl in dl_obj.read(cr, uid, dl_ids, ['percentage'], context=context):
 
74
                    dl_vals = {
 
75
                        'amount': round(dl.get('percentage', False) * amount) / 100.0,
 
76
                    }
 
77
                    dl_obj.write(cr, uid, [dl.get('id')], dl_vals, context=context)
 
78
        return True
 
79
 
 
80
    def update_distribution_line_account(self, cr, uid, line_ids, account_id, context=None):
 
81
        """
 
82
        Update account on distribution line
 
83
        """
 
84
        # Some verifications
 
85
        if not context:
 
86
            context = {}
 
87
        # Return False if no line_ids
 
88
        if not account_id or not line_ids: # fix bug on UF-2205 with analytic lines that comes from INTL Engagement journal without any distribution
 
89
            return False
 
90
        if isinstance(line_ids, (int, long)):
 
91
            line_ids = [line_ids]
 
92
        # Prepare some values
 
93
        account = self.pool.get('account.analytic.account').browse(cr, uid, [account_id], context=context)[0]
 
94
        if account.category == 'OC':
 
95
            vals = {'cost_center_id': account_id}
 
96
        elif account.category == 'DEST':
 
97
            vals = {'destination_id': account_id}
 
98
        else:
 
99
            vals = {'analytic_id': account_id}
 
100
        return self.pool.get('funding.pool.distribution.line').write(cr, uid, line_ids, vals)
 
101
 
 
102
    def create_funding_pool_lines(self, cr, uid, ids, account_id=False, context=None):
 
103
        """
 
104
        Create funding pool lines regarding cost_center_lines from analytic distribution.
 
105
        If funding_pool_lines exists, then nothing appends.
 
106
        By default, add funding_pool_lines with MSF Private Fund element (written in an OpenERP demo file).
 
107
        For destination axis, get those from account_id default configuration (default_destination_id).
 
108
        """
 
109
        # Some verifications
 
110
        if not context:
 
111
            context = {}
 
112
        if isinstance(ids, (int, long)):
 
113
            ids = [ids]
 
114
        # Prepare some values
 
115
        res = {}
 
116
        # Browse distributions
 
117
        for distrib in self.browse(cr, uid, ids, context=context):
 
118
            if distrib.funding_pool_lines:
 
119
                res[distrib.id] = False
 
120
                continue
 
121
            # Browse cost center lines
 
122
            for line in distrib.cost_center_lines:
 
123
                # Search MSF Private Fund
 
124
                try:
 
125
                    pf_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution',
 
126
                    'analytic_account_msf_private_funds')[1]
 
127
                except ValueError:
 
128
                    pf_id = 0
 
129
                if pf_id:
 
130
                    vals = {
 
131
                        'analytic_id': pf_id,
 
132
                        'amount': line.amount or 0.0,
 
133
                        'percentage': line.percentage or 0.0,
 
134
                        'currency_id': line.currency_id and line.currency_id.id or False,
 
135
                        'distribution_id': distrib.id or False,
 
136
                        'cost_center_id': line.analytic_id and line.analytic_id.id or False,
 
137
                        'destination_id': line.destination_id and line.destination_id.id or False,
 
138
                    }
 
139
                    if distrib and distrib.partner_type:
 
140
                        vals.update({'partner_type': distrib.partner_type})
 
141
 
 
142
                    # Search default destination if no one given
 
143
                    if account_id and not vals.get('destination_id'):
 
144
                        account = self.pool.get('account.account').browse(cr, uid, account_id)
 
145
                        if account and account.is_analytic_addicted:
 
146
                            vals.update({'destination_id': account.default_destination_id and account.default_destination_id.id or False})
 
147
                    self.pool.get('funding.pool.distribution.line').create(cr, uid, vals, context=context)
 
148
            res[distrib.id] = True
 
149
        return res
 
150
 
 
151
    def create_analytic_lines(self, cr, uid, ids, name, date, amount, journal_id, currency_id, document_date=False, ref=False, source_date=False, general_account_id=False, \
 
152
        move_id=False, invoice_line_id=False, commitment_line_id=False, context=None):
 
153
        """
 
154
        Create analytic lines from given elements:
 
155
         - date
 
156
         - name
 
157
         - amount
 
158
         - journal_id (analytic_journal_id)
 
159
         - currency_id
 
160
         - ref (optional)
 
161
         - source_date (optional)
 
162
         - general_account_id (optional)
 
163
         - move_id (optional)
 
164
         - invoice_line_id (optional)
 
165
         - commitment_line_id (optional)
 
166
        Return all created ids, otherwise return false (or [])
 
167
        """
 
168
        # Some verifications
 
169
        if not context:
 
170
            context = {}
 
171
        if isinstance(ids, (int, long)):
 
172
            ids = [ids]
 
173
        if not name or not date or not amount or not journal_id or not currency_id:
 
174
            return False
 
175
        if not document_date:
 
176
            document_date = date
 
177
        # Prepare some values
 
178
        res = []
 
179
        vals = {
 
180
            'name': name,
 
181
            'date': source_date or date,
 
182
            'document_date': document_date,
 
183
            'ref': ref or '',
 
184
            'journal_id': journal_id,
 
185
            'general_account_id': general_account_id or False,
 
186
            'move_id': move_id or False,
 
187
            'invoice_line_id': invoice_line_id or False,
 
188
            'user_id': uid,
 
189
            'currency_id': currency_id,
 
190
            'source_date': source_date or False,
 
191
            'commitment_line_id': commitment_line_id or False,
 
192
        }
 
193
        company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
 
194
        # Browse distribution(s)
 
195
        for distrib in self.browse(cr, uid, ids, context=context):
 
196
            vals.update({'distribution_id': distrib.id,})
 
197
            # create lines
 
198
            for distrib_lines in [distrib.funding_pool_lines, distrib.free_1_lines, distrib.free_2_lines]:
 
199
                for distrib_line in distrib_lines:
 
200
                    context.update({'date': source_date or date}) # for amount computing
 
201
                    anal_amount = (distrib_line.percentage * amount) / 100
 
202
                    vals.update({
 
203
                        'amount': -1 * self.pool.get('res.currency').compute(cr, uid, currency_id, company_currency,
 
204
                            anal_amount, round=False, context=context),
 
205
                        'amount_currency': -1 * anal_amount,
 
206
                        'account_id': distrib_line.analytic_id.id,
 
207
                        'cost_center_id': False,
 
208
                        'destination_id': False,
 
209
                        'distrib_line_id': '%s,%s'%(distrib_line._name, distrib_line.id),
 
210
                    })
 
211
                    # Update values if we come from a funding pool
 
212
                    if distrib_line._name == 'funding.pool.distribution.line':
 
213
                        vals.update({'cost_center_id': distrib_line.cost_center_id and distrib_line.cost_center_id.id or False,
 
214
                            'destination_id': distrib_line.destination_id and distrib_line.destination_id.id or False,})
 
215
                    # create analytic line
 
216
                    al_id = self.pool.get('account.analytic.line').create(cr, uid, vals, context=context)
 
217
                    res.append(al_id)
 
218
        return res
 
219
 
 
220
analytic_distribution1()
 
221
 
 
222
class distribution_line(osv.osv):
 
223
    _name = "distribution.line"
 
224
 
 
225
    _columns = {
 
226
        'name': fields.char('Name', size=64),
 
227
        "distribution_id": fields.many2one('analytic.distribution', 'Associated Analytic Distribution', ondelete='cascade', select="1"), # select is for optimisation purposes. Example: 3 seconds on 1 invoice creation+validation
 
228
        "analytic_id": fields.many2one('account.analytic.account', 'Analytical Account'),
 
229
        "amount": fields.float('Amount', digits_compute=dp.get_precision('Account')),
 
230
        "percentage": fields.float('Percentage', digits=(16,4)),
 
231
        "currency_id": fields.many2one('res.currency', 'Currency', required=True),
 
232
        "date": fields.date(string="Date"),
 
233
        "source_date": fields.date(string="Source Date", help="This date is for source_date for analytic lines"),
 
234
        'partner_type': fields.text(string='Partner Type of FO/PO', required=False, readonly=True),
 
235
    }
 
236
 
 
237
    _defaults ={
 
238
        'name': 'Distribution Line',
 
239
        'date': lambda *a: strftime('%Y-%m-%d'),
 
240
        'source_date': lambda *a: strftime('%Y-%m-%d'),
 
241
    }
 
242
 
 
243
    def _check_percentage(self, cr, uid, ids, context=None):
 
244
        """
 
245
        Do not allow 0.0 percentage value
 
246
        """
 
247
        for l in self.browse(cr, uid, ids):
 
248
            if l.percentage == 0.0:
 
249
                return False
 
250
        return True
 
251
 
 
252
    _constraints = [
 
253
        (_check_percentage, '0 is not allowed as percentage value!', ['percentage']),
 
254
    ]
 
255
 
 
256
    def create_analytic_lines(self, cr, uid, ids, move_line_id, date, document_date, source_date=False, name=False, ref='', context=None):
 
257
        '''
 
258
        Creates an analytic lines from a distribution line and an account.move.line
 
259
        '''
 
260
        if isinstance(ids, (int, long)):
 
261
            ids = [ids]
 
262
 
 
263
        ret = {}
 
264
        move_line = self.pool.get('account.move.line').browse(cr, uid, move_line_id)
 
265
        company = self.pool.get('res.users').browse(cr, uid, uid).company_id
 
266
        company_currency_id = company.currency_id.id
 
267
        instance_id = company.instance_id.id
 
268
 
 
269
        for line in self.browse(cr, uid, ids):
 
270
            amount_cur = (move_line.credit_currency - move_line.debit_currency) * line.percentage / 100
 
271
            ctx = {'date': source_date or date}
 
272
            amount = self.pool.get('res.currency').compute(cr, uid, move_line.currency_id.id, company_currency_id, amount_cur, round=False, context=ctx)
 
273
            vals = {
 
274
                'instance_id': instance_id,
 
275
                'account_id': line.analytic_id.id,
 
276
                'amount_currency': amount_cur,
 
277
                'amount': amount,
 
278
                'currency_id': move_line.currency_id.id,
 
279
                'general_account_id': move_line.account_id.id,
 
280
                'date': date,
 
281
                # UFTP-361: source_date or source date from line or from line posting date if any
 
282
                # for rev line must be the source date of the move line: posting date of reversed line
 
283
                'source_date': source_date or move_line.source_date or move_line.date,
 
284
                'document_date': document_date,
 
285
                'journal_id': move_line.journal_id and move_line.journal_id.analytic_journal_id and move_line.journal_id.analytic_journal_id.id or False,
 
286
                'move_id': move_line.id,
 
287
                'name': name or move_line.name,
 
288
                'distrib_id': line.distribution_id.id,
 
289
                'distribution_id': line.distribution_id.id,
 
290
                'distrib_line_id': '%s,%s'%(self._name, line.id),
 
291
                'ref': ref or move_line.move_id.name,
 
292
            }
 
293
            if self._name == 'funding.pool.distribution.line':
 
294
                vals.update({
 
295
                    'destination_id': line.destination_id and line.destination_id.id or False,
 
296
                    'cost_center_id': line.cost_center_id and line.cost_center_id.id or False,
 
297
                })
 
298
            ret[line.id] = self.pool.get('account.analytic.line').create(cr, uid, vals)
 
299
 
 
300
        return ret
 
301
 
 
302
distribution_line()
 
303
 
 
304
class cost_center_distribution_line(osv.osv):
 
305
    _name = "cost.center.distribution.line"
 
306
    _inherit = "distribution.line"
 
307
    _columns = {
 
308
        "destination_id": fields.many2one('account.analytic.account', 'Destination', domain="[('type', '!=', 'view'), ('category', '=', 'DEST')]", required=True),
 
309
    }
 
310
 
 
311
cost_center_distribution_line()
 
312
 
 
313
class funding_pool_distribution_line(osv.osv):
 
314
    _name = "funding.pool.distribution.line"
 
315
    _inherit = "distribution.line"
 
316
    _columns = {
 
317
        "cost_center_id": fields.many2one('account.analytic.account', 'Cost Center Account', required=True),
 
318
        "destination_id": fields.many2one('account.analytic.account', 'Destination', domain="[('type', '!=', 'view'), ('category', '=', 'DEST')]", required=True),
 
319
    }
 
320
 
 
321
funding_pool_distribution_line()
 
322
 
 
323
class free_1_distribution_line(osv.osv):
 
324
    _name = "free.1.distribution.line"
 
325
    _inherit = "distribution.line"
 
326
    _columns = {
 
327
        "destination_id": fields.many2one('account.analytic.account', 'Destination', domain="[('type', '!=', 'view'), ('category', '=', 'DEST')]", required=False),
 
328
    }
 
329
 
 
330
free_1_distribution_line()
 
331
 
 
332
class free_2_distribution_line(osv.osv):
 
333
    _name = "free.2.distribution.line"
 
334
    _inherit = "distribution.line"
 
335
    _columns = {
 
336
        "destination_id": fields.many2one('account.analytic.account', 'Destination', domain="[('type', '!=', 'view'), ('category', '=', 'DEST')]", required=False),
 
337
    }
 
338
 
 
339
free_2_distribution_line()
 
340
 
 
341
class analytic_distribution(osv.osv):
 
342
    _name = 'analytic.distribution'
 
343
    _inherit = "analytic.distribution"
 
344
 
 
345
    def _get_lines_count(self, cr, uid, ids, name=False, args=False, context=None):
 
346
        """
 
347
        Get count of each analytic distribution lines type.
 
348
        Example: with an analytic distribution with 2 cost center, 3 funding pool and 1 Free 1:
 
349
        2 CC; 3 FP; 1 F1; 0 F2;
 
350
        (Number of chars: 20 chars + 4 x some lines number)
 
351
        """
 
352
        # Some verifications
 
353
        if not context:
 
354
            context = {}
 
355
        # Prepare some values
 
356
        res = {}
 
357
        if not ids:
 
358
            return res
 
359
        if isinstance(ids, (int, long)):
 
360
            ids = [ids]
 
361
        # Browse given invoices
 
362
        for distrib in self.browse(cr, uid, ids, context=context):
 
363
            txt = ''
 
364
            txt += str(len(distrib.cost_center_lines) or '0') + ' CC; '
 
365
            txt += str(len(distrib.funding_pool_lines) or '0') + ' FP; '
 
366
            txt += str(len(distrib.free_1_lines) or '0') + ' F1; '
 
367
            txt += str(len(distrib.free_2_lines) or '0') + ' F2'
 
368
            if not txt:
 
369
                txt = ''
 
370
            res[distrib.id] = txt
 
371
        return res
 
372
 
 
373
    _columns = {
 
374
        'cost_center_lines': fields.one2many('cost.center.distribution.line', 'distribution_id', 'Cost Center Distribution'),
 
375
        'funding_pool_lines': fields.one2many('funding.pool.distribution.line', 'distribution_id', 'Funding Pool Distribution'),
 
376
        'free_1_lines': fields.one2many('free.1.distribution.line', 'distribution_id', 'Free 1 Distribution'),
 
377
        'free_2_lines': fields.one2many('free.2.distribution.line', 'distribution_id', 'Free 2 Distribution'),
 
378
        'name': fields.function(_get_lines_count, method=True, type='char', size=256, string="Name", readonly=True, store=False),
 
379
    }
 
380
 
 
381
analytic_distribution()
 
382
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: