1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
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.
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.
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/>.
20 ##############################################################################
22 from openerp.osv import fields, osv
24 #----------------------------------------------------------
26 #----------------------------------------------------------
27 class procurement_rule(osv.osv):
28 _inherit = 'procurement.rule'
30 'invoice_state': fields.selection([
31 ("invoiced", "Invoiced"),
32 ("2binvoiced", "To Be Invoiced"),
33 ("none", "Not Applicable")], "Invoice Status",
37 #----------------------------------------------------------
39 #----------------------------------------------------------
42 class procurement_order(osv.osv):
43 _inherit = "procurement.order"
45 'invoice_state': fields.selection([("invoiced", "Invoiced"),
46 ("2binvoiced", "To Be Invoiced"),
47 ("none", "Not Applicable")
48 ], "Invoice Control", required=True),
51 def _run_move_create(self, cr, uid, procurement, context=None):
52 res = super(procurement_order, self)._run_move_create(cr, uid, procurement, context=context)
53 res.update({'invoice_state': (procurement.rule_id.invoice_state in ('none', False) and procurement.invoice_state or procurement.rule_id.invoice_state) or 'none'})
57 'invoice_state': 'none'
61 #----------------------------------------------------------
63 #----------------------------------------------------------
65 class stock_move(osv.osv):
66 _inherit = "stock.move"
68 'invoice_state': fields.selection([("invoiced", "Invoiced"),
69 ("2binvoiced", "To Be Invoiced"),
70 ("none", "Not Applicable")], "Invoice Control",
71 select=True, required=True, track_visibility='onchange',
72 states={'draft': [('readonly', False)]}),
75 'invoice_state': lambda *args, **argv: 'none'
78 def _get_master_data(self, cr, uid, move, company, context=None):
79 ''' returns a tupple (browse_record(res.partner), ID(res.users), ID(res.currency)'''
80 return move.picking_id.partner_id, uid, company.currency_id.id
82 def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):
83 return self.pool.get('account.invoice.line').create(cr, uid, invoice_line_vals, context=context)
85 def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
86 fp_obj = self.pool.get('account.fiscal.position')
88 if inv_type in ('out_invoice', 'out_refund'):
89 account_id = move.product_id.property_account_income.id
91 account_id = move.product_id.categ_id.property_account_income_categ.id
93 account_id = move.product_id.property_account_expense.id
95 account_id = move.product_id.categ_id.property_account_expense_categ.id
96 fiscal_position = partner.property_account_position
97 account_id = fp_obj.map_account(cr, uid, fiscal_position, account_id)
99 # set UoS if it's a sale and the picking doesn't have one
100 uos_id = move.product_uom.id
101 quantity = move.product_uom_qty
103 uos_id = move.product_uos.id
104 quantity = move.product_uos_qty
107 'account_id': account_id,
108 'product_id': move.product_id.id,
110 'quantity': quantity,
111 'price_unit': move.product_id.list_price, # TODO: use price_get
113 'account_analytic_id': False,
116 #----------------------------------------------------------
118 #----------------------------------------------------------
120 class stock_picking(osv.osv):
121 _inherit = 'stock.picking'
122 def __get_invoice_state(self, cr, uid, ids, name, arg, context=None):
124 for pick in self.browse(cr, uid, ids, context=context):
125 result[pick.id] = 'none'
126 for move in pick.move_lines:
127 if move.invoice_state == 'invoiced':
128 result[pick.id] = 'invoiced'
129 elif move.invoice_state == '2binvoiced':
130 result[pick.id] = '2binvoiced'
134 def __get_picking_move(self, cr, uid, ids, context={}):
136 for move in self.pool.get('stock.move').browse(cr, uid, ids, context=context):
138 res.append(move.picking_id.id)
142 'invoice_state': fields.function(__get_invoice_state, type='selection', selection=[
143 ("invoiced", "Invoiced"),
144 ("2binvoiced", "To Be Invoiced"),
145 ("none", "Not Applicable")
146 ], string="Invoice Control", required=True,
149 'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['state'], 10),
150 'stock.move': (__get_picking_move, ['picking_id', 'invoice_state'], 10),
155 'invoice_state': lambda *args, **argv: 'none'
158 def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None):
159 ''' This function simply creates the invoice from the given values. It is overriden in delivery module to add the delivery costs.
161 invoice_obj = self.pool.get('account.invoice')
162 return invoice_obj.create(cr, uid, vals, context=context)
164 def action_invoice_create(self, cr, uid, ids, journal_id=False, group=False, type='out_invoice', context=None):
165 """ Creates invoice based on the invoice state selected for picking.
166 @param journal_id: Id of journal
167 @param group: Whether to create a group invoice or not
168 @param type: Type invoice to be created
169 @return: Ids of created invoices for the pickings
171 context = context or {}
173 for picking in self.browse(cr, uid, ids, context=context):
174 key = group and picking.id or True
175 for move in picking.move_lines:
176 if move.procurement_id and (move.procurement_id.invoice_state == '2binvoiced') or move.invoice_state == '2binvoiced':
177 if (move.state != 'cancel') and not move.scrapped:
178 todo.setdefault(key, [])
179 todo[key].append(move)
181 for moves in todo.values():
182 invoices = self.__invoice_create_line(cr, uid, moves, journal_id, type, context=context)
185 def __invoice_create_line(self, cr, uid, moves, journal_id=False, inv_type='out_invoice', context=None):
186 invoice_obj = self.pool.get('account.invoice')
187 move_obj = self.pool.get('stock.move')
190 company = move.company_id
191 origin = move.picking_id.name
192 partner, user_id, currency_id = move_obj._get_master_data(cr, uid, move, company, context=context)
194 key = (partner.id, currency_id, company.id, user_id)
196 if key not in invoices:
197 # Get account and payment terms
198 if inv_type in ('out_invoice', 'out_refund'):
199 account_id = partner.property_account_receivable.id
200 payment_term = partner.property_payment_term.id or False
202 account_id = partner.property_account_payable.id
203 payment_term = partner.property_supplier_payment_term.id or False
207 'date_invoice': context.get('date_inv', False),
209 'partner_id': partner.id,
210 'account_id': account_id,
211 'payment_term': payment_term,
213 'fiscal_position': partner.property_account_position.id,
214 'company_id': company.id,
215 'currency_id': currency_id,
216 'journal_id': journal_id,
218 invoice_id = self._create_invoice_from_picking(cr, uid, move.picking_id, invoice_vals, context=context)
219 invoices[key] = invoice_id
221 invoice_line_vals = move_obj._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
222 invoice_line_vals['invoice_id'] = invoices[key]
223 invoice_line_vals['origin'] = origin
225 move_obj._create_invoice_line_from_vals(cr, uid, move, invoice_line_vals, context=context)
227 move_obj.write(cr, uid, move.id, {'invoice_state': 'invoiced'}, context=context)
228 if move.procurement_id:
229 self.pool.get('procurement.order').write(cr, uid, [move.procurement_id.id], {
230 'invoice_state': 'invoiced',
233 invoice_obj.button_compute(cr, uid, invoices.values(), context=context, set_total=(inv_type in ('in_invoice', 'in_refund')))
234 return invoices.values()