[FIX] better split of onshipping invoice (some code needed to be moved in sale_stock\!) + misc fixes in delivery (yaml test fixed as well)

bzr revid: qdp-launchpad@openerp.com-20130909142350-axvodv298wnmm7ox
This commit is contained in:
Quentin (OpenERP) 2013-09-09 16:23:50 +02:00
commit 15dd2573d5
6 changed files with 132 additions and 114 deletions

View File

@ -32,7 +32,7 @@ You can define your own carrier and delivery grids for prices. When creating
invoices from picking, OpenERP is able to add and compute the shipping line. invoices from picking, OpenERP is able to add and compute the shipping line.
""", """,
'author': 'OpenERP SA', 'author': 'OpenERP SA',
'depends': ['sale', 'purchase', 'stock_account'], 'depends': ['sale_stock', 'purchase'],
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'delivery_report.xml', 'delivery_report.xml',

View File

@ -28,8 +28,19 @@ class shipping(report_sxw.rml_parse):
super(shipping, self).__init__(cr, uid, name, context=context) super(shipping, self).__init__(cr, uid, name, context=context)
self.localcontext.update({ self.localcontext.update({
'time': time, 'time': time,
'get_partner_invoice_info': self.get_partner_invoice_info,
}) })
def get_partner_invoice_info(self, origin):
"""This method is used to get information of invoiced partner.
:param: origin: origin of picking
:return: tuple contaning partner name and address of invoiced partner
"""
sale_obj = self.pool.get('sale.order')
sale_id = sale_obj.search(self.cr, self.uid, [('name', '=', origin)])[0]
partner_invoice_id = sale_obj.browse(self.cr, self.uid, sale_id).partner_invoice_id
return partner_invoice_id.name, self.pool.get('res.partner')._display_address(self.cr, self.uid, partner_invoice_id)
report_sxw.report_sxw('report.sale.shipping','stock.picking','addons/delivery/report/shipping.rml',parser=shipping) report_sxw.report_sxw('report.sale.shipping','stock.picking','addons/delivery/report/shipping.rml',parser=shipping)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -107,14 +107,11 @@
<story> <story>
<pto> <pto>
<pto_header> <pto_header>
<blockTable colWidths="370.0,85.0,82.0" repeatRows="1" style="Table3"> <blockTable colWidths="455.0,82.0" repeatRows="1" style="Table3">
<tr> <tr>
<td> <td>
<para style="terp_tblheader_Details">Description</para> <para style="terp_tblheader_Details">Description</para>
</td> </td>
<td>
<para style="terp_tblheader_Details_Centre">Lot</para>
</td>
<td> <td>
<para style="terp_tblheader_Details_Right">Quantity</para> <para style="terp_tblheader_Details_Right">Quantity</para>
</td> </td>
@ -130,12 +127,12 @@
<tr> <tr>
<td> <td>
<para style="terp_default_Bold_9">Invoiced to</para> <para style="terp_default_Bold_9">Invoiced to</para>
<para style="terp_default_9">[[ o.sale_id and o.sale_id.partner_invoice_id and o.sale_id.partner_invoice_id.name or '']]</para> <para style="terp_default_9">[[ o.origin and get_partner_invoice_info(o.origin)[0] or '' ]]</para>
<para style="terp_default_9">[[ o.sale_id and o.sale_id.partner_invoice_id and display_address(o.sale_id.partner_invoice_id) ]]</para> <para style="terp_default_9">[[ o.origin and get_partner_invoice_info(o.origin)[1] or '' ]]</para>
</td> </td>
<td> <td>
<para style="terp_default_9">[[ o.partner_id and o.partner_id and o.partner_id.name or '' ]]</para> <para style="terp_default_9">[[ o.partner_id and o.partner_id.name or '' ]]</para>
<para style="terp_default_9">[[ o.partner_id and o.partner_id and display_address(o.partner_id) ]]</para> <para style="terp_default_9">[[ o.partner_id and display_address(o.partner_id) ]]</para>
</td> </td>
</tr> </tr>
</blockTable> </blockTable>
@ -165,7 +162,7 @@
<blockTable colWidths="126.0,103.0,103.0,103.0,103.0" style="Table2"> <blockTable colWidths="126.0,103.0,103.0,103.0,103.0" style="Table2">
<tr> <tr>
<td> <td>
<para style="terp_default_Centre_8">[[ o.sale_id and o.sale_id.name ]]</para> <para style="terp_default_Centre_8">[[ o.origin or '' ]]</para>
</td> </td>
<td> <td>
<para style="terp_default_Centre_8">[[ formatLang(o.date,date_time=True) ]]</para> <para style="terp_default_Centre_8">[[ formatLang(o.date,date_time=True) ]]</para>
@ -184,14 +181,11 @@
<para style="Standard"> <para style="Standard">
<font color="white"> </font> <font color="white"> </font>
</para> </para>
<blockTable colWidths="370.0,85.0,82.0" repeatRows="1" style="Table3"> <blockTable colWidths="455.0,82.0" repeatRows="1" style="Table3">
<tr> <tr>
<td> <td>
<para style="terp_tblheader_Details">Description</para> <para style="terp_tblheader_Details">Description</para>
</td> </td>
<td>
<para style="terp_tblheader_Details_Centre">Lot</para>
</td>
<td> <td>
<para style="terp_tblheader_Details_Right">Quantity</para> <para style="terp_tblheader_Details_Right">Quantity</para>
</td> </td>
@ -199,14 +193,11 @@
</blockTable> </blockTable>
<section> <section>
<para style="terp_default_1">[[repeatIn(o.move_lines,'line')]]</para> <para style="terp_default_1">[[repeatIn(o.move_lines,'line')]]</para>
<blockTable colWidths="370.0,85.0,83.0" style="Table4"> <blockTable colWidths="455.0,82.0" style="Table4">
<tr> <tr>
<td> <td>
<para style="terp_default_9">[[line.product_id.code ]] [[ line.product_id and line.product_id.name or '']]</para> <para style="terp_default_9">[[line.product_id.code ]] [[ line.product_id and line.product_id.name or '']]</para>
</td> </td>
<td>
<para style="terp_default_Centre_9">[[ (line.prodlot_id and (line.prodlot_id.name + (line.prodlot_id.ref and ('/' + line.prodlot_id.ref) or ''))) or ' ' ]]</para>
</td>
<td> <td>
<para style="terp_default_Right_9">[[ formatLang(line.product_qty) ]] [[ line.product_uom and line.product_uom.name ]]</para> <para style="terp_default_Right_9">[[ formatLang(line.product_qty) ]] [[ line.product_uom and line.product_uom.name ]]</para>
</td> </td>

