From 50462d4296f21ba932dd5b38319a6e7182da60ce Mon Sep 17 00:00:00 2001 From: Yogesh Sakhreliya Date: Tue, 4 Jan 2011 15:30:59 +0530 Subject: [PATCH 001/189] [FIX] use ustr function instead of encoding in xsl report. lp bug: https://launchpad.net/bugs/695960 fixed bzr revid: ysa@tinyerp.com-20110104100059-55eydjnmtd22saed --- bin/report/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/report/interface.py b/bin/report/interface.py index 16dfafe0a18..3e710db9660 100644 --- a/bin/report/interface.py +++ b/bin/report/interface.py @@ -39,7 +39,7 @@ def toxml(val): if isinstance(val, str): str_utf8 = val elif isinstance(val, unicode): - str_utf8 = val.encode('utf-8') + str_utf8 = tools.ustr(val) else: str_utf8 = str(val) return str_utf8.replace('&', '&').replace('<','<').replace('>','>') From d0c25a2c23f222534f97e4451507cad2744ffe81 Mon Sep 17 00:00:00 2001 From: Yogesh Sakhreliya Date: Thu, 6 Jan 2011 16:53:17 +0530 Subject: [PATCH 002/189] [FIX] display simple error instead of traceback in sql bad query. bzr revid: ysa@tinyerp.com-20110106112317-0mj9v7n8n133af29 --- bin/sql_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/sql_db.py b/bin/sql_db.py index aed10423bb7..b9b72023980 100644 --- a/bin/sql_db.py +++ b/bin/sql_db.py @@ -133,7 +133,7 @@ class Cursor(object): raise except Exception: if log_exceptions or self.sql_log: - self.__logger.exception("bad query: %s", self._obj.query or query) + self.__logger.error("bad query: %s", self._obj.query or query) raise if self.sql_log: From fcf7c478cc18bd50530d94a56fc17d4edb0f01dd Mon Sep 17 00:00:00 2001 From: "YSA (Openerp)" Date: Thu, 20 Jan 2011 11:10:34 +0530 Subject: [PATCH 003/189] [FIX] call name_search method then pass context parameter in import_data method.. bzr revid: ysa@tinyerp.com-20110120054034-b8mdwsev5ax5c2cj --- bin/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 89b93c41923..1b6c9358e7a 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -728,7 +728,7 @@ class orm_template(object): id = ir_model_data[0]['res_id'] else: obj_model = self.pool.get(model_name) - ids = obj_model.name_search(cr, uid, id, operator='=') + ids = obj_model.name_search(cr, uid, id, operator='=', context=context) if not ids: raise ValueError('No record found for %s' % (id,)) id = ids[0][0] From bafa90b716f3d1c1382be039c317ed554912ca98 Mon Sep 17 00:00:00 2001 From: Olivier Ligot Date: Wed, 9 Feb 2011 11:08:45 +0100 Subject: [PATCH 004/189] [IMP] The command line option --i18n-overwrite can also be used when updating modules bzr revid: olivier.ligot@groupes.be-20110209100845-ldgoxolfz98k3mnu --- openerp/addons/__init__.py | 2 +- openerp/tools/config.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openerp/addons/__init__.py b/openerp/addons/__init__.py index af080724136..f91d66eb7a7 100644 --- a/openerp/addons/__init__.py +++ b/openerp/addons/__init__.py @@ -779,7 +779,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= modobj.write(cr, 1, [mid], {'state': 'installed', 'latest_version': ver}) cr.commit() # Update translations for all installed languages - modobj.update_translations(cr, 1, [mid], None) + modobj.update_translations(cr, 1, [mid], None, {'overwrite': tools.config['overwrite_existing_translations']}) cr.commit() package.state = 'installed' diff --git a/openerp/tools/config.py b/openerp/tools/config.py index 7d0b04739e4..7b0e560f4f6 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -217,7 +217,7 @@ class configmanager(object): group.add_option("--i18n-import", dest="translate_in", help="import a CSV or a PO file with translations and exit. The '-l' option is required.") group.add_option("--i18n-overwrite", dest="overwrite_existing_translations", action="store_true", default=False, - help="overwrites existing translation terms on importing a CSV or a PO file.") + help="overwrites existing translation terms on updating a module or importing a CSV or a PO file.") group.add_option("--modules", dest="translate_modules", help="specify modules to export. Use in combination with --i18n-export") group.add_option("--addons-path", dest="addons_path", @@ -264,8 +264,8 @@ class configmanager(object): die(opt.translate_in and (not opt.language or not opt.db_name), "the i18n-import option cannot be used without the language (-l) and the database (-d) options") - die(opt.overwrite_existing_translations and (not opt.translate_in), - "the i18n-overwrite option cannot be used without the i18n-import option") + die(opt.overwrite_existing_translations and not (opt.translate_in or opt.update), + "the i18n-overwrite option cannot be used without the i18n-import option or without the update option") die(opt.translate_out and (not opt.db_name), "the i18n-export option cannot be used without the database (-d) option") From 7be91c10088e835ecc333bcdc7973734ea0041ed Mon Sep 17 00:00:00 2001 From: "ksa (Open ERP)" Date: Tue, 22 Mar 2011 14:21:52 +0530 Subject: [PATCH 005/189] [FIX]:problem with create_date in base synchro lp bug: https://launchpad.net/bugs/725073 fixed bzr revid: ksa@tinyerp.co.in-20110322085152-xmq5lgh93351l7xh --- addons/base_synchro/wizard/base_synchro.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/base_synchro/wizard/base_synchro.py b/addons/base_synchro/wizard/base_synchro.py index 0535ca8054d..1a593684b59 100644 --- a/addons/base_synchro/wizard/base_synchro.py +++ b/addons/base_synchro/wizard/base_synchro.py @@ -103,6 +103,11 @@ class base_synchro(osv.osv_memory): if object.model_id.model=='crm.case.history': fields = ['email','description','log_id'] value = pool_src.get(object.model_id.model).read(cr, uid, [id], fields)[0] + if 'create_date' in value: + del value['create_date'] + for key ,val in value.iteritems(): + if type(val)==tuple: + value.update({key:val[0]}) value = self.data_transform(cr, uid, pool_src, pool_dest, object.model_id.model, value, action, context=context) id2 = self.get_id(cr, uid, object.id, id, action, context) # From 6d10583973d371fff93a10896d43af832bc9826f Mon Sep 17 00:00:00 2001 From: "ARA (OpenERP)" Date: Thu, 24 Mar 2011 14:14:17 +0530 Subject: [PATCH 006/189] [FIX] Account: Account chart wizard does not check if generated account code for bank journal exsits lp bug: https://launchpad.net/bugs/684119 fixed bzr revid: ara@tinyerp.com-20110324084417-9rqbu46o4v97x2ey --- addons/account/account.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/addons/account/account.py b/addons/account/account.py index 2bdb62b44c0..8947afc8fe4 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -2921,15 +2921,27 @@ class wizard_multi_charts_accounts(osv.osv_memory): ref_acc_bank = obj_multi.chart_template_id.bank_account_view_id current_num = 1 + valid = True for line in obj_multi.bank_accounts_id: #create the account_account for this bank journal tmp = line.acc_name dig = obj_multi.code_digits if ref_acc_bank.code: - try: - new_code = str(int(ref_acc_bank.code.ljust(dig,'0')) + current_num) - except: - new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)),'0')) + str(current_num) + while valid: + try: + new_code = str(int(ref_acc_bank.code.ljust(dig, '0')) + current_num) + ids = obj_acc.search(cr, uid,[('code', '=', new_code)]) + if not ids: + valid = False + else: + current_num += 1 + except: + new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)), '0')) + str(current_num) + ids = obj_acc.search(cr, uid,[('code', '=', new_code)]) + if not ids: + valid = False + else: + current_num += 1 vals = { 'name': tmp, 'currency_id': line.currency_id and line.currency_id.id or False, @@ -2962,6 +2974,7 @@ class wizard_multi_charts_accounts(osv.osv_memory): vals_journal['default_debit_account_id'] = acc_cash_id obj_journal.create(cr, uid, vals_journal) current_num += 1 + valid = True #create the properties property_obj = self.pool.get('ir.property') From 0de7622c037ee2aa18dea205847703624761343d Mon Sep 17 00:00:00 2001 From: "ARA (OpenERP)" Date: Thu, 24 Mar 2011 14:16:53 +0530 Subject: [PATCH 007/189] [FIX] Account: Account chart wizard does not check if generated account code for bank journal exsits bzr revid: ara@tinyerp.com-20110324084653-ysbw98hvxcynrgqt --- addons/account/account.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/account.py b/addons/account/account.py index 8947afc8fe4..def72ec08d3 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -2930,14 +2930,14 @@ class wizard_multi_charts_accounts(osv.osv_memory): while valid: try: new_code = str(int(ref_acc_bank.code.ljust(dig, '0')) + current_num) - ids = obj_acc.search(cr, uid,[('code', '=', new_code)]) + ids = obj_acc.search(cr, uid, [('code', '=', new_code)]) if not ids: valid = False else: current_num += 1 except: new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)), '0')) + str(current_num) - ids = obj_acc.search(cr, uid,[('code', '=', new_code)]) + ids = obj_acc.search(cr, uid, [('code', '=', new_code)]) if not ids: valid = False else: From 82565f571b748ac285754e1eb1a633b9bcd00c51 Mon Sep 17 00:00:00 2001 From: "ARA (OpenERP)" Date: Fri, 25 Mar 2011 15:19:39 +0530 Subject: [PATCH 008/189] [FIX] Account: payment term line need at least 5 to 6 digits precision lp bug: https://launchpad.net/bugs/740596 fixed bzr revid: ara@tinyerp.com-20110325094939-k30q24tu5okj7mcm --- addons/account/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/account.py b/addons/account/account.py index 2bdb62b44c0..1dab0d077af 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -102,7 +102,7 @@ class account_payment_term_line(osv.osv): ('fixed', 'Fixed Amount')], 'Valuation', required=True, help="""Select here the kind of valuation related to this payment term line. Note that you should have your last line with the type 'Balance' to ensure that the whole amount will be threated."""), - 'value_amount': fields.float('Value Amount', help="For Value percent enter % ratio between 0-1."), + 'value_amount': fields.float('Value Amount', digits=(16, 6), help="For Value percent enter % ratio between 0-1."), 'days': fields.integer('Number of Days', required=True, help="Number of days to add before computation of the day of month." \ "If Date=15/01, Number of Days=22, Day of Month=-1, then the due date is 28/02."), 'days2': fields.integer('Day of the Month', required=True, help="Day of the month, set -1 for the last day of the current month. If it's positive, it gives the day of the next month. Set 0 for net days (otherwise it's based on the beginning of the month)."), From 10fbcafa0366bff92d3a77f966408cb9c5e84a6a Mon Sep 17 00:00:00 2001 From: "ARA (OpenERP)" Date: Wed, 30 Mar 2011 11:48:09 +0530 Subject: [PATCH 009/189] [FIX] Account:Account chart wizard does not check if generated account code for bank journal exsits bzr revid: ara@tinyerp.com-20110330061809-3b28ug6dz37tq23v --- addons/account/account.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/addons/account/account.py b/addons/account/account.py index def72ec08d3..e25ec7fa08c 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -2930,18 +2930,13 @@ class wizard_multi_charts_accounts(osv.osv_memory): while valid: try: new_code = str(int(ref_acc_bank.code.ljust(dig, '0')) + current_num) - ids = obj_acc.search(cr, uid, [('code', '=', new_code)]) - if not ids: - valid = False - else: - current_num += 1 except: new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)), '0')) + str(current_num) - ids = obj_acc.search(cr, uid, [('code', '=', new_code)]) - if not ids: - valid = False - else: - current_num += 1 + ids = obj_acc.search(cr, uid, [('code', '=', new_code)]) + if not ids: + valid = False + else: + current_num += 1 vals = { 'name': tmp, 'currency_id': line.currency_id and line.currency_id.id or False, From 53cad5a3bf55108a443d726a2637f3bc3e9823a6 Mon Sep 17 00:00:00 2001 From: "ron@tinyerp.com" <> Date: Thu, 31 Mar 2011 16:52:06 +0530 Subject: [PATCH 010/189] [FIX]sale: wrong price calculation when changing UoM and pricelist based on other pricelist lp bug: https://launchpad.net/bugs/742100 fixed bzr revid: ron@tinyerp.com-20110331112206-5ww6yrqyc3y88yzw --- addons/product/pricelist.py | 1 + addons/sale/sale.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index 2271dbc86a6..4e7caff0e96 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -234,6 +234,7 @@ class product_pricelist(osv.osv): [res['base_pricelist_id']], product_id, qty, context=context)[res['base_pricelist_id']] ptype_src = self.browse(cr, uid, res['base_pricelist_id']).currency_id.id + uom_price_already_computed = True price = currency_obj.compute(cr, uid, ptype_src, res['currency_id'], price_tmp, round=False) elif res['base'] == -2: # this section could be improved by moving the queries outside the loop: diff --git a/addons/sale/sale.py b/addons/sale/sale.py index f80d610eb03..ac80f65e5d9 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -1111,6 +1111,8 @@ class sale_order_line(osv.osv): result['product_uos_qty'] = qty result['th_weight'] = q * product_obj.weight # Round the quantity up + if not uom: + uom =product_obj.uom_id and product_obj.uom_id.id if not uom2: uom2 = product_obj.uom_id if (product_obj.type=='product') and (product_obj.virtual_available * uom2.factor < qty * product_obj.uom_id.factor) \ From 79ca9ad384686e9fd70ec9f97fdf356bb5f5e5b1 Mon Sep 17 00:00:00 2001 From: "ron@tinyerp.com" <> Date: Fri, 1 Apr 2011 15:19:10 +0530 Subject: [PATCH 011/189] [IMP]product: wrong price calculation when changing UoM and pricelist based on other pricelist bzr revid: ron@tinyerp.com-20110401094910-stho2qg6pcgdtrve --- addons/product/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product/product.py b/addons/product/product.py index bab6b5f5cc1..a56f13e73fa 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -593,7 +593,7 @@ class product_product(osv.osv): res[product.id] = (res[product.id] * (product.price_margin or 1.0)) + \ product.price_extra if 'uom' in context: - uom = product.uos_id or product.uom_id + uom = product.uom_id or product.uos_id res[product.id] = product_uom_obj._compute_price(cr, uid, uom.id, res[product.id], context['uom']) # Convert from price_type currency to asked one From 4bc1c69250829f82ace458aeedca7b44a15c3ff0 Mon Sep 17 00:00:00 2001 From: "ron@tinyerp.com" <> Date: Mon, 4 Apr 2011 15:31:41 +0530 Subject: [PATCH 012/189] [REF]sale:refectoring code wrong price calculation when changing UoM and pricelist based on other pricelist bzr revid: ron@tinyerp.com-20110404100141-2i3og2pxcxf3n1sg --- addons/sale/sale.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index ac80f65e5d9..919358f500a 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -1111,8 +1111,6 @@ class sale_order_line(osv.osv): result['product_uos_qty'] = qty result['th_weight'] = q * product_obj.weight # Round the quantity up - if not uom: - uom =product_obj.uom_id and product_obj.uom_id.id if not uom2: uom2 = product_obj.uom_id if (product_obj.type=='product') and (product_obj.virtual_available * uom2.factor < qty * product_obj.uom_id.factor) \ @@ -1135,7 +1133,7 @@ class sale_order_line(osv.osv): else: price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist], product, qty or 1.0, partner_id, { - 'uom': uom, + 'uom': uom or result.get('product_uom'), 'date': date_order, })[pricelist] if price is False: From 0cf43b7857b45455be2076b52c99f5fa84f1a70d Mon Sep 17 00:00:00 2001 From: "Ferdinand @ Camptocamp" <> Date: Wed, 13 Apr 2011 13:02:11 +0530 Subject: [PATCH 013/189] [FIX] account: Improved invoice analysis report for calculation of total without tax lp bug: https://launchpad.net/bugs/748178 fixed bzr revid: pso@tinyerp.com-20110413073211-nktkleb1izezr7o0 --- .../account/report/account_invoice_report.py | 59 +++++++++++-------- .../report/account_invoice_report_view.xml | 4 +- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/addons/account/report/account_invoice_report.py b/addons/account/report/account_invoice_report.py index 9c7cf014e4d..4815b00ba25 100644 --- a/addons/account/report/account_invoice_report.py +++ b/addons/account/report/account_invoice_report.py @@ -69,6 +69,7 @@ class account_invoice_report(osv.osv): 'address_contact_id': fields.many2one('res.partner.address', 'Contact Address Name', readonly=True), 'address_invoice_id': fields.many2one('res.partner.address', 'Invoice Address Name', readonly=True), 'account_id': fields.many2one('account.account', 'Account',readonly=True), + 'account_line_id': fields.many2one('account.account', 'Account Line',readonly=True), 'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account',readonly=True), 'residual': fields.float('Total Residual', readonly=True), 'delay_to_pay': fields.float('Avg. Delay To Pay', readonly=True, group_operator="avg"), @@ -106,44 +107,48 @@ class account_invoice_report(osv.osv): ai.address_contact_id as address_contact_id, ai.address_invoice_id as address_invoice_id, ai.account_id as account_id, + ail.account_id as account_line_id, ai.partner_bank_id as partner_bank_id, sum(case when ai.type in ('out_refund','in_invoice') then - ail.quantity / u.factor * -1 + -ail.quantity / u.factor else ail.quantity / u.factor end) as product_qty, + sum(case when ai.type in ('out_refund','in_invoice') then - ail.quantity*ail.price_unit * -1 + -ail.price_subtotal else - ail.quantity*ail.price_unit + ail.price_subtotal end) / cr.rate as price_total, + +-- +-- FIXME the line total incl tax can't be caculated by deviding the invoice total / number of lines +-- sum(case when ai.type in ('out_refund','in_invoice') then - ai.amount_total * -1 + -ai.amount_total else ai.amount_total - end) / (CASE WHEN + end) / (CASE WHEN (select count(l.id) from account_invoice_line as l left join account_invoice as a ON (a.id=l.invoice_id) - where a.id=ai.id) <> 0 - THEN + where a.id=ai.id) <> 0 + THEN (select count(l.id) from account_invoice_line as l left join account_invoice as a ON (a.id=l.invoice_id) - where a.id=ai.id) - ELSE 1 + where a.id=ai.id) + ELSE 1 END) / cr.rate as price_total_tax, + (case when ai.type in ('out_refund','in_invoice') then - sum(ail.quantity*ail.price_unit*-1) + sum(-ail.price_subtotal) else - sum(ail.quantity*ail.price_unit) - end) / (CASE WHEN - (case when ai.type in ('out_refund','in_invoice') - then sum(ail.quantity/u.factor*-1) - else sum(ail.quantity/u.factor) end) <> 0 - THEN - (case when ai.type in ('out_refund','in_invoice') - then sum(ail.quantity/u.factor*-1) - else sum(ail.quantity/u.factor) end) - ELSE 1 + sum(ail.price_subtotal) + end) / (CASE WHEN sum(ail.quantity/u.factor) <> 0 + THEN + (case when ai.type in ('out_refund','in_invoice') + then sum(-ail.quantity/u.factor) + else sum(ail.quantity/u.factor) end) + ELSE 1 END) / cr.rate as price_average, @@ -159,22 +164,23 @@ class account_invoice_report(osv.osv): left join account_invoice_line as l ON (a.id=l.invoice_id) where a.id=ai.id)) as due_delay, (case when ai.type in ('out_refund','in_invoice') then - ai.residual * -1 + -ai.residual else ai.residual - end)/ (CASE WHEN + end)/ (CASE WHEN (select count(l.id) from account_invoice_line as l left join account_invoice as a ON (a.id=l.invoice_id) - where a.id=ai.id) <> 0 + where a.id=ai.id) <> 0 THEN (select count(l.id) from account_invoice_line as l left join account_invoice as a ON (a.id=l.invoice_id) - where a.id=ai.id) - ELSE 1 + where a.id=ai.id) + ELSE 1 END) / cr.rate as residual from account_invoice_line as ail left join account_invoice as ai ON (ai.id=ail.invoice_id) - left join product_template pt on (pt.id=ail.product_id) + left join product_product pr on (pr.id=ail.product_id) + left join product_template pt on (pt.id=pr.product_tmpl_id) left join product_uom u on (u.id=ail.uos_id), res_currency_rate cr where cr.id in (select id from res_currency_rate cr2 where (cr2.currency_id = ai.currency_id) @@ -202,6 +208,7 @@ class account_invoice_report(osv.osv): ai.address_contact_id, ai.address_invoice_id, ai.account_id, + ail.account_id, ai.partner_bank_id, ai.residual, ai.amount_total, diff --git a/addons/account/report/account_invoice_report_view.xml b/addons/account/report/account_invoice_report_view.xml index 6c1bc3f9762..a0a9729a775 100644 --- a/addons/account/report/account_invoice_report_view.xml +++ b/addons/account/report/account_invoice_report_view.xml @@ -27,10 +27,10 @@ + - @@ -103,6 +103,7 @@ + @@ -120,6 +121,7 @@ + From 3b31cb43692cfd1a7ef1c57dff8d4fc1928c1990 Mon Sep 17 00:00:00 2001 From: "Ujjvala Collins (OpenERP)" Date: Thu, 14 Apr 2011 11:03:11 +0530 Subject: [PATCH 014/189] [FIX] project: If a project is deleted its related analytic account should also be deleted. lp bug: https://launchpad.net/bugs/758699 fixed bzr revid: uco@tinyerp.com-20110414053311-ucmrf4vkl3ogl872 --- addons/project/project.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/project/project.py b/addons/project/project.py index 134364d8b1a..9473918bf95 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -118,9 +118,11 @@ class project(osv.osv): return result.keys() def unlink(self, cr, uid, ids, *args, **kwargs): + analytic_obj = self.pool.get('account.analytic.account') for proj in self.browse(cr, uid, ids): if proj.tasks: raise osv.except_osv(_('Operation Not Permitted !'), _('You can not delete a project with tasks. I suggest you to deactivate it.')) + analytic_obj.unlink(cr, uid, [proj.analytic_account_id.id]) return super(project, self).unlink(cr, uid, ids, *args, **kwargs) _columns = { From 96d2e9b535773c30b29f3c498170a28a833f2c00 Mon Sep 17 00:00:00 2001 From: cpa-openerp Date: Fri, 15 Apr 2011 15:02:53 +0530 Subject: [PATCH 015/189] [FIX] Dataset is used to read records (read_ids method). bzr revid: cpa@tinyerp.com-20110415093253-qx78tf0001u1cg4d --- addons/base_gantt/__openerp__.py | 4 +- addons/base_gantt/controllers/main.py | 176 +-------- .../lib/dhtmlxGantt/sources/dhtmlxgantt.js | 4 +- addons/base_gantt/static/src/js/gantt.js | 366 +++++++++++------- .../base_gantt/static/src/xml/base_gantt.xml | 5 +- 5 files changed, 231 insertions(+), 324 deletions(-) diff --git a/addons/base_gantt/__openerp__.py b/addons/base_gantt/__openerp__.py index 55cec2c0863..c23f352a4f7 100644 --- a/addons/base_gantt/__openerp__.py +++ b/addons/base_gantt/__openerp__.py @@ -3,8 +3,8 @@ "version": "2.0", "depends": ['base'], "js": [ - 'static/lib/dhtmlxGantt/codebase/dhtmlxcommon.js', - 'static/lib/dhtmlxGantt/codebase/dhtmlxgantt.js', + 'static/lib/dhtmlxGantt/sources/dhtmlxcommon.js', + 'static/lib/dhtmlxGantt/sources/dhtmlxgantt.js', 'static/src/js/gantt.js' ], "css": ['static/lib/dhtmlxGantt/codebase/dhtmlxgantt.css'], diff --git a/addons/base_gantt/controllers/main.py b/addons/base_gantt/controllers/main.py index 7edb4d28763..a2e52c0cb32 100644 --- a/addons/base_gantt/controllers/main.py +++ b/addons/base_gantt/controllers/main.py @@ -1,184 +1,24 @@ -import glob, os -from xml.etree import ElementTree -import math -import simplejson import openerpweb -import time -import datetime -from base.controllers.main import Xml2Json - +from base.controllers.main import View -COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400', - '#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', - '#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00', - '#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900', ] - -_colorline = ['#%02x%02x%02x' % (25 + ((r + 10) % 11) * 23, 5 + ((g + 1) % 11) * 20, 25 + ((b + 4) % 11) * 23) for r in range(11) for g in range(11) for b in range(11) ] - -def choice_colors(n): - if n > len(COLOR_PALETTE): - return _colorline[0:-1:len(_colorline) / (n + 1)] - elif n: - return COLOR_PALETTE[:n] - return [] - -class GanttView(openerpweb.Controller): +class GanttView(View): _cp_path = "/base_gantt/ganttview" - date_start = None - date_delay = None - date_stop = None - color_field = None - - day_length = 8 - fields = {} - events = [] - calendar_fields = {} - ids = [] model = '' domain = [] context = {} - event_res = [] - colors = {} - color_values = [] @openerpweb.jsonrequest def load(self, req, model, view_id): - m = req.session.model(model) - r = m.fields_view_get(view_id, 'gantt') - r["arch"] = Xml2Json.convert_to_structure(r["arch"]) - return {'fields_view':r} - - @openerpweb.jsonrequest - def get_events(self, req, **kw): - - self.model = kw['model'] - self.fields = kw['fields'] - self.day_length = kw['day_length'] - self.calendar_fields = kw['calendar_fields'] - self.color_field = kw.get('color_field') or self.color_field or None - self.fields[self.color_field] = "" - self.colors = kw.get('colors') or {} - self.text = self.calendar_fields['text']['name'] + fields_view = self.fields_view_get(req, model, view_id, 'gantt') + return {'fields_view':fields_view} - self.date_start = self.calendar_fields['date_start']['name'] - self.fields[self.date_start] = "" - - if self.calendar_fields.get('date_stop'): - self.date_stop = self.calendar_fields['date_stop']['name'] - self.fields[self.date_stop] = "" - if self.calendar_fields.get('date_delay'): - self.date_delay = self.calendar_fields['date_delay']['name'] - self.fields[self.date_delay] = "" - if self.calendar_fields.get('parent'): - self.parent = self.calendar_fields['parent']['name'] - self.fields[self.parent] = "" - - model = req.session.model(self.model) - event_ids = model.search([]) - - return self.create_event(event_ids, model) - - def create_event(self, event_ids, model): - - self.events = model.read(event_ids, self.fields.keys()) - result = [] - for evt in self.events: - - event_res = {} - key = evt[self.color_field] - name = key - value = key - if isinstance(key, list): # M2O, XMLRPC returns List instead of Tuple - name = key[0] - value = key[-1] - evt[self.color_field] = key = key[-1] - if isinstance(key, tuple): # M2O - value, name = key - - self.colors[key] = (name, value, None) - - st_date = evt.get(self.date_start) - if st_date: - self.set_format(st_date) - if self.date_delay: - duration = evt.get(self.date_delay) - else: - en_date = evt.get(self.date_stop) - - duration = (time.mktime(time.strptime(en_date, self.format))-\ - time.mktime(time.strptime(st_date, self.format)))/ (60 * 60) - - if duration > self.day_length : - d = math.floor(duration / 24) - h = duration % 24 - duration = d * self.day_length + h - - event_res = {} - event_res['start_date'] = st_date - event_res['duration'] = duration - event_res['text'] = evt.get(self.text) - event_res['id'] = evt['id'] - event_res['parent'] = evt.get(self.parent) - result.append(event_res) - - colors = choice_colors(len(self.colors)) - for i, (key, value) in enumerate(self.colors.items()): - self.colors[key] = [value[0], value[1], colors[i]] - - return {'result': result,'sidebar': self.colors} - - def set_format(self, st_date): - if len(st_date) == 10 : - self.format = "%Y-%m-%d" - else : - self.format = "%Y-%m-%d %H:%M:%S" - return - - def check_format(self, date): - if self.format == "%Y-%m-%d %H:%M:%S": - date = date + " 00:00:00" - return date - - @openerpweb.jsonrequest - def on_event_resize(self, req, **kw): - if self.date_delay: - key = self.date_delay - value = kw['duration'] - else: - key = self.date_stop - value = self.check_format(kw['end_date']) - try: - model = req.session.model(self.model) - res = model.write(kw['id'], {key : value}) - except Exception, e: - print "eeeeeeeeeeeeeeeeeeeeeeeeeee",e - return True - - @openerpweb.jsonrequest - def on_event_drag(self, req, **kw): - start_date = self.check_format(kw['start_date']) - if self.date_delay: - key = self.date_delay - value = kw['duration'] - else: - key = self.date_stop - value = self.check_format(kw['end_date']) - try: - model = req.session.model(self.model) - res = model.write(kw['id'], {self.date_start : start_date, key : value}) - except Exception, e: - print "eeeeeeeeeeeeeeeeeeeeeeeeeee",e - return True - @openerpweb.jsonrequest def reload_gantt(self, req, **kw): model = req.session.model(kw['model']) - if (kw['domain']): - domain = (kw['color_field'],'in', kw['domain']) - event_ids = model.search([domain]) - else: - event_ids = model.search([]) - return self.create_event(event_ids, model) + domain = kw['domain'] + + event_ids = model.search(domain) + return event_ids \ No newline at end of file diff --git a/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxgantt.js b/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxgantt.js index 52b9b562e96..7efcd730293 100644 --- a/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxgantt.js +++ b/addons/base_gantt/static/lib/dhtmlxGantt/sources/dhtmlxgantt.js @@ -348,7 +348,7 @@ GanttProject.prototype.create = function() * @type: public * @topic: 0 */ -function GanttChart() +function GanttChart(day_length) { this.Error = new GanttError(); this.dhtmlXMLSenderObject = new dhtmlXMLSenderObject(this); @@ -356,7 +356,7 @@ function GanttChart() //settings this.heightTaskItem = 12; this.dayInPixels = 24; - this.hoursInDay = 8; + this.hoursInDay = day_length; this._showTreePanel = true; this._showTooltip = true; this.isShowDescTask = false; diff --git a/addons/base_gantt/static/src/js/gantt.js b/addons/base_gantt/static/src/js/gantt.js index f8391f2744b..f23da0c580d 100644 --- a/addons/base_gantt/static/src/js/gantt.js +++ b/addons/base_gantt/static/src/js/gantt.js @@ -7,7 +7,8 @@ QWeb.add_template('/base_gantt/static/src/xml/base_gantt.xml'); openerp.base.views.add('gantt', 'openerp.base_gantt.GanttView'); openerp.base_gantt.GanttView = openerp.base.Controller.extend({ - init: function(view_manager, session, element_id, dataset, view_id) { +init: function(view_manager, session, element_id, dataset, view_id) { + this._super(session, element_id); this.view_manager = view_manager; this.dataset = dataset; @@ -16,82 +17,224 @@ openerp.base_gantt.GanttView = openerp.base.Controller.extend({ this.fields_views = {}; this.widgets = {}; this.widgets_counter = 0; - this.fields = {}; - this.datarecord = {}; - this.calendar_fields = {}; - }, - do_show: function () { - // TODO: re-trigger search - this.$element.show(); - }, - do_hide: function () { - this.$element.hide(); + this.fields = this.dataset.fields ? this.dataset.fields: {}; + this.ids = this.dataset.ids; + this.name = ""; + this.date_start = ""; + this.date_delay = ""; + this.date_stop = ""; + this.color_field = ""; + this.day_lenth = 8; + this.colors = []; + this.color_values = []; + this.calendar_fields = {}; + this.info_fields = []; + this.domain = this.dataset._domain ? this.dataset._domain: []; + this.context = {}; + }, + start: function() { + this.rpc("/base_gantt/ganttview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded); + }, + on_loaded: function(data) { + + var self = this; this.fields_view = data.fields_view; - var self = this; this.name = this.fields_view.name || this.fields_view.arch.attrs.string; this.view_id = this.fields_view.view_id; this.date_start = this.fields_view.arch.attrs.date_start; this.date_delay = this.fields_view.arch.attrs.date_delay; this.date_stop = this.fields_view.arch.attrs.date_stop; - this.color_field = this.fields_view.arch.attrs.color; + this.color_field = this.fields_view.arch.attrs.color; this.day_length = this.fields_view.arch.attrs.day_length || 8; this.colors = this.fields_view.arch.attrs.colors; - this.fields = this.fields_view.fields; this.text = this.fields_view.arch.children[0].children[0].attrs.name; this.parent = this.fields_view.arch.children[0].attrs.link; - - this.calendar_fields['parent'] = {'name': this.parent}; - this.calendar_fields['date_start'] = {'name': this.date_start}; - this.calendar_fields['text'] = {'name': this.text}; - if(this.date_delay) - this.calendar_fields['date_delay'] = {'name': this.date_delay}; - if(this.date_stop) - this.calendar_fields['date_stop'] = {'name': this.date_stop}; - - this.calendar_fields['day_length'] = this.day_length; - this.rpc('/base_gantt/ganttview/get_events', - {'model': this.model, - 'fields': this.fields, - 'color_field': this.color_field, - 'day_length': this.day_length, - 'calendar_fields': this.calendar_fields, - 'colors': this.colors, - 'info_fields': this.info_fields - }, - function(res) { - self.create_gantt(); - self.load_event(res); - }) + + this.format = "%Y-%m-%d"; + this.time = "00:00:00"; + + self.create_gantt(); + self.get_events(self.ids); + this.$element.html(QWeb.render("GanttView", {"view": this, "fields_view": this.fields_view})); }, + + create_gantt: function() { + + ganttChartControl = new GanttChart(this.day_length); + ganttChartControl.setImagePath("/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/"); + ganttChartControl.setEditable(true); + ganttChartControl.showTreePanel(true); + ganttChartControl.showContextMenu(true); + ganttChartControl.showDescTask(true,'d,s-f'); + ganttChartControl.showDescProject(true,'n,d'); + + }, + + get_events: function(event_ids) { + + var self = this; + this.dataset.read_ids(event_ids, {}, function(result) { + self.load_event(result); + }); + + }, + + load_event: function(events) { + + var self = this; + var result = events; + var project_id = new Array(); + var project = new Array(); + var sidebar = {} + var j = -1; + + for (i in result) { + + if (result[i][this.date_start] != false){ + var parent_id = result[i][this.parent][0]; + var parent_name = result[i][this.parent][1]; + + if (jQuery.inArray(parent_id, project_id) == -1){ + if (parent_id == undefined){ + parent_name = ""; + } + j = j + 1; + project[j] = new GanttProjectInfo(parent_id, parent_name, new Date(2011, 1, 1)); + project_id[j] = parent_id; + } + + var id = result[i]['id']; + var text = result[i][this.text]; + + var start_date = this.convert_date_format(result[i][this.date_start]); + + if (this.date_stop != undefined){ + if (result[i][this.date_stop] != false){ + var stop_date = this.convert_date_format(result[i][this.date_stop]); + var duration= self.hours_between(start_date, stop_date); + } + else{ + var duration = 0; + } + } + else{ + var duration = result[i][this.date_delay]; + } + if (duration == false) + duration = 0 + + var task = new GanttTaskInfo(id, text, start_date, duration, 100, ""); + + k = project_id.indexOf(parent_id); + project[k].addTask(task); + } + } + + for (i in project_id){ + ganttChartControl.addProject(project[i]); + } + + ganttChartControl.create("GanttDiv"); + ganttChartControl.attachEvent("onTaskEndResize", function(task) {self.on_task_end_resize(task);}) + ganttChartControl.attachEvent("onTaskEndDrag", function(task) {self.on_task_end_drag(task);}) + + }, + + hours_between: function(date1, date2) { + + var ONE_DAY = 1000 * 60 * 60 * 24 + var date1_ms = date1.getTime() + var date2_ms = date2.getTime() + var difference_ms = Math.abs(date1_ms - date2_ms) + + d = Math.round(difference_ms / ONE_DAY) + h = Math.round(difference_ms % ONE_DAY) + + return (d * this.day_length) + h; + + }, + + on_task_end_resize : function(task) { + + var event_id = task.getId(); + var data = {}; + + if (this.date_stop != undefined){ + data[this.date_stop] = this.reverse_convert_date_format(task.getFinishDate()); + }else{ + data[this.date_delay] = task.getDuration(); + } + this.dataset.write(event_id, data, function(result) {}); + + }, + + on_task_end_drag : function(task) { + + var event_id = task.getId(); + var data = {}; + + data[this.date_start] = this.reverse_convert_date_format(task.getEST()); + + if (this.date_stop != undefined){ + data[this.date_stop] = this.reverse_convert_date_format(task.getFinishDate()); + }else{ + data[this.date_delay] = task.getDuration(); + } + + this.dataset.write(event_id, data, function(result) {}); + + }, + + do_show: function () { + + this.$element.show(); + + }, + + do_hide: function () { + + this.$element.hide(); + + }, + convert_date_format: function(date) { - date=date+""; - if(typeof (date)!="string"||date.length===0){ + var self = this; + + if (date.length == 19){ + self.format = "%Y-%m-%d %H:%M:%S"; + self.time = date.split(' ')[1]; + } + + date = date+""; + if(typeof (date) != "string" || date.length === 0){ return null; } var iso=date.split("-"); - if(iso.length===0){ + if(iso.length === 0){ return null; } var day = iso[2]; + var iso_hours = day.split(' '); if (iso_hours.length > 1) { day = iso_hours[0]; - var iso_date_hours = iso_hours[1].split(':') + var iso_date_hours = iso_hours[1].split(':'); var new_date = new Date(iso[0], iso[1] - 1, day); new_date.setHours(iso_date_hours[0]); new_date.setMinutes(iso_date_hours[1]); new_date.setSeconds(iso_date_hours[2]); + } else { var new_date = new Date(iso[0], iso[1] - 1, day); @@ -100,125 +243,52 @@ openerp.base_gantt.GanttView = openerp.base.Controller.extend({ new_date.setMonth(iso[1]-1); new_date.setDate(day); return new_date; + }, - create_gantt: function() { - ganttChartControl = new GanttChart(); - ganttChartControl.setImagePath("/base_gantt/static/lib/dhtmlxGantt/codebase/imgs/"); - ganttChartControl.setEditable(true); - ganttChartControl.showTreePanel(true); - ganttChartControl.showContextMenu(true); - ganttChartControl.showDescTask(true,'d,s-f'); - ganttChartControl.showDescProject(true,'n,d'); - }, - load_event: function(res) { - var self = this - var result = res.result; - var sidebar = res.sidebar; - var project_id = new Array(); - var project = new Array(); - var j = -1; - var self = this; - for (i in result) { - - var parent_id = result[i]['parent'][0]; - var parent_name = result[i]['parent'][1]; - - if (jQuery.inArray(parent_id, project_id) == -1){ - if (parent_id == undefined){ - parent_name = ""; - } - j = j + 1; - project[j] = new GanttProjectInfo(parent_id, parent_name, new Date(2011, 1, 1)); - project_id[j] = parent_id; - } - - var id = result[i]['id']; - var text = result[i]['text']; - var start_date = this.convert_date_format(result[i]['start_date']); - var duration = result[i]['duration']; - - var task = new GanttTaskInfo(id, text, start_date, duration, 100, ""); - - k = project_id.indexOf(parent_id); - project[k].addTask(task); + reverse_convert_date_format: function(date) { + var self = this; - } - for (i in project_id){ - ganttChartControl.addProject(project[i]); - } - ganttChartControl.create("GanttDiv"); - ganttChartControl.attachEvent("onTaskEndResize", function(task) {self.on_task_end_resize(task);}) - ganttChartControl.attachEvent("onTaskEndDrag", function(task) {self.on_task_end_drag(task);}) + if (self.format == "%Y-%m-%d %H:%M:%S") + { + return date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()+' '+self.time; + } + else + { + return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate(); + } - //Create Sidebar - if (jQuery('#cal-sidebar-option').length == 0){ - jQuery('#gantt-sidebar').append( - jQuery('',{'width':'100%','cellspacing': 0, 'cellpadding': 0, 'id':'cal-sidebar-option'}) - ) - for(s in sidebar) { - jQuery('#cal-sidebar-option').append( - jQuery('').append( - jQuery('
').append( - jQuery('
') - .append( - jQuery('', - { - 'type': 'checkbox', - 'id':sidebar[s][0], - 'value':sidebar[s][0] - }).bind('click',function(){ - self.reload_gantt(self.color_field,self.model) - }), - sidebar[s][1] - ) - .css('background-color',sidebar[s][sidebar[s].length-1]) - ) - ) - ) - } - } }, - reload_gantt: function(color_field, model) { - var domain = []; - var self = this; - jQuery('input[type=checkbox]:checked','#cal-sidebar-option').each(function() { - domain.push(parseInt(jQuery(this).attr('id'))) - }); + + reload_gantt: function(domain) { + + var self = this; + this.rpc('/base_gantt/ganttview/reload_gantt',{ - 'domain':domain, - 'color_field':color_field, - 'model': model - },function(res) { + 'domain': domain, + 'model': self.model + },function(event_ids) { ganttChartControl.clearAll(); jQuery("#GanttDiv").children().remove(); - self.load_event(res); + self.get_events(event_ids); }); - }, - reverse_convert_date_format: function(date) { - return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate(); + }, - on_task_end_resize : function(task) { - this.rpc('/base_gantt/ganttview/on_event_resize', - {'id' : task.getId(), - 'end_date' : this.reverse_convert_date_format(task.getFinishDate()), - 'duration' : task.getDuration() - }, - function(result) { - }) - }, - on_task_end_drag : function(task) { - this.rpc('/base_gantt/ganttview/on_event_drag', - {'id' : task.getId(), - 'start_date' : this.reverse_convert_date_format(task.getEST()), - 'end_date' : this.reverse_convert_date_format(task.getFinishDate()), - 'duration' : task.getDuration() - }, - function(result) { - }) + do_search: function (domains, contexts, groupbys) { + var self = this; + return this.rpc('/base/session/eval_domain_and_context', { + domains: domains, + contexts: contexts, + group_by_seq: groupbys + }, function (results) { + + self.dataset.context = results.context; + self.dataset.domain = results.domain; + return self.reload_gantt(self.dataset.domain); + }); } - + }); // here you may tweak globals object, if any, and play with on_* or do_* callbacks on them diff --git a/addons/base_gantt/static/src/xml/base_gantt.xml b/addons/base_gantt/static/src/xml/base_gantt.xml index 72c14ceb16c..c85abf0cad8 100644 --- a/addons/base_gantt/static/src/xml/base_gantt.xml +++ b/addons/base_gantt/static/src/xml/base_gantt.xml @@ -3,12 +3,9 @@

