From 31ad2aa31ea663ce957adc6ab8b55a64d66e8f1f Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Tue, 27 Feb 2018 18:35:38 -0800 Subject: [PATCH 1/2] [FIX] crm: avoid timezone date change to mess with dashboard stats Have your OS be in Vancouver with time = 15:59:00 We are on day X Have a next activity on a lead, scheduled for today At 15:59:00 the next activity is not overdue Before this commit: Past 16:00:00 the next activity becomes overdue This is because 16:00:00 is 00:00:00 in UTC (+8 hours) And the next activity is scheduled for day X But in UTC, we just passed at day X+1 Hence, the next activity being overdue After this commit: The next activity is not overdue, since we are actually on day X OPW 1815323 --- addons/crm/crm_lead.py | 33 ++++++++++++------- .../crm/static/src/js/sales_team_dashboard.js | 2 +- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 465ab6540eb..2f996e00579 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +import pytz from datetime import datetime, timedelta, date from dateutil.relativedelta import relativedelta import logging @@ -1105,6 +1106,14 @@ Update your business card, phone book, social media,... Send an email right now return res def retrieve_sales_dashboard(self, cr, uid, context=None): + date_today = date.today() + # We imitate here what the JS search does in the user's browser: + # retrieve the user's local date + if context and context.get('tz'): + user_tz = pytz.timezone(context['tz']) + now_utc = pytz.utc.localize(datetime.now()) + now_user_tz = now_utc.astimezone(user_tz) + date_today = date(now_user_tz.year, now_user_tz.month, now_user_tz.day) res = { 'meeting': { @@ -1143,32 +1152,32 @@ Update your business card, phone book, social media,... Send an email right now if opp['date_deadline']: date_deadline = datetime.strptime(opp['date_deadline'], tools.DEFAULT_SERVER_DATE_FORMAT).date() - if date_deadline == date.today(): + if date_deadline == date_today: res['closing']['today'] += 1 - if date_deadline >= date.today() and date_deadline <= date.today() + timedelta(days=7): + if date_deadline >= date_today and date_deadline <= date_today + timedelta(days=7): res['closing']['next_7_days'] += 1 - if date_deadline < date.today() and not opp['date_closed']: + if date_deadline < date_today and not opp['date_closed']: res['closing']['overdue'] += 1 # Next activities if opp['next_activity_id'] and opp['date_action']: date_action = datetime.strptime(opp['date_action'], tools.DEFAULT_SERVER_DATE_FORMAT).date() - if date_action == date.today(): + if date_action == date_today: res['activity']['today'] += 1 - if date_action >= date.today() and date_action <= date.today() + timedelta(days=7): + if date_action >= date_today and date_action <= date_today + timedelta(days=7): res['activity']['next_7_days'] += 1 - if date_action < date.today() and not opp['date_closed']: + if date_action < date_today and not opp['date_closed']: res['activity']['overdue'] += 1 # Won in Opportunities if opp['date_closed']: date_closed = datetime.strptime(opp['date_closed'], tools.DEFAULT_SERVER_DATETIME_FORMAT).date() - if date_closed <= date.today() and date_closed >= date.today().replace(day=1): + if date_closed <= date_today and date_closed >= date_today.replace(day=1): if opp['planned_revenue']: res['won']['this_month'] += opp['planned_revenue'] - elif date_closed < date.today().replace(day=1) and date_closed >= date.today().replace(day=1) - relativedelta(months=+1): + elif date_closed < date_today.replace(day=1) and date_closed >= date_today.replace(day=1) - relativedelta(months=+1): if opp['planned_revenue']: res['won']['last_month'] += opp['planned_revenue'] @@ -1198,9 +1207,9 @@ Update your business card, phone book, social media,... Send an email right now for act in activites_done: if act['date']: date_act = datetime.strptime(act['date'], tools.DEFAULT_SERVER_DATETIME_FORMAT).date() - if date_act <= date.today() and date_act >= date.today().replace(day=1): + if date_act <= date_today and date_act >= date_today.replace(day=1): res['done']['this_month'] += 1 - elif date_act < date.today().replace(day=1) and date_act >= date.today().replace(day=1) - relativedelta(months=+1): + elif date_act < date_today.replace(day=1) and date_act >= date_today.replace(day=1) - relativedelta(months=+1): res['done']['last_month'] += 1 # Meetings @@ -1216,9 +1225,9 @@ Update your business card, phone book, social media,... Send an email right now if meeting['start']: start = datetime.strptime(meeting['start'], tools.DEFAULT_SERVER_DATETIME_FORMAT).date() - if start == date.today(): + if start == date_today: res['meeting']['today'] += 1 - if start >= date.today() and start <= date.today() + timedelta(days=7): + if start >= date_today and start <= date_today + timedelta(days=7): res['meeting']['next_7_days'] += 1 res['nb_opportunities'] = len(opportunities) diff --git a/addons/crm/static/src/js/sales_team_dashboard.js b/addons/crm/static/src/js/sales_team_dashboard.js index b2bec86a753..2f1df97bbb1 100644 --- a/addons/crm/static/src/js/sales_team_dashboard.js +++ b/addons/crm/static/src/js/sales_team_dashboard.js @@ -8,7 +8,7 @@ SalesTeamDashboardView.include({ fetch_data: function() { return new Model('crm.lead') - .call('retrieve_sales_dashboard', []); + .call('retrieve_sales_dashboard', [], {context: this.session.user_context || {}}); } }); From 4aea19d9e81a65ffefa9c770622b7772d071b781 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 6 Mar 2018 11:23:46 +0100 Subject: [PATCH 2/2] [FIX] sale_crm,crm: handle timezone in dashboard Complete parent commit by correcting overwritten method. Also use existing method to retrive date depending on tz in context. --- addons/crm/crm_lead.py | 15 +++------------ addons/sale_crm/crm_lead.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 2f996e00579..bdc01a8781b 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -1,15 +1,13 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import pytz -from datetime import datetime, timedelta, date +from datetime import datetime, timedelta from dateutil.relativedelta import relativedelta import logging from operator import itemgetter -from werkzeug import url_encode from openerp import SUPERUSER_ID -from openerp import tools, api +from openerp import tools, api, fields as newfields from openerp.addons.base.res.res_partner import format_address from openerp.addons.crm import crm_stage from openerp.osv import fields, osv @@ -1106,14 +1104,7 @@ Update your business card, phone book, social media,... Send an email right now return res def retrieve_sales_dashboard(self, cr, uid, context=None): - date_today = date.today() - # We imitate here what the JS search does in the user's browser: - # retrieve the user's local date - if context and context.get('tz'): - user_tz = pytz.timezone(context['tz']) - now_utc = pytz.utc.localize(datetime.now()) - now_user_tz = now_utc.astimezone(user_tz) - date_today = date(now_user_tz.year, now_user_tz.month, now_user_tz.day) + date_today = newfields.Date.from_string(fields.date.context_today(self, cr, uid, context=context)) res = { 'meeting': { diff --git a/addons/sale_crm/crm_lead.py b/addons/sale_crm/crm_lead.py index 77c05f1be2b..d8fd0493960 100644 --- a/addons/sale_crm/crm_lead.py +++ b/addons/sale_crm/crm_lead.py @@ -1,8 +1,8 @@ -from openerp import models, fields, api, _, tools -from datetime import datetime, date +from openerp import models, fields, api, tools +from openerp.osv import fields as oldfields +from datetime import datetime from dateutil.relativedelta import relativedelta -import openerp.addons.decimal_precision as dp class crm_lead(models.Model): _inherit = ['crm.lead'] @@ -28,6 +28,8 @@ class crm_lead(models.Model): def retrieve_sales_dashboard(self, cr, uid, context=None): res = super(crm_lead, self).retrieve_sales_dashboard(cr, uid, context=None) + today = fields.Date.from_string(oldfields.date.context_today(self, cr, uid, context=context)) + res['invoiced'] = { 'this_month': 0, 'last_month': 0, @@ -35,7 +37,7 @@ class crm_lead(models.Model): account_invoice_domain = [ ('state', 'in', ['open', 'paid']), ('user_id', '=', uid), - ('date', '>=', date.today().replace(day=1) - relativedelta(months=+1)), + ('date', '>=', today.replace(day=1) - relativedelta(months=+1)), ('type', 'in', ['out_invoice', 'out_refund']) ] @@ -43,9 +45,9 @@ class crm_lead(models.Model): for inv in invoice_ids: if inv['date']: inv_date = datetime.strptime(inv['date'], tools.DEFAULT_SERVER_DATE_FORMAT).date() - if inv_date <= date.today() and inv_date >= date.today().replace(day=1): + if inv_date <= today and inv_date >= today.replace(day=1): res['invoiced']['this_month'] += inv['amount_untaxed_signed'] - elif inv_date < date.today().replace(day=1) and inv_date >= date.today().replace(day=1) - relativedelta(months=+1): + elif inv_date < today.replace(day=1) and inv_date >= today.replace(day=1) - relativedelta(months=+1): res['invoiced']['last_month'] += inv['amount_untaxed_signed'] res['invoiced']['target'] = self.pool('res.users').browse(cr, uid, uid, context=context).target_sales_invoiced