Exemplo n.º 1
0
 def _get_profitability_values(self, project):
     costs_revenues = project.analytic_account_id and project.allow_billable
     timesheets = project.allow_timesheets and self.user_has_groups(
         'hr_timesheet.group_hr_timesheet_user')
     if not (self.user_has_groups('project.group_project_manager') and
             (costs_revenues or timesheets)):
         return {}
     profitability = project._get_profitability_common()
     return {
         'analytic_account_id':
         project.analytic_account_id,
         'costs':
         format_amount(self.env, -profitability['costs'],
                       self.env.company.currency_id),
         'revenues':
         format_amount(self.env, profitability['revenues'],
                       self.env.company.currency_id),
         'margin':
         profitability['margin'],
         'margin_formatted':
         format_amount(self.env, profitability['margin'],
                       self.env.company.currency_id),
         'margin_percentage':
         formatLang(
             self.env,
             not float_utils.float_is_zero(profitability['costs'],
                                           precision_digits=2)
             and -(profitability['margin'] / profitability['costs']) * 100
             or 0.0,
             digits=0),
     }
Exemplo n.º 2
0
 def _get_profitability_values(self, project):
     costs_revenues = project.analytic_account_id and project.allow_billable
     if not (self.user_has_groups('project.group_project_manager')
             and costs_revenues):
         return {}
     profitability_items = project._get_profitability_items(False)
     costs = sum(profitability_items['costs']['total'].values())
     revenues = sum(profitability_items['revenues']['total'].values())
     margin = revenues + costs
     return {
         'analytic_account_id':
         project.analytic_account_id,
         'costs':
         costs,
         'costs_formatted':
         format_amount(self.env, -costs, project.currency_id),
         'revenues':
         revenues,
         'revenues_formatted':
         format_amount(self.env, revenues, project.currency_id),
         'margin':
         margin,
         'margin_formatted':
         format_amount(self.env, margin, project.currency_id),
         'margin_percentage':
         formatLang(
             self.env,
             not float_utils.float_is_zero(costs, precision_digits=2) and
             (margin / -costs) * 100 or 0.0,
             digits=0),
     }
Exemplo n.º 3
0
 def _get_profitability_items(self):
     if not self.user_has_groups('project.group_project_manager'):
         return {'data': []}
     data = []
     if self.allow_billable:
         profitability = self._get_profitability_common()
         margin_color = False
         if not float_is_zero(profitability['margin'], precision_digits=0):
             margin_color = profitability['margin'] > 0 and 'green' or 'red'
         data += [{
             'name': _("Revenues"),
             'value': format_amount(self.env, profitability['revenues'], self.env.company.currency_id)
         }, {
             'name': _("Costs"),
             'value': format_amount(self.env, profitability['costs'], self.env.company.currency_id)
         }, {
             'name': _("Margin"),
             'color': margin_color,
             'value': format_amount(self.env, profitability['margin'], self.env.company.currency_id)
         }]
     return {
         'action': self.allow_billable and self.allow_timesheets and "action_view_timesheet",
         'allow_billable': self.allow_billable,
         'data': data,
     }
Exemplo n.º 4
0
 def _get_profitability_items(self):
     if not self.user_has_groups('project.group_project_manager'):
         return {'data': []}
     profitability = self.get_profitability_common()
     data = []
     if self.allow_timesheets and self.user_has_groups('hr_timesheet.group_hr_timesheet_user'):
         data += [{
             'name': _("Timesheets"),
             'value': self.env.ref('sale_timesheet.project_profitability_timesheet_panel')._render({
                 'timesheet_unit_amount': float_round(profitability['timesheet_unit_amount'], precision_digits=2),
                 'timesheet_uom': self.env.company._timesheet_uom_text(),
                 'is_timesheet_uom_hour': self.env.company._is_timesheet_hour_uom(),
                 'percentage_billable': formatLang(self.env, profitability['timesheet_percentage_billable'], digits=0),
             }, engine='ir.qweb'),
         }]
     if self.allow_billable:
         margin_color = False
         if not float_is_zero(profitability['margin'], precision_digits=0):
             margin_color = profitability['margin'] > 0 and 'green' or 'red'
         data += [{
             'name': _("Revenues"),
             'value': format_amount(self.env, profitability['revenues'], self.env.company.currency_id)
         }, {
             'name': _("Costs"),
             'value': format_amount(self.env, profitability['costs'], self.env.company.currency_id)
         }, {
             'name': _("Margin"),
             'color': margin_color,
             'value': format_amount(self.env, profitability['margin'], self.env.company.currency_id)
         }]
     return {
         'action': self.allow_billable and self.allow_timesheets and "action_view_timesheet",
         'allow_billable': self.allow_billable,
         'data': data,
     }
