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

« back to all changes in this revision

Viewing changes to analytic_distribution_invoice/invoice.py

  • Committer: jf
  • Date: 2014-06-18 08:26:21 UTC
  • Revision ID: jfb@tempo-consulting.fr-20140618082621-cptq430pbwqo6z1t
Tags: pilot3.1b2
UFTP-249 [FIX] Reference field not imported in Unifield when importing register lines
lp:~unifield-team/unifield-wm/UFTP-78 2000..2001

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) 2011 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 tools.translate import _
25
 
 
26
 
class account_invoice(osv.osv):
27
 
    _name = 'account.invoice'
28
 
    _inherit = 'account.invoice'
29
 
 
30
 
    def _check_active_product(self, cr, uid, ids, context=None):
31
 
        '''
32
 
        Check if the Purchase order contains a line with an inactive products
33
 
        '''
34
 
        inactive_lines = self.pool.get('account.invoice.line').search(cr, uid, [
35
 
            ('product_id.active', '=', False),
36
 
            ('invoice_id', 'in', ids),
37
 
            ('invoice_id.state', 'not in', ['draft', 'cancel', 'done'])
38
 
        ], context=context)
39
 
        
40
 
        if inactive_lines:
41
 
            plural = len(inactive_lines) == 1 and _('A product has') or _('Some products have')
42
 
            l_plural = len(inactive_lines) == 1 and _('line') or _('lines')
43
 
            p_plural = len(inactive_lines) == 1 and _('this inactive product') or _('those inactive products')
44
 
            raise osv.except_osv(_('Error'), _('%s been inactivated. If you want to validate this document you have to remove/correct the %s containing %s (see red %s of the document)') % (plural, l_plural, p_plural, l_plural))
45
 
            return False
46
 
        return True
47
 
    
48
 
    _constraints = [
49
 
        (_check_active_product, "You cannot validate this invoice because it contains a line with an inactive product", ['invoice_line', 'state'])
50
 
    ]
51
 
 
52
 
    def _check_analytic_distribution_state(self, cr, uid, ids, context=None):
53
 
        """
54
 
        Check if analytic distribution is valid
55
 
        """
56
 
        if not context:
57
 
            context = {}
58
 
        if isinstance(ids, (int, long)):
59
 
            ids = [ids]
60
 
        for inv in self.browse(cr, uid, ids, context=context):
61
 
            for invl in inv.invoice_line:
62
 
                if inv.from_yml_test or invl.from_yml_test:
63
 
                    continue
64
 
                if invl.analytic_distribution_state != 'valid':
65
 
                    raise osv.except_osv(_('Error'), _('Analytic distribution is not valid for "%s"') % invl.name)
66
 
        return True
67
 
 
68
 
    def button_close_direct_invoice(self, cr, uid, ids, context=None):
69
 
        """
70
 
        Check analytic distribution before closing pop-up
71
 
        """
72
 
        if not context:
73
 
            context = {}
74
 
        if isinstance(ids, (int, long)):
75
 
            ids = [ids]
76
 
        self._check_analytic_distribution_state(cr, uid, ids, context)
77
 
        if context.get('from_register', False):
78
 
            return {'type': 'ir.actions.act_window_close'}
79
 
        return True
80
 
 
81
 
    def _hook_fields_for_refund(self, cr, uid, *args):
82
 
        """
83
 
        Add these fields to result:
84
 
         - analytic_distribution_id
85
 
        """
86
 
        res = super(account_invoice, self)._hook_fields_for_refund(cr, uid, args)
87
 
        res.append('analytic_distribution_id')
88
 
        res.append('document_date')
89
 
        return res
90
 
 
91
 
    def _hook_fields_m2o_for_refund(self, cr, uid, *args):
92
 
        """
93
 
        Add these fields to result:
94
 
         - analytic_distribution_id
95
 
        """
96
 
        res = super(account_invoice, self)._hook_fields_m2o_for_refund(cr, uid, args)
97
 
        res.append('analytic_distribution_id')
98
 
        return res
99
 
 
100
 
    def _hook_refund_data(self, cr, uid, data, *args):
101
 
        """
102
 
        Copy analytic distribution for refund invoice
103
 
        """
104
 
        if not data:
105
 
            return False
106
 
        if 'analytic_distribution_id' in data:
107
 
            if data.get('analytic_distribution_id', False):
108
 
                data['analytic_distribution_id'] = self.pool.get('analytic.distribution').copy(cr, uid, data.get('analytic_distribution_id'), {}) or False
109
 
            else:
110
 
                data['analytic_distribution_id'] = False
111
 
        return data
112
 
 
113
 
    def _refund_cleanup_lines(self, cr, uid, lines):
114
 
        """
115
 
        Add right analytic distribution values on each lines
116
 
        """
117
 
        res = super(account_invoice, self)._refund_cleanup_lines(cr, uid, lines)
118
 
        for el in res:
119
 
            if el[2]:
120
 
                # Give analytic distribution on line
121
 
                if 'analytic_distribution_id' in el[2]:
