diff --git a/MANIFEST.in b/MANIFEST.in index eea6b83adeb..7c447c6c377 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -10,6 +10,7 @@ recursive-include openerp *.jpg recursive-include openerp *.js recursive-include openerp *.less recursive-include openerp *.md +recursive-include openerp *.mp3 recursive-include openerp *.png recursive-include openerp *.po recursive-include openerp *.rml diff --git a/addons/account/account.py b/addons/account/account.py index 38c6b54fbbb..e598d9fce4b 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1166,13 +1166,15 @@ class account_move(osv.osv): _order = 'id desc' def account_assert_balanced(self, cr, uid, context=None): + obj_precision = self.pool.get('decimal.precision') + prec = obj_precision.precision_get(cr, uid, 'Account') cr.execute("""\ SELECT move_id FROM account_move_line WHERE state = 'valid' GROUP BY move_id - HAVING abs(sum(debit) - sum(credit)) > 0.00001 - """) + HAVING abs(sum(debit) - sum(credit)) >= %s + """ % (10 ** (-max(5, prec)))) assert len(cr.fetchall()) == 0, \ "For all Journal Items, the state is valid implies that the sum " \ "of credits equals the sum of debits" @@ -1533,6 +1535,8 @@ class account_move(osv.osv): valid_moves = [] #Maintains a list of moves which can be responsible to create analytic entries obj_analytic_line = self.pool.get('account.analytic.line') obj_move_line = self.pool.get('account.move.line') + obj_precision = self.pool.get('decimal.precision') + prec = obj_precision.precision_get(cr, uid, 'Account') for move in self.browse(cr, uid, ids, context): journal = move.journal_id amount = 0 @@ -1556,7 +1560,7 @@ class account_move(osv.osv): if line.account_id.currency_id.id != line.currency_id.id and (line.account_id.currency_id.id != line.account_id.company_id.currency_id.id): raise UserError(_("""Cannot create move with currency different from ..""") % (line.account_id.code, line.account_id.name)) - if abs(amount) < 10 ** -4: + if round(abs(amount), prec) < 10 ** (-max(5, prec)): # If the move is balanced # Add to the list of valid moves # (analytic lines will be created later for valid moves) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index 215a9eccec0..9eadf12e9e5 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -910,7 +910,10 @@ class account_invoice(models.Model): i[2]['period_id'] = period.id ctx['invoice'] = inv - move = account_move.with_context(ctx).create(move_vals) + ctx_nolang = ctx.copy() + ctx_nolang.pop('lang', None) + move = account_move.with_context(ctx_nolang).create(move_vals) + # make the invoice point to that move vals = { 'move_id': move.id, diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index 865ed22dc47..19274d1d8ac 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -225,7 +225,7 @@ class account_move_line(osv.osv): 'journal_id': obj_line.journal_id.analytic_journal_id.id, 'ref': obj_line.ref, 'move_id': obj_line.id, - 'user_id': uid, + 'user_id': obj_line.invoice.user_id.id or uid, } def create_analytic_lines(self, cr, uid, ids, context=None): @@ -995,7 +995,7 @@ class account_move_line(osv.osv): if context is None: context = {} company_list = [] - for line in self.browse(cr, uid, ids, context=context): + for line in lines: if company_list and not line.company_id.id in company_list: raise UserError(_('To reconcile the entries company should be the same for all entries.')) company_list.append(line.company_id.id) diff --git a/addons/account/test/account_test_users.yml b/addons/account/test/account_test_users.yml index c0002ac8b67..7426fb7e8a3 100644 --- a/addons/account/test/account_test_users.yml +++ b/addons/account/test/account_test_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Accountant login: acc - password: acc email: accountuser@yourcompany.com - I added groups for Accountant. @@ -21,7 +20,6 @@ company_id: base.main_company name: Financial Manager login: fm - password: fm email: accountmanager@yourcompany.com - I added groups for Financial Manager. @@ -29,4 +27,4 @@ !record {model: res.users, id: res_users_account_manager}: groups_id: - account.group_account_manager - - base.group_partner_manager \ No newline at end of file + - base.group_partner_manager diff --git a/addons/account_budget/account_budget.py b/addons/account_budget/account_budget.py index 9b436378c2a..04ea7bdeb61 100644 --- a/addons/account_budget/account_budget.py +++ b/addons/account_budget/account_budget.py @@ -119,10 +119,12 @@ class crossovered_budget_lines(osv.osv): result = 0.0 if context is None: context = {} + account_obj = self.pool.get('account.account') for line in self.browse(cr, uid, ids, context=context): acc_ids = [x.id for x in line.general_budget_id.account_ids] if not acc_ids: raise UserError(_("The Budget '%s' has no accounts!") % ustr(line.general_budget_id.name)) + acc_ids = account_obj._get_children_and_consol(cr, uid, acc_ids, context=context) date_to = line.date_to date_from = line.date_from if line.analytic_account_id.id: diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index bad54497819..15ea283faa4 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -227,8 +227,8 @@ class account_voucher(osv.osv): if not ids: return {} currency_obj = self.pool.get('res.currency') res = {} - debit = credit = 0.0 for voucher in self.browse(cr, uid, ids, context=context): + debit = credit = 0.0 sign = voucher.type == 'payment' and -1 or 1 for l in voucher.line_dr_ids: debit += l.amount diff --git a/addons/account_voucher/test/account_voucher_users.yml b/addons/account_voucher/test/account_voucher_users.yml index cb822ae4cef..4126ef874bc 100644 --- a/addons/account_voucher/test/account_voucher_users.yml +++ b/addons/account_voucher/test/account_voucher_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Voucher Accountant login: vacc - password: acc email: accountant@yourcompany.com - I added groups to Accountant for account voucher. @@ -21,7 +20,6 @@ company_id: base.main_company name: Financial Manager for voucher login: fmv - password: fmv email: finmanager@yourcompany.com - I added groups to Financial Manager for account voucher. diff --git a/addons/auth_signup/auth_signup_data.xml b/addons/auth_signup/auth_signup_data.xml index 5f5a05740ac..51a4dbfc676 100644 --- a/addons/auth_signup/auth_signup_data.xml +++ b/addons/auth_signup/auth_signup_data.xml @@ -6,8 +6,6 @@ Template User portaltemplate - - diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py index 00c27e38c58..dbce913be7c 100644 --- a/addons/auth_signup/res_users.py +++ b/addons/auth_signup/res_users.py @@ -265,7 +265,7 @@ class res_users(osv.Model): if not user_ids: user_ids = self.search(cr, uid, [('email', '=', login)], context=context) if len(user_ids) != 1: - raise Exception('Reset password: invalid username or email') + raise Exception(_('Reset password: invalid username or email')) return self.action_reset_password(cr, uid, user_ids, context=context) def action_reset_password(self, cr, uid, ids, context=None): diff --git a/addons/crm/test/crm_access_group_users.yml b/addons/crm/test/crm_access_group_users.yml index ffde96a18f3..e7fdc86d096 100644 --- a/addons/crm/test/crm_access_group_users.yml +++ b/addons/crm/test/crm_access_group_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Crm Sales manager login: csm - password: csm email: crmmanager@yourcompany.com - I added groups for Crm Salesmanager. @@ -20,7 +19,6 @@ company_id: base.main_company name: Crm Salesman login: csu - password: csu email: crmuser@yourcompany.com - I added groups for Crm Salesman. diff --git a/addons/crm/test/lead2opportunity_assign_salesmen.yml b/addons/crm/test/lead2opportunity_assign_salesmen.yml index dbf917ecfc9..ddc587e846d 100644 --- a/addons/crm/test/lead2opportunity_assign_salesmen.yml +++ b/addons/crm/test/lead2opportunity_assign_salesmen.yml @@ -4,22 +4,18 @@ !record {model: res.users, id: test_res_user_01}: name: 'Test user A' login: 'tua@example.com' - new_password: 'tua' - !record {model: res.users, id: test_res_user_02}: name: 'Test user B' login: 'tub@example.com' - new_password: 'tub' - !record {model: res.users, id: test_res_user_03}: name: 'Test user C' login: 'tuc@example.com' - new_password: 'tuc' - !record {model: res.users, id: test_res_user_04}: name: 'Test user D' login: 'tud@example.com' - new_password: 'tud' - Salesman also creates lead so giving access rights of salesman. - diff --git a/addons/delivery/delivery.py b/addons/delivery/delivery.py index cf61228fc6a..428b00253de 100644 --- a/addons/delivery/delivery.py +++ b/addons/delivery/delivery.py @@ -113,12 +113,11 @@ class delivery_carrier(osv.osv): # not using advanced pricing per destination: override grid grid_id = grid_pool.search(cr, uid, [('carrier_id', '=', record.id)], context=context) - if grid_id and not (record.normal_price or record.free_if_more_than): + if grid_id and not (record.normal_price is not False or record.free_if_more_than): grid_pool.unlink(cr, uid, grid_id, context=context) grid_id = None - # Check that float, else 0.0 is False - if not (isinstance(record.normal_price,float) or record.free_if_more_than): + if not (record.normal_price is not False or record.free_if_more_than): continue if not grid_id: @@ -145,7 +144,7 @@ class delivery_carrier(osv.osv): 'list_price': 0.0, } grid_line_pool.create(cr, uid, line_data, context=context) - if isinstance(record.normal_price,float): + if record.normal_price is not False: line_data = { 'grid_id': grid_id and grid_id[0], 'name': _('Default price'), diff --git a/addons/delivery/sale.py b/addons/delivery/sale.py index 4b41c1be6e1..cc10d90e4ab 100644 --- a/addons/delivery/sale.py +++ b/addons/delivery/sale.py @@ -67,6 +67,7 @@ class sale_order(osv.Model): acc_fp_obj = self.pool.get('account.fiscal.position') self._delivery_unset(cr, uid, ids, context=context) currency_obj = self.pool.get('res.currency') + line_ids = [] for order in self.browse(cr, uid, ids, context=context): grid_id = carrier_obj.grid_get(cr, uid, [order.carrier_id.id], order.partner_shipping_id.id) if not grid_id: @@ -85,7 +86,7 @@ class sale_order(osv.Model): price_unit = currency_obj.compute(cr, uid, order.company_id.currency_id.id, order.pricelist_id.currency_id.id, price_unit, context=dict(context or {}, date=order.date_order)) #create the sale order line - line_obj.create(cr, uid, { + line_id = line_obj.create(cr, uid, { 'order_id': order.id, 'name': grid.carrier_id.name, 'product_uom_qty': 1, @@ -95,3 +96,5 @@ class sale_order(osv.Model): 'tax_id': [(6, 0, taxes_ids)], 'is_delivery': True }, context=context) + line_ids.append(line_id) + return line_ids diff --git a/addons/event/test/ui/event_users.yml b/addons/event/test/ui/event_users.yml index 1f4d7a56035..15dbe3b7cb9 100644 --- a/addons/event/test/ui/event_users.yml +++ b/addons/event/test/ui/event_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Event manager login: em - password: em email: eventmanager@yourcompany.com - I added groups for Event manager. @@ -20,7 +19,6 @@ company_id: base.main_company name: User login: eu - password: eu email: eventuser@yourcompany.com - I added groups for Event user. diff --git a/addons/google_calendar/google_calendar.py b/addons/google_calendar/google_calendar.py index 1bcbad15413..ed7a6d859cf 100644 --- a/addons/google_calendar/google_calendar.py +++ b/addons/google_calendar/google_calendar.py @@ -202,6 +202,8 @@ class google_calendar(osv.AbstractModel): _name = 'google.%s' % STR_SERVICE def generate_data(self, cr, uid, event, isCreating=False, context=None): + if not context: + context = {} if event.allday: start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.start, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T').split('T')[0] final_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.start, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=event.duration) + timedelta(days=isCreating and 1 or 0), context=context).isoformat('T').split('T')[0] @@ -226,19 +228,18 @@ class google_calendar(osv.AbstractModel): "method": "email" if alarm.type == "email" else "popup", "minutes": alarm.duration_minutes }) - data = { "summary": event.name or '', "description": event.description or '', "start": { type: start_date, vstype: None, - 'timeZone': 'UTC' + 'timeZone': context.get('tz', 'UTC'), }, "end": { type: final_date, vstype: None, - 'timeZone': 'UTC' + 'timeZone': context.get('tz', 'UTC'), }, "attendees": attendee_list, "reminders": { @@ -365,7 +366,7 @@ class google_calendar(osv.AbstractModel): url = "/calendar/v3/calendars/%s/events/%s?fields=%s&access_token=%s" % ('primary', google_event['id'], 'id,updated', self.get_token(cr, uid, context)) headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} - data = self.generate_data(cr, uid, oe_event, context) + data = self.generate_data(cr, uid, oe_event, context=context) data['sequence'] = google_event.get('sequence', 0) data_json = simplejson.dumps(data) diff --git a/addons/hr/test/hr_users.yml b/addons/hr/test/hr_users.yml index 820180bfc9b..551dcb63d0f 100644 --- a/addons/hr/test/hr_users.yml +++ b/addons/hr/test/hr_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: HR manager login: hrm - password: hrm - I added groups for HR Manager. - @@ -19,7 +18,6 @@ company_id: base.main_company name: HR Officer login: hro - password: hro email: hro@example.com - I added groups for HR Officer. @@ -34,7 +32,6 @@ company_id: base.main_company name: Employee login: emp - password: emp - I added groups for Employee. - diff --git a/addons/hr_attendance/test/attendance_process.yml b/addons/hr_attendance/test/attendance_process.yml index 2ecd2df3531..1a7302fe3c0 100644 --- a/addons/hr_attendance/test/attendance_process.yml +++ b/addons/hr_attendance/test/attendance_process.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: HR Officer login: ao - password: ao - I added groups for HR Attendance Officer. - diff --git a/addons/hr_gamification/wizard/grant_badge.py b/addons/hr_gamification/wizard/grant_badge.py index fc78fbb2e62..fcf66daa5e1 100644 --- a/addons/hr_gamification/wizard/grant_badge.py +++ b/addons/hr_gamification/wizard/grant_badge.py @@ -31,7 +31,7 @@ class hr_grant_badge_wizard(osv.TransientModel): 'employee_id': fields.many2one("hr.employee", string='Employee', required=True), 'user_id': fields.related("employee_id", "user_id", type="many2one", relation="res.users", - store=True, string='User', required=True) + store=True, string='User') } def action_grant_badge(self, cr, uid, ids, context=None): diff --git a/addons/hr_recruitment/test/recruitment_process.yml b/addons/hr_recruitment/test/recruitment_process.yml index 85abad2a9d6..201b8781981 100644 --- a/addons/hr_recruitment/test/recruitment_process.yml +++ b/addons/hr_recruitment/test/recruitment_process.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: HR Recruitment Officer login: hrro - password: hrro email: hrofcr@yourcompany.com - I added groups for HR Recruitment Officer. diff --git a/addons/hr_timesheet/test/hr_timesheet_users.yml b/addons/hr_timesheet/test/hr_timesheet_users.yml index 09731a16cf9..181ce6b6597 100644 --- a/addons/hr_timesheet/test/hr_timesheet_users.yml +++ b/addons/hr_timesheet/test/hr_timesheet_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: HR timesheet manager login: hrtm - password: hrtm - I added groups for HR timesheet Manager. - @@ -19,7 +18,6 @@ company_id: base.main_company name: HR timesheet Officer login: hrto - password: hrto - I added groups for HR timesheet Officer. - @@ -33,7 +31,6 @@ company_id: base.main_company name: Timesheet Employee login: empt - password: empt - I added groups for Timesheet Employee. - diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml index 4b2e884134e..813ee2e08f2 100644 --- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml +++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml @@ -108,7 +108,7 @@ - + diff --git a/addons/l10n_be/account_pcmn_belgium.xml b/addons/l10n_be/account_pcmn_belgium.xml index 54b8b4f4025..1e562e729e7 100644 --- a/addons/l10n_be/account_pcmn_belgium.xml +++ b/addons/l10n_be/account_pcmn_belgium.xml @@ -3589,6 +3589,7 @@ other + Acomptes reçus @@ -3596,6 +3597,7 @@ other + Compensations fournisseurs @@ -3603,6 +3605,7 @@ other + DETTES FISCALES, SALARIALES ET SOCIALES diff --git a/addons/l10n_ch/chart/vat2011.xml b/addons/l10n_ch/chart/vat2011.xml index e5133319a1a..ccbe5ac3fc6 100644 --- a/addons/l10n_ch/chart/vat2011.xml +++ b/addons/l10n_ch/chart/vat2011.xml @@ -12,17 +12,17 @@ - TVA due a 8.0% (TN) + TVA due a 8.0% 301b - TVA due a 2.5% (TR) + TVA due a 2.5% 311b - TVA due a 3.8% (TS) + TVA due a 3.8% 341b @@ -57,22 +57,22 @@ - Chiffre d'affaires imposable a 8.0% (TN) + Chiffre d'affaires imposable a 8.0% 301a - Chiffre d'affaires imposable a 2.5% (TR) + Chiffre d'affaires imposable a 2.5% 311a - Chiffre d'affaires imposable a 3.8% (TS) + Chiffre d'affaires imposable a 3.8% 341a - Chiffre d'affaires imposable a 0% (export) + Exportations 200-220 @@ -82,52 +82,57 @@ - Acquisition - total + Acquisitions - total - Acquisition de biens et services + Acquisitions de biens et services - Acquisition de biens et services a 0% - Babs0 - + Importations + imp + + + + Acquisitions non soumise à TVA (exclue) + Bexcl + - Acquisition de biens et services a 8.0% (TN) + Acquisitions de biens et services a 8.0% Babs8 - Acquisition de biens et services a 2.5% (TR) + Acquisitions de biens et services a 2.5% Babs25 - Acquisition de biens et services a 3.8% (TS) + Acquisitions de biens et services a 3.8% Babs38 - Acquisition de biens d'invest. et autres charges + Acquisitions de biens d'invest. et autres charges - Acquisition de biens d'invest. et autres charges a 8.0% (TN) + Acquisitions de biens d'invest. et autres charges a 8.0% Binv8 - Acquisition de biens d'invest. et autres charges a 2.5% (TR) + Acquisitions de biens d'invest. et autres charges a 2.5% Binv25 - Acquisition de biens d'invest. et autres charges a 3.8% (TS) + Acquisitions de biens d'invest. et autres charges a 3.8% Binv38 @@ -135,7 +140,7 @@ # TVA - Taxe sur la Valeur Ajoutée --> - TVA due a 2.5% (TR) + TVA due a 2.5% 2.5% percent @@ -152,8 +157,27 @@ sale + + TVA due a 2.5% TTC + 2.5% TTC + + + percent + + + + + + + + + + + + sale + - TVA 2.5% sur achat B&S (TR) + TVA 2.5% sur achats, biens et services 2.5% achat percent @@ -171,9 +195,30 @@ purchase - + + + TVA 2.5% sur achats, biens et services TTC + 2.5% achat TTC + + + percent + + + + + result = round((price_unit * 0.025) / 0.05) * 0.05 + result = round((price_unit * ( 1 - (1 / 1.025))) /0.05) * 0.05 + + + + + + purchase + + + - TVA 2.5% sur invest. et autres ch. (TR) + TVA 2.5% sur invest. et autres ch. 2.5% invest. percent @@ -192,9 +237,29 @@ - + + TVA 2.5% sur invest. et autres ch. TTC + 2.5% invest.TTC + + + percent + + + + + result = round((price_unit * 0.025) / 0.05) * 0.05 + result = round((price_unit * ( 1 - (1 / 1.025))) /0.05) * 0.05 + + + + + + purchase + + + - TVA due a 3.8% (TS) + TVA due a 3.8% 3.8% percent @@ -213,8 +278,29 @@ + + TVA due a 3.8% TTC + 3.8% TTC + + + percent + + + + + result = round((price_unit * 0.038) / 0.05) * 0.05 + result = round((price_unit * ( 1 - (1 / 1.038))) /0.05) * 0.05 + + + + + + sale + + + - TVA 3.8% sur achat B&S (TS) + TVA 3.8% sur achats, biens et services 3.8% achat percent @@ -233,8 +319,29 @@ + + TVA 3.8% sur achats, biens et services TTC + 3.8% achat TTC + + + percent + + + + + result = round((price_unit * 0.038) / 0.05) * 0.05 + result = round((price_unit * ( 1 - (1 / 1.038))) /0.05) * 0.05 + + + + + + purchase + + + - TVA 3.8% sur invest. et autres ch. (TS) + TVA 3.8% sur invest. et autres ch. 3.8% invest percent @@ -253,8 +360,29 @@ + + TVA 3.8% sur invest. et autres ch. TTC + 3.8% invest TTC + + + percent + + + + + result = round((price_unit * 0.038) / 0.05) * 0.05 + result = round((price_unit * ( 1 - (1 / 1.038))) /0.05) * 0.05 + + + + + + purchase + + + - TVA due a 8.0% (TN) + TVA due a 8.0% 8.0% @@ -275,7 +403,7 @@ - TVA 8.0% sur achat B&S (TN) + TVA 8.0% sur achats, biens et services 8.0% achat percent @@ -294,9 +422,52 @@ purchase - + + + TVA due a 8.0% TTC + 8.0% TTC + + + percent + + + + + result = round((price_unit * 0.080) / 0.05) * 0.05 + result = round((price_unit * ( 1 - (1 / 1.080))) /0.05) * 0.05 + + + + + + sale + + + + + TVA 8.0% sur achats, biens et services TTC + 8.0% achat TTC + + + percent + + + + + result = round((price_unit * 0.080) / 0.05) * 0.05 + result = round((price_unit * ( 1 - (1 / 1.080))) /0.05) * 0.05 + + + + + + purchase + + + + - TVA 8.0% sur invest. et autres ch. (TN) + TVA 8.0% sur invest. et autres ch. 8.0% invest. percent @@ -315,6 +486,27 @@ + + TVA 8.0% sur invest. et autres ch.TTC + 8.0% invest.TTC + + + percent + + + + + result = round((price_unit * 0.080) / 0.05) * 0.05 + result = round((price_unit * ( 1 - (1 / 1.080))) /0.05) * 0.05 + + + + + + purchase + + + TVA due a 0% (Exportations) @@ -334,8 +526,8 @@ - TVA 0% exclue - 0% excl. + TVA exclue/ventes + exclue percent @@ -351,8 +543,24 @@ + + TVA exclue/achats + 0% excl.ach. + + percent + + + + + + + + purchase + + + - TVA 0% Importations de biens et services + TVA 0% Importations 0% import. percent @@ -371,8 +579,25 @@ - 100% dédouanement TVA - 100% imp. + 100% dédouanement TVA sur invest. et autres ch. + 100% imp.invest. + + percent + + + + + + + + purchase + + + + + + 100% dédouanement TVA sur achats, biens et services + 100% imp.abs. percent @@ -383,8 +608,8 @@ purchase - - - + + + diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 48cf100e578..9c4c2491b76 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -446,6 +446,9 @@ class mail_thread(osv.AbstractModel): cascaded, because link is done through (res_model, res_id). """ msg_obj = self.pool.get('mail.message') fol_obj = self.pool.get('mail.followers') + + if isinstance(ids, (int, long)): + ids = [ids] # delete messages and notifications msg_ids = msg_obj.search(cr, uid, [('model', '=', self._name), ('res_id', 'in', ids)], context=context) msg_obj.unlink(cr, uid, msg_ids, context=context) @@ -837,7 +840,7 @@ class mail_thread(osv.AbstractModel): if not message_dict.get('parent_id'): raise ValueError('Routing: posting a message without model should be with a parent_id (private mesage).') _warn('posting a message without model should be with a parent_id (private mesage), skipping') - return () + return False # Existing Document: check if exists; if not, fallback on create if allowed if thread_id and not model_pool.exists(cr, uid, thread_id): @@ -848,7 +851,7 @@ class mail_thread(osv.AbstractModel): assert model_pool.exists(cr, uid, thread_id), 'Routing: reply to missing document (%s,%s)' % (model, thread_id) else: _warn('reply to missing document (%s,%s), skipping' % (model, thread_id)) - return () + return False # Existing Document: check model accepts the mailgateway if thread_id and model and not hasattr(model_pool, 'message_update'): @@ -859,7 +862,7 @@ class mail_thread(osv.AbstractModel): assert hasattr(model_pool, 'message_update'), 'Routing: model %s does not accept document update, crashing' % model else: _warn('model %s does not accept document update, skipping' % model) - return () + return False # New Document: check model accepts the mailgateway if not thread_id and model and not hasattr(model_pool, 'message_new'): @@ -869,7 +872,7 @@ class mail_thread(osv.AbstractModel): 'Model %s does not accept document creation, crashing' % model ) _warn('model %s does not accept document creation, skipping' % model) - return () + return False # Update message author if asked # We do it now because we need it for aliases (contact settings) @@ -888,16 +891,16 @@ class mail_thread(osv.AbstractModel): if not author_id or not author_id in [fol.id for fol in obj.message_follower_ids]: _warn('alias %s restricted to internal followers, skipping' % alias.alias_name) _create_bounce_email() - return () + return False elif alias and alias.alias_contact == 'partners' and not author_id: _warn('alias %s does not accept unknown author, skipping' % alias.alias_name) _create_bounce_email() - return () + return False if not model and not thread_id and not alias and not allow_private: return () - return (model, thread_id, route[2], route[3], route[4]) + return (model, thread_id, route[2], route[3], None if context.get('drop_alias', False) else route[4]) def message_route(self, cr, uid, message, message_dict, model=None, thread_id=None, custom_values=None, context=None): @@ -937,6 +940,7 @@ class mail_thread(osv.AbstractModel): if not isinstance(message, Message): raise TypeError('message must be an email.message.Message at this point') mail_msg_obj = self.pool['mail.message'] + mail_alias = self.pool.get('mail.alias') fallback_model = model # Get email.message.Message variables for future processing @@ -964,15 +968,21 @@ class mail_thread(osv.AbstractModel): if ref_match and mail_message_ids: original_msg = mail_msg_obj.browse(cr, SUPERUSER_ID, mail_message_ids[0], context=context) model, thread_id = original_msg.model, original_msg.res_id + alias_ids = mail_alias.search(cr, uid, [('alias_name', '=', (tools.email_split(email_to) or [''])[0].split('@', 1)[0].lower())]) + alias = None + if alias_ids: + alias = mail_alias.browse(cr, uid, [alias_ids[0]], context=context) route = self.message_route_verify( cr, uid, message, message_dict, - (model, thread_id, custom_values, uid, None), - update_author=True, assert_model=False, create_fallback=True, context=context) + (model, thread_id, custom_values, uid, alias), + update_author=True, assert_model=False, create_fallback=True, context=dict(context, drop_alias=True)) if route: _logger.info( 'Routing mail from %s to %s with Message-Id %s: direct reply to msg: model: %s, thread_id: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, model, thread_id, custom_values, uid) return [route] + elif route is False: + return [] # 2. message is a reply to an existign thread (6.1 compatibility) if ref_match: @@ -1001,6 +1011,8 @@ class mail_thread(osv.AbstractModel): 'Routing mail from %s to %s with Message-Id %s: direct thread reply (compat-mode) to model: %s, thread_id: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, model, thread_id, custom_values, uid) return [route] + elif route is False: + return [] # 3. Reply to a private message if in_reply_to: @@ -1018,6 +1030,8 @@ class mail_thread(osv.AbstractModel): 'Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s', email_from, email_to, message_id, mail_message.id, custom_values, uid) return [route] + elif route is False: + return [] # 4. Look for a matching mail.alias entry # Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values @@ -1030,7 +1044,6 @@ class mail_thread(osv.AbstractModel): decode_header(message, 'Resent-Cc')]) local_parts = [e.split('@')[0] for e in tools.email_split(rcpt_tos)] if local_parts: - mail_alias = self.pool.get('mail.alias') alias_ids = mail_alias.search(cr, uid, [('alias_name', 'in', local_parts)]) if alias_ids: routes = [] @@ -1085,7 +1098,7 @@ class mail_thread(osv.AbstractModel): context = dict(context or {}) partner_ids = message_dict.pop('partner_ids', []) thread_id = False - for model, thread_id, custom_values, user_id, alias in routes: + for model, thread_id, custom_values, user_id, alias in routes or (): if self._name == 'mail.thread': context['thread_model'] = model if model: diff --git a/addons/mail/tests/common.py b/addons/mail/tests/common.py index 1825d532571..5a07c634951 100644 --- a/addons/mail/tests/common.py +++ b/addons/mail/tests/common.py @@ -100,7 +100,7 @@ class TestMail(common.SavepointCase): 'login': 'raoul', 'alias_name': 'raoul', 'groups_id': [(6, 0, [cls.group_employee_id])] - }) + }, {'no_reset_password': True}) cls.user_bert_id = cls.res_users.create(cr, uid, { 'name': 'Bert Tartignole', 'signature': 'SignBert', @@ -108,7 +108,7 @@ class TestMail(common.SavepointCase): 'login': 'bert', 'alias_name': 'bert', 'groups_id': [(6, 0, [])] - }) + }, {'no_reset_password': True}) cls.user_raoul = cls.res_users.browse(cr, uid, cls.user_raoul_id) cls.user_bert = cls.res_users.browse(cr, uid, cls.user_bert_id) cls.user_admin = cls.res_users.browse(cr, uid, uid) diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index 01698773e34..2295874d2b8 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -28,6 +28,46 @@ class MassMailingTag(osv.Model): } +class MassMailingList(osv.Model): + """Model of a contact list. """ + _name = 'mail.mass_mailing.list' + _order = 'name' + _description = 'Mailing List' + + def _get_contact_nbr(self, cr, uid, ids, name, arg, context=None): + result = dict.fromkeys(ids, 0) + Contacts = self.pool.get('mail.mass_mailing.contact') + for group in Contacts.read_group(cr, uid, [('list_id', 'in', ids), ('opt_out', '!=', True)], ['list_id'], ['list_id'], context=context): + result[group['list_id'][0]] = group['list_id_count'] + return result + + _columns = { + 'name': fields.char('Mailing List', required=True), + 'create_date': fields.datetime('Creation Date'), + 'contact_nbr': fields.function( + _get_contact_nbr, type='integer', + string='Number of Contacts', + ), + 'popup_content': fields.html("Website Popup Content", translate=True, required=True, sanitize=False), + 'popup_redirect_url': fields.char("Website Popup Redirect URL"), + } + + def _get_default_popup_content(self, cr, uid, context=None): + return """
+

