def view_meeting(self, token, id, **kwargs): attendee = request.env['calendar.attendee'].sudo().search([ ('access_token', '=', token), ('event_id', '=', int(id)) ]) if not attendee: return request.not_found() timezone = attendee.partner_id.tz lang = attendee.partner_id.lang or get_lang(request.env).code event = request.env['calendar.event'].with_context( tz=timezone, lang=lang).sudo().browse(int(id)) # If user is internal and logged, redirect to form view of event # otherwise, display the simplifyed web page with event informations if request.session.uid and request.env['res.users'].browse( request.session.uid).user_has_groups('base.group_user'): return werkzeug.utils.redirect( '/web?db=%s#id=%s&view_type=form&model=calendar.event' % (request.env.cr.dbname, id)) # NOTE : we don't use request.render() since: # - we need a template rendering which is not lazy, to render before cursor closing # - we need to display the template in the language of the user (not possible with # request.render()) response_content = request.env['ir.ui.view'].with_context( lang=lang)._render_template('calendar.invitation_page_anonymous', { 'event': event, 'attendee': attendee, }) return request.make_response(response_content, headers=[('Content-Type', 'text/html')])
def nav_list(self, blog=None): dom = blog and [('blog_id', '=', blog.id)] or [] if not request.env.user.has_group('website.group_website_designer'): dom += [('post_date', '<=', fields.Datetime.now())] groups = request.env['blog.post']._read_group_raw( dom, ['name', 'post_date'], groupby=["post_date"], orderby="post_date desc") for group in groups: (r, label) = group['post_date'] start, end = r.split('/') group['post_date'] = label group['date_begin'] = start group['date_end'] = end locale = get_lang(request.env).code start = pytz.UTC.localize(fields.Datetime.from_string(start)) tzinfo = pytz.timezone(request.context.get('tz', 'utc') or 'utc') group['month'] = babel.dates.format_datetime(start, format='MMMM', tzinfo=tzinfo, locale=locale) group['year'] = babel.dates.format_datetime(start, format='yyyy', tzinfo=tzinfo, locale=locale) return OrderedDict( (year, [m for m in months]) for year, months in itertools.groupby(groups, lambda g: g['year']))
def _load(self, name, options): lang = options.get('lang', get_lang(self.env).code) env = self.env if lang != env.context.get('lang'): env = env(context=dict(env.context, lang=lang)) view_id = self.env['ir.ui.view'].get_view_id(name) template = env['ir.ui.view'].sudo()._read_template(view_id) # QWeb's `_read_template` will check if one of the first children of # what we send to it has a "t-name" attribute having `name` as value # to consider it has found it. As it'll never be the case when working # with view ids or children view or children primary views, force it here. def is_child_view(view_name): view_id = self.env['ir.ui.view'].get_view_id(view_name) view = self.env['ir.ui.view'].sudo().browse(view_id) return view.inherit_id is not None if isinstance(name, int) or is_child_view(name): view = etree.fromstring(template) for node in view: if node.get('t-name'): node.set('t-name', str(name)) return view else: return template
def action_submit_rating(self, token, **kwargs): rate = int(kwargs.get('rate')) assert rate in (1, 3, 5), "Incorrect rating" rating = request.env['helpdesk.ticket'].sudo().search([('access_token', '=', token)]) if not rating: return request.not_found() feedback = (kwargs.get('feedback')) rating.rating_last_value = float(rate) if feedback: message = plaintext2html(feedback) post_values = { 'res_model': 'helpdesk.ticket', 'res_id': rating.id, 'message': feedback, 'send_after_commit': False, 'attachment_ids': False, # will be added afterward } message = _message_post_helper(**post_values) lang = rating.partner_id.lang or get_lang(request.env).code return request.env['ir.ui.view'].with_context( lang=lang)._render_template( 'helpdesk_basic.rating_external_page_view', { 'web_base_url': request.env['ir.config_parameter'].sudo().get_param( 'web.base.url'), 'rating_value': rating, })
def _compile_directive_lang(self, el, options): lang = el.attrib.pop('t-lang', get_lang(self.env).code) if el.get('t-call-options'): el.set('t-call-options', el.get('t-call-options')[0:-1] + u', "lang": %s}' % lang) else: el.set('t-call-options', u'{"lang": %s}' % lang) return self._compile_node(el, options)
def get_formated_date(self, event): start_date = fields.Datetime.from_string(event.date_begin).date() end_date = fields.Datetime.from_string(event.date_end).date() month = babel.dates.get_month_names( 'abbreviated', locale=get_lang(event.env).code)[start_date.month] return ('%s %s%s') % (month, start_date.strftime("%e"), (end_date != start_date and ("-" + end_date.strftime("%e")) or ""))
def user_lang(self): """ user_lang() Fetches the res.lang record corresponding to the language code stored in the user's context. :returns: Model[res.lang] """ return get_lang(self.env)
def check_report(self): self.ensure_one() data = {} data['ids'] = self.env.context.get('active_ids', []) data['model'] = self.env.context.get('active_model', 'ir.ui.menu') data['form'] = self.read(['date_from', 'date_to', 'journal_ids', 'target_move', 'company_id'])[0] used_context = self._build_contexts(data) data['form']['used_context'] = dict(used_context, lang=get_lang(self.env).code) return self.with_context(discard_logo_check=True)._print_report(data)
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): if name and operator == '=' and not args: # search on the name of the pricelist and its currency, opposite of name_get(), # Used by the magic context filter in the product search view. query_args = { 'name': name, 'limit': limit, 'lang': get_lang(self.env).code } query = """SELECT p.id FROM (( SELECT pr.id, pr.name FROM product_pricelist pr JOIN res_currency cur ON (pr.currency_id = cur.id) WHERE pr.name || ' (' || cur.name || ')' = %(name)s ) UNION ( SELECT tr.res_id as id, tr.value as name FROM ir_translation tr JOIN product_pricelist pr ON ( pr.id = tr.res_id AND tr.type = 'model' AND tr.name = 'product.pricelist,name' AND tr.lang = %(lang)s ) JOIN res_currency cur ON (pr.currency_id = cur.id) WHERE tr.value || ' (' || cur.name || ')' = %(name)s ) ) p ORDER BY p.name""" if limit: query += " LIMIT %(limit)s" self._cr.execute(query, query_args) ids = [r[0] for r in self._cr.fetchall()] # regular search() to apply ACLs - may limit results below limit in some cases pricelist_ids = self._search([('id', 'in', ids)], limit=limit, access_rights_uid=name_get_uid) if pricelist_ids: return pricelist_ids return super(Pricelist, self)._name_search(name, args, operator=operator, limit=limit, name_get_uid=name_get_uid)
def get_month_filter_domain(filter_name, months_delta): first_day_of_the_month = today.replace(day=1) filter_string = _('This month') if months_delta == 0 \ else format_date(request.env, value=today + relativedelta(months=months_delta), date_format='LLLL', lang_code=get_lang(request.env).code).capitalize() return [ filter_name, filter_string, [("date_end", ">=", sd(first_day_of_the_month + relativedelta(months=months_delta))), ("date_begin", "<", sd(first_day_of_the_month + relativedelta(months=months_delta + 1)))], 0 ]
def get_interval(self, interval, tz=None): """ Format and localize some dates to be used in email templates :param string interval: Among 'day', 'month', 'dayname' and 'time' indicating the desired formatting :param string tz: Timezone indicator (optional) :return unicode: Formatted date or time (as unicode string, to prevent jinja2 crash) """ self.ensure_one() date = fields.Datetime.from_string(self.start) if tz: timezone = pytz.timezone(tz or 'UTC') date = date.replace( tzinfo=pytz.timezone('UTC')).astimezone(timezone) if interval == 'day': # Day number (1-31) result = str(date.day) elif interval == 'month': # Localized month name and year result = babel.dates.format_date(date=date, format='MMMM y', locale=get_lang(self.env).code) elif interval == 'dayname': # Localized day name result = babel.dates.format_date(date=date, format='EEEE', locale=get_lang(self.env).code) elif interval == 'time': # Localized time # FIXME: formats are specifically encoded to bytes, maybe use babel? dummy, format_time = self._get_date_formats() result = tools.ustr(date.strftime(format_time + " %Z")) return result
def _read_progress_bar(self, domain, group_by, progress_bar): """ Implementation of read_progress_bar() that returns results in the format of read_group(). """ try: fname = progress_bar['field'] return self.read_group(domain, [fname], [group_by, fname], lazy=False) except UserError: # possibly failed because of grouping on or aggregating non-stored # field; fallback on alternative implementation pass # Workaround to match read_group's infrastructure # TO DO in master: harmonize this function and readgroup to allow factorization group_by_name = group_by.partition(':')[0] group_by_modifier = group_by.partition(':')[2] or 'month' records_values = self.search_read(domain or [], [progress_bar['field'], group_by_name]) field_type = self._fields[group_by_name].type for record_values in records_values: group_by_value = record_values.pop(group_by_name) # Again, imitating what _read_group_format_result and _read_group_prepare_data do if group_by_value and field_type in ['date', 'datetime']: locale = get_lang(self.env).code group_by_value = date_utils.start_of(fields.Datetime.to_datetime(group_by_value), group_by_modifier) group_by_value = pytz.timezone('UTC').localize(group_by_value) tz_info = None if field_type == 'datetime' and self._context.get('tz') in pytz.all_timezones: tz_info = self._context.get('tz') group_by_value = babel.dates.format_datetime( group_by_value, format=DISPLAY_DATE_FORMATS[group_by_modifier], tzinfo=tz_info, locale=locale) else: group_by_value = babel.dates.format_date( group_by_value, format=DISPLAY_DATE_FORMATS[group_by_modifier], locale=locale) record_values[group_by] = group_by_value record_values['__count'] = 1 return records_values
def action_open_rating(self, token, rate, **kwargs): assert rate in (1, 3, 5), "Incorrect rating" rating = request.env['helpdesk.ticket'].sudo().search([('access_token', '=', token)]) if not rating: return request.not_found() rate_names = { 5: _("satisfied"), 3: _("not satisfied"), 1: _("highly dissatisfied") } lang = rating.partner_id.lang or get_lang(request.env).code return request.env['ir.ui.view'].with_context( lang=lang)._render_template( 'helpdesk_basic.rating_external_page_submit', { 'token': token, 'rate_names': rate_names, 'rate': rate })
def action_submit_rating(self, token, **kwargs): rate = int(kwargs.get('rate')) assert rate in (1, 3, 5), "Incorrect rating" rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)]) if not rating: return request.not_found() record_sudo = request.env[rating.res_model].sudo().browse( rating.res_id) record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback')) lang = rating.partner_id.lang or get_lang(request.env).code return request.env['ir.ui.view'].with_context( lang=lang)._render_template( 'rating.rating_external_page_view', { 'web_base_url': request.env['ir.config_parameter'].sudo().get_param( 'web.base.url'), 'rating': rating, })
def send_and_print_action(self): self.ensure_one() # Send the mails in the correct language by splitting the ids per lang. # This should ideally be fixed in mail_compose_message, so when a fix is made there this whole commit should be reverted. # basically self.body (which could be manually edited) extracts self.template_id, # which is then not translated for each customer. if self.composition_mode == 'mass_mail' and self.template_id: active_ids = self.env.context.get('active_ids', self.res_id) active_records = self.env[self.model].browse(active_ids) langs = active_records.mapped('partner_id.lang') default_lang = get_lang(self.env) for lang in (set(langs) or [default_lang]): active_ids_lang = active_records.filtered( lambda r: r.partner_id.lang == lang).ids self_lang = self.with_context(active_ids=active_ids_lang, lang=lang) self_lang.onchange_template_id() self_lang._send_email() else: self._send_email() if self.is_print: return self._print_document() return {'type': 'ir.actions.act_window_close'}
def generate_fec(self): self.ensure_one() if not (self.env.is_admin() or self.env.user.has_group('account.group_account_user')): raise AccessDenied() # We choose to implement the flat file instead of the XML # file for 2 reasons : # 1) the XSD file impose to have the label on the account.move # but Flectra has the label on the account.move.line, so that's a # problem ! # 2) CSV files are easier to read/use for a regular accountant. # So it will be easier for the accountant to check the file before # sending it to the fiscal administration today = fields.Date.today() if self.date_from > today or self.date_to > today: raise UserError( _('You could not set the start date or the end date in the future.' )) if self.date_from >= self.date_to: raise UserError( _('The start date must be inferior to the end date.')) company = self.env.company company_legal_data = self._get_company_legal_data(company) header = [ u'JournalCode', # 0 u'JournalLib', # 1 u'EcritureNum', # 2 u'EcritureDate', # 3 u'CompteNum', # 4 u'CompteLib', # 5 u'CompAuxNum', # 6 We use partner.id u'CompAuxLib', # 7 u'PieceRef', # 8 u'PieceDate', # 9 u'EcritureLib', # 10 u'Debit', # 11 u'Credit', # 12 u'EcritureLet', # 13 u'DateLet', # 14 u'ValidDate', # 15 u'Montantdevise', # 16 u'Idevise', # 17 ] rows_to_write = [header] # INITIAL BALANCE unaffected_earnings_xml_ref = self.env.ref( 'account.data_unaffected_earnings') unaffected_earnings_line = True # used to make sure that we add the unaffected earning initial balance only once if unaffected_earnings_xml_ref: #compute the benefit/loss of last year to add in the initial balance of the current year earnings account unaffected_earnings_results = self._do_query_unaffected_earnings() unaffected_earnings_line = False sql_query = ''' SELECT 'OUV' AS JournalCode, 'Balance initiale' AS JournalLib, 'OUVERTURE/' || %s AS EcritureNum, %s AS EcritureDate, MIN(aa.code) AS CompteNum, replace(replace(MIN(aa.name), '|', '/'), '\t', '') AS CompteLib, '' AS CompAuxNum, '' AS CompAuxLib, '-' AS PieceRef, %s AS PieceDate, '/' AS EcritureLib, replace(CASE WHEN sum(aml.balance) <= 0 THEN '0,00' ELSE to_char(SUM(aml.balance), '000000000000000D99') END, '.', ',') AS Debit, replace(CASE WHEN sum(aml.balance) >= 0 THEN '0,00' ELSE to_char(-SUM(aml.balance), '000000000000000D99') END, '.', ',') AS Credit, '' AS EcritureLet, '' AS DateLet, %s AS ValidDate, '' AS Montantdevise, '' AS Idevise, MIN(aa.id) AS CompteID FROM account_move_line aml LEFT JOIN account_move am ON am.id=aml.move_id JOIN account_account aa ON aa.id = aml.account_id LEFT JOIN account_account_type aat ON aa.user_type_id = aat.id WHERE am.date < %s AND am.company_id = %s AND aat.include_initial_balance = 't' ''' # For official report: only use posted entries if self.export_type == "official": sql_query += ''' AND am.state = 'posted' ''' sql_query += ''' GROUP BY aml.account_id, aat.type HAVING aat.type not in ('receivable', 'payable') ''' formatted_date_from = fields.Date.to_string(self.date_from).replace( '-', '') date_from = self.date_from formatted_date_year = date_from.year currency_digits = 2 self._cr.execute( sql_query, (formatted_date_year, formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id)) for row in self._cr.fetchall(): listrow = list(row) account_id = listrow.pop() if not unaffected_earnings_line: account = self.env['account.account'].browse(account_id) if account.user_type_id.id == self.env.ref( 'account.data_unaffected_earnings').id: #add the benefit/loss of previous fiscal year to the first unaffected earnings account found. unaffected_earnings_line = True current_amount = float(listrow[11].replace( ',', '.')) - float(listrow[12].replace(',', '.')) unaffected_earnings_amount = float( unaffected_earnings_results[11].replace( ',', '.')) - float( unaffected_earnings_results[12].replace( ',', '.')) listrow_amount = current_amount + unaffected_earnings_amount if float_is_zero(listrow_amount, precision_digits=currency_digits): continue if listrow_amount > 0: listrow[11] = str(listrow_amount).replace('.', ',') listrow[12] = '0,00' else: listrow[11] = '0,00' listrow[12] = str(-listrow_amount).replace('.', ',') rows_to_write.append(listrow) #if the unaffected earnings account wasn't in the selection yet: add it manually if (not unaffected_earnings_line and unaffected_earnings_results and (unaffected_earnings_results[11] != '0,00' or unaffected_earnings_results[12] != '0,00')): #search an unaffected earnings account unaffected_earnings_account = self.env['account.account'].search( [('user_type_id', '=', self.env.ref('account.data_unaffected_earnings').id)], limit=1) if unaffected_earnings_account: unaffected_earnings_results[ 4] = unaffected_earnings_account.code unaffected_earnings_results[ 5] = unaffected_earnings_account.name rows_to_write.append(unaffected_earnings_results) # INITIAL BALANCE - receivable/payable sql_query = ''' SELECT 'OUV' AS JournalCode, 'Balance initiale' AS JournalLib, 'OUVERTURE/' || %s AS EcritureNum, %s AS EcritureDate, MIN(aa.code) AS CompteNum, replace(MIN(aa.name), '|', '/') AS CompteLib, CASE WHEN MIN(aat.type) IN ('receivable', 'payable') THEN CASE WHEN rp.ref IS null OR rp.ref = '' THEN rp.id::text ELSE replace(rp.ref, '|', '/') END ELSE '' END AS CompAuxNum, CASE WHEN aat.type IN ('receivable', 'payable') THEN COALESCE(replace(rp.name, '|', '/'), '') ELSE '' END AS CompAuxLib, '-' AS PieceRef, %s AS PieceDate, '/' AS EcritureLib, replace(CASE WHEN sum(aml.balance) <= 0 THEN '0,00' ELSE to_char(SUM(aml.balance), '000000000000000D99') END, '.', ',') AS Debit, replace(CASE WHEN sum(aml.balance) >= 0 THEN '0,00' ELSE to_char(-SUM(aml.balance), '000000000000000D99') END, '.', ',') AS Credit, '' AS EcritureLet, '' AS DateLet, %s AS ValidDate, '' AS Montantdevise, '' AS Idevise, MIN(aa.id) AS CompteID FROM account_move_line aml LEFT JOIN account_move am ON am.id=aml.move_id LEFT JOIN res_partner rp ON rp.id=aml.partner_id JOIN account_account aa ON aa.id = aml.account_id LEFT JOIN account_account_type aat ON aa.user_type_id = aat.id WHERE am.date < %s AND am.company_id = %s AND aat.include_initial_balance = 't' ''' # For official report: only use posted entries if self.export_type == "official": sql_query += ''' AND am.state = 'posted' ''' sql_query += ''' GROUP BY aml.account_id, aat.type, rp.ref, rp.id HAVING aat.type in ('receivable', 'payable') ''' self._cr.execute( sql_query, (formatted_date_year, formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id)) for row in self._cr.fetchall(): listrow = list(row) account_id = listrow.pop() rows_to_write.append(listrow) # LINES sql_query = ''' SELECT REGEXP_REPLACE(replace(aj.code, '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS JournalCode, REGEXP_REPLACE(replace(COALESCE(aj__name.value, aj.name), '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS JournalLib, REGEXP_REPLACE(replace(am.name, '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS EcritureNum, TO_CHAR(am.date, 'YYYYMMDD') AS EcritureDate, aa.code AS CompteNum, REGEXP_REPLACE(replace(aa.name, '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS CompteLib, CASE WHEN aat.type IN ('receivable', 'payable') THEN CASE WHEN rp.ref IS null OR rp.ref = '' THEN rp.id::text ELSE replace(rp.ref, '|', '/') END ELSE '' END AS CompAuxNum, CASE WHEN aat.type IN ('receivable', 'payable') THEN COALESCE(REGEXP_REPLACE(replace(rp.name, '|', '/'), '[\\t\\r\\n]', ' ', 'g'), '') ELSE '' END AS CompAuxLib, CASE WHEN am.ref IS null OR am.ref = '' THEN '-' ELSE REGEXP_REPLACE(replace(am.ref, '|', '/'), '[\\t\\r\\n]', ' ', 'g') END AS PieceRef, TO_CHAR(am.date, 'YYYYMMDD') AS PieceDate, CASE WHEN aml.name IS NULL OR aml.name = '' THEN '/' WHEN aml.name SIMILAR TO '[\\t|\\s|\\n]*' THEN '/' ELSE REGEXP_REPLACE(replace(aml.name, '|', '/'), '[\\t\\n\\r]', ' ', 'g') END AS EcritureLib, replace(CASE WHEN aml.debit = 0 THEN '0,00' ELSE to_char(aml.debit, '000000000000000D99') END, '.', ',') AS Debit, replace(CASE WHEN aml.credit = 0 THEN '0,00' ELSE to_char(aml.credit, '000000000000000D99') END, '.', ',') AS Credit, CASE WHEN rec.name IS NULL THEN '' ELSE rec.name END AS EcritureLet, CASE WHEN aml.full_reconcile_id IS NULL THEN '' ELSE TO_CHAR(rec.create_date, 'YYYYMMDD') END AS DateLet, TO_CHAR(am.date, 'YYYYMMDD') AS ValidDate, CASE WHEN aml.amount_currency IS NULL OR aml.amount_currency = 0 THEN '' ELSE replace(to_char(aml.amount_currency, '000000000000000D99'), '.', ',') END AS Montantdevise, CASE WHEN aml.currency_id IS NULL THEN '' ELSE rc.name END AS Idevise FROM account_move_line aml LEFT JOIN account_move am ON am.id=aml.move_id LEFT JOIN res_partner rp ON rp.id=aml.partner_id JOIN account_journal aj ON aj.id = am.journal_id LEFT JOIN ir_translation aj__name ON aj__name.res_id = aj.id AND aj__name.type = 'model' AND aj__name.name = 'account.journal,name' AND aj__name.lang = %s AND aj__name.value != '' JOIN account_account aa ON aa.id = aml.account_id LEFT JOIN account_account_type aat ON aa.user_type_id = aat.id LEFT JOIN res_currency rc ON rc.id = aml.currency_id LEFT JOIN account_full_reconcile rec ON rec.id = aml.full_reconcile_id WHERE am.date >= %s AND am.date <= %s AND am.company_id = %s ''' # For official report: only use posted entries if self.export_type == "official": sql_query += ''' AND am.state = 'posted' ''' sql_query += ''' ORDER BY am.date, am.name, aml.id ''' lang = self.env.user.lang or get_lang(self.env).code self._cr.execute(sql_query, (lang, self.date_from, self.date_to, company.id)) for row in self._cr.fetchall(): rows_to_write.append(list(row)) fecvalue = self._csv_write_rows(rows_to_write) end_date = fields.Date.to_string(self.date_to).replace('-', '') suffix = '' if self.export_type == "nonofficial": suffix = '-NONOFFICIAL' self.write({ 'fec_data': base64.encodebytes(fecvalue), # Filename = <siren>FECYYYYMMDD where YYYMMDD is the closing date 'filename': '%sFEC%s%s.csv' % (company_legal_data, end_date, suffix), }) # Set fiscal year lock date to the end date (not in test) fiscalyear_lock_date = self.env.company.fiscalyear_lock_date if not self.test_file and (not fiscalyear_lock_date or fiscalyear_lock_date < self.date_to): self.env.company.write({'fiscalyear_lock_date': self.date_to}) return { 'name': 'FEC', 'type': 'ir.actions.act_url', 'url': "web/content/?model=account.fr.fec&id=" + str(self.id) + "&filename_field=filename&field=fec_data&download=true&filename=" + self.filename, 'target': 'self', }
def _to_short_month_name(date): month_index = fields.Date.from_string(date).month return babel.dates.get_month_names('abbreviated', locale=get_lang(self.env).code)[month_index]
def _get_date_formats(self): """ get current date and time format, according to the context lang :return: a tuple with (format date, format time) """ lang = get_lang(self.env) return (lang.date_format, lang.time_format)
def _compute_sale_graph(self, date_from, date_to, sales_domain, previous=False): days_between = (date_to - date_from).days date_list = [(date_from + timedelta(days=x)) for x in range(0, days_between + 1)] daily_sales = request.env['sale.report'].read_group( domain=sales_domain, fields=['date', 'price_subtotal'], groupby='date:day') daily_sales_dict = {p['date:day']: p['price_subtotal'] for p in daily_sales} sales_graph = [{ '0': fields.Date.to_string(d) if not previous else fields.Date.to_string(d + timedelta(days=days_between)), # Respect read_group format in models.py '1': daily_sales_dict.get(babel.dates.format_date(d, format='dd MMM yyyy', locale=get_lang(request.env).code), 0) } for d in date_list] return sales_graph
def read_progress_bar(self, domain, group_by, progress_bar): """ Gets the data needed for all the kanban column progressbars. These are fetched alongside read_group operation. :param domain - the domain used in the kanban view to filter records :param group_by - the name of the field used to group records into kanban columns :param progress_bar - the <progressbar/> declaration attributes (field, colors, sum) :return a dictionnary mapping group_by values to dictionnaries mapping progress bar field values to the related number of records """ # Workaround to match read_group's infrastructure # TO DO in master: harmonize this function and readgroup to allow factorization group_by_modifier = group_by.partition(':')[2] or 'month' group_by = group_by.partition(':')[0] display_date_formats = { 'day': 'dd MMM yyyy', 'week': "'W'w YYYY", 'month': 'MMMM yyyy', 'quarter': 'QQQ yyyy', 'year': 'yyyy' } records_values = self.search_read(domain or [], [progress_bar['field'], group_by]) data = {} field_type = self._fields[group_by].type if field_type == 'selection': selection_labels = dict(self.fields_get()[group_by]['selection']) for record_values in records_values: group_by_value = record_values[group_by] # Again, imitating what _read_group_format_result and _read_group_prepare_data do if group_by_value and field_type in ['date', 'datetime']: locale = get_lang(self.env).code group_by_value = date_utils.start_of( fields.Datetime.to_datetime(group_by_value), group_by_modifier) group_by_value = pytz.timezone('UTC').localize(group_by_value) tz_info = None if field_type == 'datetime' and self._context.get( 'tz') in pytz.all_timezones: tz_info = self._context.get('tz') group_by_value = babel.dates.format_datetime( group_by_value, format=display_date_formats[group_by_modifier], tzinfo=tz_info, locale=locale) else: group_by_value = babel.dates.format_date( group_by_value, format=display_date_formats[group_by_modifier], locale=locale) if field_type == 'selection': group_by_value = selection_labels[group_by_value] \ if group_by_value in selection_labels else False if type(group_by_value) == tuple: group_by_value = group_by_value[ 1] # FIXME should use technical value (0) if group_by_value not in data: data[group_by_value] = {} for key in progress_bar['colors']: data[group_by_value][key] = 0 field_value = record_values[progress_bar['field']] if field_value in data[group_by_value]: data[group_by_value][field_value] += 1 return data
def get_bar_graph_datas(self): data = [] today = fields.Datetime.now(self) data.append({'label': _('Due'), 'value': 0.0, 'type': 'past'}) day_of_week = int( format_datetime(today, 'e', locale=get_lang(self.env).code)) first_day_of_week = today + timedelta(days=-day_of_week + 1) for i in range(-1, 4): if i == 0: label = _('This Week') elif i == 3: label = _('Not Due') else: start_week = first_day_of_week + timedelta(days=i * 7) end_week = start_week + timedelta(days=6) if start_week.month == end_week.month: label = str(start_week.day) + '-' + str( end_week.day) + ' ' + format_date( end_week, 'MMM', locale=get_lang(self.env).code) else: label = format_date( start_week, 'd MMM', locale=get_lang(self.env).code) + '-' + format_date( end_week, 'd MMM', locale=get_lang(self.env).code) data.append({ 'label': label, 'value': 0.0, 'type': 'past' if i < 0 else 'future' }) # Build SQL query to find amount aggregated by week (select_sql_clause, query_args) = self._get_bar_graph_select_query() query = '' start_date = (first_day_of_week + timedelta(days=-7)) for i in range(0, 6): if i == 0: query += "(" + select_sql_clause + " and invoice_date_due < '" + start_date.strftime( DF) + "')" elif i == 5: query += " UNION ALL (" + select_sql_clause + " and invoice_date_due >= '" + start_date.strftime( DF) + "')" else: next_date = start_date + timedelta(days=7) query += " UNION ALL (" + select_sql_clause + " and invoice_date_due >= '" + start_date.strftime( DF) + "' and invoice_date_due < '" + next_date.strftime( DF) + "')" start_date = next_date self.env.cr.execute(query, query_args) query_results = self.env.cr.dictfetchall() is_sample_data = True for index in range(0, len(query_results)): if query_results[index].get('aggr_date') != None: is_sample_data = False data[index]['value'] = query_results[index].get('total') [graph_title, graph_key] = self._graph_title_and_key() if is_sample_data: for index in range(0, len(query_results)): data[index]['type'] = 'o_sample_data' # we use unrealistic values for the sample data data[index]['value'] = random.randint(0, 20) graph_key = _('Sample data') return [{ 'values': data, 'title': graph_title, 'key': graph_key, 'is_sample_data': is_sample_data }]
def get_line_graph_datas(self): """Computes the data used to display the graph for bank and cash journals in the accounting dashboard""" currency = self.currency_id or self.company_id.currency_id def build_graph_data(date, amount): #display date in locale format name = format_date(date, 'd LLLL Y', locale=locale) short_name = format_date(date, 'd MMM', locale=locale) return {'x': short_name, 'y': amount, 'name': name} self.ensure_one() BankStatement = self.env['account.bank.statement'] data = [] today = datetime.today() last_month = today + timedelta(days=-30) locale = get_lang(self.env).code #starting point of the graph is the last statement last_stmt = self._get_last_bank_statement(domain=[('move_id.state', '=', 'posted')]) last_balance = last_stmt and last_stmt.balance_end_real or 0 data.append(build_graph_data(today, last_balance)) #then we subtract the total amount of bank statement lines per day to get the previous points #(graph is drawn backward) date = today amount = last_balance query = ''' SELECT move.date, sum(st_line.amount) as amount FROM account_bank_statement_line st_line JOIN account_move move ON move.id = st_line.move_id WHERE move.journal_id = %s AND move.date > %s AND move.date <= %s GROUP BY move.date ORDER BY move.date desc ''' self.env.cr.execute(query, (self.id, last_month, today)) query_result = self.env.cr.dictfetchall() for val in query_result: date = val['date'] if date != today.strftime( DF): # make sure the last point in the graph is today data[:0] = [build_graph_data(date, amount)] amount = currency.round(amount - val['amount']) # make sure the graph starts 1 month ago if date.strftime(DF) != last_month.strftime(DF): data[:0] = [build_graph_data(last_month, amount)] [graph_title, graph_key] = self._graph_title_and_key() color = '#009EFB' if 'e' in version else '#7c7bad' is_sample_data = not last_stmt and len(query_result) == 0 if is_sample_data: data = [] for i in range(30, 0, -5): current_date = today + timedelta(days=-i) data.append( build_graph_data(current_date, random.randint(-5, 15))) return [{ 'values': data, 'title': graph_title, 'key': graph_key, 'area': True, 'color': color, 'is_sample_data': is_sample_data }]