- -
+
-
-
From 26e21b097e151c1d93aea77049ca5eab2758728a Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 19 Apr 2011 17:34:59 +0200 Subject: [PATCH 016/189] [FIX] account: fix error on initial balance if we don't give any criteria lp bug: https://launchpad.net/bugs/744789 fixed bzr revid: qdp-launchpad@openerp.com-20110419153459-fpd1zitw5ud3lzct --- addons/account/account_move_line.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 83a67df9178..e541a8f7490 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -93,6 +93,10 @@ class account_move_line(osv.osv): else: query = obj+".state <> 'draft' AND "+obj+".period_id IN (SELECT id FROM account_period WHERE fiscalyear_id IN (%s)) %s %s" % (fiscalyear_clause, where_move_state, where_move_lines_by_date) + if initial_bal and not context.get('periods', False) and not where_move_lines_by_date: + #we didn't pass any filter in the context, and the initial balance can't be computed using only the fiscalyear otherwise entries will be summed twice + #so we have to invalidate this query + query += " AND 1=2" if context.get('journal_ids', False): query += ' AND '+obj+'.journal_id IN (%s)' % ','.join(map(str, context['journal_ids'])) From b2a3d521faf426e6affcea10d1dee3f707065a90 Mon Sep 17 00:00:00 2001 From: "ARA (OpenERP)" Date: Wed, 27 Apr 2011 12:33:18 +0530 Subject: [PATCH 017/189] [FIX] account: payment term line need at least 5 to 6 digits precision bzr revid: ara@tinyerp.com-20110427070318-nq5757mhtqbay99o --- addons/account/account.py | 2 +- addons/account/data/account_data2.xml | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/account/account.py b/addons/account/account.py index 1dab0d077af..fec7f39d86e 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -102,7 +102,7 @@ class account_payment_term_line(osv.osv): ('fixed', 'Fixed Amount')], 'Valuation', required=True, help="""Select here the kind of valuation related to this payment term line. Note that you should have your last line with the type 'Balance' to ensure that the whole amount will be threated."""), - 'value_amount': fields.float('Value Amount', digits=(16, 6), help="For Value percent enter % ratio between 0-1."), + 'value_amount': fields.float('Value Amount', digits_compute=dp.get_precision('Payment Term'), help="For Value percent enter % ratio between 0-1."), 'days': fields.integer('Number of Days', required=True, help="Number of days to add before computation of the day of month." \ "If Date=15/01, Number of Days=22, Day of Month=-1, then the due date is 28/02."), 'days2': fields.integer('Day of the Month', required=True, help="Day of the month, set -1 for the last day of the current month. If it's positive, it gives the day of the next month. Set 0 for net days (otherwise it's based on the beginning of the month)."), diff --git a/addons/account/data/account_data2.xml b/addons/account/data/account_data2.xml index 4f482b496af..4a44c726960 100644 --- a/addons/account/data/account_data2.xml +++ b/addons/account/data/account_data2.xml @@ -21,7 +21,10 @@ - + + Payment Term + 6 + From 5060d7111c0c08abd77b69c19a3777f0e3088abf Mon Sep 17 00:00:00 2001 From: "sma (Tiny)" Date: Wed, 27 Apr 2011 17:50:51 +0530 Subject: [PATCH 018/189] [IMP] Implement many2one initiall work. bzr revid: sma@tinyerp.com-20110427122051-h80fka7fqjz0fcpz --- addons/base/controllers/main.py | 6 +++ addons/base/static/src/base.html | 1 + addons/base/static/src/css/base.css | 59 +++++++++++++++++++++++++++++ addons/base/static/src/js/base.js | 1 + addons/base/static/src/js/data.js | 10 +++++ addons/base/static/src/js/form.js | 16 ++++++++ addons/base/static/src/xml/base.xml | 5 ++- addons/base/static/test/test.html | 1 + 8 files changed, 98 insertions(+), 1 deletion(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 8faca685300..a1560936213 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -420,6 +420,12 @@ class DataSet(openerpweb.Controller): r = m.default_get(fields, context) return {'result': r} + @openerpweb.jsonrequest + def name_search(self, req, model, search_str, domain=[], context={}): + m = req.session.model(model) + r = m.name_search(search_str, domain, 'ilike', context) + return {'result': r} + class View(openerpweb.Controller): def fields_view_get(self, request, model, view_id, view_type, transform=True, toolbar=False, submenu=False): diff --git a/addons/base/static/src/base.html b/addons/base/static/src/base.html index 83fbfcecefc..8d18b2f14ca 100644 --- a/addons/base/static/src/base.html +++ b/addons/base/static/src/base.html @@ -23,6 +23,7 @@ + diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 1bd004b53f6..dc16c772785 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -779,3 +779,62 @@ body.openerp { background: url(http://placekitten.com/g/212/100) repeat; } +/* Many2one Autosearch */ + +.openerp .combo_img { + position: absolute; + margin-left: -19px; + margin-top: 3px; +} + +.openerp .autoTextResults { + position: absolute; + z-index: 1000; + background-color: #fff; + border: 1px solid #333; + display: none; + padding: 0 2px 0 2px; + min-width: 132px; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + color: #1F1F1F; + overflow: auto; +} + +.openerp table.autoTextTable { + border: none; + font-family: arial, sans-serif; + font-size: 13px; + font-style: normal; + font-variant: normal; + font-weight: normal; + width: 100%; +} + +.openerp table.autoTextTable tr.autoTextNormalRow td { +} + +.openerp table.autoTextTable tr.autoTextSelectedRow td { + background-color: DarkGray; + color: #1F1F1F; + cursor: pointer; +} + +.openerp table.autoTextTable ul{ + list-style-image:none; + list-style-type:none; +} + +.openerp table.autoTextTable td a.autoTextHighlight { + font-weight: bold; + text-decoration: none; + color: #FFF; +} + +.openerp table.autoTextTable td.autoTextHidden { + display: none; +} + +/* ------------- End autocomplete ------- */ + diff --git a/addons/base/static/src/js/base.js b/addons/base/static/src/js/base.js index 504f5ca744d..615b2c8e889 100644 --- a/addons/base/static/src/js/base.js +++ b/addons/base/static/src/js/base.js @@ -125,6 +125,7 @@ openerp.base = function(instance) { openerp.base.views(instance); openerp.base.search(instance); openerp.base.list(instance); + openerp.base.m2o(instance); openerp.base.form(instance); }; diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index a29f320b79c..79482f33430 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -118,6 +118,16 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base. ids: ids, args: args }, callback); + + }, + name_search: function (search_str, callback) { + search_str = search_str || ''; + return this.rpc('/base/dataset/name_search', { + model: this.model, + search_str: search_str, + domain: this.domain || [], + context: this.context + }, callback); }, exec_workflow: function (id, signal, callback) { return this.rpc('/base/dataset/exec_workflow', { diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 84d7fe0babd..9a5e092b142 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -824,10 +824,24 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({ } }); +openerp.base.form.FieldMany2OneDatasSet = openerp.base.DataSetStatic.extend({ + start: function() { + }, + write: function (id, data, callback) { + this._super(id, data, callback); + }, +}); + openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ init: function(view, node) { this._super(view, node); this.template = "FieldMany2One"; + this.is_field_m2o = true; + }, + start: function() { + this.$element = $('#' + this.element_id); + this.dataset = new openerp.base.form.FieldMany2OneDatasSet(this.session, this.field.relation); + new openerp.base.m2o(this.$element, this.field.relation, this.dataset) }, set_value: function(value) { this._super.apply(this, arguments); @@ -837,6 +851,8 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ this.value = value[0]; } this.$element.find('input').val(show_value); + // Need to replace this `text` with original `id` after discuss with xmo + this.$element.find('input').attr('text', this.value); } }); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index b49ef2c7d6a..c59229511a9 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -257,7 +257,7 @@
+ +
diff --git a/addons/base/static/test/test.html b/addons/base/static/test/test.html index 5fcf4f4c594..b71e8231bd7 100644 --- a/addons/base/static/test/test.html +++ b/addons/base/static/test/test.html @@ -21,6 +21,7 @@ + + diff --git a/addons/base/static/lib/qweb/qweb2.js b/addons/base/static/lib/qweb/qweb2.js index edf8f8b2b21..3c473423a44 100644 --- a/addons/base/static/lib/qweb/qweb2.js +++ b/addons/base/static/lib/qweb/qweb2.js @@ -77,6 +77,41 @@ var QWeb2 = { } return -1; }, + xml_node_to_string : function(node, childs_only) { + if (childs_only) { + var childs = node.childNodes, r = []; + for (var i = 0, ilen = childs.length; i < ilen; i++) { + r.push(this.xml_node_to_string(childs[i])); + } + return r.join(''); + } else { + if (node.xml !== undefined) { + return node.xml; + } else { + return (new XMLSerializer()).serializeToString(node); + } + } + }, + xpath_selectNodes : function(node, expr) { + if (node.selectNodes !== undefined) { + return node.selectNodes(expr); + } else { + var xpath = new XPathEvaluator(); + try { + var result = xpath.evaluate(expr, node, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); + } catch(error) { + this.exception("Error with XPath expression '" + expr + "' : " + error); + } + var r = []; + if (result != null) { + var element; + while (element = result.iterateNext()) { + r.push(element); + } + } + return r + } + }, call: function(context, template, old_dict, _import, callback) { var new_dict = this.extend({}, old_dict); new_dict['__caller__'] = old_dict['__template__']; @@ -157,8 +192,10 @@ QWeb2.Engine = (function() { this.templates_resources = []; // TODO: implement this.reload() this.templates = {}; this.compiled_templates = {}; + this.extend_templates = {}; this.dict = {}; this.tools = QWeb2.tools; + this.jQuery = window.jQuery; for (var i = 0; i < arguments.length; i++) { this.add_template(arguments[i]); } @@ -178,8 +215,16 @@ QWeb2.Engine = (function() { return this.tools.exception(node.innerText); } var name = node.getAttribute(this.prefix + '-name'); + var extend = node.getAttribute(this.prefix + '-extend'); if (name) { this.templates[name] = node; + } else if (extend) { + delete(this.compiled_templates[extend]); + if (this.extend_templates[extend]) { + this.extend_templates[extend].push(node); + } else { + this.extend_templates[extend] = [node]; + } } } } @@ -256,15 +301,26 @@ QWeb2.Engine = (function() { "});"; }, render : function(template, dict) { - //console.time("QWeb render template " + template); + if (this.debug && window['console'] !== undefined) { + console.time("QWeb render template " + template); + } var r = this._render(template, dict); - //console.timeEnd("QWeb render template " + template); + if (this.debug && window['console'] !== undefined) { + console.timeEnd("QWeb render template " + template); + } return r; }, _render : function(template, dict) { if (this.compiled_templates[template]) { return this.compiled_templates[template].apply(this, [dict || {}]); } else if (this.templates[template]) { + var ext; + if (ext = this.extend_templates[template]) { + var extend_node; + while (extend_node = ext.shift()) { + this.extend(template, extend_node); + } + } var code = this.compile(this.templates[template]), tcompiled; try { // tcompiled = new Function(code); TODO: Check if could use this in order to avoid eval @@ -278,6 +334,53 @@ QWeb2.Engine = (function() { } else { return this.tools.exception("Template '" + template + "' not found"); } + }, + extend : function(template, extend_node) { + if (!this.jQuery) { + return this.tools.exception("Can't extend template " + template + " without jQuery"); + } + for (var i = 0, ilen = extend_node.childNodes.length; i < ilen; i++) { + var child = extend_node.childNodes[i]; + if (child.nodeType === 1) { + var xpath = child.getAttribute(this.prefix + '-xpath'), + jquery = child.getAttribute(this.prefix + '-jquery'), + operation = child.getAttribute(this.prefix + '-operation'), + target, + error_msg = "Error while extending template '" + template; + if (jquery) { + target = this.jQuery(jquery, this.templates[template]); + } else if (xpath) { + // NOTE: due to the XPath implementation, extending a template will only work once + // when using XPath because XPathResult won't match objects with other constructor than 'Element' + // As jQuery will create HTMLElements, xpath will ignore them then causing problems when a + // template has already been extended. XPath selectors will probably be removed in QWeb. + target = this.jQuery(this.tools.xpath_selectNodes(this.templates[template], xpath)); + } else { + this.tools.exception(error_msg + "No expression given"); + } + error_msg += "' (expression='" + (jquery || xpath) + "') : "; + var inner = this.tools.xml_node_to_string(child, true); + if (operation) { + var allowed_operations = "append,prepend,before,after,replace,inner".split(','); + if (this.tools.arrayIndexOf(allowed_operations, operation) == -1) { + this.tools.exception(error_msg + "Invalid operation : '" + operation + "'"); + } + operation = {'replace' : 'replaceWith', 'inner' : 'html'}[operation] || operation; + target[operation]($(inner)); + } else { + try { + var f = new Function(['$'], inner); + } catch(error) { + return this.tools.exception("Parse " + error_msg + error); + } + try { + f.apply(target, [this.jQuery]); + } catch(error) { + return this.tools.exception("Runtime " + error_msg + error); + } + } + } + } } }); return Engine; From 40b1aa2de182c9ef96572289619947176edbf78d Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 9 May 2011 12:05:41 +0200 Subject: [PATCH 075/189] [IMP] search popup wip bzr revid: nicolas.vanhoren@openerp.com-20110509100541-g0iqhn00e3q17yw4 --- addons/base/static/src/js/form.js | 27 +++++++++++++++++++++++---- addons/base/static/src/xml/base.xml | 7 ++++--- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index bf3c806140a..33c855af537 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -962,9 +962,9 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({ }, do_add_record: function (e) { e.stopImmediatePropagation(); - debugger; var pop = new openerp.base.form.Many2XSelectPopup(null, this.m2m_field.view.session); - pop.select_element(null,null); + pop.select_element(this.model); + //TODO niv: add callback }, on_select_row: function(event) { var $target = $(event.currentTarget); @@ -989,14 +989,33 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({ identifier_prefix: "many2xselectpopup", template: "Many2XSelectPopup", - select_element: function(model, callback) { + select_element: function(model) { this.model = model; - this.callback = callback; var html = this.render(); jQuery(html).dialog({title: '', modal: true, minWidth: 800}); this.start(); + }, + start: function() { + this.dataset = new openerp.base.DataSetSearch(this.session, this.model); + this.setup_search_view(); + }, + setup_search_view: function() { + var self = this; + if (this.searchview) { + this.searchview.stop(); + } + this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", + this.dataset, false, {}); + /*this.searchview.on_search.add(function(domains, contexts, groupbys) { + //TODO niv: do it correctly + self.views[self.active_view].controller.do_search.call( + self, domains, contexts, groupbys); + });*/ + return this.searchview.start(); + }, + on_select_element: function(element_id) { } }); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 7df230f3d3e..84528b75e9b 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -491,7 +491,8 @@ -
+
+
@@ -572,8 +573,8 @@
-
- Brian is in the kitchen. +
+
From cb854aa0b39653ea6f5f6850d0956d91aeb121aa Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 9 May 2011 12:59:53 +0200 Subject: [PATCH 076/189] [FIX] Rendering issue in Chrome. bzr revid: nicolas.vanhoren@openerp.com-20110509105953-ffjp4t06p6gulumd --- addons/base/static/src/js/search.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js index ae5e8551b93..efaca3c0239 100644 --- a/addons/base/static/src/js/search.js +++ b/addons/base/static/src/js/search.js @@ -121,7 +121,10 @@ openerp.base.SearchView = openerp.base.Controller.extend({ 'lines': lines, 'defaults': this.defaults }); - this.$element.html(render); + // We don't understand why the following commented line does not work in Chrome but + // the non-commented line does. As far as we investigated, only God knows. + //this.$element.html(render); + jQuery(render).appendTo(this.$element); var f = this.$element.find('form'); this.$element.find('form') From 98b32b936f36ad59a2fb985390198988648e7a53 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 9 May 2011 13:21:43 +0200 Subject: [PATCH 077/189] [IMP] product: improved order of product_category bzr revid: qdp-launchpad@openerp.com-20110509112143-hwl7z720g2fuk0co --- addons/product/product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/product/product.py b/addons/product/product.py index 4865f71c4f6..aad703b0afb 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -218,7 +218,7 @@ class product_category(osv.osv): 'type' : lambda *a : 'normal', } - _order = "sequence" + _order = "sequence, name" def _check_recursion(self, cr, uid, ids, context=None): level = 100 while len(ids): From a1149a97c6250aca4dfb54a0cf7817f422d5fdae Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Mon, 9 May 2011 13:52:33 +0200 Subject: [PATCH 078/189] [IMP] Many2x search popup wip. Currently working, need to add possibility to create new object. bzr revid: nicolas.vanhoren@openerp.com-20110509115233-j1j004r9yxlhm63x --- addons/base/static/src/js/form.js | 28 +++++++++++++++++++++++----- addons/base/static/src/xml/base.xml | 1 + 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 33c855af537..37a5683360a 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -964,7 +964,15 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({ e.stopImmediatePropagation(); var pop = new openerp.base.form.Many2XSelectPopup(null, this.m2m_field.view.session); pop.select_element(this.model); - //TODO niv: add callback + var self = this; + pop.on_select_element.add(function(element_id) { + if(! _.detect(self.dataset.ids, function(x) {return x == element_id;})) { + self.dataset.ids.push(element_id); + self.dataset.count = self.dataset.ids.length; + self.do_reload(); + } + pop.stop(); + }); }, on_select_row: function(event) { var $target = $(event.currentTarget); @@ -998,8 +1006,13 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({ this.start(); }, start: function() { + this._super(); this.dataset = new openerp.base.DataSetSearch(this.session, this.model); this.setup_search_view(); + this.view_list = new openerp.base.form.Many2XPopupListView( null, this.session, + this.element_id + "_view_list", this.dataset, false); + this.view_list.popup = this; + this.view_list.start(); }, setup_search_view: function() { var self = this; @@ -1008,17 +1021,22 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({ } this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, false, {}); - /*this.searchview.on_search.add(function(domains, contexts, groupbys) { - //TODO niv: do it correctly - self.views[self.active_view].controller.do_search.call( + this.searchview.on_search.add(function(domains, contexts, groupbys) { + self.view_list.do_search.call( self, domains, contexts, groupbys); - });*/ + }); return this.searchview.start(); }, on_select_element: function(element_id) { } }); +openerp.base.form.Many2XPopupListView = openerp.base.ListView.extend({ + switch_to_record: function(index) { + this.popup.on_select_element(this.dataset.ids[index]); + } +}); + openerp.base.form.FieldReference = openerp.base.form.Field.extend({ init: function(view, node) { this._super(view, node); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 84528b75e9b..d6c4d3edbb1 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -575,6 +575,7 @@
+
From d6bf99ff900c49021b32110b2a8f817e2fea3cbe Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 9 May 2011 14:03:54 +0200 Subject: [PATCH 079/189] [IMP] Removed font weight bold on form's labels bzr revid: fme@openerp.com-20110509120354-e4ssdfk66f2vtxoj --- addons/base/static/src/css/base.css | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 0ca1c995b33..8c4df744219 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -568,7 +568,6 @@ body.openerp { /* Form */ .openerp table.oe_frame td { color: #4c4c4c; - font-weight: bold; } .openerp .required.error { border: 1px solid #900; From 84c0e981ec15fb8015fcaead877ea5faebce9dc2 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 9 May 2011 14:19:01 +0200 Subject: [PATCH 080/189] [ADD] Added clone template in QWeb2 (t-name & t-extend) bzr revid: fme@openerp.com-20110509121901-kmpcn7n6gsrjx6bl --- addons/base/static/lib/qweb/qweb-test-extend.xml | 5 +++++ addons/base/static/lib/qweb/qweb-test.js.html | 2 ++ addons/base/static/lib/qweb/qweb2.js | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/addons/base/static/lib/qweb/qweb-test-extend.xml b/addons/base/static/lib/qweb/qweb-test-extend.xml index 23e10d52599..44fda920e43 100644 --- a/addons/base/static/lib/qweb/qweb-test-extend.xml +++ b/addons/base/static/lib/qweb/qweb-test-extend.xml @@ -24,4 +24,9 @@ END + + +
  • CLONED TEMPLATE
  • +
    + diff --git a/addons/base/static/lib/qweb/qweb-test.js.html b/addons/base/static/lib/qweb/qweb-test.js.html index e341fa753fd..fda837497c4 100644 --- a/addons/base/static/lib/qweb/qweb-test.js.html +++ b/addons/base/static/lib/qweb/qweb-test.js.html @@ -251,6 +251,8 @@ test("jQuery extend", function () { equals(render('jquery-extend', {}), '
    • 1
    • 2
    • 3
    END
    ', "Extend template with jQuery"); + equals(render('jquery-extend-clone', {}), '
    • one
    • CLONED TEMPLATE
    ', + "Clone template"); }); }); diff --git a/addons/base/static/lib/qweb/qweb2.js b/addons/base/static/lib/qweb/qweb2.js index 3c473423a44..36d0dce09c4 100644 --- a/addons/base/static/lib/qweb/qweb2.js +++ b/addons/base/static/lib/qweb/qweb2.js @@ -216,6 +216,15 @@ QWeb2.Engine = (function() { } var name = node.getAttribute(this.prefix + '-name'); var extend = node.getAttribute(this.prefix + '-extend'); + if (name && extend) { + // Clone template and extend it + if (!this.templates[extend]) { + return this.tools.exception("Can't clone undefined template " + extend); + } + this.templates[name] = this.templates[extend].cloneNode(true); + extend = name; + name = undefined; + } if (name) { this.templates[name] = node; } else if (extend) { From 2e760b3699e6befced31bd16f2672cb41c1644f6 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 9 May 2011 14:48:08 +0200 Subject: [PATCH 081/189] [IMP] Force vertical resize of textareas bzr revid: fme@openerp.com-20110509124808-7bujdh4xqtn43n17 --- addons/base/static/src/css/base.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 8c4df744219..61ad2bf8286 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -610,6 +610,9 @@ body.openerp { min-width: 90px; color: #1f1f1f; } +.openerp textarea { + resize:vertical; +} .openerp input[type="text"], .openerp input[type="password"], .openerp select, .openerp .button { height: 22px; } From 93d7852342e9bba2f714160fd6ac5d7833c46f3b Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 9 May 2011 16:10:01 +0200 Subject: [PATCH 082/189] [ADD] Added percentage in progressbar (can't center it for the moment) bzr revid: fme@openerp.com-20110509141001-33vihmt5edam0ydq --- addons/base/static/src/css/base.css | 6 ++++++ addons/base/static/src/js/form.js | 8 ++++++++ addons/base/static/src/xml/base.xml | 4 +++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 61ad2bf8286..6656dd42849 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -648,6 +648,12 @@ body.openerp { background-color: #F66; border: 1px solid #D00; } +.openerp div.oe-progressbar span { + position: absolute; + margin-left: 10px; + margin-top: 5px; + font-weight: bold; +} /* jQuery UI override */ .openerp .ui-widget { diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 3a6ef174c8d..27beadbdecf 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -773,6 +773,14 @@ openerp.base.form.FieldProgressBar = openerp.base.form.Field.extend({ value: this.value, disabled: this.readonly }); + }, + set_value: function(value) { + this._super.apply(this, arguments); + var show_value = Number(value); + if (show_value === NaN) { + show_value = 0; + } + this.$element.find('div').progressbar('option', 'value', show_value).find('span').html(show_value + '%'); } }); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index aae0d445a03..8675e59818d 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -365,7 +365,9 @@ t-att-class="'field_' + widget.type"/> -
    +
    + +
    - [[ formatLang(line.discount, digits=get_digits(dp='Sale Price')) ]] + [[ formatLang(line.discount) ]] [[ formatLang(line.price_subtotal, digits=get_digits(dp='Sale Price')) ]] [[ o.pricelist_id.currency_id.symbol ]] diff --git a/addons/sale_layout/report/report_sale_layout.rml b/addons/sale_layout/report/report_sale_layout.rml index fd9cbe90bf8..941df09aeb5 100644 --- a/addons/sale_layout/report/report_sale_layout.rml +++ b/addons/sale_layout/report/report_sale_layout.rml @@ -292,7 +292,7 @@ [[ a['layout_type']=='subtotal' and ( setTag('para','para',{'fontName':'Helvetica-Bold'})) or removeParentNode('font') ]] [[ formatLang(a['price_unit'], digits=get_digits(dp='Sale Price')) ]] - [[ a['layout_type']=='subtotal' and ( setTag('para','para',{'fontName':'Helvetica-Bold'})) or removeParentNode('font') ]] [[ formatLang(a['discount'], digits=get_digits(dp='Sale Price')) ]] + [[ a['layout_type']=='subtotal' and ( setTag('para','para',{'fontName':'Helvetica-Bold'})) or removeParentNode('font') ]] [[ formatLang(a['discount']) ]] [[ a['layout_type']=='break' and removeParentNode('blockTable')]][[ a['layout_type']=='subtotal' and ( setTag('para','para',{'fontName':'Helvetica-Bold'})) or removeParentNode('font') ]] [[ formatLang(a['price_subtotal'], digits=get_digits(dp='Sale Price')) ]] [[ o.pricelist_id.currency_id.symbol ]] From 0dcd78a54e59f89567cc079bd3399bbf73b5ea16 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 10 May 2011 10:34:20 +0200 Subject: [PATCH 086/189] [ADD] DataGroup API bzr revid: xmo@openerp.com-20110510083420-18zr6j8ab5d9c023 --- addons/base/controllers/main.py | 7 +++ addons/base/static/src/js/data.js | 79 +++++++++++++++++++++++++++++-- addons/base/static/src/js/list.js | 12 +++++ 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 085e48d89e0..e21f4fb853f 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -425,6 +425,13 @@ class DataSet(openerpweb.Controller): r = m.default_get(fields, context) return {'result': r} +class DataGroup(openerpweb.Controller): + _cp_path = "/base/group" + @openerpweb.jsonrequest + def read(self, request, model, group_by_fields, domain=None, context=None): + Model = request.session.model(model) + return Model.read_group(domain or False, False, group_by_fields, 0, False, context or False) + class View(openerpweb.Controller): def fields_view_get(self, request, model, view_id, view_type, transform=True, toolbar=False, submenu=False): diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index da0f18001a8..bb190e068c6 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -3,15 +3,88 @@ openerp.base.data = function(openerp) { openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.base.DataGroup# */{ /** - * Management interface between views and the collection of selected OpenERP - * records (represents the view's state?) + * Management interface between views and grouped collections of OpenERP + * records * * @constructs * @extends openerp.base.Controller + * + * @param {Array} group_by sequence of fields by which to group * @param {openerp.base.Session} session Current OpenERP session + * @param {openerp.base.DataSet} dataset root dataset, holder of base view state */ - init: function(session) { + init: function(session, group_by, dataset) { this._super(session, null); + this.model = dataset.model; + this.context = dataset.context; + this.domain = dataset.domain; + + this.group_by = group_by; + + this.groups = null; + }, + fetch: function () { + var d = new $.Deferred(); + var self = this; + + if (this.groups) { + d.resolveWith(this, [this.groups]); + } else { + this.rpc('/base/group/read', { + model: this.model, + context: this.context, + domain: this.domain, + group_by_fields: this.group_by + }, function () { }).then(function (response) { + self.groups = response.result; + d.resolveWith(self, [response.result]); + }, function () { + d.rejectWith.apply(d, self, [arguments]); + }); + } + return d.promise(); + }, + /** + * Retrieves the content of the nth-level item in the DataGroup, which + * results in either a DataSet or a DataGroup instance. + * + * Calling :js:func:`~openerp.base.DataGroup.get` without having called + * :js:func:`~openerp.base.DataGroup.list` beforehand will likely result + * in an error. + * + * @param {Number} index the index of the group to open in the datagroup's collection + * @param {Function} ifDataSet executed if the item results in a DataSet, provided with the dataset as parameter and as context + * @param {Function} ifDataGroup executed if the item results in a DataSet, provided with the datagroup as parameter and as context + */ + get: function (index, ifDataSet, ifDataGroup) { + var group = this.groups[index]; + if (!group) { + throw new Error("No group at index " + index); + } + + var child_context = _.extend({}, this.context, group.__context); + if (group.__context.group_by.length) { + var datagroup = new openerp.base.DataGroup( + this.session, group.__context.group_by, { + model: this.model, + context: child_context, + domain: group.__domain + }); + ifDataGroup.call(datagroup, datagroup); + } else { + var dataset = new openerp.base.DataSetSearch(this.session, this.model); + dataset.domain = group.__domain; + dataset.context = child_context; + ifDataSet.call(dataset, dataset); + } + }, + /** + * Provides a list of all top-level items of the data group. + * + * @returns {$.Deferred} + */ + list: function () { + return this.fetch(); } }); diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 62d29da0cba..f4a2e481418 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -290,6 +290,18 @@ openerp.base.ListView = openerp.base.Controller.extend( // TODO: handle non-empty results.group_by with read_group self.dataset.context = results.context; self.dataset.domain = results.domain; + if (results.group_by.length) { + var group = new openerp.base.DataGroup( + self.session, results.group_by, self.dataset); + group.list().then(function (lst) { + console.log(this, lst); + this.get(0, function () { + console.log('set', this); + }, function () { + console.log('group', this); + }); + }); + } return self.do_reload(); }); }, From 9dcb8cfe246fb67eab8ec4db5604befc5261c5be Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 10 May 2011 12:30:46 +0200 Subject: [PATCH 088/189] [IMP] Added new object to m2m popup. bzr revid: nicolas.vanhoren@openerp.com-20110510103046-6hctgajnom4y3x91 --- addons/base/static/src/js/form.js | 43 ++++++++++++++++++++++++++++- addons/base/static/src/xml/base.xml | 11 +++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 37a5683360a..934d8fabe10 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1025,9 +1025,50 @@ openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({ self.view_list.do_search.call( self, domains, contexts, groupbys); }); - return this.searchview.start(); + this.searchview.on_loaded.add_last(function () { + var $buttons = self.searchview.$element.find(".oe_search-view-buttons"); + $buttons.append(QWeb.render("Many2XSelectPopup.search.buttons")); + var $nbutton = $buttons.find(".oe_many2xselectpopup-search-new"); + $nbutton.click(function() { + self.new_object(); + }); + var $cbutton = $buttons.find(".oe_many2xselectpopup-search-close"); + $cbutton.click(function() { + self.stop(); + }); + }); + this.searchview.start(); + }, on_select_element: function(element_id) { + }, + new_object: function() { + var self = this; + this.searchview.hide(); + this.view_list.$element.hide(); + this.dataset.index = null; + this.view_form = new openerp.base.FormView({}, this.session, + this.element_id + "_view_form", this.dataset, false); + this.view_form.start(); + this.view_form.on_loaded.add_last(function() { + var $buttons = self.view_form.$element.find(".oe_form_buttons"); + $buttons.html(QWeb.render("Many2XSelectPopup.form.buttons")); + var $nbutton = $buttons.find(".oe_many2xselectpopup-form-save"); + $nbutton.click(function() { + self.view_form.do_save(); + }); + var $cbutton = $buttons.find(".oe_many2xselectpopup-form-close"); + $cbutton.click(function() { + self.stop(); + }); + }); + this.view_form.on_created.add_last(function(r, success) { + if (r.result) { + var id = arguments[0].result; + self.on_select_element(id); + } + }); + this.view_form.do_show(); } }); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index d6c4d3edbb1..9e1646ace08 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -383,7 +383,7 @@

    -
    +
    @@ -576,6 +576,15 @@
    +
    + + + + + + + + From 45f47ae65c0e22e7a780806f69eedcaa57c37259 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 10 May 2011 13:07:23 +0200 Subject: [PATCH 089/189] [ADD] display groups in a most dreadful manner, need to cleanup the generation function and to handle displaying it in the correct table bzr revid: xmo@openerp.com-20110510110723-ic13ty3rs92zg9z9 --- addons/base/static/src/js/data.js | 23 +++++++++-- addons/base/static/src/js/list.js | 68 ++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/addons/base/static/src/js/data.js b/addons/base/static/src/js/data.js index bb190e068c6..c3683ed592e 100644 --- a/addons/base/static/src/js/data.js +++ b/addons/base/static/src/js/data.js @@ -37,7 +37,19 @@ openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.bas group_by_fields: this.group_by }, function () { }).then(function (response) { self.groups = response.result; - d.resolveWith(self, [response.result]); + // read_group results are annoying: they use the name of the + // field grouped on to hold the value and the count, so no + // generic access to those values is possible. + // Alias them to `value` and `length`. + d.resolveWith(self, [_(response.result).map(function (group) { + var field_name = self.group_by[0]; + return _.extend({}, group, { + // provide field used for grouping + grouped_on: field_name, + length: group[field_name + '_count'], + value: group[field_name] + }); + })]); }, function () { d.rejectWith.apply(d, self, [arguments]); }); @@ -52,9 +64,14 @@ openerp.base.DataGroup = openerp.base.Controller.extend( /** @lends openerp.bas * :js:func:`~openerp.base.DataGroup.list` beforehand will likely result * in an error. * + * The resulting :js:class:`~openerp.base.DataGroup` or + * :js:class:`~openerp.base.DataSet` will be provided through the relevant + * callback function. In both functions, the current DataGroup will be + * provided as context (``this``) + * * @param {Number} index the index of the group to open in the datagroup's collection - * @param {Function} ifDataSet executed if the item results in a DataSet, provided with the dataset as parameter and as context - * @param {Function} ifDataGroup executed if the item results in a DataSet, provided with the datagroup as parameter and as context + * @param {Function} ifDataSet executed if the item results in a DataSet, provided with the new dataset as parameter + * @param {Function} ifDataGroup executed if the item results in a DataSet, provided with the new datagroup as parameter */ get: function (index, ifDataSet, ifDataGroup) { var group = this.groups[index]; diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index f4a2e481418..87a59f0a469 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -61,7 +61,11 @@ openerp.base.ListView = openerp.base.Controller.extend( columns: this.columns, rows: this.rows }); - $(this.list).bind({ + this.groups = new openerp.base.ListView.Groups({ + options: this.options, + columns: this.columns + }); + $([this.list, this.groups]).bind({ 'selected': function (e, selection) { self.$element.find('#oe-list-delete') .toggle(!!selection.length); @@ -291,16 +295,10 @@ openerp.base.ListView = openerp.base.Controller.extend( self.dataset.context = results.context; self.dataset.domain = results.domain; if (results.group_by.length) { - var group = new openerp.base.DataGroup( + self.groups.datagroup = new openerp.base.DataGroup( self.session, results.group_by, self.dataset); - group.list().then(function (lst) { - console.log(this, lst); - this.get(0, function () { - console.log('set', this); - }, function () { - console.log('group', this); - }); - }); + self.$element.html(self.groups.render()); + return; } return self.do_reload(); }); @@ -476,7 +474,55 @@ openerp.base.ListView.List = Class.extend( // drag and drop // editable? }); - +openerp.base.ListView.Groups = Class.extend( + /** @lends openerp.base.ListView.Groups# */{ + /** + * Grouped display for the ListView. Handles basic DOM events and interacts + * with the :js:class:`~openerp.base.DataGroup` bound to it. + * + * Provides events similar to those of + * :js:class:`~openerp.base.ListView.List` + */ + init: function (opts) { + this.options = opts.options; + this.columns = opts.columns; + this.datagroup = {}; + }, + make_level: function (datagroup) { + var self = this, $root = $('
    '); + datagroup.list().then(function (list) { + _(list).each(function (group, index) { + var $title = $('
    ') + .text(group.grouped_on + ': ' + group.value + ' (' + group.length + ')') + .appendTo($root); + $title.click(function () { + datagroup.get(index, function (new_dataset) { + var $content = $('