Exemplo n.º 5
0
 def _compute_rule_tip(self):
     base_selection_vals = {
         elem[0]: elem[1]
         for elem in self._fields['base']._description_selection(self.env)
     }
     self.rule_tip = False
     for item in self:
         if item.compute_price != 'formula':
             continue
         base_amount = 100
         discount_factor = (100 - item.price_discount) / 100
         discounted_price = base_amount * discount_factor
         if item.price_round:
             discounted_price = tools.float_round(
                 discounted_price, precision_rounding=item.price_round)
         surcharge = tools.format_amount(item.env, item.price_surcharge,
                                         item.currency_id)
         item.rule_tip = _(
             "%(base)s with a %(discount)s %% discount and %(surcharge)s extra fee\n"
             "Example: %(amount)s * %(discount_charge)s + %(price_surcharge)s → %(total_amount)s",
             base=base_selection_vals[item.base],
             discount=item.price_discount,
             surcharge=surcharge,
             amount=tools.format_amount(item.env, 100, item.currency_id),
             discount_charge=discount_factor,
             price_surcharge=surcharge,
             total_amount=tools.format_amount(
                 item.env, discounted_price + item.price_surcharge,
                 item.currency_id),
         )
Exemplo n.º 6
0
 def _onchange_partner_invoice_id(self):
     for so in self:
         partner = so.partner_invoice_id.commercial_partner_id
         if partner.credit_limit and partner.credit_limit <= partner.credit:
             m = 'Partner outstanding receivables %s is above their credit limit of %s' \
                                        % (tools.format_amount(self.env, partner.credit, so.currency_id),
                                           tools.format_amount(self.env, partner.credit_limit, so.currency_id))
             return {
                 'warning': {
                     'title': 'Sale Credit Limit',
                     'message': m
                 }
             }
Exemplo n.º 7
0
 def _compute_tax_string(self):
     for record in self:
         currency = record.currency_id
         res = record.taxes_id.compute_all(record.list_price)
         joined = []
         included = res['total_included']
         if currency.compare_amounts(included, record.list_price):
             joined.append(_('%s Incl. Taxes', format_amount(self.env, included, currency)))
         excluded = res['total_excluded']
         if currency.compare_amounts(excluded, record.list_price):
             joined.append(_('%s Excl. Taxes', format_amount(self.env, excluded, currency)))
         if joined:
             record.tax_string = f"(= {', '.join(joined)})"
         else:
             record.tax_string = " "
Exemplo n.º 8
0
    def _get_common_eval_context(self):
        """ Evaluation context used in all rendering engines. Contains

          * ``user``: current user browse record;
          * ``ctx```: current context;
          * various formatting tools;
        """
        return {
            'format_date':
            lambda date, date_format=False, lang_code=False: format_date(
                self.env, date, date_format, lang_code),
            'format_datetime':
            lambda dt, tz=False, dt_format=False, lang_code=False:
            format_datetime(self.env, dt, tz, dt_format, lang_code),
            'format_time':
            lambda time, tz=False, time_format=False, lang_code=False:
            format_time(self.env, time, tz, time_format, lang_code),
            'format_amount':
            lambda amount, currency, lang_code=False: tools.format_amount(
                self.env, amount, currency, lang_code),
            'format_duration':
            lambda value: tools.format_duration(value),
            'user':
            self.env.user,
            'ctx':
            self._context,
        }
