############################################################################## # # Copyright (c) 2005 TINY SPRL. (http://tiny.be) All Rights Reserved. # # $Id: mrp.py 1292 2005-09-08 03:26:33Z pinky $ # # WARNING: This program as such is intended to be used by professional # programmers who take the whole responsability of assessing all potential # consequences resulting from its eventual inadequacies and bugs # End users who are looking for a ready-to-use solution with commercial # garantees and support are strongly adviced to contract a Free Software # Service Company # # This program is Free Software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## from osv import fields from osv import osv import ir import netsvc import time from mx import DateTime #---------------------------------------------------------- # Workcenters #---------------------------------------------------------- # capacity_hour : capacity per hour. default: 1.0. # Eg: If 5 concurrent operations at one time: capacity = 5 (because 5 employees) # unit_per_cycle : how many units are produced for one cycle # # TODO: Work Center may be recursive ? # class mrp_workcenter(osv.osv): _name = 'mrp.workcenter' _description = 'Workcenter' _columns = { 'name': fields.char('Name', size=64, required=True), 'active': fields.boolean('Active'), 'type': fields.selection([('machine','Machine'),('hr','Human Ressource'),('tool','Tool')], 'Type', required=True), 'code': fields.char('Code', size=8), 'timesheet_id': fields.many2one('hr.timesheet', 'Timesheet'), 'note': fields.text('Description'), 'capacity_per_cycle': fields.float('Capacity per Cycle'), 'time_cycle': fields.float('Time for 1 cycle (hour)'), 'time_start': fields.float('Time before prod.'), 'time_stop': fields.float('Time after prod.'), 'time_efficiency': fields.float('Time Efficiency'), 'costs_hour': fields.float('Cost per hour'), 'costs_hour_account_id': fields.many2one('account.account', 'Hour Account', domain=[('type','=','expense')]), 'costs_cycle': fields.float('Cost per cycle'), 'costs_cycle_account_id': fields.many2one('account.account', 'Cycle Account', domain=[('type','=','expense')]), 'project_id': fields.many2one('account.project', 'Profit/Cost center') } _defaults = { 'active': lambda *a: 1, 'type': lambda *a: 'machine', 'time_efficiency': lambda *a: 1.0, 'capacity_per_cycle': lambda *a: 1.0, } mrp_workcenter() class mrp_property_group(osv.osv): _name = 'mrp.property.group' _description = 'Property Group' _columns = { 'name': fields.char('Property Group', size=64, required=True), 'description': fields.text('Description'), } mrp_property_group() class mrp_property(osv.osv): _name = 'mrp.property' _description = 'Property' _columns = { 'name': fields.char('Name', size=64, required=True), 'composition': fields.selection([('min','min'),('max','max'),('plus','plus')], 'Properties composition', required=True), 'group_id': fields.many2one('mrp.property.group', 'Property Group', required=True), 'description': fields.text('Description'), } _defaults = { 'composition': lambda *a: 'min', } mrp_property() class mrp_routing(osv.osv): _name = 'mrp.routing' _description = 'Routing' _columns = { 'name': fields.char('Name', size=64, required=True), 'active': fields.boolean('Active'), 'code': fields.char('Code', size=8), 'note': fields.text('Description'), 'workcenter_lines': fields.one2many('mrp.routing.workcenter', 'routing_id', 'Workcenters'), 'location_id': fields.many2one('stock.location', 'Production Location'), } _defaults = { 'active': lambda *a: 1, } mrp_routing() class mrp_routing_workcenter(osv.osv): _name = 'mrp.routing.workcenter' _description = 'Routing workcenter usage' _columns = { 'workcenter_id': fields.many2one('mrp.workcenter', 'Workcenter', required=True), 'name': fields.char('Name', size=64, required=True), 'sequence': fields.integer('Sequence'), 'cycle_nbr': fields.float('Number of cycle', required=True), 'hour_nbr': fields.float('Number of hours', required=True), 'routing_id': fields.many2one('mrp.routing', 'Parent Routing'), 'note': fields.text('Description') } _defaults = { 'cycle_nbr': lambda *a: 1.0, 'hour_nbr': lambda *a: 0.0, } mrp_routing_workcenter() class mrp_bom(osv.osv): _name = 'mrp.bom' _description = 'Bill of Material' _columns = { 'name': fields.char('Name', size=64, required=True), 'code': fields.char('Code', size=16), 'active': fields.boolean('Active'), 'type': fields.selection([('normal','Normal BOM'),('phantom','Phantom')],'BOM Type',required=True), 'date_start': fields.date('Valid from'), 'date_stop': fields.date('Valid until'), 'sequence': fields.integer('Sequence'), 'position': fields.char('Internal Ref.', size=64), 'product_id': fields.many2one('product.product', 'Product', required=True, domain=[('type','=','product')]), 'product_qty': fields.float('Product Qty', required=True), 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True), 'product_rounding': fields.float('Product Rounding'), 'product_efficiency': fields.float('Product Efficiency', required=True), 'bom_lines': fields.one2many('mrp.bom', 'bom_id', 'BOM Lines'), 'bom_id': fields.many2one('mrp.bom', 'Parent BOM'), 'routing_id': fields.many2one('mrp.routing', 'Routing'), 'property_ids': fields.many2many('mrp.property', 'mrp_bom_property_rel', 'bom_id','property_id', 'Properties'), 'revision_ids': fields.one2many('mrp.bom.revision', 'bom_id', 'BOM Revisions'), 'revision_type': fields.selection([('numeric','numeric indices'),('alpha','alphabetical indices')], 'indice type') } _defaults = { 'active': lambda *a: 1, 'product_efficiency': lambda *a: 1.0, 'product_qty': lambda *a: 1.0, 'product_rounding': lambda *a: 1.0, 'type': lambda *a: 'normal', } _order = "sequence" def onchange_product_id(self, cr, uid, ids, product_id, name, context={}): if product_id: prod=self.pool.get('product.product').browse(cr,uid,[product_id])[0] v = {'product_uom':prod.uom_id.id} if not name: v['name'] = prod.name return {'value': v} return {} def _bom_find(self, cr, uid, product_id, product_uom, properties = []): bom_result = False cr.execute('select id from mrp_bom where product_id=%d and bom_id is null order by sequence', (product_id,)) ids = map(lambda x: x[0], cr.fetchall()) max_prop = 0 result = False for bom in self.pool.get('mrp.bom').browse(cr, uid, ids): prop = 0 for prop_id in bom.property_ids: if prop_id.id in properties: prop+=1 if (prop>max_prop) or ((max_prop==0) and not result): result = bom.id return result def _bom_explode(self, cr, uid, bom, factor, properties, addthis=False, level=10): factor = factor / (bom.product_efficiency or 1.0) factor = rounding(factor, bom.product_rounding) if factor 'done'): self.pool.get('stock.move').action_done(cr, uid, [procurement.move_id.id]) return self.write(cr, uid, ids, {'state':'done', 'date_close':time.strftime('%Y-%m-%d')}) mrp_procurement() class stock_warehouse_orderpoint(osv.osv): _name = "stock.warehouse.orderpoint" _description = "Warehouse Orderpoint" _columns = { 'name': fields.char('Name', size=32, required=True), 'active': fields.boolean('Active'), 'logic': fields.selection([('max','Order to Max'),('price','Best price (not yet active!)')], 'Reordering Mode', required=True), 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', required=True ), 'product_id': fields.many2one('product.product', 'Product', required=True, domain=[('type','=','product')] ), 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True ), 'product_min_qty': fields.float('Min Quantity', required=True), 'product_max_qty': fields.float('Max Quantity', required=True), 'product_max_qty': fields.float('Max Quantity', required=True), 'qty_multiple': fields.integer('Qty Multiple', required=True), 'procurement_id': fields.many2one('mrp.procurement', 'Purchase Order') } _defaults = { 'active': lambda *a: 1, 'logic': lambda *a: 'max', 'qty_multiple': lambda *a: 1 } def onchange_product_id(self, cr, uid, ids, product_id, context={}): if product_id: prod=self.pool.get('product.product').browse(cr,uid,[product_id])[0] v = {'product_uom':prod.uom_id.id} return {'value': v} return {} stock_warehouse_orderpoint()