[IMP] Invoice on picking cleaned

bzr revid: fp@openerp.com-20130804115325-ejsbn2qoawnrgaic
This commit is contained in:
Fabien Pinckaers 2013-08-04 13:53:25 +02:00
parent dc62d65efa
commit c522a3d440
20 changed files with 141 additions and 668 deletions

View File

@ -61,7 +61,7 @@ class procurement_group(osv.osv):
('direct', 'Partial'), ('one', 'All at once')],
'Delivery Method', required=True),
'partner_id': fields.many2one('res.partner', string = 'Partner'), #Sale should pass it here
'procurement_ids': fields.many2one('procurement.order', 'group_id', 'Procurements'),
'procurement_ids': fields.one2many('procurement.order', 'group_id', 'Procurements'),
}
_defaults = {
'name': lambda self, cr, uid, c: self.pool.get('ir.sequence').get(cr, uid, 'procurement.group') or '',

View File

@ -286,7 +286,7 @@ class sale_order(osv.osv):
partner_lang = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context).lang
context_lang.update({'lang': partner_lang})
return self.pool.get('res.users').browse(cr, uid, uid, context=context_lang).company_id.sale_note
def onchange_partner_id(self, cr, uid, ids, part, context=None):
if not part:
return {'value': {'partner_invoice_id': False, 'partner_shipping_id': False, 'payment_term': False, 'fiscal_position': False}}
@ -635,6 +635,8 @@ class sale_order(osv.osv):
'company_id': order.company_id.id,
'note': line.name,
'group_id': group_id,
'invoice_state': (order.order_policy=='picking') and '2binvoiced' or 'none',
'sale_line_id': line.id
}
def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
@ -656,7 +658,7 @@ class sale_order(osv.osv):
procurement_obj = self.pool.get('procurement.order')
for order in self.browse(cr, uid, ids, context=context):
proc_ids = []
group_id = self.pool.get("procurement.group").create(cr, uid, {'name': order.name, 'sale_id': order.id}, context=context)
group_id = self.pool.get("procurement.group").create(cr, uid, {'name': order.name}, context=context)
order.write({'procurement_group_id': group_id}, context=context)
for line in order.order_line:
if (line.state == 'done') or not line.product_id:
@ -664,7 +666,7 @@ class sale_order(osv.osv):
proc_id = procurement_obj.create(cr, uid, self._prepare_order_line_procurement(cr, uid, order, line, group_id=group_id, context=context))
proc_ids.append(proc_id)
line.write({'procurement_id': proc_id})
#Confirm procurement order such that rules will be applied on it
procurement_obj.run(cr, uid, proc_ids, context=context)
# FP NOTE: do we need this? isn't it the workflow that should set this
@ -683,9 +685,6 @@ class sale_order(osv.osv):
# TODO add a field price_unit_uos
# - update it on change product and unit price
# - use it in report if there is a uos
@ -738,7 +737,8 @@ class sale_order_line(osv.osv):
'invoiced': fields.function(_fnct_line_invoiced, string='Invoiced', type='boolean',
store={
'account.invoice': (_order_lines_from_invoice, ['state'], 10),
'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10)}),
'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10)
}),
'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}),
'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]},
help="From stock: When needed, the product is taken from the stock or we wait for replenishment.\nOn order: When needed, the product is purchased or produced."),
@ -761,8 +761,7 @@ class sale_order_line(osv.osv):
'salesman_id':fields.related('order_id', 'user_id', type='many2one', relation='res.users', store=True, string='Salesperson'),
'company_id': fields.related('order_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
'delay': fields.float('Delivery Lead Time', required=True, help="Number of days between the order confirmation and the shipping of the products to the customer", readonly=True, states={'draft': [('readonly', False)]}),
'procurement_id': fields.many2one('procurement.order', 'Procurement'),
#'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties', readonly=True, states={'draft': [('readonly', False)]}),
'procurement_ids': fields.many2one('procurement.order', 'sale_line_ids', 'Procurements'),
}
_order = 'order_id desc, sequence, id'
_defaults = {
@ -841,11 +840,6 @@ class sale_order_line(osv.osv):
return res
def invoice_line_create(self, cr, uid, ids, context=None):
if context is None:
context = {}
@ -1075,12 +1069,20 @@ class account_invoice(osv.Model):
wf_service.trg_validate(uid, 'account.invoice', id, 'invoice_cancel', cr)
return super(account_invoice, self).unlink(cr, uid, ids, context=context)
class procurement_group(osv.osv):
_inherit = 'procurement.group'
class procurement_order(osv.osv):
_inherit = 'procurement.order'
_columns = {
'sale_id': fields.many2one('sale.order', string = 'Sales Order')
}
'sale_line_id': fields.many2one('sale.order.line', string = 'Sale Order Line')
'invoice_state': fields.selection(
[
("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable")
], "Invoice Control", required=True),
}
_defaults = {
'invoice_state': 'none',
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -25,4 +25,3 @@ import report
import company
import res_config
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -45,7 +45,7 @@ You can choose flexible invoicing methods:
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
'images': ['images/deliveries_to_invoice.jpeg'],
'depends': ['sale', 'stock_account', 'procurement'],
'depends': ['sale', 'stock_account'],
'init_xml': [],
'update_xml': ['security/sale_stock_security.xml',
'security/ir.model.access.csv',
@ -65,4 +65,3 @@ You can choose flexible invoicing methods:
'installable': True,
'auto_install': True,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -34,5 +34,3 @@ class company(osv.osv):
_defaults = {
'security_lead': 0.0,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -18,4 +18,5 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import sale_report
import sale_report

View File

@ -39,7 +39,6 @@ class sale_report(osv.osv):
('cancel', 'Cancelled')
], 'Order Status', readonly=True),
}
def init(self, cr):
tools.drop_view_if_exists(cr, 'sale_report')
cr.execute("""
@ -93,4 +92,3 @@ class sale_report(osv.osv):
)
""")
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -70,10 +70,11 @@ class sale_order(osv.osv):
if not sale.procurement_group_id:
res[sale.id] = []
continue
picking_ids = {}
for procurement in sale.procurement_group_id.procurement_ids:
if procurement.move_id and procurement.move_id.picking_id:
picking_ids.append(procurement.move_id.picking_id.id)
res[sale.id] = list(set(picking_ids))
picking_ids[procurement.move_id.picking_id.id] = True
res[sale.id] = picking_ids.keys()
return res
def _prepare_order_line_procurement(self, cr, uid, order, line, group_id = False, context=None):
@ -261,13 +262,6 @@ class sale_order(osv.osv):
res.append(line.procurement_id.id)
return res
class stock_move(osv.osv):
_inherit = 'stock.move'
_columns = {
'sale_line_id': fields.many2one('sale.order.line', 'Sale Line'),
}
class sale_order_line(osv.osv):
_inherit = 'sale.order.line'
@ -281,7 +275,6 @@ class sale_order_line(osv.osv):
return res
_columns = {
'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True),
'product_packaging': fields.many2one('product.packaging', 'Packaging'),
'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'),
}