Exemplo n.º 9
0
    def _render_eval_context(self):
        """ Evaluation context used in all rendering engines. Contains

          * ``user``: current user browse record;
          * ``ctx```: current context;
          * various formatting tools;
        """
        render_context = {
            'format_date':
            lambda date, date_format=False, lang_code=False: format_date(
                self.env, date, date_format, lang_code),
            'format_datetime':
            lambda dt, tz=False, dt_format=False, lang_code=False:
            format_datetime(self.env, dt, tz, dt_format, lang_code),
            'format_time':
            lambda time, tz=False, time_format=False, lang_code=False:
            format_time(self.env, time, tz, time_format, lang_code),
            'format_amount':
            lambda amount, currency, lang_code=False: tools.format_amount(
                self.env, amount, currency, lang_code),
            'format_duration':
            lambda value: tools.format_duration(value),
            'user':
            self.env.user,
            'ctx':
            self._context,
            'is_html_empty':
            is_html_empty,
        }
        render_context.update(copy.copy(template_env_globals))
        return render_context
Exemplo n.º 10
0
    def _render_jinja_eval_context(self):
        """ Prepare jinja evaluation context, containing for all rendering

          * ``user``: current user browse record;
          * ``ctx```: current context, named ctx to avoid clash with jinja
            internals that already uses context;
          * various formatting tools;
        """
        render_context = {
            'format_date':
            lambda date, date_format=False, lang_code=False: format_date(
                self.env, date, date_format, lang_code),
            'format_datetime':
            lambda dt, tz=False, dt_format=False, lang_code=False:
            format_datetime(self.env, dt, tz, dt_format, lang_code),
            'format_amount':
            lambda amount, currency, lang_code=False: tools.format_amount(
                self.env, amount, currency, lang_code),
            'format_duration':
            lambda value: tools.format_duration(value),
            'user':
            self.env.user,
            'ctx':
            self._context,
        }
        return render_context
Exemplo n.º 11
0
    def _get_sent_message(self):
        """ Return the message stating that the transaction has been requested.

        Note: self.ensure_one()

        :return: The 'transaction sent' message
        :rtype: str
        """
        self.ensure_one()

        # Choose the message based on the payment flow
        if self.operation in ('online_redirect', 'online_direct'):
            message = _(
                "A transaction with reference %(ref)s has been initiated (%(acq_name)s).",
                ref=self.reference, acq_name=self.acquirer_id.name
            )
        elif self.operation == 'refund':
            formatted_amount = format_amount(self.env, -self.amount, self.currency_id)
            message = _(
                "A refund request of %(amount)s has been sent. The payment will be created soon. "
                "Refund transaction reference: %(ref)s (%(acq_name)s).",
                amount=formatted_amount, ref=self.reference, acq_name=self.acquirer_id.name
            )
        else:  # 'online_token'
            message = _(
                "A transaction with reference %(ref)s has been initiated using the payment method "
                "%(token_name)s (%(acq_name)s).",
                ref=self.reference, token_name=self.token_id.name, acq_name=self.acquirer_id.name
            )
        return message
Exemplo n.º 12
0
    def name_get(self):
        res = super().name_get()
        with_price_unit = self.env.context.get('with_price_unit')
        if with_price_unit:
            names = dict(res)
            result = []
            sols_by_so_dict = defaultdict(
                lambda: self.env[self._name]
            )  # key: (sale_order_id, product_id), value: sale order line
            for line in self:
                sols_by_so_dict[line.order_id.id, line.product_id.id] += line

            for sols in sols_by_so_dict.values():
                if len(sols) > 1 and all(sols.mapped('is_service')):
                    result += [
                        (line.id,
                         '%s - %s' % (names.get(line.id),
                                      format_amount(self.env, line.price_unit,
                                                    line.currency_id)))
                        for line in sols
                    ]
                else:
                    result += [(line.id, names.get(line.id)) for line in sols]
            return result
        return res