View File

@ -30,7 +30,6 @@ class stock_picking(osv.osv):
def _cal_weight(self, cr, uid, ids, name, args, context=None): def _cal_weight(self, cr, uid, ids, name, args, context=None):
res = {} res = {}
uom_obj = self.pool.get('product.uom')
for picking in self.browse(cr, uid, ids, context=context): for picking in self.browse(cr, uid, ids, context=context):
total_weight = total_weight_net = 0.00 total_weight = total_weight_net = 0.00
@ -119,26 +118,22 @@ class stock_picking(osv.osv):
'invoice_line_tax_id': [(6, 0, taxes_ids)], 'invoice_line_tax_id': [(6, 0, taxes_ids)],
} }
def action_invoice_create(self, cr, uid, ids, journal_id=False, def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None):
group=False, type='out_invoice', context=None): ''' This function simply creates the invoice from the given values. It is overriden in delivery module to add the delivery costs. picking is a browse_record
invoice_obj = self.pool.get('account.invoice') '''
picking_obj = self.pool.get('stock.picking')
invoice_line_obj = self.pool.get('account.invoice.line') invoice_line_obj = self.pool.get('account.invoice.line')
result = super(stock_picking, self).action_invoice_create(cr, uid, invoice_id = super(stock_picking, self)._create_invoice_from_picking(cr, uid, picking, vals, context=context)
ids, journal_id=journal_id, group=group, type=type, invoice = self.browse(cr, uid, invoice_id, context=context)
context=context) invoice_line = self._prepare_shipping_invoice_line(cr, uid, picking, invoice, context=context)
for picking in picking_obj.browse(cr, uid, result, context=context): if invoice_line:
invoice = invoice_obj.browse(cr, uid, picking.id, context=context) invoice_line_obj.create(cr, uid, invoice_line)
invoice_line = self._prepare_shipping_invoice_line(cr, uid, picking, invoice, context=context) return invoice_id
if invoice_line:
invoice_line_obj.create(cr, uid, invoice_line) def _get_default_uom(self, cr, uid, c):
invoice_obj.button_compute(cr, uid, [invoice.id], context=context)
return result
def _get_default_uom(self,cr,uid,c):
uom_categ, uom_categ_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'product', 'product_uom_categ_kgm') uom_categ, uom_categ_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'product', 'product_uom_categ_kgm')
return self.pool.get('product.uom').search(cr, uid, [('category_id', '=', uom_categ_id),('factor','=',1)])[0] return self.pool.get('product.uom').search(cr, uid, [('category_id', '=', uom_categ_id), ('factor', '=', 1)])[0]
_defaults = { _defaults = {
'weight_uom_id': lambda self,cr,uid,c: self._get_default_uom(cr,uid,c) 'weight_uom_id': lambda self, cr, uid, c: self._get_default_uom(cr, uid, c)
} }

