diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py
index d3bb42208a7..1cf884dc78e 100644
--- a/addons/procurement/procurement.py
+++ b/addons/procurement/procurement.py
@@ -105,12 +105,12 @@ class procurement_order(osv.osv):
'group_id': fields.many2one('procurement.group', 'Procurement Requisition'),
'rule_id': fields.many2one('procurement.rule', 'Rule'),
- 'product_id': fields.many2one('product.product', 'Product', required=True, states={'draft': [('readonly', False)]}, readonly=True),
- 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True, states={'draft': [('readonly', False)]}, readonly=True),
- 'product_uom': fields.many2one('product.uom', 'Product Unit of Measure', required=True, states={'draft': [('readonly', False)]}, readonly=True),
+ 'product_id': fields.many2one('product.product', 'Product', required=True, states={'confirmed': [('readonly', False)]}, readonly=True),
+ 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True, states={'confirmed': [('readonly', False)]}, readonly=True),
+ 'product_uom': fields.many2one('product.uom', 'Product Unit of Measure', required=True, states={'confirmed': [('readonly', False)]}, readonly=True),
- 'product_uos_qty': fields.float('UoS Quantity', states={'draft': [('readonly', False)]}, readonly=True),
- 'product_uos': fields.many2one('product.uom', 'Product UoS', states={'draft': [('readonly', False)]}, readonly=True),
+ 'product_uos_qty': fields.float('UoS Quantity', states={'confirmed': [('readonly', False)]}, readonly=True),
+ 'product_uos': fields.many2one('product.uom', 'Product UoS', states={'confirmed': [('readonly', False)]}, readonly=True),
'state': fields.selection([
('cancel', 'Cancelled'),
diff --git a/addons/procurement/procurement_view.xml b/addons/procurement/procurement_view.xml
index 0475be9ce63..ffb3642f6a7 100644
--- a/addons/procurement/procurement_view.xml
+++ b/addons/procurement/procurement_view.xml
@@ -83,7 +83,7 @@
-
+
diff --git a/addons/sale/__openerp__.py b/addons/sale/__openerp__.py
index 8cc4919e3a1..a71f5f56c0b 100644
--- a/addons/sale/__openerp__.py
+++ b/addons/sale/__openerp__.py
@@ -59,7 +59,7 @@ The Dashboard for the Sales Manager will include
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
'images': ['images/sale_dashboard.jpeg','images/Sale_order_line_to_invoice.jpeg','images/sale_order.jpeg','images/sales_analysis.jpeg'],
- 'depends': ['account_voucher'],
+ 'depends': ['account_voucher', 'procurement'],
'data': [
'wizard/sale_make_invoice_advance.xml',
'wizard/sale_line_invoice.xml',
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index 55bd34009bf..f99b19b5d55 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -624,6 +624,78 @@ class sale_order(osv.osv):
+
+ def _prepare_order_line_procurement(self, cr, uid, order, line, group_id = False, context=None):
+ mod_obj = self.pool.get('ir.model.data')
+ location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', 'stock_location_customers')
+ date_planned = self._get_date_planned(cr, uid, order, line, order.date_order, context=context)
+ return {
+ 'name': line.name,
+ 'origin': order.name,
+ 'date_planned': date_planned,
+ 'product_id': line.product_id.id,
+ 'product_qty': line.product_uom_qty,
+ 'product_uom': line.product_uom.id,
+ 'product_uos_qty': (line.product_uos and line.product_uos_qty)\
+ or line.product_uom_qty,
+ 'product_uos': (line.product_uos and line.product_uos.id)\
+ or line.product_uom.id,
+ 'location_id': location_id,
+ 'company_id': order.company_id.id,
+ 'note': line.name,
+ 'group_id': group_id,
+ }
+
+ def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
+ start_date = self.date_to_datetime(cr, uid, start_date, context)
+ date_planned = datetime.strptime(start_date, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=line.delay or 0.0)
+ date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+ return date_planned
+
+ def action_ship_create(self, cr, uid, ids, context=None):
+ """Create the required procurements to supply sales order lines, also connecting
+ the procurements to appropriate stock moves in order to bring the goods to the
+ sales order's requested location.
+
+ :param browse_record order: sales order to which the order lines belong
+ :param list(browse_record) order_lines: sales order line records to procure
+ :param int picking_id: optional ID of a stock picking to which the created stock moves
+ will be added. A new picking will be created if omitted.
+ :return: True
+ """
+ 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}, context=context)
+ for line in order.order_line:
+ if (line.state == 'done') or not line.product_id:
+ continue
+
+ 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})
+
+ procurement_obj.signal_button_confirm(cr, uid, proc_ids)
+
+ # FP NOTE: do we need this? isn't it the workflow that should set this
+ val = {}
+ if order.state == 'shipping_except':
+ val['state'] = 'progress'
+ val['shipped'] = False
+
+ if (order.order_policy == 'manual'):
+ for line in order.order_line:
+ if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
+ val['state'] = 'manual'
+ break
+ order.write(val)
+ return True
+
+
+
+
+
+
# TODO add a field price_unit_uos
# - update it on change product and unit price
# - use it in report if there is a uos
@@ -664,6 +736,15 @@ class sale_order_line(osv.osv):
WHERE rel.invoice_id = ANY(%s)""", (list(ids),))
return [i[0] for i in cr.fetchall()]
+ def _number_packages(self, cr, uid, ids, field_name, arg, context=None):
+ res = {}
+ for line in self.browse(cr, uid, ids, context=context):
+ try:
+ res[line.id] = int((line.product_uom_qty+line.product_packaging.qty-0.0001) / line.product_packaging.qty)
+ except:
+ res[line.id] = 1
+ return res
+
_name = 'sale.order.line'
_description = 'Sales Order Line'
_columns = {
@@ -697,6 +778,12 @@ class sale_order_line(osv.osv):
'order_partner_id': fields.related('order_id', 'partner_id', type='many2one', relation='res.partner', store=True, string='Customer'),
'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)]}),
+ 'product_packaging': fields.many2one('product.packaging', 'Packaging'),
+ 'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'),
+
}
_order = 'order_id desc, sequence, id'
_defaults = {
@@ -708,6 +795,8 @@ class sale_order_line(osv.osv):
'state': 'draft',
'type': 'make_to_stock',
'price_unit': 0.0,
+ 'delay': 0.0,
+ 'product_packaging': False,
}
def _get_line_qty(self, cr, uid, line, context=None):
@@ -776,6 +865,111 @@ class sale_order_line(osv.osv):
return res
+
+
+ def product_packaging_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False,
+ partner_id=False, packaging=False, flag=False, context=None):
+ if not product:
+ return {'value': {'product_packaging': False}}
+ product_obj = self.pool.get('product.product')
+ product_uom_obj = self.pool.get('product.uom')
+ pack_obj = self.pool.get('product.packaging')
+ warning = {}
+ result = {}
+ warning_msgs = ''
+ if flag:
+ res = self.product_id_change(cr, uid, ids, pricelist=pricelist,
+ product=product, qty=qty, uom=uom, partner_id=partner_id,
+ packaging=packaging, flag=False, context=context)
+ warning_msgs = res.get('warning') and res['warning']['message']
+
+ products = product_obj.browse(cr, uid, product, context=context)
+ if not products.packaging:
+ packaging = result['product_packaging'] = False
+ elif not packaging and products.packaging and not flag:
+ packaging = products.packaging[0].id
+ result['product_packaging'] = packaging
+
+ if packaging:
+ default_uom = products.uom_id and products.uom_id.id
+ pack = pack_obj.browse(cr, uid, packaging, context=context)
+ q = product_uom_obj._compute_qty(cr, uid, uom, pack.qty, default_uom)
+# qty = qty - qty % q + q
+ if qty and (q and not (qty % q) == 0):
+ ean = pack.ean or _('(n/a)')
+ qty_pack = pack.qty
+ type_ul = pack.ul
+ if not warning_msgs:
+ warn_msg = _("You selected a quantity of %d Units.\n"
+ "But it's not compatible with the selected packaging.\n"
+ "Here is a proposition of quantities according to the packaging:\n"
+ "EAN: %s Quantity: %s Type of ul: %s") % \
+ (qty, ean, qty_pack, type_ul.name)
+ warning_msgs += _("Picking Information ! : ") + warn_msg + "\n\n"
+ warning = {
+ 'title': _('Configuration Error!'),
+ 'message': warning_msgs
+ }
+ result['product_uom_qty'] = qty
+
+ return {'value': result, 'warning': warning}
+
+ def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
+ uom=False, qty_uos=0, uos=False, name='', partner_id=False,
+ lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
+ context = context or {}
+ product_uom_obj = self.pool.get('product.uom')
+ partner_obj = self.pool.get('res.partner')
+ product_obj = self.pool.get('product.product')
+ warning = {}
+ res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,
+ uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
+ lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)
+
+ if not product:
+ res['value'].update({'product_packaging': False})
+ return res
+
+ #update of result obtained in super function
+ product_obj = product_obj.browse(cr, uid, product, context=context)
+ res['value']['delay'] = (product_obj.sale_delay or 0.0)
+ #res['value']['type'] = product_obj.procure_method
+
+ #check if product is available, and if not: raise an error
+ uom2 = False
+ if uom:
+ uom2 = product_uom_obj.browse(cr, uid, uom)
+ if product_obj.uom_id.category_id.id != uom2.category_id.id:
+ uom = False
+ if not uom2:
+ uom2 = product_obj.uom_id
+
+ # Calling product_packaging_change function after updating UoM
+ res_packing = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context)
+ res['value'].update(res_packing.get('value', {}))
+ warning_msgs = res_packing.get('warning') and res_packing['warning']['message'] or ''
+ compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding)
+ if (product_obj.type=='product') and int(compare_qty) == -1:
+ #and (product_obj.procure_method=='make_to_stock'): --> need to find alternative for procure_method
+ warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \
+ (qty, uom2 and uom2.name or product_obj.uom_id.name,
+ max(0,product_obj.virtual_available), product_obj.uom_id.name,
+ max(0,product_obj.qty_available), product_obj.uom_id.name)
+ warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n"
+
+ #update of warning messages
+ if warning_msgs:
+ warning = {
+ 'title': _('Configuration Error!'),
+ 'message' : warning_msgs
+ }
+ res.update({'warning': warning})
+ return res
+
+
+
+
+
def invoice_line_create(self, cr, uid, ids, context=None):
if context is None:
context = {}
diff --git a/addons/sale_stock/__openerp__.py b/addons/sale_stock/__openerp__.py
index df6b9ad1fdf..070d132a61d 100644
--- a/addons/sale_stock/__openerp__.py
+++ b/addons/sale_stock/__openerp__.py
@@ -57,7 +57,7 @@ You can choose flexible invoicing methods:
'report/sale_report_view.xml',
#'process/sale_stock_process.xml',
],
- 'demo_xml': ['sale_stock_demo.xml'],
+ 'demo_xml': ['sale_stock_demo.xml'],
'test': ['test/cancel_order_sale_stock.yml',
'test/picking_order_policy.yml',
'test/prepaid_order_policy.yml',
diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py
index 38a8d77ebbc..7c02e1b1ad6 100644
--- a/addons/sale_stock/sale_stock.py
+++ b/addons/sale_stock/sale_stock.py
@@ -37,6 +37,18 @@ class sale_order(osv.osv):
})
return super(sale_order, self).copy(cr, uid, id, default, context=context)
+ #Might have been deleted before for a reason
+ def shipping_policy_change(self, cr, uid, ids, policy, context=None):
+ if not policy:
+ return {}
+ inv_qty = 'order'
+ if policy == 'prepaid':
+ inv_qty = 'order'
+ elif policy == 'picking':
+ inv_qty = 'procurement'
+ return {'value': {'invoice_quantity': inv_qty}}
+
+
def _get_default_warehouse(self, cr, uid, context=None):
company_id = self.pool.get('res.users')._get_company(cr, uid, context=context)
warehouse_ids = self.pool.get('stock.warehouse').search(cr, uid, [('company_id', '=', company_id)], context=context)
@@ -139,7 +151,7 @@ class sale_order(osv.osv):
for mov in pick.move_lines:
proc_ids = proc_obj.search(cr, uid, [('move_id', '=', mov.id)])
if proc_ids:
- proc_obj.signal_button_check(cr, uid, proc_ids)
+ proc_obj.signal_button_check(cr, uid, proc_ids)
for r in self.read(cr, uid, ids, ['picking_ids']):
stock_obj.signal_button_cancel(cr, uid, r['picking_ids'])
return super(sale_order, self).action_cancel(cr, uid, ids, context=context)
@@ -152,13 +164,6 @@ class sale_order(osv.osv):
self.write(cr, uid, [o.id], {'order_policy': 'manual'}, context=context)
return res
- def procurement_lines_get(self, cr, uid, ids, *args):
- res = []
- for order in self.browse(cr, uid, ids, context={}):
- for line in order.order_line:
- if line.procurement_id:
- res.append(line.procurement_id.id)
- return res
def date_to_datetime(self, cr, uid, userdate, context=None):
""" Convert date values expressed in user's timezone to
@@ -215,81 +220,6 @@ class sale_order(osv.osv):
elif mode == 'canceled':
return canceled
- def _prepare_order_line_procurement(self, cr, uid, order, line, group_id = False, context=None):
- mod_obj = self.pool.get('ir.model.data')
- location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', 'stock_location_customers')
- date_planned = self._get_date_planned(cr, uid, order, line, order.date_order, context=context)
- return {
- 'name': line.name,
- 'origin': order.name,
- 'date_planned': date_planned,
- 'product_id': line.product_id.id,
- 'product_qty': line.product_uom_qty,
- 'product_uom': line.product_uom.id,
- 'product_uos_qty': (line.product_uos and line.product_uos_qty)\
- or line.product_uom_qty,
- 'product_uos': (line.product_uos and line.product_uos.id)\
- or line.product_uom.id,
- 'location_id': location_id,
- 'procure_method': line.type,
- 'move_id': move_id,
- 'company_id': order.company_id.id,
- 'note': line.name,
- 'group_id': group_id,
- }
-
- def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
- start_date = self.date_to_datetime(cr, uid, start_date, context)
- date_planned = datetime.strptime(start_date, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=line.delay or 0.0)
- date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
- return date_planned
-
- def action_ship_create(self, cr, uid, ids, context=None):
- """Create the required procurements to supply sales order lines, also connecting
- the procurements to appropriate stock moves in order to bring the goods to the
- sales order's requested location.
-
- If ``picking_id`` is provided, the stock moves will be added to it, otherwise
- a standard outgoing picking will be created to wrap the stock moves, as returned
- by :meth:`~._prepare_order_picking`.
-
- Modules that wish to customize the procurements or partition the stock moves over
- multiple stock pickings may override this method and call ``super()`` with
- different subsets of ``order_lines`` and/or preset ``picking_id`` values.
-
- :param browse_record order: sales order to which the order lines belong
- :param list(browse_record) order_lines: sales order line records to procure
- :param int picking_id: optional ID of a stock picking to which the created stock moves
- will be added. A new picking will be created if ommitted.
- :return: True
- """
- 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}, context=context)
- for line in order.order_lines:
- if (line.state == 'done') or not line.product_id:
- continue
-
- 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})
-
- procurement_obj.signal_button_confirm(cr, uid, proc_ids)
-
- # FP NOTE: do we need this? isn't it the workflow that should set this
- val = {}
- if order.state == 'shipping_except':
- val['state'] = 'progress'
- val['shipped'] = False
-
- if (order.order_policy == 'manual'):
- for line in order.order_line:
- if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
- val['state'] = 'manual'
- break
- order.write(val)
- return True
def action_ship_end(self, cr, uid, ids, context=None):
for order in self.browse(cr, uid, ids, context=context):
@@ -316,6 +246,14 @@ class sale_order(osv.osv):
if order_line.product_id and order_line.product_id.type in ('product', 'consu'):
return True
return False
+
+ def procurement_lines_get(self, cr, uid, ids, *args):
+ res = []
+ for order in self.browse(cr, uid, ids, context={}):
+ for line in order.order_line:
+ if line.procurement_id:
+ res.append(line.procurement_id.id)
+ return res
class stock_move(osv.osv):
_inherit = 'stock.move'
@@ -326,27 +264,11 @@ class stock_move(osv.osv):
class sale_order_line(osv.osv):
- def _number_packages(self, cr, uid, ids, field_name, arg, context=None):
- res = {}
- for line in self.browse(cr, uid, ids, context=context):
- try:
- res[line.id] = int((line.product_uom_qty+line.product_packaging.qty-0.0001) / line.product_packaging.qty)
- except:
- res[line.id] = 1
- return res
+
_inherit = 'sale.order.line'
_columns = {
- '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)]}),
- 'product_packaging': fields.many2one('product.packaging', 'Packaging'),
'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True),
- 'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'),
- }
- _defaults = {
- 'delay': 0.0,
- 'product_packaging': False,
}
def button_cancel(self, cr, uid, ids, context=None):
@@ -365,105 +287,6 @@ class sale_order_line(osv.osv):
default.update({'move_ids': []})
return super(sale_order_line, self).copy_data(cr, uid, id, default, context=context)
- def product_packaging_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False,
- partner_id=False, packaging=False, flag=False, context=None):
- if not product:
- return {'value': {'product_packaging': False}}
- product_obj = self.pool.get('product.product')
- product_uom_obj = self.pool.get('product.uom')
- pack_obj = self.pool.get('product.packaging')
- warning = {}
- result = {}
- warning_msgs = ''
- if flag:
- res = self.product_id_change(cr, uid, ids, pricelist=pricelist,
- product=product, qty=qty, uom=uom, partner_id=partner_id,
- packaging=packaging, flag=False, context=context)
- warning_msgs = res.get('warning') and res['warning']['message']
-
- products = product_obj.browse(cr, uid, product, context=context)
- if not products.packaging:
- packaging = result['product_packaging'] = False
- elif not packaging and products.packaging and not flag:
- packaging = products.packaging[0].id
- result['product_packaging'] = packaging
-
- if packaging:
- default_uom = products.uom_id and products.uom_id.id
- pack = pack_obj.browse(cr, uid, packaging, context=context)
- q = product_uom_obj._compute_qty(cr, uid, uom, pack.qty, default_uom)
-# qty = qty - qty % q + q
- if qty and (q and not (qty % q) == 0):
- ean = pack.ean or _('(n/a)')
- qty_pack = pack.qty
- type_ul = pack.ul
- if not warning_msgs:
- warn_msg = _("You selected a quantity of %d Units.\n"
- "But it's not compatible with the selected packaging.\n"
- "Here is a proposition of quantities according to the packaging:\n"
- "EAN: %s Quantity: %s Type of ul: %s") % \
- (qty, ean, qty_pack, type_ul.name)
- warning_msgs += _("Picking Information ! : ") + warn_msg + "\n\n"
- warning = {
- 'title': _('Configuration Error!'),
- 'message': warning_msgs
- }
- result['product_uom_qty'] = qty
-
- return {'value': result, 'warning': warning}
-
- def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
- uom=False, qty_uos=0, uos=False, name='', partner_id=False,
- lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
- context = context or {}
- product_uom_obj = self.pool.get('product.uom')
- partner_obj = self.pool.get('res.partner')
- product_obj = self.pool.get('product.product')
- warning = {}
- res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,
- uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
- lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)
-
- if not product:
- res['value'].update({'product_packaging': False})
- return res
-
- #update of result obtained in super function
- product_obj = product_obj.browse(cr, uid, product, context=context)
- res['value']['delay'] = (product_obj.sale_delay or 0.0)
- res['value']['type'] = product_obj.procure_method
-
- #check if product is available, and if not: raise an error
- uom2 = False
- if uom:
- uom2 = product_uom_obj.browse(cr, uid, uom)
- if product_obj.uom_id.category_id.id != uom2.category_id.id:
- uom = False
- if not uom2:
- uom2 = product_obj.uom_id
-
- # Calling product_packaging_change function after updating UoM
- res_packing = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context)
- res['value'].update(res_packing.get('value', {}))
- warning_msgs = res_packing.get('warning') and res_packing['warning']['message'] or ''
- compare_qty = float_compare(product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding)
- if (product_obj.type=='product') and int(compare_qty) == -1 \
- and (product_obj.procure_method=='make_to_stock'):
- warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \
- (qty, uom2 and uom2.name or product_obj.uom_id.name,
- max(0,product_obj.virtual_available), product_obj.uom_id.name,
- max(0,product_obj.qty_available), product_obj.uom_id.name)
- warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n"
-
- #update of warning messages
- if warning_msgs:
- warning = {
- 'title': _('Configuration Error!'),
- 'message' : warning_msgs
- }
- res.update({'warning': warning})
- return res
-
class sale_advance_payment_inv(osv.osv_memory):
_inherit = "sale.advance.payment.inv"
diff --git a/addons/stock/procurement.py b/addons/stock/procurement.py
index ca1f5075ae7..1ad13b67aef 100644
--- a/addons/stock/procurement.py
+++ b/addons/stock/procurement.py
@@ -77,6 +77,7 @@ class procurement_order(osv.osv):
'location_id': procurement.rule_id.location_src_id.id,
'location_dest_id': procurement.rule_id.location_id.id,
'move_dest_id': procurement.move_dest_id and procurement.move_dest_id.id or False,
+ 'procure_method': procurement.rule_id and procurement.rule_id.procure_method or 'make_to_stock',
#'cancel_cascade': procurement.rule_id and procurement.rule_id.cancel_cascade or False,
'group_id': procurement.group_id and procurement.group_id.id or False,
}
diff --git a/addons/stock_location/stock_location.py b/addons/stock_location/stock_location.py
index 1f5c25e11ca..674ae0d8768 100644
--- a/addons/stock_location/stock_location.py
+++ b/addons/stock_location/stock_location.py
@@ -140,7 +140,7 @@ class procurement_order(osv.osv):
date = procurement.date_planned
newdate = (datetime.strptime(date, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.rule_id.delay or 0)).strftime('%Y-%m-%d %H:%M:%S')
d.update({
- 'date_planned': newdate,
+ 'date': newdate,
})
return d
diff --git a/addons/stock_location_sale/__init__.py b/addons/stock_location_sale/__init__.py
deleted file mode 100644
index d9d11c54f81..00000000000
--- a/addons/stock_location_sale/__init__.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-import stock_location_sale
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/stock_location_sale/__openerp__.py b/addons/stock_location_sale/__openerp__.py
deleted file mode 100644
index 84fe0e7b704..00000000000
--- a/addons/stock_location_sale/__openerp__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-
-{
- 'name': 'Advanced Routes with sales',
- 'version': '1.0',
- 'category': 'Manufacturing',
- 'description': """
-Cross-module for stock_location and sale such that a sale order generates a procurement in stock instead
- """,
- 'author': 'OpenERP SA',
- 'images': [],
- 'depends': ['sale', 'stock_location'],
- 'data': [],
- 'demo': [
- # 'stock_location_demo_cpu1.xml',
- # 'stock_location_demo_cpu3.yml',
- ],
- 'installable': True,
- 'test': [
- # 'test/stock_location_pull_flow.yml',
- # 'test/stock_location_push_flow.yml',
- ],
- 'auto_install': False,
-}
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/stock_location_sale/stock_location_sale.py b/addons/stock_location_sale/stock_location_sale.py
deleted file mode 100644
index 366af26f7e7..00000000000
--- a/addons/stock_location_sale/stock_location_sale.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv import fields, osv
-from openerp.tools.translate import _
-
-
-class sale_order(osv.osv):
- _inherit = "sale.order"
-
- def action_ship_create(self, cr, uid, ids, context=None):
- print "acitonshipcreate"
- for order in self.browse(cr, uid, ids, context=context):
- self._create_pickings_and_procurements(cr, uid, order, order.order_line, None, context=context)
- return True
-
-
- def _create_pickings_and_procurements(self, cr, uid, order, order_lines, picking_id=False, context=None):
- """Create the required procurements to supply sales order lines, also connecting
- the procurements to appropriate stock moves in order to bring the goods to the
- sales order's requested location.
-
- If ``picking_id`` is provided, the stock moves will be added to it, otherwise
- a standard outgoing picking will be created to wrap the stock moves, as returned
- by :meth:`~._prepare_order_picking`.
-
- Modules that wish to customize the procurements or partition the stock moves over
- multiple stock pickings may override this method and call ``super()`` with
- different subsets of ``order_lines`` and/or preset ``picking_id`` values.
-
- :param browse_record order: sales order to which the order lines belong
- :param list(browse_record) order_lines: sales order line records to procure
- :param int picking_id: optional ID of a stock picking to which the created stock moves
- will be added. A new picking will be created if omitted.
- :return: True
- """
- print "Create pickings and procurements!"
- move_obj = self.pool.get('stock.move')
- picking_obj = self.pool.get('stock.picking')
- procurement_obj = self.pool.get('procurement.order')
- proc_ids = []
-
- #Create group
- group_id = self.pool.get("procurement.group").create(cr, uid, {'name': order.name}, context=context)
-
- for line in order_lines:
- if line.state == 'done':
- continue
-
- date_planned = self._get_date_planned(cr, uid, order, line, order.date_order, context=context)
-
-# if line.product_id:
-# if line.product_id.type in ('product', 'consu'):
-# if not picking_id:
-# picking_id = picking_obj.create(cr, uid, self._prepare_order_picking(cr, uid, order, context=context))
-# #move_id = move_obj.create(cr, uid, self._prepare_order_line_move(cr, uid, order, line, picking_id, date_planned, group_id=group_id, context=context))
-# else:
-# # a service has no stock move
-# move_id = False
-
- #TODO Need to do something instead of warehouse
- if line.product_id:
- proc_id = procurement_obj.create(cr, uid, self._prepare_order_line_procurement(cr, uid, order, line, [], date_planned, group_id = group_id, context=context))
- proc_ids.append(proc_id)
- line.write({'procurement_id': proc_id})
- #self.ship_recreate(cr, uid, order, line, move_id, proc_id)
-
-# if picking_id:
-# picking_obj.signal_button_confirm(cr, uid, [picking_id])
- procurement_obj.signal_button_confirm(cr, uid, proc_ids)
-
- val = {}
- if order.state == 'shipping_except':
- val['state'] = 'progress'
- val['shipped'] = False
-
- if (order.order_policy == 'manual'):
- for line in order.order_line:
- if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
- val['state'] = 'manual'
- break
- order.write(val)
- return True
-
-
-
- def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, group_id = False, context=None):
- mod_obj = self.pool.get('ir.model.data')
- location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', 'stock_location_customers')
- output_id = order.warehouse_id.lot_output_id.id
- return {
- 'name': line.name,
- 'origin': order.name,
- 'date_planned': date_planned,
- 'product_id': line.product_id.id,
- 'product_qty': line.product_uom_qty,
- 'product_uom': line.product_uom.id,
- 'product_uos_qty': (line.product_uos and line.product_uos_qty)\
- or line.product_uom_qty,
- 'product_uos': (line.product_uos and line.product_uos.id)\
- or line.product_uom.id,
- 'location_id': location_id,
- 'procure_method': line.type,
- 'move_id': move_id,
- 'company_id': order.company_id.id,
- 'note': line.name,
- 'group_id': group_id,
- 'state': 'draft',
- }