Exemplo n.º 13
0
    def name_get(self):
        res = super(SaleOrderLine, self).name_get()
        with_remaining_hours = self.env.context.get('with_remaining_hours')
        with_price_unit = self.env.context.get('with_price_unit')
        if with_remaining_hours or with_price_unit:
            names = dict(res)
            result = []
            uom_hour = with_remaining_hours and self.env.ref('uom.product_uom_hour')
            uom_day = with_remaining_hours and self.env.ref('uom.product_uom_day')
            sols_by_so_dict = with_price_unit and defaultdict(lambda: self.env[self._name])  # key: (sale_order_id, product_id), value: sale order line
            for line in self:
                if with_remaining_hours:
                    name = names.get(line.id)
                    if line.remaining_hours_available:
                        company = self.env.company
                        encoding_uom = company.timesheet_encode_uom_id
                        remaining_time = ''
                        if encoding_uom == uom_hour:
                            hours, minutes = divmod(abs(line.remaining_hours) * 60, 60)
                            round_minutes = minutes / 30
                            minutes = math.ceil(round_minutes) if line.remaining_hours >= 0 else math.floor(round_minutes)
                            if minutes > 1:
                                minutes = 0
                                hours += 1
                            else:
                                minutes = minutes * 30
                            remaining_time = ' ({sign}{hours:02.0f}:{minutes:02.0f})'.format(
                                sign='-' if line.remaining_hours < 0 else '',
                                hours=hours,
                                minutes=minutes)
                        elif encoding_uom == uom_day:
                            remaining_days = company.project_time_mode_id._compute_quantity(line.remaining_hours, encoding_uom, round=False)
                            remaining_time = ' ({qty:.02f} {unit})'.format(
                                qty=remaining_days,
                                unit=_('days') if abs(remaining_days) > 1 else _('day')
                            )
                        name = '{name}{remaining_time}'.format(
                            name=name,
                            remaining_time=remaining_time
                        )
                        if with_price_unit:
                            names[line.id] = name
                    if not with_price_unit:
                        result.append((line.id, name))
                if with_price_unit:
                    sols_by_so_dict[line.order_id.id, line.product_id.id] += line

            if with_price_unit:
                for sols in sols_by_so_dict.values():
                    if len(sols) > 1:
                        result += [(
                            line.id,
                            '%s - %s' % (
                                names.get(line.id), format_amount(self.env, line.price_unit, line.currency_id))
                        ) for line in sols]
                    else:
                        result.append((sols.id, names.get(sols.id)))
            return result
        return res
Exemplo n.º 14
0
    def _render_template(self, template_txt, model, res_ids, post_process=False):
        """ Render the given template text, replace mako expressions ``${expr}``
        with the result of evaluating these expressions with an evaluation
        context containing:

         - ``user``: Model of the current user
         - ``object``: record of the document record this mail is related to
         - ``context``: the context passed to the mail composition wizard

        :param str template_txt: the template text to render
        :param str model: model name of the document record this mail is related to.
        :param int res_ids: list of ids of document records those mails are related to.
        """
        multi_mode = True
        if isinstance(res_ids, int):
            multi_mode = False
            res_ids = [res_ids]

        results = dict.fromkeys(res_ids, u"")

        # try to load the template
        try:
            mako_env = mako_safe_template_env if self.env.context.get('safe') else mako_template_env
            template = mako_env.from_string(tools.ustr(template_txt))
        except Exception:
            _logger.info("Failed to load template %r", template_txt, exc_info=True)
            return multi_mode and results or results[res_ids[0]]

        # prepare template variables
        records = self.env[model].browse(it for it in res_ids if it)  # filter to avoid browsing [None]
        res_to_rec = dict.fromkeys(res_ids, None)
        for record in records:
            res_to_rec[record.id] = record
        variables = {
            'format_date': lambda date, date_format=False, lang_code=False: format_date(self.env, date, date_format, lang_code),
            'format_datetime': lambda dt, tz=False, dt_format=False, lang_code=False: format_datetime(self.env, dt, tz, dt_format, lang_code),
            'format_amount': lambda amount, currency, lang_code=False: tools.format_amount(self.env, amount, currency, lang_code),
            'format_duration': lambda value: tools.format_duration(value),
            'user': self.env.user,
            'ctx': self._context,  # context kw would clash with mako internals
        }
        for res_id, record in res_to_rec.items():
            variables['object'] = record
            try:
                render_result = template.render(variables)
            except Exception as e:
                _logger.info("Failed to render template %r using values %r" % (template, variables), exc_info=True)
                raise UserError(_("Failed to render template %r using values %r") % (template, variables) +
                                "\n\n%s: %s" % (type(e).__name__, str(e)))
            if render_result == u"False":
                render_result = u""
            results[res_id] = render_result

        if post_process:
            for res_id, result in results.items():
                results[res_id] = self.render_post_process(result)

        return multi_mode and results or results[res_ids[0]]