View File

@ -430,3 +430,33 @@ class sale_order_line(osv.osv):
res.update({'warning': warning}) res.update({'warning': warning})
return res return res
class stock_move(osv.osv):
_inherit = 'stock.move'
def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):
invoice_line_id = self.pool.get('account.invoice.line').create(cr, uid, invoice_line_vals, context=context)
if move.procurement_id and move.procurement_id.sale_line_id:
sale_line = move.procurement_id.sale_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_line.order_id.id], {
'invoice_ids': [(4, invoice_line_vals['invoice_id'])],
})
return invoice_line_id
def _get_master_data(self, cr, uid, move, company, context=None):
if move.procurement_id and move.procurement_id.sale_line_id:
sale_order = move.procurement_id.sale_line_id.order_id
return sale_order.partner_invoice_id, sale_order.user_id.id, sale_order.pricelist_id.currency_id.id
return super(stock_move, self)._get_master_data(cr, uid, move, company, context=context)
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
res = super(stock_move, self)._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
if move.procurement_id and move.procurement_id.sale_line_id:
sale_line = move.procurement_id.sale_line_id
res['invoice_line_tax_id'] = [(6, 0, [x.id for x in sale_line.tax_id])]
res['account_analytic_id'] = sale_line.order_id.project_id and sale_line.order_id.project_id.id or False
res['price_unit'] = sale_line.price_unit
res['discount'] = sale_line.discount
return res

View File

