From e5c5b1cc23f3f95af9b2dd056f21ab0dfbd63fd8 Mon Sep 17 00:00:00 2001 From: Commandant Custo Date: Fri, 28 Aug 2015 10:36:25 +0200 Subject: [PATCH 1/6] [FIX] portal_sale: fix default domains Quotations/Sales orders menu in the portal must copy the behavior of the menus in the regular back-end. closes #8271 opw:648186 --- addons/portal_sale/portal_sale_view.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/portal_sale/portal_sale_view.xml b/addons/portal_sale/portal_sale_view.xml index 1dd8db4e51c..b9b18507389 100644 --- a/addons/portal_sale/portal_sale_view.xml +++ b/addons/portal_sale/portal_sale_view.xml @@ -54,7 +54,8 @@ ir.actions.act_window sale.order tree,form - {"search_default_draft":1} + [('state','in',('draft','sent','cancel'))] + {} We haven't sent you any quotation. @@ -65,7 +66,8 @@ sale.order tree,form - {"search_default_sales":1} + [('state', 'not in', ('draft', 'sent', 'cancel'))] + {} We haven't sent you any sales order. From fdd08a8b4bf0484f728459195128f097097690f5 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 1 Sep 2015 11:31:08 +0200 Subject: [PATCH 2/6] [FIX] account: closed period in test The period used to make the test must be closed. --- addons/account/tests/test_account_move_closed_period.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/account/tests/test_account_move_closed_period.py b/addons/account/tests/test_account_move_closed_period.py index 68ad8788476..4e88994f2d2 100644 --- a/addons/account/tests/test_account_move_closed_period.py +++ b/addons/account/tests/test_account_move_closed_period.py @@ -14,21 +14,21 @@ class TestPeriodState(TransactionCase): self.wizard_period_close = self.registry('account.period.close') self.wizard_period_close_id = self.wizard_period_close.create(cr, uid, {'sure': 1}) _, self.sale_journal_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account", "sales_journal") - _, self.period_9_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account", "period_9") + _, self.period_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account", "period_0") def test_period_state(self): cr, uid = self.cr, self.uid self.wizard_period_close.data_save(cr, uid, [self.wizard_period_close_id], { 'lang': 'en_US', 'active_model': 'account.period', - 'active_ids': [self.period_9_id], + 'active_ids': [self.period_id], 'tz': False, - 'active_id': self.period_9_id + 'active_id': self.period_id }) with self.assertRaises(except_orm): self.registry('account.move').create(cr, uid, { 'name': '/', - 'period_id': self.period_9_id, + 'period_id': self.period_id, 'journal_id': self.sale_journal_id, 'date': date.today(), 'line_id': [(0, 0, { From b8f630e59f9cc21390e15e1b06f0189b5716b503 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 1 Sep 2015 16:18:10 +0200 Subject: [PATCH 3/6] [FIX] stock_account: context could be None In the use case of a mrp repair ending, the context when calling `_store_average_cost_price` is None opw-648254 --- addons/stock_account/stock_account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock_account/stock_account.py b/addons/stock_account/stock_account.py index 2b12106af38..63c4a542e16 100644 --- a/addons/stock_account/stock_account.py +++ b/addons/stock_account/stock_account.py @@ -285,7 +285,7 @@ class stock_move(osv.osv): average_valuation_price += q.qty * q.cost average_valuation_price = average_valuation_price / move.product_qty # Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products - ctx = dict(context, force_company=move.company_id.id) + ctx = dict(context or {}, force_company=move.company_id.id) product_obj.write(cr, SUPERUSER_ID, [move.product_id.id], {'standard_price': average_valuation_price}, context=ctx) self.write(cr, uid, [move.id], {'price_unit': average_valuation_price}, context=context) From 1c533b193feb7629d87ab1ff740b0cbc7615812e Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 1 Sep 2015 17:03:47 +0200 Subject: [PATCH 4/6] [FIX] google_calendar: events disappearing This rev. is related to a9e3d74713b6882c64617345696ad326d75a4745 This new revision is about the same use case than above, except that both Google users login doesn't match the Odoo login email. e.g. User A: A@agrolait.com in Odoo, A@gmail.com in Google User B: B@agrolait.com in Odoo, B@gmail.com in Google. When A creates an event, with B in the attendees, and syncs his calendar to Google, B is not automatically invited Google side, as his attendee email is B@agrolait.com, which doesn't match any existing Google User (doesn't match B@gmail.com) While the revision mentioned above, a9e3d74713b6882c64617345696ad326d75a4745, expected the attendee to be automatically invited Google side, and therefore expected the event to already exists in B's calendar. Therefore, when B syncs his calendar in Odoo, as the event was there in his Odoo calendar, but not in his Google Calendar, the code actually think it's no - longer - there, and take the assumption the event has been deleted Google side. So, it deletes the event in Odoo side as well, for both users A & B. To overcome this new issue, when the Google & Odoo users emails do not match, while keeping the compatibility when the Google & Odoo emails do match (and therefore the invitation is automatically sent Google side, as the email matches an existing Google account, and the event is automatically created in B's calendar without needing the sync in Odoo), we now force the Google internal id to be the same for all attendees of an event, event by Google side. opw-645745 --- addons/google_calendar/google_calendar.py | 34 ++++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/addons/google_calendar/google_calendar.py b/addons/google_calendar/google_calendar.py index c60eea29cc4..72325e39c76 100644 --- a/addons/google_calendar/google_calendar.py +++ b/addons/google_calendar/google_calendar.py @@ -259,6 +259,9 @@ class google_calendar(osv.AbstractModel): if not self.get_need_synchro_attendee(cr, uid, context=context): data.pop("attendees") + other_google_ids = [other_att.google_internal_event_id for other_att in event.attendee_ids if other_att.google_internal_event_id] + if other_google_ids: + data["id"] = other_google_ids[0] return data def create_an_event(self, cr, uid, event, context=None): @@ -428,7 +431,7 @@ class google_calendar(osv.AbstractModel): if type == "write": for oe_attendee in event['attendee_ids']: if oe_attendee.email == partner_email: - calendar_attendee_obj.write(cr, uid, [oe_attendee.id], {'state': google_attendee['responseStatus'], 'google_internal_event_id': single_event_dict.get('id')}, context=context) + calendar_attendee_obj.write(cr, uid, [oe_attendee.id], {'state': google_attendee['responseStatus']}, context=context) google_attendee['found'] = True continue @@ -447,7 +450,6 @@ class google_calendar(osv.AbstractModel): partner_record.append((4, attendee.get('id'))) attendee['partner_id'] = attendee.pop('id') attendee['state'] = google_attendee['responseStatus'] - attendee['google_internal_event_id'] = single_event_dict.get('id') attendee_record.append((0, 0, attendee)) for google_alarm in single_event_dict.get('reminders', {}).get('overrides', []): alarm_id = calendar_alarm_obj.search( @@ -626,17 +628,23 @@ class google_calendar(osv.AbstractModel): ('event_id.final_date', '>', self.get_minTime(cr, uid, context=context).strftime(DEFAULT_SERVER_DATETIME_FORMAT)), ], context=context_norecurrent) for att in att_obj.browse(cr, uid, my_att_ids, context=context): - if not att.event_id.recurrent_id or att.event_id.recurrent_id == 0: - st, response, ask_time = self.create_an_event(cr, uid, att.event_id, context=context) - if status_response(st): - update_date = datetime.strptime(response['updated'], "%Y-%m-%dT%H:%M:%S.%fz") - ev_obj.write(cr, uid, att.event_id.id, {'oe_update_date': update_date}) - new_ids.append(response['id']) - att_obj.write(cr, uid, [att.id for att in att.event_id.attendee_ids], {'google_internal_event_id': response['id'], 'oe_synchro_date': update_date}) - cr.commit() - else: - _logger.warning("Impossible to create event %s. [%s]" % (att.event_id.id, st)) - _logger.warning("Response : %s" % response) + other_google_ids = [other_att.google_internal_event_id for other_att in att.event_id.attendee_ids if other_att.google_internal_event_id and other_att.id != att.id] + for other_google_id in other_google_ids: + if self.get_one_event_synchro(cr, uid, other_google_id, context=context): + att_obj.write(cr, uid, [att.id], {'google_internal_event_id': other_google_id}) + break + else: + if not att.event_id.recurrent_id or att.event_id.recurrent_id == 0: + st, response, ask_time = self.create_an_event(cr, uid, att.event_id, context=context) + if status_response(st): + update_date = datetime.strptime(response['updated'], "%Y-%m-%dT%H:%M:%S.%fz") + ev_obj.write(cr, uid, att.event_id.id, {'oe_update_date': update_date}) + new_ids.append(response['id']) + att_obj.write(cr, uid, [att.id], {'google_internal_event_id': response['id'], 'oe_synchro_date': update_date}) + cr.commit() + else: + _logger.warning("Impossible to create event %s. [%s]" % (att.event_id.id, st)) + _logger.warning("Response : %s" % response) return new_ids def get_context_no_virtual(self, context): From 3c0fe940aa5f91a4ed45cf2fa96fb11c079c5733 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 1 Sep 2015 17:36:52 +0200 Subject: [PATCH 5/6] [FIX] google_calendar: force internal id only on creation This rev. is related to 1c533b193feb7629d87ab1ff740b0cbc7615812e The reason why we force the event Google internal id is explained in the above commit. Forcing the internal id must be done only when creating the event in Google, not when updating, for retro-compatibility: if the event is already in the attendee calendar, with a different internal id then the other attendee, we must leave it like this, otherwise Google will be lost. --- addons/google_calendar/google_calendar.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/google_calendar/google_calendar.py b/addons/google_calendar/google_calendar.py index 72325e39c76..fb7dd0dfa6a 100644 --- a/addons/google_calendar/google_calendar.py +++ b/addons/google_calendar/google_calendar.py @@ -259,9 +259,10 @@ class google_calendar(osv.AbstractModel): if not self.get_need_synchro_attendee(cr, uid, context=context): data.pop("attendees") - other_google_ids = [other_att.google_internal_event_id for other_att in event.attendee_ids if other_att.google_internal_event_id] - if other_google_ids: - data["id"] = other_google_ids[0] + if isCreating: + other_google_ids = [other_att.google_internal_event_id for other_att in event.attendee_ids if other_att.google_internal_event_id] + if other_google_ids: + data["id"] = other_google_ids[0] return data def create_an_event(self, cr, uid, event, context=None): From a0d44f99528a06008749e725ee514fe31e2e2e21 Mon Sep 17 00:00:00 2001 From: Lionel Sausin Date: Thu, 30 Jul 2015 17:34:42 +0200 Subject: [PATCH 6/6] [IMP] update the expiry dates when changing the product Written in the new API even though the rest is in the old API, because otherwise we'd have to add an onchange in the views which may be a problem for existing custom modules. We want this behavior because previously, in some cases the default values were only added at create() time, ie. possibily when the users close the pop-up, so they may never have an opportunity to see and adjust the default. --- addons/product_expiry/product_expiry.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/addons/product_expiry/product_expiry.py b/addons/product_expiry/product_expiry.py index 392e574a0bb..4b52d9bf3b6 100644 --- a/addons/product_expiry/product_expiry.py +++ b/addons/product_expiry/product_expiry.py @@ -21,6 +21,7 @@ import datetime import openerp +from openerp import api, models from openerp.osv import fields, osv class stock_production_lot(osv.osv): @@ -75,6 +76,19 @@ class stock_production_lot(osv.osv): } +# Onchange added in new api to avoid having to change views +class StockProductionLot(models.Model): + _inherit = 'stock.production.lot' + + @api.onchange('product_id') + def _onchange_product(self): + defaults = self.with_context( + product_id=self.product_id.id).default_get( + ['life_date', 'use_date', 'removal_date', 'alert_date']) + for field, value in defaults.items(): + setattr(self, field, value) + + class stock_quant(osv.osv): _inherit = 'stock.quant'