122
 
                    if el[2].get('analytic_distribution_id', False) and el[2].get('analytic_distribution_id')[0]:
123
 
                        distrib_id = el[2].get('analytic_distribution_id')[0]
124
 
                        el[2]['analytic_distribution_id'] = self.pool.get('analytic.distribution').copy(cr, uid, distrib_id, {}) or False
125
 
                    else:
126
 
                        # default value
127
 
                        el[2]['analytic_distribution_id'] = False
128
 
                # Give false analytic lines for 'line' in order not to give an error
129
 
                if 'analytic_line_ids' in el[2]:
130
 
                    el[2]['analytic_line_ids'] = False
131
 
                # Give false order_line_id in order not to give an error
132
 
                if 'order_line_id' in el[2]:
133
 
                    el[2]['order_line_id'] = el[2].get('order_line_id', False) and el[2]['order_line_id'][0] or False
134
 
        return res
135
 
 
136
 
    def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=None, document_date=None):
137
 
        """
138
 
        Reverse lines for given invoice
139
 
        """
140
 
        if isinstance(ids, (int, long)):
141
 
            ids = [ids]
142
 
        for inv in self.browse(cr, uid, ids):
143
 
            # Check for dates (refund must be done after invoice)
144
 
            if date and date < inv.date_invoice:
145
 
                raise osv.except_osv(_('Error'), _("Posting date for the refund is before the invoice's posting date!"))
146
 
            if document_date and document_date < inv.document_date:
147
 
                raise osv.except_osv(_('Error'), _("Document date for the refund is before the invoice's document date!"))
148
 
        new_ids = super(account_invoice, self).refund(cr, uid, ids, date, period_id, description, journal_id)
149
 
        # add document date
150
 
        if document_date:
151
 
            self.write(cr, uid, new_ids, {'document_date': document_date})
152
 
        return new_ids
153
 
 
154
 
    def copy(self, cr, uid, id, default=None, context=None):
155
 
        """
156
 
        Copy global distribution and give it to new invoice
157
 
        """
158
 
        if not context:
159
 
            context = {}
160
 
        if not default:
161
 
            default = {}
162
 
        inv = self.browse(cr, uid, [id], context=context)[0]
163
 
        if inv.analytic_distribution_id:
164
 
            new_distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, inv.analytic_distribution_id.id, {}, context=context)
165
 
            if new_distrib_id:
166
 
                default.update({'analytic_distribution_id': new_distrib_id})
167
 
        return super(account_invoice, self).copy(cr, uid, id, default, context)
168
 
 
169
 
    def action_open_invoice(self, cr, uid, ids, context=None, *args):
170
 
        """
171
 
        Add verification on all lines for analytic_distribution_id to be present and valid !
172
 
        """
173
 
        # Some verifications
174
 
        if not context:
175
 
            context = {}
176
 
        if isinstance(ids, (int, long)):
177
 
            ids = [ids]
178
 
        # Browse invoice and all invoice lines to detect a non-valid line
179
 
        self._check_analytic_distribution_state(cr, uid, ids)
180
 
        return super(account_invoice, self).action_open_invoice(cr, uid, ids, context, args)
181
 
 
182
 
account_invoice()
183
 
 
184
 
class account_invoice_line(osv.osv):
185
 
    _name = 'account.invoice.line'
186
 
    _inherit = 'account.invoice.line'
187
 
 
188
 
    def _get_distribution_state(self, cr, uid, ids, name, args, context=None):
189
 
        """
190
 
        Get state of distribution:
191
 
         - if compatible with the invoice line, then "valid"
192
 
         - if no distribution, take a tour of invoice distribution, if compatible, then "valid"
193
 
         - if no distribution on invoice line and invoice, then "none"
194
 
         - all other case are "invalid"
195
 
        """
196
 
        # Some verifications
197
 
        if not context:
198
 
            context = {}
199
 
        if isinstance(ids, (int, long)):
200
 
            ids = [ids]
201
 
        # Prepare some values
202
 
        res = {}
203
 
        # Browse all given lines
204
 
        for line in self.browse(cr, uid, ids, context=context):
205
 
            if line.from_yml_test:
206
 
                res[line.id] = 'valid'
207
 
            else:
208
 
                res[line.id] = self.pool.get('analytic.distribution')._get_distribution_state(cr, uid, line.analytic_distribution_id.id, line.invoice_id.analytic_distribution_id.id, line.account_id.id)
209
 
        return res
210
 
 
211
 
    def _have_analytic_distribution_from_header(self, cr, uid, ids, name, arg, context=None):
212
 
        """
213
 
        If invoice have an analytic distribution, return False, else return True
214
 
        """
215
 
        # Some verifications
216
 
        if not context:
217
 
            context = {}
218
 
        if isinstance(ids, (int, long)):
219
 
            ids = [ids]
220
 
        res = {}
221
 
        for inv in self.browse(cr, uid, ids, context=context):
222
 
            res[inv.id] = True
