Esempio n. 1
0
    def _l10n_it_edi_upload(self, files, proxy_user):
        '''Upload files to fatturapa.

        :param files:    A list of dictionary {filename, base64_xml}.
        :returns:        A dictionary.
        * message:       Message from fatturapa.
        * transactionId: The fatturapa ID of this request.
        * error:         An eventual error.
        * error_level:   Info, warning, error.
        '''
        ERRORS = {
            'EI01': {'error': _lt('Attached file is empty'), 'blocking_level': 'error'},
            'EI02': {'error': _lt('Service momentarily unavailable'), 'blocking_level': 'warning'},
            'EI03': {'error': _lt('Unauthorized user'), 'blocking_level': 'error'},
        }

        server_url = self.env['ir.config_parameter'].get_param('account_edi_proxy_client.edi_server_url', DEFAULT_SERVER_URL)
        result = proxy_user._make_request(server_url + '/api/l10n_it_edi/1/out/SdiRiceviFile', params={'files': files})

        # Translate the errors.
        for filename in result.keys():
            if 'error' in result[filename]:
                result[filename] = ERRORS.get(result[filename]['error'], {'error': result[filename]['error'], 'blocking_level': 'error'})

        return result
Esempio n. 2
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('mrp.group_mrp_user'):
         buttons.extend([{
             'icon': 'wrench',
             'text': _lt('Manufacturing Orders'),
             'number': self.production_count,
             'action_type': 'object',
             'action': 'action_view_mrp_production',
             'show': self.production_count > 0,
             'sequence': 39,
         },
         {
             'icon': 'cog',
             'text': _lt('Work Orders'),
             'number': self.workorder_count,
             'action_type': 'object',
             'action': 'action_view_workorder',
             'show': self.workorder_count > 0,
             'sequence': 42,
         },
         {
             'icon': 'flask',
             'text': _lt('Bills of Materials'),
             'number': self.bom_count,
             'action_type': 'object',
             'action': 'action_view_mrp_bom',
             'show': self.bom_count > 0,
             'sequence': 45,
         }])
     return buttons
Esempio n. 3
0
 def _get_profitability_labels(self):
     return {
         **super()._get_profitability_labels(),
         'service_revenues':
         _lt('Other Services'),
         'other_revenues':
         _lt('Material'),
     }
Esempio n. 4
0
 def _get_profitability_labels(self):
     return {
         **super()._get_profitability_labels(),
         'billable_fixed':
         _lt('Timesheets (Fixed Price)'),
         'billable_time':
         _lt('Timesheets (Billed on Timesheets)'),
         'billable_milestones':
         _lt('Timesheets (Billed on Milestones)'),
         'billable_manual':
         _lt('Timesheets (Billed Manually)'),
         'non_billable':
         _lt('Timesheets (Non Billable)'),
     }
Esempio n. 5
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('hr_timesheet.group_hr_timesheet_approver'):
         buttons.append({
             'icon':
             'clock-o',
             'text':
             _lt('Billable Time'),
             'number':
             '%s %%' % (self.billable_percentage),
             'action_type':
             'object',
             'action':
             'action_billable_time_button',
             'additional_context':
             json.dumps({
                 'active_id': self.id,
                 'default_project_id': self.id
             }),
             'show':
             self.allow_timesheets and bool(self.analytic_account_id),
             'sequence':
             9,
         })
     return buttons
Esempio n. 6
0
 def _get_sale_order_stat_button(self):
     self.ensure_one()
     return {
         'icon': 'dollar',
         'text': _lt('Sales Order'),
         'action_type': 'object',
         'action': 'action_view_so',
         'show': bool(self.sale_order_id),
         'sequence': 1,
     }
Esempio n. 7
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('sales_team.group_sale_salesman_all_leads'):
         buttons.append({
             'icon': 'dollar',
             'text': _lt('Sales Orders'),
             'number': self.sale_order_count,
             'action_type': 'object',
             'action': 'action_view_sos',
             'show': self.sale_order_count > 0,
             'sequence': 1,
         })
     if self.user_has_groups('account.group_account_readonly'):
         buttons.append({
             'icon':
             'pencil-square-o',
             'text':
             _lt('Invoices'),
             'number':
             self.invoice_count,
             'action_type':
             'object',
             'action':
             'action_open_project_invoices',
             'show':
             bool(self.analytic_account_id) and self.invoice_count > 0,
             'sequence':
             30,
         })
     if self.user_has_groups('account.group_account_readonly'):
         buttons.append({
             'icon': 'pencil-square-o',
             'text': _lt('Vendor Bills'),
             'number': self.vendor_bill_count,
             'action_type': 'object',
             'action': 'action_open_project_vendor_bills',
             'show': self.vendor_bill_count > 0,
             'sequence': 48,
         })
     return buttons
Esempio n. 8
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('purchase.group_purchase_user'):
         buttons.append({
             'icon': 'credit-card',
             'text': _lt('Purchase Orders'),
             'number': self.purchase_orders_count,
             'action_type': 'object',
             'action': 'action_open_project_purchase_orders',
             'show': self.purchase_orders_count > 0,
             'sequence': 36,
         })
     return buttons
Esempio n. 9
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('hr_expense.group_hr_expense_team_approver'):
         buttons.append({
             'icon': 'money',
             'text': _lt('Expenses'),
             'number': self.expenses_count,
             'action_type': 'object',
             'action': 'action_open_project_expenses',
             'show': self.expenses_count > 0,
             'sequence': 33,
         })
     return buttons
Esempio n. 10
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('hr_timesheet.group_hr_timesheet_user'):
         buttons.append({
             'icon': 'clock-o',
             'text': _lt('Recorded'),
             'number': '%s %s' % (self.total_timesheet_time, self.env.company.timesheet_encode_uom_id.name),
             'action_type': 'object',
             'action': 'action_show_timesheets_by_employee_invoice_type',
             'show': self.allow_timesheets,
             'sequence': 6,
         })
     return buttons
Esempio n. 11
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('mrp.group_mrp_user'):
         buttons.extend([{
             'icon': 'flask',
             'text': _lt('Bills of Materials'),
             'number': self.bom_count,
             'action_type': 'object',
             'action': 'action_view_mrp_bom',
             'show': self.bom_count > 0,
             'sequence': 45,
         }])
     return buttons
Esempio n. 12
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('account.group_account_readonly'):
         buttons.append({
             'icon': 'pencil-square-o',
             'text': _lt('Vendor Bills'),
             'number': self.vendor_bill_count,
             'action_type': 'object',
             'action': 'action_open_project_vendor_bills',
             'show': self.vendor_bill_count > 0,
             'sequence': 48,
         })
     return buttons
Esempio n. 13
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('sales_team.group_sale_salesman_all_leads'):
         buttons.append({
             'icon': 'dollar',
             'text': _lt('Sales Orders'),
             'number': self.sale_order_count,
             'action_type': 'object',
             'action': 'action_view_sos',
             'show': self.sale_order_count > 0,
             'sequence': 1,
         })
     return buttons
Esempio n. 14
0
 def _get_stat_buttons(self):
     buttons = super(Project, self)._get_stat_buttons()
     if self.user_has_groups('account.group_account_readonly'):
         buttons.append({
             'icon':
             'pencil-square-o',
             'text':
             _lt('Invoices'),
             'number':
             self.invoice_count,
             'action_type':
             'object',
             'action':
             'action_open_project_invoices',
             'show':
             bool(self.analytic_account_id) and self.invoice_count > 0,
             'sequence':
             30,
         })
     return buttons
Esempio n. 15
0
class AccountStudentLedger(models.AbstractModel):
    _inherit = "account.report"
    _name = "account.student.ledger"
    _description = "Student Ledger"

    filter_date = {'mode': 'range', 'filter': 'this_year'}
    filter_all_entries = False
    filter_unfold_all = False
    filter_account_type = [
        {
            'id': 'receivable',
            'name': _lt('Receivable'),
            'selected': False
        },
        {
            'id': 'payable',
            'name': _lt('Payable'),
            'selected': False
        },
    ]
    filter_unreconciled = False
    filter_partner = True
    filter_family = True

    ####################################################
    # OPTIONS
    ####################################################
    @api.model
    def _init_filter_partner(self, options, previous_options=None):
        if not self.filter_partner:
            return
        super(AccountStudentLedger,
              self)._init_filter_partner(options, previous_options)
        options['family_ids'] = previous_options and previous_options.get(
            'family_ids') or []
        selected_family_ids = [int(family) for family in options['family_ids']]
        selected_families = selected_family_ids and self.env[
            'res.partner'].browse(
                selected_family_ids) or self.env['res.partner']
        options['selected_family_ids'] = selected_families.mapped('name')
        options['grade_level_ids'] = previous_options and previous_options.get(
            'grade_level_ids') or []
        selected_grade_level_ids = [
            int(category) for category in options['grade_level_ids']
        ]
        selected_grade_levels = selected_grade_level_ids and self.env[
            'school_base.grade_level'].browse(
                selected_grade_level_ids
            ) or self.env['school_base.grade_level']
        options['selected_grade_level_ids'] = selected_grade_levels.mapped(
            'name')
        options['homeroom'] = previous_options and previous_options.get(
            'homeroom') or ''
        options['selected_homeroom'] = options['homeroom']

    @api.model
    def _get_options_account_type(self, options):
        ''' Get select account type in the filter widget (see filter_account_type).
        :param options: The report options.
        :return:        Selected account types.
        '''
        all_account_types = []
        account_types = []
        for account_type_option in options.get('account_type', []):
            if account_type_option['selected']:
                account_types.append(account_type_option)
            all_account_types.append(account_type_option)
        return account_types or all_account_types

    @api.model
    def _get_options_domain(self, options):
        # OVERRIDE
        # Handle filter_unreconciled + filter_account_type
        domain = super(AccountStudentLedger, self)._get_options_domain(options)
        if options.get('unreconciled'):
            domain.append(('full_reconcile_id', '=', False))
        domain.append(
            ('account_id.internal_type', 'in',
             [t['id'] for t in self._get_options_account_type(options)]))
        return domain

    @api.model
    def _get_options_partner_domain(self, options):
        domain = []
        if options.get('partner_ids'):
            student_ids = [int(student) for student in options['partner_ids']]
            domain.append(('student_id', 'in', student_ids))
        if options.get('family_ids'):
            family_ids = [int(family) for family in options['family_ids']]
            domain.append(('family_id', 'in', family_ids))
        if options.get('grade_level_ids'):
            grade_level_ids = [
                int(grade_level) for grade_level in options['grade_level_ids']
            ]
            domain.append(('student_id.grade_level_id', 'in', grade_level_ids))
        if options.get('partner_categories'):
            partner_category_ids = [
                int(category) for category in options['partner_categories']
            ]
            domain.append(
                ('student_id.category_id', 'in', partner_category_ids))
        if options.get('homeroom'):
            domain.append(('homeroom', '=ilike', options['homeroom']))
        return domain

    @api.model
    def _get_options_sum_balance(self, options):
        ''' Create options with the 'strict_range' enabled on the filter_date.
        The resulting dates domain will be:
        [
            ('date' <= options['date_to']),
            ('date' >= options['date_from'])
        ]
        :param options: The report options.
        :return:        A copy of the options.
        '''
        new_options = options.copy()
        new_options['date'] = new_options['date'].copy()
        new_options['date']['strict_range'] = True
        return new_options

    @api.model
    def _get_options_initial_balance(self, options):
        ''' Create options used to compute the initial balances for each partner.
        The resulting dates domain will be:
        [('date' <= options['date_from'] - 1)]
        :param options: The report options.
        :return:        A copy of the options.
        '''
        new_options = options.copy()
        new_options['date'] = new_options['date'].copy()
        new_date_to = fields.Date.from_string(
            new_options['date']['date_from']) - timedelta(days=1)
        new_options['date'].update({
            'date_from':
            False,
            'date_to':
            fields.Date.to_string(new_date_to),
        })
        return new_options

    def _set_context(self, options):
        ctx = super(AccountStudentLedger, self)._set_context(options)
        if options.get('family_ids'):
            ctx['family_ids'] = self.env['res.partner'].browse(
                [int(family) for family in options['family_ids']])
        if options.get('grade_level_ids'):
            ctx['grade_level_ids'] = self.env[
                'school_base.grade_level'].browse([
                    int(grade_level)
                    for grade_level in options['grade_level_ids']
                ])
        if options.get('homeroom'):
            ctx['homeroom'] = options['homeroom']
        return ctx

    def get_report_informations(self, options):
        info = super(AccountStudentLedger,
                     self).get_report_informations(options)
        options = options or self._get_options(options)
        if options.get('family'):
            info['options']['selected_family_ids'] = [
                self.env['res.partner'].browse(int(family)).name
                for family in options['family_ids']
            ]
        if options.get('grade_level'):
            info['options']['selected_grade_level_ids'] = [
                self.env['school_base.grade_level'].browse(
                    int(grade_level)).name
                for grade_level in options['grade_level_ids']
            ]
        if options.get('homeroom'):
            info['options']['selected_grade_level_ids'] = options['homeroom']
        return info

    ####################################################
    # QUERIES
    ####################################################

    @api.model
    def _get_query_sums(self, options, expanded_partner=None):
        ''' Construct a query retrieving all the aggregated sums to build the report. It includes:
        - sums for all accounts.
        - sums for the initial balances.
        - sums for the unaffected earnings.
        - sums for the tax declaration.
        :param options:             The report options.
        :param expanded_partner:    An optional account.account record that must be specified when expanding a line
                                    with of without the load more.
        :return:                    (query, params)
        '''
        params = []
        queries = []

        if expanded_partner:
            if expanded_partner.id == self.env.company.partner_id.id:
                domain = [('student_id', '=', False)]
            else:
                domain = [('student_id', '=', expanded_partner.id)]
        else:
            domain = []

        # Create the currency table.
        ct_query = self._get_query_currency_table(options)

        # Get sums for all partners.
        # period: [('date' <= options['date_to']), ('date' >= options['date_from'])]
        new_options = self._get_options_sum_balance(options)
        tables, where_clause, where_params = self._query_get(new_options,
                                                             domain=domain)
        params += where_params
        queries.append('''
            SELECT
                account_move_line.student_id        AS groupby,
                'sum'                               AS key,
                SUM(ROUND(account_move_line.debit * currency_table.rate, currency_table.precision))   AS debit,
                SUM(ROUND(account_move_line.credit * currency_table.rate, currency_table.precision))  AS credit,
                SUM(ROUND(account_move_line.balance * currency_table.rate, currency_table.precision)) AS balance
            FROM %s
            LEFT JOIN %s ON currency_table.company_id = account_move_line.company_id
            WHERE %s
            GROUP BY account_move_line.student_id
        ''' % (tables, ct_query, where_clause))

        # Get sums for the initial balance.
        # period: [('date' <= options['date_from'] - 1)]
        new_options = self._get_options_initial_balance(options)
        tables, where_clause, where_params = self._query_get(new_options,
                                                             domain=domain)
        params += where_params
        queries.append('''
            SELECT
                account_move_line.student_id        AS groupby,
                'initial_balance'                   AS key,
                SUM(ROUND(account_move_line.debit * currency_table.rate, currency_table.precision))   AS debit,
                SUM(ROUND(account_move_line.credit * currency_table.rate, currency_table.precision))  AS credit,
                SUM(ROUND(account_move_line.balance * currency_table.rate, currency_table.precision)) AS balance
            FROM %s
            LEFT JOIN %s ON currency_table.company_id = account_move_line.company_id
            WHERE %s
            GROUP BY account_move_line.student_id
        ''' % (tables, ct_query, where_clause))

        return ' UNION ALL '.join(queries), params

    @api.model
    def _get_query_amls(self,
                        options,
                        expanded_partner=None,
                        offset=None,
                        limit=None):
        ''' Construct a query retrieving the account.move.lines when expanding a report line with or without the load
        more.
        :param options:             The report options.
        :param expanded_partner:    The res.partner record corresponding to the expanded line.
        :param offset:              The offset of the query (used by the load more).
        :param limit:               The limit of the query (used by the load more).
        :return:                    (query, params)
        '''
        unfold_all = options.get('unfold_all') or (
            self._context.get('print_mode') and not options['unfolded_lines'])

        # Get sums for the account move lines.
        # period: [('date' <= options['date_to']), ('date', '>=', options['date_from'])]
        if expanded_partner:
            if expanded_partner.id == self.env.company.partner_id.id:
                domain = [('student_id', '=', False)]
            else:
                domain = [('student_id', '=', expanded_partner.id)]
        elif unfold_all:
            domain = []
        elif options['unfolded_lines']:
            domain = [('student_id', 'in',
                       [int(line[8:]) for line in options['unfolded_lines']])]

        new_options = self._get_options_sum_balance(options)
        tables, where_clause, where_params = self._query_get(new_options,
                                                             domain=domain)
        ct_query = self._get_query_currency_table(options)

        query = '''
            SELECT
                account_move_line.id,
                account_move_line.date,
                account_move_line.date_maturity,
                account_move_line.name,
                account_move_line.ref,
                account_move_line.company_id,
                account_move_line.account_id,             
                account_move_line.payment_id,
                account_move_line.student_id,
                account_move_line.currency_id,
                account_move_line.amount_currency,
                ROUND(account_move_line.debit * currency_table.rate, currency_table.precision)   AS debit,
                ROUND(account_move_line.credit * currency_table.rate, currency_table.precision)  AS credit,
                ROUND(account_move_line.balance * currency_table.rate, currency_table.precision) AS balance,
                account_move_line__move_id.name         AS move_name,
                company.currency_id                     AS company_currency_id,
                partner.name                            AS partner_name,
                account_move_line__move_id.type         AS move_type,
                account.code                            AS account_code,
                account.name                            AS account_name,
                journal.code                            AS journal_code,
                journal.name                            AS journal_name,
                full_rec.name                           AS full_rec_name
            FROM account_move_line
            LEFT JOIN account_move account_move_line__move_id ON account_move_line__move_id.id = account_move_line.move_id
            LEFT JOIN %s ON currency_table.company_id = account_move_line.company_id
            LEFT JOIN res_company company               ON company.id = account_move_line.company_id
            LEFT JOIN res_partner partner               ON partner.id = account_move_line.student_id
            LEFT JOIN account_account account           ON account.id = account_move_line.account_id
            LEFT JOIN account_journal journal           ON journal.id = account_move_line.journal_id
            LEFT JOIN account_full_reconcile full_rec   ON full_rec.id = account_move_line.full_reconcile_id
            WHERE %s
            ORDER BY account_move_line.id
        ''' % (ct_query, where_clause)

        if offset:
            query += ' OFFSET %s '
            where_params.append(offset)
        if limit:
            query += ' LIMIT %s '
            where_params.append(limit)

        return query, where_params

    @api.model
    def _do_query(self, options, expanded_partner=None):
        ''' Execute the queries, perform all the computation and return partners_results,
        a lists of tuple (partner, fetched_values) sorted by the table's model _order:
            - partner is a res.parter record.
            - fetched_values is a dictionary containing:
                - sum:                              {'debit': float, 'credit': float, 'balance': float}
                - (optional) initial_balance:       {'debit': float, 'credit': float, 'balance': float}
                - (optional) lines:                 [line_vals_1, line_vals_2, ...]
        :param options:             The report options.
        :param expanded_account:    An optional account.account record that must be specified when expanding a line
                                    with of without the load more.
        :param fetch_lines:         A flag to fetch the account.move.lines or not (the 'lines' key in accounts_values).
        :return:                    (accounts_values, taxes_results)
        '''
        company_currency = self.env.company.currency_id

        # Execute the queries and dispatch the results.
        query, params = self._get_query_sums(options,
                                             expanded_partner=expanded_partner)

        groupby_partners = {}

        self._cr.execute(query, params)
        for res in self._cr.dictfetchall():
            key = res['key']
            if key == 'sum':
                if not company_currency.is_zero(
                        res['debit']) or not company_currency.is_zero(
                            res['credit']):
                    groupby_partners.setdefault(res['groupby'], {})
                    groupby_partners[res['groupby']][key] = res
            elif key == 'initial_balance':
                if not company_currency.is_zero(res['balance']):
                    groupby_partners.setdefault(res['groupby'], {})
                    groupby_partners[res['groupby']][key] = res

        # Fetch the lines of unfolded accounts.
        unfold_all = options.get('unfold_all') or (
            self._context.get('print_mode') and not options['unfolded_lines'])
        if expanded_partner or unfold_all or options['unfolded_lines']:
            query, params = self._get_query_amls(
                options, expanded_partner=expanded_partner)
            self._cr.execute(query, params)
            for res in self._cr.dictfetchall():
                if res['student_id'] not in groupby_partners:
                    continue
                groupby_partners[res['student_id']].setdefault('lines', [])
                groupby_partners[res['student_id']]['lines'].append(res)

        # Retrieve the partners to browse.
        # groupby_partners.keys() contains all account ids affected by:
        # - the amls in the current period.
        # - the amls affecting the initial balance.
        # Note a search is done instead of a browse to preserve the table ordering.
        if groupby_partners.get(None):
            groupby_partners[
                self.env.company.partner_id.id] = groupby_partners.pop(None)

        if expanded_partner:
            partners = expanded_partner
        elif groupby_partners:
            partners = self.env['res.partner'].with_context(
                active_test=False).search([('id', 'in',
                                            list(groupby_partners.keys()))])
        else:
            partners = []
        return [(partner, groupby_partners[partner.id])
                for partner in partners]

    ####################################################
    # COLUMNS/LINES
    ####################################################

    @api.model
    def _get_report_line_partner(self, options, partner, initial_balance,
                                 debit, credit, balance):
        company_currency = self.env.company.currency_id
        unfold_all = self._context.get(
            'print_mode') and not options.get('unfolded_lines')

        columns = [
            {
                'name': self.format_value(initial_balance),
                'class': 'number'
            },
            {
                'name': self.format_value(debit),
                'class': 'number'
            },
            {
                'name': self.format_value(credit),
                'class': 'number'
            },
        ]
        if self.user_has_groups('base.group_multi_currency'):
            columns.append({'name': ''})
        columns.append({'name': self.format_value(balance), 'class': 'number'})

        return {
            'id':
            'partner_%s' % partner.id,
            'name':
            'Undefined' if partner.id == self.env.company.partner_id.id else
            partner.name[:128],
            'columns':
            columns,
            'level':
            2,
            'trust':
            partner.trust,
            'unfoldable':
            not company_currency.is_zero(debit)
            or not company_currency.is_zero(credit),
            'unfolded':
            'partner_%s' % partner.id in options['unfolded_lines']
            or unfold_all,
            'colspan':
            6,
        }

    @api.model
    def _get_report_line_move_line(self, options, partner, aml,
                                   cumulated_init_balance, cumulated_balance):
        if aml['payment_id']:
            caret_type = 'account.payment'
        elif aml['move_type'] in ('in_refund', 'in_invoice', 'in_receipt'):
            caret_type = 'account.invoice.in'
        elif aml['move_type'] in ('out_refund', 'out_invoice', 'out_receipt'):
            caret_type = 'account.invoice.out'
        else:
            caret_type = 'account.move'

        date_maturity = aml['date_maturity'] and format_date(
            self.env, fields.Date.from_string(aml['date_maturity']))
        columns = [
            {
                'name': aml['journal_code']
            },
            {
                'name': aml['account_code']
            },
            {
                'name':
                self._format_aml_name(aml['name'], aml['ref'],
                                      aml['move_name'])
            },
            {
                'name': date_maturity or '',
                'class': 'date'
            },
            {
                'name': aml['full_rec_name'] or ''
            },
            {
                'name': self.format_value(cumulated_init_balance),
                'class': 'number'
            },
            {
                'name': self.format_value(aml['debit'], blank_if_zero=True),
                'class': 'number'
            },
            {
                'name': self.format_value(aml['credit'], blank_if_zero=True),
                'class': 'number'
            },
        ]
        if self.user_has_groups('base.group_multi_currency'):
            if aml['currency_id']:
                currency = self.env['res.currency'].browse(aml['currency_id'])
                formatted_amount = self.format_value(aml['amount_currency'],
                                                     currency=currency,
                                                     blank_if_zero=True)
                columns.append({'name': formatted_amount, 'class': 'number'})
            else:
                columns.append({'name': ''})
        columns.append({
            'name': self.format_value(cumulated_balance),
            'class': 'number'
        })
        return {
            'id': aml['id'],
            'parent_id': 'partner_%s' % partner.id,
            'name': format_date(self.env, aml['date']),
            'class': 'date',
            'columns': columns,
            'caret_options': caret_type,
            'level': 4,
        }

    @api.model
    def _get_report_line_load_more(self, options, partner, offset, remaining,
                                   progress):
        return {
            'id':
            'loadmore_%s' % partner.id,
            'offset':
            offset,
            'progress':
            progress,
            'remaining':
            remaining,
            'class':
            'o_account_reports_load_more text-center',
            'parent_id':
            'account_%s' % partner.id,
            'name':
            _('Load more... (%s remaining)' % remaining),
            'colspan':
            10 if self.user_has_groups('base.group_multi_currency') else 9,
            'columns': [{}],
        }

    @api.model
    def _get_report_line_total(self, options, initial_balance, debit, credit,
                               balance):
        columns = [
            {
                'name': self.format_value(initial_balance),
                'class': 'number'
            },
            {
                'name': self.format_value(debit),
                'class': 'number'
            },
            {
                'name': self.format_value(credit),
                'class': 'number'
            },
        ]
        if self.user_has_groups('base.group_multi_currency'):
            columns.append({'name': ''})
        columns.append({'name': self.format_value(balance), 'class': 'number'})
        return {
            'id': 'partner_ledger_total_%s' % self.env.company.id,
            'name': _('Total'),
            'class': 'total',
            'level': 1,
            'columns': columns,
            'colspan': 6,
        }

    @api.model
    def _get_partner_ledger_lines(self, options, line_id=None):
        ''' Get lines for the whole report or for a specific line.
        :param options: The report options.
        :return:        A list of lines, each one represented by a dictionary.
        '''
        lines = []
        unfold_all = options.get('unfold_all') or (
            self._context.get('print_mode') and not options['unfolded_lines'])

        expanded_partner = line_id and self.env['res.partner'].browse(
            int(line_id[8:]))
        partners_results = self._do_query(options,
                                          expanded_partner=expanded_partner)

        total_initial_balance = total_debit = total_credit = total_balance = 0.0
        for partner, results in partners_results:
            is_unfolded = 'partner_%s' % partner.id in options[
                'unfolded_lines']

            # res.partner record line.
            partner_sum = results.get('sum', {})
            partner_init_bal = results.get('initial_balance', {})

            initial_balance = partner_init_bal.get('balance', 0.0)
            debit = partner_sum.get('debit', 0.0)
            credit = partner_sum.get('credit', 0.0)
            balance = initial_balance + partner_sum.get('balance', 0.0)

            lines.append(
                self._get_report_line_partner(options, partner,
                                              initial_balance, debit, credit,
                                              balance))

            total_initial_balance += initial_balance
            total_debit += debit
            total_credit += credit
            total_balance += balance

            if unfold_all or is_unfolded:
                cumulated_balance = initial_balance

                # account.move.line record lines.
                amls = results.get('lines', [])

                load_more_remaining = len(amls)
                load_more_counter = self._context.get(
                    'print_mode') and load_more_remaining or self.MAX_LINES

                for aml in amls:
                    # Don't show more line than load_more_counter.
                    if load_more_counter == 0:
                        break

                    cumulated_init_balance = cumulated_balance
                    cumulated_balance += aml['balance']
                    lines.append(
                        self._get_report_line_move_line(
                            options, partner, aml, cumulated_init_balance,
                            cumulated_balance))

                    load_more_remaining -= 1
                    load_more_counter -= 1

                if load_more_remaining > 0:
                    # Load more line.
                    lines.append(
                        self._get_report_line_load_more(
                            options,
                            partner,
                            self.MAX_LINES,
                            load_more_remaining,
                            cumulated_balance,
                        ))

        if not line_id:
            # Report total line.
            lines.append(
                self._get_report_line_total(options, total_initial_balance,
                                            total_debit, total_credit,
                                            total_balance))
        return lines

    @api.model
    def _load_more_lines(self, options, line_id, offset, load_more_remaining,
                         progress):
        ''' Get lines for an expanded line using the load more.
        :param options: The report options.
        :return:        A list of lines, each one represented by a dictionary.
        '''
        lines = []

        expanded_partner = line_id and self.env['res.partner'].browse(
            int(line_id[9:]))

        load_more_counter = self.MAX_LINES

        # Fetch the next batch of lines.
        amls_query, amls_params = self._get_query_amls(
            options,
            expanded_partner=expanded_partner,
            offset=offset,
            limit=load_more_counter)
        self._cr.execute(amls_query, amls_params)
        for aml in self._cr.dictfetchall():
            # Don't show more line than load_more_counter.
            if load_more_counter == 0:
                break

            cumulated_init_balance = progress
            progress += aml['balance']

            # account.move.line record line.
            lines.append(
                self._get_report_line_move_line(options, expanded_partner, aml,
                                                cumulated_init_balance,
                                                progress))

            offset += 1
            load_more_remaining -= 1
            load_more_counter -= 1

        if load_more_remaining > 0:
            # Load more line.
            lines.append(
                self._get_report_line_load_more(
                    options,
                    expanded_partner,
                    offset,
                    load_more_remaining,
                    progress,
                ))
        return lines

    def _get_columns_name(self, options):
        columns = [{}, {
            'name': _('JRNL')
        }, {
            'name': _('Account')
        }, {
            'name': _('Ref')
        }, {
            'name': _('Due Date'),
            'class': 'date'
        }, {
            'name': _('Matching Number')
        }, {
            'name': _('Initial Balance'),
            'class': 'number'
        }, {
            'name': _('Debit'),
            'class': 'number'
        }, {
            'name': _('Credit'),
            'class': 'number'
        }]

        if self.user_has_groups('base.group_multi_currency'):
            columns.append({'name': _('Amount Currency'), 'class': 'number'})

        columns.append({'name': _('Balance'), 'class': 'number'})
        return columns

    @api.model
    def _get_lines(self, options, line_id=None):
        offset = int(options.get('lines_offset', 0))
        remaining = int(options.get('lines_remaining', 0))
        balance_progress = float(options.get('lines_progress', 0))

        if offset > 0:
            # Case a line is expanded using the load more.
            res = self._load_more_lines(options, line_id, offset, remaining,
                                        balance_progress)
            return res
        else:
            # Case the whole report is loaded or a line is expanded for the first time.
            res = self._get_partner_ledger_lines(options, line_id=line_id)
            return res

    @api.model
    def _get_report_name(self):
        return _('Student Ledger')