View File

@ -38,22 +38,6 @@
<workflow action="order_confirm" model="sale.order" ref="sale.sale_order_1"/>
<workflow action="order_confirm" model="sale.order" ref="sale.sale_order_5"/>
<record id="sale.sale_order_line_4" model="sale.order.line">
<field name="type">make_to_order</field>
</record>
<record id="sale.sale_order_line_5" model="sale.order.line">
<field name="type">make_to_order</field>
</record>
<record id="sale.sale_order_line_6" model="sale.order.line">
<field name="type">make_to_order</field>
</record>
<record id="sale.sale_order_line_8" model="sale.order.line">
<field name="type">make_to_order</field>
</record>
<!-- Run all schedulers -->
<function model="procurement.order" name="run_scheduler"/>

View File

@ -24,98 +24,127 @@ from openerp.tools.translate import _
class stock_picking(osv.osv):
_inherit = 'stock.picking'
def __get_invoice_state(self, cursor, user, ids, name, arg, context=None):
result = {}
for pick in self.browse(cr, uid, ids, context=context):
result[pick.id] = 'none'
for move in pick.move_lines:
if move.procurement_id:
if move.procurement_id.invoice_state=='invoiced':
result[pick.id] = 'invoiced'
elif move.procurement_id.invoice_state=='2binvoiced':
result[pick.id] = '2binvoiced'
break
return result
_columns = {
'sale_id': fields.many2one('sale.order', 'Sales Order', ondelete='set null', select=True),
}
_defaults = {
'sale_id': False
# TODO: add a store=...
'invoice_state': fields.function(_get_invoice_state, type='selection', selection=[
("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable")
], "Invoice Control", required=True),
}
def get_currency_id(self, cursor, user, picking):
if picking.sale_id:
return picking.sale_id.pricelist_id.currency_id.id
else:
return super(stock_picking, self).get_currency_id(cursor, user, picking)
def _get_partner_to_invoice(self, cr, uid, picking, context=None):
""" Inherit the original function of the 'stock' module
We select the partner of the sales order as the partner of the customer invoice
def action_invoice_create(self, cr, uid, ids, journal_id=False, group=False, type='out_invoice', context=None):
""" Creates invoice based on the invoice state selected for picking.
@param journal_id: Id of journal
@param group: Whether to create a group invoice or not
@param type: Type invoice to be created
@return: Ids of created invoices for the pickings
"""
if picking.sale_id:
return picking.sale_id.partner_invoice_id
return super(stock_picking, self)._get_partner_to_invoice(cr, uid, picking, context=context)
context = context or {}
todo = {}
for picking in self.browse(cr, uid, ids, context=context):
key = group and picking.id or True
for move in picking.move_lines:
if (not move.procurement_id) or (move.procurement_id.invoice_state <> '2binvoiced'):
if (move.state <> 'cancel') and not move.scrapped:
todo[key].append(move)
for moves in todo.values():
self.__invoice_create_line(cr, uid, moves, journal_id, type, context=context)
return True
def _get_comment_invoice(self, cursor, user, picking):
if picking.note or (picking.sale_id and picking.sale_id.note):
return picking.note or picking.sale_id.note
return super(stock_picking, self)._get_comment_invoice(cursor, user, picking)
def __invoice_create_line(self, cr, uid, moves, journal_id=False, inv_type='out_invoice', context=None):
invoices = {}
for move in moves:
sale_line = move.procurement_id.sale_line_id
sale = sale_line.order_id
partner = sale.partner_invoice_id
def _prepare_invoice(self, cr, uid, picking, partner, inv_type, journal_id, context=None):
""" Inherit the original function of the 'stock' module in order to override some
values if the picking has been generated by a sales order
"""
invoice_vals = super(stock_picking, self)._prepare_invoice(cr, uid, picking, partner, inv_type, journal_id, context=context)
if picking.sale_id:
invoice_vals['fiscal_position'] = picking.sale_id.fiscal_position.id
invoice_vals['payment_term'] = picking.sale_id.payment_term.id
invoice_vals['user_id'] = picking.sale_id.user_id.id
invoice_vals['name'] = picking.sale_id.client_order_ref or ''
return invoice_vals
currency_id = sale.pricelist_id.currency_id.id
key = (partner.id, currency_id, sale.company_id.id, sale.user_id and sale.user_id.id or False)
def _prepare_invoice_line(self, cr, uid, group, picking, move_line, invoice_id, invoice_vals, context=None):
invoice_vals = super(stock_picking, self)._prepare_invoice_line(cr, uid, group, picking, move_line, invoice_id, invoice_vals, context=context)
if picking.sale_id:
if move_line.sale_line_id:
invoice_vals['account_analytic_id'] = self._get_account_analytic_invoice(cr, uid, picking, move_line)
return invoice_vals
if key not in invoices:
# Get account and payment terms
if inv_type in ('out_invoice', 'out_refund'):
account_id = partner.property_account_receivable.id
payment_term = partner.property_payment_term.id or False
else:
account_id = partner.property_account_payable.id
payment_term = partner.property_supplier_payment_term.id or False
def _get_price_unit_invoice(self, cursor, user, move_line, type):
if move_line.sale_line_id and move_line.sale_line_id.product_id.id == move_line.product_id.id:
uom_id = move_line.product_id.uom_id.id
uos_id = move_line.product_id.uos_id and move_line.product_id.uos_id.id or False
price = move_line.sale_line_id.price_unit
coeff = move_line.product_id.uos_coeff
if uom_id != uos_id and coeff != 0:
price_unit = price / coeff
return price_unit
return move_line.sale_line_id.price_unit
return super(stock_picking, self)._get_price_unit_invoice(cursor, user, move_line, type)
invoice_id = self.pool.get('account.invoice').create(cr, uid, {
'origin': sale.name,
'date_invoice': context.get('date_inv', False),
'user_id': sale.user_id and sale.user_id.id or False
'partner_id': partner.id,
'account_id': account_id,
'payment_term': payment_term,
'type': inv_type,
'fiscal_position': partner.property_account_position.id,
'company_id': sale.company_id.id,
'currency_id': sale.pricelist_id.currency_id.id,
'journal_id': journal_id,
}, context=context)
invoices[key] = invoice_id
def _get_discount_invoice(self, cursor, user, move_line):
if move_line.sale_line_id:
return move_line.sale_line_id.discount
return super(stock_picking, self)._get_discount_invoice(cursor, user, move_line)
# Get account_id
if inv_type in ('out_invoice', 'out_refund'):
account_id = move.product_id.property_account_income.id
if not account_id:
account_id = move.product_id.categ_id.property_account_income_categ.id
else:
account_id = move.product_id.property_account_expense.id
if not account_id:
account_id = move.product_id.categ_id.property_account_expense_categ.id
fp_obj = self.pool.get('account.fiscal.position')
fiscal_position = partner.property_account_position
account_id = fp_obj.map_account(cr, uid, fiscal_position, account_id)
def _get_taxes_invoice(self, cursor, user, move_line, type):
if move_line.sale_line_id and move_line.sale_line_id.product_id.id == move_line.product_id.id:
return [x.id for x in move_line.sale_line_id.tax_id]
return super(stock_picking, self)._get_taxes_invoice(cursor, user, move_line, type)
# set UoS if it's a sale and the picking doesn't have one
if move.product_uos:
uos_id = move.product_uos.id
quantity = move.product_uos_qty
else:
uos_id = move.product_uom.id
quantity = move.product_uom_qty
def _get_account_analytic_invoice(self, cursor, user, picking, move_line):
if picking.sale_id:
return picking.sale_id.project_id.id
return super(stock_picking, self)._get_account_analytic_invoice(cursor, user, picking, move_line)
invoice_line_id = self.pool.get('account.invoice.line').create(cr, uid, {
'name': move.name,
'origin': move.picking_id and move.picking_id.origin or False,
'invoice_id': invoices[key],
'account_id': account_id,
'product_id': line.product_id.id,
'uos_id': uos_id,
'quantity': quantity,
'price_unit': sale_line.price_unit,
'discount': sale_line.discount,
'invoice_line_tax_id': [(6, 0, [x.id for x in sale_line.tax_id])],
'account_analytic_id': sale.project_id and sale.project_id.id or False,
}, context=context)
def _invoice_line_hook(self, cursor, user, move_line, invoice_line_id):
if move_line.sale_line_id:
move_line.sale_line_id.write({'invoice_lines': [(4, invoice_line_id)]})
return super(stock_picking, self)._invoice_line_hook(cursor, user, move_line, invoice_line_id)
self.pool.get('sale.order.line').write(cr, uid, [sale_line.id], {
'invoice_lines': [(4, invoice_line_id)]
}, context=context)
self.pool.get('sale.order').write(cr, uid, [sale.id], {
'invoice_ids': [(4, invoices[key])],
})
def _invoice_hook(self, cursor, user, picking, invoice_id):
sale_obj = self.pool.get('sale.order')
if picking.sale_id:
sale_obj.write(cursor, user, [picking.sale_id.id], {
'invoice_ids': [(4, invoice_id)],
})
return super(stock_picking, self)._invoice_hook(cursor, user, picking, invoice_id)
def action_done(self, cr, uid, ids, context=None):
""" Changes picking state to done. This method is called at the end of
the workflow by the activity "done".
"""
for record in self.browse(cr, uid, ids, context):
if record.type == "out" and record.sale_id:
self.pool.get('sale.order').message_post(cr, uid, [record.sale_id.id], body=_("Products delivered"), context=context)
return super(stock_picking, self).action_done(cr, uid, ids, context=context)
self.pool.get('procurement.order').write(cr, uid, [move.procurement_id.id], {
'invoice_state': 'invoiced',
}, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
invoice_obj.button_compute(cr, uid, invoices.values(), context=context, set_total=(inv_type in ('in_invoice', 'in_refund')))
return invoices.keys()

View File

@ -2,41 +2,6 @@
<openerp>
<data>
<record id="stock_move_sale" model="ir.ui.view">
<field name="name">stock.move.form</field>
<field name="model">stock.move</field>
<field name="inherit_id" ref="stock.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='origin_grp']" position="inside">
<field name="sale_line_id"/>
</xpath>
</field>
</record>
<!--
<act_window
domain="[('sale_id', '=', active_id)]"
id="act_sale_order_2_stock_picking"
name="Picking"
res_model="stock.picking"
src_model="sale.order"
context="{'contact_display': 'partner'}" />
<record id="action_sale_picking_out_tree_view" model="ir.actions.act_window.view">
<field eval="1" name="sequence"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="stock.view_picking_out_tree"/>
<field name="act_window_id" ref="act_sale_order_2_stock_picking"/>
</record>
<record id="action_sale_picking_out_form_view" model="ir.actions.act_window.view">
<field eval="2" name="sequence"/>
<field name="view_mode">form</field>
<field name="view_id" ref="stock.view_picking_form"/>
<field name="act_window_id" ref="act_sale_order_2_stock_picking"/>
</record>
-->
<!-- Adding Sales Order Reference to outgoing picking -->
<record id="stock_picking_out_inherit_sale" model="ir.ui.view">

View File

@ -23,10 +23,7 @@ from stock import *
import partner
import product
import procurement
#import stock_fifo_lifo
import report
import wizard
import res_config
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -148,5 +148,3 @@ class procurement_order(osv.osv):
pass
return {}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1431,104 +1431,6 @@ class stock_move(osv.osv):
self.action_done(cr, uid, res, context=context)
return res
# def price_calculation(self, cr, uid, ids, quants, context=None):
# '''
# This method puts the right price on the stock move,
# adapts the price on the product when necessary
# and creates the necessary stock move matchings
# :param quants: are quants to be reconciled and needs to be done when IN move reconciles out move
#
# It returns a list of tuples with (move_id, match_id)
# which is used for generating the accounting entries when FIFO/LIFO
# '''
# product_obj = self.pool.get('product.product')
# currency_obj = self.pool.get('res.currency')
# matching_obj = self.pool.get('stock.move.matching')
# uom_obj = self.pool.get('product.uom')
# quant_obj = self.pool.get('stock.quant')
#
# product_avail = {}
# res = {}
# for move in self.browse(cr, uid, ids, context=context):
# # Initialize variables
# res[move.id] = []
# move_qty = move.product_qty
# move_uom = move.product_uom.id
# company_id = move.company_id.id
# ctx = context.copy()
# user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
# ctx['force_company'] = move.company_id.id
# product = product_obj.browse(cr, uid, move.product_id.id, context=ctx)
# cost_method = product.cost_method
# product_uom_qty = uom_obj._compute_qty(cr, uid, move_uom, move_qty, product.uom_id.id, round=False)
# if not product.id in product_avail:
# product_avail[product.id] = product.qty_available
#
# # Check if out -> do stock move matchings and if fifo/lifo -> update price
# # only update the cost price on the product form on stock moves of type == 'out' because if a valuation has to be made without PO,
# # for inventories for example we want to use the last value used for an outgoing move
# if move.location_id.usage == 'internal' and move.location_dest_id.usage != 'internal':
# fifo = (cost_method != 'lifo')
# #Ok -> do calculation based on quants
# price_amount = 0.0
# amount = 0.0
# #if move.id in quants???
# #search quants_move which are the quants associated with this move, which are not propagated quants
# quants_move = quant_obj.search(cr, uid, [('history_ids', 'in', move.id), ('propagated_from_id', '=', False)], context=context)
# for quant in quant_obj.browse(cr, uid, quants_move, context=context):
# price_amount += quant.qty * quant.price_unit
# amount += quant.qty
#
## tuples = product_obj.get_stock_matchings_fifolifo(cr, uid, [product.id], move_qty, fifo,
## move_uom, move.company_id.currency_id.id, context=ctx) #TODO Would be better to use price_currency_id for migration?
## price_amount = 0.0
## amount = 0.0
## #Write stock matchings
## for match in tuples:
## matchvals = {'move_in_id': match[0], 'qty': match[1],
## 'move_out_id': move.id}
## match_id = matching_obj.create(cr, uid, matchvals, context=context)
## res[move.id].append(match_id)
## price_amount += match[1] * match[2]
## amount += match[1]
# #Write price on out move
# if product_avail[product.id] >= product_uom_qty and product.cost_method in ['real']:
# if amount > 0:
# self.write(cr, uid, move.id, {'price_unit': price_amount / move_qty}, context=context) #Should be converted
# product_obj.write(cr, uid, product.id, {'standard_price': price_amount / amount}, context=ctx)
# else:
# pass
## raise osv.except_osv(_('Error'), _("Something went wrong finding quants ") + str(self.search(cr, uid, [('company_id','=', company_id), ('qty_remaining', '>', 0), ('state', '=', 'done'),
## ('location_id.usage', '!=', 'internal'), ('location_dest_id.usage', '=', 'internal'), ('product_id', '=', product.id)],
## order = 'date, id', context=context)) + str(move_qty) + str(move_uom) + str(move.company_id.currency_id.id))
# else:
# new_price = uom_obj._compute_price(cr, uid, product.uom_id.id, product.standard_price, move_uom)
# self.write(cr, uid, move.id, {'price_unit': new_price}, context=ctx)
# #Adjust product_avail when not average and move returned from
# if product.cost_method != 'average':
# product_avail[product.id] -= product_uom_qty
#
# #Check if in => if price 0.0, take standard price / Update price when average price and price on move != standard price
# if move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal':
# if move.price_unit == 0.0:
# new_price = uom_obj._compute_price(cr, uid, product.uom_id.id, product.standard_price, move_uom)
# self.write(cr, uid, move.id, {'price_unit': new_price}, context=ctx)
# elif product.cost_method == 'average':
# move_product_price = uom_obj._compute_price(cr, uid, move_uom, move.price_unit, product.uom_id.id)
# if product_avail[product.id] > 0.0:
# amount_unit = product.standard_price
# new_std_price = ((amount_unit * product_avail[product.id])\
# + (move_product_price * product_uom_qty))/(product_avail[product.id] + product_uom_qty)
# else:
# new_std_price = move_product_price
# product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}, context=ctx)
# # Should create the stock move matchings for previous outs for the negative stock that can be matched with is in
# if product_avail[product.id] < 0.0: #TODO LATER
# resneg = self._generate_negative_stock_matchings(cr, uid, [move.id], product, quants[move.id], context=ctx)
# res[move.id] += resneg
# product_avail[product.id] += product_uom_qty
# return res
def split(self, cr, uid, move, qty, context=None):
""" Partially (or not) moves a stock.move.
@param partial_datas: Dictionary containing details of partial picking
@ -2235,5 +2137,3 @@ class stock_picking_type(osv.osv):
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4