Exemplo n.º 15
0
    def _check_amount_and_confirm_order(self):
        """ Confirm the sales order based on the amount of a transaction.

        Confirm the sales orders only if the transaction amount is equal to the total amount of the
        sales orders. Neither partial payments nor grouped payments (paying multiple sales orders in
        one transaction) are not supported.

        :return: The confirmed sales orders.
        :rtype: a `sale.order` recordset
        """
        confirmed_orders = self.env['sale.order']
        for tx in self:
            # We only support the flow where exactly one quotation is linked to a transaction and
            # vice versa.
            if len(tx.sale_order_ids) == 1:
                quotation = tx.sale_order_ids.filtered(lambda so: so.state in
                                                       ('draft', 'sent'))
                if quotation and len(quotation.transaction_ids) == 1:
                    # Check if the SO is fully paid
                    if quotation.currency_id.compare_amounts(
                            tx.amount, quotation.amount_total) == 0:
                        quotation.with_context(
                            send_email=True).action_confirm()
                        confirmed_orders |= quotation
                    else:
                        _logger.warning(
                            '<%(provider)s> transaction AMOUNT MISMATCH for order %(so_name)s '
                            '(ID %(so_id)s): expected %(so_amount)s, got %(tx_amount)s',
                            {
                                'provider':
                                tx.provider,
                                'so_name':
                                quotation.name,
                                'so_id':
                                quotation.id,
                                'so_amount':
                                format_amount(quotation.env,
                                              quotation.amount_total,
                                              quotation.currency_id),
                                'tx_amount':
                                format_amount(tx.env, tx.amount,
                                              tx.currency_id),
                            },
                        )
        return confirmed_orders
Exemplo n.º 16
0
 def _construct_tax_string(self, price):
     currency = self.currency_id
     res = self.taxes_id.compute_all(price,
                                     product=self,
                                     partner=self.env['res.partner'])
     joined = []
     included = res['total_included']
     if currency.compare_amounts(included, price):
         joined.append(
             _('%s Incl. Taxes', format_amount(self.env, included,
                                               currency)))
     excluded = res['total_excluded']
     if currency.compare_amounts(excluded, price):
         joined.append(
             _('%s Excl. Taxes', format_amount(self.env, excluded,
                                               currency)))
     if joined:
         tax_string = f"(= {', '.join(joined)})"
     else:
         tax_string = " "
     return tax_string
Exemplo n.º 17
0
    def _get_received_message(self):
        """ Return the message stating that the transaction has been received by the provider.

        Note: self.ensure_one()
        """
        self.ensure_one()

        formatted_amount = format_amount(self.env, self.amount, self.currency_id)
        if self.state == 'pending':
            message = _(
                "The transaction with reference %(ref)s for %(amount)s is pending (%(acq_name)s).",
                ref=self.reference, amount=formatted_amount, acq_name=self.acquirer_id.name
            )
        elif self.state == 'authorized':
            message = _(
                "The transaction with reference %(ref)s for %(amount)s has been authorized "
                "(%(acq_name)s).", ref=self.reference, amount=formatted_amount,
                acq_name=self.acquirer_id.name
            )
        elif self.state == 'done':
            message = _(
                "The transaction with reference %(ref)s for %(amount)s has been confirmed "
                "(%(acq_name)s).", ref=self.reference, amount=formatted_amount,
                acq_name=self.acquirer_id.name
            )
            if self.payment_id:
                message += "<br />" + _(
                    "The related payment is posted: %s",
                    self.payment_id._get_payment_chatter_link()
                )
        elif self.state == 'error':
            message = _(
                "The transaction with reference %(ref)s for %(amount)s encountered an error"
                " (%(acq_name)s).",
                ref=self.reference, amount=formatted_amount, acq_name=self.acquirer_id.name
            )
            if self.state_message:
                message += "<br />" + _("Error: %s", self.state_message)
        else:
            message = _(
                "The transaction with reference %(ref)s for %(amount)s is canceled (%(acq_name)s).",
                ref=self.reference, amount=formatted_amount, acq_name=self.acquirer_id.name
            )
            if self.state_message:
                message += "<br />" + _("Reason: %s", self.state_message)
        return message
Exemplo n.º 18
0
    def get_account_balance(self):
        if not self.user_has_groups('base.group_erp_manager'):
            raise AccessError(_("You can't access account balance."))

        if not self.env.company.adyen_account_id:
            return {}

        balance_fields = {'balance': 'balance', 'onHoldBalance': 'on_hold', 'pendingBalance': 'pending'}
        balances = self.env['adyen.account.balance'].sudo().search([
            ('adyen_account_id', '=', self.env.company.adyen_account_id.id)
        ])

        delta = fields.Datetime.now() - timedelta(hours=1)
        if not balances or any(b.write_date <= delta for b in balances):
            response = {}
            try:
                response = self.env.company.adyen_account_id._adyen_rpc('v1/account_holder_balance', {
                    'accountHolderCode': self.env.company.adyen_account_id.account_holder_code,
                })
            except UserError as e:
                _logger.warning(_('Cannot update account balance, showing previous values: %s', e))

            balances.write({
                f: 0 for f in balance_fields.values()
            })
            for total_balance, adyen_balances in response.get('totalBalance', {}).items():
                for balance in adyen_balances:
                    currency_id = self.env['res.currency'].search([('name', '=', balance.get('currency'))])
                    bal = balances.filtered(lambda b: b.currency_id == currency_id)
                    if not bal:
                        bal = self.env['adyen.account.balance'].sudo().create({
                            'adyen_account_id': self.env.company.adyen_account_id.id,
                            'currency_id': currency_id.id,
                        })
                        balances |= bal
                    bal[balance_fields.get(total_balance)] = to_major_currency(balance.get('value', 0), currency_id.decimal_places)

        warning_delta = fields.Datetime.now() - timedelta(hours=2)
        return [{
            'currency': b.currency_id.name,
            'balance': format_amount(self.env, b.balance, b.currency_id),
            'payout_date': format_datetime(self.env, self.env.company.adyen_account_id.next_scheduled_payout, dt_format='short'),
            'last_update_warning': b.write_date <= warning_delta,
            'last_update': format_datetime(self.env, b.write_date),
        } for b in balances]
Exemplo n.º 19
0
 def _get_profitability_values(self, project):
     costs_revenues = project.analytic_account_id and project.allow_billable
     timesheets = project.allow_timesheets and self.user_has_groups(
         'hr_timesheet.group_hr_timesheet_user')
     if not (self.user_has_groups('project.group_project_manager') and
             (costs_revenues or timesheets)):
         return {}
     this_month = fields.Date.context_today(self) + relativedelta(day=1)
     previous_month = this_month + relativedelta(months=-1, day=1)
     result = {
         'allow_timesheets':
         timesheets,
         'allow_costs_and_revenues':
         costs_revenues,
         'analytic_account_id':
         project.analytic_account_id,
         'month':
         format_date(self.env, this_month, date_format='LLLL y'),
         'previous_month':
         format_date(self.env, previous_month, date_format='LLLL'),
         'is_timesheet_uom_hour':
         self.env.company._is_timesheet_hour_uom(),
         'timesheet_uom':
         self.env.company._timesheet_uom_text(),
         'timesheet_unit_amount':
         '',
         'previous_timesheet_unit_amount':
         '',
         'timesheet_trend':
         '',
         'costs':
         '',
         'revenues':
         '',
         'margin':
         '',
         'margin_formatted':
         '',
         'margin_percentage':
         '',
         'billing_rate':
         '',
     }
     if timesheets:
         timesheets_per_month = self.env[
             'account.analytic.line'].read_group(
                 [('project_id', '=', project.id),
                  ('date', '>=', previous_month)], ['date', 'unit_amount'],
                 ['date:month'])
         timesheet_unit_amount = {
             ts['__range']['date']['from']: ts['unit_amount']
             for ts in timesheets_per_month
         }
         this_amount = timesheet_unit_amount.get(
             this_month.replace(day=1).strftime(DEFAULT_SERVER_DATE_FORMAT),
             0.0)
         previous_amount = timesheet_unit_amount.get(
             previous_month.replace(
                 day=1).strftime(DEFAULT_SERVER_DATE_FORMAT), 0.0)
         result.update({
             'timesheet_unit_amount':
             formatLang(
                 self.env,
                 project._convert_project_uom_to_timesheet_encode_uom(
                     this_amount),
                 digits=0),
             'previous_timesheet_unit_amount':
             formatLang(
                 self.env,
                 project._convert_project_uom_to_timesheet_encode_uom(
                     previous_amount),
                 digits=0),
             'timesheet_trend':
             formatLang(self.env,
                        previous_amount > 0 and
                        ((this_amount / previous_amount) - 1) * 100 or 0.0,
                        digits=0),
         })
     if costs_revenues:
         profitability = project._get_profitability_common(
             costs_revenues=True, timesheets=False)
         result.update({
             'costs':
             format_amount(self.env, -profitability['costs'],
                           self.env.company.currency_id),
             'revenues':
             format_amount(self.env, profitability['revenues'],
                           self.env.company.currency_id),
             'margin':
             profitability['margin'],
             'margin_formatted':
             format_amount(self.env, profitability['margin'],
                           self.env.company.currency_id),
             'margin_percentage':
             formatLang(
                 self.env,
                 not float_utils.float_is_zero(profitability['costs'],
                                               precision_digits=2) and
                 -(profitability['margin'] / profitability['costs']) * 100
                 or 0.0,
                 digits=0),
             'billing_rate':
             formatLang(
                 self.env,
                 not float_utils.float_is_zero(profitability['costs'],
                                               precision_digits=2) and
                 -(profitability['revenues'] / profitability['costs']) * 100
                 or 0.0,
                 digits=0),
         })
     return result