223
 
            if inv.analytic_distribution_id:
224
 
                res[inv.id] = False
225
 
        return res
226
 
 
227
 
    def _get_is_allocatable(self, cr, uid, ids, name, arg, context=None):
228
 
        """
229
 
        If expense account, then this account is allocatable.
230
 
        """
231
 
        if isinstance(ids, (int, long)):
232
 
            ids = [ids]
233
 
        res = {}
234
 
        for invl in self.browse(cr, uid, ids):
235
 
            res[invl.id] = True
236
 
            if invl.account_id and invl.account_id.user_type and invl.account_id.user_type.code and invl.account_id.user_type.code != 'expense':
237
 
                res[invl.id] = False
238
 
        return res
239
 
 
240
 
    def _get_distribution_state_recap(self, cr, uid, ids, name, arg, context=None):
241
 
        """
242
 
        Get a recap from analytic distribution state and if it come from header or not.
243
 
        """
244
 
        if isinstance(ids, (int, long)):
245
 
            ids = [ids]
246
 
        res = {}
247
 
        for invl in self.browse(cr, uid, ids):
248
 
            res[invl.id] = ''
249
 
            if not invl.is_allocatable:
250
 
                continue
251
 
            from_header = ''
252
 
            if invl.have_analytic_distribution_from_header:
253
 
                from_header = _(' (from header)')
254
 
            res[invl.id] = '%s%s' % (self.pool.get('ir.model.fields').get_browse_selection(cr, uid, invl, 'analytic_distribution_state', context), from_header)
255
 
        return res
256
 
 
257
 
    def _get_inactive_product(self, cr, uid, ids, field_name, args, context=None):
258
 
        '''
259
 
        Fill the error message if the product of the line is inactive
260
 
        '''
261
 
        res = {}
262
 
        for line in self.browse(cr, uid, ids, context=context):
263
 
            res[line.id] = {'inactive_product': False,
264
 
                            'inactive_error': ''}
265
 
            if line.invoice_id and line.invoice_id.state not in ('cancel', 'done') and line.product_id and not line.product_id.active:
266
 
                res[line.id] = {
267
 
                    'inactive_product': True,
268
 
                    'inactive_error': _('The product in line is inactive !')
269
 
                }
270
 
                
271
 
        return res
272
 
 
273
 
    _columns = {
274
 
        'analytic_distribution_state': fields.function(_get_distribution_state, method=True, type='selection', 
275
 
            selection=[('none', 'None'), ('valid', 'Valid'), ('invalid', 'Invalid')], 
276
 
            string="Distribution state", help="Informs from distribution state among 'none', 'valid', 'invalid."),
277
 
        'have_analytic_distribution_from_header': fields.function(_have_analytic_distribution_from_header, method=True, type='boolean', 
278
 
            string='Header Distrib.?'),
279
 
        'newline': fields.boolean('New line'),
280
 
        'is_allocatable': fields.function(_get_is_allocatable, method=True, type='boolean', string="Is allocatable?", readonly=True, store=False),
281
 
        'analytic_distribution_state_recap': fields.function(_get_distribution_state_recap, method=True, type='char', size=30, 
282
 
            string="Distribution", 
283
 
            help="Informs you about analaytic distribution state among 'none', 'valid', 'invalid', from header or not, or no analytic distribution"),
284
 
        'inactive_product': fields.function(_get_inactive_product, method=True, type='boolean', string='Product is inactive', store=False, multi='inactive'),
285
 
        'inactive_error': fields.function(_get_inactive_product, method=True, type='char', string='Comment', store=False, multi='inactive'),
286
 
    }
287
 
    
288
 
    _defaults = {
289
 
        'newline': lambda *a: True,
290
 
        'have_analytic_distribution_from_header': lambda *a: True,
291
 
        'is_allocatable': lambda *a: True,
292
 
        'analytic_distribution_state_recap': lambda *a: '',
293
 
        'inactive_product': False,
294
 
        'inactive_error': lambda *a: '',
295
 
    }
296
 
 
297
 
    def create(self, cr, uid, vals, context=None):
298
 
        vals.update({'newline': False,})
299
 
        return super(account_invoice_line, self).create(cr, uid, vals, context)
300
 
 
301
 
    def copy_data(self, cr, uid, id, default=None, context=None):
302
 
        """
303
 
        Copy global distribution and give it to new invoice line
304
 
        """
305
 
        # Some verifications
306
 
        if not context:
307
 
            context = {}
308
 
        if not default:
309
 
            default = {}
310
 
        # Copy analytic distribution
311
 
        invl = self.browse(cr, uid, [id], context=context)[0]
312
 
        if invl.analytic_distribution_id:
313
 
            new_distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, invl.analytic_distribution_id.id, {}, context=context)
314
 
            if new_distrib_id:
315
 
                default.update({'analytic_distribution_id': new_distrib_id})
316
 
        return super(account_invoice_line, self).copy_data(cr, uid, id, default, context)
317
 
 
318
 
account_invoice_line()
319
 
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: