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

« back to all changes in this revision

Viewing changes to account_journal/invoice.py

  • Committer: Quentin THEURET
  • Date: 2011-12-12 08:02:59 UTC
  • mto: This revision was merged to the branch mainline in revision 724.
  • Revision ID: qt@tempo-consulting.fr-20111212080259-oul1f0g37hcpubyc
UF-641 [ADD] Added the empty purchase_followup module

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
#-*- encoding:utf-8 -*-
 
3
##############################################################################
 
4
#
 
5
#    OpenERP, Open Source Management Solution
 
6
#    Copyright (C) 2011 TeMPO Consulting, MSF. All Rights Reserved
 
7
#    Developer: Olivier DOSSMANN
 
8
#
 
9
#    This program is free software: you can redistribute it and/or modify
 
10
#    it under the terms of the GNU Affero General Public License as
 
11
#    published by the Free Software Foundation, either version 3 of the
 
12
#    License, or (at your option) any later version.
 
13
#
 
14
#    This program is distributed in the hope that it will be useful,
 
15
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
#    GNU Affero General Public License for more details.
 
18
#
 
19
#    You should have received a copy of the GNU Affero General Public License
 
20
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
#
 
22
##############################################################################
 
23
 
 
24
from osv import osv
 
25
from osv import fields
 
26
from tools.translate import _
 
27
from datetime import datetime
 
28
 
 
29
class account_invoice(osv.osv):
 
30
    _name = 'account.invoice'
 
31
    _inherit = 'account.invoice'
 
32
 
 
33
    def action_cancel(self, cr, uid, ids, context={}, *args):
 
34
        """
 
35
        Delete engagement journal lines if exists
 
36
        """
 
37
        # Some verifications
 
38
        if not context:
 
39
            context={}
 
40
        if isinstance(ids, (int, long)):
 
41
            ids = [ids]
 
42
        # Prepare some values
 
43
        analytic_line_obj = self.pool.get('account.analytic.line')
 
44
        # Unlink all engagement journal lines
 
45
        for inv in self.browse(cr, uid, ids, context=context):
 
46
            for invl_line in inv.invoice_line:
 
47
                if invl_line.analytic_line_ids:
 
48
                    analytic_line_obj.unlink(cr, uid, [x.id for x in invl_line.analytic_line_ids], context=context)
 
49
        res = super(account_invoice, self).action_cancel(cr, uid, ids, context, args)
 
50
        return True
 
51
 
 
52
    def action_cancel_draft(self, cr, uid, ids, context={}, *args):
 
53
        """
 
54
        Recreate engagement journal lines when resetting invoice to draft state
 
55
        """
 
56
        # Some verifications
 
57
        if not context:
 
58
            context={}
 
59
        if isinstance(ids, (int, long)):
 
60
            ids = [ids]
 
61
        res = super(account_invoice, self).action_cancel_draft(cr, uid, ids, args)
 
62
        # Recreate engagement journal lines
 
63
        for inv in self.browse(cr, uid, ids, context=context):
 
64
            self.pool.get('account.invoice.line').create_engagement_lines(cr, uid, [x.id for x in inv.invoice_line], context=context)
 
65
        return res
 
66
 
 
67
    def action_reverse_engagement_lines(self, cr, uid, ids, context, *args):
 
68
        """
 
69
        Reverse an engagement lines with an opposite amount
 
70
        """
 
71
        if not context:
 
72
            context = {}
 
73
        eng_obj = self.pool.get('account.analytic.line')
 
74
        # Browse invoice
 
75
        for inv in self.browse(cr, uid, ids, context=context):
 
76
            # Search engagement journal line ids
 
77
            invl_ids = [x.id for x in inv.invoice_line]
 
78
            eng_ids = eng_obj.search(cr, uid, [('invoice_line_id', 'in', invl_ids)])
 
79
            # Browse engagement journal line ids
 
80
            for eng in eng_obj.browse(cr, uid, eng_ids, context=context):
 
81
                # Create new line and change some fields:
 
82
                # - name with REV
 
83
                # - amount * -1
 
84
                # - date with invoice_date
 
85
                # Copy this line for reverse
 
86
                new_line_id = eng_obj.copy(cr, uid, eng.id, context=context)
 
87
                # Prepare reverse values
 
88
                vals = {
 
89
                    'name': eng_obj.join_without_redundancy(eng.name, 'REV'),
 
90
                    'amount': eng.amount * -1,
 
91
                    'date': inv.date_invoice,
 
92
                    'reversal_origin': eng.id,
 
93
                    'amount_currency': eng.amount_currency * -1,
 
94
                    'currency_id': eng.currency_id.id,
 
95
                }
 
96
                # Write changes
 
97
                eng_obj.write(cr, uid, [new_line_id], vals, context=context)
 
98
        return True
 
99
 
 
100
    def action_open_invoice(self, cr, uid, ids, context={}, *args):
 
101
        """
 
102
        Reverse engagement lines before opening invoice
 
103
        """
 
104
        res = super(account_invoice, self).action_open_invoice(cr, uid, ids, context, args)
 
105
        if not self.action_reverse_engagement_lines(cr, uid, ids, context, args):
 
106
            return False
 
107
        return res
 
108
 
 
109
account_invoice()
 
110
 
 
111
class account_invoice_line(osv.osv):
 
112
    _name = 'account.invoice.line'
 
113
    _inherit = 'account.invoice.line'
 
114
 
 
115
    _columns = {
 
116
        'analytic_line_ids': fields.one2many('account.analytic.line', 'invoice_line_id', string="Analytic line", 
 
117
            help="An analytic line linked with this invoice from an engagement journal (theorically)"),
 
118
    }
 
119
 
 
120
    def create_engagement_lines(self, cr, uid, ids, context={}):
 
121
        """
 
122
        Create engagement journal lines from given invoice lines (ids)
 
123
        """
 
124
        # Some verifications
 
125
        if not context:
 
126
            context={}
 
127
        if isinstance(ids, (int, long)):
 
128
            ids = [ids]
 
129
        # Prepare some values
 
130
        analytic_line_obj = self.pool.get('account.analytic.line')
 
131
        j_obj = self.pool.get('account.analytic.journal')
 
132
        journals = j_obj.search(cr, uid, [('type', '=', 'engagement')])
 
133
        analytic_acc_obj = self.pool.get('account.analytic.account')
 
134
        plan_line_obj = self.pool.get('account.analytic.plan.instance.line')
 
135
        journal = journals and journals[0] or False
 
136
        if not journal:
 
137
            raise osv.except_osv(_('Error'), _('No engagement journal found!'))
 
138
        engagement_line_ids = []
 
139
        company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
 
140
        for inv_line in self.browse(cr, uid, ids, context=context):
 
141
            # Don't create engagement journal line if the invoice come from a purchase list
 
142
            if inv_line.invoice_id.purchase_list or inv_line.invoice_id.state!='draft':
 
143
                continue
 
144
            # Search old engagement journal lines to be deleted (to not have split invoice problem that delete not engagement journal lines)
 
145
            analytic_line_ids = analytic_line_obj.search(cr, uid, [('invoice_line_id', '=', inv_line.id)], context=context)
 
146
            analytic_line_obj.unlink(cr, uid, analytic_line_ids, context=context)
 
147
            if inv_line.analytic_distribution_id:
 
148
                # Search distribution lines
 
149
                distrib_obj = self.pool.get('analytic.distribution').browse(cr, uid, inv_line.analytic_distribution_id.id, context=context)
 
150
                for distrib_lines in [distrib_obj.cost_center_lines, distrib_obj.funding_pool_lines, distrib_obj.free_1_lines, distrib_obj.free_2_lines]:
 
151
                    for distrib_line in distrib_lines:
 
152
                        date = inv_line.invoice_id.date_invoice
 
153
                        if not date:
 
154
                            perm = self.perm_read(cr, uid, [inv_line.id], context=context)
 
155
                            if perm and 'create_date' in perm[0]:
 
156
                                date = datetime.strptime(perm[0].get('create_date').split('.')[0], '%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d')
 
157
                        # Prepare some values
 
158
                        invoice_currency = inv_line.invoice_id.currency_id.id
 
159
                        amount = round(distrib_line.percentage * 
 
160
                            self.pool.get('account.invoice.line')._amount_line(cr, uid, [inv_line.id], None, None, {})[inv_line.id]) / 100.0
 
161
                        if inv_line.invoice_id.type in ['in_invoice', 'out_refund']:
 
162
                            amount = -1 * amount
 
163
                        context.update({'date': date})
 
164
                        al_vals = {
 
165
                            'name': inv_line.name,
 
166
                            'date': date,
 
167
                            'account_id': distrib_line.analytic_id and distrib_line.analytic_id.id or False,
 
168
                            'unit_amount': inv_line.quantity,
 
169
                            'product_id': inv_line.product_id and inv_line.product_id.id or False,
 
170
                            'product_uom_id': inv_line.uos_id and inv_line.uos_id.id or False,
 
171
                            'amount': self.pool.get('res.currency').compute(cr, uid, invoice_currency, company_currency, amount or 0.0, round=False, context=context),
 
172
                            'amount_currency': amount or 0.0,
 
173
                            'currency_id': invoice_currency,
 
174
                            'general_account_id': inv_line.account_id.id,
 
175
                            'journal_id': journal,
 
176
                            'source_date': date,
 
177
                            'invoice_line_id': inv_line.id,
 
178
                        }
 
179
                        # Update values if we come from a funding pool
 
180
                        if distrib_line._name == 'funding.pool.distribution.line':
 
181
                            al_vals.update({'cost_center_id': distrib_line.cost_center_id and distrib_line.cost_center_id.id or False,})
 
182
                        res = analytic_line_obj.create(cr, uid, al_vals, context=context)
 
183
                        engagement_line_ids.append(res)
 
184
        return engagement_line_ids or False
 
185
 
 
186
    def create(self, cr, uid, vals, context={}):
 
187
        """
 
188
        Add engagement journal lines creation when creating a new invoice line
 
189
        """
 
190
        if not context:
 
191
            context={}
 
192
        # Default behaviour
 
193
        res = super(account_invoice_line, self).create(cr, uid, vals, context=context)
 
194
        # FIXME / TODO: Verify that this invoice line don't come from a standard donation or purchase list
 
195
        # Verify that the invoice is in draft state
 
196
        if res and vals.get('invoice_id'):
 
197
            invoice_id = vals.get('invoice_id')
 
198
            objname = self._name == 'wizard.account.invoice.line' and 'wizard.account.invoice' or 'account.invoice'
 
199
            state = self.pool.get(objname).read(cr, uid, [invoice_id], ['state'])[0].get('state', False)
 
200
            # if invoice in draft state, do engagement journal lines
 
201
            if state and state == 'draft':
 
202
                self.create_engagement_lines(cr, uid, [res], context=context)
 
203
        return res
 
204
 
 
205
    def write(self, cr, uid, ids, vals, context={}):
 
206
        """
 
207
        Update engagement journal lines
 
208
        """
 
209
        # Some verifications
 
210
        if not context:
 
211
            context={}
 
212
        if isinstance(ids, (int, long)):
 
213
            ids = [ids]
 
214
        # Prepare some values
 
215
        analytic_line_obj = self.pool.get('account.analytic.line')
 
216
        # Write object
 
217
        res = super(account_invoice_line, self).write(cr, uid, ids, vals, context=context)
 
218
        # Search analytic lines to remove
 
219
        to_remove = analytic_line_obj.search(cr, uid, [('invoice_line_id', 'in', ids)], context=context)
 
220
        # Search analytic line to create
 
221
        to_create = []
 
222
        for inv_line in self.pool.get('account.invoice.line').browse(cr, uid, ids, context=context):
 
223
            # Don't create any line if state not draft
 
224
            if inv_line.invoice_id.state != 'draft':
 
225
                continue
 
226
            if inv_line.analytic_distribution_id:
 
227
                to_create.append(inv_line.id)
 
228
        if to_create:
 
229
            # Create new analytic lines
 
230
            self.create_engagement_lines(cr, uid, to_create, context=context)
 
231
        return res
 
232
 
 
233
account_invoice_line()
 
234
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: