From 4e634e7668e29fe008e7abbc529872d2dcc8b89f Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 22 Sep 2008 07:56:30 +0200 Subject: [PATCH 01/21] tooltips bzr revid: fp@tinyerp.com-20080922055630-uqzvzyz8ws260omr --- addons/account/partner.py | 4 +- addons/product/pricelist.py | 32 +++++++------- addons/product/product.py | 53 ++++++++++++------------ addons/profile_manufacturing/__terp__.py | 2 +- addons/stock/product.py | 8 ++-- 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/addons/account/partner.py b/addons/account/partner.py index ef68a12de48..c1eac82b99c 100644 --- a/addons/account/partner.py +++ b/addons/account/partner.py @@ -86,8 +86,8 @@ class res_partner(osv.osv): return [('id','in',map(lambda x:x[0], res))] _columns = { - 'credit': fields.function(_credit_debit_get, fnct_search=_credit_search, method=True, string='Total Receivable', multi='dc'), - 'debit': fields.function(_credit_debit_get, fnct_search=_debit_search, method=True, string='Total Payable', multi='dc'), + 'credit': fields.function(_credit_debit_get, fnct_search=_credit_search, method=True, string='Total Receivable', multi='dc', help="Total amount this customer owns you."), + 'debit': fields.function(_credit_debit_get, fnct_search=_debit_search, method=True, string='Total Payable', multi='dc', help="Total amount you have to pay to this supplier."), 'debit_limit': fields.float('Payable Limit'), 'property_account_payable': fields.property( 'account.account', diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index e5d52cbb632..927a185251b 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -56,10 +56,10 @@ class price_type(osv.osv): _name = "product.price.type" _description = "Price type" _columns = { - "name" : fields.char("Price Name", size=32, required=True, translate=True) , + "name" : fields.char("Price Name", size=32, required=True, translate=True, help="Name of this kinf of price."), "active" : fields.boolean("Active"), - "field" : fields.selection(_price_field_get, "Product Field", required=True), - "currency_id" : fields.many2one('res.currency', "Currency", required=True), + "field" : fields.selection(_price_field_get, "Product Field", required=True, help="Associated field in the product form."), + "currency_id" : fields.many2one('res.currency', "Currency", required=True, help="Associated currency."), } _defaults = { "active": lambda *args: True, @@ -76,7 +76,7 @@ class product_pricelist_type(osv.osv): _description = "Pricelist Type" _columns = { 'name': fields.char('Name',size=64, required=True), - 'key': fields.char('Key', size=64, required=True), + 'key': fields.char('Key', size=64, required=True, help="Used in the code to select specific prices based on the context. Keep unchanged."), } product_pricelist_type() @@ -88,7 +88,7 @@ class product_pricelist(osv.osv): _name = "product.pricelist" _description = "Pricelist" _columns = { - 'name': fields.char('Name',size=64, required=True, translate=True), + 'name': fields.char('Pricelist Name',size=64, required=True, translate=True), 'active': fields.boolean('Active'), 'type': fields.selection(_pricelist_type_get, 'Pricelist Type', required=True), 'version_id': fields.one2many('product.pricelist.version', 'pricelist_id', 'Pricelist Versions'), @@ -247,8 +247,8 @@ class product_pricelist_version(osv.osv): 'active': fields.boolean('Active'), 'items_id': fields.one2many('product.pricelist.item', 'price_version_id', 'Price List Items', required=True), - 'date_start': fields.date('Start Date'), - 'date_end': fields.date('End Date'), + 'date_start': fields.date('Start Date', help="Starting date for validity of this pricelist version."), + 'date_end': fields.date('End Date', help="Ending date for validity of this pricelist version."), } _defaults = { 'active': lambda *a: 1, @@ -320,22 +320,26 @@ class product_pricelist_item(osv.osv): 'price_discount': lambda *a: 0, } _columns = { - 'name': fields.char('Name', size=64), + 'name': fields.char('Rule Name', size=64, help="Explicit rule name for this pricelist line."), 'price_version_id': fields.many2one('product.pricelist.version', 'Price List Version', required=True, select=True), - 'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade'), - 'product_id': fields.many2one('product.product', 'Product', ondelete='cascade'), - 'categ_id': fields.many2one('product.category', 'Product Category', ondelete='cascade'), + 'product_tmpl_id': fields.many2one('product.template', 'Product Template', ondelete='cascade', help="Set a template if this rule only apply to a template of product. Keep empty for all products"), + 'product_id': fields.many2one('product.product', 'Product', ondelete='cascade', help="Set a product if this rule only apply to one product. Keep empty for all products"), + 'categ_id': fields.many2one('product.category', 'Product Category', ondelete='cascade', help="Set a category of product if this rule only apply to products of a category and his childs. Keep empty for all products"), - 'min_quantity': fields.integer('Min. Quantity', required=True), + 'min_quantity': fields.integer('Min. Quantity', required=True, help="The rule only apply if the partner buys/sells more than this quantity."), 'sequence': fields.integer('Sequence', required=True), - 'base': fields.selection(_price_field_get, 'Based on', required=True, size=-1), + 'base': fields.selection(_price_field_get, 'Based on', required=True, size=-1, help="The mode of computation of the price for this rule."), 'base_pricelist_id': fields.many2one('product.pricelist', 'If Other Pricelist'), 'price_surcharge': fields.float('Price Surcharge', digits=(16, int(config['price_accuracy']))), 'price_discount': fields.float('Price Discount', digits=(16,4)), 'price_round': fields.float('Price Rounding', - digits=(16, int(config['price_accuracy']))), + digits=(16, int(config['price_accuracy'])), + help="Sets the price so that it is a multiple of this value.\n" \ + "Rounding is applied after the discount and before the surcharge.\n" \ + "To have prices that ends by 9.99, set rounding 10, surcharge -0.01" \ + ), 'price_min_margin': fields.float('Price Min. Margin', digits=(16, int(config['price_accuracy']))), 'price_max_margin': fields.float('Price Max. Margin', diff --git a/addons/product/product.py b/addons/product/product.py index 965974f6160..bdd0b5f35b1 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -250,20 +250,21 @@ class product_template(osv.osv): '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 refurnishing. 'Make to Order': When needed, purchase or produce for the procurement request."), 'rental': fields.boolean('Rentable product'), 'categ_id': fields.many2one('product.category','Category', required=True, change_default=True), - 'list_price': fields.float('Sale Price', digits=(16, int(config['price_accuracy']))), - 'standard_price': fields.float('Cost Price', required=True, digits=(16, int(config['price_accuracy']))), + 'list_price': fields.float('Sale Price', digits=(16, int(config['price_accuracy'])), help="Base price for computing the customer price. Sometimes called the catalog price."), + 'standard_price': fields.float('Cost Price', required=True, digits=(16, int(config['price_accuracy'])), help="The cost of the product for accounting stock valorisation. It can serves as a base price for supplier price."), 'volume': fields.float('Volume', help="The weight in Kg."), 'weight': fields.float('Gross weight'), 'weight_net': fields.float('Net weight'), - 'cost_method': fields.selection([('standard','Standard Price'), ('average','Average Price')], 'Costing Method', required=True), + 'cost_method': fields.selection([('standard','Standard Price'), ('average','Average Price')], 'Costing Method', required=True, + help="Standard Price: the cost price is fixed and recomputed periodically (usually at the end of the year), Average Price: the cost price is recomputed at each reception of products."), 'warranty': fields.float('Warranty (months)'), 'sale_ok': fields.boolean('Can be sold', help="Determine if the product can be visible in the list of product within a selection from a sale order line."), 'purchase_ok': fields.boolean('Can be Purchased', help="Determine if the product is visible in the list of products within a selection from a purchase order line."), - 'uom_id': fields.many2one('product.uom', 'Default UoM', required=True, help="This is the default Unit of Measure used for all stock operation."), - 'uom_po_id': fields.many2one('product.uom', 'Purchase UoM', required=True), + 'uom_id': fields.many2one('product.uom', 'Default UoM', required=True, help="Default Unit of Measure used for all stock operation."), + 'uom_po_id': fields.many2one('product.uom', 'Purchase UoM', required=True, help="Default Unit of Measure used for purchase orders. It must in the same category than the default unit of measure."), 'state': fields.selection([('',''),('draft', 'In Development'),('sellable','In Production'),('end','End of Lifecycle'),('obsolete','Obsolete')], 'Status', help="Tells the user if he can use the product or not."), 'uos_id' : fields.many2one('product.uom', 'Unit of Sale', - help='Keep empty to use the default UOM'), + help='Used by companies that manages two unit of measure: invoicing and stock management. For example, in food industries, you will manage a stock of ham but invoice in Kg. Keep empty to use the default UOM.'), 'uos_coeff': fields.float('UOM -> UOS Coeff', digits=(16,4), help='Coefficient to convert UOM to UOS\n' ' uom = uos * coeff'), @@ -412,7 +413,7 @@ class product_product(osv.osv): 'variants': fields.char('Variants', size=64), 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True), 'ean13': fields.char('EAN13', size=13), - 'packaging' : fields.one2many('product.packaging', 'product_id', 'Palettization', help="Gives the different ways to package the same product. This has no impact on the packing order and is mainly used if you use the EDI module."), + 'packaging' : fields.one2many('product.packaging', 'product_id', 'Logistical Units', help="Gives the different ways to package the same product. This has no impact on the packing order and is mainly used if you use the EDI module."), 'price_extra': fields.float('Variant Price Extra', digits=(16, int(config['price_accuracy']))), 'price_margin': fields.float('Variant Price Margin', digits=(16, int(config['price_accuracy']))), } @@ -526,28 +527,28 @@ product_product() class product_packaging(osv.osv): _name = "product.packaging" - _description = "Conditionnement" + _description = "Packaging" _rec_name = 'ean' _columns = { 'name' : fields.char('Description', size=64), - 'qty' : fields.float('Quantity by UL', - help="The total number of products you can put by UL."), - 'ul' : fields.many2one('product.ul', 'Type of UL', required=True), - 'ul_qty' : fields.integer('UL by layer'), - 'rows' : fields.integer('Number of layer', required=True, - help='The number of layer on palette'), + 'qty' : fields.float('Quantity by Package', + help="The total number of products you can put by palet or box."), + 'ul' : fields.many2one('product.ul', 'Type of Package', required=True), + 'ul_qty' : fields.integer('Package by layer'), + 'rows' : fields.integer('Number of Layer', required=True, + help='The number of layer on a palet or box'), 'product_id' : fields.many2one('product.product', 'Product', select=1, ondelete='cascade', required=True), 'ean' : fields.char('EAN', size=14, - help="The EAN code of the transport unit."), + help="The EAN code of the package unit."), 'code' : fields.char('Code', size=14, help="The code of the transport unit."), - 'weight': fields.float('Palette Weight', - help='The weight of the empty palette'), - 'weight_ul': fields.float('UL Weight', + 'weight': fields.float('Total Package Weight', + help='The weight of a full of products palet or box.'), + 'weight_ul': fields.float('Empty Package Weight', help='The weight of the empty UL'), - 'height': fields.float('Height', help='The height of the palette'), - 'width': fields.float('Width', help='The width of the palette'), - 'length': fields.float('Length', help='The length of the palette'), + 'height': fields.float('Height', help='The height of the package'), + 'width': fields.float('Width', help='The width of the package'), + 'length': fields.float('Length', help='The length of the package'), } def _get_1st_ul(self, cr, uid, context={}): @@ -575,13 +576,13 @@ class product_supplierinfo(osv.osv): _name = "product.supplierinfo" _description = "Information about a product supplier" _columns = { - 'name' : fields.many2one('res.partner', 'Partner', required=True, ondelete='cascade'), - 'product_name': fields.char('Partner product name', size=128), - 'product_code': fields.char('Partner product reference', size=64), + 'name' : fields.many2one('res.partner', 'Partner', required=True, ondelete='cascade', help="Supplier of this product"), + 'product_name': fields.char('Partner Product Name', size=128, help="Name of the product for this partner, will be used when printing a request for quotation. Keep empty to use the internal one."), + 'product_code': fields.char('Partner Product Code', size=64, help="Code of the product for this partner, will be used when printing a request for quotation. Keep empty to use the internal one."), 'sequence' : fields.integer('Priority'), - 'qty' : fields.float('Minimal quantity', required=True), + 'qty' : fields.float('Minimal Quantity', required=True, help="The minimal quantity to purchase for this supplier, expressed in the default unit of measure."), 'product_id' : fields.many2one('product.template', 'Product', required=True, ondelete='cascade', select=True), - 'delay' : fields.integer('Delivery delay', required=True), + 'delay' : fields.integer('Delivery Delay', required=True, help="Delay in days between the confirmation of the purchase order and the reception of the products in your warehouse. Used by the scheduler for automatic computation of the purchase order planning."), 'pricelist_ids': fields.one2many('pricelist.partnerinfo', 'suppinfo_id', 'Supplier Pricelist'), } _defaults = { diff --git a/addons/profile_manufacturing/__terp__.py b/addons/profile_manufacturing/__terp__.py index 40479ffc38f..92ea4224877 100644 --- a/addons/profile_manufacturing/__terp__.py +++ b/addons/profile_manufacturing/__terp__.py @@ -31,7 +31,7 @@ "version":"1.0", "author":"Tiny", "category":"Profile", - "depends":["mrp", "crm", "sale", "delivery","board_manufacturing"], + "depends":["mrp", "sale", "delivery","board_manufacturing"], "demo_xml":[], "update_xml":[ "security/ir.model.access.csv", diff --git a/addons/stock/product.py b/addons/stock/product.py index 342e7af1546..f66e41acd4a 100644 --- a/addons/stock/product.py +++ b/addons/stock/product.py @@ -77,10 +77,10 @@ class product_product(osv.osv): _product_outgoing_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('out',)) _product_incoming_qty = _get_product_available_func(('confirmed','waiting','assigned'), ('in',)) _columns = { - 'qty_available': fields.function(_product_qty_available, method=True, type='float', string='Real Stock'), - 'virtual_available': fields.function(_product_virtual_available, method=True, type='float', string='Virtual Stock'), - 'incoming_qty': fields.function(_product_incoming_qty, method=True, type='float', string='Incoming'), - 'outgoing_qty': fields.function(_product_outgoing_qty, method=True, type='float', string='Outgoing'), + 'qty_available': fields.function(_product_qty_available, method=True, type='float', string='Real Stock', help="Current quantities of products in selected locations or all internal if none have been selected."), + 'virtual_available': fields.function(_product_virtual_available, method=True, type='float', string='Virtual Stock', help="Futur stock for this product according to the selected location or all internal if none have been selected. Computed as: Real Stock - Outgoing + Incoming."), + 'incoming_qty': fields.function(_product_incoming_qty, method=True, type='float', string='Incoming', help="Quantities of products that are planned to arrive in selected locations or all internal if none have been selected."), + 'outgoing_qty': fields.function(_product_outgoing_qty, method=True, type='float', string='Outgoing', help="Quantities of products that are planned to leave in selected locations or all internal if none have been selected."), 'track_production' : fields.boolean('Track Production Lots' , help="Force to use a Production Lot during production order"), 'track_incoming' : fields.boolean('Track Incomming Lots', help="Force to use a Production Lot during receptions"), 'track_outgoing' : fields.boolean('Track Outging Lots', help="Force to use a Production Lot during deliveries"), From 172b81981226e1698dd64fd41d35114393cbb101 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 22 Sep 2008 08:06:56 +0200 Subject: [PATCH 02/21] tooltips bzr revid: fp@tinyerp.com-20080922060656-bl3w7h6uez38ktka --- addons/account/invoice.py | 22 +++++++++++----------- addons/product/pricelist.py | 4 ++-- addons/product/product.py | 6 ++++-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/addons/account/invoice.py b/addons/account/invoice.py index a6d39d42f10..8d23f8312e5 100644 --- a/addons/account/invoice.py +++ b/addons/account/invoice.py @@ -148,7 +148,7 @@ class account_invoice(osv.osv): _order = "number" _columns = { 'name': fields.char('Description', size=64, select=True,readonly=True, states={'draft':[('readonly',False)]}), - 'origin': fields.char('Origin', size=64), + 'origin': fields.char('Origin', size=64, help="Reference of the document that produced this invoice."), 'type': fields.selection([ ('out_invoice','Customer Invoice'), ('in_invoice','Supplier Invoice'), @@ -156,8 +156,8 @@ class account_invoice(osv.osv): ('in_refund','Supplier Refund'), ],'Type', readonly=True, select=True), - 'number': fields.char('Invoice Number', size=32, readonly=True), - 'reference': fields.char('Invoice Reference', size=64), + 'number': fields.char('Invoice Number', size=32, readonly=True, help="Uniq number of the invoice, computed automatically when the invoice is created."), + 'reference': fields.char('Invoice Reference', size=64, help="The partner reference of this invoice."), 'reference_type': fields.selection(_get_reference_type, 'Reference Type', required=True), 'comment': fields.text('Additionnal Information'), @@ -181,11 +181,11 @@ class account_invoice(osv.osv): 'period_id': fields.many2one('account.period', 'Force Period', help="Keep empty to use the period of the validation date."), - 'account_id': fields.many2one('account.account', 'Account', required=True, readonly=True, states={'draft':[('readonly',False)]}), + 'account_id': fields.many2one('account.account', 'Account', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="The partner account used for this invoice."), 'invoice_line': fields.one2many('account.invoice.line', 'invoice_id', 'Invoice Lines', readonly=True, states={'draft':[('readonly',False)]}), 'tax_line': fields.one2many('account.invoice.tax', 'invoice_id', 'Tax Lines', readonly=True, states={'draft':[('readonly',False)]}), - 'move_id': fields.many2one('account.move', 'Invoice Movement', readonly=True), + 'move_id': fields.many2one('account.move', 'Invoice Movement', readonly=True, help="Link to the automatically generated account moves."), 'amount_untaxed': fields.function(_amount_untaxed, method=True, digits=(16,2),string='Untaxed', store=True), 'amount_tax': fields.function(_amount_tax, method=True, digits=(16,2), string='Tax', store=True), 'amount_total': fields.function(_amount_total, method=True, digits=(16,2), string='Total', store=True), @@ -193,11 +193,11 @@ class account_invoice(osv.osv): 'journal_id': fields.many2one('account.journal', 'Journal', required=True,readonly=True, states={'draft':[('readonly',False)]}), 'company_id': fields.many2one('res.company', 'Company', required=True), 'check_total': fields.float('Total', digits=(16,2), states={'open':[('readonly',True)],'close':[('readonly',True)]}), - 'reconciled': fields.function(_reconciled, method=True, string='Paid/Reconciled', type='boolean'), + 'reconciled': fields.function(_reconciled, method=True, string='Paid/Reconciled', type='boolean', help="The account moves of the invoice have been reconciled with account moves of the payment(s)."), 'partner_bank': fields.many2one('res.partner.bank', 'Bank Account', help='The bank account to pay to or to be paid from'), 'move_lines':fields.function(_get_lines , method=True,type='many2many' , relation='account.move.line',string='Move Lines'), - 'residual': fields.function(_amount_residual, method=True, digits=(16,2),string='Residual', store=True), + 'residual': fields.function(_amount_residual, method=True, digits=(16,2),string='Residual', store=True, help="Remaining amount due."), 'payment_ids': fields.function(_compute_lines, method=True, relation='account.move.line', type="many2many", string='Payments'), } _defaults = { @@ -815,9 +815,9 @@ class account_invoice_line(osv.osv): _columns = { 'name': fields.char('Description', size=256, required=True), 'invoice_id': fields.many2one('account.invoice', 'Invoice Ref', ondelete='cascade', select=True), - 'uos_id': fields.many2one('product.uom', 'Unit', ondelete='set null'), + 'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'), 'product_id': fields.many2one('product.product', 'Product', ondelete='set null'), - 'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')]), + 'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."), 'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))), 'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal',store=True), 'quantity': fields.float('Quantity', required=True), @@ -983,9 +983,9 @@ class account_invoice_tax(osv.osv): 'manual': fields.boolean('Manual'), 'sequence': fields.integer('Sequence'), - 'base_code_id': fields.many2one('account.tax.code', 'Base Code'), + 'base_code_id': fields.many2one('account.tax.code', 'Base Code', help="The case of the tax declaration."), 'base_amount': fields.float('Base Code Amount', digits=(16,2)), - 'tax_code_id': fields.many2one('account.tax.code', 'Tax Code'), + 'tax_code_id': fields.many2one('account.tax.code', 'Tax Code', help="The case of the tax declaration."), 'tax_amount': fields.float('Tax Code Amount', digits=(16,2)), } def base_change(self, cr, uid, ids, base): diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index 927a185251b..3d597f45a8c 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -56,10 +56,10 @@ class price_type(osv.osv): _name = "product.price.type" _description = "Price type" _columns = { - "name" : fields.char("Price Name", size=32, required=True, translate=True, help="Name of this kinf of price."), + "name" : fields.char("Price Name", size=32, required=True, translate=True, help="Name of this kind of price."), "active" : fields.boolean("Active"), "field" : fields.selection(_price_field_get, "Product Field", required=True, help="Associated field in the product form."), - "currency_id" : fields.many2one('res.currency', "Currency", required=True, help="Associated currency."), + "currency_id" : fields.many2one('res.currency', "Currency", required=True, help="The currency the field is expressed in."), } _defaults = { "active": lambda *args: True, diff --git a/addons/product/product.py b/addons/product/product.py index bdd0b5f35b1..671433bd0fe 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -87,7 +87,8 @@ class product_uom(osv.osv): _columns = { 'name': fields.char('Name', size=64, required=True), - 'category_id': fields.many2one('product.uom.categ', 'UOM Category', required=True, ondelete='cascade'), + 'category_id': fields.many2one('product.uom.categ', 'UoM Category', required=True, ondelete='cascade', + help="Unit of Measure of the same category can be converted between each others."), 'factor': fields.float('Rate', digits=(12, 6), required=True, help='The coefficient for the formula:\n' \ '1 (base unit) = coef (this unit)'), @@ -96,7 +97,8 @@ class product_uom(osv.osv): help='The coefficient for the formula:\n' \ 'coef (base unit) = 1 (this unit)'), 'factor_inv_data': fields.float('Factor', digits=(12, 6)), - 'rounding': fields.float('Rounding Precision', digits=(16, 3), required=True), + 'rounding': fields.float('Rounding Precision', digits=(16, 3), required=True, + help="The computed quantity will be a multiple of this value. Use 1.0 for products that can not be splitted."), 'active': fields.boolean('Active'), } From f2209f5e12ca7cd7d360ee8b6c2d5f9854b67af4 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 22 Sep 2008 08:19:37 +0200 Subject: [PATCH 03/21] tooltips bzr revid: fp@tinyerp.com-20080922061937-6gundahvs6ihc8fp --- addons/mrp/mrp.py | 60 +++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index bb6684ca04f..170cefd6fbc 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -49,26 +49,28 @@ class mrp_workcenter(osv.osv): _name = 'mrp.workcenter' _description = 'Workcenter' _columns = { - 'name': fields.char('Name', size=64, required=True), + 'name': fields.char('Workcenter Name', size=64, required=True), 'active': fields.boolean('Active'), 'type': fields.selection([('machine','Machine'),('hr','Human Resource'),('tool','Tool')], 'Type', required=True), - 'code': fields.char('Code', size=8), - 'timesheet_id': fields.many2one('hr.timesheet.group', 'Timesheet'), - 'note': fields.text('Description'), + 'code': fields.char('Code', size=16), + 'timesheet_id': fields.many2one('hr.timesheet.group', 'Working Time', help="The normal working time of the workcenter."), + 'note': fields.text('Description', help="Description of the workcenter. Explain here what's a cycle according to this workcenter."), - 'capacity_per_cycle': fields.float('Capacity per Cycle'), + 'capacity_per_cycle': fields.float('Capacity per Cycle', help="Number of operation this workcenter can do in parallel. If this workcenter represent a team of 5 workers, the capacity per cycle is 5."), - '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'), + 'time_cycle': fields.float('Time for 1 cycle (hour)', help="Time in hours for doing one cycle."), + 'time_start': fields.float('Time before prod.', help="Time in hours for the setup."), + 'time_stop': fields.float('Time after prod.', help="Time in hours for the cleaning."), + 'time_efficiency': fields.float('Time Efficiency', help="Factor that multiplies all times expressed in the workcenter."), 'costs_hour': fields.float('Cost per hour'), - 'costs_hour_account_id': fields.many2one('account.analytic.account', 'Hour Account', domain=[('type','=','expense')]), + 'costs_hour_account_id': fields.many2one('account.analytic.account', 'Hour Account', domain=[('type','<>','view')], + help="Complete this only if you want automatic analytic accounting entries on production orders."), 'costs_cycle': fields.float('Cost per cycle'), - 'costs_cycle_account_id': fields.many2one('account.analytic.account', 'Cycle Account', domain=[('type','=','expense')]), + 'costs_cycle_account_id': fields.many2one('account.analytic.account', 'Cycle Account', domain=[('type','<>','view')], + help="Complete this only if you want automatic analytic accounting entries on production orders."), 'costs_journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal'), - 'costs_general_account_id': fields.many2one('account.account', 'General Account'), + 'costs_general_account_id': fields.many2one('account.account', 'General Account', domain=[('type','<>','view')]), } _defaults = { 'active': lambda *a: 1, @@ -93,7 +95,7 @@ class mrp_property(osv.osv): _description = 'Property' _columns = { 'name': fields.char('Name', size=64, required=True), - 'composition': fields.selection([('min','min'),('max','max'),('plus','plus')], 'Properties composition', required=True), + 'composition': fields.selection([('min','min'),('max','max'),('plus','plus')], 'Properties composition', required=True, help="Not used in computations, for information purpose only."), 'group_id': fields.many2one('mrp.property.group', 'Property Group', required=True), 'description': fields.text('Description'), } @@ -113,7 +115,11 @@ class mrp_routing(osv.osv): 'note': fields.text('Description'), 'workcenter_lines': fields.one2many('mrp.routing.workcenter', 'routing_id', 'Workcenters'), - 'location_id': fields.many2one('stock.location', 'Production Location'), + 'location_id': fields.many2one('stock.location', 'Production Location', + help="Keep empty if you produce at the location where the finnished products are needed." \ + "Put a location if you produce at a fixed location. This can be a partner location " \ + "if you subcontract the manufacturing operations." + ), } _defaults = { 'active': lambda *a: 1, @@ -127,8 +133,8 @@ class mrp_routing_workcenter(osv.osv): '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), + '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', select=True), 'note': fields.text('Description') } @@ -145,11 +151,11 @@ class mrp_bom(osv.osv): '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','Sets / Phantom')], 'BoM Type', required=True, help="Use a phantom bill of material in lines that have a sub-bom and that have to be automatically computed in one line, without habing two production orders."), - 'date_start': fields.date('Valid from'), - 'date_stop': fields.date('Valid until'), + 'type': fields.selection([('normal','Normal BoM'),('phantom','Sets / Phantom')], 'BoM Type', required=True, help="Use a phantom bill of material in lines that have a sub-bom and that have to be automatically computed in one line, without having two production orders."), + 'date_start': fields.date('Valid From', help="Validity of this BoM or component. Keep empty if it's always valid."), + 'date_stop': fields.date('Valid Until', help="Validity of this BoM or component. Keep empty if it's always valid."), 'sequence': fields.integer('Sequence'), - 'position': fields.char('Internal Ref.', size=64), + 'position': fields.char('Internal Ref.', size=64, help="Reference to a position in an external plan."), 'product_id': fields.many2one('product.product', 'Product', required=True), 'product_uos_qty': fields.float('Product UOS Qty'), 'product_uos': fields.many2one('product.uom', 'Product UOS'), @@ -304,7 +310,7 @@ class mrp_production(osv.osv): _name = 'mrp.production' _description = 'Production' _date_name = 'date_planned' - + def _get_sale_order(self,cr,uid,ids,field_name=False): move_obj=self.pool.get('stock.move') def get_parent_move(move_id): @@ -324,13 +330,13 @@ class mrp_production(osv.osv): 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 return res - + def _sale_name_calc(self, cr, uid, ids, prop, unknow_none, unknow_dict): return self._get_sale_order(cr,uid,ids,field_name='name') - + def _sale_ref_calc(self, cr, uid, ids, prop, unknow_none, unknow_dict): return self._get_sale_order(cr,uid,ids,field_name='client_order_ref') - + _columns = { 'name': fields.char('Reference', size=64, required=True), 'origin': fields.char('Origin', size=64), @@ -640,11 +646,9 @@ mrp_production() class stock_move(osv.osv): _name = 'stock.move' _inherit = 'stock.move' - _columns = { - 'production_id': fields.many2one('mrp.production', 'Production', select=True), - } - + 'production_id': fields.many2one('mrp.production', 'Production', select=True), + } stock_move() class mrp_production_workcenter_line(osv.osv): From 68dd2596bf3f24894da245ffe4c219d4484f0f9a Mon Sep 17 00:00:00 2001 From: Jay Vora Date: Mon, 22 Sep 2008 12:18:49 +0530 Subject: [PATCH 04/21] fix:Displayed required and readonly attributes of a model. bzr revid: jvo@tinyerp.com-20080922064849-q2wphtmsblxjn1yl --- bin/addons/base/ir/__init__.py | 2 +- bin/addons/base/ir/ir_model.py | 20 ++++++++++---------- bin/osv/orm.py | 10 ++++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/bin/addons/base/ir/__init__.py b/bin/addons/base/ir/__init__.py index f6d3f769213..37e285d3f20 100644 --- a/bin/addons/base/ir/__init__.py +++ b/bin/addons/base/ir/__init__.py @@ -28,11 +28,11 @@ # ############################################################################## +import ir_model import ir_sequence import ir_ui_menu import ir_ui_view import ir_default -import ir_model import ir_actions import ir_report_custom import ir_attachment diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 5f31b46c73b..721fa088a1d 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -268,13 +268,13 @@ class ir_model_access(osv.osv): 'perm_create': fields.boolean('Create Access'), 'perm_unlink': fields.boolean('Delete Permission'), } - + def check_groups(self, cr, uid, group): res = False grouparr = group.split('.') if grouparr: cr.execute("select * from res_groups_users_rel where uid=" + str(uid) + " and gid in(select res_id from ir_model_data where module=%s and name=%s)", (grouparr[0], grouparr[1],)) - r = cr.fetchall() + r = cr.fetchall() if not r: res = False else: @@ -282,30 +282,30 @@ class ir_model_access(osv.osv): else: res = False return res - + def check_groups_by_id(self, cr, uid, group_id): cr.execute("select * from res_groups_users_rel where uid=%i and gid=%i", (uid, group_id,)) - r = cr.fetchall() + r = cr.fetchall() if not r: res = False else: res = True return res - + def check(self, cr, uid, model_name, mode='read',raise_exception=True): # Users root have all access (Todo: exclude xml-rpc requests) if uid==1: return True - + assert mode in ['read','write','create','unlink'], 'Invalid access mode' - + # We check if a specific rule exists cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' 'from ir_model_access a join ir_model m on (m.id=a.model_id) ' 'join res_groups_users_rel gu on (gu.gid = a.group_id) ' 'where m.model=%s and gu.uid=%s', (model_name, uid,)) r = cr.fetchall() - + if not r[0][0]: if raise_exception: msgs = { @@ -382,7 +382,7 @@ class ir_model_data(osv.osv): def _update(self,cr, uid, model, module, values, xml_id=False, store=True, noupdate=False, mode='init', res_id=False): warning = True model_obj = self.pool.get(model) - context = {} + context = {} if xml_id and ('.' in xml_id): assert len(xml_id.split('.'))==2, _('"%s" contains too many dots. XML ids should not contain dots ! These are used to refer to other modules data, as in module.reference_id') % (xml_id) warning = False @@ -544,7 +544,7 @@ class ir_model_config(osv.osv): 'type': 'ir.actions.act_window', 'target':'new', } - + def action_update_pw(self, cr, uid, ids, context={}): res = self.read(cr,uid,ids)[0] root = self.pool.get('res.users').browse(cr, uid, [1])[0] diff --git a/bin/osv/orm.py b/bin/osv/orm.py index e0722cbe4dc..00e2f30b35f 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -324,7 +324,9 @@ class orm_template(object): 'relate': (f.relate and 1) or 0, 'relation': f._obj or 'NULL', 'view_load': (f.view_load and 1) or 0, - 'select_level': str(f.select or 0) + 'select_level': str(f.select or 0), + 'readonly':(f.readonly and 1) or 0, + 'required':(f.required and 1) or 0, } if k not in cols: cr.execute('select nextval(%s)', ('ir_model_fields_id_seq',)) @@ -334,7 +336,7 @@ class orm_template(object): id, model_id, model, name, field_description, ttype, relate,relation,view_load,state,select_level ) VALUES ( - %d,%s,%s,%s,%s,%s,%s,%s,%s,%s, %s + %d,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s )""", ( id, vals['model_id'], vals['model'], vals['name'], vals['field_description'], vals['ttype'], bool(vals['relate']), vals['relation'], bool(vals['view_load']), 'base', @@ -351,12 +353,12 @@ class orm_template(object): cr.commit() cr.execute("""UPDATE ir_model_fields SET model_id=%s, field_description=%s, ttype=%s, relate=%s, relation=%s, - view_load=%s, select_level=%s + view_load=%s, select_level=%s, readonly=%s ,required=%s WHERE model=%s AND name=%s""", ( vals['model_id'], vals['field_description'], vals['ttype'], bool(vals['relate']), vals['relation'], bool(vals['view_load']), - vals['select_level'], vals['model'], vals['name'] + vals['select_level'], bool(vals['readonly']),bool(vals['required']), vals['model'], vals['name'] )) continue cr.commit() From aeabe5cc355ae695e4232980e1276f1c6f095ec1 Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Mon, 22 Sep 2008 13:25:47 +0530 Subject: [PATCH 05/21] Subflow support. bzr revid: ame@tinyerp.com-20080922075547-5wqi826hsdw0hjbq --- addons/process/process.py | 2 ++ addons/process/process_view.xml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/addons/process/process.py b/addons/process/process.py index f2d64499667..451d5c78257 100644 --- a/addons/process/process.py +++ b/addons/process/process.py @@ -81,6 +81,7 @@ class process_process(osv.osv): data['name'] = node.name data['model'] = (node.model_id or None) and node.model_id.model data['kind'] = node.kind + data['subflow'] = (node.subflow_id or None) and node.subflow_id.id data['notes'] = node.note data['active'] = 0 data['gray'] = 0 @@ -165,6 +166,7 @@ class process_node(osv.osv): 'note': fields.text('Notes', translate=True), 'model_id': fields.many2one('ir.model', 'Object', ondelete='set null'), 'model_states': fields.char('States Expression', size=128), + 'subflow_id': fields.many2one('process.process', 'Subflow', ondelete='set null'), 'flow_start': fields.boolean('Starting Flow'), 'transition_in': fields.one2many('process.transition', 'target_node_id', 'Starting Transitions'), 'transition_out': fields.one2many('process.transition', 'source_node_id', 'Ending Transitions'), diff --git a/addons/process/process_view.xml b/addons/process/process_view.xml index d9a4d93799f..20015d17e64 100644 --- a/addons/process/process_view.xml +++ b/addons/process/process_view.xml @@ -31,6 +31,7 @@ + @@ -156,6 +157,7 @@ + From e39269549639e54f181a9c0d418f8068be6ff55b Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 22 Sep 2008 10:14:07 +0200 Subject: [PATCH 06/21] tooltips bzr revid: fp@tinyerp.com-20080922081407-6tp9ew5d4q1diqdi --- addons/purchase/purchase.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 13d48317139..26fdf26c953 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -154,14 +154,19 @@ class purchase_order(osv.osv): _columns = { 'name': fields.char('Order Reference', size=64, required=True, select=True), - 'origin': fields.char('Origin', size=64), + 'origin': fields.char('Origin', size=64, + help="Reference of the document that generated this purchase order request." + ), 'partner_ref': fields.char('Partner Ref.', size=64), 'date_order':fields.date('Date Ordered', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}), - 'date_approve':fields.date('Date Approved'), + 'date_approve':fields.date('Date Approved', readonly=1), 'partner_id':fields.many2one('res.partner', 'Supplier', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}, change_default=True), 'partner_address_id':fields.many2one('res.partner.address', 'Address', required=True, states={'posted':[('readonly',True)]}), - 'dest_address_id':fields.many2one('res.partner.address', 'Destination Address', states={'posted':[('readonly',True)]}), + 'dest_address_id':fields.many2one('res.partner.address', 'Destination Address', states={'posted':[('readonly',True)]}, + help="Put an address if you want to deliver directly from the supplier to the customer." \ + "In this case, it will remove the warehouse link and set the customer location." + ), 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', states={'posted':[('readonly',True)]}), 'location_id': fields.many2one('stock.location', 'Destination', required=True), @@ -177,7 +182,12 @@ class purchase_order(osv.osv): 'shipped_rate': fields.function(_shipped_rate, method=True, string='Received', type='float'), 'invoiced':fields.boolean('Invoiced & Paid', readonly=True, select=True), 'invoiced_rate': fields.function(_invoiced_rate, method=True, string='Invoiced', type='float'), - 'invoice_method': fields.selection([('manual','Manual'),('order','From order'),('picking','From picking')], 'Invoicing Control', required=True), + 'invoice_method': fields.selection([('manual','Manual'),('order','From Order'),('picking','From Picking')], 'Invoicing Control', required=True, + help="From Order: a draft invoice will be pre-generated based on the purchase order. The accountant " \ + "will just have to validate this invoice for control.\n" \ + "From Picking: a draft invoice will be pre-genearted based on validated receptions.\n" \ + "Manual: no invoice will be pre-generated. The accountant will have to encode manually." + ), 'minimum_planned_date':fields.function(_minimum_planned_date, fnct_inv=_set_minimum_planned_date, method=True,store=True, string='Planned Date', type='datetime', help="This is computed as the minimum scheduled date of all purchase order lines' products."), 'amount_untaxed': fields.function(_amount_untaxed, method=True, string='Untaxed Amount'), 'amount_tax': fields.function(_amount_tax, method=True, string='Taxes'), From 3413e6e8dde03683d5cb17a9182fa611a86231fb Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Mon, 22 Sep 2008 10:18:36 +0200 Subject: [PATCH 07/21] tooltipsandbetterdata bzr revid: fp@tinyerp.com-20080922081836-3mx735iw6eq9xday --- bin/addons/base/res/partner/partner.py | 8 ++++---- bin/addons/base/res/partner/partner_demo.xml | 11 +++++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/bin/addons/base/res/partner/partner.py b/bin/addons/base/res/partner/partner.py index 4183eccaf2f..d568032fdd1 100644 --- a/bin/addons/base/res/partner/partner.py +++ b/bin/addons/base/res/partner/partner.py @@ -151,8 +151,8 @@ class res_partner(osv.osv): 'credit_limit': fields.float(string='Credit Limit'), 'ean13': fields.char('EAN13', size=13), 'active': fields.boolean('Active'), - 'customer': fields.boolean('Customer'), - 'supplier': fields.boolean('Supplier'), + 'customer': fields.boolean('Customer', help="Check this box if the partner if a customer."), + 'supplier': fields.boolean('Supplier', help="Check this box if the partner if a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."), 'city':fields.related('address','city',type='char', string='City'), 'country':fields.related('address','country_id',type='many2one', relation='res.country', string='Country'), } @@ -279,7 +279,7 @@ class res_partner_address(osv.osv): _order = 'id' _columns = { 'partner_id': fields.many2one('res.partner', 'Partner', ondelete='cascade', select=True), - 'type': fields.selection( [ ('default','Default'),('invoice','Invoice'), ('delivery','Delivery'), ('contact','Contact'), ('other','Other') ],'Address Type'), + 'type': fields.selection( [ ('default','Default'),('invoice','Invoice'), ('delivery','Delivery'), ('contact','Contact'), ('other','Other') ],'Address Type', help="Used to select automatically the right address according to the context in sales and purchases documents."), 'function': fields.many2one('res.partner.function', 'Function'), 'title': fields.selection(_contact_title_get, 'Title', size=32), 'name': fields.char('Contact Name', size=64), @@ -294,7 +294,7 @@ class res_partner_address(osv.osv): 'fax': fields.char('Fax', size=64), 'mobile': fields.char('Mobile', size=64), 'birthdate': fields.char('Birthdate', size=64), - 'active': fields.boolean('Active'), + 'active': fields.boolean('Active', help="Uncheck the active field to hide the contact."), } _defaults = { 'active': lambda *a: 1, diff --git a/bin/addons/base/res/partner/partner_demo.xml b/bin/addons/base/res/partner/partner_demo.xml index d14d5705e7b..92797377da1 100644 --- a/bin/addons/base/res/partner/partner_demo.xml +++ b/bin/addons/base/res/partner/partner_demo.xml @@ -115,6 +115,7 @@ ASUStek + 1 Agrolait @@ -123,9 +124,10 @@ Camptocamp + 1 - Sednacom + Syleam @@ -133,8 +135,9 @@ - Desertic - Hispafuentes + Axelor + 1 Tiny AT Work @@ -151,6 +154,7 @@ Distrib PC + 1 Ecole de Commerce de Liege @@ -160,18 +164,21 @@ Elec Import + 1 Maxtor + 1 Seagate + 1 http://mediapole.net From b0a16b4cfce9e911a8e7e72026bb874fe99f8655 Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Mon, 22 Sep 2008 15:28:51 +0530 Subject: [PATCH 08/21] Node with resource information. bzr revid: ame@tinyerp.com-20080922095851-2dw4985vlipd6vbj --- addons/process/process.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/addons/process/process.py b/addons/process/process.py index 451d5c78257..8b61067dfce 100644 --- a/addons/process/process.py +++ b/addons/process/process.py @@ -64,6 +64,7 @@ class process_process(osv.osv): } def graph_get(self, cr, uid, id, res_model, res_id, scale, context): + pool = pooler.get_pool(cr.dbname) process = pool.get('process.process').browse(cr, uid, [id])[0] @@ -71,6 +72,17 @@ class process_process(osv.osv): current_user = pool.get('res.users').browse(cr, uid, [uid], context)[0] expr_context = Env(current_object, current_user) + + fields = pool.get(res_model).fields_get(cr, uid, context=context) + + def get_resource_info(node): + ret = False + + for name, field in fields.items(): + if node.model_id and field.get('relation', False) == node.model_id.model: + #TODO: get resource info + + return ret nodes = {} start = [] @@ -83,20 +95,26 @@ class process_process(osv.osv): data['kind'] = node.kind data['subflow'] = (node.subflow_id or None) and node.subflow_id.id data['notes'] = node.note - data['active'] = 0 - data['gray'] = 0 + data['active'] = False + data['gray'] = False + data['res'] = get_resource_info(node) if node.menu_id: data['menu'] = {'name': node.menu_id.complete_name, 'id': node.menu_id.id} - if node.kind == "state" and node.model_id and node.model_id.model == res_model: + if node.model_id and node.model_id.model == res_model: + + data['res'] = resource = {} + resource['name'] = current_object.name_get(context)[0][1] + resource['model'] = res_model + resource['id'] = res_id + try: - if eval(node.model_states, expr_context): - data['active'] = current_object.name_get(context)[0][1] + data['active'] = eval(node.model_states, expr_context) except Exception, e: # waring: invalid state expression pass - + if not data['active']: try: gray = True From b74fd90c8572c7c701e336db57ed06b8d3ff80c5 Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Mon, 22 Sep 2008 15:29:50 +0530 Subject: [PATCH 09/21] minor fix bzr revid: ame@tinyerp.com-20080922095950-82p9ek2lvbh0zjdu --- addons/process/process.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/process/process.py b/addons/process/process.py index 8b61067dfce..7e53beb4b87 100644 --- a/addons/process/process.py +++ b/addons/process/process.py @@ -81,6 +81,7 @@ class process_process(osv.osv): for name, field in fields.items(): if node.model_id and field.get('relation', False) == node.model_id.model: #TODO: get resource info + pass return ret From c8d51ca11f4773b4dcdccaaf4245b6e70eca323a Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Mon, 22 Sep 2008 15:39:23 +0530 Subject: [PATCH 10/21] Node with related resource information. bzr revid: ame@tinyerp.com-20080922100923-37nk60zyqv3hxoai --- addons/process/process.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/process/process.py b/addons/process/process.py index 7e53beb4b87..636135cc8e6 100644 --- a/addons/process/process.py +++ b/addons/process/process.py @@ -79,9 +79,12 @@ class process_process(osv.osv): ret = False for name, field in fields.items(): - if node.model_id and field.get('relation', False) == node.model_id.model: - #TODO: get resource info - pass + if node.model_id and field.get('relation', False) == node.model_id.model and current_object[name]: + rel = current_object[name][0] + ret = {} + ret['name'] = rel.name_get(context)[0][1] + ret['model'] = field['relation'] + ret['id'] = rel.id return ret From 9cdba9adce3aece0c903f539bc6e113a4903eaad Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Mon, 22 Sep 2008 12:16:05 +0200 Subject: [PATCH 11/21] fix DivideByZero bzr revid: stephane@tinyerp.com-20080922101605-lsof52sp7b6gi60f --- bin/addons/base/res/res_currency.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/addons/base/res/res_currency.py b/bin/addons/base/res/res_currency.py index 05541689154..55de9ecc380 100644 --- a/bin/addons/base/res/res_currency.py +++ b/bin/addons/base/res/res_currency.py @@ -71,7 +71,10 @@ class res_currency(osv.osv): _order = "code" def round(self, cr, uid, currency, amount): - return round(amount / currency.rounding) * currency.rounding + if currency.rounding == 0: + return 0.0 + else: + return round(amount / currency.rounding) * currency.rounding def is_zero(self, cr, uid, currency, amount): return abs(self.round(cr, uid, currency, amount)) < currency.rounding From 1d155900cfa11b1401717bfa7be1cab52300fb39 Mon Sep 17 00:00:00 2001 From: Jay Vora Date: Mon, 22 Sep 2008 16:02:12 +0530 Subject: [PATCH 12/21] Added Tooltips on fields of account_payment module bzr revid: jvo@tinyerp.com-20080922103212-65t7r14t6t7tb7xb --- addons/account_payment/__init__.py | 1 + addons/account_payment/payment.py | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/addons/account_payment/__init__.py b/addons/account_payment/__init__.py index 3b652e0b3a3..7fc464279cd 100644 --- a/addons/account_payment/__init__.py +++ b/addons/account_payment/__init__.py @@ -36,6 +36,7 @@ import payment import wizard import account_move_line import account_invoice +import report # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account_payment/payment.py b/addons/account_payment/payment.py index 3f4665878b8..22ca132453c 100644 --- a/addons/account_payment/payment.py +++ b/addons/account_payment/payment.py @@ -39,8 +39,8 @@ class payment_type(osv.osv): _name= 'payment.type' _description= 'Payment type' _columns= { - 'name': fields.char('Name', size=64, required=True), - 'code': fields.char('Code', size=64, required=True), + 'name': fields.char('Name', size=64, required=True,help='Payment Type'), + 'code': fields.char('Code', size=64, required=True,help='Specify the Code for Payment Type'), 'suitable_bank_types': fields.many2many('res.partner.bank.type', 'bank_type_payment_type_rel', 'pay_type_id','bank_type_id', @@ -54,12 +54,12 @@ class payment_mode(osv.osv): _name= 'payment.mode' _description= 'Payment mode' _columns= { - 'name': fields.char('Name', size=64, required=True), + 'name': fields.char('Name', size=64, required=True,help='Mode of Payment'), 'bank_id': fields.many2one('res.partner.bank', "Bank account", - required=True), + required=True,help='Bank Account for the Payment Mode'), 'journal': fields.many2one('account.journal', 'Journal', required=True, - domain=[('type', '=', 'cash')]), - 'type': fields.many2one('payment.type','Payment type',required=True), + domain=[('type', '=', 'cash')],help='Cash Journal for the Payment Mode'), + 'type': fields.many2one('payment.type','Payment type',required=True,help='Select the Payment Type for the Payment Mode.'), } def suitable_bank_types(self,cr,uid,payment_code=None,context={}): @@ -102,9 +102,9 @@ class payment_order(osv.osv): return res _columns = { - 'date_planned': fields.date('Scheduled date if fixed'), + 'date_planned': fields.date('Scheduled date if fixed',help='Select a date if you have chosen Preferred Date to be fixed.'), 'reference': fields.char('Reference',size=128,required=1), - 'mode': fields.many2one('payment.mode','Payment mode', select=True, required=1), + 'mode': fields.many2one('payment.mode','Payment mode', select=True, required=1,help='Select the Payment Mode to be applied.'), 'state': fields.selection([ ('draft', 'Draft'), ('open','Confirmed'), @@ -118,7 +118,7 @@ class payment_order(osv.osv): ('now', 'Directly'), ('due', 'Due date'), ('fixed', 'Fixed date') - ], "Prefered date", change_default=True, required=True), + ], "Prefered date", change_default=True, required=True,help="Choose an option for the Payment Order:'Fixed' stands for a date specified by you.'Directly' stands for the direct execution.'Due date' stands for the scheduled date of execution."), 'date_created': fields.date('Creation date', readonly=True), 'date_done': fields.date('Execution date', readonly=True), } @@ -381,9 +381,9 @@ class payment_line(osv.osv): _columns = { 'name': fields.char('Your Reference', size=64, required=True), - 'communication': fields.char('Communication', size=64, required=True), - 'communication2': fields.char('Communication 2', size=64), - 'move_line_id': fields.many2one('account.move.line','Entry line', domain=[('reconcile_id','=', False), ('account_id.type', '=','payable')]), + 'communication': fields.char('Communication', size=64, required=True,help="Used as the message between ordering customer and current company.Depicts 'What do you want to say to the receipent about this oder?'"), + 'communication2': fields.char('Communication 2', size=64,help='The successor message of Communication.'), + 'move_line_id': fields.many2one('account.move.line','Entry line', domain=[('reconcile_id','=', False), ('account_id.type', '=','payable')],help='This Entry Line will be referred for the information of the ordering customer.'), 'amount_currency': fields.float('Amount in Partner Currency', digits=(16,2), required=True, help='Payment amount in the partner currency'), # 'to_pay_currency': fields.function(_to_pay_currency, string='To Pay', @@ -396,7 +396,7 @@ class payment_line(osv.osv): 'bank_id': fields.many2one('res.partner.bank', 'Destination Bank account'), 'order_id': fields.many2one('payment.order', 'Order', required=True, ondelete='cascade', select=True), - 'partner_id': fields.many2one('res.partner', string="Partner",required=True), + 'partner_id': fields.many2one('res.partner', string="Partner",required=True,help='The Ordering Customer'), 'amount': fields.function(_amount, string='Amount in Company Currency', method=True, type='float', help='Payment amount in the company currency'), @@ -410,8 +410,8 @@ class payment_line(osv.osv): # type='char'), 'ml_maturity_date': fields.function(_get_ml_maturity_date, method=True, type='char', string='Maturity Date'), 'ml_inv_ref': fields.function(_get_ml_inv_ref, method=True, type='many2one', relation='account.invoice', string='Invoice Ref'), - 'info_owner': fields.function(info_owner, string="Owner Account", method=True, type="text"), - 'info_partner': fields.function(info_partner, string="Destination Account", method=True, type="text"), + 'info_owner': fields.function(info_owner, string="Owner Account", method=True, type="text",help='Address of the Main Partner'), + 'info_partner': fields.function(info_partner, string="Destination Account", method=True, type="text",help='Address of the Ordering Customer.'), # 'partner_payable': fields.function(partner_payable, string="Partner payable", method=True, type='float'), # 'value_date': fields.function(_value_date, string='Value Date', # method=True, type='date'), From ceb689c8e236d94c06c44e96b6291958e43fb76f Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Mon, 22 Sep 2008 16:11:44 +0530 Subject: [PATCH 13/21] Node with related resource information. bzr revid: ame@tinyerp.com-20080922104144-piob6t3zdt2zgcnj --- addons/process/process.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/addons/process/process.py b/addons/process/process.py index 636135cc8e6..8cd51798708 100644 --- a/addons/process/process.py +++ b/addons/process/process.py @@ -73,18 +73,34 @@ class process_process(osv.osv): expr_context = Env(current_object, current_user) - fields = pool.get(res_model).fields_get(cr, uid, context=context) - def get_resource_info(node): ret = False + src_model = res_model + src_id = res_id + + if node.transition_in: + tr = node.transition_in[0] + src = nodes.get(tr.source_node_id.id) + if src['res']: + src_model = src['res']['model'] + src_id = src['res']['id'] + else: + return False + + fields = pool.get(src_model).fields_get(cr, uid, context=context) + for name, field in fields.items(): - if node.model_id and field.get('relation', False) == node.model_id.model and current_object[name]: - rel = current_object[name][0] - ret = {} - ret['name'] = rel.name_get(context)[0][1] - ret['model'] = field['relation'] - ret['id'] = rel.id + if node.model_id and field.get('relation', False) == node.model_id.model: + src_obj = pool.get(src_model).browse(cr, uid, [src_id], context)[0] + rel = src_obj[name] + if rel: + if isinstance(rel, (list, tuple)): + rel = rel[0] + ret = {} + ret['name'] = rel.name_get(context)[0][1] + ret['model'] = field['relation'] + ret['id'] = rel.id return ret From 180b5be158aef1fa64f812992b4f3bebb3d9896c Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Mon, 22 Sep 2008 13:13:18 +0200 Subject: [PATCH 14/21] * fix error with access rights * some refactor bzr revid: christophe@tinyerp.com-20080922111318-y6hx790y5kqvsoyv --- bin/addons/base/ir/ir_model.py | 70 +++++++++++++++++---------------- bin/addons/base/res/res_user.py | 5 ++- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/bin/addons/base/ir/ir_model.py b/bin/addons/base/ir/ir_model.py index 721fa088a1d..66010201701 100644 --- a/bin/addons/base/ir/ir_model.py +++ b/bin/addons/base/ir/ir_model.py @@ -272,27 +272,17 @@ class ir_model_access(osv.osv): def check_groups(self, cr, uid, group): res = False grouparr = group.split('.') - if grouparr: - cr.execute("select * from res_groups_users_rel where uid=" + str(uid) + " and gid in(select res_id from ir_model_data where module=%s and name=%s)", (grouparr[0], grouparr[1],)) - r = cr.fetchall() - if not r: - res = False - else: - res = True - else: - res = False - return res + if not grouparr: + return False + + cr.execute("select 1 from res_groups_users_rel where uid=%d and gid in(select res_id from ir_model_data where module=%s and name=%s)", (uid, grouparr[0], grouparr[1],)) + return bool(cr.fetchone()) def check_groups_by_id(self, cr, uid, group_id): - cr.execute("select * from res_groups_users_rel where uid=%i and gid=%i", (uid, group_id,)) - r = cr.fetchall() - if not r: - res = False - else: - res = True - return res + cr.execute("select 1 from res_groups_users_rel where uid=%i and gid=%i", (uid, group_id,)) + return bool(cr.fetchone()) - def check(self, cr, uid, model_name, mode='read',raise_exception=True): + def check(self, cr, uid, model_name, mode='read', raise_exception=True): # Users root have all access (Todo: exclude xml-rpc requests) if uid==1: return True @@ -300,22 +290,36 @@ class ir_model_access(osv.osv): assert mode in ['read','write','create','unlink'], 'Invalid access mode' # We check if a specific rule exists - cr.execute('SELECT MAX(CASE WHEN perm_'+mode+' THEN 1 else 0 END) ' - 'from ir_model_access a join ir_model m on (m.id=a.model_id) ' - 'join res_groups_users_rel gu on (gu.gid = a.group_id) ' - 'where m.model=%s and gu.uid=%s', (model_name, uid,)) - r = cr.fetchall() + cr.execute('SELECT MAX(CASE WHEN perm_' + mode + ' THEN 1 ELSE 0 END) ' + ' FROM ir_model_access a ' + ' JOIN ir_model m ON (m.id = a.model_id) ' + ' JOIN res_groups_users_rel gu ON (gu.gid = a.group_id) ' + ' WHERE m.model = %s ' + ' AND gu.uid = %s ' + , (model_name, uid,) + ) + r = cr.fetchone()[0] - if not r[0][0]: - if raise_exception: - msgs = { - 'read': _('You can not read this document! (%s)'), - 'write': _('You can not write in this document! (%s)'), - 'create': _('You can not create this kind of document! (%s)'), - 'unlink': _('You can not delete this document! (%s)'), - } - raise except_orm(_('AccessError'), msgs[mode] % model_name ) - return r[0][0] + if r is None: + # there is no specific rule. We check the generic rule + cr.execute('SELECT MAX(CASE WHEN perm_' + mode + ' THEN 1 ELSE 0 END) ' + ' FROM ir_model_access a ' + ' JOIN ir_model m ON (m.id = a.model_id) ' + ' WHERE a.group_id IS NULL ' + ' AND m.model = %s ' + , (model_name,) + ) + r = cr.fetchone()[0] + + if not r and raise_exception: + msgs = { + 'read': _('You can not read this document! (%s)'), + 'write': _('You can not write in this document! (%s)'), + 'create': _('You can not create this kind of document! (%s)'), + 'unlink': _('You can not delete this document! (%s)'), + } + raise except_orm(_('AccessError'), msgs[mode] % model_name ) + return r check = tools.cache()(check) diff --git a/bin/addons/base/res/res_user.py b/bin/addons/base/res/res_user.py index 4a5e7d9e81c..62e54728c3e 100644 --- a/bin/addons/base/res/res_user.py +++ b/bin/addons/base/res/res_user.py @@ -189,7 +189,7 @@ class users(osv.osv): default.update({'login': login+' (copy)'}) return super(users, self).copy(cr, uid, id, default, context) - def context_get(self, cr, uid, context={}): + def context_get(self, cr, uid, context=None): user = self.browse(cr, uid, uid, context) result = {} for k in self._columns.keys(): @@ -276,3 +276,6 @@ class res_config_view(osv.osv_memory): } res_config_view() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + From 3128a6f16a38c243dc79ca461a6ee2d8aff78fe7 Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Mon, 22 Sep 2008 17:28:05 +0530 Subject: [PATCH 15/21] Process Notes. bzr revid: ame@tinyerp.com-20080922115805-v74barv0qb07ehxg --- addons/process/process.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/process/process.py b/addons/process/process.py index 8cd51798708..16c16805e18 100644 --- a/addons/process/process.py +++ b/addons/process/process.py @@ -104,6 +104,7 @@ class process_process(osv.osv): return ret + notes = process.note nodes = {} start = [] transitions = {} @@ -113,7 +114,7 @@ class process_process(osv.osv): data['name'] = node.name data['model'] = (node.model_id or None) and node.model_id.model data['kind'] = node.kind - data['subflow'] = (node.subflow_id or None) and node.subflow_id.id + data['subflow'] = (node.subflow_id or False) and [node.subflow_id.id, node.subflow_id.name] data['notes'] = node.note data['active'] = False data['gray'] = False @@ -189,7 +190,7 @@ class process_process(osv.osv): for k, v in nodes.items(): y = v['y'] v['y'] = min(y - miny + 10, y) - return dict(nodes=nodes, transitions=transitions) + return dict(notes=notes, nodes=nodes, transitions=transitions) process_process() From c8f452b00070c3ff6d1a34a32333190fe88e8a0c Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Mon, 22 Sep 2008 18:49:45 +0530 Subject: [PATCH 16/21] Roles for Process transition. bzr revid: ame@tinyerp.com-20080922131945-740do6g3tbo1ipls --- addons/process/process.py | 5 +++++ addons/process/process_view.xml | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/addons/process/process.py b/addons/process/process.py index 16c16805e18..73af1beffec 100644 --- a/addons/process/process.py +++ b/addons/process/process.py @@ -169,6 +169,10 @@ class process_process(osv.osv): role = {} role['name'] = r.role_id.name roles.append(role) + for r in tr.role_ids: + role = {} + role['name'] = r.name + roles.append(role) transitions[tr.id] = data g = tools.graph(nodes.keys(), map(lambda x: (x['source'], x['target']), transitions.values())) @@ -238,6 +242,7 @@ class process_transition(osv.osv): 'target_node_id': fields.many2one('process.node', 'Target Node', required=True, ondelete='cascade'), 'action_ids': fields.one2many('process.transition.action', 'transition_id', 'Buttons'), 'transition_ids': fields.many2many('workflow.transition', 'process_transition_ids', 'ptr_id', 'wtr_id', 'Workflow Transitions'), + 'role_ids': fields.many2many('res.roles', 'process_transition_roles_rel', 'tid', 'rid', 'Roles'), 'note': fields.text('Description', translate=True), } process_transition() diff --git a/addons/process/process_view.xml b/addons/process/process_view.xml index 20015d17e64..d5ae44a2a55 100644 --- a/addons/process/process_view.xml +++ b/addons/process/process_view.xml @@ -63,6 +63,9 @@ + + + @@ -189,6 +192,9 @@ + + + @@ -276,9 +282,13 @@ - - - + + + + + + + From 6130fbd77bcff26646f1edaa6f1d043fdd3c1033 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Mon, 22 Sep 2008 16:23:50 +0200 Subject: [PATCH 17/21] fix error in demo data bzr revid: christophe@tinyerp.com-20080922142350-jf952125rnp5kzxi --- bin/addons/base/base_demo.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/addons/base/base_demo.xml b/bin/addons/base/base_demo.xml index 46f9a15330d..235e7e77b75 100644 --- a/bin/addons/base/base_demo.xml +++ b/bin/addons/base/base_demo.xml @@ -5,12 +5,12 @@ demo demo Demo User - Fabien Pinckaers + Mr Demo - + From 3a4f98c7e4287a7f973c088e032c2b05f2b22b73 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Mon, 22 Sep 2008 16:26:12 +0200 Subject: [PATCH 18/21] remove print statement bzr revid: stephane@tinyerp.com-20080922142612-67kil8o8kem4zunt --- bin/addons/base/res/res_user.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/addons/base/res/res_user.py b/bin/addons/base/res/res_user.py index 62e54728c3e..d168a69de38 100644 --- a/bin/addons/base/res/res_user.py +++ b/bin/addons/base/res/res_user.py @@ -249,7 +249,6 @@ class res_config_view(osv.osv_memory): } def action_cancel(self,cr,uid,ids,conect=None): - print ' Cancel action' return { 'view_type': 'form', "view_mode": 'form', From 808595eb78652f97557c267b6a781c2e163a2f0d Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Mon, 22 Sep 2008 16:26:14 +0200 Subject: [PATCH 19/21] Remove the visible tag and add the password tag bzr revid: stephane@tinyerp.com-20080922142614-87ffd7sn532yek29 --- bin/addons/base/rng/view.rng | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/addons/base/rng/view.rng b/bin/addons/base/rng/view.rng index 666ab76194b..aac75e1e565 100644 --- a/bin/addons/base/rng/view.rng +++ b/bin/addons/base/rng/view.rng @@ -162,7 +162,7 @@ - + From 8cb169f404ba74abf4289b63f7aeca07af082133 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Mon, 22 Sep 2008 16:51:25 +0200 Subject: [PATCH 20/21] use the password tag for the password field bzr revid: stephane@tinyerp.com-20080922145125-l7esstedgx2fb59r --- bin/addons/base/base_update.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/addons/base/base_update.xml b/bin/addons/base/base_update.xml index 0cff3091f62..b56866a5a15 100644 --- a/bin/addons/base/base_update.xml +++ b/bin/addons/base/base_update.xml @@ -76,7 +76,7 @@
- +