Odoo Presents

+
+
+ 7 + Business Hacks + to
boost your marketing
+
+

Join our Marketing newsletter and get this white paper instantly

""" + + _defaults = { + 'popup_content': _get_default_popup_content, + } + + class MassMailingContact(osv.Model): """Model of a contact. This model is different from the partner model because it holds only some basic information: name, email. The purpose is to @@ -108,46 +148,6 @@ class MassMailingContact(osv.Model): self.write(cr, uid, [obj.id], {'message_bounce': obj.message_bounce + 1}, context=context) -class MassMailingList(osv.Model): - """Model of a contact list. """ - _name = 'mail.mass_mailing.list' - _order = 'name' - _description = 'Mailing List' - - def _get_contact_nbr(self, cr, uid, ids, name, arg, context=None): - result = dict.fromkeys(ids, 0) - Contacts = self.pool.get('mail.mass_mailing.contact') - for group in Contacts.read_group(cr, uid, [('list_id', 'in', ids), ('opt_out', '!=', True)], ['list_id'], ['list_id'], context=context): - result[group['list_id'][0]] = group['list_id_count'] - return result - - _columns = { - 'name': fields.char('Mailing List', required=True), - 'create_date': fields.datetime('Creation Date'), - 'contact_nbr': fields.function( - _get_contact_nbr, type='integer', - string='Number of Contacts', - ), - 'popup_content': fields.html("Website Popup Content", translate=True, required=True, sanitize=False), - 'popup_redirect_url': fields.char("Website Popup Redirect URL"), - } - - def _get_default_popup_content(self, cr, uid, context=None): - return """
-

Odoo Presents

-
-
- 7 - Business Hacks - to
boost your marketing
-
-

Join our Marketing newsletter and get this white paper instantly

""" - - _defaults = { - 'popup_content': _get_default_popup_content, - } - - class MassMailingStage(osv.Model): """Stage for mass mailing campaigns. """ _name = 'mail.mass_mailing.stage' diff --git a/addons/mass_mailing/views/mass_mailing.xml b/addons/mass_mailing/views/mass_mailing.xml index 9fb357432aa..741948255a7 100644 --- a/addons/mass_mailing/views/mass_mailing.xml +++ b/addons/mass_mailing/views/mass_mailing.xml @@ -25,17 +25,16 @@ - - - - + + + + - - - + + + + + @@ -400,15 +399,18 @@ diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 442d673b33f..684c5630e41 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -507,6 +507,12 @@ class mrp_production(osv.osv): result[prod.id]['cycle_total'] += wc.cycle return result + def _get_workcenter_line(self, cr, uid, ids, context=None): + result = {} + for line in self.pool['mrp.production.workcenter.line'].browse(cr, uid, ids, context=context): + result[line.production_id.id] = True + return result.keys() + def _src_id_default(self, cr, uid, ids, context=None): try: location_model, location_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock') @@ -605,8 +611,14 @@ class mrp_production(osv.osv): If the stock is available then the status is set to 'Ready to Produce'.\n\ When the production gets started then the status is set to 'In Production'.\n\ When the production is over, the status is set to 'Done'."), - 'hour_total': fields.function(_production_calc, type='float', string='Total Hours', multi='workorder', store=True), - 'cycle_total': fields.function(_production_calc, type='float', string='Total Cycles', multi='workorder', store=True), + 'hour_total': fields.function(_production_calc, type='float', string='Total Hours', multi='workorder', store={ + _name: (lambda self, cr, uid, ids, c={}: ids, ['workcenter_lines'], 40), + 'mrp.production.workcenter.line': (_get_workcenter_line, ['hour', 'cycle'], 40), + }), + 'cycle_total': fields.function(_production_calc, type='float', string='Total Cycles', multi='workorder', store={ + _name: (lambda self, cr, uid, ids, c={}: ids, ['workcenter_lines'], 40), + 'mrp.production.workcenter.line': (_get_workcenter_line, ['hour', 'cycle'], 40), + }), 'user_id': fields.many2one('res.users', 'Responsible'), 'company_id': fields.many2one('res.company', 'Company', required=True), 'ready_production': fields.function(_moves_assigned, type='boolean', string="Ready for production", store={'stock.move': (_mrp_from_move, ['state'], 10)}), diff --git a/addons/mrp/test/mrp_users.yml b/addons/mrp/test/mrp_users.yml index 8f89207a47d..414610feb19 100644 --- a/addons/mrp/test/mrp_users.yml +++ b/addons/mrp/test/mrp_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: MRP Manager login: mam - password: mam email: mrp_manager@yourcompany.com - I added groups for MRP Manager. @@ -21,11 +20,10 @@ company_id: base.main_company name: MRP User login: mau - password: mau email: mrp_user@yourcompany.com - I added groups for MRP User. - !record {model: res.users, id: res_users_mrp_user}: groups_id: - - mrp.group_mrp_user \ No newline at end of file + - mrp.group_mrp_user diff --git a/addons/mrp_operations/test/workcenter_operations.yml b/addons/mrp_operations/test/workcenter_operations.yml index a595fe7f624..0432d4ad8e1 100644 --- a/addons/mrp_operations/test/workcenter_operations.yml +++ b/addons/mrp_operations/test/workcenter_operations.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: MRP User login: maou - password: maou email: mrp_operation_user@yourcompany.com - I added groups for MRP User. diff --git a/addons/mrp_repair/test/mrp_repair_users.yml b/addons/mrp_repair/test/mrp_repair_users.yml index fe8a2f5babe..ba39b09ab0d 100644 --- a/addons/mrp_repair/test/mrp_repair_users.yml +++ b/addons/mrp_repair/test/mrp_repair_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: MRP Manager login: marm - password: marm email: mrp_repair_manager@yourcompany.com - I added groups for MRP Repair Manager. @@ -20,11 +19,10 @@ company_id: base.main_company name: MRP User login: maru - password: maru email: mrp_repair_user@yourcompany.com - I added groups for MRP Repair User. - !record {model: res.users, id: res_mrp_repair_user}: groups_id: - - mrp.group_mrp_user \ No newline at end of file + - mrp.group_mrp_user diff --git a/addons/payment_ogone/models/ogone.py b/addons/payment_ogone/models/ogone.py index f6610544113..25bcb561e72 100644 --- a/addons/payment_ogone/models/ogone.py +++ b/addons/payment_ogone/models/ogone.py @@ -7,6 +7,7 @@ from lxml import etree, objectify from openerp.tools.translate import _ from pprint import pformat import time +from datetime import datetime from urllib import urlencode import urllib2 import urlparse @@ -289,7 +290,7 @@ class PaymentTxOgone(osv.Model): if status in self._ogone_valid_tx_status: tx.write({ 'state': 'done', - 'date_validate': data['TRXDATE'], + 'date_validate': datetime.strptime(data['TRXDATE'],'%m/%d/%y').strftime(DEFAULT_SERVER_DATE_FORMAT), 'acquirer_reference': data['PAYID'], }) return True diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index 09ca3903d96..0ef1613e0ef 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -708,7 +708,8 @@ class pos_order(osv.osv): val1 += self._amount_line_tax(cr, uid, line, context=context) val2 += line.price_subtotal res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val1) - res[order.id]['amount_total'] = cur_obj.round(cr, uid, cur, val1+val2) + amount_untaxed = cur_obj.round(cr, uid, cur, val2) + res[order.id]['amount_total'] = res[order.id]['amount_tax'] + amount_untaxed return res _columns = { @@ -1009,7 +1010,6 @@ class pos_order(osv.osv): 'invoice_id': inv_id, 'product_id': line.product_id.id, 'quantity': line.qty, - 'account_analytic_id': self._prepare_analytic_account(cr, uid, line, context=context), } inv_name = product_obj.name_get(cr, uid, [line.product_id.id], context=context)[0][1] inv_line.update(inv_line_ref.product_id_change(cr, uid, [], @@ -1017,6 +1017,10 @@ class pos_order(osv.osv): line.product_id.uom_id.id, line.qty, partner_id = order.partner_id.id, fposition_id=order.partner_id.property_account_position.id)['value']) + if not inv_line.get('account_analytic_id', False): + inv_line['account_analytic_id'] = \ + self._prepare_analytic_account(cr, uid, line, + context=context) inv_line['price_unit'] = line.price_unit inv_line['discount'] = line.discount inv_line['name'] = inv_name diff --git a/addons/point_of_sale/static/src/js/db.js b/addons/point_of_sale/static/src/js/db.js index 83c5a7be2f5..e836060df43 100644 --- a/addons/point_of_sale/static/src/js/db.js +++ b/addons/point_of_sale/static/src/js/db.js @@ -380,7 +380,7 @@ openerp.point_of_sale.load_db = function load_db(instance, module){ search_product_in_category: function(category_id, query){ try { query = query.replace(/[\[\]\(\)\+\*\?\.\-\!\&\^\$\|\~\_\{\}\:\,\\\/]/g,'.'); - query = query.replace(' ','.+'); + query = query.replace(/ /g,'.+'); var re = RegExp("([0-9]+):.*?"+query,"gi"); }catch(e){ return []; diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 4976d8da07e..204021cf725 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -1176,6 +1176,7 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo taxtotal += tax.amount; taxdetail[tax.id] = tax.amount; }); + totalNoTax = round_pr(totalNoTax, this.pos.currency.rounding); return { "priceWithTax": totalTax, @@ -1651,9 +1652,7 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo }), 0), this.pos.currency.rounding); }, get_total_with_tax: function() { - return round_pr(this.orderlines.reduce((function(sum, orderLine) { - return sum + orderLine.get_price_with_tax(); - }), 0), this.pos.currency.rounding); + return this.get_total_without_tax() + this.get_total_tax(); }, get_total_without_tax: function() { return round_pr(this.orderlines.reduce((function(sum, orderLine) { diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py index 65f41355a36..15b484a557d 100644 --- a/addons/portal/tests/test_portal.py +++ b/addons/portal/tests/test_portal.py @@ -35,7 +35,12 @@ class test_portal(TestMail): cls.group_portal_id = cls.env.ref('base.group_portal').id # Create Chell (portal user) - cls.user_chell_id = cls.res_users.create(cr, uid, {'name': 'Chell Gladys', 'login': 'chell', 'email': 'chell@gladys.portal', 'groups_id': [(6, 0, [cls.group_portal_id])]}) + cls.user_chell_id = cls.res_users.create(cr, uid, { + 'name': 'Chell Gladys', + 'login': 'chell', + 'email': 'chell@gladys.portal', + 'groups_id': [(6, 0, [cls.group_portal_id])] + }, {'no_reset_password': True}) cls.user_chell = cls.res_users.browse(cr, uid, cls.user_chell_id) cls.partner_chell_id = cls.user_chell.partner_id.id diff --git a/addons/portal_project/tests/test_access_rights.py b/addons/portal_project/tests/test_access_rights.py index c1b75b07bff..f33b5dbbd86 100644 --- a/addons/portal_project/tests/test_access_rights.py +++ b/addons/portal_project/tests/test_access_rights.py @@ -45,19 +45,19 @@ class TestPortalProjectBase(TestProjectBase): 'login': 'chell', 'alias_name': 'chell', 'groups_id': [(6, 0, [self.group_portal_id])] - }) + }, {'no_reset_password': True}) self.user_public_id = self.res_users.create(cr, uid, { 'name': 'Donovan Public', 'login': 'donovan', 'alias_name': 'donovan', 'groups_id': [(6, 0, [self.group_public_id])] - }) + }, {'no_reset_password': True}) self.user_manager_id = self.res_users.create(cr, uid, { 'name': 'Eustache Manager', 'login': 'eustache', 'alias_name': 'eustache', 'groups_id': [(6, 0, [self.group_project_manager_id])] - }) + }, {'no_reset_password': True}) # Test 'Pigs' project self.project_pigs_id = self.project_project.create(cr, uid, { diff --git a/addons/product/product.py b/addons/product/product.py index 6e28ab26c0b..15566e403f3 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -721,7 +721,7 @@ class product_template(osv.osv): # unlink or inactive product for variant_id in map(int,variants_inactive): try: - with cr.savepoint(): + with cr.savepoint(), tools.mute_logger('openerp.sql_db'): product_obj.unlink(cr, uid, [variant_id], context=ctx) #We catch all kind of exception to be sure that the operation doesn't fail. except (psycopg2.Error, except_orm): @@ -937,12 +937,12 @@ class product_product(osv.osv): def _set_image_variant(self, cr, uid, id, name, value, args, context=None): image = tools.image_resize_image_big(value) - res = self.write(cr, uid, [id], {'image_variant': image}, context=context) + product = self.browse(cr, uid, id, context=context) - if not product.product_tmpl_id.image: - product.write({'image_variant': None}) - product.product_tmpl_id.write({'image': image}) - return res + if product.product_tmpl_id.image: + product.image_variant = image + else: + product.product_tmpl_id.image = image def _get_price_extra(self, cr, uid, ids, name, args, context=None): result = dict.fromkeys(ids, False) diff --git a/addons/project/tests/test_project_base.py b/addons/project/tests/test_project_base.py index fc788de5c6c..3c91a979315 100644 --- a/addons/project/tests/test_project_base.py +++ b/addons/project/tests/test_project_base.py @@ -57,21 +57,21 @@ class TestProjectBase(TestMail): 'alias_name': 'armande', 'email': 'armande.projectuser@example.com', 'groups_id': [(6, 0, [cls.group_employee_id, cls.group_project_user_id])] - }) + }, {'no_reset_password': True}) cls.user_projectmanager_id = cls.res_users.create(cr, uid, { 'name': 'Bastien ProjectManager', 'login': 'bastien', 'alias_name': 'bastien', 'email': 'bastien.projectmanager@example.com', 'groups_id': [(6, 0, [cls.group_employee_id, cls.group_project_manager_id])] - }) + }, {'no_reset_password': True}) cls.user_none_id = cls.res_users.create(cr, uid, { 'name': 'Charlie Avotbonkeur', 'login': 'charlie', 'alias_name': 'charlie', 'email': 'charlie.noone@example.com', 'groups_id': [(6, 0, [])] - }) + }, {'no_reset_password': True}) cls.user_projectuser = cls.res_users.browse(cr, uid, cls.user_projectuser_id) cls.user_projectmanager = cls.res_users.browse(cr, uid, cls.user_projectmanager_id) cls.partner_projectuser_id = cls.user_projectuser.partner_id.id diff --git a/addons/project_issue/test/issue_users.yml b/addons/project_issue/test/issue_users.yml index 7ec9d22c7e2..a0ad327b86b 100644 --- a/addons/project_issue/test/issue_users.yml +++ b/addons/project_issue/test/issue_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Project Manager login: prim - password: prim email: issuemanager@yourcompany.com - I added groups for Project manager. @@ -20,11 +19,10 @@ company_id: base.main_company name: Project User login: priu - password: priu email: issueuser@yourcompany.com - I added groups for Project user. - !record {model: res.users, id: res_users_project_issue_user}: groups_id: - - project.group_project_user \ No newline at end of file + - project.group_project_user diff --git a/addons/project_timesheet/test/worktask_entry_to_timesheetline_entry.yml b/addons/project_timesheet/test/worktask_entry_to_timesheetline_entry.yml index c62c5584516..38cadc97017 100644 --- a/addons/project_timesheet/test/worktask_entry_to_timesheetline_entry.yml +++ b/addons/project_timesheet/test/worktask_entry_to_timesheetline_entry.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: HR Manager login: hr - password: hr groups_id: - base.group_hr_manager - diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 2d385a96103..9ae4cad20e3 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -863,6 +863,7 @@ class purchase_order(osv.osv): } picking_id = self.pool.get('stock.picking').create(cr, uid, picking_vals, context=context) self._create_stock_moves(cr, uid, order, order.order_line, picking_id, context=context) + return picking_id def picking_done(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'shipped':1,'state':'approved'}, context=context) @@ -1704,7 +1705,8 @@ class account_invoice(osv.Model): not all(picking.invoice_state in ['invoiced'] for picking in order.picking_ids)): shipped = False for po_line in order.order_line: - if all(line.invoice_id.state not in ['draft', 'cancel'] for line in po_line.invoice_lines): + if (po_line.invoice_lines and + all(line.invoice_id.state not in ['draft', 'cancel'] for line in po_line.invoice_lines)): invoiced.append(po_line.id) if invoiced and shipped: self.pool['purchase.order.line'].write(cr, user_id, invoiced, {'invoiced': True}) diff --git a/addons/purchase/stock.py b/addons/purchase/stock.py index e1d966e770a..d7906c83f3b 100644 --- a/addons/purchase/stock.py +++ b/addons/purchase/stock.py @@ -94,9 +94,12 @@ class stock_move(osv.osv): return invoice_line_id def _get_master_data(self, cr, uid, move, company, context=None): - if context.get('inv_type') in ('in_invoice', 'in_refund') and move.purchase_line_id: + if context.get('inv_type') == 'in_invoice' and move.purchase_line_id: purchase_order = move.purchase_line_id.order_id return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id + if context.get('inv_type') == 'in_refund' and move.origin_returned_move_id.purchase_line_id: + purchase_order = move.origin_returned_move_id.purchase_line_id.order_id + return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id elif context.get('inv_type') in ('in_invoice', 'in_refund') and move.picking_id: # In case of an extra move, it is better to use the data from the original moves for purchase_move in move.picking_id.move_lines: @@ -114,10 +117,14 @@ class stock_move(osv.osv): def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None): res = super(stock_move, self)._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context) - if inv_type in ('in_invoice', 'in_refund') and move.purchase_line_id: + if inv_type == 'in_invoice' and move.purchase_line_id: purchase_line = move.purchase_line_id res['invoice_line_tax_id'] = [(6, 0, [x.id for x in purchase_line.taxes_id])] res['price_unit'] = purchase_line.price_unit + elif inv_type == 'in_refund' and move.origin_returned_move_id.purchase_line_id: + purchase_line = move.origin_returned_move_id.purchase_line_id + res['invoice_line_tax_id'] = [(6, 0, [x.id for x in purchase_line.taxes_id])] + res['price_unit'] = purchase_line.price_unit return res def _get_moves_taxes(self, cr, uid, moves, inv_type, context=None): diff --git a/addons/purchase/test/ui/purchase_users.yml b/addons/purchase/test/ui/purchase_users.yml index e15998589d0..872af41a6d8 100644 --- a/addons/purchase/test/ui/purchase_users.yml +++ b/addons/purchase/test/ui/purchase_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Purchase Manager login: pm - password: pm email: purchasemanager@yourcompany.com - I added groups for Purchase manager. @@ -20,7 +19,6 @@ company_id: base.main_company name: Purchase User login: pu - password: pu email: purchaseuser@yourcompany.com - I added groups for Purchase user. diff --git a/addons/purchase_requisition/test/purchase_requisition_users.yml b/addons/purchase_requisition/test/purchase_requisition_users.yml index 4e66d70a25c..61f9c0952cb 100644 --- a/addons/purchase_requisition/test/purchase_requisition_users.yml +++ b/addons/purchase_requisition/test/purchase_requisition_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Purchase requisition Manager login: prm - password: prm email: requisition_manager@yourcompany.com - I added groups for Purchase Requisition Manager. @@ -20,11 +19,10 @@ company_id: base.main_company name: Purchase requisition User login: pru - password: pru email: requisition_user@yourcompany.com - I added groups for Purchase Requisition User. - !record {model: res.users, id: res_users_purchase_requisition_user}: groups_id: - - purchase_requisition.group_purchase_requisition_user \ No newline at end of file + - purchase_requisition.group_purchase_requisition_user diff --git a/addons/report/views/layouts.xml b/addons/report/views/layouts.xml index 37d93226e7f..2ca22e1b951 100644 --- a/addons/report/views/layouts.xml +++ b/addons/report/views/layouts.xml @@ -40,6 +40,9 @@ .table-condensed > thead > tr > th { border-bottom: 1px solid black !important; } + .table-condensed > tbody > tr { + page-break-inside: avoid !important; + } .zero_min_height { min-height: 0px !important; } diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 6181ad2c9fa..1de3281091a 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -40,7 +40,7 @@ class sale_order(osv.osv): _description = "Sales Order" _track = { 'state': { - 'sale.mt_order_confirmed': lambda self, cr, uid, obj, ctx=None: obj.state in ['manual'], + 'sale.mt_order_confirmed': lambda self, cr, uid, obj, ctx=None: obj.state in ['manual', 'progress'], 'sale.mt_order_sent': lambda self, cr, uid, obj, ctx=None: obj.state in ['sent'] }, } diff --git a/addons/sale/test/create_sale_users.yml b/addons/sale/test/create_sale_users.yml index 165fc2130c5..0035b7675df 100644 --- a/addons/sale/test/create_sale_users.yml +++ b/addons/sale/test/create_sale_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Sales manager login: sm - password: sm email: salesmanager@yourcompany.com - I added groups for Salesmanager. @@ -20,7 +19,6 @@ company_id: base.main_company name: Salesman login: su - password: su email: salesman@yourcompany.com - I added groups for Salesman. diff --git a/addons/sale_stock/test/sale_order_onchange.yml b/addons/sale_stock/test/sale_order_onchange.yml index f01b8ba0bf6..dcf60a240ea 100644 --- a/addons/sale_stock/test/sale_order_onchange.yml +++ b/addons/sale_stock/test/sale_order_onchange.yml @@ -9,6 +9,7 @@ !record {model: product.product, id: product_onchange1}: name: 'Devil Worship Book' list_price: 66.6 + default_code: 'DWB00001' - In sale order to test process of onchange of Sale Order with access rights of saleman. - @@ -28,5 +29,5 @@ !python {model: sale.order}: | from openerp.tools import float_compare order_line = self.browse(cr, uid, ref('sale_order_onchange1')).order_line - assert order_line[0].name == u'Devil Worship Book', "The onchange function of product was not correctly triggered" + assert order_line[0].name == u'[DWB00001] Devil Worship Book', "The onchange function of product was not correctly triggered" assert float_compare(order_line[0].price_unit, 66.6, precision_digits=2) == 0, "The onchange function of product was not correctly triggered" diff --git a/addons/sale_stock/test/sale_stock_users.yml b/addons/sale_stock/test/sale_stock_users.yml index 04152b43c9a..559929632c9 100644 --- a/addons/sale_stock/test/sale_stock_users.yml +++ b/addons/sale_stock/test/sale_stock_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Stock Sales manager login: ssm - password: ssm email: ss_salesmanager@yourcompany.com - I added groups for Salesmanager. @@ -20,7 +19,6 @@ company_id: base.main_company name: Stock Salesman login: ssu - password: ssu email: ss_salesman@yourcompany.com - I added groups for Stock Salesman. @@ -36,7 +34,6 @@ company_id: base.main_company name: Stock User login: sau - password: sau email: stock_user@yourcompany.com - I added groups for Stock User. @@ -51,8 +48,6 @@ company_id: base.main_company name: Stock Manager login: sam - password: sam - email: admin@portal.example.com email: stock_manager@yourcompany.com - I added groups for Stock Manager. diff --git a/addons/stock/res_config.py b/addons/stock/res_config.py index 5f8af18d5ef..b58699dfed8 100644 --- a/addons/stock/res_config.py +++ b/addons/stock/res_config.py @@ -82,10 +82,10 @@ This installs the module product_expiry."""), 'group_uom': fields.boolean("Manage different units of measure for products", implied_group='product.group_uom', help="""Allows you to select and maintain different units of measure for products."""), - 'group_uos': fields.boolean("Invoice products in a different unit of measure than the sales order", + 'group_uos': fields.boolean("Store products in a different unit of measure than the sales order", implied_group='product.group_uos', - help='Allows you to sell units of a product, but invoice based on a different unit of measure.\n' - 'For instance, you can sell pieces of meat that you invoice based on their weight.'), + help='Allows you to store units of a product, but sell and invoice based on a different unit of measure.\n' + 'For instance, you can store pieces of meat that you sell and invoice based on their weight.'), 'group_stock_packaging': fields.boolean("Allow to define several packaging methods on products", implied_group='product.group_stock_packaging', help="""Allows you to create and manage your packaging dimensions and types you want to be maintained in your system."""), diff --git a/addons/stock/stock.py b/addons/stock/stock.py index f5e10c45d0d..f1dae99d7f1 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -759,6 +759,13 @@ class stock_picking(osv.osv): res.add(move.picking_id.id) return list(res) + def _get_pickings_dates_priority(self, cr, uid, ids, context=None): + res = set() + for move in self.browse(cr, uid, ids, context=context): + if move.picking_id and (not (move.picking_id.min_date < move.date_expected < move.picking_id.max_date) or move.priority > move.picking_id.priority): + res.add(move.picking_id.id) + return list(res) + def _get_pack_operation_exist(self, cr, uid, ids, field_name, arg, context=None): res = {} for pick in self.browse(cr, uid, ids, context=context): @@ -819,12 +826,12 @@ class stock_picking(osv.osv): * Cancelled: has been cancelled, can't be confirmed anymore""" ), 'priority': fields.function(get_min_max_date, multi="min_max_date", fnct_inv=_set_priority, type='selection', selection=procurement.PROCUREMENT_PRIORITIES, string='Priority', - store={'stock.move': (_get_pickings, ['priority', 'picking_id'], 20)}, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, select=1, help="Priority for this picking. Setting manually a value here would set it as priority for all the moves", + store={'stock.move': (_get_pickings_dates_priority, ['priority', 'picking_id'], 20)}, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, select=1, help="Priority for this picking. Setting manually a value here would set it as priority for all the moves", track_visibility='onchange', required=True), 'min_date': fields.function(get_min_max_date, multi="min_max_date", fnct_inv=_set_min_date, - store={'stock.move': (_get_pickings, ['date_expected', 'picking_id'], 20)}, type='datetime', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, string='Scheduled Date', select=1, help="Scheduled time for the first part of the shipment to be processed. Setting manually a value here would set it as expected date for all the stock moves.", track_visibility='onchange'), + store={'stock.move': (_get_pickings_dates_priority, ['date_expected', 'picking_id'], 20)}, type='datetime', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, string='Scheduled Date', select=1, help="Scheduled time for the first part of the shipment to be processed. Setting manually a value here would set it as expected date for all the stock moves.", track_visibility='onchange'), 'max_date': fields.function(get_min_max_date, multi="min_max_date", - store={'stock.move': (_get_pickings, ['date_expected', 'picking_id'], 20)}, type='datetime', string='Max. Expected Date', select=2, help="Scheduled time for the last part of the shipment to be processed"), + store={'stock.move': (_get_pickings_dates_priority, ['date_expected', 'picking_id'], 20)}, type='datetime', string='Max. Expected Date', select=2, help="Scheduled time for the last part of the shipment to be processed"), 'date': fields.datetime('Creation Date', help="Creation Date, usually the time of the order", select=True, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, track_visibility='onchange'), 'date_done': fields.datetime('Date of Transfer', help="Date of Completion", states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, copy=False), 'move_lines': fields.one2many('stock.move', 'picking_id', 'Internal Moves', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, copy=True), @@ -1800,7 +1807,9 @@ class stock_move(osv.osv): 'date': fields.datetime('Date', required=True, select=True, help="Move date: scheduled date until move is done, then date of actual move processing", states={'done': [('readonly', True)]}), 'date_expected': fields.datetime('Expected Date', states={'done': [('readonly', True)]}, required=True, select=True, help="Scheduled date for the processing of this move"), 'product_id': fields.many2one('product.product', 'Product', required=True, select=True, domain=[('type', '<>', 'service')], states={'done': [('readonly', True)]}), - 'product_qty': fields.function(_quantity_normalize, fnct_inv=_set_product_qty, type='float', digits=0, store=True, string='Quantity', + 'product_qty': fields.function(_quantity_normalize, fnct_inv=_set_product_qty, type='float', digits=0, store={ + _name: (lambda self, cr, uid, ids, c={}: ids, ['product_id', 'product_uom', 'product_uom_qty'], 10), + }, string='Quantity', help='Quantity in the default UoM of the product'), 'product_uom_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True, states={'done': [('readonly', True)]}, diff --git a/addons/stock/test/stock_users.yml b/addons/stock/test/stock_users.yml index 0dbb576c115..6bd8f3ebbd5 100644 --- a/addons/stock/test/stock_users.yml +++ b/addons/stock/test/stock_users.yml @@ -5,7 +5,6 @@ company_id: base.main_company name: Stock Manager login: sam - password: sam email: stockmanager@yourcompany.com - I added groups for Stock Manager. @@ -20,7 +19,6 @@ company_id: base.main_company name: Stock User login: sau - password: sau email: stockuser@yourcompany.com - I added groups for Stock User. diff --git a/addons/stock_account/stock.py b/addons/stock_account/stock.py index 4a7372a6302..1b12d4d95b4 100644 --- a/addons/stock_account/stock.py +++ b/addons/stock_account/stock.py @@ -200,7 +200,7 @@ class stock_picking(osv.osv): def __get_picking_move(self, cr, uid, ids, context={}): res = [] for move in self.pool.get('stock.move').browse(cr, uid, ids, context=context): - if move.picking_id: + if move.picking_id and move.invoice_state != move.picking_id.invoice_state: res.append(move.picking_id.id) return res diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 82edbc2f35b..c5cd6a87ab5 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -753,7 +753,7 @@ instance.web.DataSetStatic = instance.web.DataSet.extend({ var offset = options.offset || 0, limit = options.limit || false; var end_pos = limit && limit !== -1 ? offset + limit : this.ids.length; - return this.read_ids(this.ids.slice(offset, end_pos), fields); + return this.read_ids(this.ids.slice(offset, end_pos), fields, options); }, set_ids: function (ids) { this.ids = ids; diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 3a09c1af899..81acc466df8 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -4383,8 +4383,12 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({ }); instance.web.form.One2ManyDataSet = instance.web.BufferedDataSet.extend({ - get_context: function() { + get_context: function(extra_context) { this.context = this.o2m.build_context(); + if(extra_context) + { + this.context.add(extra_context); + } return this.context; } }); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 31826d69673..ed5e32e4fa9 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -2312,7 +2312,7 @@ instance.web.list.Binary = instance.web.list.Column.extend({ * @private */ _format: function (row_data, options) { - var text = _t("Download"); + var text = _t("Download"), filename=_t('Binary file'); var value = row_data[this.id].value; if (!value) { return options.value_if_empty || ''; @@ -2330,11 +2330,13 @@ instance.web.list.Binary = instance.web.list.Column.extend({ if (this.filename && row_data[this.filename]) { text = _.str.sprintf(_t("Download \"%s\""), instance.web.format_value( row_data[this.filename].value, {type: 'char'})); + filename = row_data[this.filename].value; } - return _.template('<%-text%> (<%-size%>)')({ + return _.template('<%-text%> (<%-size%>)')({ text: text, href: download_url, size: instance.web.binary_to_binsize(value), + download: filename, }); } }); diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 54061771cf6..80075748d31 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -933,17 +933,18 @@ class website_sale(http.Controller): for line in order_lines: ret.append({ 'id': line.order_id and line.order_id.id, - 'name': line.product_id.categ_id and line.product_id.categ_id.name or '-', 'sku': line.product_id.id, - 'quantity': line.product_uom_qty, + 'name': line.product_id.name or '-', + 'category': line.product_id.categ_id and line.product_id.categ_id.name or '-', 'price': line.price_unit, + 'quantity': line.product_uom_qty, }) return ret @http.route(['/shop/tracking_last_order'], type='json', auth="public") def tracking_cart(self, **post): """ return data about order in JSON needed for google analytics""" - cr, uid, context = request.cr, request.uid, request.context + cr, context = request.cr, request.context ret = {} sale_order_id = request.session.get('sale_last_order_id') if sale_order_id: diff --git a/doc/cla/corporate/delta-comm.md b/doc/cla/corporate/delta-comm.md new file mode 100644 index 00000000000..c2559561b3f --- /dev/null +++ b/doc/cla/corporate/delta-comm.md @@ -0,0 +1,16 @@ +Georgia, 2015-06-30 + +Delta Comm LLC agrees to the terms of the Odoo Corporate Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Karlo Matitaishvili kmatitaishvili@delta-comm.ge https://github.com/kmatitaishvili + +List of contributors: + +Temur Vibliani tvibliani@delta-comm.ge https://github.com/tvibliani +Mikheil Tutberidze mtutberidze@delta-comm.ge https://github.com/mtutberidze diff --git a/doc/cla/corporate/meta-it.md b/doc/cla/corporate/meta-it.md new file mode 100644 index 00000000000..01b33f35c8b --- /dev/null +++ b/doc/cla/corporate/meta-it.md @@ -0,0 +1,15 @@ +France, 2015 June 25 + +META-IT agrees to the terms of the Odoo Corporate Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Robin Lucbenet robin@meta-it.fr https://github.com/n1b0r + +List of contributors: + +Guillaume Masson guillaume.masson@meta-it.fr diff --git a/doc/cla/corporate/oerp.md b/doc/cla/corporate/oerp.md new file mode 100644 index 00000000000..e5b98c428d4 --- /dev/null +++ b/doc/cla/corporate/oerp.md @@ -0,0 +1,15 @@ +Canada, 25-06-2015 + +OERP Canada agrees to the terms of the Odoo Corporate Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Daniel Dico ddico@oerp.ca https://github.com/ddico + +List of contributors: + +Daniel Dico ddico@oerp.ca https://github.com/ddico diff --git a/doc/cla/corporate/uktech.md b/doc/cla/corporate/uktech.md new file mode 100644 index 00000000000..74e889199be --- /dev/null +++ b/doc/cla/corporate/uktech.md @@ -0,0 +1,13 @@ +Brazil, 2015-06-25 + +Uhlig & Korovsky Tecnologia Ltda - ME agrees to the terms of the Odoo Corporate Contributor License Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this declaration. + +Signed, + +Carlos Alberto Cipriano Korovsky contato@uktech.com.br https://github.com/uktechbr + +List of contributors: + +Carlos Alberto Cipriano Korovsky carlos.korovsky@uktech.com.br https://github.com/carlos-korovsky \ No newline at end of file diff --git a/doc/cla/corporate/via_laurea.md b/doc/cla/corporate/via_laurea.md new file mode 100644 index 00000000000..66986aeaa6e --- /dev/null +++ b/doc/cla/corporate/via_laurea.md @@ -0,0 +1,13 @@ +Lithuania, 2015-06-29 + +Via laurea agrees to the terms of the Odoo Corporate Contributor License Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this declaration. + +Signed, + +Saulius Zilys saulius@vialaurea.lt https://github.com/realsaiko + +List of contributors: + +Saulius Zilys saulius@vialaurea.lt https://github.com/realsaiko diff --git a/doc/cla/individual/Ichag.md b/doc/cla/individual/Ichag.md new file mode 100644 index 00000000000..e0223a84468 --- /dev/null +++ b/doc/cla/individual/Ichag.md @@ -0,0 +1,11 @@ +Germany, 2015-06-12 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Max Hellwig max.hellwig@datenbetrieb.de https://github.com/Ichag diff --git a/doc/cla/individual/bevanweiss.md b/doc/cla/individual/bevanweiss.md new file mode 100644 index 00000000000..a0bc3b6a062 --- /dev/null +++ b/doc/cla/individual/bevanweiss.md @@ -0,0 +1,11 @@ +Australia, 17 May 2015 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Bevan Weiss bevan.weiss@gmail.com https://github.com/bevanweiss diff --git a/doc/cla/individual/endika.md b/doc/cla/individual/endika.md new file mode 100644 index 00000000000..ea288d95748 --- /dev/null +++ b/doc/cla/individual/endika.md @@ -0,0 +1,11 @@ +Spain, 2015-06-24 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Endika Iglesias endika2@gmail.com https://github.com/endika diff --git a/doc/cla/individual/flotho.md b/doc/cla/individual/flotho.md new file mode 100644 index 00000000000..4bd1f64bbfe --- /dev/null +++ b/doc/cla/individual/flotho.md @@ -0,0 +1,11 @@ +France, 2015-06-29 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Florent THOMAS florent.thomas@mind-and-go.com https://github.com/flotho diff --git a/doc/cla/individual/ludwiktrammer.md b/doc/cla/individual/ludwiktrammer.md new file mode 100644 index 00000000000..3e5a2548f49 --- /dev/null +++ b/doc/cla/individual/ludwiktrammer.md @@ -0,0 +1,11 @@ +Poland, 2015-05-25 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Ludwik Trammer ludwik@gmail.com https://github.com/ludwiktrammer \ No newline at end of file diff --git a/doc/cla/individual/nicobustillos.md b/doc/cla/individual/nicobustillos.md index 5e460b51c51..aac29668a5d 100644 --- a/doc/cla/individual/nicobustillos.md +++ b/doc/cla/individual/nicobustillos.md @@ -8,4 +8,4 @@ declaration. Signed, -Nicolas Bustillos nicolas.bustillos@poiesisconsulting.com https://github.com/nicobustillos +Nicolas Bustillos nicobustillos@users.noreply.github.com https://github.com/nicobustillos diff --git a/doc/cla/individual/npiganeau.md b/doc/cla/individual/npiganeau.md index 4cd08fcb99c..a01f87403d2 100644 --- a/doc/cla/individual/npiganeau.md +++ b/doc/cla/individual/npiganeau.md @@ -8,4 +8,4 @@ declaration. Signed, -Nicolas Piganeau nicolas.piganeau@ndp-systemes.fr https://github.com/npiganeau \ No newline at end of file +Nicolas Piganeau npi@m4x.org https://github.com/npiganeau \ No newline at end of file diff --git a/doc/cla/individual/vuamitom.md b/doc/cla/individual/vuamitom.md new file mode 100644 index 00000000000..efd28eeedf3 --- /dev/null +++ b/doc/cla/individual/vuamitom.md @@ -0,0 +1,11 @@ +Vietnam, 2015-05-27 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Tam Vu vumhtam@gmail.com https://github.com/vuamitom diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index c06cfb83659..9da68a171be 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -266,7 +266,7 @@ class view(osv.osv): # Sanity checks: the view should not break anything upon rendering! # Any exception raised below will cause a transaction rollback. for view in self.browse(cr, uid, ids, context): - view_def = self.read_combined(cr, uid, view.id, None, context=context) + view_def = self.read_combined(cr, uid, view.id, ['arch'], context=context) view_arch_utf8 = view_def['arch'] if view.type != 'qweb': view_doc = etree.fromstring(view_arch_utf8) @@ -595,7 +595,7 @@ class view(osv.osv): # arch and model fields are always returned if fields: - fields = list(set(fields) | set(['arch', 'model'])) + fields = list({'arch', 'model'}.union(fields)) # read the view arch [view] = self.read(cr, uid, [root_id], fields=fields, context=context) diff --git a/openerp/addons/base/res/res_country_data.xml b/openerp/addons/base/res/res_country_data.xml index affa93f5329..c9ef761d282 100644 --- a/openerp/addons/base/res/res_country_data.xml +++ b/openerp/addons/base/res/res_country_data.xml @@ -428,6 +428,7 @@ Finland fi + diff --git a/openerp/cli/start.py b/openerp/cli/start.py index d23bca8b8d5..b0cc932e19d 100644 --- a/openerp/cli/start.py +++ b/openerp/cli/start.py @@ -61,6 +61,13 @@ class Start(Command): if '--db-filter' not in cmdargs: cmdargs.append('--db-filter=^%s$' % args.db_name) + # Remove --path /-p options from the command arguments + def to_remove(i, l): + return l[i] == '-p' or l[i].startswith('--path') or \ + (i > 0 and l[i-1] in ['-p', '--path']) + cmdargs = [v for i, v in enumerate(cmdargs) + if not to_remove(i, cmdargs)] + main(cmdargs) def die(message, code=1): diff --git a/openerp/models.py b/openerp/models.py index 104fb404db8..aaf692b6e5e 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -1194,8 +1194,11 @@ class BaseModel(object): type = 'warning' if isinstance(exception, Warning) else 'error' # logs the logical (not human-readable) field name for automated # processing of response, but injects human readable in message - record = dict(base, type=type, field=field, - message=unicode(exception.args[0]) % base) + # Before applying string substitution, we need to escape all '%' + # characters that are not part of substitutable reference. + regex = '%%(?!\((%s)\)s)' % '|'.join(base.keys()) + message = unicode(re.sub(regex, '%%', exception.args[0])) % base + record = dict(base, type=type, field=field, message=message) if len(exception.args) > 1 and exception.args[1]: record.update(exception.args[1]) log(record) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 752e5a866ab..7e9ce92afd5 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1591,6 +1591,8 @@ class sparse(function): """ if self._type == 'many2many': + if not value: + return [] assert value[0][0] == 6, 'Unsupported m2m value for sparse field: %s' % value return value[0][2] diff --git a/openerp/tools/image.py b/openerp/tools/image.py index f860ab4d547..f2933f4e405 100644 --- a/openerp/tools/image.py +++ b/openerp/tools/image.py @@ -129,16 +129,14 @@ def image_save_for_web(image, fp=None, format=None): opt = dict(format=image.format or format) if image.format == 'PNG': opt.update(optimize=True) + alpha = False + if image.mode in ('RGBA', 'LA') or (image.mode == 'P' and 'transparency' in image.info): + alpha = image.convert('RGBA').split()[-1] if image.mode != 'P': - # Get the alpha band - alpha = image.split()[-1] # Floyd Steinberg dithering by default image = image.convert('RGBA').convert('P', palette=Image.WEB, colors=256) - # Set all pixel values below 128 to 255 and the rest to 0 - mask = Image.eval(alpha, lambda a: 255 if a <=128 else 0) - # Paste the color of index 255 and use alpha as a mask - image.paste(255, mask) - opt.update(transparency=255) + if alpha: + image.putalpha(alpha) elif image.format == 'JPEG': opt.update(optimize=True, quality=80) if fp: diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index 13b5d1ec7f9..c3cd1a27602 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -316,10 +316,10 @@ class YamlInterpreter(object): if not self._coerce_bool(record.forcecreate): return None - #context = self.get_context(record, self.eval_context) - #TOFIX: record.context like {'withoutemployee':True} should pass from self.eval_context. example: test_project.yml in project module - context = record.context + # FIXME: record.context like {'withoutemployee':True} should pass from self.eval_context. example: test_project.yml in project module + # TODO: cleaner way to avoid resetting password in auth_signup (makes user creation costly) + context = dict(record.context or {}, no_reset_password=True) view_info = False if view_id: varg = view_id