diff --git a/contributing.md b/CONTRIBUTING.md similarity index 100% rename from contributing.md rename to CONTRIBUTING.md diff --git a/README.md b/README.md index 7b3896022f0..c400772c2ba 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,52 @@ -About Odoo -========== +Odoo +---- -Odoo is a suite of open source Business apps. More info at http://www.odoo.com +Odoo is a suite of web based open source business apps. More info at http://www.odoo.com -Installation -============ - -[Setup/migration guide for employees](https://github.com/odoo/odoo/blob/master/doc/git.rst) +The easiest way to play with it is the Odoo free trial, email registration is NOT required, use the "skip this step" link on the registration page to skip it. -Migration from bazaar -===================== +Getting started with Odoo developement +-------------------------------------- -If you have existing bazaar branches and want to move them to a git repository, -there are several options: +If you are a developer type the following command at your terminal [1]: -* download http://nightly.openerp.com/move-branch.zip and run it with - `python move-branch.zip -h` (for the help). It should be able to convert - simple-enough branches for you (even if they have merge commits &al) -* Extract the branch contents as patches and use `git apply` or `git am` to - rebuild a branch from them -* Replay the branch by hand + wget -O- https://raw.githubusercontent.com/odoo/odoo/master/odoo.py | python + +Then follow the developer tutorial + +[1] You may want to check the content of the odoo.py file before executing it. -System Requirements -------------------- +Packages, tarballs and installers +--------------------------------- -The dependencies are listed in setup.py +* Debian packages + + Add this apt repository to your /etc/apt/sources.list file + + deb http://nightly.openerp.com/8.0/deb/ ./ + + Then type: + + $ sudo apt-get update + $ sudo apt-get install odoo + +* Source tarballs + +* Windows installer + +* RPM package -Debian/Ubuntu -------------- +For Odoo employees +------------------ -Add the apt repository +To add the odoo-dev remote use this command: - deb http://nightly.openerp.com/7.0/deb/ ./ + $ ./odoo.py setup_git_dev -in your source.list and type: +To fetch odoo merge pull requests refs use this command: - $ sudo apt-get update - $ sudo apt-get install openerp - -Or download the deb file and type: - - $ sudo dpkg -i - $ sudo apt-get install -f - -RedHat, Fedora, CentOS ----------------------- - -Install the required dependencies: - - $ yum install python - $ easy_install pip - $ pip install ..... - -Install the openerp rpm - - $ rpm -i openerp-VERSION.rpm - -Windows -------- - -Check the notes in setup.py - - -Setting up your database ------------------------- - -Point your browser to http://localhost:8069/ and click "Manage Databases", the -default master password is "admin". + $ ./odoo.py setup_git_review diff --git a/addons/account/product_view.xml b/addons/account/product_view.xml index 73b31bbb02a..9c1b0ee39b7 100644 --- a/addons/account/product_view.xml +++ b/addons/account/product_view.xml @@ -1,57 +1,52 @@ - - product.normal.form.inherit - product.product + + product.template.form.inherit + product.template 5 - + - + + + + attrs="{'readonly': [('is_product_variant', '=', True)]}"/> + attrs="{'readonly':[ '|', ('sale_ok','=',0), ('is_product_variant', '=', True)]}"/> + attrs="{'readonly': [('is_product_variant', '=', True)]}"/> + attrs="{'readonly': [('is_product_variant', '=', True)]}"/> - + - - product.template.product.form.inherit + + product.template.search product.template - + primary + - - - - - - - - - - - - - - - + + + + + + + - - product.category.property.form.inherit product.category diff --git a/addons/account_analytic_analysis/account_analytic_analysis.py b/addons/account_analytic_analysis/account_analytic_analysis.py index 4b2352bc880..6c710dc2c04 100644 --- a/addons/account_analytic_analysis/account_analytic_analysis.py +++ b/addons/account_analytic_analysis/account_analytic_analysis.py @@ -553,18 +553,17 @@ class account_analytic_account(osv.osv): 'nodestroy': True, } - def on_change_template(self, cr, uid, ids, template_id, date_start=False, fix_price_invoices=False, invoice_on_timesheets=False, recurring_invoices=False, context=None): + def on_change_template(self, cr, uid, ids, template_id, date_start=False, context=None): if not template_id: return {} - obj_analytic_line = self.pool.get('account.analytic.invoice.line') res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, date_start=date_start, context=context) template = self.browse(cr, uid, template_id, context=context) - if not fix_price_invoices: + if not ids: res['value']['fix_price_invoices'] = template.fix_price_invoices res['value']['amount_max'] = template.amount_max - if not invoice_on_timesheets: + if not ids: res['value']['invoice_on_timesheets'] = template.invoice_on_timesheets res['value']['hours_qtt_est'] = template.hours_qtt_est @@ -572,7 +571,7 @@ class account_analytic_account(osv.osv): res['value']['to_invoice'] = template.to_invoice.id if template.pricelist_id.id: res['value']['pricelist_id'] = template.pricelist_id.id - if not recurring_invoices: + if not ids: invoice_line_ids = [] for x in template.recurring_invoice_line_ids: invoice_line_ids.append((0, 0, { diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml index af6eb47ffa4..af4caae608f 100644 --- a/addons/account_analytic_analysis/account_analytic_analysis_view.xml +++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml @@ -38,9 +38,6 @@ {'required': [('type','=','contract'),'|','|',('fix_price_invoices','=',True), ('invoice_on_timesheets', '=', True), ('recurring_invoices', '=', True)]} - - on_change_template(template_id, date_start, fix_price_invoices, invoice_on_timesheets, recurring_invoices) - diff --git a/addons/account_anglo_saxon/product_view.xml b/addons/account_anglo_saxon/product_view.xml index c06decf2c92..5a589131218 100644 --- a/addons/account_anglo_saxon/product_view.xml +++ b/addons/account_anglo_saxon/product_view.xml @@ -1,29 +1,18 @@ - - product.normal.form.inherit.stock - product.product - - - - - - - product.template.product.form.inherit + product.normal.form.inherit.stock product.template + diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml index a4341d403ca..52a7d30d7f5 100644 --- a/addons/base_action_rule/base_action_rule_view.xml +++ b/addons/base_action_rule/base_action_rule_view.xml @@ -87,6 +87,7 @@ + diff --git a/addons/event/email_template.xml b/addons/event/email_template.xml index d99774acd3c..d4479bcfc87 100644 --- a/addons/event/email_template.xml +++ b/addons/event/email_template.xml @@ -9,7 +9,7 @@ Your registration at ${object.event_id.name} Hello ${object.name},

-

The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin} to ${object.event_id.date_end}. +

The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin_located.strftime('%Y-%m-%d %H:%M:%S (%Z)')} to ${object.event_id.date_end_located.strftime('%Y-%m-%d %H:%M:%S (%Z)')}. For any further information please contact our event department.

Thank you for your participation!

Best regards

]]>
diff --git a/addons/event/event.py b/addons/event/event.py index 5e5d1204a17..a31ec00b8c0 100644 --- a/addons/event/event.py +++ b/addons/event/event.py @@ -18,7 +18,8 @@ # along with this program. If not, see . # ############################################################################## - +import pytz +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT from datetime import datetime, timedelta from openerp.osv import fields, osv from openerp.tools.translate import _ @@ -156,6 +157,22 @@ class event_event(osv.osv): for event in self.browse(cr, uid, ids, context=context) } + def _compute_date_tz(self, cr, uid, ids, fld, arg, context=None): + if context is None: + context = {} + res = {} + for event in self.browse(cr, uid, ids, context=context): + ctx = dict(context, tz=(event.date_tz or 'UTC')) + if fld == 'date_begin_located': + date_to_convert = event.date_begin + elif fld == 'date_end_located': + date_to_convert = event.date_end + res[event.id] = fields.datetime.context_timestamp(cr, uid, datetime.strptime(date_to_convert, DEFAULT_SERVER_DATETIME_FORMAT), context=ctx) + return res + + def _tz_get(self, cr, uid, context=None): + return [(x, x) for x in pytz.all_timezones] + _columns = { 'name': fields.char('Event Name', size=64, required=True, translate=True, readonly=False, states={'done': [('readonly', True)]}), 'user_id': fields.many2one('res.users', 'Responsible User', readonly=False, states={'done': [('readonly', True)]}), @@ -175,8 +192,11 @@ class event_event(osv.osv): store={'event.registration': (_get_events_from_registrations, ['state'], 10), 'event.event': (lambda self, cr, uid, ids, c = {}: ids, ['seats_max', 'registration_ids'], 20)}), 'registration_ids': fields.one2many('event.registration', 'event_id', 'Registrations', readonly=False, states={'done': [('readonly', True)]}), + 'date_tz': fields.selection(_tz_get, string='Timezone'), 'date_begin': fields.datetime('Start Date', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'date_end': fields.datetime('End Date', required=True, readonly=True, states={'draft': [('readonly', False)]}), + 'date_begin_located': fields.function(_compute_date_tz, string='Start Date Located', type="datetime"), + 'date_end_located': fields.function(_compute_date_tz, string='End Date Located', type="datetime"), 'state': fields.selection([ ('draft', 'Unconfirmed'), ('cancel', 'Cancelled'), @@ -204,7 +224,8 @@ class event_event(osv.osv): 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'event.event', context=c), 'user_id': lambda obj, cr, uid, context: uid, 'organizer_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id, - 'address_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id + 'address_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id, + 'date_tz': lambda self, cr, uid, ctx: ctx.get('tz', "UTC"), } def _check_seats_limit(self, cr, uid, ids, context=None): diff --git a/addons/event/event_view.xml b/addons/event/event_view.xml index cc6edfbd9bd..baa553babaf 100644 --- a/addons/event/event_view.xml +++ b/addons/event/event_view.xml @@ -89,6 +89,7 @@ + diff --git a/addons/event_sale/event_sale_view.xml b/addons/event_sale/event_sale_view.xml index 8987354acdd..a049565074a 100644 --- a/addons/event_sale/event_sale_view.xml +++ b/addons/event_sale/event_sale_view.xml @@ -1,18 +1,19 @@ - - product.product - + + + product.template + -
- -
diff --git a/addons/sale/sale.py b/addons/sale/sale.py index e3b59c00015..70dece22651 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -880,7 +880,7 @@ class sale_order_line(osv.osv): 'order_id': fields.many2one('sale.order', 'Order Reference', required=True, ondelete='cascade', select=True, readonly=True, states={'draft':[('readonly',False)]}), 'name': fields.text('Description', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of sales order lines."), - 'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True, readonly=True, states={'draft': [('readonly', False)]}), + 'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True, readonly=True, states={'draft': [('readonly', False)]}, ondelete='restrict'), 'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True), 'invoiced': fields.function(_fnct_line_invoiced, string='Invoiced', type='boolean', store={ diff --git a/addons/sale_mrp/test/cancellation_propagated.yml b/addons/sale_mrp/test/cancellation_propagated.yml index 0005e15db53..6a5c557a958 100644 --- a/addons/sale_mrp/test/cancellation_propagated.yml +++ b/addons/sale_mrp/test/cancellation_propagated.yml @@ -16,18 +16,19 @@ uom_id: product.product_uom_unit uom_po_id: product.product_uom_unit - - I create a bom for this product + I create a bom for this product - !record {model: mrp.bom, id: mrp_bom_test1}: company_id: base.main_company name: My BOM + product_tmpl_id: product_manu_product_template product_id: product_manu + product_uom: product.product_uom_unit product_qty: 1.0 type: normal - bom_lines: - - company_id: base.main_company - name: GrapWorks Software - product_id: product.product_product_44 + bom_line_ids: + - product_id: product.product_product_44 + product_uom: product.product_uom_unit product_qty: 1.0 - And set routes on product to be MTO and manufacture diff --git a/addons/sale_mrp/test/sale_mrp.yml b/addons/sale_mrp/test/sale_mrp.yml index 85e25b502f3..11b0af8be6f 100644 --- a/addons/sale_mrp/test/sale_mrp.yml +++ b/addons/sale_mrp/test/sale_mrp.yml @@ -54,10 +54,10 @@ company_id: base.main_company name: Slider Mobile product_efficiency: 1.0 + product_tmpl_id: product_product_slidermobile0_product_template product_id: product_product_slidermobile0 product_qty: 1.0 product_uom: product.product_uom_unit - product_uos_qty: 0.0 sequence: 0.0 type: normal - diff --git a/addons/sale_mrp/tests/test_move_explode.py b/addons/sale_mrp/tests/test_move_explode.py index 5bb8e8550cc..88dab7135b1 100644 --- a/addons/sale_mrp/tests/test_move_explode.py +++ b/addons/sale_mrp/tests/test_move_explode.py @@ -35,9 +35,9 @@ class TestMoveExplode(common.TransactionCase): self.mrp_bom = self.registry('mrp.bom') #product that has a phantom bom - self.product_bom_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_4')[1] + self.product_bom_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_3')[1] #bom with that product - self.bom_id = self.ir_model_data.get_object_reference(cr, uid, 'mrp', 'mrp_bom_24')[1] + self.bom_id = self.ir_model_data.get_object_reference(cr, uid, 'mrp', 'mrp_bom_9')[1] #partner agrolait self.partner_id = self.ir_model_data.get_object_reference(cr, uid, 'base', 'res_partner_1')[1] @@ -55,5 +55,5 @@ class TestMoveExplode(common.TransactionCase): move_ids = [x.id for x in browse_move_ids] #we should have same amount of move as the component in the phatom bom bom = self.mrp_bom.browse(cr, uid, self.bom_id, context=context) - bom_component_length = self.mrp_bom._bom_explode(cr, uid, bom, 1, []) + bom_component_length = self.mrp_bom._bom_explode(cr, uid, bom, self.product_bom_id, 1, []) self.assertEqual(len(move_ids), len(bom_component_length[0])) diff --git a/addons/stock/__openerp__.py b/addons/stock/__openerp__.py index 5e21055208c..6acc6a7bfd0 100644 --- a/addons/stock/__openerp__.py +++ b/addons/stock/__openerp__.py @@ -84,7 +84,9 @@ Dashboard / Reports for Warehouse Management will include: 'report/report_stock_view.xml', 'res_config_view.xml', 'views/report_package_barcode.xml', - 'views/report_stockpicking.xml', + 'views/report_lot_barcode.xml', + 'views/report_location_barcode.xml', + 'views/report_stockpicking.xml', 'views/report_stockinventory.xml', 'views/stock.xml', ], diff --git a/addons/stock/procurement.py b/addons/stock/procurement.py index 42a86a32db4..0a574579808 100644 --- a/addons/stock/procurement.py +++ b/addons/stock/procurement.py @@ -188,6 +188,7 @@ class procurement_order(osv.osv): 'date': newdate, 'date_expected': newdate, 'propagate': procurement.rule_id.propagate, + 'priority': procurement.priority, } return vals @@ -288,7 +289,7 @@ class procurement_order(osv.osv): self._procure_orderpoint_confirm(cr, SUPERUSER_ID, use_new_cursor=False, company_id=company.id, context=context) #Search all confirmed stock_moves and try to assign them - confirmed_ids = move_obj.search(cr, uid, [('state', '=', 'confirmed')], limit=None, order='picking_priority desc, date_expected asc', context=context) + confirmed_ids = move_obj.search(cr, uid, [('state', '=', 'confirmed')], limit=None, order='priority desc, date_expected asc', context=context) for x in xrange(0, len(confirmed_ids), 100): move_obj.action_assign(cr, uid, confirmed_ids[x:x + 100], context=context) if use_new_cursor: diff --git a/addons/stock/product.py b/addons/stock/product.py index 54353cd010c..0cf7df5e836 100644 --- a/addons/stock/product.py +++ b/addons/stock/product.py @@ -168,9 +168,16 @@ class product_product(osv.osv): res.append(('id', 'in', ids)) return res + def _product_available_text(self, cr, uid, ids, field_names=None, arg=False, context=None): + res = {} + for product in self.browse(cr, uid, ids, context=context): + res[product.id] = str(product.qty_available) + _(" In Stock") + return res + _columns = { 'reception_count': fields.function(_stock_move_count, string="Reception", type='integer', multi='pickings'), 'delivery_count': fields.function(_stock_move_count, string="Delivery", type='integer', multi='pickings'), + 'qty_in_stock': fields.function(_product_available_text, type='char'), 'qty_available': fields.function(_product_available, multi='qty_available', type='float', digits_compute=dp.get_precision('Product Unit of Measure'), string='Quantity On Hand', @@ -222,14 +229,9 @@ class product_product(osv.osv): "any of its children.\n" "Otherwise, this includes goods leaving any Stock " "Location with 'internal' type."), - 'track_incoming': fields.boolean('Track Incoming Lots', help="Forces to specify a Serial Number for all moves containing this product and coming from a Supplier Location"), - 'track_outgoing': fields.boolean('Track Outgoing Lots', help="Forces to specify a Serial Number for all moves containing this product and going to a Customer Location"), - 'track_all': fields.boolean('Full Lots Traceability', help="Forces to specify a Serial Number on each and every operation related to this product"), '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_route_product', 'product_id', 'route_id', 'Routes', domain="[('product_selectable', '=', True)]", - 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): @@ -275,25 +277,52 @@ class product_product(osv.osv): res['fields']['qty_available']['string'] = _('Produced Qty') return res - def action_view_routes(self, cr, uid, ids, context=None): - route_obj = self.pool.get("stock.location.route") - act_obj = self.pool.get('ir.actions.act_window') - mod_obj = self.pool.get('ir.model.data') - product_route_ids = set() - for product in self.browse(cr, uid, ids, context=context): - product_route_ids |= set([r.id for r in product.route_ids]) - product_route_ids |= set([r.id for r in product.categ_id.total_route_ids]) - route_ids = route_obj.search(cr, uid, ['|', ('id', 'in', list(product_route_ids)), ('warehouse_selectable', '=', True)], context=context) - result = mod_obj.get_object_reference(cr, uid, 'stock', 'action_routes_form') - id = result and result[1] or False - result = act_obj.read(cr, uid, [id], context=context)[0] - result['domain'] = "[('id','in',[" + ','.join(map(str, route_ids)) + "])]" - return result - class product_template(osv.osv): _name = 'product.template' _inherit = 'product.template' + + def _product_available(self, cr, uid, ids, name, arg, context=None): + res = dict.fromkeys(ids, 0) + for product in self.browse(cr, uid, ids, context=context): + res[product.id] = { + # "reception_count": sum([p.reception_count for p in product.product_variant_ids]), + # "delivery_count": sum([p.delivery_count for p in product.product_variant_ids]), + "qty_available": sum([p.qty_available for p in product.product_variant_ids]), + "virtual_available": sum([p.virtual_available for p in product.product_variant_ids]), + "incoming_qty": sum([p.incoming_qty for p in product.product_variant_ids]), + "outgoing_qty": sum([p.outgoing_qty for p in product.product_variant_ids]), + } + return res + + def _search_product_quantity(self, cr, uid, obj, name, domain, context): + prod = self.pool.get("product.product") + res = [] + for field, operator, value in domain: + #to prevent sql injections + assert field in ('qty_available', 'virtual_available', 'incoming_qty', 'outgoing_qty'), 'Invalid domain left operand' + assert operator in ('<', '>', '=', '<=', '>='), 'Invalid domain operator' + assert isinstance(value, (float, int)), 'Invalid domain right operand' + + if operator == '=': + operator = '==' + + product_ids = prod.search(cr, uid, [], context=context) + ids = [] + if product_ids: + #TODO: use a query instead of this browse record which is probably making the too much requests, but don't forget + #the context that can be set with a location, an owner... + for element in prod.browse(cr, uid, product_ids, context=context): + if eval(str(element[field]) + operator + str(value)): + ids.append(element.id) + res.append(('product_variant_ids', 'in', ids)) + return res + _columns = { + 'valuation':fields.selection([('manual_periodic', 'Periodical (manual)'), + ('real_time','Real Time (automated)'),], 'Inventory Valuation', + help="If real-time valuation is enabled for a product, the system will automatically write journal entries corresponding to stock moves." \ + "The inventory variation account set on the product category will represent the current inventory value, and the stock input and stock output account will hold the counterpart moves for incoming and outgoing products." + , required=True), 'type': fields.selection([('product', 'Stockable Product'), ('consu', 'Consumable'), ('service', 'Service')], 'Product Type', required=True, help="Consumable: Will not imply stock management for this product. \nStockable product: Will imply stock management for this product."), 'property_stock_procurement': fields.property( type='many2one', @@ -317,12 +346,47 @@ class product_template(osv.osv): 'loc_rack': fields.char('Rack', size=16), 'loc_row': fields.char('Row', size=16), 'loc_case': fields.char('Case', size=16), + 'track_incoming': fields.boolean('Track Incoming Lots', help="Forces to specify a Serial Number for all moves containing this product and coming from a Supplier Location"), + 'track_outgoing': fields.boolean('Track Outgoing Lots', help="Forces to specify a Serial Number for all moves containing this product and going to a Customer Location"), + 'track_all': fields.boolean('Full Lots Traceability', help="Forces to specify a Serial Number on each and every operation related to this product"), + + # sum of product variant qty + # 'reception_count': fields.function(_product_available, multi='qty_available', + # fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), + # 'delivery_count': fields.function(_product_available, multi='qty_available', + # fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), + 'qty_available': fields.function(_product_available, multi='qty_available', + fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), + 'virtual_available': fields.function(_product_available, multi='qty_available', + fnct_search=_search_product_quantity, type='float', string='Quantity Available'), + 'incoming_qty': fields.function(_product_available, multi='qty_available', + fnct_search=_search_product_quantity, type='float', string='Incoming'), + 'outgoing_qty': fields.function(_product_available, multi='qty_available', + fnct_search=_search_product_quantity, type='float', string='Outgoing'), + + 'route_ids': fields.many2many('stock.location.route', 'stock_route_product', 'product_id', 'route_id', 'Routes', domain="[('product_selectable', '=', True)]", + 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,..."), } _defaults = { 'sale_delay': 7, + 'valuation': 'manual_periodic', } + def action_view_routes(self, cr, uid, ids, context=None): + route_obj = self.pool.get("stock.location.route") + act_obj = self.pool.get('ir.actions.act_window') + mod_obj = self.pool.get('ir.model.data') + product_route_ids = set() + for product in self.browse(cr, uid, ids, context=context): + product_route_ids |= set([r.id for r in product.route_ids]) + product_route_ids |= set([r.id for r in product.categ_id.total_route_ids]) + route_ids = route_obj.search(cr, uid, ['|', ('id', 'in', list(product_route_ids)), ('warehouse_selectable', '=', True)], context=context) + result = mod_obj.get_object_reference(cr, uid, 'stock', 'action_routes_form') + id = result and result[1] or False + result = act_obj.read(cr, uid, [id], context=context)[0] + result['domain'] = "[('id','in',[" + ','.join(map(str, route_ids)) + "])]" + return result class product_removal_strategy(osv.osv): _name = 'product.removal' diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml index aaecf4e48e2..b482f2aeab3 100644 --- a/addons/stock/product_view.xml +++ b/addons/stock/product_view.xml @@ -2,70 +2,17 @@ - - product.search.stock.form - product.product - - - - - - - - - - - - - - - - - product.stock.tree.inherit product.product - - - - - {'red':virtual_available<0, 'blue':virtual_available>=0 and state in ('draft', 'end', 'obsolete'), 'black':virtual_available>=0 and state not in ('draft', 'end', 'obsolete')} - - - - - product.template.stock.property.form.inherit - product.template - - - - - - - - - - - - - - - - - - - - {'default_groups_ref': ['base.group_user', 'base.group_sale_manager', 'stock.group_stock_manager']} - + + + @@ -109,12 +56,117 @@
+ + + + product.template.search.stock.form + product.template + + + + + + + + + + + + + + + + + product.template.stock.property.form.inherit + product.template + + + + + + + + + + + + + + + + + + + + + + + + {'default_groups_ref': ['base.group_user', 'base.group_sale_manager', 'stock.group_stock_manager']} + + + +