@ -20,21 +20,20 @@
############################################################################## ##############################################################################
from openerp.osv import fields, osv from openerp.osv import fields, osv
from openerp.tools.translate import _
#---------------------------------------------------------- #----------------------------------------------------------
# Procurement Rule # Procurement Rule
#---------------------------------------------------------- #----------------------------------------------------------
class procurement_rule(osv.osv): class procurement_rule(osv.osv):
_inherit = 'procurement.rule' _inherit = 'procurement.rule'
_columns= { _columns = {
'invoice_state': fields.selection([ 'invoice_state': fields.selection([
("invoiced", "Invoiced"), ("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"), ("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable")], "Invoice Status", ("none", "Not Applicable")], "Invoice Status",
required=False), required=False),
} }
#---------------------------------------------------------- #----------------------------------------------------------
# Procurement Order # Procurement Order
#---------------------------------------------------------- #----------------------------------------------------------
@ -43,18 +42,17 @@ class procurement_rule(osv.osv):
class procurement_order(osv.osv): class procurement_order(osv.osv):
_inherit = "procurement.order" _inherit = "procurement.order"
_columns = { _columns = {
'invoice_state': fields.selection( 'invoice_state': fields.selection([("invoiced", "Invoiced"),
[("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"), ("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable") ("none", "Not Applicable")
], "Invoice Control", required=True), ], "Invoice Control", required=True),
} }
def _run_move_create(self, cr, uid, procurement, context=None): def _run_move_create(self, cr, uid, procurement, context=None):
res = super(procurement_order, self)._run_move_create(cr, uid, procurement, context=context) res = super(procurement_order, self)._run_move_create(cr, uid, procurement, context=context)
res.update({'invoice_state': (procurement.rule_id.invoice_state in ('none', False) and procurement.invoice_state or procurement.rule_id.invoice_state) or 'none'}) res.update({'invoice_state': (procurement.rule_id.invoice_state in ('none', False) and procurement.invoice_state or procurement.rule_id.invoice_state) or 'none'})
return res return res
_defaults = { _defaults = {
'invoice_state': 'none' 'invoice_state': 'none'
} }
@ -70,15 +68,51 @@ class stock_move(osv.osv):
'invoice_state': fields.selection([("invoiced", "Invoiced"), 'invoice_state': fields.selection([("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"), ("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable")], "Invoice Control", ("none", "Not Applicable")], "Invoice Control",
select=True, required=True, track_visibility='onchange', select=True, required=True, track_visibility='onchange',
states={'draft': [('readonly', False)]}), states={'draft': [('readonly', False)]}),
} }
_defaults= { _defaults = {
'invoice_state': lambda *args, **argv: 'none' 'invoice_state': lambda *args, **argv: 'none'
}
def _get_master_data(self, cr, uid, move, company, context=None):
''' returns a tupple (browse_record(res.partner), ID(res.users), ID(res.currency)'''
return move.picking_id.partner_id, uid, company.currency_id.id
def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):
return self.pool.get('account.invoice.line').create(cr, uid, invoice_line_vals, context=context)
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
fp_obj = self.pool.get('account.fiscal.position')
# 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
fiscal_position = partner.property_account_position
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.product_uom.id
quantity = move.product_uom_qty
if move.product_uos:
uos_id = move.product_uos.id
quantity = move.product_uos_qty
return {
'name': move.name,
'account_id': account_id,
'product_id': move.product_id.id,
'uos_id': uos_id,
'quantity': quantity,
'price_unit': move.product_id.list_price, # TODO: use price_get
'discount': 0.0,
'account_analytic_id': False,
} }
#---------------------------------------------------------- #----------------------------------------------------------
# Picking # Picking
#---------------------------------------------------------- #----------------------------------------------------------
@ -90,9 +124,9 @@ class stock_picking(osv.osv):
for pick in self.browse(cr, uid, ids, context=context): for pick in self.browse(cr, uid, ids, context=context):
result[pick.id] = 'none' result[pick.id] = 'none'
for move in pick.move_lines: for move in pick.move_lines:
if move.invoice_state=='invoiced': if move.invoice_state == 'invoiced':
result[pick.id] = 'invoiced' result[pick.id] = 'invoiced'
elif move.invoice_state=='2binvoiced': elif move.invoice_state == '2binvoiced':
result[pick.id] = '2binvoiced' result[pick.id] = '2binvoiced'
break break
return result return result
@ -100,7 +134,7 @@ class stock_picking(osv.osv):
def __get_picking_move(self, cr, uid, ids, context={}): def __get_picking_move(self, cr, uid, ids, context={}):
res = [] res = []
for move in self.pool.get('stock.move').browse(cr, uid, ids, context=context): for move in self.pool.get('stock.move').browse(cr, uid, ids, context=context):
if move.picking_id: if move.picking_id:
res.append(move.picking_id.id) res.append(move.picking_id.id)
return res return res
@ -109,11 +143,11 @@ class stock_picking(osv.osv):
("invoiced", "Invoiced"), ("invoiced", "Invoiced"),
("2binvoiced", "To Be Invoiced"), ("2binvoiced", "To Be Invoiced"),
("none", "Not Applicable") ("none", "Not Applicable")
], string="Invoice Control", required=True, ], string="Invoice Control", required=True,
store={ store={
'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['state'], 10), 'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['state'], 10),
'stock.move': (__get_picking_move, ['picking_id'], 10), 'stock.move': (__get_picking_move, ['picking_id', 'invoice_state'], 10),
}, },
), ),
} }
@ -121,6 +155,12 @@ class stock_picking(osv.osv):
'invoice_state': lambda *args, **argv: 'none' 'invoice_state': lambda *args, **argv: 'none'
} }
def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None):
''' This function simply creates the invoice from the given values. It is overriden in delivery module to add the delivery costs.
'''
invoice_obj = self.pool.get('account.invoice')
return invoice_obj.create(cr, uid, vals, context=context)
def action_invoice_create(self, cr, uid, ids, journal_id=False, group=False, type='out_invoice', context=None): 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. """ Creates invoice based on the invoice state selected for picking.
@param journal_id: Id of journal @param journal_id: Id of journal
@ -134,7 +174,7 @@ class stock_picking(osv.osv):
key = group and picking.id or True key = group and picking.id or True
for move in picking.move_lines: for move in picking.move_lines:
if move.procurement_id and (move.procurement_id.invoice_state == '2binvoiced') or move.invoice_state == '2binvoiced': if move.procurement_id and (move.procurement_id.invoice_state == '2binvoiced') or move.invoice_state == '2binvoiced':
if (move.state <> 'cancel') and not move.scrapped: if (move.state != 'cancel') and not move.scrapped:
todo.setdefault(key, []) todo.setdefault(key, [])
todo[key].append(move) todo[key].append(move)
invoices = [] invoices = []
@ -144,27 +184,12 @@ class stock_picking(osv.osv):
def __invoice_create_line(self, cr, uid, moves, journal_id=False, inv_type='out_invoice', context=None): def __invoice_create_line(self, cr, uid, moves, journal_id=False, inv_type='out_invoice', context=None):
invoice_obj = self.pool.get('account.invoice') invoice_obj = self.pool.get('account.invoice')
move_obj = self.pool.get('stock.move')
invoices = {} invoices = {}
for move in moves: for move in moves:
company = move.company_id company = move.company_id
account_analytic_id = False origin = move.picking_id.name
if move.procurement_id: partner, user_id, currency_id = move_obj._get_master_data(cr, uid, move, company, context=context)
sale_line = move.procurement_id.sale_line_id
sale = sale_line.order_id
user_id = sale.user_id and sale.user_id.id or False
partner = sale.partner_invoice_id
currency_id = sale.pricelist_id.currency_id.id
origin = sale.name
account_analytic_id = sale.project_id and sale.project_id.id or False
unit_price = sale_line.price_unit
discount = sale_line.discount
else:
partner = move.picking_id.partner_id
currency_id = company.currency_id.id
user_id = uid
origin = move.picking_id.name
unit_price = move.product_id.list_price #TODO: use price_get
discount = 0
key = (partner.id, currency_id, company.id, user_id) key = (partner.id, currency_id, company.id, user_id)
if key not in invoices: if key not in invoices:
@ -176,7 +201,7 @@ class stock_picking(osv.osv):
account_id = partner.property_account_payable.id account_id = partner.property_account_payable.id
payment_term = partner.property_supplier_payment_term.id or False payment_term = partner.property_supplier_payment_term.id or False
invoice_id = invoice_obj.create(cr, uid, { invoice_vals = {
'origin': origin, 'origin': origin,
'date_invoice': context.get('date_inv', False), 'date_invoice': context.get('date_inv', False),
'user_id': user_id, 'user_id': user_id,
@ -188,52 +213,18 @@ class stock_picking(osv.osv):
'company_id': company.id, 'company_id': company.id,
'currency_id': currency_id, 'currency_id': currency_id,
'journal_id': journal_id, 'journal_id': journal_id,
}, context=context) }
invoice_id = self._create_invoice_from_picking(cr, uid, move.picking_id, invoice_vals, context=context)
invoices[key] = invoice_id invoices[key] = invoice_id
# Get account_id invoice_line_vals = move_obj._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
if inv_type in ('out_invoice', 'out_refund'): invoice_line_vals['invoice_id'] = invoices[key]
account_id = move.product_id.property_account_income.id invoice_line_vals['origin'] = origin
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)
# set UoS if it's a sale and the picking doesn't have one move_obj._create_invoice_line_from_vals(cr, uid, move, invoice_line_vals, context=context)
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
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': move.product_id.id,
'uos_id': uos_id,
'quantity': quantity,
'price_unit': unit_price,
'discount': discount,
#'invoice_line_tax_id': [(6, 0, [x.id for x in sale_line.tax_id])], TODO add me back
'account_analytic_id': account_analytic_id,
}, context=context)
move_obj.write(cr, uid, move.id, {'invoice_state': 'invoiced'}, context=context)
if move.procurement_id: if move.procurement_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])],
})
self.pool.get('procurement.order').write(cr, uid, [move.procurement_id.id], { self.pool.get('procurement.order').write(cr, uid, [move.procurement_id.id], {
'invoice_state': 'invoiced', 'invoice_state': 'invoiced',
}, context=context) }, context=context)