Exemplo n.º 20
0
 def _get_profitability_values(self, project):
     if not (self.user_has_groups('project.group_project_manager') and
             (project.analytic_account_id and project.allow_billable
              or project.allow_timesheets)):
         return {}
     profitability = project.get_profitability_common()
     start_of_month = fields.Date.context_today(self) + relativedelta(day=1)
     timesheets_this_month = self.env[
         'project.profitability.report'].read_group(
             [('project_id', '=', project.id),
              ('line_date', '>=', start_of_month)],
             ['project_id', 'timesheet_unit_amount'], ['project_id'])
     timesheets_previous_month = self.env[
         'project.profitability.report'].read_group(
             [('project_id', '=', project.id),
              ('line_date', '>=',
               start_of_month + relativedelta(months=-1, day=1)),
              ('line_date', '<', start_of_month)],
             ['project_id', 'timesheet_unit_amount'], ['project_id'])
     timesheet_unit_amount = timesheets_this_month and timesheets_this_month[
         0]['timesheet_unit_amount'] or 0.0
     previous_timesheet_unit_amount = timesheets_previous_month and timesheets_previous_month[
         0]['timesheet_unit_amount'] or 0.0
     return {
         'allow_timesheets':
         project.allow_timesheets,
         'analytic_account_id':
         project.analytic_account_id,
         'month':
         start_of_month.strftime('%B %Y'),
         'previous_month':
         (start_of_month + relativedelta(months=-1, day=1)).strftime('%B'),
         'is_timesheet_uom_hour':
         self.env.company._is_timesheet_hour_uom(),
         'timesheet_uom':
         self.env.company._timesheet_uom_text(),
         'timesheet_unit_amount':
         formatLang(self.env,
                    project._convert_project_uom_to_timesheet_encode_uom(
                        timesheet_unit_amount),
                    digits=0),
         'previous_timesheet_unit_amount':
         formatLang(self.env,
                    project._convert_project_uom_to_timesheet_encode_uom(
                        previous_timesheet_unit_amount),
                    digits=0),
         'timesheet_trend':
         formatLang(
             self.env,
             previous_timesheet_unit_amount > 0 and
             ((timesheet_unit_amount / previous_timesheet_unit_amount) - 1)
             * 100 or 0.0,
             digits=0),
         'costs':
         format_amount(self.env, -profitability['costs'],
                       self.env.company.currency_id),
         'revenues':
         format_amount(self.env, profitability['revenues'],
                       self.env.company.currency_id),
         'margin':
         profitability['margin'],
         'margin_formatted':
         format_amount(self.env, profitability['margin'],
                       self.env.company.currency_id),
         'margin_percentage':
         formatLang(
             self.env,
             not float_utils.float_is_zero(profitability['costs'],
                                           precision_digits=2)
             and -(profitability['margin'] / profitability['costs']) * 100
             or 0.0,
             digits=0),
         'billing_rate':
         formatLang(
             self.env,
             not float_utils.float_is_zero(profitability['costs'],
                                           precision_digits=2)
             and -(profitability['revenues'] / profitability['costs']) * 100
             or 0.0,
             digits=0),
     }