diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml
index a56d850a8e3..0a19b304c17 100644
--- a/addons/account/account_view.xml
+++ b/addons/account/account_view.xml
@@ -558,6 +558,7 @@
+
@@ -2572,7 +2573,7 @@ action = self.pool.get('res.config').next(cr, uid, [], context)
-
+
@@ -412,6 +460,28 @@
+
+ mrp.bom.component.tree
+ mrp.bom
+ tree
+ child_complete_ids
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Bill of Materials
ir.actions.act_window
@@ -426,6 +496,7 @@
ir.actions.act_window
mrp.bom
form
+
[('bom_id','!=',False)]
Bills of materials components are components and sub-products used to create master bills of materials. Use this menu to search in which BoM a specific component is used.
@@ -616,7 +687,6 @@
-
@@ -630,7 +700,8 @@
-
+
+
@@ -645,7 +716,6 @@
-
+ colspan="2" />
diff --git a/addons/mrp/product.py b/addons/mrp/product.py
index bb9bc27625f..7301527f68e 100644
--- a/addons/mrp/product.py
+++ b/addons/mrp/product.py
@@ -90,4 +90,13 @@ class product_product(osv.osv):
for bom in bom_obj.browse(cr, uid, bom_ids, context=context):
_compute_price(bom)
+ def copy(self, cr, uid, id, default=None, context=None):
+ if not default:
+ default = {}
+ default.update({
+ 'bom_ids': []
+ })
+ return super(product_product, self).copy(cr, uid, id, default, context=context)
+
+
product_product()
diff --git a/addons/mrp/stock.py b/addons/mrp/stock.py
index 8758bc09cd5..5ccb7c8ba7a 100644
--- a/addons/mrp/stock.py
+++ b/addons/mrp/stock.py
@@ -30,6 +30,11 @@ class StockMove(osv.osv):
_columns = {
'production_id': fields.many2one('mrp.production', 'Production', select=True),
}
+
+ def create_chained_picking(self, cr, uid, moves, context=None):
+ new_moves = super(StockMove, self).create_chained_picking(cr, uid, moves, context=context)
+ self.write(cr, uid, [x.id for x in new_moves], {'production_id': False}, context=context)
+ return new_moves
def _action_explode(self, cr, uid, move, context=None):
""" Explodes pickings.
diff --git a/addons/mrp_repair/mrp_repair.py b/addons/mrp_repair/mrp_repair.py
index 899a7460fdf..bedaa22b433 100644
--- a/addons/mrp_repair/mrp_repair.py
+++ b/addons/mrp_repair/mrp_repair.py
@@ -327,6 +327,9 @@ class mrp_repair(osv.osv):
self.write(cr, uid, [o.id], {'state': '2binvoiced'})
else:
self.write(cr, uid, [o.id], {'state': 'confirmed'})
+ for line in o.operations:
+ if line.product_id.track_production and not line.prodlot_id:
+ raise osv.except_osv(_('Warning'), _("Production lot is required for opration line with product '%s'") % (line.product_id.name))
mrp_line_obj.write(cr, uid, [l.id for l in o.operations], {'state': 'confirmed'})
return True
@@ -535,6 +538,7 @@ class mrp_repair(osv.osv):
'location_id': move.location_id.id,
'location_dest_id': move.location_dest_id.id,
'tracking_id': False,
+ 'prodlot_id': move.prodlot_id and move.prodlot_id.id or False,
'state': 'done',
})
repair_line_obj.write(cr, uid, [move.id], {'move_id': move_id, 'state': 'done'}, context=context)
@@ -661,6 +665,7 @@ class mrp_repair_line(osv.osv, ProductChangeMixin):
'tax_id': fields.many2many('account.tax', 'repair_operation_line_tax', 'repair_operation_line_id', 'tax_id', 'Taxes'),
'product_uom_qty': fields.float('Quantity (UoM)', digits=(16,2), required=True),
'product_uom': fields.many2one('product.uom', 'Product UoM', required=True),
+ 'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number',domain="[('product_id','=',product_id)]"),
'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', readonly=True),
'location_id': fields.many2one('stock.location', 'Source Location', required=True, select=True),
'location_dest_id': fields.many2one('stock.location', 'Dest. Location', required=True, select=True),
diff --git a/addons/mrp_repair/mrp_repair_view.xml b/addons/mrp_repair/mrp_repair_view.xml
index 11a9eadb249..724dafc741d 100644
--- a/addons/mrp_repair/mrp_repair_view.xml
+++ b/addons/mrp_repair/mrp_repair_view.xml
@@ -49,7 +49,8 @@
-
+
+
@@ -178,7 +179,7 @@
-
+
@@ -202,7 +203,7 @@
-
+
Repair Orders
@@ -212,7 +213,7 @@
tree,form
Repair orders allow you to organize your product repairs. In a repair order, you can detail the components you remove, add or replace and record the time you spent on the different operations. The repair order uses the warranty date on the production lot in order to know if whether the repair should be invoiced to the customer or not.
-
+
diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py
index 1db9ebbe26b..2459bfa15f9 100644
--- a/addons/point_of_sale/point_of_sale.py
+++ b/addons/point_of_sale/point_of_sale.py
@@ -299,8 +299,11 @@ class pos_order(osv.osv):
@param name: Names of fields.
@return: pricelist ID
"""
- pricelist = self.pool.get('product.pricelist').search(cr, uid, [('name', '=', 'Public Pricelist')], context=context)
- return pricelist and pricelist[0] or False
+ res = self.pool.get('sale.shop').search(cr, uid, [], context=context)
+ if res:
+ shop = self.pool.get('sale.shop').browse(cr, uid, res[0], context=context)
+ return shop.pricelist_id and shop.pricelist_id.id or False
+ return False
def _journal_default(self, cr, uid, context=None):
""" To get default pricelist for the order
@@ -1246,4 +1249,4 @@ class stock_picking(osv.osv):
stock_picking()
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py
index 1b2d7c93466..3257f0a5694 100644
--- a/addons/procurement/procurement.py
+++ b/addons/procurement/procurement.py
@@ -361,17 +361,22 @@ class procurement_order(osv.osv):
"""
ok = True
if procurement.move_id:
+ message = False
id = procurement.move_id.id
if not (procurement.move_id.state in ('done','assigned','cancel')):
ok = ok and self.pool.get('stock.move').action_assign(cr, uid, [id])
cr.execute('select count(id) from stock_warehouse_orderpoint where product_id=%s', (procurement.product_id.id,))
- if not cr.fetchone()[0]:
- cr.execute('update procurement_order set message=%s where id=%s',
- (_('Not enough stock and no minimum orderpoint rule defined.'),
- procurement.id))
- message = _("Procurement '%s' is in exception: not enough stock.") % \
- (procurement.name,)
- self.log(cr, uid, procurement.id, message)
+ res = cr.fetchone()[0]
+ if not res and not ok:
+ message = _("Not enough stock and no minimum orderpoint rule defined.")
+ elif not res:
+ message = _("No minimum orderpoint rule defined.")
+ elif not ok:
+ message = _("Not enough stock.")
+
+ if message:
+ self.log(cr, uid, procurement.id, _("Procurement '%s' is in exception: ") % (procurement.name) + message)
+ cr.execute('update procurement_order set message=%s where id=%s', (message, procurement.id))
return ok
def action_produce_assign_service(self, cr, uid, ids, context=None):
diff --git a/addons/product/__openerp__.py b/addons/product/__openerp__.py
index 851031e0424..712e17aebc3 100644
--- a/addons/product/__openerp__.py
+++ b/addons/product/__openerp__.py
@@ -53,6 +53,7 @@
'product_data.xml',
'product_report.xml',
'product_view.xml',
+ 'product_shortcut_data.xml',
'pricelist_view.xml',
'partner_view.xml',
'process/product_process.xml'
diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py
index cd8c338da89..6899b673c70 100644
--- a/addons/product/pricelist.py
+++ b/addons/product/pricelist.py
@@ -166,10 +166,9 @@ class product_pricelist(osv.osv):
pricelist_version_ids = pricelist_ids
else:
# all pricelists:
- pricelist_version_ids = product_pricelist_version_obj.search(cr, uid, [])
+ pricelist_version_ids = self.pool.get('product.pricelist').search(cr, uid, [], context=context)
pricelist_version_ids = list(set(pricelist_version_ids))
-
plversions_search_args = [
('pricelist_id', 'in', pricelist_version_ids),
'|',
diff --git a/addons/product/product.py b/addons/product/product.py
index eabd9494908..12ad7676fb0 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -482,6 +482,19 @@ class product_product(osv.osv):
'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),
'name_template': fields.related('product_tmpl_id', 'name', string="Name", type='char', size=128, store=True),
}
+
+ def unlink(self, cr, uid, ids, context=None):
+ unlink_ids = []
+ unlink_product_tmpl_ids = []
+ for product in self.browse(cr, uid, ids, context=context):
+ tmpl_id = product.product_tmpl_id.id
+ # Check if the product is last product of this template
+ other_product_ids = self.search(cr, uid, [('product_tmpl_id', '=', tmpl_id), ('id', '!=', product.id)], context=context)
+ if not other_product_ids:
+ unlink_product_tmpl_ids.append(tmpl_id)
+ unlink_ids.append(product.id)
+ self.pool.get('product.template').unlink(cr, uid, unlink_product_tmpl_ids, context=context)
+ return super(product_product, self).unlink(cr, uid, unlink_ids, context=context)
def onchange_uom(self, cursor, user, ids, uom_id,uom_po_id):
if uom_id and uom_po_id:
diff --git a/addons/product/product_shortcut_data.xml b/addons/product/product_shortcut_data.xml
new file mode 100644
index 00000000000..4f48445a197
--- /dev/null
+++ b/addons/product/product_shortcut_data.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ Products
+ ir.ui.menu
+
+
+
+
+
+
diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml
index 642ef43caf9..83240716715 100644
--- a/addons/product/product_view.xml
+++ b/addons/product/product_view.xml
@@ -9,7 +9,7 @@
search
-
+
@@ -30,7 +30,7 @@
-
+
@@ -101,7 +101,7 @@
-
+
@@ -567,7 +567,7 @@
-
+
@@ -635,12 +635,6 @@
form
-
- Products
- ir.ui.menu
-
-
-
diff --git a/addons/product/report/product_pricelist.py b/addons/product/report/product_pricelist.py
index 1148718668b..7e9748c2523 100644
--- a/addons/product/report/product_pricelist.py
+++ b/addons/product/report/product_pricelist.py
@@ -62,18 +62,18 @@ class product_pricelist(report_sxw.rml_parse):
def _get_pricelist(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
- pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['name'])[0]
+ pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['name'], context=self.localcontext)[0]
return pricelist['name']
def _get_currency(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
- pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'])[0]
+ pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'], context=self.localcontext)[0]
return pricelist['currency_id'][1]
def _get_currency_symbol(self, pricelist_id):
pool = pooler.get_pool(self.cr.dbname)
- pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'])[0]
- symbol = pool.get('res.currency').read(self.cr, self.uid, [pricelist['currency_id'][0]], ['symbol'])[0]
+ pricelist = pool.get('product.pricelist').read(self.cr, self.uid, [pricelist_id], ['currency_id'], context=self.localcontext)[0]
+ symbol = pool.get('res.currency').read(self.cr, self.uid, [pricelist['currency_id'][0]], ['symbol'], context=self.localcontext)[0]
return symbol['symbol'] or ''
def _get_categories(self, products,form):
@@ -88,13 +88,13 @@ class product_pricelist(report_sxw.rml_parse):
if product.categ_id.id not in cat_ids:
cat_ids.append(product.categ_id.id)
- cats = pool.get('product.category').name_get(self.cr, self.uid, cat_ids)
+ cats = pool.get('product.category').name_get(self.cr, self.uid, cat_ids, context=self.localcontext)
if not cats:
return res
for cat in cats:
- product_ids=pool.get('product.product').search(self.cr, self.uid, [('id','in',pro_ids),('categ_id','=',cat[0])])
+ product_ids=pool.get('product.product').search(self.cr, self.uid, [('id', 'in', pro_ids), ('categ_id', '=', cat[0])], context=self.localcontext)
products = []
- for product in pool.get('product.product').read(self.cr, self.uid, product_ids, ['name','code']):
+ for product in pool.get('product.product').read(self.cr, self.uid, product_ids, ['name', 'code'], context=self.localcontext):
val = {
'id':product['id'],
'name':product['name'],
@@ -114,7 +114,7 @@ class product_pricelist(report_sxw.rml_parse):
def _get_price(self,pricelist_id, product_id,qty):
sale_price_digits = self.get_digits(dp='Sale Price')
pool = pooler.get_pool(self.cr.dbname)
- price_dict = pool.get('product.pricelist').price_get(self.cr, self.uid, [pricelist_id], product_id,qty)
+ price_dict = pool.get('product.pricelist').price_get(self.cr, self.uid, [pricelist_id], product_id, qty, context=self.localcontext)
if price_dict[pricelist_id]:
price = self.formatLang(price_dict[pricelist_id], digits=sale_price_digits)
else:
diff --git a/addons/project/project.py b/addons/project/project.py
index b2dedfd2e36..eb09586ba2c 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -126,7 +126,8 @@ class project(osv.osv):
'priority': fields.integer('Sequence', help="Gives the sequence order when displaying the list of projects"),
'warn_manager': fields.boolean('Warn Manager', help="If you check this field, the project manager will receive a request each time a task is completed by his team.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project Members', help="Project's member. Not used in any computation, just for information purpose, but a user has to be member of a project to add a the to this project.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
+ 'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project Members',
+ help="Project's members are users who can have an access to the tasks related to this project.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'tasks': fields.one2many('project.task', 'project_id', "Project tasks"),
'planned_hours': fields.function(_progress_rate, multi="progress", method=True, string='Planned Time', help="Sum of planned hours of all tasks related to this project and its child projects.",
store = {
diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py
index b0e8b9a6c62..1c5e8cff492 100644
--- a/addons/purchase/purchase.py
+++ b/addons/purchase/purchase.py
@@ -148,7 +148,7 @@ class purchase_order(osv.osv):
STATE_SELECTION = [
('draft', 'Request for Quotation'),
('wait', 'Waiting'),
- ('confirmed', 'Waiting Supplier Ack'),
+ ('confirmed', 'Waiting Approval'),
('approved', 'Approved'),
('except_picking', 'Shipping Exception'),
('except_invoice', 'Invoice Exception'),
@@ -363,7 +363,7 @@ class purchase_order(osv.osv):
_('There is no purchase journal defined for this company: "%s" (id:%d)') % (o.company_id.name, o.company_id.id))
inv = {
'name': o.partner_ref or o.name,
- 'reference': "P%dPO%d" % (o.partner_id.id, o.id),
+ 'reference': o.partner_ref or o.name,
'account_id': a,
'type': 'in_invoice',
'partner_id': o.partner_id.id,
@@ -440,7 +440,7 @@ class purchase_order(osv.osv):
if order_line.product_id.product_tmpl_id.type in ('product', 'consu'):
dest = order.location_id.id
move = self.pool.get('stock.move').create(cr, uid, {
- 'name': 'PO:'+order_line.name,
+ 'name': order.name + ': ' +(order_line.name or ''),
'product_id': order_line.product_id.id,
'product_qty': order_line.product_qty,
'product_uos_qty': order_line.product_qty,
@@ -455,6 +455,7 @@ class purchase_order(osv.osv):
'state': 'draft',
'purchase_line_id': order_line.id,
'company_id': order.company_id.id,
+ 'price_unit': order_line.price_unit
})
if order_line.move_dest_id:
self.pool.get('stock.move').write(cr, uid, [order_line.move_dest_id.id], {'location_id':order.location_id.id})
@@ -816,4 +817,22 @@ class procurement_order(osv.osv):
procurement_order()
+class stock_invoice_onshipping(osv.osv_memory):
+ _inherit = "stock.invoice.onshipping"
+
+ def create_invoice(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ res = super(stock_invoice_onshipping,self).create_invoice(cr, uid, ids, context=context)
+ purchase_obj = self.pool.get('purchase.order')
+ picking_obj = self.pool.get('stock.picking')
+ for pick_id in res:
+ pick = picking_obj.browse(cr, uid, pick_id, context=context)
+ if pick.purchase_id:
+ purchase_obj.write(cr, uid, [pick.purchase_id.id], {
+ 'invoice_ids': [(4, res[pick_id])]}, context=context)
+ return res
+
+stock_invoice_onshipping()
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/purchase/purchase_demo.xml b/addons/purchase/purchase_demo.xml
index 57c06eab346..f3f0ef0672c 100644
--- a/addons/purchase/purchase_demo.xml
+++ b/addons/purchase/purchase_demo.xml
@@ -5,19 +5,19 @@
-
+
-
+
-
+
@@ -48,7 +48,7 @@
[PC3] Medium PC
-
+
900
1
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml
index 359810fb306..7ee96dca850 100644
--- a/addons/purchase/purchase_view.xml
+++ b/addons/purchase/purchase_view.xml
@@ -15,7 +15,7 @@
-
+
@@ -32,7 +32,7 @@
-
+
@@ -40,7 +40,7 @@
-
+
@@ -113,10 +113,10 @@
-
+
-
+
@@ -194,7 +194,7 @@
-
+
@@ -292,7 +292,7 @@
You can create a request for quotation when you want to buy products to a supplier but the purchase is not confirmed yet. Use also this menu to review requests for quotation created automatically based on your logistic rules (minimum stock, MTO, etc). You can convert the request for quotation into a purchase order once the order is confirmed. If you use the extended interface (from user's preferences), you can select the way to control your supplier invoices: based on the order, based on the receptions or manual encoding.
-
@@ -458,7 +458,7 @@
Purchase Lines Not Invoiced
ir.actions.act_window
purchase.order.line
- [('state','in',('confirmed','done')), ('invoiced', '=', False)]
+ [('order_id.invoice_method','<>','picking'), ('state','in',('confirmed','done')), ('invoiced', '=', False)]
form
tree,form
diff --git a/addons/purchase/report/purchase_report_view.xml b/addons/purchase/report/purchase_report_view.xml
index 7f52ca73cf0..40c05e2955c 100644
--- a/addons/purchase/report/purchase_report_view.xml
+++ b/addons/purchase/report/purchase_report_view.xml
@@ -171,7 +171,8 @@
-
+
diff --git a/addons/purchase/stock.py b/addons/purchase/stock.py
index 0d82baa96aa..e32528f985d 100644
--- a/addons/purchase/stock.py
+++ b/addons/purchase/stock.py
@@ -58,6 +58,19 @@ class stock_picking(osv.osv):
'purchase_id': False,
}
+ def _get_address_invoice(self, cr, uid, picking):
+ """ Gets invoice address of a partner
+ @return {'contact': address, 'invoice': address} for invoice
+ """
+ res = super(stock_picking, self)._get_address_invoice(cr, uid, picking)
+ if picking.purchase_id:
+ partner_obj = self.pool.get('res.partner')
+ partner = picking.purchase_id.partner_id or picking.address_id.partner_id
+ data = partner_obj.address_get(cr, uid, [partner.id],
+ ['contact', 'invoice'])
+ res.update(data)
+ return res
+
def get_currency_id(self, cursor, user, picking):
if picking.purchase_id:
return picking.purchase_id.pricelist_id.currency_id.id
diff --git a/addons/purchase/wizard/purchase_line_invoice.py b/addons/purchase/wizard/purchase_line_invoice.py
index 3ff0ee53b6e..200778b6d70 100644
--- a/addons/purchase/wizard/purchase_line_invoice.py
+++ b/addons/purchase/wizard/purchase_line_invoice.py
@@ -158,7 +158,7 @@ class purchase_line_invoice(osv.osv_memory):
'view_mode': 'tree,form',
'res_model': 'account.invoice',
'view_id': False,
- 'context': "{'type':'in_invoice'}",
+ 'context': "{'type':'in_invoice', 'journal_type': 'purchase'}",
'type': 'ir.actions.act_window'
}
purchase_line_invoice()
diff --git a/addons/purchase_requisition/purchase_requisition_view.xml b/addons/purchase_requisition/purchase_requisition_view.xml
index c9580357e57..c68c6dbbb89 100644
--- a/addons/purchase_requisition/purchase_requisition_view.xml
+++ b/addons/purchase_requisition/purchase_requisition_view.xml
@@ -22,7 +22,7 @@
-
+
diff --git a/addons/purchase_requisition/security/ir.model.access.csv b/addons/purchase_requisition/security/ir.model.access.csv
index 4e14688ecc5..ec8c031f88b 100644
--- a/addons/purchase_requisition/security/ir.model.access.csv
+++ b/addons/purchase_requisition/security/ir.model.access.csv
@@ -1,7 +1,7 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_purchase_requisition","purchase.requisition","model_purchase_requisition","purchase.group_purchase_user",1,1,1,1
-"access_purchase_requisition_line","purchase.requisition.line","model_purchase_requisition_line","purchase.group_purchase_user",1,1,1,1
+"access_purchase_requisition_line_purchase_user","purchase.requisition.line","model_purchase_requisition_line","purchase.group_purchase_user",1,1,1,1
"access_purchase_requisition_manager","purchase.requisition manager","model_purchase_requisition","purchase.group_purchase_manager",1,0,0,0
"access_purchase_requisition_line_manager","purchase.requisition.line manager","model_purchase_requisition_line","purchase.group_purchase_manager",1,0,0,0
-"access_purchase_requisition","purchase.requisition","model_purchase_requisition","stock.group_stock_manager",1,0,1,0
-"access_purchase_requisition_line","purchase.requisition.line","model_purchase_requisition_line","stock.group_stock_manager",1,0,1,0
+"access_purchase_requisition_stock_manager","purchase.requisition","model_purchase_requisition","stock.group_stock_manager",1,0,1,0
+"access_purchase_requisition_line_stock_manager","purchase.requisition.line","model_purchase_requisition_line","stock.group_stock_manager",1,0,1,0
diff --git a/addons/report_intrastat/report_intrastat_data.xml b/addons/report_intrastat/report_intrastat_data.xml
index f3c465c1549..006151915e2 100644
--- a/addons/report_intrastat/report_intrastat_data.xml
+++ b/addons/report_intrastat/report_intrastat_data.xml
@@ -4,6 +4,9 @@
+
+
+
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index b0c7e1484b2..520a40b4924 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -403,7 +403,7 @@ class sale_order(osv.osv):
'name': order.client_order_ref or '',
'origin': order.name,
'type': 'out_invoice',
- 'reference': "P%dSO%d" % (order.partner_id.id, order.id),
+ 'reference': order.client_order_ref or order.name,
'account_id': a,
'partner_id': order.partner_id.id,
'journal_id': journal_ids[0],
@@ -705,7 +705,6 @@ class sale_order(osv.osv):
#'state': 'waiting',
'note': line.notes,
'company_id': order.company_id.id,
- 'returned_price': line.price_unit,
})
if line.product_id:
@@ -739,12 +738,13 @@ class sale_order(osv.osv):
proc_obj.write(cr, uid, [proc_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
val = {}
- for proc_id in proc_ids:
- wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
if picking_id:
wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
+ for proc_id in proc_ids:
+ wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
+
if order.state == 'shipping_except':
val['state'] = 'progress'
val['shipped'] = False
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index 3d1a14edd53..15bf57bff9a 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -172,6 +172,7 @@
+
diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml
index dca180baeec..24da97c58ea 100644
--- a/addons/stock/product_view.xml
+++ b/addons/stock/product_view.xml
@@ -106,7 +106,7 @@
+ type="action" icon="gtk-execute" groups = "stock.group_stock_manager,stock.group_stock_user"/>
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index ee21ce83a75..51417c52075 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -272,7 +272,7 @@ class stock_location(osv.osv):
context['compute_child'] = False
if not product_ids:
- product_ids = product_obj.search(cr, uid, [])
+ product_ids = product_obj.search(cr, uid, [], context={'active_test': False})
products = product_obj.browse(cr, uid, product_ids, context=context)
products_by_uom = {}
@@ -864,8 +864,7 @@ class stock_picking(osv.osv):
@return {'contact': address, 'invoice': address} for invoice
"""
partner_obj = self.pool.get('res.partner')
- partner = (picking.purchase_id and picking.purchase_id.partner_id) or (picking.sale_id and picking.sale_id.partner_id) or picking.address_id.partner_id
-
+ partner = picking.address_id.partner_id
return partner_obj.address_get(cr, uid, [partner.id],
['contact', 'invoice'])
@@ -960,6 +959,7 @@ class stock_picking(osv.osv):
invoice_obj = self.pool.get('account.invoice')
invoice_line_obj = self.pool.get('account.invoice.line')
+ address_obj = self.pool.get('res.partner.address')
invoices_group = {}
res = {}
inv_type = type
@@ -983,6 +983,7 @@ class stock_picking(osv.osv):
address_contact_id, address_invoice_id = \
self._get_address_invoice(cr, uid, picking).values()
+ address = address_obj.browse(cr, uid, address_contact_id, context=context)
comment = self._get_comment_invoice(cr, uid, picking)
if group and partner.id in invoices_group:
@@ -1002,7 +1003,7 @@ class stock_picking(osv.osv):
'origin': (picking.name or '') + (picking.origin and (':' + picking.origin) or ''),
'type': inv_type,
'account_id': account_id,
- 'partner_id': partner.id,
+ 'partner_id': address.partner_id.id,
'address_invoice_id': address_invoice_id,
'address_contact_id': address_contact_id,
'comment': comment,
@@ -1159,6 +1160,7 @@ class stock_picking(osv.osv):
complete, too_many, too_few = [], [], []
move_product_qty = {}
prodlot_ids = {}
+ product_avail = {}
for move in pick.move_lines:
if move.state in ('done', 'cancel'):
continue
@@ -1184,6 +1186,12 @@ class stock_picking(osv.osv):
move_currency_id = move.company_id.currency_id.id
context['currency_id'] = move_currency_id
qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
+
+ if product.id in product_avail:
+ product_avail[product.id] += qty
+ else:
+ product_avail[product.id] = product.qty_available
+
if qty > 0:
new_price = currency_obj.compute(cr, uid, product_currency,
move_currency_id, product_price)
@@ -1194,9 +1202,8 @@ class stock_picking(osv.osv):
else:
# Get the standard price
amount_unit = product.price_get('standard_price', context)[product.id]
- new_std_price = ((amount_unit * product.qty_available)\
- + (new_price * qty))/(product.qty_available + qty)
-
+ new_std_price = ((amount_unit * product_avail[product.id])\
+ + (new_price * qty))/(product_avail[product.id] + qty)
# Write the field according to price type field
product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price})
@@ -1206,8 +1213,6 @@ class stock_picking(osv.osv):
{'price_unit': product_price,
'price_currency_id': product_currency})
- if not move.returned_price:
- move_obj.write(cr, uid, [move.id], {'returned_price': move.price_unit})
for move in too_few:
product_qty = move_product_qty[move.id]
@@ -1547,7 +1552,6 @@ class stock_move(osv.osv):
# used for colors in tree views:
'scrapped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scrapped', readonly=True),
- 'returned_price': fields.float('Returned product price', digits_compute= dp.get_precision('Sale Price')),
}
_constraints = [
(_check_tracking,
@@ -1784,7 +1788,7 @@ class stock_move(osv.osv):
picking_obj = self.pool.get('stock.picking')
pick_id= picking_obj.create(cr, uid, {
'name': pick_name,
- 'origin': str(picking.origin or ''),
+ 'origin': tools.ustr(picking.origin or ''),
'type': ptype,
'note': picking.note,
'move_type': picking.move_type,
@@ -1796,6 +1800,51 @@ class stock_move(osv.osv):
'date': picking.date,
})
return pick_id
+ def create_chained_picking(self, cr, uid, moves, context=None):
+ res_obj = self.pool.get('res.company')
+ location_obj = self.pool.get('stock.location')
+ move_obj = self.pool.get('stock.move')
+ wf_service = netsvc.LocalService("workflow")
+ new_moves = []
+ if context is None:
+ context = {}
+ seq_obj = self.pool.get('ir.sequence')
+ for picking, todo in self._chain_compute(cr, uid, moves, context=context).items():
+ ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
+ if picking:
+ # name of new picking according to its type
+ new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
+ pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
+ # Need to check name of old picking because it always considers picking as "OUT" when created from Sale Order
+ old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
+ if old_ptype != picking.type:
+ old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
+ self.pool.get('stock.picking').write(cr, uid, picking.id, {'name': old_pick_name}, context=context)
+ else:
+ pickid = False
+ for move, (loc, dummy, delay, dummy, company_id, ptype) in todo:
+ new_id = move_obj.copy(cr, uid, move.id, {
+ 'location_id': move.location_dest_id.id,
+ 'location_dest_id': loc.id,
+ 'date_moved': time.strftime('%Y-%m-%d'),
+ 'picking_id': pickid,
+ 'state': 'waiting',
+ 'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
+ 'move_history_ids': [],
+ 'date': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
+ 'move_history_ids2': []}
+ )
+ move_obj.write(cr, uid, [move.id], {
+ 'move_dest_id': new_id,
+ 'move_history_ids': [(4, new_id)]
+ })
+ new_moves.append(self.browse(cr, uid, [new_id])[0])
+ if pickid:
+ wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
+ if new_moves:
+ new_moves += self.create_chained_picking(cr, uid, new_moves, context)
+ return new_moves
+
def action_confirm(self, cr, uid, ids, context=None):
""" Confirms stock move.
@return: List of ids.
@@ -1807,46 +1856,7 @@ class stock_move(osv.osv):
move_obj = self.pool.get('stock.move')
wf_service = netsvc.LocalService("workflow")
- def create_chained_picking(self, cr, uid, moves, context=None):
- new_moves = []
- if context is None:
- context = {}
- seq_obj = self.pool.get('ir.sequence')
- for picking, todo in self._chain_compute(cr, uid, moves, context=context).items():
- ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
- if picking:
- # name of new picking according to its type
- new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
- pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
- # Need to check name of old picking because it always considers picking as "OUT" when created from Sale Order
- old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
- if old_ptype != picking.type:
- old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
- self.pool.get('stock.picking').write(cr, uid, picking.id, {'name': old_pick_name}, context=context)
- else:
- pickid = False
- for move, (loc, dummy, delay, dummy, company_id, ptype) in todo:
- new_id = move_obj.copy(cr, uid, move.id, {
- 'location_id': move.location_dest_id.id,
- 'location_dest_id': loc.id,
- 'date_moved': time.strftime('%Y-%m-%d'),
- 'picking_id': pickid,
- 'state': 'waiting',
- 'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
- 'move_history_ids': [],
- 'date': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
- 'move_history_ids2': []}
- )
- move_obj.write(cr, uid, [move.id], {
- 'move_dest_id': new_id,
- 'move_history_ids': [(4, new_id)]
- })
- new_moves.append(self.browse(cr, uid, [new_id])[0])
- if pickid:
- wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
- if new_moves:
- create_chained_picking(self, cr, uid, new_moves, context)
- create_chained_picking(self, cr, uid, moves, context)
+ self.create_chained_picking(cr, uid, moves, context)
return []
def action_assign(self, cr, uid, ids, *args):
@@ -2114,6 +2124,8 @@ class stock_move(osv.osv):
prodlot_id = partial_datas and partial_datas.get('move%s_prodlot_id' % (move.id), False)
if prodlot_id:
self.write(cr, uid, [move.id], {'prodlot_id': prodlot_id}, context=context)
+ if move.state not in ('confirmed','done'):
+ self.action_confirm(cr, uid, move_ids, context=context)
self.write(cr, uid, move_ids, {'state': 'done', 'date_planned': time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
for id in move_ids:
@@ -2218,6 +2230,8 @@ class stock_move(osv.osv):
'tracking_id': move.tracking_id.id,
'prodlot_id': move.prodlot_id.id,
}
+ if move.location_id.usage <> 'internal':
+ default_val.update({'location_id': move.location_dest_id.id})
new_move = self.copy(cr, uid, move.id, default_val)
res += [new_move]
@@ -2568,22 +2582,33 @@ class stock_inventory(osv.osv):
self.write(cr, uid, [inv.id], {'state': 'confirm', 'move_ids': [(6, 0, move_ids)]})
return True
- def action_cancel(self, cr, uid, ids, context=None):
+ 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)
- self.write(cr, uid, [inv.id], {'state': 'draft'})
+ 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_inventary(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):
- self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context)
- self.write(cr, uid, [inv.id], {'state':'cancel'})
+ 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(_('UserError'),
+ _('You can not cancel inventory which has any account move with posted state.'))
+ account_move_obj.unlink(cr, uid, [account_move['id']], context=context)
+ self.write(cr, uid, [inv.id], {'state': 'cancel'}, context=context)
return True
stock_inventory()
diff --git a/addons/stock/stock_incoterms.xml b/addons/stock/stock_incoterms.xml
index 371b61055ba..fb9082161ba 100644
--- a/addons/stock/stock_incoterms.xml
+++ b/addons/stock/stock_incoterms.xml
@@ -49,5 +49,14 @@
DDU
DELIVERED DUTY UNPAID
+
+ DAT
+ Delivered At Terminal
+
+
+ DAP
+ Delivered At Place
+
+
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index 4c7c6e56442..13684b3999a 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -170,11 +170,11 @@
-
-
+
+
-
+
@@ -773,7 +773,7 @@
-
+
@@ -967,7 +967,7 @@
-
+
@@ -1189,7 +1189,7 @@
-
+
@@ -1779,6 +1779,8 @@
tree,form
+
+
-
+
diff --git a/addons/stock/wizard/stock_partial_picking.py b/addons/stock/wizard/stock_partial_picking.py
index d9822fff6b1..5d15b3715bd 100644
--- a/addons/stock/wizard/stock_partial_picking.py
+++ b/addons/stock/wizard/stock_partial_picking.py
@@ -33,51 +33,71 @@ class stock_partial_picking(osv.osv_memory):
'product_moves_in' : fields.one2many('stock.move.memory.in', 'wizard_id', 'Moves'),
}
- def __is_in(self,cr, uid, pick_ids):
+ def get_picking_type(self, cr, uid, picking, context=None):
+ picking_type = picking.type
+ for move in picking.move_lines:
+ if picking.type == 'in' and move.product_id.cost_method == 'average':
+ picking_type = 'in'
+ break
+ else:
+ picking_type = 'out'
+ return picking_type
+
+ def default_get(self, cr, uid, fields, context=None):
+ """ To get default values for the object.
+ @param self: The object pointer.
+ @param cr: A database cursor
+ @param uid: ID of the user currently logged in
+ @param fields: List of fields for which we want default values
+ @param context: A standard dictionary
+ @return: A dictionary which of fields with values.
"""
- @return: True if one of the moves has as picking type 'in'
- """
- if not pick_ids:
- return False
+ if context is None:
+ context = {}
+
+ pick_obj = self.pool.get('stock.picking')
+ res = super(stock_partial_picking, self).default_get(cr, uid, fields, context=context)
+ picking_ids = context.get('active_ids', [])
+ if not picking_ids:
+ return res
+
+ result = []
+ for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
+ pick_type = self.get_picking_type(cr, uid, pick, context=context)
+ for m in pick.move_lines:
+ if m.state in ('done', 'cancel'):
+ continue
+ result.append(self.__create_partial_picking_memory(m, pick_type))
+
+ if 'product_moves_in' in fields:
+ res.update({'product_moves_in': result})
+ if 'product_moves_out' in fields:
+ res.update({'product_moves_out': result})
+ if 'date' in fields:
+ res.update({'date': time.strftime('%Y-%m-%d %H:%M:%S')})
+ return res
+
+ def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
+ result = super(stock_partial_picking, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
pick_obj = self.pool.get('stock.picking')
- pick_ids = pick_obj.search(cr, uid, [('id','in',pick_ids)])
-
-
- for pick in pick_obj.browse(cr, uid, pick_ids):
- for move in pick.move_lines:
- if pick.type == 'in' and move.product_id.cost_method == 'average':
- return True
- return False
-
- def __get_picking_type(self, cr, uid, pick_ids):
- if self.__is_in(cr, uid, pick_ids):
- return "product_moves_in"
- else:
- return "product_moves_out"
-
- def view_init(self, cr, uid, fields_list, context=None):
- res = super(stock_partial_picking, self).view_init(cr, uid, fields_list, context=context)
- return res
-
- def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False,submenu=False):
- result = super(stock_partial_picking, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu)
-
-
picking_ids = context.get('active_ids', False)
- picking_type = self.__get_picking_type(cr, uid, picking_ids)
+
+ for pick in pick_obj.browse(cr, uid, picking_ids, context=context):
+ picking_type = self.get_picking_type(cr, uid, pick, context=context)
_moves_arch_lst = """