diff options
| author | Denis Ledoux <dle@openerp.com> | 2013-09-23 19:13:10 +0200 |
|---|---|---|
| committer | Denis Ledoux <dle@openerp.com> | 2013-09-23 19:13:10 +0200 |
| commit | db84e912bd58ff3e0c111d3032c2d0aedca4882c (patch) | |
| tree | e659fc7dbcc0957b39d72440e6bd891474a627d1 | |
| parent | 64e0e77605bf248f98a995bbe180ee092b590793 (diff) | |
| parent | 274cf1e293e95677cb4a6a0e92a440434427fd38 (diff) | |
[MERGE] Forward-port of latest saas-1 bugfixes, up to rev. 8781 rev-id: dle@openerp.com-20130923165651-0jt823r5wy37enw6
bzr revid: dle@openerp.com-20130923171310-mav1riq3d2rebmv2
29 files changed, 368 insertions, 105 deletions
diff --git a/addons/account/account.py b/addons/account/account.py index df623f32174..21a5ce992d7 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1416,14 +1416,17 @@ class account_move(osv.osv): l[2]['period_id'] = default_period context['period_id'] = default_period - if 'line_id' in vals: + if vals.get('line_id', False): c = context.copy() c['novalidate'] = True c['period_id'] = vals['period_id'] if 'period_id' in vals else self._get_period(cr, uid, context) c['journal_id'] = vals['journal_id'] if 'date' in vals: c['date'] = vals['date'] result = super(account_move, self).create(cr, uid, vals, c) - self.validate(cr, uid, [result], context) + tmp = self.validate(cr, uid, [result], context) + journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context) + if journal.entry_posted and tmp: + self.button_validate(cr,uid, [result], context) else: result = super(account_move, self).create(cr, uid, vals, context) return result diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index d56fe27759c..1b7bd658faf 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -349,6 +349,7 @@ <page string="Invoice Lines"> <field name="invoice_line" nolabel="1" widget="one2many_list" context="{'type': type}"> <tree string="Invoice Lines" editable="bottom"> + <field name="sequence" widget="handle"/> <field name="product_id" on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.currency_id, context, parent.company_id)"/> <field name="name"/> diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 7f5fa9707c1..0fc9d9e2227 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -1283,7 +1283,7 @@ class account_move_line(osv.osv): self.create(cr, uid, data, context) del vals['account_tax_id'] - if check and ((not context.get('no_store_function')) or journal.entry_posted): + if check and not context.get('novalidate') and ((not context.get('no_store_function')) or journal.entry_posted): tmp = move_obj.validate(cr, uid, [vals['move_id']], context) if journal.entry_posted and tmp: move_obj.button_validate(cr,uid, [vals['move_id']], context) diff --git a/addons/account/wizard/account_report_partner_ledger_view.xml b/addons/account/wizard/account_report_partner_ledger_view.xml index 34c5d55e4c1..61b57f87d7e 100644 --- a/addons/account/wizard/account_report_partner_ledger_view.xml +++ b/addons/account/wizard/account_report_partner_ledger_view.xml @@ -15,7 +15,7 @@ <newline/> </xpath> <xpath expr="//field[@name='filter']" position="replace"> - <field name="filter" on_change="onchange_filter(filter, fiscalyear_id)" colspan="4"/> + <field name="filter" on_change="onchange_filter(filter, fiscalyear_id)"/> <field name="initial_balance" attrs="{'readonly':[('filter', 'in', ('filter_no', 'unreconciled'))]}" /> </xpath> </data> diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index d4cd1e083b4..6194324e183 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -1208,20 +1208,44 @@ rule or repeating pattern of time to exclude from the recurring rule."), new_rrule_str = ';'.join(new_rrule_str) rdates = get_recurrent_dates(str(new_rrule_str), exdate, event_date, data['exrule']) for r_date in rdates: - ok = True + # fix domain evaluation + # step 1: check date and replace expression by True or False, replace other expressions by True + # step 2: evaluation of & and | + # check if there are one False + pile = [] for arg in domain: - if arg[0] in ('date', 'date_deadline'): - if (arg[1]=='='): - ok = ok and r_date.strftime('%Y-%m-%d')==arg[2] - if (arg[1]=='>'): - ok = ok and r_date.strftime('%Y-%m-%d')>arg[2] - if (arg[1]=='<'): - ok = ok and r_date.strftime('%Y-%m-%d')<arg[2] - if (arg[1]=='>='): - ok = ok and r_date.strftime('%Y-%m-%d')>=arg[2] - if (arg[1]=='<='): - ok = ok and r_date.strftime('%Y-%m-%d')<=arg[2] - if not ok: + if str(arg[0]) in (str('date'), str('date_deadline')): + if (arg[1] == '='): + ok = r_date.strftime('%Y-%m-%d')==arg[2] + if (arg[1] == '>'): + ok = r_date.strftime('%Y-%m-%d')>arg[2] + if (arg[1] == '<'): + ok = r_date.strftime('%Y-%m-%d')<arg[2] + if (arg[1] == '>='): + ok = r_date.strftime('%Y-%m-%d')>=arg[2] + if (arg[1] == '<='): + ok = r_date.strftime('%Y-%m-%d')<=arg[2] + pile.append(ok) + elif str(arg) == str('&') or str(arg) == str('|'): + pile.append(arg) + else: + pile.append(True) + pile.reverse() + new_pile = [] + for item in pile: + if not isinstance(item, basestring): + res = item + elif str(item) == str('&'): + first = new_pile.pop() + second = new_pile.pop() + res = first and second + elif str(item) == str('|'): + first = new_pile.pop() + second = new_pile.pop() + res = first or second + new_pile.append(res) + + if [True for item in new_pile if not item]: continue idval = real_id2base_calendar_id(data['id'], r_date.strftime("%Y-%m-%d %H:%M:%S")) result.append(idval) @@ -1346,18 +1370,17 @@ rule or repeating pattern of time to exclude from the recurring rule."), for arg in args: new_arg = arg - if arg[0] in ('date', unicode('date'), 'date_deadline', unicode('date_deadline')): + if arg[0] in ('date_deadline', unicode('date_deadline')): if context.get('virtual_id', True): - new_args += ['|','&',('recurrency','=',1),('recurrent_id_date', arg[1], arg[2])] + new_args += ['|','&',('recurrency','=',1),('end_date', arg[1], arg[2])] elif arg[0] == "id": new_id = get_real_ids(arg[2]) new_arg = (arg[0], arg[1], new_id) new_args.append(new_arg) - #offset, limit and count must be treated separately as we may need to deal with virtual ids res = super(calendar_event, self).search(cr, uid, new_args, offset=0, limit=0, order=order, context=context, count=False) if context.get('virtual_id', True): - res = self.get_recurrent_ids(cr, uid, res, new_args, limit, context=context) + res = self.get_recurrent_ids(cr, uid, res, args, limit, context=context) if count: return len(res) elif limit: @@ -1436,6 +1459,14 @@ rule or repeating pattern of time to exclude from the recurring rule."), vals['vtimezone'] = vals['vtimezone'][40:] res = super(calendar_event, self).write(cr, uid, ids, vals, context=context) + + # set end_date for calendar searching + if vals.get('recurrency', True) and vals.get('end_type', 'count') in ('count', unicode('count')) and \ + (vals.get('rrule_type') or vals.get('count') or vals.get('date') or vals.get('date_deadline')): + for data in self.read(cr, uid, ids, ['date', 'date_deadline', 'recurrency', 'rrule_type', 'count', 'end_type'], context=context): + end_date = self._set_recurrency_end_date(data, context=context) + super(calendar_event, self).write(cr, uid, [data['id']], {'end_date': end_date}, context=context) + if vals.get('partner_ids', False): self.create_attendees(cr, uid, ids, context) @@ -1554,6 +1585,21 @@ rule or repeating pattern of time to exclude from the recurring rule."), self.unlink_events(cr, uid, ids, context=context) return res + def _set_recurrency_end_date(self, data, context=None): + end_date = data.get('end_date') + if data.get('recurrency') and data.get('end_type') in ('count', unicode('count')): + data_date_deadline = datetime.strptime(data.get('date_deadline'), '%Y-%m-%d %H:%M:%S') + if data.get('rrule_type') in ('daily', unicode('count')): + rel_date = relativedelta(days=data.get('count')+1) + elif data.get('rrule_type') in ('weekly', unicode('weekly')): + rel_date = relativedelta(days=(data.get('count')+1)*7) + elif data.get('rrule_type') in ('monthly', unicode('monthly')): + rel_date = relativedelta(months=data.get('count')+1) + elif data.get('rrule_type') in ('yearly', unicode('yearly')): + rel_date = relativedelta(years=data.get('count')+1) + end_date = data_date_deadline + rel_date + return end_date + def create(self, cr, uid, vals, context=None): if context is None: context = {} @@ -1561,7 +1607,9 @@ rule or repeating pattern of time to exclude from the recurring rule."), if vals.get('vtimezone', '') and vals.get('vtimezone', '').startswith('/freeassociation.sourceforge.net/tzfile/'): vals['vtimezone'] = vals['vtimezone'][40:] + vals['end_date'] = self._set_recurrency_end_date(vals, context=context) res = super(calendar_event, self).create(cr, uid, vals, context) + alarm_obj = self.pool.get('res.alarm') alarm_obj.do_alarm_create(cr, uid, [res], self._name, 'date', context=context) self.create_attendees(cr, uid, [res], context) diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py index 70f94a4f57e..9226787e908 100644 --- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py +++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py @@ -458,7 +458,7 @@ class hr_timesheet_sheet_sheet_day(osv.osv): THEN (SUM(total_attendance) + CASE WHEN current_date <> name THEN 1440 - ELSE (EXTRACT(hour FROM current_time) * 60) + EXTRACT(minute FROM current_time) + ELSE (EXTRACT(hour FROM current_time AT TIME ZONE 'UTC') * 60) + EXTRACT(minute FROM current_time AT TIME ZONE 'UTC') END ) ELSE SUM(total_attendance) diff --git a/addons/mrp/__openerp__.py b/addons/mrp/__openerp__.py index 5f5ded337a7..99afd01707a 100644 --- a/addons/mrp/__openerp__.py +++ b/addons/mrp/__openerp__.py @@ -77,6 +77,7 @@ Dashboard / Reports for MRP will include: #TODO: This yml tests are needed to be completely reviewed again because the product wood panel is removed in product demo as it does not suit for new demo context of computer and consultant company # so the ymls are too complex to change at this stage 'test': [ + 'test/bom_with_service_type_product.yml', 'test/mrp_users.yml', 'test/order_demo.yml', 'test/order_process.yml', diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index e4efc9a4779..475bb065c92 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -601,12 +601,12 @@ class mrp_production(osv.osv): """ self.write(cr, uid, ids, {'state': 'picking_except'}) return True - - def action_compute(self, cr, uid, ids, properties=None, context=None): - """ Computes bills of material of a product. - @param properties: List containing dictionaries of properties. - @return: No. of products. + + def _action_compute_lines(self, cr, uid, ids, properties=None, context=None): + """ Compute product_lines and workcenter_lines from BoM structure + @return: product_lines """ + if properties is None: properties = [] results = [] @@ -614,13 +614,15 @@ class mrp_production(osv.osv): uom_obj = self.pool.get('product.uom') prod_line_obj = self.pool.get('mrp.production.product.line') workcenter_line_obj = self.pool.get('mrp.production.workcenter.line') - for production in self.browse(cr, uid, ids): - - p_ids = prod_line_obj.search(cr, SUPERUSER_ID, [('production_id', '=', production.id)], context=context) - prod_line_obj.unlink(cr, SUPERUSER_ID, p_ids, context=context) - w_ids = workcenter_line_obj.search(cr, SUPERUSER_ID, [('production_id', '=', production.id)], context=context) - workcenter_line_obj.unlink(cr, SUPERUSER_ID, w_ids, context=context) + for production in self.browse(cr, uid, ids, context=context): + #unlink product_lines + prod_line_obj.unlink(cr, SUPERUSER_ID, [line.id for line in production.product_lines], context=context) + + #unlink workcenter_lines + workcenter_line_obj.unlink(cr, SUPERUSER_ID, [line.id for line in production.workcenter_lines], context=context) + + # search BoM structure and route bom_point = production.bom_id bom_id = production.bom_id.id if not bom_point: @@ -629,20 +631,33 @@ class mrp_production(osv.osv): bom_point = bom_obj.browse(cr, uid, bom_id) routing_id = bom_point.routing_id.id or False self.write(cr, uid, [production.id], {'bom_id': bom_id, 'routing_id': routing_id}) - + if not bom_id: raise osv.except_osv(_('Error!'), _("Cannot find a bill of material for this product.")) + + # get components and workcenter_lines from BoM structure factor = uom_obj._compute_qty(cr, uid, production.product_uom.id, production.product_qty, bom_point.product_uom.id) res = bom_obj._bom_explode(cr, uid, bom_point, factor / bom_point.product_qty, properties, routing_id=production.routing_id.id) - results = res[0] - results2 = res[1] + results = res[0] # product_lines + results2 = res[1] # workcenter_lines + + # reset product_lines in production order for line in results: line['production_id'] = production.id prod_line_obj.create(cr, uid, line) + + #reset workcenter_lines in production order for line in results2: line['production_id'] = production.id workcenter_line_obj.create(cr, uid, line) - return len(results) + return results + + def action_compute(self, cr, uid, ids, properties=None, context=None): + """ Computes bills of material of a product. + @param properties: List containing dictionaries of properties. + @return: No. of products. + """ + return len(self._action_compute_lines(cr, uid, ids, properties=properties, context=context)) def action_cancel(self, cr, uid, ids, context=None): """ Cancels the production order and related stock moves. @@ -669,8 +684,12 @@ class mrp_production(osv.osv): move_obj = self.pool.get('stock.move') self.write(cr, uid, ids, {'state': 'ready'}) - for (production_id,name) in self.name_get(cr, uid, ids): - production = self.browse(cr, uid, production_id) + for production in self.browse(cr, uid, ids, context=context): + if not production.move_created_ids: + produce_move_id = self._make_production_produce_line(cr, uid, production, context=context) + for scheduled in production.product_lines: + self._make_production_line_procurement(cr, uid, scheduled, False, context=context) + if production.move_prod_id and production.move_prod_id.location_id.id != production.location_dest_id.id: move_obj.write(cr, uid, [production.move_prod_id.id], {'location_id': production.location_dest_id.id}) @@ -722,6 +741,10 @@ class mrp_production(osv.osv): stock_mov_obj = self.pool.get('stock.move') production = self.browse(cr, uid, production_id, context=context) + if not production.move_lines and production.state == 'ready': + # trigger workflow if not products to consume (eg: services) + self.signal_button_produce(cr, uid, [production_id]) + produced_qty = 0 for produced_product in production.move_created_ids2: if (produced_product.scrapped) or (produced_product.product_id.id != production.product_id.id): @@ -784,9 +807,9 @@ class mrp_production(osv.osv): subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context) rest_qty = (subproduct_factor * production.product_qty) - produced_qty - if rest_qty < production_qty: + if rest_qty < (subproduct_factor * production_qty): prod_name = produce_product.product_id.name_get()[0][1] - raise osv.except_osv(_('Warning!'), _('You are going to produce total %s quantities of "%s".\nBut you can only produce up to total %s quantities.') % (production_qty, prod_name, rest_qty)) + raise osv.except_osv(_('Warning!'), _('You are going to produce total %s quantities of "%s".\nBut you can only produce up to total %s quantities.') % ((subproduct_factor * production_qty), prod_name, rest_qty)) if rest_qty > 0 : stock_mov_obj.action_consume(cr, uid, [produce_product.id], (subproduct_factor * production_qty), context=context) @@ -861,13 +884,19 @@ class mrp_production(osv.osv): """ res = True for production in self.browse(cr, uid, ids): - if not production.product_lines: - if not self.action_compute(cr, uid, [production.id]): - res = False + boms = self._action_compute_lines(cr, uid, [production.id]) + res = False + for bom in boms: + product = self.pool.get('product.product').browse(cr, uid, bom['product_id']) + if product.type in ('product', 'consu'): + res = True return res def _get_auto_picking(self, cr, uid, production): return True + + def _hook_create_post_procurement(self, cr, uid, production, procurement_id, context=None): + return True def _make_production_line_procurement(self, cr, uid, production_line, shipment_move_id, context=None): procurement_order = self.pool.get('procurement.order') @@ -1015,11 +1044,13 @@ class mrp_production(osv.osv): for line in production.product_lines: consume_move_id = self._make_production_consume_line(cr, uid, line, produce_move_id, source_location_id=source_location_id, context=context) - shipment_move_id = self._make_production_internal_shipment_line(cr, uid, line, shipment_id, consume_move_id,\ + if shipment_id: + shipment_move_id = self._make_production_internal_shipment_line(cr, uid, line, shipment_id, consume_move_id,\ destination_location_id=source_location_id, context=context) - self._make_production_line_procurement(cr, uid, line, shipment_move_id, context=context) + self._make_production_line_procurement(cr, uid, line, shipment_move_id, context=context) - self.pool.get('stock.picking').signal_button_confirm(cr, uid, [shipment_id]) + if shipment_id: + self.pool.get('stock.picking').signal_button_confirm(cr, uid, [shipment_id]) production.write({'state':'confirmed'}, context=context) return shipment_id diff --git a/addons/mrp/test/bom_with_service_type_product.yml b/addons/mrp/test/bom_with_service_type_product.yml new file mode 100644 index 00000000000..dc434cabf73 --- /dev/null +++ b/addons/mrp/test/bom_with_service_type_product.yml @@ -0,0 +1,134 @@ +- + I create Bill of Materials with one service type product and one consumable product. +- + !record {model: mrp.bom, id: mrp_bom_test1}: + company_id: base.main_company + name: PC Assemble SC234 + product_id: product.product_product_3 + product_qty: 1.0 + type: normal + bom_lines: + - company_id: base.main_company + name: On Site Assistance + product_id: product.product_product_2 + product_qty: 1.0 + - company_id: base.main_company + name: GrapWorks Software + product_id: product.product_product_44 + product_qty: 1.0 +- + I make the production order using BoM having one service type product and one consumable product. +- + !record {model: mrp.production, id: mrp_production_servicetype_mo1}: + product_id: product.product_product_5 + product_qty: 1.0 + bom_id: mrp_bom_test1 + date_planned: !eval time.strftime('%Y-%m-%d %H:%M:%S') +- + I compute the data of production order. +- + !python {model: mrp.production}: | + self.action_compute(cr, uid, [ref("mrp_production_servicetype_mo1")], {"lang": "en_US", "tz": False, "search_default_Current": 1, + "active_model": "ir.ui.menu", "active_ids": [ref("mrp.menu_mrp_production_action")], + "active_id": ref("mrp.menu_mrp_production_action"), }) +- + I confirm the production order. +- + !workflow {model: mrp.production, action: button_confirm, ref: mrp_production_servicetype_mo1} +- + I confirm the Consume Products. +- + !python {model: mrp.production}: | + order = self.browse(cr, uid, ref("mrp_production_servicetype_mo1")) + assert order.state == 'confirmed', "Production order should be confirmed." + for move_line in order.move_lines: + move_line.action_consume(move_line.product_qty) +- + I processed the Product Entirely. +- + !python {model: mrp.production}: | + order = self.browse(cr, uid, ref("mrp_production_servicetype_mo1")) + assert order.state == 'in_production', 'Production order should be in production State.' + for move_created in order.move_created_ids: + move_created.action_done() +- + I produce product. +- + !python {model: mrp.product.produce}: | + context.update({'active_id': ref('mrp_production_servicetype_mo1')}) +- + !record {model: mrp.product.produce, id: mrp_product_produce_1}: + mode: 'consume_produce' +- + !python {model: mrp.product.produce}: | + self.do_produce(cr, uid, [ref('mrp_product_produce_1')], context=context) +- + I check production order after produced. +- + !python {model: mrp.production}: | + order = self.browse(cr, uid, ref("mrp_production_servicetype_mo1")) + assert order.state == 'done', "Production order should be closed." +- + I create Bill of Materials with two service type products. +- + !record {model: mrp.bom, id: mrp_bom_test_2}: + company_id: base.main_company + name: PC Assemble SC234 + product_id: product.product_product_3 + product_qty: 1.0 + type: normal + bom_lines: + - company_id: base.main_company + name: On Site Monitoring + product_id: product.product_product_1 + product_qty: 1.0 + - company_id: base.main_company + name: On Site Assistance + product_id: product.product_product_2 + product_qty: 1.0 +- + I make the production order using BoM having two service type products. +- + !record {model: mrp.production, id: mrp_production_servicetype_2}: + product_id: product.product_product_5 + product_qty: 1.0 + bom_id: mrp_bom_test_2 + date_planned: !eval time.strftime('%Y-%m-%d %H:%M:%S') +- + I compute the data of production order. +- + !python {model: mrp.production}: | + self.action_compute(cr, uid, [ref("mrp_production_servicetype_2")], {"lang": "en_US", "tz": False, "search_default_Current": 1, + "active_model": "ir.ui.menu", "active_ids": [ref("mrp.menu_mrp_production_action")], + "active_id": ref("mrp.menu_mrp_production_action"), }) +- + I confirm the production order. +- + !workflow {model: mrp.production, action: button_confirm, ref: mrp_production_servicetype_2} +- + Now I start production. +- + !workflow {model: mrp.production, action: button_produce, ref: mrp_production_servicetype_2} +- + I check that production order in production state after start production. +- + !python {model: mrp.production}: | + order = self.browse(cr, uid, ref("mrp_production_servicetype_2")) + assert order.state == 'in_production', 'Production order should be in production State.' +- + I produce product. +- + !python {model: mrp.product.produce}: | + context.update({'active_id': ref('mrp_production_servicetype_2')}) +- + !record {model: mrp.product.produce, id: mrp_product_produce_2}: + mode: 'consume_produce' +- + !python {model: mrp.product.produce}: | + self.do_produce(cr, uid, [ref('mrp_product_produce_2')], context=context) +- + I check production order after produced. +- + !python {model: mrp.production}: | + order = self.browse(cr, uid, ref("mrp_production_servicetype_2")) + assert order.state == 'done', "Production order should be closed." diff --git a/addons/mrp_operations/mrp_operations_view.xml b/addons/mrp_operations/mrp_operations_view.xml index f2d1a84b40a..9b8587349bc 100644 --- a/addons/mrp_operations/mrp_operations_view.xml +++ b/addons/mrp_operations/mrp_operations_view.xml @@ -9,7 +9,7 @@ <field name="arch" type="xml"> <xpath expr="//field[@name='workcenter_lines']/form//field[@name='name']" position="before"> <header colspan="8"> - <button name="button_start_working" string="Start" states="draft" icon="terp-gtk-jump-to-ltr" help="Start Working"/> + <button name="button_start_working" string="Start" states="draft" icon="gtk-media-play" help="Start Working"/> <button name="button_cancel" string="Cancel Order" states="draft,startworking" icon="gtk-stop" help="Cancel Order"/> <button name="button_draft" string="Set Draft" states="cancel" icon="gtk-convert" help="Set to Draft"/> <button name="button_resume" string="Resume" states="pause" icon="gtk-media-pause" help="Resume Work Order"/> @@ -29,7 +29,7 @@ <xpath expr="//field[@name='workcenter_lines']/tree/field[@name='hour']" position="after"> <field name="state"/> <button name="button_draft" string="Set Draft" states="cancel" icon="gtk-convert"/> - <button name="button_start_working" string="Start" states="draft" icon="terp-gtk-jump-to-ltr"/> + <button name="button_start_working" string="Start" states="draft" icon="gtk-media-play"/> <button name="button_resume" string="Resume" states="pause" icon="gtk-media-pause"/> <button name="button_pause" string="Pending" states="startworking" icon="gtk-media-pause"/> <button name="button_done" string="Finished" states="startworking" icon="terp-check"/> diff --git a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPClient/OpenERPConnect.cs b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPClient/OpenERPConnect.cs index d6672828ed0..f9314adc417 100644 --- a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPClient/OpenERPConnect.cs +++ b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPClient/OpenERPConnect.cs @@ -377,20 +377,6 @@ namespace OpenERPClient return version;
}
- public bool check_connectivity()
- {
- /*
- It will check connection on given server url.
-
- :return : True or False.
- */
-
- this.Open(OpenERPClient.OpenERPService.Common);
- bool flag = this.rpcclient.check_connectivity();
- this.Close();
- return flag;
- }
-
}
diff --git a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPClient/XMLRPCClient.cs b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPClient/XMLRPCClient.cs index ebe9ec142e2..23768b02b4f 100644 --- a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPClient/XMLRPCClient.cs +++ b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPClient/XMLRPCClient.cs @@ -47,10 +47,6 @@ namespace OpenERPClient [XmlRpcMethod("server_version")]
string ServerVersion();
- [XmlRpcMethod("check_connectivity")]
- bool check_connectivity();
-
-
}
public interface Ixmlrpcconnect : IOpenERPCommon, IOpenERPDB, IOpenERPObject
{
@@ -84,11 +80,6 @@ namespace OpenERPClient {
return rpcclient.ServerVersion();
}
-
- public bool check_connectivity()
- {
- return rpcclient.check_connectivity();
- }
#endregion
diff --git a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPlugin/frm_openerp_connection.Designer.cs b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPlugin/frm_openerp_connection.Designer.cs index aeca33da72f..ce88d2e713d 100644 --- a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPlugin/frm_openerp_connection.Designer.cs +++ b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPlugin/frm_openerp_connection.Designer.cs @@ -64,6 +64,7 @@ this.chkSSL.TabIndex = 19;
this.chkSSL.Text = "SSL (https)";
this.chkSSL.UseVisualStyleBackColor = true;
+ this.chkSSL.CheckedChanged += new System.EventHandler(this.chkSSL_CheckedChanged);
//
// txt_server_port
//
diff --git a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPlugin/frm_openerp_connection.cs b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPlugin/frm_openerp_connection.cs index 1c663f58fe2..5e09fc153a2 100644 --- a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPlugin/frm_openerp_connection.cs +++ b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPlugin/frm_openerp_connection.cs @@ -20,6 +20,13 @@ using System;
using System.Windows.Forms;
using OpenERPClient;
+using System.Net;
+using System.IO;
+using System.Text;
+using System.Security;
+using System.Net;
+using System.Security.Cryptography.X509Certificates;
+using System.Net.Security;
namespace OpenERPOutlookPlugin
{
@@ -50,6 +57,15 @@ namespace OpenERPOutlookPlugin }
}
+ public static bool ValidateServerCertificate(
+ object sender,
+ X509Certificate certificate,
+ X509Chain chain,
+ SslPolicyErrors sslPolicyErrors)
+ {
+ // Somehow the cert always has PolicyErrors so I am returning true regardless.
+ return true;
+ }
private void btn_server_ok_Click(object sender, EventArgs e)
{
@@ -59,7 +75,10 @@ namespace OpenERPOutlookPlugin OpenERPConnect openerp_connect = openerp_outlook.Connection;
string url = Tools.JoinURL(this.txt_server_host.Text, this.txt_server_port.Text, this.chkSSL.Checked);
this.txtServerURL.Text = url;
- openerp_connect.check_connectivity();
+ if (this.chkSSL.Checked)
+ {
+ ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
+ }
this.Close();
}
catch (Exception ex)
@@ -74,6 +93,16 @@ namespace OpenERPOutlookPlugin this.Close();
}
-
+ private void chkSSL_CheckedChanged(object sender, EventArgs e)
+ {
+ if (this.chkSSL.Checked)
+ {
+ txt_server_port.Text = "443";
+ }
+ else
+ {
+ txt_server_port.Text = "8069";
+ }
+ }
}
}
diff --git a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPluginSetup32.msi b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPluginSetup32.msi Binary files differindex 9d9dd5d3ad3..64f54f22a65 100644 --- a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPluginSetup32.msi +++ b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPluginSetup32.msi diff --git a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPluginSetup64.msi b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPluginSetup64.msi Binary files differindex 0c2fa88bb24..3b91dafed55 100644 --- a/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPluginSetup64.msi +++ b/addons/plugin_outlook/static/openerp-outlook-plugin/OpenERPOutlookPluginSetup64.msi diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py index 63fc84c2ccf..07bc38339bd 100644 --- a/addons/product/pricelist.py +++ b/addons/product/pricelist.py @@ -171,9 +171,7 @@ class product_pricelist(osv.osv): if context is None: context = {} - date = time.strftime('%Y-%m-%d') - if 'date' in context: - date = context['date'] + date = context.get('date') or time.strftime('%Y-%m-%d') currency_obj = self.pool.get('res.currency') product_obj = self.pool.get('product.product') diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 6c00902a7c0..4d025d15cb4 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -128,7 +128,7 @@ <notebook> <page string="Team" name="team"> <field colspan="4" name="members" widget="many2many_kanban" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'group_project_user']}"> - <kanban quick_create="false" create="true"> + <kanban quick_create="false" create="true" delete="true"> <field name="name"/> <templates> <t t-name="kanban-box"> diff --git a/addons/project_mrp/process/project_mrp_process.xml b/addons/project_mrp/process/project_mrp_process.xml index db733d26d15..b147740758a 100644 --- a/addons/project_mrp/process/project_mrp_process.xml +++ b/addons/project_mrp/process/project_mrp_process.xml @@ -46,12 +46,29 @@ Process Transition --> + <!-- This "foreign" process node is duplicated here from the corresponding sale_stock node because + `project_mrp` implements a basic procurement system for services without actually using the + full-fledged procurement process from sale_stock, and without the dependency. So it stil + represents a "procurement system". + TODO: To cleanup this invalid foreign external ID, the node should probably be moved to the + `sale` module directly, and removed from both `sale_stock` and `project_mrp`. + --> + <record id="sale_stock.process_node_saleprocurement0" model="process.node"> + <field name="menu_id" ref="procurement.menu_stock_procurement_action"/> + <field name="model_id" ref="procurement.model_procurement_order"/> + <field name="kind">subflow</field> + <field name="name">Procurement</field> + <field name="subflow_id" ref="procurement.process_process_procurementprocess0"/> + <field name="process_id" ref="sale.process_process_salesprocess0"/> + <field name="model_states">object.state=='confirmed'</field> + <field name="flow_start" eval="1"/> + </record> <record id="process_transition_procuretask0" model="process.transition"> <field eval="[(6,0,[])]" name="transition_ids"/> <field eval=""""Procurement Task"""" name="name"/> <field eval=""""if product type is 'service' then it creates the task."""" name="note"/> <field name="target_node_id" ref="process_node_procuretasktask0"/> - <field name="source_node_id" ref="mrp.process_node_productionorder0"/> + <field name="source_node_id" ref="sale_stock.process_node_saleprocurement0"/> </record> <record id="process_transition_createtask0" model="process.transition"> diff --git a/addons/project_mrp/project_mrp.py b/addons/project_mrp/project_mrp.py index d5ed55a8d31..d7880ba90cd 100644 --- a/addons/project_mrp/project_mrp.py +++ b/addons/project_mrp/project_mrp.py @@ -125,4 +125,3 @@ class sale_order(osv.osv): 'picked_rate': fields.function(_picked_rate, method=True, string='Picked', type='float'), } -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 94a6f9fe7ab..a45afd1c5bc 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -1238,8 +1238,8 @@ class account_invoice(osv.Model): res = super(account_invoice, self).invoice_validate(cr, uid, ids, context=context) purchase_order_obj = self.pool.get('purchase.order') po_ids = purchase_order_obj.search(cr, uid, [('invoice_ids', 'in', ids)], context=context) - if po_ids: - purchase_order_obj.message_post(cr, uid, po_ids, body=_("Invoice received"), context=context) + for po_id in po_ids: + purchase_order_obj.message_post(cr, uid, po_id, body=_("Invoice received"), context=context) return res def confirm_paid(self, cr, uid, ids, context=None): diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 55bd34009bf..ad048e505e5 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -43,6 +43,7 @@ class sale_order(osv.osv): if not default: default = {} default.update({ + 'date_order': fields.date.context_today(self, cr, uid, context=context), 'state': 'draft', 'invoice_ids': [], 'date_confirm': False, diff --git a/addons/sale_crm/sale_crm.py b/addons/sale_crm/sale_crm.py index 109f1061ed0..d6413c994e7 100644 --- a/addons/sale_crm/sale_crm.py +++ b/addons/sale_crm/sale_crm.py @@ -31,7 +31,7 @@ class sale_order(osv.osv): _columns = { 'section_id': fields.many2one('crm.case.section', 'Sales Team'), 'categ_ids': fields.many2many('crm.case.categ', 'sale_order_category_rel', 'order_id', 'category_id', 'Categories', \ - domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]") + domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]", context="{'object_name': 'crm.lead'}") } def _prepare_invoice(self, cr, uid, order, lines, context=None): diff --git a/addons/sale_mrp/sale_mrp.py b/addons/sale_mrp/sale_mrp.py index 77a35972638..f043791d0d9 100644 --- a/addons/sale_mrp/sale_mrp.py +++ b/addons/sale_mrp/sale_mrp.py @@ -69,6 +69,19 @@ class mrp_production(osv.osv): res[production.id] = move.sale_line_id and move.sale_line_id.order_id.client_order_ref or False return res + def _hook_create_post_procurement(self, cr, uid, production, procurement_id, context=None): + def get_parent_move(move): + if move.move_dest_id: + return get_parent_move(move.move_dest_id) + return move + + res = super(mrp_production, self)._hook_create_post_procurement(cr, uid, production, procurement_id, context) + if production.move_prod_id: + parent_move_line = get_parent_move(production.move_prod_id) + if parent_move_line and parent_move_line.sale_line_id: + self.pool.get('procurement.order').write(cr, uid, procurement_id, {'sale_line_id': parent_move_line.sale_line_id.id}) + return res + _columns = { 'sale_name': fields.function(_ref_calc, multi='sale_name', type='char', string='Sale Name', help='Indicate the name of sales order.'), 'sale_ref': fields.function(_ref_calc, multi='sale_name', type='char', string='Sale Reference', help='Indicate the Customer Reference from sales order.'), diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 77c1eae328a..1e032626194 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -397,7 +397,16 @@ class stock_location(osv.osv): uom_rounding = self.pool.get('product.product').browse(cr, uid, product_id, context=context).uom_id.rounding if context.get('uom'): uom_rounding = uom_obj.browse(cr, uid, context.get('uom'), context=context).rounding - for id in self.search(cr, uid, [('location_id', 'child_of', ids)]): + + locations_ids = self.search(cr, uid, [('location_id', 'child_of', ids)]) + # Fetch only the locations in which this product has ever been processed (in or out) + cr.execute("""SELECT l.id FROM stock_location l WHERE l.id in %s AND + EXISTS (SELECT 1 FROM stock_move m WHERE m.product_id = %s + AND ((state = 'done' AND m.location_dest_id = l.id) + OR (state in ('done','assigned') AND m.location_id = l.id))) + """, (tuple(locations_ids), product_id,)) + + for id in [i for (i,) in cr.fetchall()]: if lock: try: # Must lock with a separate select query because FOR UPDATE can't be used with @@ -1910,7 +1919,8 @@ class stock_move(osv.osv): """ if not prod_id: return {} - lang = False + user = self.pool.get('res.users').browse(cr, uid, uid) + lang = user and user.lang or False if partner_id: addr_rec = self.pool.get('res.partner').browse(cr, uid, partner_id) if addr_rec: diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 6bfc4c6eeb9..c48a7cf0f2b 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -759,7 +759,7 @@ <header> <button name="draft_force_assign" states="draft" string="Confirm" type="object" class="oe_highlight" groups="base.group_user"/> <button name="draft_validate" states="draft" string="Confirm & Transfer" type="object" class="oe_highlight" groups="base.group_user"/> - <!-- <button name="action_assign" states="confirmed" string="Check Availability" type="object"/> --> + <button name="action_assign" states="confirmed" string="Check Availability" type="object" class="oe_highlight"/> <button name="force_assign" states="confirmed" string="Force Availability" type="object" class="oe_highlight" groups="base.group_user"/> <button name="action_process" states="assigned" string="Confirm & Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight"/> <button name="%(action_stock_invoice_onshipping)d" string="Create Invoice/Refund" attrs="{'invisible': ['|','|',('state','<>','done'),('invoice_state','=','invoiced'),('invoice_state','=','none')]}" context="{'group_field_invisible': True}" type="action" class="oe_highlight" groups="base.group_user"/> @@ -909,7 +909,6 @@ </xpath> <xpath expr="/form/header//button[@name='draft_validate']" position="replace"> <button name="draft_validate" states="draft" string="Confirm & Deliver" type="object" class="oe_highlight"/> - <button name="action_assign" states="confirmed" string="Check Availability" type="object" class="oe_highlight"/> </xpath> <xpath expr="/form/header//button[@name='action_process']" position="replace"> <button name="action_process" states="assigned" string="Deliver" type="object" class="oe_highlight"/> diff --git a/addons/stock/wizard/stock_change_standard_price.py b/addons/stock/wizard/stock_change_standard_price.py index e6614724454..f83fd044aca 100644 --- a/addons/stock/wizard/stock_change_standard_price.py +++ b/addons/stock/wizard/stock_change_standard_price.py @@ -27,7 +27,7 @@ class change_standard_price(osv.osv_memory): _name = "stock.change.standard.price" _description = "Change Standard Price" _columns = { - 'new_price': fields.float('Price', required=True, digits_compute=dp.get_precision('Account'), + 'new_price': fields.float('Price', required=True, digits_compute=dp.get_precision('Product Price'), help="If cost price is increased, stock variation account will be debited " "and stock output account will be credited with the value = (difference of amount * quantity available).\n" "If cost price is decreased, stock variation account will be creadited and stock input account will be debited."), diff --git a/addons/survey/report/survey_browse_response.py b/addons/survey/report/survey_browse_response.py index 4f2dd8544e0..344de523628 100644 --- a/addons/survey/report/survey_browse_response.py +++ b/addons/survey/report/survey_browse_response.py @@ -27,6 +27,7 @@ from openerp import tools from openerp.report import report_sxw from openerp.report.interface import report_rml from openerp.tools import to_xml +from openerp.tools.translate import _ class survey_browse_response(report_rml): def create(self, cr, uid, ids, datas, context): @@ -69,7 +70,7 @@ class survey_browse_response(report_rml): rml +=""" <fill color="gray"/> <setFont name="Helvetica" size="10"/> - <drawRightString x='"""+tools.ustr(float(_pageSize[0].replace('cm','')) - float(1.00))+'cm'+"""' y="0.6cm">Page : <pageNumber/> </drawRightString>""" + <drawRightString x='"""+tools.ustr(float(_pageSize[0].replace('cm','')) - float(1.00))+'cm'+"""' y="0.6cm">"""+_('Page : ')+"""<pageNumber/> </drawRightString>""" rml +="""</pageGraphics> </pageTemplate> </template> @@ -209,29 +210,29 @@ class survey_browse_response(report_rml): resp_create = tools.ustr(time.strftime('%d-%m-%Y %I:%M:%S %p', time.strptime(response.date_create.split('.')[0], '%Y-%m-%d %H:%M:%S'))) rml += """<blockTable colWidths='""" + colwidth + """' style="Table_heading"> <tr> - <td><para style="terp_default_9_Bold">Print Date : </para></td> + <td><para style="terp_default_9_Bold">""" + _('Print Date : ') + """</para></td> <td><para style="terp_default_9">""" + to_xml(rml_obj.formatLang(time.strftime("%Y-%m-%d %H:%M:%S"),date_time=True)) + """</para></td> <td><para style="terp_default_9"></para></td> - <td><para style="terp_default_9_Bold">Answered by : </para></td> + <td><para style="terp_default_9_Bold">""" +_('Answered by : ') + """</para></td> <td><para style="terp_default_9">""" + to_xml(response.user_id.login or '') + """</para></td> </tr> <tr> <td><para style="terp_default_9"></para></td> <td><para style="terp_default_9"></para></td> <td><para style="terp_default_9"></para></td> - <td><para style="terp_default_9_Bold">Answer Date : </para></td> + <td><para style="terp_default_9_Bold">""" +_('Answer Date : ') + """</para></td> <td><para style="terp_default_9">""" + to_xml(resp_create) + """</para></td> </tr> </blockTable><para style="P2"></para>""" - status = "Not Finished" - if response.state == "done": status = "Finished" + status = _("Not Finished") + if response.state == "done": status = _("Finished") colwidth = str(tbl_width - 7) + "cm," colwidth += "7cm" rml += """<blockTable colWidths='""" + str(colwidth) + """' style="title_tbl"> <tr> <td><para style="title">""" + to_xml(tools.ustr(survey.title)) + """</para><para style="P2"><font></font></para></td> - <td><para style="descriptive_text_heading">Status :- """ + to_xml(tools.ustr(status)) + """</para><para style="P2"><font></font></para></td> + <td><para style="descriptive_text_heading">"""+_('Status :- ')+ to_xml(tools.ustr(status)) + """</para><para style="P2"><font></font></para></td> </tr> </blockTable>""" @@ -242,7 +243,7 @@ class survey_browse_response(report_rml): for page in survey.page_ids: rml += """<blockTable colWidths='""" + str(_tbl_widths) + """' style="page_tbl"> - <tr><td><para style="page">Page :- """ + to_xml(tools.ustr(page.title or '')) + """</para></td></tr> + <tr><td><para style="page">"""+_('Page :- ') + to_xml(tools.ustr(page.title or '')) + """</para></td></tr> </blockTable>""" if page.note: rml += """<para style="P2"></para> @@ -302,7 +303,7 @@ class survey_browse_response(report_rml): else: rml +="""<blockTable colWidths='""" + str(_tbl_widths) + """' style="simple_table"> - <tr><td> <para style="response">No Answer</para></td> </tr> + <tr><td> <para style="response">"""+ _('No Answer') + """</para></td> </tr> </blockTable>""" elif que.type in ['multiple_choice_only_one_ans','multiple_choice_multiple_ans']: diff --git a/addons/survey/wizard/survey_answer.py b/addons/survey/wizard/survey_answer.py index 7e58c8a10eb..5b9bbb5de7e 100644 --- a/addons/survey/wizard/survey_answer.py +++ b/addons/survey/wizard/survey_answer.py @@ -173,8 +173,8 @@ class survey_question_wiz(osv.osv_memory): # TODO: l10n, cleanup this code to make it readable. Or template? xml_group = etree.SubElement(xml_form, 'group', {'col': '40', 'colspan': '4'}) record = sur_response_obj.browse(cr, uid, context['response_id'][context['response_no']]) - etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr('Answer Of :- ' + record.user_id.name + ', Date :- ' + record.date_create.split('.')[0] )), 'align':"0.0"}) - etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(" Answer :- " + str(context.get('response_no',0) + 1) +"/" + str(len(context.get('response_id',0))) )), 'align':"0.0"}) + etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(_('Answer Of :- ') + record.user_id.name + _(', Date :- ') + record.date_create.split('.')[0] )), 'align':"0.0"}) + etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(_(" Answer :- ") + str(context.get('response_no',0) + 1) +"/" + str(len(context.get('response_id',0))) )), 'align':"0.0"}) if context.get('response_no',0) > 0: etree.SubElement(xml_group, 'button', {'colspan':"1",'icon':"gtk-go-back",'name':"action_forward_previous",'string': tools.ustr("Previous Answer"),'type':"object"}) if context.get('response_no',0) + 1 < len(context.get('response_id',0)): @@ -221,7 +221,7 @@ class survey_question_wiz(osv.osv_memory): selection.append((tools.ustr(ans.id), ans.answer)) xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'}) etree.SubElement(xml_group, 'field', {'readonly':str(readonly), 'name': tools.ustr(que.id) + "_selection"}) - fields[tools.ustr(que.id) + "_selection"] = {'type':'selection', 'selection' :selection, 'string':"Answer"} + fields[tools.ustr(que.id) + "_selection"] = {'type':'selection', 'selection' :selection, 'string':_('Answer')} elif que_rec.type == 'multiple_choice_multiple_ans': xml_group = etree.SubElement(xml_group, 'group', {'col': '4', 'colspan': '4'}) @@ -374,10 +374,10 @@ class survey_question_wiz(osv.osv_memory): if pre_button: etree.SubElement(xml_footer, 'label', {'string': ""}) - etree.SubElement(xml_footer, 'button', {'name':"action_previous",'string':"Previous",'type':"object"}) - but_string = "Next" + etree.SubElement(xml_footer, 'button', {'name':"action_previous",'string':_('Previous'),'type':"object"}) + but_string = _('Next') if int(page_number) + 1 == total_pages: - but_string = "Done" + but_string = _('Done') if context.has_key('active') and context.get('active',False) and int(page_number) + 1 == total_pages and context.has_key('response_id') and context.has_key('response_no') and context.get('response_no',0) + 1 == len(context.get('response_id',0)): etree.SubElement(xml_footer, 'label', {'string': ""}) etree.SubElement(xml_footer, 'button', {'special' : 'cancel','string': tools.ustr("Done") ,'context' : tools.ustr(context), 'class':"oe_highlight"}) @@ -390,8 +390,8 @@ class survey_question_wiz(osv.osv_memory): else: etree.SubElement(xml_footer, 'label', {'string': ""}) etree.SubElement(xml_footer, 'button', {'name':"action_next",'string': tools.ustr(but_string) ,'type':"object",'context' : tools.ustr(context), 'class':"oe_highlight"}) - etree.SubElement(xml_footer, 'label', {'string': "or"}) - etree.SubElement(xml_footer, 'button', {'special': "cancel",'string':"Exit",'class':"oe_link"}) + etree.SubElement(xml_footer, 'label', {'string': _('or')}) + etree.SubElement(xml_footer, 'button', {'special': "cancel",'string':_('Exit'),'class':"oe_link"}) etree.SubElement(xml_footer, 'label', {'string': tools.ustr(page_number+ 1) + "/" + tools.ustr(total_pages), 'class':"oe_survey_title_page oe_right"}) root = xml_form.getroottree() |
