[MRG] merge with lp:~openerp-dev/openobject-addons/trunk-wmsimplement-seduce-fp
bzr revid: tpa@tinyerp.com-20130910113951-3ner2h0gmi09apvd
This commit is contained in:
@@ -192,7 +192,7 @@
|
||||
- company_id: base.main_company
|
||||
location_id: stock.stock_location_stock
|
||||
product_id: product.product_product_3
|
||||
product_qty: 1.0
|
||||
product_uom_qty: 1.0
|
||||
product_uom: product.product_uom_unit
|
||||
location_dest_id: stock.stock_location_customers
|
||||
invoice_state: 2binvoiced
|
||||
@@ -235,9 +235,7 @@
|
||||
!python {model: stock.invoice.onshipping}: |
|
||||
wiz_id = self.create(cr, uid, {'invoice_date': '2013-03-04', 'journal_id': ref('account.sales_journal')},
|
||||
{'active_ids': [ref("stock_picking_out001")], "active_model": "stock.picking"})
|
||||
self.create_invoice(cr, uid, [wiz_id], {"lang": "en_US",
|
||||
"search_default_available": 1, "tz": False, "active_model": "stock.picking",
|
||||
"contact_display": "partner", "active_ids": [ref("stock_picking_out001")], "active_id": ref("stock_picking_out001")})
|
||||
self.create_invoice(cr, uid, [wiz_id], {"active_ids": [ref("stock_picking_out001")], "active_id": ref("stock_picking_out001")})
|
||||
-
|
||||
I check that the customer invoice is created successfully.
|
||||
-
|
||||
|
||||
@@ -32,7 +32,7 @@ You can define your own carrier and delivery grids for prices. When creating
|
||||
invoices from picking, OpenERP is able to add and compute the shipping line.
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['sale', 'purchase', 'stock_account'],
|
||||
'depends': ['sale_stock', 'purchase'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'delivery_report.xml',
|
||||
|
||||
@@ -28,8 +28,19 @@ class shipping(report_sxw.rml_parse):
|
||||
super(shipping, self).__init__(cr, uid, name, context=context)
|
||||
self.localcontext.update({
|
||||
'time': time,
|
||||
'get_partner_invoice_info': self.get_partner_invoice_info,
|
||||
})
|
||||
|
||||
def get_partner_invoice_info(self, origin):
|
||||
"""This method is used to get information of invoiced partner.
|
||||
:param: origin: origin of picking
|
||||
:return: tuple contaning partner name and address of invoiced partner
|
||||
"""
|
||||
sale_obj = self.pool.get('sale.order')
|
||||
sale_id = sale_obj.search(self.cr, self.uid, [('name', '=', origin)])[0]
|
||||
partner_invoice_id = sale_obj.browse(self.cr, self.uid, sale_id).partner_invoice_id
|
||||
return partner_invoice_id.name, self.pool.get('res.partner')._display_address(self.cr, self.uid, partner_invoice_id)
|
||||
|
||||
report_sxw.report_sxw('report.sale.shipping','stock.picking','addons/delivery/report/shipping.rml',parser=shipping)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -107,14 +107,11 @@
|
||||
<story>
|
||||
<pto>
|
||||
<pto_header>
|
||||
<blockTable colWidths="370.0,85.0,82.0" repeatRows="1" style="Table3">
|
||||
<blockTable colWidths="455.0,82.0" repeatRows="1" style="Table3">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="terp_tblheader_Details">Description</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_tblheader_Details_Centre">Lot</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_tblheader_Details_Right">Quantity</para>
|
||||
</td>
|
||||
@@ -130,12 +127,12 @@
|
||||
<tr>
|
||||
<td>
|
||||
<para style="terp_default_Bold_9">Invoiced to</para>
|
||||
<para style="terp_default_9">[[ o.sale_id and o.sale_id.partner_invoice_id and o.sale_id.partner_invoice_id.name or '']]</para>
|
||||
<para style="terp_default_9">[[ o.sale_id and o.sale_id.partner_invoice_id and display_address(o.sale_id.partner_invoice_id) ]]</para>
|
||||
<para style="terp_default_9">[[ o.origin and get_partner_invoice_info(o.origin)[0] or '' ]]</para>
|
||||
<para style="terp_default_9">[[ o.origin and get_partner_invoice_info(o.origin)[1] or '' ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_9">[[ o.partner_id and o.partner_id and o.partner_id.name or '' ]]</para>
|
||||
<para style="terp_default_9">[[ o.partner_id and o.partner_id and display_address(o.partner_id) ]]</para>
|
||||
<para style="terp_default_9">[[ o.partner_id and o.partner_id.name or '' ]]</para>
|
||||
<para style="terp_default_9">[[ o.partner_id and display_address(o.partner_id) ]]</para>
|
||||
</td>
|
||||
</tr>
|
||||
</blockTable>
|
||||
@@ -165,7 +162,7 @@
|
||||
<blockTable colWidths="126.0,103.0,103.0,103.0,103.0" style="Table2">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="terp_default_Centre_8">[[ o.sale_id and o.sale_id.name ]]</para>
|
||||
<para style="terp_default_Centre_8">[[ o.origin or '' ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Centre_8">[[ formatLang(o.date,date_time=True) ]]</para>
|
||||
@@ -184,14 +181,11 @@
|
||||
<para style="Standard">
|
||||
<font color="white"> </font>
|
||||
</para>
|
||||
<blockTable colWidths="370.0,85.0,82.0" repeatRows="1" style="Table3">
|
||||
<blockTable colWidths="455.0,82.0" repeatRows="1" style="Table3">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="terp_tblheader_Details">Description</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_tblheader_Details_Centre">Lot</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_tblheader_Details_Right">Quantity</para>
|
||||
</td>
|
||||
@@ -199,14 +193,11 @@
|
||||
</blockTable>
|
||||
<section>
|
||||
<para style="terp_default_1">[[repeatIn(o.move_lines,'line')]]</para>
|
||||
<blockTable colWidths="370.0,85.0,83.0" style="Table4">
|
||||
<blockTable colWidths="455.0,82.0" style="Table4">
|
||||
<tr>
|
||||
<td>
|
||||
<para style="terp_default_9">[[line.product_id.code ]] [[ line.product_id and line.product_id.name or '']]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Centre_9">[[ (line.prodlot_id and (line.prodlot_id.name + (line.prodlot_id.ref and ('/' + line.prodlot_id.ref) or ''))) or ' ' ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Right_9">[[ formatLang(line.product_qty) ]] [[ line.product_uom and line.product_uom.name ]]</para>
|
||||
</td>
|
||||
|
||||
+13
-18
@@ -30,7 +30,6 @@ class stock_picking(osv.osv):
|
||||
|
||||
def _cal_weight(self, cr, uid, ids, name, args, context=None):
|
||||
res = {}
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
for picking in self.browse(cr, uid, ids, context=context):
|
||||
total_weight = total_weight_net = 0.00
|
||||
|
||||
@@ -119,26 +118,22 @@ class stock_picking(osv.osv):
|
||||
'invoice_line_tax_id': [(6, 0, taxes_ids)],
|
||||
}
|
||||
|
||||
def action_invoice_create(self, cr, uid, ids, journal_id=False,
|
||||
group=False, type='out_invoice', context=None):
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
picking_obj = self.pool.get('stock.picking')
|
||||
def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None):
|
||||
''' This function simply creates the invoice from the given values. It is overriden in delivery module to add the delivery costs. picking is a browse_record
|
||||
'''
|
||||
invoice_line_obj = self.pool.get('account.invoice.line')
|
||||
result = super(stock_picking, self).action_invoice_create(cr, uid,
|
||||
ids, journal_id=journal_id, group=group, type=type,
|
||||
context=context)
|
||||
for picking in picking_obj.browse(cr, uid, result, context=context):
|
||||
invoice = invoice_obj.browse(cr, uid, picking.id, context=context)
|
||||
invoice_line = self._prepare_shipping_invoice_line(cr, uid, picking, invoice, context=context)
|
||||
if invoice_line:
|
||||
invoice_line_obj.create(cr, uid, invoice_line)
|
||||
invoice_obj.button_compute(cr, uid, [invoice.id], context=context)
|
||||
return result
|
||||
def _get_default_uom(self,cr,uid,c):
|
||||
invoice_id = super(stock_picking, self)._create_invoice_from_picking(cr, uid, picking, vals, context=context)
|
||||
invoice = self.browse(cr, uid, invoice_id, context=context)
|
||||
invoice_line = self._prepare_shipping_invoice_line(cr, uid, picking, invoice, context=context)
|
||||
if invoice_line:
|
||||
invoice_line_obj.create(cr, uid, invoice_line)
|
||||
return invoice_id
|
||||
|
||||
def _get_default_uom(self, cr, uid, c):
|
||||
uom_categ, uom_categ_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'product', 'product_uom_categ_kgm')
|
||||
return self.pool.get('product.uom').search(cr, uid, [('category_id', '=', uom_categ_id),('factor','=',1)])[0]
|
||||
return self.pool.get('product.uom').search(cr, uid, [('category_id', '=', uom_categ_id), ('factor', '=', 1)])[0]
|
||||
_defaults = {
|
||||
'weight_uom_id': lambda self,cr,uid,c: self._get_default_uom(cr,uid,c)
|
||||
'weight_uom_id': lambda self, cr, uid, c: self._get_default_uom(cr, uid, c)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<field name="res_model">product.product</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context" eval="'{\'default_type\':\'service\',\'default_procure_method\':\'make_to_stock\',\'default_supply_method\':\'buy\',\'default_purchase_ok\':True, \'default_sale_ok\':False, \'default_hr_expense_ok\':True,\'default_categ_id\': ' + str(ref('cat_expense')) +'}'"/>
|
||||
<field name="context" eval="'{\'default_type\':\'service\',\'default_purchase_ok\':True, \'default_sale_ok\':False, \'default_hr_expense_ok\':True,\'default_categ_id\': ' + str(ref('cat_expense')) +'}'"/>
|
||||
<field name="domain">[('hr_expense_ok','=',True)]</field>
|
||||
<field name="view_id" ref="product_expense_installer_tree_view"/>
|
||||
<field name="help">Define one product for each expense type allowed for an employee (travel by car, hostel, restaurant, etc). If you reimburse the employees at a fixed rate, set a cost and a unit of measure on the product. If you reimburse based on real costs, set the cost at 0.00. The user will set the real price when recording his expense sheet.</field>
|
||||
|
||||
+8
-8
@@ -187,7 +187,7 @@ class mrp_bom(osv.osv):
|
||||
result[bom.id] = []
|
||||
if bom.bom_lines:
|
||||
continue
|
||||
ok = ((name=='child_complete_ids') and (bom.product_id.supply_method=='produce'))
|
||||
ok = ((name=='child_complete_ids'))
|
||||
if (bom.type=='phantom' or ok):
|
||||
sids = bom_obj.search(cr, uid, [('bom_id','=',False),('product_id','=',bom.product_id.id)])
|
||||
if sids:
|
||||
@@ -209,11 +209,10 @@ class mrp_bom(osv.osv):
|
||||
continue
|
||||
if line.bom_lines or line.type == 'phantom':
|
||||
continue
|
||||
if line.product_id.supply_method == 'produce':
|
||||
if line.product_id.procure_method == 'make_to_stock':
|
||||
res[line.id] = 'stock'
|
||||
else:
|
||||
res[line.id] = 'order'
|
||||
if line.product_id.procure_method == 'make_to_stock':
|
||||
res[line.id] = 'stock'
|
||||
else:
|
||||
res[line.id] = 'order'
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
@@ -454,11 +453,12 @@ class mrp_production(osv.osv):
|
||||
|
||||
def _moves_assigned(self, cr, uid, ids, name, arg, context=None):
|
||||
""" Test whether all the consume lines are assigned """
|
||||
res = True
|
||||
res = {}
|
||||
for production in self.browse(cr, uid, ids, context=context):
|
||||
res[production.id] = True
|
||||
states = [x.state != 'assigned' for x in production.move_lines if x]
|
||||
if any(states) or len(states) == 0:
|
||||
return False
|
||||
res[production.id] = False
|
||||
return res
|
||||
|
||||
|
||||
|
||||
@@ -27,5 +27,21 @@ This application supports complete integration and production scheduling for sto
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Procurement rules and routes
|
||||
-->
|
||||
|
||||
<record id="route_warehouse0_manufacture" model='stock.location.route'>
|
||||
<field name="name">Manufacture</field>
|
||||
<field name="sequence">5</field>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_supply_stock" model="procurement.rule">
|
||||
<field name="name">Manufacture to stock</field>
|
||||
<field name="action">manufacture</field>
|
||||
<field name="location_id" ref="stock.stock_location_stock"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_in"/>
|
||||
<field name="route_id" ref="route_warehouse0_manufacture"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
+5
-18
@@ -347,7 +347,7 @@
|
||||
<form string="Bill of Material" version="7.0">
|
||||
<group>
|
||||
<group>
|
||||
<field name="product_id" on_change="onchange_product_id(product_id, name, context)" context="{'default_supply_method':'produce'}" class="oe_inline"/>
|
||||
<field name="product_id" on_change="onchange_product_id(product_id, name, context)" class="oe_inline"/>
|
||||
<label for="product_qty" string="Quantity"/>
|
||||
<div>
|
||||
<field name="product_qty" class="oe_inline"/>
|
||||
@@ -380,7 +380,7 @@
|
||||
<page string="Components">
|
||||
<field name="bom_lines" widget="one2many_list">
|
||||
<tree string="Components" editable="bottom">
|
||||
<field name="product_id" context="{'default_supply_method':'produce'}" on_change="onchange_product_id(product_id, name)"/>
|
||||
<field name="product_id" on_change="onchange_product_id(product_id, name)"/>
|
||||
<field name="product_qty"/>
|
||||
<field name="product_uom" on_change="onchange_uom(product_id, product_uom)" groups="product.group_uom"/>
|
||||
<field name="name" invisible="1"/>
|
||||
@@ -517,7 +517,7 @@
|
||||
<field name="res_model">product.product</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="context">{'search_default_filter_supply_method_produce' : 1}</field>
|
||||
<field name="context">{}</field>
|
||||
<field name="search_view_id" ref="product.product_search_form_view"/>
|
||||
</record>
|
||||
<!-- BOM menus -->
|
||||
@@ -634,7 +634,7 @@
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="product_id" on_change="product_id_change(product_id)" domain="[('bom_ids','!=',False),('bom_ids.bom_id','=',False)]" class="oe_inline" context='{"default_supply_method":"produce", "default_type": "product"}'/>
|
||||
<field name="product_id" on_change="product_id_change(product_id)" domain="[('bom_ids','!=',False),('bom_ids.bom_id','=',False)]" class="oe_inline" context='{"default_type": "product"}'/>
|
||||
<label for="product_qty"/>
|
||||
<div>
|
||||
<field name="product_qty" class="oe_inline"/>
|
||||
@@ -950,20 +950,7 @@
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
<record id="product_product_normal_form_supply_view" model="ir.ui.view">
|
||||
<field name="name">product.normal.form.mrp.inherit</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="stock.product_form_view_procurement_button"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='supply_method']" position="attributes">
|
||||
<attribute name="invisible">False</attribute>
|
||||
</xpath>
|
||||
<group name="procurement_help" position="inside">
|
||||
<!-- TODO: create help with routes -->
|
||||
<p>Here should come some help about manufacturing routes</p>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Menu for Resource for MRP-->
|
||||
|
||||
|
||||
@@ -44,9 +44,8 @@ class procurement_order(osv.osv):
|
||||
rule_id = super(procurement_order, self)._find_suitable_rule(cr, uid, procurement, context=context)
|
||||
if not rule_id:
|
||||
#if there isn't any specific procurement.rule defined for the product, we try to directly supply it from a supplier
|
||||
if procurement.product_id.supply_method == 'manufacture':
|
||||
rule_id = self._search_suitable_rule(cr, uid, procurement, [('action', '=', 'manufacture'), ('location_id', '=', procurement.location_id.id)], context=context)
|
||||
rule_id = rule_id and rule_id[0] or False
|
||||
rule_id = self._search_suitable_rule(cr, uid, procurement, [('action', '=', 'manufacture'), ('location_id', '=', procurement.location_id.id)], context=context)
|
||||
rule_id = rule_id and rule_id[0] or False
|
||||
return rule_id
|
||||
|
||||
def _run(self, cr, uid, procurement, context=None):
|
||||
@@ -92,7 +91,7 @@ class procurement_order(osv.osv):
|
||||
|
||||
def get_phantom_bom_id(self, cr, uid, ids, context=None):
|
||||
for procurement in self.browse(cr, uid, ids, context=context):
|
||||
if procurement.move_dest_id and procurement.move_dest_id.product_id.supply_method=='produce':
|
||||
if procurement.move_dest_id:
|
||||
phantom_bom_id = self.pool.get('mrp.bom').search(cr, uid, [
|
||||
('product_id', '=', procurement.move_dest_id.product_id.id),
|
||||
('bom_id', '=', False),
|
||||
|
||||
+50
-50
@@ -41,57 +41,57 @@ class StockMove(osv.osv):
|
||||
procurement_obj = self.pool.get('procurement.order')
|
||||
product_obj = self.pool.get('product.product')
|
||||
processed_ids = [move.id]
|
||||
if move.product_id.supply_method == 'produce':
|
||||
bis = bom_obj.search(cr, uid, [
|
||||
('product_id','=',move.product_id.id),
|
||||
('bom_id','=',False),
|
||||
('type','=','phantom')])
|
||||
if bis:
|
||||
factor = move.product_qty
|
||||
bom_point = bom_obj.browse(cr, uid, bis[0], context=context)
|
||||
res = bom_obj._bom_explode(cr, uid, bom_point, factor, [])
|
||||
state = 'confirmed'
|
||||
if move.state == 'assigned':
|
||||
state = 'assigned'
|
||||
for line in res[0]:
|
||||
valdef = {
|
||||
'picking_id': move.picking_id.id,
|
||||
'product_id': line['product_id'],
|
||||
'product_uom': line['product_uom'],
|
||||
'product_qty': line['product_qty'],
|
||||
'product_uos': line['product_uos'],
|
||||
'product_uos_qty': line['product_uos_qty'],
|
||||
'move_dest_id': move.id,
|
||||
'state': state,
|
||||
'name': line['name'],
|
||||
'procurements': [],
|
||||
}
|
||||
mid = move_obj.copy(cr, uid, move.id, default=valdef)
|
||||
processed_ids.append(mid)
|
||||
prodobj = product_obj.browse(cr, uid, line['product_id'], context=context)
|
||||
proc_id = procurement_obj.create(cr, uid, {
|
||||
'name': (move.picking_id.origin or ''),
|
||||
'origin': (move.picking_id.origin or ''),
|
||||
'date_planned': move.date,
|
||||
'product_id': line['product_id'],
|
||||
'product_qty': line['product_qty'],
|
||||
'product_uom': line['product_uom'],
|
||||
'product_uos_qty': line['product_uos'] and line['product_uos_qty'] or False,
|
||||
'product_uos': line['product_uos'],
|
||||
'location_id': move.location_id.id,
|
||||
'procure_method': prodobj.procure_method,
|
||||
'move_id': mid,
|
||||
})
|
||||
procurement_obj.signal_button_confirm(cr, uid, [proc_id])
|
||||
|
||||
move_obj.write(cr, uid, [move.id], {
|
||||
'location_dest_id': move.location_id.id, # dummy move for the kit
|
||||
'picking_id': False,
|
||||
'state': 'confirmed'
|
||||
|
||||
bis = bom_obj.search(cr, uid, [
|
||||
('product_id','=',move.product_id.id),
|
||||
('bom_id','=',False),
|
||||
('type','=','phantom')])
|
||||
if bis:
|
||||
factor = move.product_qty
|
||||
bom_point = bom_obj.browse(cr, uid, bis[0], context=context)
|
||||
res = bom_obj._bom_explode(cr, uid, bom_point, factor, [])
|
||||
state = 'confirmed'
|
||||
if move.state == 'assigned':
|
||||
state = 'assigned'
|
||||
for line in res[0]:
|
||||
valdef = {
|
||||
'picking_id': move.picking_id.id,
|
||||
'product_id': line['product_id'],
|
||||
'product_uom': line['product_uom'],
|
||||
'product_qty': line['product_qty'],
|
||||
'product_uos': line['product_uos'],
|
||||
'product_uos_qty': line['product_uos_qty'],
|
||||
'move_dest_id': move.id,
|
||||
'state': state,
|
||||
'name': line['name'],
|
||||
'procurements': [],
|
||||
}
|
||||
mid = move_obj.copy(cr, uid, move.id, default=valdef)
|
||||
processed_ids.append(mid)
|
||||
prodobj = product_obj.browse(cr, uid, line['product_id'], context=context)
|
||||
proc_id = procurement_obj.create(cr, uid, {
|
||||
'name': (move.picking_id.origin or ''),
|
||||
'origin': (move.picking_id.origin or ''),
|
||||
'date_planned': move.date,
|
||||
'product_id': line['product_id'],
|
||||
'product_qty': line['product_qty'],
|
||||
'product_uom': line['product_uom'],
|
||||
'product_uos_qty': line['product_uos'] and line['product_uos_qty'] or False,
|
||||
'product_uos': line['product_uos'],
|
||||
'location_id': move.location_id.id,
|
||||
'procure_method': prodobj.procure_method,
|
||||
'move_id': mid,
|
||||
})
|
||||
procurement_ids = procurement_obj.search(cr, uid, [('move_id','=',move.id)], context)
|
||||
procurement_obj.signal_button_confirm(cr, uid, procurement_ids)
|
||||
procurement_obj.signal_button_wait_done(cr, uid, procurement_ids)
|
||||
procurement_obj.signal_button_confirm(cr, uid, [proc_id])
|
||||
|
||||
move_obj.write(cr, uid, [move.id], {
|
||||
'location_dest_id': move.location_id.id, # dummy move for the kit
|
||||
'picking_id': False,
|
||||
'state': 'confirmed'
|
||||
})
|
||||
procurement_ids = procurement_obj.search(cr, uid, [('move_id','=',move.id)], context)
|
||||
procurement_obj.signal_button_confirm(cr, uid, procurement_ids)
|
||||
procurement_obj.signal_button_wait_done(cr, uid, procurement_ids)
|
||||
return processed_ids
|
||||
|
||||
def action_consume(self, cr, uid, ids, product_qty, location_id=False, context=None):
|
||||
|
||||
@@ -157,6 +157,7 @@ class mrp_repair(osv.osv):
|
||||
'quotation_notes': fields.text('Quotation Notes'),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'deliver_bool': fields.boolean('Deliver', help="Check this box if you want to manage the delivery once the product is repaired and create a picking with selected product. Note that you can select the locations in the Info tab, if you have the extended view.", states={'confirmed':[('readonly',True)]}),
|
||||
'picking_type_id': fields.many2one('stock.picking.type', 'Picking Type'),
|
||||
'invoiced': fields.boolean('Invoiced', readonly=True),
|
||||
'repaired': fields.boolean('Repaired', readonly=True),
|
||||
'amount_untaxed': fields.function(_amount_untaxed, string='Untaxed Amount',
|
||||
@@ -501,7 +502,6 @@ class mrp_repair(osv.osv):
|
||||
res = {}
|
||||
move_obj = self.pool.get('stock.move')
|
||||
repair_line_obj = self.pool.get('mrp.repair.line')
|
||||
seq_obj = self.pool.get('ir.sequence')
|
||||
pick_obj = self.pool.get('stock.picking')
|
||||
for repair in self.browse(cr, uid, ids, context=context):
|
||||
for move in repair.operations:
|
||||
@@ -517,7 +517,9 @@ class mrp_repair(osv.osv):
|
||||
})
|
||||
repair_line_obj.write(cr, uid, [move.id], {'move_id': move_id, 'state': 'done'}, context=context)
|
||||
if repair.deliver_bool:
|
||||
pick_name = seq_obj.get(cr, uid, 'stock.picking.out')
|
||||
if not repair.picking_type_id:
|
||||
raise osv.except_osv(_('Warning!'), _('No picking type set.'))
|
||||
pick_name = self.pool.get('ir.sequence').get_id(cr, uid, repair.picking_type_id.sequence_id.id, 'id', context=context)
|
||||
picking = pick_obj.create(cr, uid, {
|
||||
'name': pick_name,
|
||||
'origin': repair.name,
|
||||
@@ -526,7 +528,7 @@ class mrp_repair(osv.osv):
|
||||
'partner_id': repair.address_id and repair.address_id.id or False,
|
||||
'note': repair.internal_notes,
|
||||
'invoice_state': 'none',
|
||||
'type': 'out',
|
||||
'picking_type_id': repair.picking_type_id.id,
|
||||
})
|
||||
move_id = move_obj.create(cr, uid, {
|
||||
'name': repair.name,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
partner_invoice_id: base.res_partner_address_1
|
||||
location_dest_id: stock.stock_location_14
|
||||
location_id: stock.stock_location_14
|
||||
picking_type_id: stock.picking_type_out
|
||||
move_id: 'stock_move_pcbasicpc0'
|
||||
name: RMA00004
|
||||
operations:
|
||||
@@ -59,6 +60,7 @@
|
||||
partner_invoice_id: base.res_partner_address_1
|
||||
location_dest_id: stock.stock_location_14
|
||||
location_id: stock.stock_location_14
|
||||
picking_type_id: stock.picking_type_out
|
||||
move_id: 'stock.stock_move_stockmvmrp1'
|
||||
name: RMA-00007
|
||||
operations:
|
||||
@@ -100,6 +102,7 @@
|
||||
partner_invoice_id: base.res_partner_address_1
|
||||
location_dest_id: stock.stock_location_14
|
||||
location_id: stock.stock_location_14
|
||||
picking_type_id: stock.picking_type_out
|
||||
move_id: 'stock.stock_move_stockmvmrp2'
|
||||
name: RMA-00011
|
||||
operations:
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<group>
|
||||
<field name="guarantee_limit"/>
|
||||
<field name="deliver_bool"/>
|
||||
<field name="picking_type_id" attrs="{'invisible': [('deliver_bool','=', False)], 'required': [('deliver_bool', '=', True)]}"/>
|
||||
<field name="repaired" groups="base.group_no_one"/>
|
||||
<field name="invoiced" groups="base.group_no_one"/>
|
||||
</group>
|
||||
|
||||
@@ -256,7 +256,7 @@
|
||||
<para style="P16">[[ o.product_id.name or '' ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="P16">[[ o.prodlot_id.name or ' ' ]]</para>
|
||||
<para style="P16">[[ ','.join([x.name for x in o.move_id.lot_ids]) ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="P16">[[ formatLang(o.guarantee_limit,date = True) ]]</para>
|
||||
|
||||
@@ -150,7 +150,6 @@
|
||||
</record>
|
||||
<record id="product_product_odoo1" model="product.product">
|
||||
<field name="default_code">ODOO</field>
|
||||
<field name="supply_method">produce</field>
|
||||
<field name="list_price">35.0</field>
|
||||
<field name="standard_price">10.0</field>
|
||||
<field name="uom_id" ref="product.product_uom_unit"/>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="product_product_jambon" model="product.product">
|
||||
<field name="supply_method">buy</field>
|
||||
<field name="list_price">7.0</field>
|
||||
<field name="standard_price">5.0</field>
|
||||
<field name="uom_id" ref="product.product_uom_unit"/>
|
||||
@@ -32,7 +31,6 @@
|
||||
</record>
|
||||
|
||||
<record id="product_product_from" model="product.product">
|
||||
<field name="supply_method">buy</field>
|
||||
<field name="list_price">8.0</field>
|
||||
<field name="standard_price">6.0</field>
|
||||
<field name="uom_id" ref="product.product_uom_unit"/>
|
||||
@@ -62,7 +60,6 @@
|
||||
</record>
|
||||
|
||||
<record id="product_product_pain" model="product.product">
|
||||
<field name="supply_method">buy</field>
|
||||
<field name="list_price">8.0</field>
|
||||
<field name="standard_price">6.0</field>
|
||||
<field name="uom_id" ref="product.product_uom_unit"/>
|
||||
@@ -92,7 +89,6 @@
|
||||
</record>
|
||||
|
||||
<record id="product_product_lait" model="product.product">
|
||||
<field name="supply_method">buy</field>
|
||||
<field name="list_price">8.0</field>
|
||||
<field name="standard_price">6.0</field>
|
||||
<field name="uom_id" ref="product.product_uom_unit"/>
|
||||
|
||||
@@ -41,16 +41,6 @@
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="product_product_normal_form_supply_view" model="ir.ui.view">
|
||||
<field name="name">product.normal.form.project_mrp.inherit</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="stock.product_form_view_procurement_button"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='supply_method']" position="attributes">
|
||||
<attribute name="invisible">False</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
mes_type: fixed
|
||||
name: HR Manager
|
||||
standard_price: 1.0
|
||||
supply_method: buy
|
||||
type: service
|
||||
uom_id: product.product_uom_hour
|
||||
uom_po_id: product.product_uom_hour
|
||||
|
||||
@@ -1122,9 +1122,8 @@ class procurement_order(osv.osv):
|
||||
rule_id = super(procurement_order, self)._find_suitable_rule(cr, uid, procurement, context=context)
|
||||
if not rule_id:
|
||||
#if there isn't any specific procurement.rule defined for the product, we try to directly supply it from a supplier
|
||||
if procurement.product_id.supply_method == 'buy' and self._check_supplier_info(cr, uid, [procurement.id], context=context):
|
||||
rule_id = self._search_suitable_rule(cr, uid, procurement, [('action', '=', 'buy'), ('location_id', '=', procurement.location_id.id)], context=context)
|
||||
rule_id = rule_id and rule_id[0] or False
|
||||
rule_id = self._search_suitable_rule(cr, uid, procurement, [('action', '=', 'buy'), ('location_id', '=', procurement.location_id.id)], context=context)
|
||||
rule_id = rule_id and rule_id[0] or False
|
||||
return rule_id
|
||||
|
||||
def _run(self, cr, uid, procurement, context=None):
|
||||
|
||||
@@ -67,14 +67,20 @@
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Procurement rules
|
||||
Procurement rules and routes
|
||||
-->
|
||||
|
||||
<record id="route_warehouse0_buy" model='stock.location.route'>
|
||||
<field name="name">Buy</field>
|
||||
<field name="sequence">5</field>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_supply_stock" model="procurement.rule">
|
||||
<field name="name">Buy to refill stock</field>
|
||||
<field name="name">Buy to stock</field>
|
||||
<field name="action">buy</field>
|
||||
<field name="location_id" ref="stock.stock_location_stock"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_in"/>
|
||||
<field name="route_id" ref="route_warehouse0_buy"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -573,18 +573,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_product_normal_form_procurement_help_view" model="ir.ui.view">
|
||||
<field name="name">product.normal.form.procurement.help.inherit</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="stock.product_form_view_procurement_button"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="procurement_help" position="inside">
|
||||
<!--TODO: Should add some procurement help here (something like route.description)-->
|
||||
<p> Procurement help </p>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_search_form_view_purchase" model="ir.ui.view">
|
||||
<field name="name">product.search.purchase.form</field>
|
||||
<field name="model">product.product</field>
|
||||
|
||||
@@ -33,9 +33,9 @@ class stock_move(osv.osv):
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
res = super(stock_move, self).write(cr, uid, ids, vals, context=context)
|
||||
wf_service = netsvc.LocalService('workflow')
|
||||
from openerp import workflow
|
||||
for id in ids:
|
||||
wf_service.trg_trigger(uid, 'stock.move', id, cr)
|
||||
workflow.trg_trigger(uid, 'stock.move', id, cr)
|
||||
return res
|
||||
|
||||
#
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
Process the reception of purchase order with usd
|
||||
-
|
||||
!python {model: stock.picking}: |
|
||||
pick_obj = self.pool.get('stock.picking').browse(cr, uid, ref("purchase_order_fifo_usd"))
|
||||
pick_obj = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo_usd")).picking_ids[0]
|
||||
pick_obj.do_partial(context=context)
|
||||
-
|
||||
We create delivery order of 49.5 kg
|
||||
@@ -255,9 +255,11 @@
|
||||
Check rounded price is 150.0 / 1.2834
|
||||
-
|
||||
!python {model: product.product}: |
|
||||
assert round(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price) == round(150.0 / 1.2834), "Product price not updated accordingly. %s found instead of %s" %(self.browse(cr, uid, ref("product_fifo_icecream")).standard_price, round(150.0/1.2834))
|
||||
product = self.browse(cr, uid, ref("product_fifo_icecream"))
|
||||
assert round(product.standard_price) == round(150.0 / 1.2834), "Product price not updated accordingly. %s found instead of %s" %(product.standard_price, round(150.0/1.2834))
|
||||
assert product.qty_available == 0.0, 'Wrong quantity in stock after first reception'
|
||||
-
|
||||
Let us create some outs to get negative stock. Create outpicking. We create delivery order of 200 kg, but will pick only 100 kg
|
||||
Let us create some outs to get negative stock. Create outpicking. We create delivery order of 100 kg.
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_fifo_shipment_neg}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
@@ -268,12 +270,18 @@
|
||||
picking_id: outgoing_fifo_shipment_neg
|
||||
product_id: product_fifo_icecream
|
||||
product_uom: product.product_uom_kgm
|
||||
product_uom_qty: 200.0
|
||||
product_uom_qty: 100.0
|
||||
location_id: stock.stock_location_stock
|
||||
location_dest_id: stock.stock_location_customers
|
||||
picking_type_id: stock.picking_type_out
|
||||
-
|
||||
Let us create another out of 400 kg, but will pick only 50 kg
|
||||
Process the delivery of the first outgoing shipment
|
||||
-
|
||||
!python {model: stock.picking}: |
|
||||
picking_obj = self.browse(cr, uid, ref("outgoing_fifo_shipment_neg"))
|
||||
picking_obj.do_partial(context=context)
|
||||
-
|
||||
Let us create another out of 400 kg
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_fifo_shipment_neg2}:
|
||||
picking_type_id: stock.picking_type_out
|
||||
@@ -292,8 +300,6 @@
|
||||
Process the delivery of the outgoing shipments
|
||||
-
|
||||
!python {model: stock.picking}: |
|
||||
picking_obj = self.browse(cr, uid, ref("outgoing_fifo_shipment_neg"))
|
||||
picking_obj.do_partial(context=context)
|
||||
picking_obj1 = self.browse(cr, uid, ref("outgoing_fifo_shipment_neg2"))
|
||||
picking_obj1.do_partial(context=context)
|
||||
-
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
-
|
||||
In order to test the scheduler to generate RFQ, I create a new product
|
||||
-
|
||||
!record {model: product.product, id: scheduler_product}:
|
||||
name: scheduler prod
|
||||
type: product
|
||||
supply_method: buy
|
||||
seller_ids:
|
||||
- delay: 1
|
||||
name: base.res_partner_2
|
||||
min_qty: 5.0
|
||||
!record {model: product.product, id: scheduler_product}:
|
||||
name: scheduler prod
|
||||
type: product
|
||||
seller_ids:
|
||||
- delay: 1
|
||||
name: base.res_partner_2
|
||||
min_qty: 5.0
|
||||
-
|
||||
Add Buy route
|
||||
-
|
||||
!python {model: product.product, id: scheduler_product}: |
|
||||
self.write(cr, uid, [ref("scheduler_product")], {"route_ids": [(4, ref("purchase.route_warehouse0_buy"))]})
|
||||
-
|
||||
I create a procurement order.
|
||||
-
|
||||
|
||||
@@ -58,13 +58,20 @@ class purchase_requisition(osv.osv):
|
||||
'Status', track_visibility='onchange', required=True),
|
||||
'multiple_rfq_per_supplier': fields.boolean('Multiple RFQ per supplier'),
|
||||
'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'),
|
||||
'picking_type_id': fields.many2one('stock.picking.type', 'Picking Type', required=True),
|
||||
}
|
||||
|
||||
def _get_picking_in(self, cr, uid, context=None):
|
||||
obj_data = self.pool.get('ir.model.data')
|
||||
return obj_data.get_object_reference(cr, uid, 'stock','picking_type_in')[1]
|
||||
|
||||
_defaults = {
|
||||
'state': 'draft',
|
||||
'exclusive': 'multiple',
|
||||
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'purchase.requisition', context=c),
|
||||
'user_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).id,
|
||||
'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'purchase.order.requisition'),
|
||||
'picking_type_id': _get_picking_in,
|
||||
}
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
@@ -142,12 +149,11 @@ class purchase_requisition(osv.osv):
|
||||
'date_order': requisition.date_end or fields.date.context_today(self, cr, uid, context=context),
|
||||
'partner_id': supplier.id,
|
||||
'pricelist_id': supplier_pricelist,
|
||||
#'location_id': location_id,
|
||||
'location_id': requisition.picking_type_id.default_location_dest_id.id,
|
||||
'company_id': requisition.company_id.id,
|
||||
'fiscal_position': supplier.property_account_position and supplier.property_account_position.id or False,
|
||||
'requisition_id': requisition.id,
|
||||
'notes': requisition.description,
|
||||
'warehouse_id': requisition.warehouse_id.id if requisition.warehouse_id else False,
|
||||
}
|
||||
|
||||
def _prepare_purchase_order_line(self, cr, uid, requisition, requisition_line, purchase_id, supplier, context=None):
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<field name="ordering_date" attrs="{'readonly': [('state','not in',('draft'))]}"/>
|
||||
<field name="schedule_date" attrs="{'readonly': [('state','not in',('draft'))]}"/>
|
||||
<field name="origin" placeholder="e.g. OP0025" attrs="{'readonly': [('state','not in',('draft'))]}"/>
|
||||
<field name="warehouse_id" widget="selection" groups="stock.group_locations" attrs="{'readonly': [('state','not in',('draft'))]}"/>
|
||||
<field name="picking_type_id" widget="selection" groups="stock.group_locations" attrs="{'readonly': [('state','not in',('draft'))]}"/>
|
||||
<field name="company_id" groups="base.group_multi_company" widget="selection" attrs="{'readonly': [('state','not in',('draft'))]}"/>
|
||||
</group>
|
||||
</group>
|
||||
@@ -197,7 +197,7 @@
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="stock.product_form_view_procurement_button"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="supply_method" position="after">
|
||||
<field name="route_ids" position="after">
|
||||
<field name="purchase_requisition"/>
|
||||
</field>
|
||||
</field>
|
||||
|
||||
+8
-4
@@ -640,9 +640,13 @@ class sale_order(osv.osv):
|
||||
|
||||
def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
|
||||
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 _prepare_procurement_group(self, cr, uid, order, context=None):
|
||||
return {
|
||||
'name': order.name, 'partner_id': order.partner_shipping_id.id,
|
||||
}
|
||||
|
||||
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
|
||||
@@ -657,9 +661,9 @@ class sale_order(osv.osv):
|
||||
procurement_obj = self.pool.get('procurement.order')
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
proc_ids = []
|
||||
group_id = self.pool.get("procurement.group").create(cr, uid, {
|
||||
'name': order.name, 'partner_id': order.partner_shipping_id.id, 'move_type': order.picking_policy
|
||||
}, context=context)
|
||||
vals = self._prepare_procurement_group(cr, uid, order, context=context)
|
||||
group_id = self.pool.get("procurement.group").create(cr, uid, vals, context=context)
|
||||
|
||||
order.write({'procurement_group_id': group_id}, context=context)
|
||||
for line in order.order_line:
|
||||
if (line.state == 'done') or not line.product_id:
|
||||
|
||||
@@ -325,7 +325,6 @@ Thanks!</field>
|
||||
<field name="type">service</field>
|
||||
<field name="list_price">150.0</field>
|
||||
<field name="standard_price">100.0</field>
|
||||
<field name="supply_method">produce</field> <!-- TODO this is a procurement field, which is not a sale dependency -->
|
||||
<field name="uom_id" ref="product.product_uom_day"/>
|
||||
<field name="uom_po_id" ref="product.product_uom_day"/>
|
||||
<field name="company_id" eval="[]"/>
|
||||
|
||||
@@ -64,9 +64,9 @@ class mrp_production(osv.osv):
|
||||
if parent_move_line:
|
||||
move = move_obj.browse(cr, uid, parent_move_line)
|
||||
if field_name == 'name':
|
||||
res[production.id] = move.sale_line_id and move.sale_line_id.order_id.name or False
|
||||
res[production.id] = move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.name or False
|
||||
if field_name == 'client_order_ref':
|
||||
res[production.id] = move.sale_line_id and move.sale_line_id.order_id.client_order_ref or False
|
||||
res[production.id] = move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.client_order_ref or False
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
mes_type: fixed
|
||||
name: Slider Mobile
|
||||
standard_price: 189.0
|
||||
supply_method: produce
|
||||
type: product
|
||||
uom_id: product.product_uom_unit
|
||||
uom_po_id: product.product_uom_unit
|
||||
@@ -38,10 +37,14 @@
|
||||
min_qty: 2.0
|
||||
qty: 5.0
|
||||
standard_price: 189.0
|
||||
supply_method: produce
|
||||
type: product
|
||||
uom_id: product.product_uom_unit
|
||||
uom_po_id: product.product_uom_unit
|
||||
-
|
||||
I add the routes manufacture and mto to the product
|
||||
-
|
||||
!python {model: product.product, id: scheduler_product}: |
|
||||
self.write(cr, uid, [ref("product_product_slidermobile0")], {"route_ids": [(4, ref("mrp.route_warehouse0_manufacture")), (4, ref("stock.route_warehouse0_mto"))]})
|
||||
-
|
||||
I create a Bill of Material record for Slider Mobile
|
||||
-
|
||||
@@ -97,7 +100,7 @@
|
||||
sale_order_obj = self.pool.get('sale.order')
|
||||
so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
|
||||
proc_ids = self.search(cr, uid, [('origin','=',so.name)])
|
||||
self.signal_button_check(cr, uid, proc_ids)
|
||||
self.run(cr, uid, proc_ids)
|
||||
-
|
||||
I verify that a procurement state is "running"
|
||||
-
|
||||
@@ -105,14 +108,14 @@
|
||||
sale_order_obj = self.pool.get('sale.order')
|
||||
so = sale_order_obj.browse(cr, uid, ref("sale_order_so0"))
|
||||
proc_ids = self.search(cr, uid, [('origin','=',so.name) and ('state','=','running')])
|
||||
assert proc_ids, 'Procurement is not in the running state!'
|
||||
assert len(proc_ids) == 2, 'Not both procurements are in the running state!'
|
||||
-
|
||||
I verify that a manufacturing order has been generated, and that its name and reference are correct
|
||||
-
|
||||
!python {model: sale.order}: |
|
||||
mnf_obj = self.pool.get('mrp.production')
|
||||
so = self.browse(cr, uid, ref("sale_order_so0"))
|
||||
mnf_id = mnf_obj.search(cr, uid, [('origin','=',so.name)])
|
||||
mnf_id = mnf_obj.search(cr, uid, [('origin','like',so.name)])
|
||||
assert mnf_id, 'Manufacturing order has not been generated'
|
||||
mo = mnf_obj.browse(cr, uid, mnf_id)[0]
|
||||
assert mo.sale_name == so.name, 'Wrong Name for the Manufacturing Order. Expected %s, Got %s' % (so.name, mo.name)
|
||||
|
||||
@@ -246,6 +246,17 @@ class sale_order(osv.osv):
|
||||
return finished
|
||||
elif mode == 'canceled':
|
||||
return canceled
|
||||
|
||||
|
||||
def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
|
||||
date_planned = super(sale_order, self)._get_date_planned(cr, uid, order, line, start_date, context=context)
|
||||
date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
return date_planned
|
||||
|
||||
def _prepare_procurement_group(self, cr, uid, order, context=None):
|
||||
res = super(sale_order, self)._prepare_procurement_group(cr, uid, order, context=None)
|
||||
res.update({'move_type': order.picking_policy})
|
||||
return res
|
||||
|
||||
|
||||
def action_ship_end(self, cr, uid, ids, context=None):
|
||||
@@ -419,3 +430,33 @@ class sale_order_line(osv.osv):
|
||||
res.update({'warning': warning})
|
||||
return res
|
||||
|
||||
class stock_move(osv.osv):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):
|
||||
invoice_line_id = self.pool.get('account.invoice.line').create(cr, uid, invoice_line_vals, context=context)
|
||||
if move.procurement_id and move.procurement_id.sale_line_id:
|
||||
sale_line = move.procurement_id.sale_line_id
|
||||
self.pool.get('sale.order.line').write(cr, uid, [sale_line.id], {
|
||||
'invoice_lines': [(4, invoice_line_id)]
|
||||
}, context=context)
|
||||
self.pool.get('sale.order').write(cr, uid, [sale_line.order_id.id], {
|
||||
'invoice_ids': [(4, invoice_line_vals['invoice_id'])],
|
||||
})
|
||||
return invoice_line_id
|
||||
|
||||
def _get_master_data(self, cr, uid, move, company, context=None):
|
||||
if move.procurement_id and move.procurement_id.sale_line_id:
|
||||
sale_order = move.procurement_id.sale_line_id.order_id
|
||||
return sale_order.partner_invoice_id, sale_order.user_id.id, sale_order.pricelist_id.currency_id.id
|
||||
return super(stock_move, self)._get_master_data(cr, uid, move, company, context=context)
|
||||
|
||||
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
|
||||
res = super(stock_move, self)._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
|
||||
if move.procurement_id and move.procurement_id.sale_line_id:
|
||||
sale_line = move.procurement_id.sale_line_id
|
||||
res['invoice_line_tax_id'] = [(6, 0, [x.id for x in sale_line.tax_id])]
|
||||
res['account_analytic_id'] = sale_line.order_id.project_id and sale_line.order_id.project_id.id or False
|
||||
res['price_unit'] = sale_line.price_unit
|
||||
res['discount'] = sale_line.discount
|
||||
return res
|
||||
|
||||
@@ -48,14 +48,14 @@ class sale_order(osv.osv):
|
||||
class sale_order_line(osv.osv):
|
||||
_inherit = 'sale.order.line'
|
||||
_columns = {
|
||||
'route_id': fields.many2one('stock.location.route', 'Route', domain=[('sale', '=', True)]),
|
||||
'route_id': fields.many2one('stock.location.route', 'Route', domain=[('sale_selectable', '=', True)]),
|
||||
}
|
||||
|
||||
|
||||
class stock_location_route(osv.osv):
|
||||
_inherit = "stock.location.route"
|
||||
_columns = {
|
||||
'sale':fields.boolean("Can be set on sale order line")
|
||||
'sale_selectable':fields.boolean("Selectable on Sales Order Line")
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,13 +41,24 @@
|
||||
|
||||
<record id="stock_location_route_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.location.route.form</field>
|
||||
<field name="inherit_id" ref="stock_location.stock_location_route_form_view"/>
|
||||
<field name="inherit_id" ref="stock.stock_location_route_form_view"/>
|
||||
<field name="model">stock.location.route</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='pull_ids']" position="after">
|
||||
<field name="sale"/>
|
||||
<xpath expr="//field[@name='warehouse_selectable']" position="after">
|
||||
<field name="sale_selectable"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record id="stock_location_route_tree_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.location.route.tree.inherit</field>
|
||||
<field name="inherit_id" ref="stock_location.stock_location_route_tree"/>
|
||||
<field name="model">stock.location.route</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='warehouse_selectable']" position="after">
|
||||
<field name="sale_selectable"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
+30
-13
@@ -40,14 +40,29 @@ class procurement_rule(osv.osv):
|
||||
result = super(procurement_rule, self)._get_action(cr, uid, context=context)
|
||||
return result + [('move', 'Move From Another Location')]
|
||||
|
||||
def _get_rules(self, cr, uid, ids, context=None):
|
||||
res = []
|
||||
for route in self.browse(cr, uid, ids):
|
||||
res += [x.id for x in route.pull_ids]
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'location_id': fields.many2one('stock.location', 'Destination Location'),
|
||||
'location_src_id': fields.many2one('stock.location', 'Source Location',
|
||||
help="Source location is action=move"),
|
||||
'route_id': fields.many2one('stock.location.route', 'Route',
|
||||
help="If route_id is False, the rule is global"),
|
||||
'procure_method': fields.selection([('make_to_stock','Make to Stock'),('make_to_order','Make to Order')], 'Procure Method', required=True, help="'Make to Stock': When needed, take from the stock or wait until re-supplying. 'Make to Order': When needed, purchase or produce for the procurement request."),
|
||||
'route_sequence': fields.related('route_id', 'sequence', string='Route Sequence', store={'stock.location.route': (_get_rules, ['sequence'], 10)}),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'picking_type_id': fields.many2one('stock.picking.type', 'Picking Type',
|
||||
help="Picking Type determines the way the picking should be shown in the view, reports, ...")
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'procure_method': 'make_to_stock',
|
||||
}
|
||||
|
||||
class procurement_order(osv.osv):
|
||||
_inherit = "procurement.order"
|
||||
_columns = {
|
||||
@@ -57,13 +72,18 @@ class procurement_order(osv.osv):
|
||||
}
|
||||
|
||||
def _search_suitable_rule(self, cr, uid, procurement, domain, context=None):
|
||||
'''method overwritten in stock_location that is used to search the best suitable rule'''
|
||||
return self.pool.get('procurement.rule').search(cr, uid, domain, context=context)
|
||||
'''we try to first find a rule among the ones defined on the procurement order group and if none is found, we try on the routes defined for the product, and finally we fallback on the default behavior'''
|
||||
route_ids = [x.id for x in procurement.product_id.route_ids]
|
||||
res = self.pool.get('procurement.rule').search(cr, uid, domain + [('route_id', 'in', route_ids)], order = 'route_sequence, sequence', context=context)
|
||||
if not res:
|
||||
res = self.pool.get('procurement.rule').search(cr, uid, domain + [('route_id', '=', False)], order='sequence', context=context)
|
||||
return res
|
||||
|
||||
|
||||
def _find_suitable_rule(self, cr, uid, procurement, context=None):
|
||||
rule_id = super(procurement_order, self)._find_suitable_rule(cr, uid, procurement, context=context)
|
||||
if not rule_id:
|
||||
rule_id = self._search_suitable_rule(cr, uid, procurement, [('location_id', '=', procurement.location_id.id)], context=context) #action=move
|
||||
rule_id = self._search_suitable_rule(cr, uid, procurement, [('location_id', 'child_of', procurement.location_id.id)], context=context) #action=move
|
||||
rule_id = rule_id and rule_id[0] or False
|
||||
return rule_id
|
||||
|
||||
@@ -88,6 +108,7 @@ class procurement_order(osv.osv):
|
||||
'move_dest_id': procurement.move_dest_id and procurement.move_dest_id.id or False,
|
||||
'procurement_id': procurement.id,
|
||||
'rule_id': procurement.rule_id.id,
|
||||
'procure_method': procurement.rule_id.procure_method,
|
||||
'origin': procurement.origin,
|
||||
'picking_type_id': procurement.rule_id.picking_type_id.id,
|
||||
}
|
||||
@@ -173,7 +194,7 @@ class procurement_order(osv.osv):
|
||||
'product_uom': product.uom_id.id,
|
||||
'location_id': location_id,
|
||||
'company_id': warehouse.company_id.id,
|
||||
'procure_method': 'make_to_order',}
|
||||
}
|
||||
|
||||
def create_automatic_op(self, cr, uid, context=None):
|
||||
"""
|
||||
@@ -203,17 +224,14 @@ class procurement_order(osv.osv):
|
||||
continue
|
||||
|
||||
product = product_obj.browse(cr, uid, [product_read['id']], context=context)[0]
|
||||
if product.supply_method == 'buy':
|
||||
location_id = warehouse.lot_input_id.id
|
||||
elif product.supply_method == 'produce':
|
||||
location_id = warehouse.lot_stock_id.id
|
||||
else:
|
||||
continue
|
||||
|
||||
location_id = warehouse.lot_stock_id.id
|
||||
|
||||
proc_id = proc_obj.create(cr, uid,
|
||||
self._prepare_automatic_op_procurement(cr, uid, product, warehouse, location_id, context=context),
|
||||
context=context)
|
||||
self.signal_button_confirm(cr, uid, [proc_id])
|
||||
self.signal_button_check(cr, uid, [proc_id])
|
||||
self.assign(cr, uid, [proc_id])
|
||||
self.run(cr, uid, [proc_id])
|
||||
return True
|
||||
|
||||
def _get_orderpoint_date_planned(self, cr, uid, orderpoint, start_date, context=None):
|
||||
@@ -229,7 +247,6 @@ class procurement_order(osv.osv):
|
||||
'company_id': orderpoint.company_id.id,
|
||||
'product_uom': orderpoint.product_uom.id,
|
||||
'location_id': orderpoint.location_id.id,
|
||||
'procure_method': 'make_to_order',
|
||||
'origin': orderpoint.name}
|
||||
|
||||
def _product_virtual_get(self, cr, uid, order_point):
|
||||
|
||||
@@ -1,29 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="product.product_product_1" model="product.product">
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_2" model="product.product">
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_3" model="product.product">
|
||||
<field name="type">product</field>
|
||||
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_4" model="product.product">
|
||||
<field name="type">product</field>
|
||||
<field name="supply_method">produce</field>
|
||||
|
||||
</record>
|
||||
<record id="product.product_product_5" model="product.product">
|
||||
<field name="type">product</field>
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_6" model="product.product">
|
||||
@@ -68,7 +56,6 @@
|
||||
|
||||
<record id="product.product_product_16" model="product.product">
|
||||
<field name="type">product</field>
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_17" model="product.product">
|
||||
@@ -77,12 +64,10 @@
|
||||
|
||||
<record id="product.product_product_18" model="product.product">
|
||||
<field name="type">product</field>
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_19" model="product.product">
|
||||
<field name="type">product</field>
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_20" model="product.product">
|
||||
@@ -115,7 +100,6 @@
|
||||
|
||||
<record id="product.product_product_27" model="product.product">
|
||||
<field name="type">product</field>
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_28" model="product.product">
|
||||
@@ -166,9 +150,6 @@
|
||||
<field name="type">product</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_44" model="product.product">
|
||||
<field name="supply_method">produce</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_45" model="product.product">
|
||||
<field name="type">product</field>
|
||||
|
||||
@@ -211,6 +211,8 @@ class product_product(osv.osv):
|
||||
'location_id': fields.dummy(string='Location', relation='stock.location', type='many2one'),
|
||||
'warehouse_id': fields.dummy(string='Warehouse', relation='stock.warehouse', type='many2one'),
|
||||
'orderpoint_ids': fields.one2many('stock.warehouse.orderpoint', 'product_id', 'Minimum Stock Rules'),
|
||||
'route_ids': fields.many2many('stock.location.route', 'stock_location_route_product', 'product_id', 'route_id', 'Routes',
|
||||
help="Depending on the modules installed, this will allow you to define the route of the product: whether it will be bought, manufactured, MTO/MTS,..."),
|
||||
}
|
||||
|
||||
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
||||
|
||||
+67
-30
@@ -33,6 +33,8 @@ import openerp.addons.decimal_precision as dp
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Incoterms
|
||||
#----------------------------------------------------------
|
||||
@@ -123,6 +125,28 @@ class stock_location(osv.osv):
|
||||
def get_removal_strategy(self, cr, uid, location, product, context=None):
|
||||
return None
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Routes
|
||||
#----------------------------------------------------------
|
||||
|
||||
class stock_location_route(osv.osv):
|
||||
_name = 'stock.location.route'
|
||||
_description = "Inventory Routes"
|
||||
_order = 'sequence'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Route Name', required=True),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'pull_ids': fields.one2many('procurement.rule', 'route_id', 'Pull Rules'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'sequence': lambda self,cr,uid,ctx: 0,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Quants
|
||||
#----------------------------------------------------------
|
||||
@@ -167,6 +191,7 @@ class stock_quant(osv.osv):
|
||||
|
||||
# Used for negative quants to reconcile after compensated by a new positive one
|
||||
'propagated_from_id': fields.many2one('stock.quant', 'Linked Quant', help='The negative quant this is coming from'),
|
||||
'negative_dest_location_id': fields.many2one('stock.location', 'Destination Location', help='Technical field used to record the destination location of a move that created a negative quant'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -231,7 +256,6 @@ class stock_quant(osv.osv):
|
||||
result += self._quants_get_lifo(cr, uid, location, product, qty, domain, prefered_order=prefered_order, context=context)
|
||||
else:
|
||||
raise osv.except_osv(_('Error!'), _('Removal strategy %s not implemented.' % (removal_strategy,)))
|
||||
print 'Quant get result', result
|
||||
return result
|
||||
|
||||
#
|
||||
@@ -261,6 +285,7 @@ class stock_quant(osv.osv):
|
||||
negative_vals['location_id'] = move.location_id.id
|
||||
negative_vals['qty'] = -qty
|
||||
negative_vals['cost'] = price_unit
|
||||
negative_vals['negative_dest_location_id'] = move.location_dest_id.id
|
||||
negative_quant_id = self.create(cr, uid, negative_vals, context=context)
|
||||
vals.update({'propagated_from_id': negative_quant_id})
|
||||
|
||||
@@ -284,6 +309,20 @@ class stock_quant(osv.osv):
|
||||
move = m
|
||||
return move
|
||||
|
||||
def _reconcile_single_negative_quant(self, cr, uid, to_solve_quant, quant, quant_neg, qty, context=None):
|
||||
move = self._get_latest_move(cr, uid, to_solve_quant, context=context)
|
||||
self._quant_split(cr, uid, quant, qty, context=context)
|
||||
remaining_to_solve_quant = self._quant_split(cr, uid, to_solve_quant, qty, context=context)
|
||||
remaining_neg_quant = self._quant_split(cr, uid, quant_neg, -qty, context=context)
|
||||
#if the reconciliation was not complete, we need to link together the remaining parts
|
||||
if remaining_to_solve_quant and remaining_neg_quant:
|
||||
self.write(cr, uid, remaining_to_solve_quant.id, {'propagated_from_id': remaining_neg_quant.id}, context=context)
|
||||
#delete the reconciled quants, as it is replaced by the solving quant
|
||||
self.unlink(cr, SUPERUSER_ID, [quant_neg.id, to_solve_quant.id], context=context)
|
||||
#call move_single_quant to ensure recursivity if necessary and do the stock valuation
|
||||
self.move_single_quant(cr, uid, quant, qty, move, context=context)
|
||||
return remaining_to_solve_quant
|
||||
|
||||
def _quant_reconcile_negative(self, cr, uid, quant, context=None):
|
||||
"""
|
||||
When new quant arrive in a location, try to reconcile it with
|
||||
@@ -293,27 +332,14 @@ class stock_quant(osv.osv):
|
||||
if quant.location_id.usage != 'internal':
|
||||
return False
|
||||
quants = self.quants_get(cr, uid, quant.location_id, quant.product_id, quant.qty, [('qty', '<', '0')], context=context)
|
||||
result = False
|
||||
for quant_neg, qty in quants:
|
||||
if not quant_neg:
|
||||
continue
|
||||
result = True
|
||||
to_solve_quant = self.search(cr, uid, [('propagated_from_id', '=', quant_neg.id), ('id', '!=', quant.id)], context=context)
|
||||
if not to_solve_quant:
|
||||
continue
|
||||
to_solve_quant = self.browse(cr, uid, to_solve_quant[0], context=context)
|
||||
move = self._get_latest_move(cr, uid, to_solve_quant, context=context)
|
||||
self._quant_split(cr, uid, quant, qty, context=context)
|
||||
remaining_to_solve_quant = self._quant_split(cr, uid, to_solve_quant, qty, context=context)
|
||||
remaining_neg_quant = self._quant_split(cr, uid, quant_neg, -qty, context=context)
|
||||
#if the reconciliation was not complete, we need to link together the remaining parts
|
||||
if remaining_to_solve_quant and remaining_neg_quant:
|
||||
self.write(cr, uid, remaining_to_solve_quant.id, {'propagated_from_id': remaining_neg_quant.id}, context=context)
|
||||
#delete the reconciled quants, as it is replaced by the solving quant
|
||||
self.unlink(cr, SUPERUSER_ID, [quant_neg.id, to_solve_quant.id], context=context)
|
||||
#call move_single_quant to ensure recursivity if necessary and do the stock valuation
|
||||
self.move_single_quant(cr, uid, quant, qty, move, context=context)
|
||||
return result
|
||||
self._reconcile_single_negative_quant(cr, uid, to_solve_quant, quant, quant_neg, qty, context=context)
|
||||
|
||||
def _price_update(self, cr, uid, quant, newprice, context=None):
|
||||
self.write(cr, uid, [quant.id], {'cost': newprice}, context=context)
|
||||
@@ -345,6 +371,8 @@ class stock_quant(osv.osv):
|
||||
domain += [('product_id','=',product.id)] + domain
|
||||
res = []
|
||||
offset = 0
|
||||
#id is added at the end of the order to make sure the order is always the same for quants created at the same second
|
||||
orderby += ', id'
|
||||
while quantity > 0:
|
||||
quants = self.search(cr, uid, domain, order=orderby, limit=10, offset=offset, context=context)
|
||||
if not quants:
|
||||
@@ -1441,7 +1469,7 @@ class stock_move(osv.osv):
|
||||
done.append(move.id)
|
||||
continue
|
||||
else:
|
||||
qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id)
|
||||
qty = move.product_qty
|
||||
dp = []
|
||||
for m2 in move.move_orig_ids:
|
||||
for q in m2.quant_ids:
|
||||
@@ -1509,7 +1537,7 @@ class stock_move(osv.osv):
|
||||
# quants = quant_obj.quants_get(cr, uid, move.location_id, move.product_id, qty, context=context)
|
||||
# quant_obj.quants_move(cr, uid, quants, move, location_dest_id, context=context)
|
||||
# should replace the above 2 lines
|
||||
domain = ['|', ('reservation_id', '=', False), ('reservation_id', '=', move.id)]
|
||||
domain = ['|', ('reservation_id', '=', False), ('reservation_id', '=', move.id), ('qty', '>', 0)]
|
||||
prefered_order = 'reservation_id'
|
||||
# if lot_id:
|
||||
# prefered_order = 'lot_id<>' + lot_id + ", " + prefered_order
|
||||
@@ -1956,7 +1984,10 @@ class stock_package(osv.osv):
|
||||
"""
|
||||
_name = "stock.quant.package"
|
||||
_description = "Physical Packages"
|
||||
_order = 'name'
|
||||
_parent_name = "parent_id"
|
||||
_parent_store = True
|
||||
_parent_order = 'name'
|
||||
_order = 'parent_left'
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
res = self._complete_name(cr, uid, ids, 'complete_name', None, context=context)
|
||||
@@ -1991,16 +2022,20 @@ class stock_package(osv.osv):
|
||||
res.add(pack.parent_id.id)
|
||||
return list(res)
|
||||
|
||||
# TODO: Problem when package is empty!
|
||||
#
|
||||
def _get_package_info(self, cr, uid, ids, name, args, context=None):
|
||||
default_company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
|
||||
res = {}.fromkeys(ids, {'location_id': False, 'company_id': default_company_id})
|
||||
for pack in self.browse(cr, uid, ids, context=context):
|
||||
if pack.quant_ids:
|
||||
res[pack.id]['location_id'] = pack.quant_ids[0].location_id.id
|
||||
res[pack.id]['owner_id'] = pack.quant_ids[0].owner_id and pack.quant_ids[0].owner_id.id or False
|
||||
res[pack.id]['company_id'] = pack.quant_ids[0].company_id.id
|
||||
elif pack.children_ids:
|
||||
res[pack.id]['location_id'] = pack.children_ids[0].location_id.id
|
||||
res[pack.id]['company_id'] = pack.children_ids[0].company_id.id
|
||||
res[pack.id]['location_id'] = pack.children_ids[0].location_id and pack.children_ids[0].location_id.id or False
|
||||
res[pack.id]['owner_id'] = pack.children_ids[0].owner_id and pack.children_ids[0].owner_id.id or False
|
||||
res[pack.id]['company_id'] = pack.children_ids[0].company_id and pack.children_ids[0].company_id.id or False
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
@@ -2012,12 +2047,21 @@ class stock_package(osv.osv):
|
||||
'location_id': fields.function(_get_package_info, type='many2one', relation='stock.location', string='Location', multi="package",
|
||||
store={
|
||||
'stock.quant': (_get_packages, ['location_id'], 10),
|
||||
'stock.quant.package': (_get_packages_to_relocate, ['children_ids', 'quant_ids', 'parent_id'], 10),
|
||||
'stock.quant.package': (_get_packages_to_relocate, ['quant_ids', 'children_ids', 'parent_id'], 10),
|
||||
}, readonly=True),
|
||||
'quant_ids': fields.one2many('stock.quant', 'package_id', 'Bulk Content'),
|
||||
'parent_id': fields.many2one('stock.quant.package', 'Parent Package', help="The package containing this item"),
|
||||
'children_ids': fields.one2many('stock.quant.package', 'parent_id', 'Contained Packages'),
|
||||
'company_id': fields.function(_get_package_info, type="many2one", relation='res.company', string='Company', multi="package"),
|
||||
'company_id': fields.function(_get_package_info, type="many2one", relation='res.company', string='Company', multi="package",
|
||||
store={
|
||||
'stock.quant': (_get_packages, ['company_id'], 10),
|
||||
'stock.quant.package': (_get_packages_to_relocate, ['quant_ids', 'children_ids', 'parent_id'], 10),
|
||||
}, readonly=True),
|
||||
'owner_id': fields.function(_get_package_info, type='many2one', relation='res.partner', string='Owner', multi="package",
|
||||
store={
|
||||
'stock.quant': (_get_packages, ['owner_id'], 10),
|
||||
'stock.quant.package': (_get_packages_to_relocate, ['quant_ids', 'children_ids', 'parent_id'], 10),
|
||||
}, readonly=True),
|
||||
}
|
||||
_defaults = {
|
||||
'name': lambda self, cr, uid, context: self.pool.get('ir.sequence').get(cr, uid, 'stock.quant.package') or _('Unknown Pack')
|
||||
@@ -2277,14 +2321,7 @@ class stock_warehouse_orderpoint(osv.osv):
|
||||
})
|
||||
return super(stock_warehouse_orderpoint, self).copy(cr, uid, id, default, context=context)
|
||||
|
||||
class product_template(osv.osv):
|
||||
_inherit = "product.template"
|
||||
_columns = {
|
||||
'supply_method': fields.selection([('produce', 'Manufacture'), ('buy', 'Buy'), ('wait', 'None')], 'Supply Method', required=True, help="Manufacture: When procuring the product, a manufacturing order or a task will be generated, depending on the product type. \nBuy: When procuring the product, a purchase order will be generated."),
|
||||
}
|
||||
_defaults = {
|
||||
'supply_method': 'buy',
|
||||
}
|
||||
|
||||
|
||||
class stock_picking_type(osv.osv):
|
||||
_name = "stock.picking.type"
|
||||
|
||||
@@ -120,6 +120,8 @@
|
||||
<record id="picking_type_internal" model="stock.picking.type">
|
||||
<field name="name">Internal Transfers</field>
|
||||
<field name="sequence_id" ref="seq_picking_type_internal"/>
|
||||
<field name="default_location_src_id" ref="stock_location_stock"/>
|
||||
<field name="default_location_dest_id" ref="stock_location_stock"/>
|
||||
<field name="code_id">internal</field>
|
||||
</record>
|
||||
|
||||
@@ -156,15 +158,30 @@ watch your stock valuation, and track production lots upstream and downstream (b
|
||||
-->
|
||||
|
||||
<record id="procurement_rule_customer0" model="procurement.rule">
|
||||
<field name="name">Stock > Customer</field>
|
||||
<field name="name">Stock → Customer</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_src_id" ref="stock_location_stock"/>
|
||||
<field name="location_id" ref="stock_location_customers"/>
|
||||
<field name="picking_type_id" ref="picking_type_out"/>
|
||||
<field name="procure_method">make_to_stock</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="route_warehouse0_mto" model='stock.location.route'>
|
||||
<field name="name">MTO</field>
|
||||
<field name="sequence">10</field>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_customer_mto" model="procurement.rule">
|
||||
<field name="name">Stock → Customer</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="stock_location_customers"/>
|
||||
<field name="location_src_id" ref="stock_location_stock"/>
|
||||
<field name="picking_type_id" ref="picking_type_out"/>
|
||||
<field name="procure_method">make_to_order</field>
|
||||
<field name="route_id" ref="route_warehouse0_mto"/>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
Properties
|
||||
-->
|
||||
@@ -226,5 +243,20 @@ watch your stock valuation, and track production lots upstream and downstream (b
|
||||
<field name="number_next">1</field>
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Add Warehouse to picking_type
|
||||
-->
|
||||
<record id="picking_type_in" model="stock.picking.type">
|
||||
<field name="warehouse_id" ref="warehouse0"/>
|
||||
</record>
|
||||
|
||||
<record id="picking_type_out" model="stock.picking.type">
|
||||
<field name="warehouse_id" ref="warehouse0"/>
|
||||
</record>
|
||||
|
||||
<record id="picking_type_internal" model="stock.picking.type">
|
||||
<field name="warehouse_id" ref="warehouse0"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -604,7 +604,7 @@
|
||||
<field name="lot_id" groups="stock.group_production_lot"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="owner_id" groups="stock.group_tracking_owner"/>
|
||||
<field name="product_qty"/>
|
||||
<field name="product_qty" attrs="{'required': [('product_id', '!=', False)]}"/>
|
||||
<field name="result_package_id" groups="stock.group_tracking_lot"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -1475,10 +1475,14 @@
|
||||
<group>
|
||||
<field name="location_src_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="route_id"/>
|
||||
<field name="route_sequence"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="action"/>
|
||||
<field name="picking_type_id" attrs="{'required': [('action', '!=', 'manufacture')]}"/>
|
||||
<field name="procure_method" attrs="{'invisible': [('action', '!=', 'move')]}"/>
|
||||
<field name="group_id"/>
|
||||
</group>
|
||||
</group>
|
||||
@@ -1592,7 +1596,7 @@
|
||||
<field name="inherit_id" ref="product.product_template_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='type']" position="after">
|
||||
<field name="supply_method"/>
|
||||
<field name="route_ids" widget="many2many_tags"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
@@ -1625,8 +1629,8 @@
|
||||
<button string="Orderpoints" name="%(product_open_orderpoint)d" type="action" attrs="{'invisible':[('type', '=', 'service')]}"/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='standard_price']" position="before">
|
||||
<field name="supply_method" groups="base.group_user"/>
|
||||
<xpath expr="//field[@name='type']" position="after">
|
||||
<field name="route_ids" widget="many2many_tags"/>
|
||||
</xpath>
|
||||
|
||||
<group name="procurement_uom" position="before">
|
||||
@@ -1715,6 +1719,7 @@
|
||||
<group>
|
||||
<field name="packaging_id"/>
|
||||
<field name='company_id' groups="base.group_multi_company"/>
|
||||
<field name='owner_id' groups="stock.group_tracking_owner"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="location_id"/>
|
||||
@@ -1790,5 +1795,31 @@
|
||||
<field name="res_model">stock.quant.package</field>
|
||||
</record>
|
||||
<menuitem id="menu_package" name="Packages" parent="menu_stock_product" action="action_package_view"/>
|
||||
|
||||
|
||||
<!--Routes-->
|
||||
<record id="stock_location_route_form_view" model="ir.ui.view">
|
||||
<field name="name">stock.location.route.form</field>
|
||||
<field name="model">stock.location.route</field>
|
||||
<field eval="7" name="priority" />
|
||||
<field name="arch" type="xml">
|
||||
<form string="Route" version="7.0">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<label string="Route name"/>
|
||||
</h1>
|
||||
<h2>
|
||||
<field name="name" class="oe_inline"/>
|
||||
</h2>
|
||||
</div>
|
||||
<field name="sequence" groups="base.group_no_one"/>
|
||||
<group string="Pull Rules" colspan="4" >
|
||||
<field name="pull_ids" colspan="4" nolabel="1"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -20,21 +20,20 @@
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Procurement Rule
|
||||
#----------------------------------------------------------
|
||||
class procurement_rule(osv.osv):
|
||||
_inherit = 'procurement.rule'
|
||||
_columns= {
|
||||
_columns = {
|
||||
'invoice_state': fields.selection([
|
||||
("invoiced", "Invoiced"),
|
||||
("2binvoiced", "To Be Invoiced"),
|
||||
("none", "Not Applicable")], "Invoice Status",
|
||||
required=False),
|
||||
}
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Procurement Order
|
||||
#----------------------------------------------------------
|
||||
@@ -43,18 +42,17 @@ class procurement_rule(osv.osv):
|
||||
class procurement_order(osv.osv):
|
||||
_inherit = "procurement.order"
|
||||
_columns = {
|
||||
'invoice_state': fields.selection(
|
||||
[("invoiced", "Invoiced"),
|
||||
'invoice_state': fields.selection([("invoiced", "Invoiced"),
|
||||
("2binvoiced", "To Be Invoiced"),
|
||||
("none", "Not Applicable")
|
||||
], "Invoice Control", required=True),
|
||||
], "Invoice Control", required=True),
|
||||
}
|
||||
|
||||
def _run_move_create(self, cr, uid, procurement, context=None):
|
||||
res = super(procurement_order, self)._run_move_create(cr, uid, procurement, context=context)
|
||||
res.update({'invoice_state': (procurement.rule_id.invoice_state in ('none', False) and procurement.invoice_state or procurement.rule_id.invoice_state) or 'none'})
|
||||
return res
|
||||
|
||||
|
||||
_defaults = {
|
||||
'invoice_state': 'none'
|
||||
}
|
||||
@@ -70,15 +68,51 @@ class stock_move(osv.osv):
|
||||
'invoice_state': fields.selection([("invoiced", "Invoiced"),
|
||||
("2binvoiced", "To Be Invoiced"),
|
||||
("none", "Not Applicable")], "Invoice Control",
|
||||
select=True, required=True, track_visibility='onchange',
|
||||
select=True, required=True, track_visibility='onchange',
|
||||
states={'draft': [('readonly', False)]}),
|
||||
}
|
||||
_defaults= {
|
||||
_defaults = {
|
||||
'invoice_state': lambda *args, **argv: 'none'
|
||||
}
|
||||
|
||||
def _get_master_data(self, cr, uid, move, company, context=None):
|
||||
''' returns a tupple (browse_record(res.partner), ID(res.users), ID(res.currency)'''
|
||||
return move.picking_id.partner_id, uid, company.currency_id.id
|
||||
|
||||
def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):
|
||||
return self.pool.get('account.invoice.line').create(cr, uid, invoice_line_vals, context=context)
|
||||
|
||||
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
|
||||
fp_obj = self.pool.get('account.fiscal.position')
|
||||
# Get account_id
|
||||
if inv_type in ('out_invoice', 'out_refund'):
|
||||
account_id = move.product_id.property_account_income.id
|
||||
if not account_id:
|
||||
account_id = move.product_id.categ_id.property_account_income_categ.id
|
||||
else:
|
||||
account_id = move.product_id.property_account_expense.id
|
||||
if not account_id:
|
||||
account_id = move.product_id.categ_id.property_account_expense_categ.id
|
||||
fiscal_position = partner.property_account_position
|
||||
account_id = fp_obj.map_account(cr, uid, fiscal_position, account_id)
|
||||
|
||||
# set UoS if it's a sale and the picking doesn't have one
|
||||
uos_id = move.product_uom.id
|
||||
quantity = move.product_uom_qty
|
||||
if move.product_uos:
|
||||
uos_id = move.product_uos.id
|
||||
quantity = move.product_uos_qty
|
||||
return {
|
||||
'name': move.name,
|
||||
'account_id': account_id,
|
||||
'product_id': move.product_id.id,
|
||||
'uos_id': uos_id,
|
||||
'quantity': quantity,
|
||||
'price_unit': move.product_id.list_price, # TODO: use price_get
|
||||
'discount': 0.0,
|
||||
'account_analytic_id': False,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Picking
|
||||
#----------------------------------------------------------
|
||||
@@ -90,9 +124,9 @@ class stock_picking(osv.osv):
|
||||
for pick in self.browse(cr, uid, ids, context=context):
|
||||
result[pick.id] = 'none'
|
||||
for move in pick.move_lines:
|
||||
if move.invoice_state=='invoiced':
|
||||
if move.invoice_state == 'invoiced':
|
||||
result[pick.id] = 'invoiced'
|
||||
elif move.invoice_state=='2binvoiced':
|
||||
elif move.invoice_state == '2binvoiced':
|
||||
result[pick.id] = '2binvoiced'
|
||||
break
|
||||
return result
|
||||
@@ -100,7 +134,7 @@ class stock_picking(osv.osv):
|
||||
def __get_picking_move(self, cr, uid, ids, context={}):
|
||||
res = []
|
||||
for move in self.pool.get('stock.move').browse(cr, uid, ids, context=context):
|
||||
if move.picking_id:
|
||||
if move.picking_id:
|
||||
res.append(move.picking_id.id)
|
||||
return res
|
||||
|
||||
@@ -109,11 +143,11 @@ class stock_picking(osv.osv):
|
||||
("invoiced", "Invoiced"),
|
||||
("2binvoiced", "To Be Invoiced"),
|
||||
("none", "Not Applicable")
|
||||
], string="Invoice Control", required=True,
|
||||
], string="Invoice Control", required=True,
|
||||
|
||||
store={
|
||||
'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['state'], 10),
|
||||
'stock.move': (__get_picking_move, ['picking_id'], 10),
|
||||
'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['state'], 10),
|
||||
'stock.move': (__get_picking_move, ['picking_id', 'invoice_state'], 10),
|
||||
},
|
||||
),
|
||||
}
|
||||
@@ -121,6 +155,12 @@ class stock_picking(osv.osv):
|
||||
'invoice_state': lambda *args, **argv: 'none'
|
||||
}
|
||||
|
||||
def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None):
|
||||
''' This function simply creates the invoice from the given values. It is overriden in delivery module to add the delivery costs.
|
||||
'''
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
return invoice_obj.create(cr, uid, vals, context=context)
|
||||
|
||||
def action_invoice_create(self, cr, uid, ids, journal_id=False, group=False, type='out_invoice', context=None):
|
||||
""" Creates invoice based on the invoice state selected for picking.
|
||||
@param journal_id: Id of journal
|
||||
@@ -133,8 +173,8 @@ class stock_picking(osv.osv):
|
||||
for picking in self.browse(cr, uid, ids, context=context):
|
||||
key = group and picking.id or True
|
||||
for move in picking.move_lines:
|
||||
if move.procurement_id and (move.procurement_id.invoice_state=='2binvoiced'):
|
||||
if (move.state <> 'cancel') and not move.scrapped:
|
||||
if move.procurement_id and (move.procurement_id.invoice_state == '2binvoiced') or move.invoice_state == '2binvoiced':
|
||||
if (move.state != 'cancel') and not move.scrapped:
|
||||
todo.setdefault(key, [])
|
||||
todo[key].append(move)
|
||||
invoices = []
|
||||
@@ -144,14 +184,13 @@ class stock_picking(osv.osv):
|
||||
|
||||
def __invoice_create_line(self, cr, uid, moves, journal_id=False, inv_type='out_invoice', context=None):
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
move_obj = self.pool.get('stock.move')
|
||||
invoices = {}
|
||||
for move in moves:
|
||||
sale_line = move.procurement_id.sale_line_id
|
||||
sale = sale_line.order_id
|
||||
partner = sale.partner_invoice_id
|
||||
|
||||
currency_id = sale.pricelist_id.currency_id.id
|
||||
key = (partner.id, currency_id, sale.company_id.id, sale.user_id and sale.user_id.id or False)
|
||||
company = move.company_id
|
||||
origin = move.picking_id.name
|
||||
partner, user_id, currency_id = move_obj._get_master_data(cr, uid, move, company, context=context)
|
||||
key = (partner.id, currency_id, company.id, user_id)
|
||||
|
||||
if key not in invoices:
|
||||
# Get account and payment terms
|
||||
@@ -162,66 +201,33 @@ class stock_picking(osv.osv):
|
||||
account_id = partner.property_account_payable.id
|
||||
payment_term = partner.property_supplier_payment_term.id or False
|
||||
|
||||
invoice_id = invoice_obj.create(cr, uid, {
|
||||
'origin': sale.name,
|
||||
invoice_vals = {
|
||||
'origin': origin,
|
||||
'date_invoice': context.get('date_inv', False),
|
||||
'user_id': sale.user_id and sale.user_id.id or False,
|
||||
'user_id': user_id,
|
||||
'partner_id': partner.id,
|
||||
'account_id': account_id,
|
||||
'payment_term': payment_term,
|
||||
'type': inv_type,
|
||||
'fiscal_position': partner.property_account_position.id,
|
||||
'company_id': sale.company_id.id,
|
||||
'currency_id': sale.pricelist_id.currency_id.id,
|
||||
'company_id': company.id,
|
||||
'currency_id': currency_id,
|
||||
'journal_id': journal_id,
|
||||
}, context=context)
|
||||
}
|
||||
invoice_id = self._create_invoice_from_picking(cr, uid, move.picking_id, invoice_vals, context=context)
|
||||
invoices[key] = invoice_id
|
||||
|
||||
# Get account_id
|
||||
if inv_type in ('out_invoice', 'out_refund'):
|
||||
account_id = move.product_id.property_account_income.id
|
||||
if not account_id:
|
||||
account_id = move.product_id.categ_id.property_account_income_categ.id
|
||||
else:
|
||||
account_id = move.product_id.property_account_expense.id
|
||||
if not account_id:
|
||||
account_id = move.product_id.categ_id.property_account_expense_categ.id
|
||||
fp_obj = self.pool.get('account.fiscal.position')
|
||||
fiscal_position = partner.property_account_position
|
||||
account_id = fp_obj.map_account(cr, uid, fiscal_position, account_id)
|
||||
invoice_line_vals = move_obj._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
|
||||
invoice_line_vals['invoice_id'] = invoices[key]
|
||||
invoice_line_vals['origin'] = origin
|
||||
|
||||
# set UoS if it's a sale and the picking doesn't have one
|
||||
if move.product_uos:
|
||||
uos_id = move.product_uos.id
|
||||
quantity = move.product_uos_qty
|
||||
else:
|
||||
uos_id = move.product_uom.id
|
||||
quantity = move.product_uom_qty
|
||||
move_obj._create_invoice_line_from_vals(cr, uid, move, invoice_line_vals, context=context)
|
||||
|
||||
invoice_line_id = self.pool.get('account.invoice.line').create(cr, uid, {
|
||||
'name': move.name,
|
||||
'origin': move.picking_id and move.picking_id.origin or False,
|
||||
'invoice_id': invoices[key],
|
||||
'account_id': account_id,
|
||||
'product_id': move.product_id.id,
|
||||
'uos_id': uos_id,
|
||||
'quantity': quantity,
|
||||
'price_unit': sale_line.price_unit,
|
||||
'discount': sale_line.discount,
|
||||
'invoice_line_tax_id': [(6, 0, [x.id for x in sale_line.tax_id])],
|
||||
'account_analytic_id': sale.project_id and sale.project_id.id or False,
|
||||
}, context=context)
|
||||
|
||||
self.pool.get('sale.order.line').write(cr, uid, [sale_line.id], {
|
||||
'invoice_lines': [(4, invoice_line_id)]
|
||||
}, context=context)
|
||||
self.pool.get('sale.order').write(cr, uid, [sale.id], {
|
||||
'invoice_ids': [(4, invoices[key])],
|
||||
})
|
||||
|
||||
self.pool.get('procurement.order').write(cr, uid, [move.procurement_id.id], {
|
||||
'invoice_state': 'invoiced',
|
||||
}, context=context)
|
||||
move_obj.write(cr, uid, move.id, {'invoice_state': 'invoiced'}, context=context)
|
||||
if move.procurement_id:
|
||||
self.pool.get('procurement.order').write(cr, uid, [move.procurement_id.id], {
|
||||
'invoice_state': 'invoiced',
|
||||
}, context=context)
|
||||
|
||||
invoice_obj.button_compute(cr, uid, invoices.values(), context=context, set_total=(inv_type in ('in_invoice', 'in_refund')))
|
||||
return invoices.values()
|
||||
|
||||
@@ -19,23 +19,13 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import time
|
||||
from operator import itemgetter
|
||||
from itertools import groupby
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp import netsvc
|
||||
from openerp import tools
|
||||
from openerp.tools import float_compare, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
import openerp.addons.decimal_precision as dp
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Stock Location
|
||||
#----------------------------------------------------------
|
||||
@@ -44,12 +34,12 @@ class stock_location(osv.osv):
|
||||
_inherit = "stock.location"
|
||||
|
||||
_columns = {
|
||||
'valuation_in_account_id': fields.many2one('account.account', 'Stock Valuation Account (Incoming)', domain = [('type','=','other')],
|
||||
'valuation_in_account_id': fields.many2one('account.account', 'Stock Valuation Account (Incoming)', domain=[('type', '=', 'other')],
|
||||
help="Used for real-time inventory valuation. When set on a virtual location (non internal type), "
|
||||
"this account will be used to hold the value of products being moved from an internal location "
|
||||
"into this location, instead of the generic Stock Output Account set on the product. "
|
||||
"This has no effect for internal locations."),
|
||||
'valuation_out_account_id': fields.many2one('account.account', 'Stock Valuation Account (Outgoing)', domain = [('type','=','other')],
|
||||
'valuation_out_account_id': fields.many2one('account.account', 'Stock Valuation Account (Outgoing)', domain=[('type', '=', 'other')],
|
||||
help="Used for real-time inventory valuation. When set on a virtual location (non internal type), "
|
||||
"this account will be used to hold the value of products being moved out of this location "
|
||||
"and into an internal location, instead of the generic Stock Output Account set on the product. "
|
||||
@@ -63,7 +53,6 @@ class stock_location(osv.osv):
|
||||
class stock_quant(osv.osv):
|
||||
_inherit = "stock.quant"
|
||||
|
||||
|
||||
def _get_inventory_value(self, cr, uid, line, prodbrow, context=None):
|
||||
#TODO: what in case of partner_id
|
||||
if prodbrow[(line.company_id.id, line.product_id.id)].cost_method in ('real'):
|
||||
@@ -170,7 +159,7 @@ class stock_quant(osv.osv):
|
||||
'name': move.name,
|
||||
'product_id': quant.product_id.id,
|
||||
'quantity': quant.qty,
|
||||
'product_uom_id': quant.product_id.uom_id.id,
|
||||
'product_uom_id': quant.product_id.uom_id.id,
|
||||
'ref': move.picking_id and move.picking_id.name or False,
|
||||
'date': time.strftime('%Y-%m-%d'),
|
||||
'partner_id': partner_id,
|
||||
@@ -181,7 +170,7 @@ class stock_quant(osv.osv):
|
||||
'name': move.name,
|
||||
'product_id': quant.product_id.id,
|
||||
'quantity': quant.qty,
|
||||
'product_uom_id': quant.product_id.uom_id.id,
|
||||
'product_uom_id': quant.product_id.uom_id.id,
|
||||
'ref': move.picking_id and move.picking_id.name or False,
|
||||
'date': time.strftime('%Y-%m-%d'),
|
||||
'partner_id': partner_id,
|
||||
@@ -197,17 +186,42 @@ class stock_quant(osv.osv):
|
||||
return move_obj.create(cr, uid, {'journal_id': journal_id,
|
||||
'line_id': move_lines,
|
||||
'ref': move.picking_id and move.picking_id.name}, context=context)
|
||||
|
||||
def _reconcile_single_negative_quant(self, cr, uid, to_solve_quant, quant, quant_neg, qty, context=None):
|
||||
move = self._get_latest_move(cr, uid, to_solve_quant, context=context)
|
||||
quant_neg_position = quant_neg.negative_dest_location_id.usage
|
||||
remaining_to_solve_quant = super(stock_quant, self)._reconcile_single_negative_quant(cr, uid, to_solve_quant, quant, quant_neg, qty, context=context)
|
||||
#update the standard price of the product, only if we would have done it if we'd have had enough stock at first, which means
|
||||
#1) there isn't any negative quant anymore
|
||||
#2) the product cost's method is 'real'
|
||||
#3) we just fixed a negative quant caused by an outgoing shipment
|
||||
if not remaining_to_solve_quant and move.product_id.cost_method == 'real' and quant_neg_position != 'internal':
|
||||
self.pool.get('stock.move')._store_average_cost_price(cr, uid, move, context=context)
|
||||
|
||||
class stock_move(osv.osv):
|
||||
_inherit = "stock.move"
|
||||
|
||||
def action_done(self, cr, uid, ids, context=None):
|
||||
self.product_price_update_before_done(cr, uid, ids, context=context)
|
||||
super(stock_move, self).action_done(cr, uid, ids, context=context)
|
||||
self.product_price_update(cr, uid, ids, context=context)
|
||||
self.product_price_update_after_done(cr, uid, ids, context=context)
|
||||
|
||||
def product_price_update(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
This method adapts the price on the product when necessary
|
||||
'''
|
||||
def _store_average_cost_price(self, cr, uid, move, context=None):
|
||||
''' move is a browe record '''
|
||||
product_obj = self.pool.get('product.product')
|
||||
move.refresh()
|
||||
if any([q.qty <= 0 for q in move.quant_ids]):
|
||||
#if there is a negative quant, the standard price shouldn't be updated
|
||||
return
|
||||
#Note: here we can't store a quant.cost directly as we may have moved out 2 units (1 unit to 5€ and 1 unit to 7€) and in case of a product return of 1 unit, we can't know which of the 2 costs has to be used (5€ or 7€?). So at that time, thanks to the average valuation price we are storing we will svaluate it at 6€
|
||||
average_valuation_price = 0.0
|
||||
for q in move.quant_ids:
|
||||
average_valuation_price += q.qty * q.cost
|
||||
average_valuation_price = average_valuation_price / move.product_qty
|
||||
product_obj.write(cr, uid, move.product_id.id, {'standard_price': average_valuation_price}, context=context)
|
||||
self.write(cr, uid, move.id, {'price_unit': average_valuation_price}, context=context)
|
||||
|
||||
def product_price_update_before_done(self, cr, uid, ids, context=None):
|
||||
product_obj = self.pool.get('product.product')
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
#adapt standard price on incomming moves if the product cost_method is 'average'
|
||||
@@ -221,21 +235,17 @@ class stock_move(osv.osv):
|
||||
else:
|
||||
# Get the standard price
|
||||
amount_unit = product.price_get('standard_price', context=ctx)[product.id]
|
||||
new_std_price = (amount_unit * (product_avail - move.product_qty) + (move.price_unit * move.product_qty)) / product_avail
|
||||
new_std_price = ((amount_unit * product_avail) + (move.price_unit * move.product_qty)) / (product_avail + move.product_qty)
|
||||
# Write the field according to price type field
|
||||
product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}, context=context)
|
||||
|
||||
def product_price_update_after_done(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
This method adapts the price on the product when necessary
|
||||
'''
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
#adapt standard price on outgoing moves if the product cost_method is 'real', so that a return
|
||||
#or an inventory loss is made using the last value used for an outgoing valuation.
|
||||
if move.product_id.cost_method == 'real' and move.location_dest_id.usage != 'internal':
|
||||
if any([q.qty <= 0 for q in move.quant_ids]):
|
||||
#if there is a negative quant, the standard price shouldn't be updated
|
||||
continue
|
||||
#get the average price of the move
|
||||
#Note: here we can't use the quant.cost directly as we may have moved out 2 units (1 unit to 5€ and 1 unit to 7€) and in case of a product return of 1 unit, we can't know which of the 2 cost has to be used (5€ or 7€?). So at that time, thanks to the average valuation price we are storing we will svaluate it at 6€
|
||||
average_valuation_price = 0.0
|
||||
for q in move.quant_ids:
|
||||
average_valuation_price += q.qty * q.cost
|
||||
average_valuation_price = average_valuation_price / move.product_qty
|
||||
product_obj.write(cr, uid, move.product_id.id, {'standard_price': average_valuation_price}, context=context)
|
||||
self.write(cr, uid, move.id, {'price_unit': average_valuation_price}, context=context)
|
||||
#store the average price of the move on the move and product form
|
||||
self._store_average_cost_price(cr, uid, move, context=context)
|
||||
|
||||
@@ -71,7 +71,6 @@ class stock_invoice_onshipping(osv.osv_memory):
|
||||
def open_invoice(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
print 'Create Invoice', context
|
||||
invoice_ids = self.create_invoice(cr, uid, ids, context=context)
|
||||
if not invoice_ids:
|
||||
raise osv.except_osv(_('Error!'), _('No invoice created!'))
|
||||
@@ -97,7 +96,6 @@ class stock_invoice_onshipping(osv.osv_memory):
|
||||
|
||||
def create_invoice(self, cr, uid, ids, context=None):
|
||||
context = context or {}
|
||||
|
||||
picking_pool = self.pool.get('stock.picking')
|
||||
onshipdata_obj = self.read(cr, uid, ids, ['journal_id', 'group', 'invoice_date', 'inv_type'])
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<field name="name">dropship</field>
|
||||
<field name="sequence_id" ref="seq_picking_type_dropship"/>
|
||||
<field name="code_id">incoming</field>
|
||||
<field name="default_location_dest_id" ref="stock.stock_location_suppliers"/>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -22,7 +23,9 @@
|
||||
<record id="route_drop_shipping" model='stock.location.route'>
|
||||
<field name="name">Drop Shipping</field>
|
||||
<field name="sequence">3</field>
|
||||
<field name="sale">True</field>
|
||||
<field name="sale_selectable" eval="True"/>
|
||||
<field name="product_selectable" eval="False"/>
|
||||
<field name="product_categ_selectable" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_drop_shipping" model="procurement.rule">
|
||||
@@ -39,7 +42,9 @@
|
||||
<!-- Crossdock -->
|
||||
<record id="stock_location.route_warehouse0_crossdock" model='stock.location.route'>
|
||||
<field name="name">Crossdock</field>
|
||||
<field name="sale">True</field>
|
||||
<field name="sale_selectable" eval="True"/>
|
||||
<field name="product_categ_selectable" eval="True"/>
|
||||
|
||||
</record>
|
||||
<record id="procurement_rule_customer0_xdock" model="procurement.rule">
|
||||
<field name="name"> Supplier → Output</field>
|
||||
@@ -49,5 +54,7 @@
|
||||
<field name="route_id" ref="stock_location.route_warehouse0_crossdock"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_in"/>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -60,4 +60,4 @@
|
||||
sale_id = self.pool.get('sale.order').browse(cr, uid, ref("sale_order_route_crossdock"))
|
||||
proc_ids = self.search(cr, uid, [('group_id.name', '=', sale_id.name)])
|
||||
purchase_id = [proc.purchase_id for proc in self.browse(cr, uid, proc_ids) if proc.purchase_id]
|
||||
assert purchase_id, 'No Purchase Quotation is created'
|
||||
assert purchase_id, 'No Purchase Quotation is created'
|
||||
@@ -19,4 +19,6 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import wizard
|
||||
import stock_location
|
||||
|
||||
|
||||
@@ -96,10 +96,12 @@ You can use the demo data as follow:
|
||||
'author': 'OpenERP SA',
|
||||
'images': ['images/pulled_flow.jpeg','images/pushed_flow.jpeg'],
|
||||
'depends': ['procurement','stock'],
|
||||
'data': ['stock_location_view.xml',
|
||||
'data': ['wizard/configure_wh_view.xml',
|
||||
'stock_location_view.xml',
|
||||
'stock_location_data.xml',
|
||||
'security/stock_location_security.xml',
|
||||
'security/ir.model.access.csv'],
|
||||
'security/ir.model.access.csv',
|
||||
'res_config_view.xml'],
|
||||
'demo': [
|
||||
'stock_location_demo_cpu1.xml',
|
||||
'stock_location_demo_cpu3.yml',
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_stock_location_config_settings" model="ir.ui.view">
|
||||
<field name="name">stock settings</field>
|
||||
<field name="model">stock.config.settings</field>
|
||||
<field name="inherit_id" ref="stock.view_stock_config_settings"/>
|
||||
<field name="arch" type="xml">
|
||||
<separator string="Location & Warehouse" position="before">
|
||||
<button name="%(action_view_stock_configure_wh)d" string="Configure a new warehouse" type="action"/>
|
||||
</separator>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -25,24 +25,23 @@ from dateutil.relativedelta import relativedelta
|
||||
from openerp.tools.translate import _
|
||||
|
||||
class stock_location_route(osv.osv):
|
||||
_name = 'stock.location.route'
|
||||
_inherit = 'stock.location.route'
|
||||
_description = "Inventory Routes"
|
||||
_order = 'sequence'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Route Name', required=True),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'pull_ids': fields.one2many('procurement.rule', 'route_id', 'Pull Rules'),
|
||||
'push_ids': fields.one2many('stock.location.path', 'route_id', 'Push Rules'),
|
||||
'product_selectable': fields.boolean('Selectable on Product'),
|
||||
'product_categ_selectable': fields.boolean('Selectable on Product Category'),
|
||||
'warehouse_selectable': fields.boolean('Selectable on Warehouse'),
|
||||
}
|
||||
_defaults = {
|
||||
'sequence': lambda self,cr,uid,ctx: 0,
|
||||
'product_selectable': True
|
||||
}
|
||||
|
||||
class stock_warehouse(osv.osv):
|
||||
_inherit = 'stock.warehouse'
|
||||
_columns = {
|
||||
'route_id': fields.many2one('stock.location.route', 'Default Routes', help='Default route through the warehouse', required=True),
|
||||
'route_id': fields.many2one('stock.location.route', 'Default Routes', domain="[('warehouse_selectable', '=', True)]", help='Default route through the warehouse', required=True),
|
||||
}
|
||||
|
||||
|
||||
@@ -112,33 +111,18 @@ class stock_location_path(osv.osv):
|
||||
|
||||
class procurement_rule(osv.osv):
|
||||
_inherit = 'procurement.rule'
|
||||
|
||||
def _get_rules(self, cr, uid, ids, context=None):
|
||||
res = []
|
||||
for route in self.browse(cr, uid, ids):
|
||||
res += [x.id for x in route.pull_ids]
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'route_id': fields.many2one('stock.location.route', 'Route',
|
||||
help="If route_id is False, the rule is global"),
|
||||
'delay': fields.integer('Number of Hours'),
|
||||
'procure_method': fields.selection([('make_to_stock','Make to Stock'),('make_to_order','Make to Order')], 'Procure Method', required=True, help="'Make to Stock': When needed, take from the stock or wait until re-supplying. 'Make to Order': When needed, purchase or produce for the procurement request."),
|
||||
'partner_address_id': fields.many2one('res.partner', 'Partner Address'),
|
||||
|
||||
'route_sequence': fields.related('route_id', 'sequence', string='Route Sequence', store={'stock.location.route': (_get_rules, ['sequence'], 10)}),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'propagate': fields.boolean('Propagate cancel and split', help='If checked, when the previous move of the move (which was generated by a next procurement) is cancelled or split, the move generated by this move will too'),
|
||||
}
|
||||
_defaults = {
|
||||
'procure_method': 'make_to_stock',
|
||||
'propagate': True,
|
||||
'delay': 0,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class procurement_order(osv.osv):
|
||||
_inherit = 'procurement.order'
|
||||
_columns = {
|
||||
@@ -154,7 +138,6 @@ class procurement_order(osv.osv):
|
||||
newdate = (datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.rule_id.delay or 0)).strftime('%Y-%m-%d %H:%M:%S')
|
||||
d.update({
|
||||
'date': newdate,
|
||||
'procure_method': procurement.rule_id.procure_method or 'make_to_stock',
|
||||
'propagate': procurement.rule_id.propagate,
|
||||
})
|
||||
return d
|
||||
@@ -171,7 +154,7 @@ class procurement_order(osv.osv):
|
||||
route_ids = [x.id for x in procurement.route_ids] + [x.id for x in procurement.product_id.route_ids]
|
||||
res = self.pool.get('procurement.rule').search(cr, uid, domain + [('route_id', 'in', route_ids)], order = 'route_sequence, sequence', context=context)
|
||||
if not res:
|
||||
res = self.pool.get('procurement.rule').search(cr, uid, domain, order='sequence', context=context)
|
||||
res = self.pool.get('procurement.rule').search(cr, uid, domain + [('route_id', '=', False)], order='sequence', context=context)
|
||||
return res
|
||||
|
||||
|
||||
@@ -201,13 +184,13 @@ class product_removal_strategy(osv.osv):
|
||||
class product_product(osv.osv):
|
||||
_inherit = 'product.product'
|
||||
_columns = {
|
||||
'route_ids': fields.many2many('stock.location.route', 'stock_location_route_product', 'product_id', 'route_id', 'Routes'),
|
||||
'route_ids': fields.many2many('stock.location.route', 'stock_location_route_product', 'product_id', 'route_id', 'Routes', domain="[('product_selectable', '=', True)]"),
|
||||
}
|
||||
|
||||
class product_category(osv.osv):
|
||||
_inherit = 'product.category'
|
||||
_columns = {
|
||||
'route_ids': fields.many2many('stock.location.route', 'stock_location_route_categ', 'categ_id', 'route_id', 'Routes'),
|
||||
'route_ids': fields.many2many('stock.location.route', 'stock_location_route_categ', 'categ_id', 'route_id', 'Routes', domain="[('product_categ_selectable', '=', True)]"),
|
||||
'removal_strategy_ids': fields.one2many('product.removal', 'product_categ_id', 'Removal Strategies'),
|
||||
#'putaway_strategy_ids': fields.one2many('product.putaway', 'product_categ_id', 'Put Away Strategies'),
|
||||
}
|
||||
|
||||
@@ -24,48 +24,56 @@
|
||||
<record id="route_warehouse0_mts" model='stock.location.route'>
|
||||
<field name="name">Sale: Ship only</field>
|
||||
<field name="sequence">20</field>
|
||||
<field name="warehouse_selectable" eval="True"/>
|
||||
<field name="product_selectable" eval="False"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="procurement_rule_customer0_mts" model="procurement.rule">
|
||||
<field name="name">Stock → output</field>
|
||||
<field name="name">Stock → customer</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="stock.stock_location_output"/>
|
||||
<field name="location_id" ref="stock.stock_location_customers"/>
|
||||
<field name="location_src_id" ref="stock.stock_location_stock"/>
|
||||
<field name="procure_method">make_to_stock</field>
|
||||
<field name="route_id" ref="route_warehouse0_mts"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_internal"/>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_customer1_mts" model="procurement.rule">
|
||||
<field name="name">Output → Customer</field>
|
||||
<!-- Override from stock-->
|
||||
<!--<record id="procurement_rule_customer_mto" model="procurement.rule">
|
||||
<field name="name">Stock → Customer</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="stock.stock_location_customers"/>
|
||||
<field name="location_src_id" ref="stock.stock_location_output"/>
|
||||
<field name="procure_method">make_to_order</field>
|
||||
<field name="route_id" ref="route_warehouse0_mts"/>
|
||||
<field name="location_src_id" ref="stock.stock_location_stock"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_out"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="route_warehouse0_mto" model='stock.location.route'>
|
||||
<field name="name">Produce or buy on Customer Order</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="procure_method">make_to_order</field>
|
||||
<field name="route_id" ref="stock.route_warehouse0_mto"/>
|
||||
<field name="product_categ_selectable" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="route_warehouse0_mto" model='stock.location.route'>
|
||||
<field name="name">MTO</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="product_categ_selectable" eval="True"/>
|
||||
</record>-->
|
||||
|
||||
<record id="procurement_rule_customer0_mto" model="procurement.rule">
|
||||
<field name="name">Stock → output</field>
|
||||
<field name="name">Stock → Customer</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="stock.stock_location_output"/>
|
||||
<field name="location_id" ref="stock.stock_location_customers"/>
|
||||
<field name="location_src_id" ref="stock.stock_location_stock"/>
|
||||
<field name="procure_method">make_to_order</field>
|
||||
<field name="route_id" ref="route_warehouse0_mto"/>
|
||||
<field name="route_id" ref="stock.route_warehouse0_mto"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_internal"/>
|
||||
</record>
|
||||
|
||||
<record id="route_warehouse0_crossdock" model='stock.location.route'>
|
||||
<field name="name">Crossdock</field>
|
||||
<field name="sequence">9</field>
|
||||
<field name="product_categ_selectable" eval="True"/>
|
||||
<field name="sale_selectable" eval="True"/>
|
||||
<field name="warehouse_selectable" eval="True"/>
|
||||
<field name="product_selectable" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_customer0_xdock" model="procurement.rule">
|
||||
@@ -81,13 +89,19 @@
|
||||
<record id="route_warehouse0_pack" model='stock.location.route'>
|
||||
<field name="name">Sale: Pack + Ship</field>
|
||||
<field name="sequence">15</field>
|
||||
<field name="warehouse_selectable" eval="True"/>
|
||||
<field name="product_selectable" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="route_warehouse0_mto_pack" model='stock.location.route'>
|
||||
<field name="name">MTO pack</field>
|
||||
<field name="sequence">10</field>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_customer0_pack" model="procurement.rule">
|
||||
<field name="name">Stock → Pack</field>
|
||||
<field name="name">Stock → Output</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="location_pack_zone"/>
|
||||
<field name="location_id" ref="stock.stock_location_output"/>
|
||||
<field name="location_src_id" ref="stock.stock_location_stock"/>
|
||||
<field name="procure_method">make_to_stock</field>
|
||||
<field name="route_id" ref="route_warehouse0_pack"/>
|
||||
@@ -103,25 +117,15 @@
|
||||
<field name="route_id" ref="route_warehouse0_pack"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_out"/>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_customer2_pack" model="procurement.rule">
|
||||
<field name="name">Pack → Output</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="stock.stock_location_output"/>
|
||||
<field name="location_src_id" ref="location_pack_zone"/>
|
||||
<field name="procure_method">make_to_order</field>
|
||||
<field name="route_id" ref="route_warehouse0_pack"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_internal"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="procurement_rule_customer0_mto_pack" model="procurement.rule">
|
||||
<field name="name">Stock → pack</field>
|
||||
<field name="name">Stock → Output MTO</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="location_pack_zone"/>
|
||||
<field name="location_id" ref="stock.stock_location_output"/>
|
||||
<field name="location_src_id" ref="stock.stock_location_stock"/>
|
||||
<field name="procure_method">make_to_order</field>
|
||||
<field name="route_id" ref="route_warehouse0_mto"/>
|
||||
<field name="route_id" ref="route_warehouse0_mto_pack"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_internal"/>
|
||||
</record>
|
||||
|
||||
@@ -130,30 +134,21 @@
|
||||
<record id="route_warehouse0_pickpack" model='stock.location.route'>
|
||||
<field name="name">Sale: Pick + Pack + Ship</field>
|
||||
<field name="sequence">20</field>
|
||||
<field name="warehouse_selectable" eval="True"/>
|
||||
<field name="product_selectable" eval="False"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="procurement_rule_customer0_pickpack" model="procurement.rule">
|
||||
<field name="name">Stock → Pick</field>
|
||||
<field name="name">Stock → Pack</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="location_pick_zone"/>
|
||||
<field name="location_id" ref="location_pack_zone"/>
|
||||
<field name="location_src_id" ref="stock.stock_location_stock"/>
|
||||
<field name="procure_method">make_to_stock</field>
|
||||
<field name="route_id" ref="route_warehouse0_pickpack"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_internal"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="procurement_rule_customer3_pickpack" model="procurement.rule">
|
||||
<field name="name">Pick → Pack</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="location_pack_zone"/>
|
||||
<field name="location_src_id" ref="location_pick_zone"/>
|
||||
<field name="procure_method">make_to_order</field>
|
||||
<field name="route_id" ref="route_warehouse0_pickpack"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_internal"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="procurement_rule_customer1_pickpack" model="procurement.rule">
|
||||
<field name="name">Output → Customer</field>
|
||||
<field name="action">move</field>
|
||||
@@ -174,14 +169,18 @@
|
||||
<field name="picking_type_id" ref="stock.picking_type_internal"/>
|
||||
</record>
|
||||
|
||||
<record id="route_warehouse0_mto_pick" model='stock.location.route'>
|
||||
<field name="name">MTO pick</field>
|
||||
<field name="sequence">10</field>
|
||||
</record>
|
||||
|
||||
<record id="procurement_rule_customer0_mto_pack" model="procurement.rule">
|
||||
<field name="name">Stock → Pick</field>
|
||||
<record id="procurement_rule_customer0_mto_pick" model="procurement.rule">
|
||||
<field name="name">Stock → Pack MTO</field>
|
||||
<field name="action">move</field>
|
||||
<field name="location_id" ref="location_pick_zone"/>
|
||||
<field name="location_id" ref="location_pack_zone"/>
|
||||
<field name="location_src_id" ref="stock.stock_location_stock"/>
|
||||
<field name="procure_method">make_to_order</field>
|
||||
<field name="route_id" ref="route_warehouse0_mto"/>
|
||||
<field name="route_id" ref="route_warehouse0_mto_pick"/>
|
||||
<field name="picking_type_id" ref="stock.picking_type_internal"/>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
@@ -6,17 +6,12 @@
|
||||
<field name="name">stock.procurement.rule.inherit.form</field>
|
||||
<field name="model">procurement.rule</field>
|
||||
<field name="inherit_id" ref="stock.view_procurement_rule_form"/>
|
||||
|
||||
<field name="arch" type="xml">
|
||||
<field name="location_id" position="after">
|
||||
<field name="route_id"/>
|
||||
<field name="route_sequence"/>
|
||||
<field name="sequence"/>
|
||||
<field name="delay"/>
|
||||
<field name="propagate"/>
|
||||
</field>
|
||||
<field name="group_id" position="before">
|
||||
<field name="procure_method"/>
|
||||
<field name="partner_address_id"/>
|
||||
</field>
|
||||
</field>
|
||||
@@ -166,25 +161,32 @@
|
||||
<tree string="Routes">
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="name"/>
|
||||
<field name="product_selectable"/>
|
||||
<field name="product_categ_selectable"/>
|
||||
<field name="warehouse_selectable"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="stock_location_route_form_view" model="ir.ui.view">
|
||||
<record id="stock_location_route_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.location.route.form</field>
|
||||
<field name="model">stock.location.route</field>
|
||||
<field eval="7" name="priority" />
|
||||
<field name="inherit_id" ref="stock.stock_location_route_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Route">
|
||||
<field name="name" />
|
||||
<field name="sequence" groups="base.group_no_one"/>
|
||||
<group string="Push Rules" colspan="4" >
|
||||
<field name="push_ids" colspan="4" nolabel="1"/>
|
||||
<xpath expr="//field[@name='sequence']" position="after">
|
||||
<group>
|
||||
<group>
|
||||
<field name="product_categ_selectable"/>
|
||||
<field name="product_selectable"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="warehouse_selectable"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Pull Rules" colspan="4" >
|
||||
<field name="pull_ids" colspan="4" nolabel="1"/>
|
||||
</group>
|
||||
</form>
|
||||
<group string="Push Rules" colspan="4" >
|
||||
<field name="push_ids" colspan="4" nolabel="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
name: res_partner_microlinktechnologies0
|
||||
min_qty: 5.0
|
||||
route_ids: [stock_location_route_push]
|
||||
supply_method: buy
|
||||
type: product
|
||||
uom_id: product.product_uom_unit
|
||||
uom_po_id: product.product_uom_unit
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import configure_wh
|
||||
@@ -0,0 +1,204 @@
|
||||
# -*- 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
|
||||
|
||||
class stock_configure_wh(osv.osv_memory):
|
||||
_name = "stock.configure.wh"
|
||||
_description = "Configure New WH"
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Warehouse Name', required=True),
|
||||
'address_id': fields.many2one('res.partner', 'Warehouse Address'),
|
||||
'internal_stock_loc_id': fields.many2one('stock.location', 'Internal Stock Location', required=True),
|
||||
'input_stock_loc_id': fields.many2one('stock.location', 'Input Location', required=True),
|
||||
'output_stock_loc_id': fields.many2one('stock.location', 'Output Location', required=True),
|
||||
'crossdock': fields.boolean('Crossdock', help='Whether this warehouse uses generally crossdock operations or not'),
|
||||
'packing': fields.boolean('Packing', help='Whether we make packing in that warehouse while making outgoing shipments or not'),
|
||||
'packing_loc_id': fields.many2one('stock.location', 'Packing Zone Location')
|
||||
}
|
||||
|
||||
def onchange_crossdock(self, cr, uid, ids, crossdock=False, context=None):
|
||||
if crossdock:
|
||||
return {'value': {'packing': False, 'packing_loc_id': False}}
|
||||
return True
|
||||
|
||||
|
||||
def onchange_packing(self, cr, uid, ids, packing=False, stock_loc=False, context=None):
|
||||
if packing:
|
||||
return {'value': {'packing_loc_id': stock_loc}}
|
||||
return True
|
||||
|
||||
|
||||
def configure_wh(self, cr, uid, ids, context=None):
|
||||
""" To Import stock inventory according to products available in the selected locations.
|
||||
@param self: The object pointer.
|
||||
@param cr: A database cursor
|
||||
@param uid: ID of the user currently logged in
|
||||
@param ids: the ID or list of IDs if we want more than one
|
||||
@param context: A standard dictionary
|
||||
@return:
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
route_obj = self.pool.get('stock.location.route')
|
||||
pull_obj = self.pool.get('procurement.rule')
|
||||
inventory_obj = self.pool.get('stock.inventory')
|
||||
if ids and len(ids):
|
||||
ids = ids[0]
|
||||
obj = self.browse(cr, uid, ids, context=context)
|
||||
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
|
||||
wh_stock_loc = obj.internal_stock_loc_id.id
|
||||
wh_input_stock_loc = obj.input_stock_loc_id.id
|
||||
wh_output_stock_loc = obj.output_stock_loc_id.id
|
||||
|
||||
customer_loc = data_obj.get_object_reference(cr, uid, 'stock', 'stock_location_customers')[1]
|
||||
supplier_loc = data_obj.get_object_reference(cr, uid, 'stock', 'stock_location_suppliers')[1]
|
||||
|
||||
#create route
|
||||
new_route_id = False
|
||||
|
||||
route_data = {
|
||||
'name': obj.name+': Ship',
|
||||
'warehouse_selectable': True,
|
||||
'product_selectable': False,
|
||||
}
|
||||
if obj.crossdock:
|
||||
route_data['name'] = obj.name+': Crossdock'
|
||||
elif wh_stock_loc != wh_output_stock_loc:
|
||||
if obj.packing:
|
||||
route_data['name'] = obj.name+': Pick + Pack + Ship'
|
||||
else:
|
||||
route_data['name'] = obj.name+': Pick + Ship'
|
||||
new_route_id = route_obj.create(cr, uid, vals=route_data, context=context)
|
||||
|
||||
#create wh
|
||||
wh_data = {
|
||||
'name': obj.name,
|
||||
'address_id': obj.address_id and obj.address_id.id or False,
|
||||
'lot_stock_id': wh_stock_loc,
|
||||
'route_id': new_route_id,
|
||||
}
|
||||
wh_obj = self.pool.get('stock.warehouse')
|
||||
new_wh_id = wh_obj.create(cr, uid, vals=wh_data, context=context)
|
||||
|
||||
#create in, out, internal picking types for wh
|
||||
#First create new sequence
|
||||
seq_obj = self.pool.get('ir.sequence')
|
||||
in_seq_id = seq_obj.create(cr, uid, values={'name': 'Picking in', 'prefix': 'IN', 'padding': 5}, context=context)
|
||||
out_seq_id = seq_obj.create(cr, uid, values={'name': 'Picking out', 'prefix': 'OUT', 'padding': 5}, context=context)
|
||||
internal_seq_id = seq_obj.create(cr, uid, values={'name': 'Picking internal', 'prefix': 'INT', 'padding': 5}, context=context)
|
||||
#then create picking_type
|
||||
picking_obj = self.pool.get('stock.picking.type')
|
||||
in_picking_id = picking_obj.create(cr, uid, vals={'name': 'Receptions', 'warehouse_id': new_wh_id, 'code_id': 'incoming', 'sequence_id': in_seq_id, 'default_location_src_id': supplier_loc, 'default_location_dest_id': wh_stock_loc}, context=context)
|
||||
out_picking_id = picking_obj.create(cr, uid, vals={'name': 'Delivery Orders', 'warehouse_id': new_wh_id, 'code_id': 'outgoing', 'sequence_id': out_seq_id, 'default_location_src_id': wh_stock_loc, 'default_location_dest_id': customer_loc}, context=context)
|
||||
internal_picking_id = picking_obj.create(cr, uid, vals={'name': 'Internal Transfers', 'warehouse_id': new_wh_id, 'code_id': 'internal', 'sequence_id': internal_seq_id, 'default_location_src_id': wh_stock_loc, 'default_location_dest_id': wh_stock_loc, 'pack': obj.packing}, context=context)
|
||||
|
||||
#add pull rules to default route
|
||||
#ship pull rules
|
||||
pull_data = {
|
||||
'name': obj.name+': Stock -> Customer',
|
||||
'location_src_id': wh_stock_loc,
|
||||
'location_id': customer_loc,
|
||||
'propagate': True,
|
||||
'route_id': new_route_id,
|
||||
'action': 'move',
|
||||
'picking_type_id': internal_picking_id,
|
||||
'procure_method': 'make_to_stock'
|
||||
}
|
||||
if obj.crossdock:
|
||||
cross_data = pull_data.copy()
|
||||
cross_data.update({
|
||||
'name': obj.name+': Output -> Customer',
|
||||
'location_src_id': wh_output_stock_loc,
|
||||
'picking_type_id': out_picking_id,
|
||||
'procure_method': 'make_to_order',
|
||||
})
|
||||
pull_obj.create(cr, uid, vals=cross_data, context=context)
|
||||
|
||||
cross_data.update({
|
||||
'name': obj.name+': Supplier -> Output',
|
||||
'location_src_id': supplier_loc,
|
||||
'location_id': wh_output_stock_loc,
|
||||
'action': 'buy',
|
||||
'picking_type_id': in_picking_id,
|
||||
})
|
||||
pull_obj.create(cr, uid, vals=cross_data, context=context)
|
||||
#ship rules
|
||||
elif wh_stock_loc == wh_output_stock_loc:
|
||||
pull_obj.create(cr, uid, vals=pull_data, context=context)
|
||||
#pick-pack-ship rules
|
||||
elif obj.packing:
|
||||
#if packing zone is the same as output or stock, only create one pull rule, otherwise, create two
|
||||
if obj.packing_loc_id.id == wh_stock_loc:
|
||||
pull_data.update({
|
||||
'name': obj.name + ' Stock -> Output',
|
||||
'location_id': wh_output_stock_loc,
|
||||
})
|
||||
pull_obj.create(cr, uid, vals=pull_data, context=context)
|
||||
else:
|
||||
|
||||
pull_data.update({
|
||||
'name': obj.name+' Stock -> Pack',
|
||||
'location_id': obj.packing_loc_id.id,
|
||||
})
|
||||
pull_obj.create(cr, uid, vals=pull_data, context=context)
|
||||
|
||||
pull_data.update({
|
||||
'name': obj.name+' Pack -> Output',
|
||||
'location_src_id': obj.packing_loc_id.id,
|
||||
'location_id': wh_output_stock_loc,
|
||||
'picking_type_id': internal_picking_id,
|
||||
'procure_method': 'make_to_order',
|
||||
})
|
||||
pull_obj.create(cr, uid, vals=pull_data, context=context)
|
||||
|
||||
pull_data.update({
|
||||
'name': obj.name+' Output -> Customer',
|
||||
'location_src_id': wh_output_stock_loc,
|
||||
'location_id': customer_loc,
|
||||
'picking_type_id': out_picking_id,
|
||||
'procure_method': 'make_to_order',
|
||||
})
|
||||
pull_obj.create(cr, uid, vals=pull_data, context=context)
|
||||
#pick-ship rules
|
||||
else:
|
||||
pull_data.update({
|
||||
'name': obj.name + ' Stock -> Output',
|
||||
'location_id': wh_output_stock_loc,
|
||||
})
|
||||
pull_obj.create(cr, uid, vals=pull_data, context=context)
|
||||
|
||||
pull_data.update({
|
||||
'name': obj.name+' Output -> Customer',
|
||||
'location_src_id': wh_output_stock_loc,
|
||||
'location_id': customer_loc,
|
||||
'picking_type_id': out_picking_id,
|
||||
'procure_method': 'make_to_order',
|
||||
})
|
||||
pull_obj.create(cr, uid, vals=pull_data, context=context)
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="stock_configure_wh" model="ir.ui.view">
|
||||
<field name="name">Configure Warehouse</field>
|
||||
<field name="model">stock.configure.wh</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Configure Warehouse" version="7.0">
|
||||
<sheet>
|
||||
<separator string="Warehouse Informations"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="address_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="crossdock" on_change="onchange_crossdock(crossdock)"/>
|
||||
<field name="packing" attrs="{'invisible': [('crossdock', '=', True)]}" on_change="onchange_packing(packing, internal_stock_loc_id)"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="Warehouse locations"/>
|
||||
<group>
|
||||
<field name="internal_stock_loc_id"/>
|
||||
<field name="input_stock_loc_id"/>
|
||||
<field name="output_stock_loc_id"/>
|
||||
<field name="packing_loc_id" attrs="{'invisible': [('packing', '=', False)], 'required': [('packing', '=', True)]}"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="configure_wh" string="Configure Warehouse" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_stock_configure_wh" model="ir.actions.act_window">
|
||||
<field name="name">Configure Warehouse</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.configure.wh</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="stock_configure_wh"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -33,9 +33,9 @@ It creates 3 warehouses
|
||||
'author': 'OpenERP SA',
|
||||
'images': [],
|
||||
'depends': ['stock_complex_routes'],
|
||||
'data': ['stock_multi_warehouse.yml'],
|
||||
'data': [],
|
||||
'demo': [
|
||||
|
||||
'stock_multi_warehouse.yml'
|
||||
],
|
||||
'installable': True,
|
||||
'test': [
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
-
|
||||
!context
|
||||
noupdate: 0
|
||||
-
|
||||
Create Two Customers
|
||||
-
|
||||
@@ -16,43 +19,43 @@
|
||||
-
|
||||
Create Location structure of Warehouse Panama Santiago District
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_santiago}:
|
||||
!record {model: stock.location, id: location_wh1}:
|
||||
name: Panama Santiago District Warehouse
|
||||
location_id: location_panama
|
||||
-
|
||||
Input
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_santiago_input}:
|
||||
!record {model: stock.location, id: location_wh1_input}:
|
||||
name: Input
|
||||
location_id: location_panama_santiago
|
||||
location_id: location_wh1
|
||||
-
|
||||
Output
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_santiago_output}:
|
||||
!record {model: stock.location, id: location_wh1_output}:
|
||||
name: Output
|
||||
location_id: location_panama_santiago
|
||||
location_id: location_wh1
|
||||
-
|
||||
Stock
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_santiago_stock}:
|
||||
!record {model: stock.location, id: location_wh1_stock}:
|
||||
name: Stock
|
||||
location_id: location_panama_santiago
|
||||
location_id: location_wh1
|
||||
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_santiago_stock_area1}:
|
||||
!record {model: stock.location, id: location_wh1_stock_area1}:
|
||||
name: Area1
|
||||
location_id: location_panama_santiago_stock
|
||||
location_id: location_wh1_stock
|
||||
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_santiago_stock_area1_bin1}:
|
||||
!record {model: stock.location, id: location_wh1_stock_area1_bin1}:
|
||||
name: Bin1
|
||||
location_id: location_panama_santiago_stock_area1
|
||||
location_id: location_wh1_stock_area1
|
||||
-
|
||||
Create warehouse Panama Santiago District
|
||||
-
|
||||
!record {model: stock.warehouse, id: wh_panama_santiago}:
|
||||
!record {model: stock.warehouse, id: wh_wh1}:
|
||||
name: Panama Santiago District Warehouse
|
||||
lot_stock_id: location_panama_santiago
|
||||
lot_stock_id: location_wh1
|
||||
-
|
||||
Create picking type in for this warehouse
|
||||
-
|
||||
@@ -60,8 +63,8 @@
|
||||
name: Reception
|
||||
code_id: incoming
|
||||
sequence_id: stock.seq_picking_type_in
|
||||
warehouse_id: wh_panama_santiago
|
||||
default_location_dest_id: location_panama_santiago_input
|
||||
warehouse_id: wh_wh1
|
||||
default_location_dest_id: location_wh1_input
|
||||
-
|
||||
Create picking type out for this warehouse
|
||||
-
|
||||
@@ -69,8 +72,8 @@
|
||||
name: Deliveries
|
||||
code_id: outgoing
|
||||
sequence_id: stock.seq_picking_type_out
|
||||
warehouse_id: wh_panama_santiago
|
||||
default_location_src_id: location_panama_santiago_output
|
||||
warehouse_id: wh_wh1
|
||||
default_location_src_id: location_wh1_output
|
||||
-
|
||||
Create picking type internal for this warehouse
|
||||
-
|
||||
@@ -78,44 +81,44 @@
|
||||
name: Internal
|
||||
code_id: internal
|
||||
sequence_id: stock.seq_picking_type_internal
|
||||
warehouse_id: wh_panama_santiago
|
||||
default_location_src_id: location_panama_santiago_input
|
||||
default_location_dest_id: location_panama_santiago_stock
|
||||
warehouse_id: wh_wh1
|
||||
default_location_src_id: location_wh1_stock
|
||||
default_location_dest_id: location_wh1_stock
|
||||
-
|
||||
Create Location structure of Warehouse Panama Main
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_main}:
|
||||
!record {model: stock.location, id: location_wh2}:
|
||||
name: Panama Main Warehouse
|
||||
location_id: location_panama
|
||||
-
|
||||
Input
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_main_input}:
|
||||
!record {model: stock.location, id: location_wh2_input}:
|
||||
name: Input
|
||||
location_id: location_panama_main
|
||||
location_id: location_wh2
|
||||
-
|
||||
Output
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_main_output}:
|
||||
!record {model: stock.location, id: location_wh2_output}:
|
||||
name: Output
|
||||
location_id: location_panama_main
|
||||
location_id: location_wh2
|
||||
-
|
||||
Stock
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_main_stock}:
|
||||
!record {model: stock.location, id: location_wh2_stock}:
|
||||
name: Stock
|
||||
location_id: location_panama_main
|
||||
location_id: location_wh2
|
||||
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_main_stock_area2}:
|
||||
!record {model: stock.location, id: location_wh2_stock_area2}:
|
||||
name: Area2
|
||||
location_id: location_panama_main_stock
|
||||
location_id: location_wh2_stock
|
||||
-
|
||||
Create warehouse Panama main
|
||||
-
|
||||
!record {model: stock.warehouse, id: wh_panama_main}:
|
||||
!record {model: stock.warehouse, id: wh_wh2}:
|
||||
name: Panama Main Warehouse
|
||||
lot_stock_id: location_panama_main
|
||||
lot_stock_id: location_wh2
|
||||
-
|
||||
Create picking type in for warehouse panama main
|
||||
-
|
||||
@@ -123,8 +126,8 @@
|
||||
name: Reception
|
||||
code_id: incoming
|
||||
sequence_id: stock.seq_picking_type_in
|
||||
warehouse_id: wh_panama_main
|
||||
default_location_dest_id: location_panama_main_input
|
||||
warehouse_id: wh_wh2
|
||||
default_location_dest_id: location_wh2_input
|
||||
-
|
||||
Create picking type out for warehouse panama main
|
||||
-
|
||||
@@ -132,8 +135,8 @@
|
||||
name: Deliveries
|
||||
code_id: outgoing
|
||||
sequence_id: stock.seq_picking_type_out
|
||||
warehouse_id: wh_panama_main
|
||||
default_location_src_id: location_panama_main_output
|
||||
warehouse_id: wh_wh2
|
||||
default_location_src_id: location_wh2_output
|
||||
-
|
||||
Create picking type internal for warehouse panama main
|
||||
-
|
||||
@@ -141,56 +144,27 @@
|
||||
name: Internal
|
||||
code_id: internal
|
||||
sequence_id: stock.seq_picking_type_internal
|
||||
warehouse_id: wh_panama_main
|
||||
default_location_src_id: location_panama_main_input
|
||||
default_location_dest_id: location_panama_main_stock
|
||||
warehouse_id: wh_wh2
|
||||
default_location_src_id: location_wh2_stock
|
||||
default_location_dest_id: location_wh2_stock
|
||||
-
|
||||
Create Location structure of Warehouse Dubai
|
||||
-
|
||||
!record {model: stock.location, id: location_panama_main}:
|
||||
name: Panama Main Warehouse
|
||||
location_id: location_panama
|
||||
-
|
||||
Create United Arab Emirates in Location structure
|
||||
-
|
||||
!record {model: stock.location, id: location_uae}:
|
||||
name: United Arab Emirates
|
||||
location_id: stock.stock_location_locations
|
||||
-
|
||||
Create Location structure of Dubai Warehouse
|
||||
-
|
||||
!record {model: stock.location, id: location_dubai}:
|
||||
name: Dubai Warehouse
|
||||
location_id: location_uae
|
||||
child_ids:
|
||||
- name: Input
|
||||
- name: Output
|
||||
- name: Stock
|
||||
child_ids:
|
||||
- name: Area3
|
||||
-
|
||||
Create Dubai warehouse
|
||||
-
|
||||
!record {model: stock.warehouse, id: wh_dubai}:
|
||||
name: Dubai Warehouse
|
||||
lot_stock_id: location_dubai
|
||||
|
||||
-
|
||||
Create Ship Route for main panama warehouse
|
||||
-
|
||||
!record {model: stock.location.route, id: route_wh_panama_main_ship}:
|
||||
!record {model: stock.location.route, id: route_wh_wh2_ship}:
|
||||
name: Ship main panama
|
||||
warehouse_selectable: True
|
||||
product_selectable: False
|
||||
pull_ids:
|
||||
- invoice_state: none
|
||||
location_id: location_panama_main_output
|
||||
location_src_id: location_panama_main_stock
|
||||
location_id: location_wh2_output
|
||||
location_src_id: location_wh2_stock
|
||||
name: Panama Main Stock -> Panama Main Output
|
||||
procure_method: make_to_stock
|
||||
picking_type_id: picking_type_main_internal
|
||||
action: move
|
||||
- invoice_state: none
|
||||
location_id: stock.stock_location_customers
|
||||
location_src_id: location_panama_main_output
|
||||
location_src_id: location_wh2_output
|
||||
name: Panama Main Output -> Customer
|
||||
picking_type_id: picking_type_main_out
|
||||
procure_method: make_to_order
|
||||
@@ -198,28 +172,31 @@
|
||||
-
|
||||
Create Ship Route for panama santiago warehouse
|
||||
-
|
||||
!record {model: stock.location.route, id: route_wh_panama_santiago_ship}:
|
||||
!record {model: stock.location.route, id: route_wh_wh1_ship}:
|
||||
name: Ship panama santiago
|
||||
warehouse_selectable: True
|
||||
product_selectable: False
|
||||
pull_ids:
|
||||
- invoice_state: none
|
||||
location_id: location_panama_santiago_output
|
||||
location_src_id: location_panama_santiago_stock
|
||||
location_id: location_wh1_output
|
||||
location_src_id: location_wh1_stock
|
||||
name: Santiago Stock -> Santiago Output
|
||||
procure_method: make_to_stock
|
||||
picking_type_id: picking_type_santiago_internal
|
||||
action: move
|
||||
- invoice_state: none
|
||||
location_id: stock.stock_location_customers
|
||||
location_src_id: location_panama_santiago_output
|
||||
location_src_id: location_wh1_output
|
||||
name: Santiago Output -> Customer
|
||||
picking_type_id: picking_type_santiago_out
|
||||
procure_method: make_to_order
|
||||
action: move
|
||||
|
||||
-
|
||||
Add routes to warehouses
|
||||
-
|
||||
!python {model: stock.warehouse}: |
|
||||
self.write(cr, uid, [ref('wh_panama_main')], {'route_id': ref('route_wh_panama_main_ship')}, context=context)
|
||||
self.write(cr, uid, [ref('wh_panama_santiago')], {'route_id': ref('route_wh_panama_santiago_ship')}, context=context)
|
||||
self.write(cr, uid, [ref('wh_wh2')], {'route_id': ref('route_wh_wh2_ship'), 'lot_stock_id': ref('location_wh2_stock')}, context=context)
|
||||
self.write(cr, uid, [ref('wh_wh1')], {'route_id': ref('route_wh_wh1_ship'), 'lot_stock_id': ref('location_wh1_stock')}, context=context)
|
||||
-
|
||||
Create Products
|
||||
-
|
||||
@@ -331,7 +308,7 @@
|
||||
-
|
||||
!record {model: stock.inventory, id: inventory_stock1}:
|
||||
name: Inventory Stock 1
|
||||
location_id: location_panama_santiago_stock
|
||||
location_id: location_wh1_stock
|
||||
-
|
||||
I create the wizard to confirm the inventory
|
||||
-
|
||||
@@ -350,14 +327,14 @@
|
||||
inventory_id: inventory_stock1
|
||||
product_id: product_A
|
||||
product_qty: 6
|
||||
location_id: location_panama_santiago_stock
|
||||
location_id: location_wh1_stock
|
||||
|
||||
-
|
||||
!record {model: stock.inventory.line, id: inventory_stock1line_productB}:
|
||||
inventory_id: inventory_stock1
|
||||
product_id: product_B
|
||||
product_qty: 12
|
||||
location_id: location_panama_santiago_stock
|
||||
location_id: location_wh1_stock
|
||||
-
|
||||
I confirm Stock1 inventory
|
||||
-
|
||||
@@ -368,7 +345,7 @@
|
||||
-
|
||||
!record {model: stock.inventory, id: inventory_stock2}:
|
||||
name: Inventory Stock 2
|
||||
location_id: location_panama_main_stock
|
||||
location_id: location_wh2_stock
|
||||
-
|
||||
I fill Stock2 inventory
|
||||
-
|
||||
@@ -382,21 +359,21 @@
|
||||
inventory_id: inventory_stock2
|
||||
product_id: product_A
|
||||
product_qty: 8
|
||||
location_id: location_panama_main_stock
|
||||
location_id: location_wh2_stock
|
||||
|
||||
-
|
||||
!record {model: stock.inventory.line, id: inventory_stock2line_productB}:
|
||||
inventory_id: inventory_stock2
|
||||
product_id: product_B
|
||||
product_qty: 120
|
||||
location_id: location_panama_main_stock
|
||||
location_id: location_wh2_stock
|
||||
|
||||
-
|
||||
!record {model: stock.inventory.line, id: inventory_stock2line_productC_1}:
|
||||
inventory_id: inventory_stock2
|
||||
product_id: product_C
|
||||
product_qty: 5
|
||||
location_id: location_panama_main_stock
|
||||
location_id: location_wh2_stock
|
||||
prod_lot_id: lot003
|
||||
|
||||
-
|
||||
@@ -404,7 +381,7 @@
|
||||
inventory_id: inventory_stock2
|
||||
product_id: product_C
|
||||
product_qty: 15
|
||||
location_id: location_panama_main_stock
|
||||
location_id: location_wh2_stock
|
||||
prod_lot_id: lot004
|
||||
-
|
||||
I confirm Stock2 inventory
|
||||
@@ -416,7 +393,7 @@
|
||||
-
|
||||
!record {model: stock.inventory, id: inventory_stock1_area1}:
|
||||
name: Inventory Stock1 area 1
|
||||
location_id: location_panama_santiago_stock_area1
|
||||
location_id: location_wh1_stock_area1
|
||||
-
|
||||
I fill Area1 inventory
|
||||
-
|
||||
@@ -430,14 +407,14 @@
|
||||
inventory_id: inventory_stock1_area1
|
||||
product_id: product_D
|
||||
product_qty: 4
|
||||
location_id: location_panama_santiago_stock_area1
|
||||
location_id: location_wh1_stock_area1
|
||||
|
||||
-
|
||||
!record {model: stock.inventory.line, id: inventory_stock1line_productD_2}:
|
||||
inventory_id: inventory_stock1_area1
|
||||
product_id: product_D
|
||||
product_qty: 5
|
||||
location_id: location_panama_santiago_stock_area1
|
||||
location_id: location_wh1_stock_area1
|
||||
-
|
||||
I confirm Area1 inventory
|
||||
-
|
||||
@@ -448,7 +425,7 @@
|
||||
-
|
||||
!record {model: stock.inventory, id: inventory_stock2_area2}:
|
||||
name: Inventory Stock2 area 2
|
||||
location_id: location_panama_main_stock_area2
|
||||
location_id: location_wh2_stock_area2
|
||||
-
|
||||
I fill Area2 inventory
|
||||
-
|
||||
@@ -462,14 +439,14 @@
|
||||
inventory_id: inventory_stock2_area2
|
||||
product_id: product_D
|
||||
product_qty: 2
|
||||
location_id: location_panama_main_stock_area2
|
||||
location_id: location_wh2_stock_area2
|
||||
|
||||
-
|
||||
!record {model: stock.inventory.line, id: inventory_stock2line_productD_2}:
|
||||
inventory_id: inventory_stock2_area2
|
||||
product_id: product_D
|
||||
product_qty: 3
|
||||
location_id: location_panama_main_stock_area2
|
||||
location_id: location_wh2_stock_area2
|
||||
-
|
||||
I confirm Area2 inventory
|
||||
-
|
||||
@@ -481,7 +458,7 @@
|
||||
-
|
||||
!record {model: stock.inventory, id: inventory_stock1_area1_bin1}:
|
||||
name: Inventory Stock1 area1 bin 1
|
||||
location_id: location_panama_santiago_stock_area1_bin1
|
||||
location_id: location_wh1_stock_area1_bin1
|
||||
-
|
||||
I fill Bin1 inventory
|
||||
-
|
||||
@@ -495,7 +472,7 @@
|
||||
inventory_id: inventory_stock1_area1_bin1
|
||||
product_id: product_C
|
||||
product_qty: 3
|
||||
location_id: location_panama_santiago_stock_area1_bin1
|
||||
location_id: location_wh1_stock_area1_bin1
|
||||
prod_lot_id: lot001
|
||||
|
||||
-
|
||||
@@ -503,7 +480,7 @@
|
||||
inventory_id: inventory_stock1_area1_bin1
|
||||
product_id: product_C
|
||||
product_qty: 14
|
||||
location_id: location_panama_santiago_stock_area1_bin1
|
||||
location_id: location_wh1_stock_area1_bin1
|
||||
prod_lot_id: lot002
|
||||
-
|
||||
I confirm Bin1 inventory
|
||||
@@ -515,7 +492,7 @@
|
||||
-
|
||||
!record {model: sale.order, id: so1}:
|
||||
partner_id: customer_1
|
||||
warehouse_id: wh_panama_main
|
||||
warehouse_id: wh_wh2
|
||||
order_line:
|
||||
- product_id: product_A
|
||||
product_uom_qty: 7
|
||||
@@ -529,7 +506,7 @@
|
||||
-
|
||||
!record {model: sale.order, id: so2}:
|
||||
partner_id: customer_1
|
||||
warehouse_id: wh_panama_main
|
||||
warehouse_id: wh_wh2
|
||||
order_line:
|
||||
- product_id: product_E
|
||||
product_uom_qty: 5
|
||||
@@ -543,7 +520,7 @@
|
||||
-
|
||||
!record {model: sale.order, id: so3}:
|
||||
partner_id: customer_2
|
||||
warehouse_id: wh_panama_santiago
|
||||
warehouse_id: wh_wh1
|
||||
order_line:
|
||||
- product_id: product_A
|
||||
product_uom_qty: 5
|
||||
|
||||
Reference in New Issue
Block a user