Esempio n. 16
0
        'sum'] else sql_results[0]['sum']

    net_new_mrr = new_mrr - churned_mrr + expansion_mrr - down_mrr

    return {
        'new_mrr': new_mrr,
        'churned_mrr': -churned_mrr,
        'expansion_mrr': expansion_mrr,
        'down_mrr': -down_mrr,
        'net_new_mrr': net_new_mrr,
    }


STAT_TYPES = {
    'mrr': {
        'name': _lt('Monthly Recurring Revenue'),
        'code': 'mrr',
        'dir': 'up',
        'prior': 1,
        'type': 'last',
        'add_symbol': 'currency',
        'compute': compute_mrr
    },
    'net_revenue': {
        'name': _lt('Net Revenue'),
        'code': 'net_revenue',
        'dir': 'up',
        'prior': 2,
        'type': 'sum',
        'add_symbol': 'currency',
        'compute': compute_net_revenue
Esempio n. 17
0
 def _get_profitability_labels(self):
     labels = super()._get_profitability_labels()
     labels['manufacturing_order'] = _lt('Manufacturing Orders')
     return labels
Esempio n. 18
0
            currency_fields = [
                k for k, v in fields
                if v.type == 'many2one' and v.comodel_name == 'res.currency'
            ]
            if currency_fields:
                options['display_currency'] = record[currency_fields[0]]
        if 'date' not in options:
            options['date'] = record._context.get('date')
        if 'company_id' not in options:
            options['company_id'] = record._context.get('company_id')

        return super(MonetaryConverter,
                     self).record_to_html(record, field_name, options)


TIMEDELTA_UNITS = (('year', _lt('year'),
                    3600 * 24 * 365), ('month', _lt('month'), 3600 * 24 * 30),
                   ('week', _lt('week'), 3600 * 24 * 7),
                   ('day', _lt('day'), 3600 * 24), ('hour', _lt('hour'), 3600),
                   ('minute', _lt('minute'), 60), ('second', _lt('second'), 1))


class FloatTimeConverter(models.AbstractModel):
    """ ``float_time`` converter, to display integral or fractional values as
    human-readable time spans (e.g. 1.5 as "01:30").

    Can be used on any numerical field.
    """
    _name = 'ir.qweb.field.float_time'
    _description = 'Qweb Field Float Time'
    _inherit = 'ir.qweb.field'
class IntrastatReport(models.AbstractModel):
    _name = 'account.intrastat.report'
    _description = 'Intrastat Report'
    _inherit = 'account.report'

    filter_date = {'mode': 'range', 'filter': 'this_month'}
    filter_journals = True
    filter_multi_company = None
    filter_with_vat = False
    filter_intrastat_type = [
        {
            'name': _lt('Arrival'),
            'selected': False,
            'id': 'arrival'
        },
        {
            'name': _lt('Dispatch'),
            'selected': False,
            'id': 'dispatch'
        },
    ]
    filter_intrastat_extended = True

    def _get_filter_journals(self):
        #only show sale/purchase journals
        return self.env['account.journal'].search(
            [('company_id', 'in', self.env.companies.ids
              or [self.env.company.id]), ('type', 'in', ('sale', 'purchase'))],
            order="company_id, name")

    def _get_columns_name(self, options):
        columns = [
            {
                'name': ''
            },
            {
                'name': _('Date')
            },
            {
                'name': _('System')
            },
            {
                'name': _('Country Code')
            },
            {
                'name': _('Transaction Code')
            },
            {
                'name': _('Region Code')
            },
            {
                'name': _('Commodity Code')
            },
            {
                'name': _('Type')
            },
            {
                'name': _('Origin Country')
            },
            {
                'name': _('Partner VAT')
            },
        ]
        if options.get('intrastat_extended'):
            columns += [
                {
                    'name': _('Transport Code')
                },
                {
                    'name': _('Incoterm Code')
                },
            ]
        columns += [
            {
                'name': _('Weight')
            },
            {
                'name': _('Quantity')
            },
            {
                'name': _('Value'),
                'class': 'number'
            },
        ]
        return columns

    @api.model
    def _create_intrastat_report_line(self, options, vals):
        caret_options = 'account.invoice.%s' % (
            vals['invoice_type'] in ('in_invoice', 'in_refund') and 'in'
            or 'out')

        columns = [{
            'name': c
        } for c in [
            vals['invoice_date'],
            vals['system'],
            vals['country_code'],
            vals['trans_code'],
            vals['region_code'],
            vals['commodity_code'],
            vals['type'],
            vals['intrastat_product_origin_country'],
            vals['partner_vat'],
        ]]
        if options.get('intrastat_extended'):
            columns += [{
                'name': c
            } for c in [
                vals['invoice_transport'] or vals['company_transport'] or '',
                vals['invoice_incoterm'] or vals['company_incoterm'] or '',
            ]]

        columns += [{
            'name': c
        } for c in [
            vals['weight'], vals['quantity'],
            self.format_value(vals['value'])
        ]]

        return {
            'id': vals['id'],
            'caret_options': caret_options,
            'model': 'account.move.line',
            'name': vals['invoice_number'],
            'columns': columns,
            'level': 2,
        }

    @api.model
    def _decode_options(self, options):
        journal_ids = self.env['account.journal'].search([
            ('type', 'in', ('sale', 'purchase'))
        ]).ids
        if options.get('journals'):
            journal_ids = [
                c['id'] for c in options['journals'] if c.get('selected')
            ] or journal_ids

        if options.get('intrastat_type'):
            incl_arrivals = options['intrastat_type'][0]['selected']
            incl_dispatches = options['intrastat_type'][1]['selected']
            if not incl_arrivals and not incl_dispatches:
                incl_arrivals = incl_dispatches = True
        else:
            incl_arrivals = incl_dispatches = True

        return options['date']['date_from'], options['date']['date_to'], journal_ids, \
            incl_arrivals, incl_dispatches, options.get('intrastat_extended'), options.get('with_vat')

    @api.model
    def _prepare_query(self,
                       date_from,
                       date_to,
                       journal_ids,
                       invoice_types=None,
                       with_vat=False):
        query_blocks, params = self._build_query(date_from,
                                                 date_to,
                                                 journal_ids,
                                                 invoice_types=invoice_types,
                                                 with_vat=with_vat)
        query = 'SELECT %(select)s FROM %(from)s WHERE %(where)s ORDER BY %(order)s' % query_blocks
        return query, params

    @api.model
    def _build_query(self,
                     date_from,
                     date_to,
                     journal_ids,
                     invoice_types=None,
                     with_vat=False):
        # triangular use cases are handled by letting the intrastat_country_id editable on
        # invoices. Modifying or emptying it allow to alter the intrastat declaration
        # accordingly to specs (https://www.nbb.be/doc/dq/f_pdf_ex/intra2017fr.pdf (§ 4.x))
        select = '''
                row_number() over () AS sequence,
                CASE WHEN inv.move_type IN ('in_invoice', 'out_refund') THEN %(import_merchandise_code)s ELSE %(export_merchandise_code)s END AS system,
                country.code AS country_code,
                company_country.code AS comp_country_code,
                CASE WHEN inv_line.intrastat_transaction_id IS NULL THEN '1' ELSE transaction.code END AS transaction_code,
                company_region.code AS region_code,
                code.code AS commodity_code,
                inv_line.id AS id,
                prodt.id AS template_id,
                inv.id AS invoice_id,
                inv.currency_id AS invoice_currency_id,
                inv.name AS invoice_number,
                coalesce(inv.date, inv.invoice_date) AS invoice_date,
                inv.move_type AS invoice_type,
                inv_incoterm.code AS invoice_incoterm,
                comp_incoterm.code AS company_incoterm,
                inv_transport.code AS invoice_transport,
                comp_transport.code AS company_transport,
                CASE WHEN inv_line.intrastat_transaction_id IS NULL THEN '1' ELSE transaction.code END AS trans_code,
                CASE WHEN inv.move_type IN ('in_invoice', 'out_refund') THEN 'Arrival' ELSE 'Dispatch' END AS type,
                prod.weight * inv_line.quantity * (
                    CASE WHEN inv_line_uom.category_id IS NULL OR inv_line_uom.category_id = prod_uom.category_id
                    THEN 1 ELSE inv_line_uom.factor END
                ) AS weight,
                inv_line.quantity * (
                    CASE WHEN inv_line_uom.category_id IS NULL OR inv_line_uom.category_id = prod_uom.category_id
                    THEN 1 ELSE inv_line_uom.factor END
                ) AS quantity,
                inv_line.price_subtotal AS value,
                CASE WHEN inv_line.intrastat_product_origin_country_id IS NULL
                     THEN \'QU\'  -- If you don't know the country of origin of the goods, as an exception you may replace the country code by "QU".
                     ELSE product_country.code
                END AS intrastat_product_origin_country,
                CASE WHEN partner_country.id IS NULL
                     THEN \'QV999999999999\'  -- For VAT numbers of companies outside the European Union, for example in the case of triangular trade, you always have to use the code "QV999999999999".
                     ELSE partner.vat
                END AS partner_vat
                '''
        from_ = '''
                account_move_line inv_line
                LEFT JOIN account_move inv ON inv_line.move_id = inv.id
                LEFT JOIN account_intrastat_code transaction ON inv_line.intrastat_transaction_id = transaction.id
                LEFT JOIN res_company company ON inv.company_id = company.id
                LEFT JOIN account_intrastat_code company_region ON company.intrastat_region_id = company_region.id
                LEFT JOIN res_partner partner ON inv_line.partner_id = partner.id
                LEFT JOIN res_partner comp_partner ON company.partner_id = comp_partner.id
                LEFT JOIN res_country country ON inv.intrastat_country_id = country.id
                LEFT JOIN res_country company_country ON comp_partner.country_id = company_country.id
                INNER JOIN product_product prod ON inv_line.product_id = prod.id
                LEFT JOIN product_template prodt ON prod.product_tmpl_id = prodt.id
                LEFT JOIN account_intrastat_code code ON prodt.intrastat_id = code.id
                LEFT JOIN uom_uom inv_line_uom ON inv_line.product_uom_id = inv_line_uom.id
                LEFT JOIN uom_uom prod_uom ON prodt.uom_id = prod_uom.id
                LEFT JOIN account_incoterms inv_incoterm ON inv.invoice_incoterm_id = inv_incoterm.id
                LEFT JOIN account_incoterms comp_incoterm ON company.incoterm_id = comp_incoterm.id
                LEFT JOIN account_intrastat_code inv_transport ON inv.intrastat_transport_mode_id = inv_transport.id
                LEFT JOIN account_intrastat_code comp_transport ON company.intrastat_transport_mode_id = comp_transport.id
                LEFT JOIN res_country product_country ON product_country.id = inv_line.intrastat_product_origin_country_id
                LEFT JOIN res_country partner_country ON partner.country_id = partner_country.id AND partner_country.intrastat IS TRUE
                '''
        where = '''
                inv.state = 'posted'
                AND inv_line.display_type IS NULL
                AND NOT inv_line.quantity = 0
                AND inv.company_id = %(company_id)s
                AND company_country.id != country.id
                AND country.intrastat = TRUE
                AND coalesce(inv.date, inv.invoice_date) >= %(date_from)s
                AND coalesce(inv.date, inv.invoice_date) <= %(date_to)s
                AND prodt.type != 'service'
                AND inv.journal_id IN %(journal_ids)s
                AND inv.move_type IN %(invoice_types)s
                AND NOT inv_line.exclude_from_invoice_tab
                '''
        order = 'inv.invoice_date DESC'
        params = {
            'company_id':
            self.env.company.id,
            'import_merchandise_code':
            _merchandise_import_code.get(self.env.company.country_id.code,
                                         '29'),
            'export_merchandise_code':
            _merchandise_export_code.get(self.env.company.country_id.code,
                                         '19'),
            'date_from':
            date_from,
            'date_to':
            date_to,
            'journal_ids':
            tuple(journal_ids),
        }
        if with_vat:
            where += ' AND partner.vat IS NOT NULL '
        if invoice_types:
            params['invoice_types'] = tuple(invoice_types)
        else:
            params['invoice_types'] = ('out_invoice', 'out_refund',
                                       'in_invoice', 'in_refund')
        query = {
            'select': select,
            'from': from_,
            'where': where,
            'order': order,
        }
        return query, params

    @api.model
    def _fill_missing_values(self, vals, cache=None):
        ''' Some values are too complex to be retrieved in the SQL query.
        Then, this method is used to compute the missing values fetched from the database.

        :param vals:    A dictionary created by the dictfetchall method.
        :param cache:   A cache dictionary used to avoid performance loss.
        '''
        if cache is None:
            cache = {}

        # Prefetch data before looping
        self.env['product.template'].browse([v['template_id']
                                             for v in vals]).read(
                                                 ['intrastat_id', 'categ_id'])
        self.env['product.category'].search([]).read(
            ['intrastat_id', 'parent_id'])

        for index in range(len(vals)):
            # Check account.intrastat.code
            # If missing, retrieve the commodity code by looking in the product category recursively.
            if not vals[index]['commodity_code']:
                cache_key = 'commodity_code_%d' % vals[index]['template_id']
                if cache_key not in cache:
                    product = self.env['product.template'].browse(
                        vals[index]['template_id'])
                    intrastat_code = product.search_intrastat_code()
                    cache[cache_key] = vals[index][
                        'commodity_code'] = intrastat_code.code
                vals[index]['commodity_code'] = cache.get(cache_key)

            # Check the currency.
            cache_key = 'currency_%d' % vals[index]['invoice_currency_id']
            if cache_key not in cache:
                cache[cache_key] = self.env['res.currency'].browse(
                    vals[index]['invoice_currency_id'])

            company_currency_id = self.env.company.currency_id
            if cache[cache_key] != company_currency_id:
                vals[index]['value'] = cache[cache_key]._convert(
                    vals[index]['value'], company_currency_id,
                    self.env.company, vals[index]['invoice_date'])
        return vals

    @api.model
    def _get_lines(self, options, line_id=None):
        self.env['account.move.line'].check_access_rights('read')

        date_from, date_to, journal_ids, incl_arrivals, incl_dispatches, extended, with_vat = self._decode_options(
            options)

        invoice_types = []
        if incl_arrivals:
            invoice_types += ['in_invoice', 'out_refund']
        if incl_dispatches:
            invoice_types += ['out_invoice', 'in_refund']

        query, params = self._prepare_query(date_from,
                                            date_to,
                                            journal_ids,
                                            invoice_types=invoice_types,
                                            with_vat=with_vat)

        self._cr.execute(query, params)
        query_res = self._cr.dictfetchall()

        # Create lines
        lines = []
        total_value = 0
        for vals in self._fill_missing_values(query_res):
            line = self._create_intrastat_report_line(options, vals)
            lines.append(line)
            total_value += vals['value']

        # Create total line if only one type selected.
        if incl_arrivals != incl_dispatches:
            colspan = 12 if extended else 10
            lines.append({
                'id':
                0,
                'name':
                _('Total'),
                'class':
                'total',
                'level':
                2,
                'columns': [{
                    'name': v
                } for v in [self.format_value(total_value)]],
                'colspan':
                colspan,
            })
        return lines

    @api.model
    def _get_report_name(self):
        return _('Intrastat Report')
Esempio n. 20
0
class ReportPartnerLedger(models.AbstractModel):
    _inherit = "account.report"
    _name = "account.partner.ledger"
    _description = "Partner Ledger"

    filter_date = {'mode': 'range', 'filter': 'this_year'}
    filter_all_entries = False
    filter_unfold_all = False
    filter_account_type = [
        {
            'id': 'receivable',
            'name': _lt('Receivable'),
            'selected': False
        },
        {
            'id': 'payable',
            'name': _lt('Payable'),
            'selected': False
        },
    ]
    filter_unreconciled = False
    filter_partner = True

    @api.model
    def _get_templates(self):
        templates = super(ReportPartnerLedger, self)._get_templates()
        templates[
            'line_template'] = 'account_reports.line_template_partner_ledger_report'
        templates[
            'main_template'] = 'account_reports.main_template_with_filter_input_partner'
        return templates

    ####################################################
    # OPTIONS
    ####################################################

    @api.model
    def _get_options_account_type(self, options):
        ''' Get select account type in the filter widget (see filter_account_type).
        :param options: The report options.
        :return:        Selected account types.
        '''
        all_account_types = []
        account_types = []
        for account_type_option in options.get('account_type', []):
            if account_type_option['selected']:
                account_types.append(account_type_option)
            all_account_types.append(account_type_option)
        return account_types or all_account_types

    @api.model
    def _get_options_domain(self, options):
        # OVERRIDE
        # Handle filter_unreconciled + filter_account_type
        domain = super(ReportPartnerLedger, self)._get_options_domain(options)
        if options.get('unreconciled'):
            domain.append(('full_reconcile_id', '=', False))
        if self.env.context.get('model') == 'account.partner.ledger':
            domain += [
                '!', '&', '&', '&', ('credit', '=', 0.0), ('debit', '=', 0.0),
                ('amount_currency', '!=', 0.0), ('ref', 'ilike', 'EXCH%')
            ]
        domain.append(
            ('account_id.internal_type', 'in',
             [t['id'] for t in self._get_options_account_type(options)]))

        return domain

    @api.model
    def _get_options_sum_balance(self, options):
        ''' Create options with the 'strict_range' enabled on the filter_date.
        The resulting dates domain will be:
        [
            ('date' <= options['date_to']),
            ('date' >= options['date_from'])
        ]
        :param options: The report options.
        :return:        A copy of the options.
        '''
        new_options = options.copy()
        new_options['date'] = new_options['date'].copy()
        new_options['date']['strict_range'] = True
        return new_options

    @api.model
    def _get_options_initial_balance(self, options):
        ''' Create options used to compute the initial balances for each partner.
        The resulting dates domain will be:
        [('date' <= options['date_from'] - 1)]
        :param options: The report options.
        :return:        A copy of the options.
        '''
        new_options = options.copy()
        new_options['date'] = new_options['date'].copy()
        new_date_to = fields.Date.from_string(
            new_options['date']['date_from']) - timedelta(days=1)
        new_options['date'].update({
            'date_from':
            False,
            'date_to':
            fields.Date.to_string(new_date_to),
        })
        return new_options

    @api.model
    def _get_options_without_partner(self, options):
        ''' Create options used to compute the special case of lines without partner reconcile
        with another line having a partner for each partner.
        :param options: The report options.
        :return:        A copy of the options.
        '''
        new_options = options.copy()
        new_options['date'] = new_options['date'].copy()
        new_options['date'].update({
            'date_from': False,
        })
        return new_options

    ####################################################
    # QUERIES
    ####################################################

    @api.model
    def _get_query_sums(self, options, expanded_partner=None):
        ''' Construct a query retrieving all the aggregated sums to build the report. It includes:
        - sums for all partners.
        - sums for the initial balances.
        :param options:             The report options.
        :param expanded_partner:    An optional res.partner record that must be specified when expanding a line
                                    with of without the load more.
        :return:                    (query, params)
        '''
        params = []
        queries = []

        if expanded_partner is not None:
            domain = [('partner_id', '=', expanded_partner.id)]
        else:
            domain = []

        # Create the currency table.
        ct_query = self.env['res.currency']._get_query_currency_table(options)

        # Get sums for all partners.
        # period: [('date' <= options['date_to']), ('date' >= options['date_from'])]
        new_options = self._get_options_sum_balance(options)
        tables, where_clause, where_params = self._query_get(new_options,
                                                             domain=domain)
        params += where_params
        queries.append('''
            SELECT
                account_move_line.partner_id        AS groupby,
                'sum'                               AS key,
                SUM(ROUND(account_move_line.debit * currency_table.rate, currency_table.precision))   AS debit,
                SUM(ROUND(account_move_line.credit * currency_table.rate, currency_table.precision))  AS credit,
                SUM(ROUND(account_move_line.balance * currency_table.rate, currency_table.precision)) AS balance
            FROM %s
            LEFT JOIN %s ON currency_table.company_id = account_move_line.company_id
            WHERE %s
            GROUP BY account_move_line.partner_id
        ''' % (tables, ct_query, where_clause))

        # Get sums for the initial balance.
        # period: [('date' <= options['date_from'] - 1)]
        new_options = self._get_options_initial_balance(options)
        tables, where_clause, where_params = self._query_get(new_options,
                                                             domain=domain)
        params += where_params
        queries.append('''
            SELECT
                account_move_line.partner_id        AS groupby,
                'initial_balance'                   AS key,
                SUM(ROUND(account_move_line.debit * currency_table.rate, currency_table.precision))   AS debit,
                SUM(ROUND(account_move_line.credit * currency_table.rate, currency_table.precision))  AS credit,
                SUM(ROUND(account_move_line.balance * currency_table.rate, currency_table.precision)) AS balance
            FROM %s
            LEFT JOIN %s ON currency_table.company_id = account_move_line.company_id
            WHERE %s
            GROUP BY account_move_line.partner_id
        ''' % (tables, ct_query, where_clause))

        return ' UNION ALL '.join(queries), params

    @api.model
    def _get_lines_without_partner(self,
                                   options,
                                   expanded_partner=None,
                                   offset=0,
                                   limit=0):
        ''' Get the detail of lines without partner reconciled with a line with a partner. Those lines should be
        considered as belonging the partner for the reconciled amount as it may clear some of the partner invoice/bill
        and they have to be accounted in the partner balance.'''

        params = []
        if expanded_partner:
            partner_clause = '= %s'
            params = [expanded_partner.id] + params
        else:
            partner_clause = 'IS NOT NULL'
        new_options = self._get_options_without_partner(options)
        params += [options['date']['date_from'], options['date']['date_to']]
        tables, where_clause, where_params = self._query_get(new_options,
                                                             domain=[])
        params += where_params + [offset]
        limit_clause = ''
        if limit != 0:
            params += [limit]
            limit_clause = "LIMIT %s"
        query = '''
            SELECT
                account_move_line.id,
                account_move_line.date,
                account_move_line.date_maturity,
                account_move_line.name,
                account_move_line.ref,
                account_move_line.company_id,
                account_move_line.account_id,
                account_move_line.payment_id,
                aml_with_partner.partner_id,
                account_move_line.currency_id,
                account_move_line.amount_currency,
                account_move_line.matching_number,
                CASE WHEN aml_with_partner.balance > 0 THEN 0 ELSE partial.amount END AS debit,
                CASE WHEN aml_with_partner.balance < 0 THEN 0 ELSE partial.amount END AS credit,
                CASE WHEN aml_with_partner.balance > 0 THEN -partial.amount ELSE partial.amount END AS balance,
                account_move_line__move_id.name         AS move_name,
                account_move_line__move_id.move_type    AS move_type,
                account.code                            AS account_code,
                account.name                            AS account_name,
                journal.code                            AS journal_code,
                journal.name                            AS journal_name,
                full_rec.name                           AS full_rec_name
            FROM {tables},
                account_partial_reconcile partial
                LEFT JOIN account_full_reconcile full_rec ON full_rec.id = partial.full_reconcile_id,
                account_move_line aml_with_partner,
                account_journal journal,
                account_account account
            WHERE (account_move_line.id = partial.debit_move_id OR account_move_line.id = partial.credit_move_id)
               AND account_move_line.partner_id IS NULL
               AND (aml_with_partner.id = partial.debit_move_id OR aml_with_partner.id = partial.credit_move_id)
               AND aml_with_partner.partner_id {partner_clause}
               AND journal.id = account_move_line.journal_id
               AND account.id = account_move_line.account_id
               AND partial.max_date BETWEEN %s AND %s
               AND {where_clause}
            ORDER BY account_move_line.date, account_move_line.id
            OFFSET %s
            {limit_clause}
        '''.format(tables=tables,
                   partner_clause=partner_clause,
                   where_clause=where_clause,
                   limit_clause=limit_clause)

        return query, params

    @api.model
    def _get_sums_without_partner(self, options, expanded_partner=None):
        ''' Get the sum of lines without partner reconciled with a line with a partner, grouped by partner. Those lines
        should be considered as belonging the partner for the reconciled amount as it may clear some of the partner
        invoice/bill and they have to be accounted in the partner balance.'''

        params = []
        if expanded_partner:
            partner_clause = '= %s'
            params = [expanded_partner.id]
        else:
            partner_clause = 'IS NOT NULL'

        new_options = self._get_options_without_partner(options)
        params = [options['date']['date_from']
                  ] + params + [options['date']['date_to']]
        tables, where_clause, where_params = self._query_get(new_options,
                                                             domain=[])
        params += where_params

        query = '''
            SELECT
                aml_with_partner.partner_id AS groupby,
                SUM(CASE WHEN aml_with_partner.balance > 0 THEN 0 ELSE partial.amount END) AS debit,
                SUM(CASE WHEN aml_with_partner.balance < 0 THEN 0 ELSE partial.amount END) AS credit,
                SUM(CASE WHEN aml_with_partner.balance > 0 THEN -partial.amount ELSE partial.amount END) AS balance,
                CASE WHEN partial.max_date < %s THEN 'initial_balance' ELSE 'sum' END as key
            FROM {tables}, account_partial_reconcile partial, account_move_line aml_with_partner
            WHERE (account_move_line.id = partial.debit_move_id OR account_move_line.id = partial.credit_move_id)
               AND account_move_line.partner_id IS NULL
               AND (aml_with_partner.id = partial.debit_move_id OR aml_with_partner.id = partial.credit_move_id)
               AND aml_with_partner.partner_id {partner_clause}
               AND partial.max_date <= %s
               AND {where_clause}
            GROUP BY aml_with_partner.partner_id, key
        '''.format(tables=tables,
                   partner_clause=partner_clause,
                   where_clause=where_clause)
        return query, params

    @api.model
    def _get_query_amls(self,
                        options,
                        expanded_partner=None,
                        offset=None,
                        limit=None):
        ''' Construct a query retrieving the account.move.lines when expanding a report line with or without the load
        more.
        :param options:             The report options.
        :param expanded_partner:    The res.partner record corresponding to the expanded line.
        :param offset:              The offset of the query (used by the load more).
        :param limit:               The limit of the query (used by the load more).
        :return:                    (query, params)
        '''
        unfold_all = options.get('unfold_all') or (
            self._context.get('print_mode') and not options['unfolded_lines'])

        # Get sums for the account move lines.
        # period: [('date' <= options['date_to']), ('date', '>=', options['date_from'])]
        if expanded_partner is not None:
            domain = [('partner_id', '=', expanded_partner.id)]
        elif unfold_all:
            domain = []
        elif options['unfolded_lines']:
            domain = [('partner_id', 'in',
                       [int(line[8:]) for line in options['unfolded_lines']])]

        new_options = self._get_options_sum_balance(options)
        tables, where_clause, where_params = self._query_get(new_options,
                                                             domain=domain)
        ct_query = self.env['res.currency']._get_query_currency_table(options)

        query = '''
            SELECT
                account_move_line.id,
                account_move_line.date,
                account_move_line.date_maturity,
                account_move_line.name,
                account_move_line.ref,
                account_move_line.company_id,
                account_move_line.account_id,
                account_move_line.payment_id,
                account_move_line.partner_id,
                account_move_line.currency_id,
                account_move_line.amount_currency,
                account_move_line.matching_number,
                ROUND(account_move_line.debit * currency_table.rate, currency_table.precision)   AS debit,
                ROUND(account_move_line.credit * currency_table.rate, currency_table.precision)  AS credit,
                ROUND(account_move_line.balance * currency_table.rate, currency_table.precision) AS balance,
                account_move_line__move_id.name         AS move_name,
                company.currency_id                     AS company_currency_id,
                partner.name                            AS partner_name,
                account_move_line__move_id.move_type    AS move_type,
                account.code                            AS account_code,
                account.name                            AS account_name,
                journal.code                            AS journal_code,
                journal.name                            AS journal_name
            FROM account_move_line
            LEFT JOIN account_move account_move_line__move_id ON account_move_line__move_id.id = account_move_line.move_id
            LEFT JOIN %s ON currency_table.company_id = account_move_line.company_id
            LEFT JOIN res_company company               ON company.id = account_move_line.company_id
            LEFT JOIN res_partner partner               ON partner.id = account_move_line.partner_id
            LEFT JOIN account_account account           ON account.id = account_move_line.account_id
            LEFT JOIN account_journal journal           ON journal.id = account_move_line.journal_id
            WHERE %s
            ORDER BY account_move_line.date, account_move_line.id
        ''' % (ct_query, where_clause)

        if offset:
            query += ' OFFSET %s '
            where_params.append(offset)
        if limit:
            query += ' LIMIT %s '
            where_params.append(limit)

        return query, where_params

    @api.model
    def _do_query(self, options, expanded_partner=None):
        ''' Execute the queries, perform all the computation and return partners_results,
        a lists of tuple (partner, fetched_values) sorted by the table's model _order:
            - partner is a res.parter record.
            - fetched_values is a dictionary containing:
                - sum:                              {'debit': float, 'credit': float, 'balance': float}
                - (optional) initial_balance:       {'debit': float, 'credit': float, 'balance': float}
                - (optional) lines:                 [line_vals_1, line_vals_2, ...]
        :param options:             The report options.
        :param expanded_account:    An optional account.account record that must be specified when expanding a line
                                    with of without the load more.
        :param fetch_lines:         A flag to fetch the account.move.lines or not (the 'lines' key in accounts_values).
        :return:                    (accounts_values, taxes_results)
        '''
        def assign_sum(row):
            key = row['key']
            fields = ['balance', 'debit', 'credit'
                      ] if key == 'sum' else ['balance']
            if any(not company_currency.is_zero(row[field])
                   for field in fields):
                groupby_partners.setdefault(
                    row['groupby'], defaultdict(lambda: defaultdict(float)))
                for field in fields:
                    groupby_partners[row['groupby']][key][field] += row[field]

        company_currency = self.env.company.currency_id

        # flush the tables that gonna be queried
        self.env['account.move.line'].flush(
            fnames=self.env['account.move.line']._fields)
        self.env['account.move'].flush(fnames=self.env['account.move']._fields)
        self.env['account.partial.reconcile'].flush(
            fnames=self.env['account.partial.reconcile']._fields)

        # Execute the queries and dispatch the results.
        query, params = self._get_query_sums(options,
                                             expanded_partner=expanded_partner)

        groupby_partners = {}

        self._cr.execute(query, params)
        for res in self._cr.dictfetchall():
            assign_sum(res)

        # Fetch the lines of unfolded accounts.
        unfold_all = options.get('unfold_all') or (
            self._context.get('print_mode') and not options['unfolded_lines'])
        if expanded_partner or unfold_all or options['unfolded_lines']:
            query, params = self._get_query_amls(
                options, expanded_partner=expanded_partner)
            self._cr.execute(query, params)
            for res in self._cr.dictfetchall():
                if res['partner_id'] not in groupby_partners:
                    continue
                groupby_partners[res['partner_id']].setdefault('lines', [])
                groupby_partners[res['partner_id']]['lines'].append(res)

            query, params = self._get_lines_without_partner(
                options, expanded_partner=expanded_partner)
            self._cr.execute(query, params)
            for row in self._cr.dictfetchall():
                # don't show lines of partners not expanded
                if row['partner_id'] in groupby_partners:
                    groupby_partners[row['partner_id']].setdefault('lines', [])
                    row['class'] = ' text-muted'
                    groupby_partners[row['partner_id']]['lines'].append(row)
                if None in groupby_partners:
                    # reconciled lines without partners are fetched to be displayed under the matched partner
                    # and thus but be inversed to be displayed under the unknown partner
                    none_row = row.copy()
                    none_row['class'] = ' text-muted'
                    none_row['debit'] = row['credit']
                    none_row['credit'] = row['debit']
                    none_row['balance'] = -row['balance']
                    groupby_partners[None].setdefault('lines', [])
                    groupby_partners[None]['lines'].append(none_row)

        # correct the sums per partner, for the lines without partner reconciled with a line having a partner
        query, params = self._get_sums_without_partner(
            options, expanded_partner=expanded_partner)
        self._cr.execute(query, params)
        total = total_debit = total_credit = total_initial_balance = 0
        for row in self._cr.dictfetchall():
            key = row['key']
            total_debit += key == 'sum' and row['debit'] or 0
            total_credit += key == 'sum' and row['credit'] or 0
            total_initial_balance += key == 'initial_balance' and row[
                'balance'] or 0
            total += key == 'sum' and row['balance'] or 0
            if None not in groupby_partners and not (
                    expanded_partner or unfold_all
                    or options['unfolded_lines']):
                groupby_partners.setdefault(None, {})
            if row['groupby'] not in groupby_partners:
                continue
            assign_sum(row)

        if None in groupby_partners:
            if 'sum' not in groupby_partners[None]:
                groupby_partners[None].setdefault('sum', {
                    'debit': 0,
                    'credit': 0,
                    'balance': 0
                })
            if 'initial_balance' not in groupby_partners[None]:
                groupby_partners[None].setdefault('initial_balance',
                                                  {'balance': 0})
            #debit/credit are inversed for the unknown partner as the computation is made regarding the balance of the known partner
            groupby_partners[None]['sum']['debit'] += total_credit
            groupby_partners[None]['sum']['credit'] += total_debit
            groupby_partners[None]['sum']['balance'] -= total
            groupby_partners[None]['initial_balance'][
                'balance'] -= total_initial_balance

        # Retrieve the partners to browse.
        # groupby_partners.keys() contains all account ids affected by:
        # - the amls in the current period.
        # - the amls affecting the initial balance.
        # Note a search is done instead of a browse to preserve the table ordering.
        if expanded_partner:
            partners = expanded_partner
        elif groupby_partners:
            partners = self.env['res.partner'].with_context(
                active_test=False).search([('id', 'in',
                                            list(groupby_partners.keys()))])
        else:
            partners = []

        # Add 'Partner Unknown' if needed
        if None in groupby_partners.keys():
            partners = [p for p in partners] + [None]
        return [(partner, groupby_partners[partner.id if partner else None])
                for partner in partners]

    ####################################################
    # COLUMNS/LINES
    ####################################################

    @api.model
    def _get_report_line_partner(self, options, partner, initial_balance,
                                 debit, credit, balance):
        company_currency = self.env.company.currency_id
        unfold_all = self._context.get(
            'print_mode') and not options.get('unfolded_lines')

        columns = [
            {
                'name': self.format_value(initial_balance),
                'class': 'number'
            },
            {
                'name': self.format_value(debit),
                'class': 'number'
            },
            {
                'name': self.format_value(credit),
                'class': 'number'
            },
        ]
        if self.user_has_groups('base.group_multi_currency'):
            columns.append({'name': ''})
        columns.append({'name': self.format_value(balance), 'class': 'number'})

        return {
            'id':
            'partner_%s' % (partner.id if partner else 0),
            'partner_id':
            partner.id if partner else None,
            'name':
            partner is not None and (partner.name or '')[:128]
            or _('Unknown Partner'),
            'columns':
            columns,
            'level':
            2,
            'trust':
            partner.trust if partner else None,
            'unfoldable':
            not company_currency.is_zero(debit)
            or not company_currency.is_zero(credit),
            'unfolded':
            'partner_%s' %
            (partner.id if partner else 0) in options['unfolded_lines']
            or unfold_all,
            'colspan':
            6,
        }

    @api.model
    def _get_report_line_move_line(self, options, partner, aml,
                                   cumulated_init_balance, cumulated_balance):
        if aml['payment_id']:
            caret_type = 'account.payment'
        else:
            caret_type = 'account.move'

        date_maturity = aml['date_maturity'] and format_date(
            self.env, fields.Date.from_string(aml['date_maturity']))
        columns = [
            {
                'name': aml['journal_code']
            },
            {
                'name': aml['account_code']
            },
            {
                'name':
                self._format_aml_name(aml['name'], aml['ref'],
                                      aml['move_name'])
            },
            {
                'name': date_maturity or '',
                'class': 'date'
            },
            {
                'name': aml['matching_number'] or ''
            },
            {
                'name': self.format_value(cumulated_init_balance),
                'class': 'number'
            },
            {
                'name': self.format_value(aml['debit'], blank_if_zero=True),
                'class': 'number'
            },
            {
                'name': self.format_value(aml['credit'], blank_if_zero=True),
                'class': 'number'
            },
        ]
        if self.user_has_groups('base.group_multi_currency'):
            if aml['currency_id']:
                currency = self.env['res.currency'].browse(aml['currency_id'])
                formatted_amount = self.format_value(aml['amount_currency'],
                                                     currency=currency,
                                                     blank_if_zero=True)
                columns.append({'name': formatted_amount, 'class': 'number'})
            else:
                columns.append({'name': ''})
        columns.append({
            'name': self.format_value(cumulated_balance),
            'class': 'number'
        })
        return {
            'id': aml['id'],
            'parent_id': 'partner_%s' % (partner.id if partner else 0),
            'name': format_date(self.env, aml['date']),
            'class': 'text' +
            aml.get('class',
                    ''),  # do not format as date to prevent text centering
            'columns': columns,
            'caret_options': caret_type,
            'level': 2,
        }

    @api.model
    def _get_report_line_load_more(self, options, partner, offset, remaining,
                                   progress):
        return {
            'id':
            'loadmore_%s' % (partner.id if partner else 0),
            'offset':
            offset,
            'progress':
            progress,
            'remaining':
            remaining,
            'class':
            'o_account_reports_load_more text-center',
            'parent_id':
            'partner_%s' % (partner.id if partner else 0),
            'name':
            _('Load more... (%s remaining)', remaining),
            'colspan':
            10 if self.user_has_groups('base.group_multi_currency') else 9,
            'columns': [{}],
        }

    @api.model
    def _get_report_line_total(self, options, initial_balance, debit, credit,
                               balance):
        columns = [
            {
                'name': self.format_value(initial_balance),
                'class': 'number'
            },
            {
                'name': self.format_value(debit),
                'class': 'number'
            },
            {
                'name': self.format_value(credit),
                'class': 'number'
            },
        ]
        if self.user_has_groups('base.group_multi_currency'):
            columns.append({'name': ''})
        columns.append({'name': self.format_value(balance), 'class': 'number'})
        return {
            'id': 'partner_ledger_total_%s' % self.env.company.id,
            'name': _('Total'),
            'class': 'total',
            'level': 1,
            'columns': columns,
            'colspan': 6,
        }

    @api.model
    def _get_partner_ledger_lines(self, options, line_id=None):
        ''' Get lines for the whole report or for a specific line.
        :param options: The report options.
        :return:        A list of lines, each one represented by a dictionary.
        '''
        lines = []
        unfold_all = options.get('unfold_all') or (
            self._context.get('print_mode') and not options['unfolded_lines'])

        expanded_partner = line_id and self.env['res.partner'].browse(
            int(line_id[8:]))
        partners_results = self._do_query(options,
                                          expanded_partner=expanded_partner)

        total_initial_balance = total_debit = total_credit = total_balance = 0.0
        for partner, results in partners_results:
            is_unfolded = 'partner_%s' % (partner.id if partner else
                                          0) in options['unfolded_lines']

            # res.partner record line.
            partner_sum = results.get('sum', {})
            partner_init_bal = results.get('initial_balance', {})

            initial_balance = partner_init_bal.get('balance', 0.0)
            debit = partner_sum.get('debit', 0.0)
            credit = partner_sum.get('credit', 0.0)
            balance = initial_balance + partner_sum.get('balance', 0.0)

            lines.append(
                self._get_report_line_partner(options, partner,
                                              initial_balance, debit, credit,
                                              balance))

            total_initial_balance += initial_balance
            total_debit += debit
            total_credit += credit
            total_balance += balance

            if unfold_all or is_unfolded:
                cumulated_balance = initial_balance

                # account.move.line record lines.
                amls = results.get('lines', [])

                load_more_remaining = len(amls)
                load_more_counter = self._context.get(
                    'print_mode') and load_more_remaining or self.MAX_LINES

                for aml in amls:
                    # Don't show more line than load_more_counter.
                    if load_more_counter == 0:
                        break

                    cumulated_init_balance = cumulated_balance
                    cumulated_balance += aml['balance']
                    lines.append(
                        self._get_report_line_move_line(
                            options, partner, aml, cumulated_init_balance,
                            cumulated_balance))

                    load_more_remaining -= 1
                    load_more_counter -= 1

                if load_more_remaining > 0:
                    # Load more line.
                    lines.append(
                        self._get_report_line_load_more(
                            options,
                            partner,
                            self.MAX_LINES,
                            load_more_remaining,
                            cumulated_balance,
                        ))

        if not line_id:
            # Report total line.
            lines.append(
                self._get_report_line_total(options, total_initial_balance,
                                            total_debit, total_credit,
                                            total_balance))
        return lines

    @api.model
    def _load_more_lines(self, options, line_id, offset, load_more_remaining,
                         progress):
        ''' Get lines for an expanded line using the load more.
        :param options: The report options.
        :return:        A list of lines, each one represented by a dictionary.
        '''
        lines = []
        expanded_partner = line_id and self.env['res.partner'].browse(
            int(line_id[9:]))

        load_more_counter = self.MAX_LINES

        starting_offset = offset
        starting_load_more_counter = load_more_counter

        # Fetch the next batch of lines
        amls_query, amls_params = self._get_query_amls(
            options,
            expanded_partner=expanded_partner,
            offset=offset,
            limit=load_more_counter)
        self._cr.execute(amls_query, amls_params)
        for aml in self._cr.dictfetchall():
            # Don't show more line than load_more_counter.
            if load_more_counter == 0:
                break

            cumulated_init_balance = progress
            progress += aml['balance']

            # account.move.line record line.
            lines.append(
                self._get_report_line_move_line(options, expanded_partner, aml,
                                                cumulated_init_balance,
                                                progress))

            offset += 1
            load_more_remaining -= 1
            load_more_counter -= 1

        query, params = self._get_lines_without_partner(
            options,
            expanded_partner=expanded_partner,
            offset=offset - starting_offset,
            limit=starting_load_more_counter - load_more_counter)
        self._cr.execute(query, params)
        for row in self._cr.dictfetchall():
            # Don't show more line than load_more_counter.
            if load_more_counter == 0:
                break

            row['class'] = ' text-muted'
            if line_id == 'loadmore_0':
                # reconciled lines without partners are fetched to be displayed under the matched partner
                # and thus but be inversed to be displayed under the unknown partner
                row['debit'] = row['balance'] < 0 and row['credit'] or 0
                row['credit'] = row['balance'] > 0 and row['debit'] or 0
                row['balance'] = -row['balance']
            cumulated_init_balance = progress
            progress += row['balance']
            lines.append(
                self._get_report_line_move_line(options, expanded_partner, row,
                                                cumulated_init_balance,
                                                progress))

            offset += 1
            load_more_remaining -= 1
            load_more_counter -= 1

        if load_more_remaining > 0:
            # Load more line.
            lines.append(
                self._get_report_line_load_more(
                    options,
                    expanded_partner,
                    offset,
                    load_more_remaining,
                    progress,
                ))
        return lines

    def _get_columns_name(self, options):
        columns = [{}, {
            'name': _('JRNL')
        }, {
            'name': _('Account')
        }, {
            'name': _('Ref')
        }, {
            'name': _('Due Date'),
            'class': 'date'
        }, {
            'name': _('Matching Number')
        }, {
            'name': _('Initial Balance'),
            'class': 'number'
        }, {
            'name': _('Debit'),
            'class': 'number'
        }, {
            'name': _('Credit'),
            'class': 'number'
        }]

        if self.user_has_groups('base.group_multi_currency'):
            columns.append({'name': _('Amount Currency'), 'class': 'number'})

        columns.append({'name': _('Balance'), 'class': 'number'})

        return columns

    @api.model
    def _get_lines(self, options, line_id=None):
        offset = int(options.get('lines_offset', 0))
        remaining = int(options.get('lines_remaining', 0))
        balance_progress = float(options.get('lines_progress', 0))

        if offset > 0:
            # Case a line is expanded using the load more.
            return self._load_more_lines(options, line_id, offset, remaining,
                                         balance_progress)
        else:
            # Case the whole report is loaded or a line is expanded for the first time.
            return self._get_partner_ledger_lines(options, line_id=line_id)

    @api.model
    def _get_report_name(self):
        return _('Partner Ledger')
Esempio n. 21
0
from odoo.tools import pdf
import io
import PIL.PdfImagePlugin   # activate PDF support in PIL
from PIL import Image
from odoo.addons.delivery_ups.models.ups_request import UPSRequest
from odoo.http import request
from zeep.exceptions import Fault
import base64

_logger = logging.getLogger(__name__)
import re

ZIP_ZIP4 = re.compile('^[0-9]{5}(-[0-9]{4})?$')

UPS_ERROR_MAP = {
    '110002': _lt("Please provide at least one item to ship."),
    '110208': _lt("Please set a valid country in the recipient address."),
    '110308': _lt("Please set a valid country in the warehouse address."),
    '110548': _lt("A shipment cannot have a KGS/IN or LBS/CM as its unit of measurements. Configure it from the delivery method."),
    '111057': _lt("This measurement system is not valid for the selected country. Please switch from LBS/IN to KGS/CM (or vice versa). Configure it from the delivery method."),
    '111091': _lt("The selected service is not possible from your warehouse to the recipient address, please choose another service."),
    '111100': _lt("The selected service is invalid from the requested warehouse, please choose another service."),
    '111107': _lt("Please provide a valid zip code in the warehouse address."),
    '111210': _lt("The selected service is invalid to the recipient address, please choose another service."),
    '111212': _lt("Please provide a valid package type available for service and selected locations."),
    '111500': _lt("The selected service is not valid with the selected packaging."),
    '112111': _lt("Please provide a valid shipper number/Carrier Account."),
    '113020': _lt("Please provide a valid zip code in the warehouse address."),
    '113021': _lt("Please provide a valid zip code in the recipient address."),
    '120031': _lt("Exceeds Total Number of allowed pieces per World Wide Express Shipment."),
    '120100': _lt("Please provide a valid shipper number/Carrier Account."),
Esempio n. 22
0
 def _get_profitability_labels(self):
     labels = super()._get_profitability_labels()
     labels['expenses'] = _lt('Expenses')
     return labels
Esempio n. 23
0
from datetime import datetime
from dateutil.relativedelta import relativedelta
import io, base64

# months in (int, str) tuples
MONTHS = [(str(month), '%02d' % month) for month in list(range(1, 13))]

TIMEZONE_RELATIVEDELTA = relativedelta(hours=7)

STATES = [('draft', 'Draft'), ('allocation_derived', 'Allocation Derived'),
          ('posted', 'Posted')]
DEFAULT_STATE = STATES[0][0]

MODEL_NAMES = {
    'material_loss': _lt('Material Loss Allocation'),
    'labor_cost': _lt('Labor Cost Allocation'),
    'click_charge': _lt('Click Charge Allocation'),
    'overhead_cost': _lt('Overhead Cost Allocation'),
}

SPECIFIC_FIELDS = {
    'material_loss': {
        'je_inverse_field': 'material_loss_allocation_id'
    },
    'labor_cost': {
        'je_inverse_field': 'labor_cost_allocation_id'
    },
    'click_charge': {
        'je_inverse_field': 'click_charge_allocation_id'
    },
Esempio n. 24
0
 def _get_profitability_labels(self):
     labels = super()._get_profitability_labels()
     labels['purchase_order'] = _lt('Purchase Orders')
     return labels
Esempio n. 25
0
class ReportPartnerLedger141(models.AbstractModel):
    _inherit = "account.partner.ledger"
    _name = "account.partner.ledger.141"

    filter_account_type = [
        {
            'id': 'receivable',
            'name': _lt('Receivable'),
            'selected': False
        },
        {
            'id': 'payable',
            'name': _lt('Payable'),
            'selected': False
        },
        {
            'id': 'other',
            'name': _lt('Regular'),
            'selected': True
        },
        {
            'id': 'liquidity',
            'name': _lt('Liquidity'),
            'selected': False
        },
    ]

    @api.model
    def _get_options_domain(self, options):
        # OVERRIDE
        # Handle filter_unreconciled + filter_account_type
        domain = super(ReportPartnerLedger141,
                       self)._get_options_domain(options)
        i = 0
        for item in domain:
            i += 1
            if 'account_id.internal_type' in item:
                domain[i - 1] = ('account_id.internal_type', 'in', [
                    'receivable', 'payable', 'other', 'liquidity'
                ])
            # if 'partner_id' in item:
            #     domain[i - 1] = ('|','partner_id', '!=', False,'partner_id', '=', False)
        domain.append(('account_id.code', '=', '141'))
        # Partner must be set.
        return domain

    @api.model
    def _get_templates(self):
        templates = super(ReportPartnerLedger141, self)._get_templates()
        templates[
            'line_template'] = 'advanced_vn_report.line_template_partner_ledger_report_141'
        return templates

    @api.model
    def _get_report_line_move_line(self, options, partner, aml,
                                   cumulated_init_balance, cumulated_balance):
        result = super(ReportPartnerLedger141,
                       self)._get_report_line_move_line(
                           options, partner, aml, cumulated_init_balance,
                           cumulated_balance)
        result['account_id'] = 141
        return result
Esempio n. 26
0
# -*- coding: utf-8 -*-
import babel.dates
import pytz
from lxml import etree
import base64
import json

from odoo import _, _lt, api, fields, models
from odoo.osv.expression import AND, TRUE_DOMAIN, normalize_domain
from odoo.tools import date_utils, lazy
from odoo.tools.misc import get_lang
from odoo.exceptions import UserError
from collections import defaultdict

SEARCH_PANEL_ERROR_MESSAGE = _lt("Too many items to display.")


def is_true_domain(domain):
    return normalize_domain(domain) == TRUE_DOMAIN


class lazymapping(defaultdict):
    def __missing__(self, key):
        value = self.default_factory(key)
        self[key] = value
        return value


class IrActionsActWindowView(models.Model):
    _inherit = 'ir.actions.act_window.view'
Esempio n. 27
0
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import logging

import requests

from odoo import api, fields, models, _, _lt
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)

TWITTER_EXCEPTION = {
    304:
    _lt('There was no new data to return.'),
    400:
    _lt('The request was invalid or cannot be otherwise served. Requests without authentication are considered invalid and will yield this response.'
        ),
    401:
    _lt('Authentication credentials were missing or incorrect. Maybe screen name tweets are protected.'
        ),
    403:
    _lt('The request is understood, but it has been refused or access is not allowed. Please check your Twitter API Key and Secret.'
        ),
    429:
    _lt('Request cannot be served due to the applications rate limit having been exhausted for the resource.'
        ),
    500:
    _lt('Twitter seems broken. Please retry later. You may consider posting an issue on Twitter forums to get help.'
        ),
    502:
Esempio n. 28
0
    net_new_mrr = new_mrr - churned_mrr + expansion_mrr - down_mrr

    return {
        'new_mrr': new_mrr,
        'churned_mrr': -churned_mrr,
        'expansion_mrr': expansion_mrr,
        'down_mrr': -down_mrr,
        'net_new_mrr': net_new_mrr,
    }


STAT_TYPES = {
    'mrr': {
        'name':
        _lt('Monthly Recurring Revenue'),
        'code':
        'mrr',
        'tooltip':
        _lt('MRR for short; total subscription revenue per month (e.g. for an annual subscription of $ 1,200, the MRR is $ 100)'
            ),
        'dir':
        'up',
        'prior':
        1,
        'type':
        'last',
        'add_symbol':
        'currency',
        'compute':
        compute_mrr