[WIP] Move from sale_stock what has only to do with procurement to sale and remove stock_location_sale
bzr revid: jco@openerp.com-20130710150207-imvyte86hftdd3pq
This commit is contained in:
parent
af7cf8a226
commit
bcf77893af
|
@ -105,12 +105,12 @@ class procurement_order(osv.osv):
|
||||||
'group_id': fields.many2one('procurement.group', 'Procurement Requisition'),
|
'group_id': fields.many2one('procurement.group', 'Procurement Requisition'),
|
||||||
'rule_id': fields.many2one('procurement.rule', 'Rule'),
|
'rule_id': fields.many2one('procurement.rule', 'Rule'),
|
||||||
|
|
||||||
'product_id': fields.many2one('product.product', 'Product', 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={'draft': [('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={'draft': [('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_qty': fields.float('UoS Quantity', states={'confirmed': [('readonly', False)]}, readonly=True),
|
||||||
'product_uos': fields.many2one('product.uom', 'Product UoS', states={'draft': [('readonly', False)]}, readonly=True),
|
'product_uos': fields.many2one('product.uom', 'Product UoS', states={'confirmed': [('readonly', False)]}, readonly=True),
|
||||||
|
|
||||||
'state': fields.selection([
|
'state': fields.selection([
|
||||||
('cancel', 'Cancelled'),
|
('cancel', 'Cancelled'),
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
<field name="date_planned"/>
|
<field name="date_planned"/>
|
||||||
<filter icon="terp-emblem-important" string="Exceptions" name="exceptions" domain="[('state','=','exception')]" help="Procurement Exceptions"/>
|
<filter icon="terp-emblem-important" string="Exceptions" name="exceptions" domain="[('state','=','exception')]" help="Procurement Exceptions"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter icon="terp-gnome-cpu-frequency-applet+" string="Late" domain="['&', ('date_planned','<', current_date), ('state', 'in', ('draft', 'confirmed'))]" help="Procurement started late" />
|
<filter icon="terp-gnome-cpu-frequency-applet+" string="Late" domain="['&', ('date_planned','<', current_date), ('state', '=', 'confirmed')]" help="Procurement started late" />
|
||||||
<field name="product_id" />
|
<field name="product_id" />
|
||||||
<field name="state" />
|
<field name="state" />
|
||||||
<group expand="0" string="Group By">
|
<group expand="0" string="Group By">
|
||||||
|
|
|
@ -59,7 +59,7 @@ The Dashboard for the Sales Manager will include
|
||||||
'author': 'OpenERP SA',
|
'author': 'OpenERP SA',
|
||||||
'website': 'http://www.openerp.com',
|
'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'],
|
'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': [
|
'data': [
|
||||||
'wizard/sale_make_invoice_advance.xml',
|
'wizard/sale_make_invoice_advance.xml',
|
||||||
'wizard/sale_line_invoice.xml',
|
'wizard/sale_line_invoice.xml',
|
||||||
|
|
|
@ -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
|
# TODO add a field price_unit_uos
|
||||||
# - update it on change product and unit price
|
# - update it on change product and unit price
|
||||||
# - use it in report if there is a uos
|
# - 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),))
|
WHERE rel.invoice_id = ANY(%s)""", (list(ids),))
|
||||||
return [i[0] for i in cr.fetchall()]
|
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'
|
_name = 'sale.order.line'
|
||||||
_description = 'Sales Order Line'
|
_description = 'Sales Order Line'
|
||||||
_columns = {
|
_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'),
|
'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'),
|
'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),
|
'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'
|
_order = 'order_id desc, sequence, id'
|
||||||
_defaults = {
|
_defaults = {
|
||||||
|
@ -708,6 +795,8 @@ class sale_order_line(osv.osv):
|
||||||
'state': 'draft',
|
'state': 'draft',
|
||||||
'type': 'make_to_stock',
|
'type': 'make_to_stock',
|
||||||
'price_unit': 0.0,
|
'price_unit': 0.0,
|
||||||
|
'delay': 0.0,
|
||||||
|
'product_packaging': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_line_qty(self, cr, uid, line, context=None):
|
def _get_line_qty(self, cr, uid, line, context=None):
|
||||||
|
@ -776,6 +865,111 @@ class sale_order_line(osv.osv):
|
||||||
|
|
||||||
return res
|
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):
|
def invoice_line_create(self, cr, uid, ids, context=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
|
@ -57,7 +57,7 @@ You can choose flexible invoicing methods:
|
||||||
'report/sale_report_view.xml',
|
'report/sale_report_view.xml',
|
||||||
#'process/sale_stock_process.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': ['test/cancel_order_sale_stock.yml',
|
||||||
'test/picking_order_policy.yml',
|
'test/picking_order_policy.yml',
|
||||||
'test/prepaid_order_policy.yml',
|
'test/prepaid_order_policy.yml',
|
||||||
|
|
|
@ -37,6 +37,18 @@ class sale_order(osv.osv):
|
||||||
})
|
})
|
||||||
return super(sale_order, self).copy(cr, uid, id, default, context=context)
|
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):
|
def _get_default_warehouse(self, cr, uid, context=None):
|
||||||
company_id = self.pool.get('res.users')._get_company(cr, uid, context=context)
|
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)
|
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:
|
for mov in pick.move_lines:
|
||||||
proc_ids = proc_obj.search(cr, uid, [('move_id', '=', mov.id)])
|
proc_ids = proc_obj.search(cr, uid, [('move_id', '=', mov.id)])
|
||||||
if proc_ids:
|
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']):
|
for r in self.read(cr, uid, ids, ['picking_ids']):
|
||||||
stock_obj.signal_button_cancel(cr, uid, r['picking_ids'])
|
stock_obj.signal_button_cancel(cr, uid, r['picking_ids'])
|
||||||
return super(sale_order, self).action_cancel(cr, uid, ids, context=context)
|
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)
|
self.write(cr, uid, [o.id], {'order_policy': 'manual'}, context=context)
|
||||||
return res
|
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):
|
def date_to_datetime(self, cr, uid, userdate, context=None):
|
||||||
""" Convert date values expressed in user's timezone to
|
""" Convert date values expressed in user's timezone to
|
||||||
|
@ -215,81 +220,6 @@ class sale_order(osv.osv):
|
||||||
elif mode == 'canceled':
|
elif mode == 'canceled':
|
||||||
return 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):
|
def action_ship_end(self, cr, uid, ids, context=None):
|
||||||
for order in self.browse(cr, uid, ids, context=context):
|
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'):
|
if order_line.product_id and order_line.product_id.type in ('product', 'consu'):
|
||||||
return True
|
return True
|
||||||
return False
|
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):
|
class stock_move(osv.osv):
|
||||||
_inherit = 'stock.move'
|
_inherit = 'stock.move'
|
||||||
|
@ -326,27 +264,11 @@ class stock_move(osv.osv):
|
||||||
|
|
||||||
class sale_order_line(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'
|
_inherit = 'sale.order.line'
|
||||||
_columns = {
|
_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),
|
'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):
|
def button_cancel(self, cr, uid, ids, context=None):
|
||||||
|
@ -365,105 +287,6 @@ class sale_order_line(osv.osv):
|
||||||
default.update({'move_ids': []})
|
default.update({'move_ids': []})
|
||||||
return super(sale_order_line, self).copy_data(cr, uid, id, default, context=context)
|
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):
|
class sale_advance_payment_inv(osv.osv_memory):
|
||||||
_inherit = "sale.advance.payment.inv"
|
_inherit = "sale.advance.payment.inv"
|
||||||
|
|
|
@ -77,6 +77,7 @@ class procurement_order(osv.osv):
|
||||||
'location_id': procurement.rule_id.location_src_id.id,
|
'location_id': procurement.rule_id.location_src_id.id,
|
||||||
'location_dest_id': procurement.rule_id.location_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,
|
'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,
|
#'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,
|
'group_id': procurement.group_id and procurement.group_id.id or False,
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ class procurement_order(osv.osv):
|
||||||
date = procurement.date_planned
|
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')
|
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({
|
d.update({
|
||||||
'date_planned': newdate,
|
'date': newdate,
|
||||||
})
|
})
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
|
||||||
#
|
|
||||||
# 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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
import stock_location_sale
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
|
@ -1,46 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
|
||||||
#
|
|
||||||
# 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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
'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:
|
|
|
@ -1,128 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
|
||||||
#
|
|
||||||
# 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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
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',
|
|
||||||
}
|
|
Loading…
Reference in New Issue