View File

@ -23,4 +23,3 @@ import product
import stock_account
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -64,4 +64,3 @@ Dashboard / Reports for Warehouse Management will include:
'auto_install': True,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -236,5 +236,3 @@ class product_category(osv.osv):
help="When real-time inventory valuation is enabled on a product, this account will hold the current value of the products.",),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -198,352 +198,3 @@ class stock_quant(osv.osv):
'line_id': move_lines,
'ref': move.picking_id and move.picking_id.name}, context=context)
#----------------------------------------------------------
# Stock Picking
#----------------------------------------------------------
class stock_picking(osv.osv):
_inherit = "stock.picking"
_columns = {
'invoice_state': fields.selection([
("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable")], "Invoice Control",
select=True, required=True, readonly=True, track_visibility='onchange', states={'draft': [('readonly', False)]}),
}
_defaults = {
'invoice_state': 'none',
}
#TODO update standard price on product after do_partial()
#TODO: we don't need to change invoice_state on cancelation, do we?
#def action_cancel(self, cr, uid, ids, context=None):
# """ Changes picking state to cancel.
# @return: True
# """
# for pick in self.browse(cr, uid, ids, context=context):
# ids2 = [move.id for move in pick.move_lines]
# self.pool.get('stock.move').action_cancel(cr, uid, ids2, context)
# self.write(cr, uid, ids, {'state': 'cancel', 'invoice_state': 'none'})
# return True
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
picking_obj = self.browse(cr, uid, id, context=context)
if 'invoice_state' not in default and picking_obj.invoice_state == 'invoiced':
default['invoice_state'] = '2binvoiced'
return super(stock_picking, self).copy(cr, uid, id, default, context)
def get_currency_id(self, cr, uid, picking):
return False
def _get_partner_to_invoice(self, cr, uid, picking, context=None):
""" Gets the partner that will be invoiced
Note that this function is inherited in the sale and purchase modules
@param picking: object of the picking for which we are selecting the partner to invoice
@return: object of the partner to invoice
"""
return picking.partner_id and picking.partner_id.id
def _get_comment_invoice(self, cr, uid, picking):
"""
@return: comment string for invoice
"""
return picking.note or ''
def _get_price_unit_invoice(self, cr, uid, move_line, type, context=None):
""" Gets price unit for invoice
@param move_line: Stock move lines
@param type: Type of invoice
@return: The price unit for the move line
"""
if context is None:
context = {}
if type in ('in_invoice', 'in_refund'):
# Take the user company and pricetype
context['currency_id'] = move_line.company_id.currency_id.id
amount_unit = move_line.product_id.price_get('standard_price', context=context)[move_line.product_id.id]
return amount_unit
else:
return move_line.product_id.list_price
def _get_discount_invoice(self, cr, uid, move_line):
'''Return the discount for the move line'''
return 0.0
def _get_taxes_invoice(self, cr, uid, move_line, type):
""" Gets taxes on invoice
@param move_line: Stock move lines
@param type: Type of invoice
@return: Taxes Ids for the move line
"""
if type in ('in_invoice', 'in_refund'):
taxes = move_line.product_id.supplier_taxes_id
else:
taxes = move_line.product_id.taxes_id
if move_line.picking_id and move_line.picking_id.partner_id and move_line.picking_id.partner_id.id:
return self.pool.get('account.fiscal.position').map_tax(
cr,
uid,
move_line.picking_id.partner_id.property_account_position,
taxes
)
else:
return map(lambda x: x.id, taxes)
def _get_account_analytic_invoice(self, cr, uid, picking, move_line):
return False
def _invoice_line_hook(self, cr, uid, move_line, invoice_line_id):
'''Call after the creation of the invoice line'''
return
def _invoice_hook(self, cr, uid, picking, invoice_id):
'''Call after the creation of the invoice'''
return
def _get_invoice_type(self, pick):
src_usage = dest_usage = None
inv_type = None
if pick.invoice_state == '2binvoiced':
if pick.move_lines:
src_usage = pick.move_lines[0].location_id.usage
dest_usage = pick.move_lines[0].location_dest_id.usage
if pick.type == 'out' and dest_usage == 'supplier':
inv_type = 'in_refund'
elif pick.type == 'out' and dest_usage == 'customer':
inv_type = 'out_invoice'
elif pick.type == 'in' and src_usage == 'supplier':
inv_type = 'in_invoice'
elif pick.type == 'in' and src_usage == 'customer':
inv_type = 'out_refund'
else:
inv_type = 'out_invoice'
return inv_type
def _prepare_invoice_group(self, cr, uid, picking, partner, invoice, context=None):
""" Builds the dict for grouped invoices
@param picking: picking object
@param partner: object of the partner to invoice (not used here, but may be usefull if this function is inherited)
@param invoice: object of the invoice that we are updating
@return: dict that will be used to update the invoice
"""
comment = self._get_comment_invoice(cr, uid, picking)
return {
'name': (invoice.name or '') + ', ' + (picking.name or ''),
'origin': (invoice.origin or '') + ', ' + (picking.name or '') + (picking.origin and (':' + picking.origin) or ''),
'comment': (comment and (invoice.comment and invoice.comment + "\n" + comment or comment)) or (invoice.comment and invoice.comment or ''),
'date_invoice': context.get('date_inv', False),
'user_id': uid,
}
def _prepare_invoice(self, cr, uid, picking, partner, inv_type, journal_id, context=None):
""" Builds the dict containing the values for the invoice
@param picking: picking object
@param partner: object of the partner to invoice
@param inv_type: type of the invoice ('out_invoice', 'in_invoice', ...)
@param journal_id: ID of the accounting journal
@return: dict that will be used to create the invoice object
"""
if isinstance(partner, int):
partner = self.pool.get('res.partner').browse(cr, uid, partner, context=context)
if inv_type in ('out_invoice', 'out_refund'):
account_id = partner.property_account_receivable.id
payment_term = partner.property_payment_term.id or False
else:
account_id = partner.property_account_payable.id
payment_term = partner.property_supplier_payment_term.id or False
comment = self._get_comment_invoice(cr, uid, picking)
invoice_vals = {
'name': picking.name,
'origin': (picking.name or '') + (picking.origin and (':' + picking.origin) or ''),
'type': inv_type,
'account_id': account_id,
'partner_id': partner.id,
'comment': comment,
'payment_term': payment_term,
'fiscal_position': partner.property_account_position.id,
'date_invoice': context.get('date_inv', False),
'company_id': picking.company_id.id,
'user_id': uid,
}
cur_id = self.get_currency_id(cr, uid, picking)
if cur_id:
invoice_vals['currency_id'] = cur_id
if journal_id:
invoice_vals['journal_id'] = journal_id
return invoice_vals
def _prepare_invoice_line(self, cr, uid, group, picking, move_line, invoice_id,
invoice_vals, context=None):
""" Builds the dict containing the values for the invoice line
@param group: True or False
@param picking: picking object
@param: move_line: move_line object
@param: invoice_id: ID of the related invoice
@param: invoice_vals: dict used to created the invoice
@return: dict that will be used to create the invoice line
"""
if group:
name = (picking.name or '') + '-' + move_line.name
else:
name = move_line.name
origin = move_line.picking_id.name or ''
if move_line.picking_id.origin:
origin += ':' + move_line.picking_id.origin
if invoice_vals['type'] in ('out_invoice', 'out_refund'):
account_id = move_line.product_id.property_account_income.id
if not account_id:
account_id = move_line.product_id.categ_id.\
property_account_income_categ.id
else:
account_id = move_line.product_id.property_account_expense.id
if not account_id:
account_id = move_line.product_id.categ_id.\
property_account_expense_categ.id
if invoice_vals['fiscal_position']:
fp_obj = self.pool.get('account.fiscal.position')
fiscal_position = fp_obj.browse(cr, uid, invoice_vals['fiscal_position'], context=context)
account_id = fp_obj.map_account(cr, uid, fiscal_position, account_id)
# set UoS if it's a sale and the picking doesn't have one
uos_id = move_line.product_uos and move_line.product_uos.id or False
if not uos_id and invoice_vals['type'] in ('out_invoice', 'out_refund'):
uos_id = move_line.product_uom.id
return {
'name': name,
'origin': origin,
'invoice_id': invoice_id,
'uos_id': uos_id,
'product_id': move_line.product_id.id,
'account_id': account_id,
'price_unit': self._get_price_unit_invoice(cr, uid, move_line, invoice_vals['type']),
'discount': self._get_discount_invoice(cr, uid, move_line),
'quantity': move_line.product_uos_qty or move_line.product_qty,
'invoice_line_tax_id': [(6, 0, self._get_taxes_invoice(cr, uid, move_line, invoice_vals['type']))],
'account_analytic_id': self._get_account_analytic_invoice(cr, uid, picking, move_line),
}
def action_invoice_create(self, cr, uid, ids, journal_id=False, group=False, type='out_invoice', context=None):
""" Creates invoice based on the invoice state selected for picking.
@param journal_id: Id of journal
@param group: Whether to create a group invoice or not
@param type: Type invoice to be created
@return: Ids of created invoices for the pickings
"""
if context is None:
context = {}
invoice_obj = self.pool.get('account.invoice')
invoice_line_obj = self.pool.get('account.invoice.line')
partner_obj = self.pool.get('res.partner')
invoices_group = {}
res = {}
inv_type = type
for picking in self.browse(cr, uid, ids, context=context):
if picking.invoice_state != '2binvoiced':
continue
partner = self._get_partner_to_invoice(cr, uid, picking, context=context)
if isinstance(partner, int):
partner = partner_obj.browse(cr, uid, [partner], context=context)[0]
if not partner:
raise osv.except_osv(_('Error, no partner!'),
_('Please put a partner on the picking list if you want to generate invoice.'))
if not inv_type:
inv_type = self._get_invoice_type(picking)
if group and partner.id in invoices_group:
invoice_id = invoices_group[partner.id]
invoice = invoice_obj.browse(cr, uid, invoice_id)
invoice_vals_group = self._prepare_invoice_group(cr, uid, picking, partner, invoice, context=context)
invoice_obj.write(cr, uid, [invoice_id], invoice_vals_group, context=context)
else:
invoice_vals = self._prepare_invoice(cr, uid, picking, partner, inv_type, journal_id, context=context)
invoice_id = invoice_obj.create(cr, uid, invoice_vals, context=context)
invoices_group[partner.id] = invoice_id
res[picking.id] = invoice_id
for move_line in picking.move_lines:
if move_line.state == 'cancel':
continue
if move_line.scrapped:
# do no invoice scrapped products
continue
vals = self._prepare_invoice_line(cr, uid, group, picking, move_line,
invoice_id, invoice_vals, context=context)
if vals:
invoice_line_id = invoice_line_obj.create(cr, uid, vals, context=context)
self._invoice_line_hook(cr, uid, move_line, invoice_line_id)
invoice_obj.button_compute(cr, uid, [invoice_id], context=context,
set_total=(inv_type in ('in_invoice', 'in_refund')))
self.write(cr, uid, [picking.id], {
'invoice_state': 'invoiced',
}, context=context)
self._invoice_hook(cr, uid, picking, invoice_id)
self.write(cr, uid, res.keys(), {
'invoice_state': 'invoiced',
}, context=context)
return res
# FP Note: review all methods above this line for stock.picking
# ----------------------------------------------------
# Move
# ----------------------------------------------------
class stock_move(osv.osv):
_inherit = "stock.move"
#TODO cancel a move must delete the accounting entry if not posted yet (otherwise raise an error)
def action_cancel(self, cr, uid, ids, context=None):
super(stock_move, self).action_cancel(cr, uid, ids, context=context)
#class stock_inventory(osv.osv):
# _name = "stock.inventory"
#
# def action_cancel_draft(self, cr, uid, ids, context=None):
# """ Cancels the stock move and change inventory state to draft.
# @return: True
# """
# for inv in self.browse(cr, uid, ids, context=context):
# self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context=context)
# self.write(cr, uid, [inv.id], {'state':'draft'}, context=context)
# return True
#
# def action_cancel_inventory(self, cr, uid, ids, context=None):
# """ Cancels both stock move and inventory
# @return: True
# """
# move_obj = self.pool.get('stock.move')
# account_move_obj = self.pool.get('account.move')
# for inv in self.browse(cr, uid, ids, context=context):
# move_obj.action_cancel(cr, uid, [x.id for x in inv.move_ids], context=context)
# for move in inv.move_ids:
# account_move_ids = account_move_obj.search(cr, uid, [('name', '=', move.name)])
# if account_move_ids:
# account_move_data_l = account_move_obj.read(cr, uid, account_move_ids, ['state'], context=context)
# for account_move in account_move_data_l:
# if account_move['state'] == 'posted':
# raise osv.except_osv(_('User Error!'),
# _('In order to cancel this inventory, you must first unpost related journal entries.'))
# account_move_obj.unlink(cr, uid, [account_move['id']], context=context)
# self.write(cr, uid, [inv.id], {'state': 'cancel'}, context=context)
# return True
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -2,7 +2,6 @@
<openerp>
<data>
<record id="view_location_form_inherit" model="ir.ui.view">
<field name="name">stock.location.form.inherit</field>
<field name="model">stock.location</field>
@ -17,7 +16,7 @@
</field>
</record>
<!-- Do not know problems here -> probably inherit of stock.picking <record id="view_picking_inherit_form2" model="ir.ui.view">
<record id="view_picking_inherit_form2" model="ir.ui.view">
<field name="name">stock.picking.form.inherit</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
@ -25,36 +24,12 @@
<xpath expr="//button[@name='action_process']" position="after">
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice/Refund" attrs="{'invisible': ['|','|',('state','&lt;&gt;','done'),('invoice_state','=','invoiced'),('invoice_state','=','none')]}" type="action" class="oe_highlight" groups="base.group_user"/>
<field name="invoice_state" string="Invoice Control" groups="account.group_account_invoice" attrs="{'invisible':[('invoice_state', '=', 'none')]}"/>
</xpath>
</field>
</record>
<record id="view_picking_out_tree_inherit" model="ir.ui.view">
<field name="name">stock.picking.out.tree.inherit</field>
<field name="model">stock.picking.out</field>
<field name="inherit_id" ref="stock.view_picking_out_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='min_date']" position="after">
<field name="invoice_state" groups="account.group_account_invoice"/>
</xpath>
</field>
</record>
<record id="view_picking_in_tree_inherit" model="ir.ui.view">
<field name="name">stock.picking.in.tree.inherit</field>
<field name="model">stock.picking.in</field>
<field name="inherit_id" ref="stock.view_picking_in_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='min_date']" position="after">
<field name="invoice_state" groups="account.group_account_invoice"/>
</xpath>
</field>
</record>-->
<record id="view_picking_internal_search_inherit" model="ir.ui.view">
<field name="name">stock.picking.in.search.inherit</field>
<field name="name">stock.picking.search.inherit</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
<field name="arch" type="xml">
@ -63,16 +38,6 @@
</xpath>
</field>
</record>
<record id="view_picking_out_search_inherit" model="ir.ui.view">
<field name="name">stock.picking.out.search.inherit</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="before">
<filter icon="terp-dolar" name="to_invoice" string="To Invoice" domain="[('invoice_state','=','2binvoiced')]" help="Delivery orders to invoice"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -146,5 +146,3 @@ class stock_invoice_onshipping(osv.osv_memory):
context=context)
return res
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: