def _compute_invoice_taxes_by_group(self): report_or_portal_view = 'commit_assetsbundle' in self.env.context or \ not self.env.context.get('params', {}).get('view_type') == 'form' if not report_or_portal_view: return super()._compute_invoice_taxes_by_group() move_with_doc_type = self.filtered('l10n_latam_document_type_id') for move in move_with_doc_type: lang_env = move.with_context(lang=move.partner_id.lang).env tax_lines = move.l10n_latam_tax_ids res = {} # There are as many tax line as there are repartition lines done_taxes = set() for line in tax_lines: res.setdefault(line.tax_line_id.tax_group_id, {'base': 0.0, 'amount': 0.0}) res[line.tax_line_id.tax_group_id]['amount'] += line.price_subtotal tax_key_add_base = tuple(move._get_tax_key_for_group_add_base(line)) if tax_key_add_base not in done_taxes: # The base should be added ONCE res[line.tax_line_id.tax_group_id]['base'] += line.tax_base_amount done_taxes.add(tax_key_add_base) res = sorted(res.items(), key=lambda l: l[0].sequence) move.amount_by_group = [( group.name, amounts['amount'], amounts['base'], formatLang(lang_env, amounts['amount'], currency_obj=move.currency_id), formatLang(lang_env, amounts['base'], currency_obj=move.currency_id), len(res), group.id, ) for group, amounts in res] super(AccountMove, self - move_with_doc_type)._compute_invoice_taxes_by_group()
def _check_build_page_info(self, i, p): multi_stub = self.company_id.account_check_printing_multi_stub return { 'sequence_number': self.check_number if (self.journal_id.check_manual_sequencing and self.check_number != 0) else False, 'payment_date': format_date(self.env, self.payment_date), 'partner_id': self.partner_id, 'partner_name': self.partner_id.name, 'currency': self.currency_id, 'state': self.state, 'amount': formatLang(self.env, self.amount, currency_obj=self.currency_id) if i == 0 else 'VOID', 'amount_in_word': self._check_fill_line(self.check_amount_in_words) if i == 0 else 'VOID', 'memo': self.communication, 'stub_cropped': not multi_stub and len(self.invoice_ids) > INV_LINES_PER_STUB, # If the payment does not reference an invoice, there is no stub line to display 'stub_lines': p, }
def _check_make_stub_line(self, invoice): """ Return the dict used to display an invoice/refund in the stub """ # Find the account.partial.reconcile which are common to the invoice and the payment if invoice.type in ['in_invoice', 'out_refund']: invoice_sign = 1 invoice_payment_reconcile = invoice.move_id.line_ids.mapped( 'matched_debit_ids').filtered( lambda r: r.debit_move_id in self.move_line_ids) else: invoice_sign = -1 invoice_payment_reconcile = invoice.move_id.line_ids.mapped( 'matched_credit_ids').filtered( lambda r: r.credit_move_id in self.move_line_ids) if self.currency_id != self.journal_id.company_id.currency_id: amount_paid = abs( sum(invoice_payment_reconcile.mapped('amount_currency'))) else: amount_paid = abs(sum(invoice_payment_reconcile.mapped('amount'))) amount_residual = invoice_sign * invoice.residual return { 'due_date': format_date(self.env, invoice.date_due), 'number': invoice.reference and invoice.number + ' - ' + invoice.reference or invoice.number, 'amount_total': formatLang(self.env, invoice_sign * invoice.amount_total, currency_obj=invoice.currency_id), 'amount_residual': formatLang( self.env, amount_residual, currency_obj=invoice.currency_id) if amount_residual * 10**4 != 0 else '-', 'amount_paid': formatLang(self.env, invoice_sign * amount_paid, currency_obj=invoice.currency_id), 'currency': invoice.currency_id, }
def name_get(self): result = [] for po in self: name = po.name if po.partner_ref: name += ' (' + po.partner_ref + ')' if self.env.context.get('show_total_amount') and po.amount_total: name += ': ' + formatLang(self.env, po.amount_total, currency_obj=po.currency_id) result.append((po.id, name)) return result
def _get_statement_line(self, st_line): """ Returns the data required by the bank statement reconciliation widget to display a statement line """ statement_currency = st_line.journal_id.currency_id or st_line.journal_id.company_id.currency_id if st_line.amount_currency and st_line.currency_id: amount = st_line.amount_currency amount_currency = st_line.amount amount_currency_str = formatLang(self.env, abs(amount_currency), currency_obj=statement_currency) else: amount = st_line.amount amount_currency = amount amount_currency_str = "" amount_str = formatLang(self.env, abs(amount), currency_obj=st_line.currency_id or statement_currency) data = { 'id': st_line.id, 'ref': st_line.ref, 'note': st_line.note or "", 'name': st_line.name, 'date': st_line.date, 'amount': amount, 'amount_str': amount_str, # Amount in the statement line currency 'currency_id': st_line.currency_id.id or statement_currency.id, 'partner_id': st_line.partner_id.id, 'journal_id': st_line.journal_id.id, 'statement_id': st_line.statement_id.id, 'account_id': [st_line.journal_id.default_debit_account_id.id, st_line.journal_id.default_debit_account_id.display_name], 'account_code': st_line.journal_id.default_debit_account_id.code, 'account_name': st_line.journal_id.default_debit_account_id.name, 'partner_name': st_line.partner_id.name, 'communication_partner_name': st_line.partner_name, 'amount_currency_str': amount_currency_str, # Amount in the statement currency 'amount_currency': amount_currency, # Amount in the statement currency 'has_no_partner': not st_line.partner_id.id, 'company_id': st_line.company_id.id, } if st_line.partner_id: if amount > 0: data['open_balance_account_id'] = st_line.partner_id.property_account_receivable_id.id else: data['open_balance_account_id'] = st_line.partner_id.property_account_payable_id.id return data
def _balance_check(self): for stmt in self: if not stmt.currency_id.is_zero(stmt.difference): if stmt.journal_type == 'cash': if stmt.difference < 0.0: account = stmt.journal_id.loss_account_id name = _('Loss') else: # statement.difference > 0.0 account = stmt.journal_id.profit_account_id name = _('Profit') if not account: raise UserError( _('There is no account defined on the journal %s for %s involved in a cash difference.' ) % (stmt.journal_id.name, name)) values = { 'statement_id': stmt.id, 'account_id': account.id, 'amount': stmt.difference, 'name': _("Cash difference observed during the counting (%s)") % name, } self.env['account.bank.statement.line'].create(values) else: balance_end_real = formatLang( self.env, stmt.balance_end_real, currency_obj=stmt.currency_id) balance_end = formatLang(self.env, stmt.balance_end, currency_obj=stmt.currency_id) raise UserError( _('The ending balance is incorrect !\nThe expected balance (%s) is different from the computed one. (%s)' ) % (balance_end_real, balance_end)) return True
def get_journal_dashboard_datas(self): res = super(AccountJournal, self).get_journal_dashboard_datas() #add the number and sum of expenses to pay to the json defining the accounting dashboard data (query, query_args) = self._get_expenses_to_pay_query() self.env.cr.execute(query, query_args) query_results_to_pay = self.env.cr.dictfetchall() (number_to_pay, sum_to_pay) = self._count_results_and_sum_amounts( query_results_to_pay, self.company_id.currency_id) res['number_expenses_to_pay'] = number_to_pay res['sum_expenses_to_pay'] = formatLang(self.env, sum_to_pay or 0.0, currency_obj=self.currency_id or self.company_id.currency_id) return res
def _get_reward_values_discount(self, program): if program.discount_type == 'fixed_amount': return [{ 'name': _("Discount: ") + program.name, 'product_id': program.discount_line_product_id.id, 'price_unit': - self._get_reward_values_discount_fixed_amount(program), 'product_uom_qty': 1.0, 'product_uom': program.discount_line_product_id.uom_id.id, 'is_reward_line': True, 'tax_id': [(4, tax.id, False) for tax in program.discount_line_product_id.taxes_id], }] reward_dict = {} lines = self._get_paid_order_lines() if program.discount_apply_on == 'cheapest_product': line = self._get_cheapest_line() if line: discount_line_amount = line.price_reduce * (program.discount_percentage / 100) if discount_line_amount: taxes = line.tax_id if self.fiscal_position_id: taxes = self.fiscal_position_id.map_tax(taxes) reward_dict[line.tax_id] = { 'name': _("Discount: ") + program.name, 'product_id': program.discount_line_product_id.id, 'price_unit': - discount_line_amount, 'product_uom_qty': 1.0, 'product_uom': program.discount_line_product_id.uom_id.id, 'is_reward_line': True, 'tax_id': [(4, tax.id, False) for tax in taxes], } elif program.discount_apply_on in ['specific_products', 'on_order']: if program.discount_apply_on == 'specific_products': # We should not exclude reward line that offer this product since we need to offer only the discount on the real paid product (regular product - free product) free_product_lines = self.env['sale.coupon.program'].search([('reward_type', '=', 'product'), ('reward_product_id', 'in', program.discount_specific_product_ids.ids)]).mapped('discount_line_product_id') lines = lines.filtered(lambda x: x.product_id in (program.discount_specific_product_ids | free_product_lines)) for line in lines: discount_line_amount = self._get_reward_values_discount_percentage_per_line(program, line) if discount_line_amount: if line.tax_id in reward_dict: reward_dict[line.tax_id]['price_unit'] -= discount_line_amount else: taxes = line.tax_id if self.fiscal_position_id: taxes = self.fiscal_position_id.map_tax(taxes) tax_name = "" if len(taxes) == 1: tax_name = " - " + _("On product with following tax: ") + ', '.join(taxes.mapped('name')) elif len(taxes) > 1: tax_name = " - " + _("On product with following taxes: ") + ', '.join(taxes.mapped('name')) reward_dict[line.tax_id] = { 'name': _("Discount: ") + program.name + tax_name, 'product_id': program.discount_line_product_id.id, 'price_unit': - discount_line_amount, 'product_uom_qty': 1.0, 'product_uom': program.discount_line_product_id.uom_id.id, 'is_reward_line': True, 'tax_id': [(4, tax.id, False) for tax in taxes], } # If there is a max amount for discount, we might have to limit some discount lines or completely remove some lines max_amount = program._compute_program_amount('discount_max_amount', self.currency_id) if max_amount > 0: amount_already_given = 0 for val in list(reward_dict): amount_to_discount = amount_already_given + reward_dict[val]["price_unit"] if abs(amount_to_discount) > max_amount: reward_dict[val]["price_unit"] = - (max_amount - abs(amount_already_given)) add_name = formatLang(self.env, max_amount, currency_obj=self.currency_id) reward_dict[val]["name"] += "( " + _("limited to ") + add_name + ")" amount_already_given += reward_dict[val]["price_unit"] if reward_dict[val]["price_unit"] == 0: del reward_dict[val] return reward_dict.values()
def get_journal_dashboard_datas(self): currency = self.currency_id or self.company_id.currency_id number_to_reconcile = number_to_check = last_balance = account_sum = 0 title = '' number_draft = number_waiting = number_late = to_check_balance = 0 sum_draft = sum_waiting = sum_late = 0.0 if self.type in ['bank', 'cash']: last_bank_stmt = self.env['account.bank.statement'].search( [('journal_id', 'in', self.ids)], order="date desc, id desc", limit=1) last_balance = last_bank_stmt and last_bank_stmt[0].balance_end or 0 #Get the number of items to reconcile for that bank journal self.env.cr.execute( """SELECT COUNT(DISTINCT(line.id)) FROM account_bank_statement_line AS line LEFT JOIN account_bank_statement AS st ON line.statement_id = st.id WHERE st.journal_id IN %s AND st.state = 'open' AND line.amount != 0.0 AND line.account_id IS NULL AND not exists (select 1 from account_move_line aml where aml.statement_line_id = line.id) """, (tuple(self.ids), )) number_to_reconcile = self.env.cr.fetchone()[0] to_check_ids = self.to_check_ids() number_to_check = len(to_check_ids) to_check_balance = sum([r.amount for r in to_check_ids]) # optimization to read sum of balance from account_move_line account_ids = tuple(ac for ac in [ self.default_debit_account_id.id, self.default_credit_account_id.id ] if ac) if account_ids: amount_field = 'aml.balance' if ( not self.currency_id or self.currency_id == self.company_id.currency_id) else 'aml.amount_currency' query = """SELECT sum(%s) FROM account_move_line aml LEFT JOIN account_move move ON aml.move_id = move.id WHERE aml.account_id in %%s AND move.date <= %%s AND move.state = 'posted';""" % ( amount_field, ) self.env.cr.execute(query, ( account_ids, fields.Date.context_today(self), )) query_results = self.env.cr.dictfetchall() if query_results and query_results[0].get('sum') != None: account_sum = query_results[0].get('sum') #TODO need to check if all invoices are in the same currency than the journal!!!! elif self.type in ['sale', 'purchase']: title = _('Bills to pay') if self.type == 'purchase' else _( 'Invoices owed to you') self.env['account.move'].flush([ 'amount_residual', 'currency_id', 'type', 'invoice_date', 'company_id', 'journal_id', 'date', 'state', 'invoice_payment_state' ]) (query, query_args) = self._get_open_bills_to_pay_query() self.env.cr.execute(query, query_args) query_results_to_pay = self.env.cr.dictfetchall() (query, query_args) = self._get_draft_bills_query() self.env.cr.execute(query, query_args) query_results_drafts = self.env.cr.dictfetchall() today = fields.Date.today() query = ''' SELECT (CASE WHEN type IN ('out_refund', 'in_refund') THEN -1 ELSE 1 END) * amount_residual AS amount_total, currency_id AS currency, type, invoice_date, company_id FROM account_move move WHERE journal_id = %s AND date <= %s AND state = 'posted' AND invoice_payment_state = 'not_paid' AND type IN ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'); ''' self.env.cr.execute(query, (self.id, today)) late_query_results = self.env.cr.dictfetchall() curr_cache = {} (number_waiting, sum_waiting) = self._count_results_and_sum_amounts( query_results_to_pay, currency, curr_cache=curr_cache) (number_draft, sum_draft) = self._count_results_and_sum_amounts( query_results_drafts, currency, curr_cache=curr_cache) (number_late, sum_late) = self._count_results_and_sum_amounts( late_query_results, currency, curr_cache=curr_cache) read = self.env['account.move'].read_group( [('journal_id', '=', self.id), ('to_check', '=', True)], ['amount_total'], 'journal_id', lazy=False) if read: number_to_check = read[0]['__count'] to_check_balance = read[0]['amount_total'] elif self.type == 'general': read = self.env['account.move'].read_group( [('journal_id', '=', self.id), ('to_check', '=', True)], ['amount_total'], 'journal_id', lazy=False) if read: number_to_check = read[0]['__count'] to_check_balance = read[0]['amount_total'] difference = currency.round(last_balance - account_sum) + 0.0 is_sample_data = self.kanban_dashboard_graph and any( data.get('is_sample_data', False) for data in json.loads(self.kanban_dashboard_graph)) return { 'number_to_check': number_to_check, 'to_check_balance': formatLang(self.env, to_check_balance, currency_obj=currency), 'number_to_reconcile': number_to_reconcile, 'account_balance': formatLang(self.env, currency.round(account_sum) + 0.0, currency_obj=currency), 'last_balance': formatLang(self.env, currency.round(last_balance) + 0.0, currency_obj=currency), 'difference': formatLang(self.env, difference, currency_obj=currency) if difference else False, 'number_draft': number_draft, 'number_waiting': number_waiting, 'number_late': number_late, 'sum_draft': formatLang(self.env, currency.round(sum_draft) + 0.0, currency_obj=currency), 'sum_waiting': formatLang(self.env, currency.round(sum_waiting) + 0.0, currency_obj=currency), 'sum_late': formatLang(self.env, currency.round(sum_late) + 0.0, currency_obj=currency), 'currency_id': currency.id, 'bank_statements_source': self.bank_statements_source, 'title': title, 'is_sample_data': is_sample_data, }
def get_journal_dashboard_datas(self): currency = self.currency_id or self.company_id.currency_id number_to_reconcile = last_balance = account_sum = 0 title = '' number_draft = number_waiting = number_late = 0 sum_draft = sum_waiting = sum_late = 0.0 if self.type in ['bank', 'cash']: last_bank_stmt = self.env['account.bank.statement'].search( [('journal_id', 'in', self.ids)], order="date desc, id desc", limit=1) last_balance = last_bank_stmt and last_bank_stmt[0].balance_end or 0 #Get the number of items to reconcile for that bank journal self.env.cr.execute( """SELECT COUNT(DISTINCT(line.id)) FROM account_bank_statement_line AS line LEFT JOIN account_bank_statement AS st ON line.statement_id = st.id WHERE st.journal_id IN %s AND st.state = 'open' AND line.amount != 0.0 AND line.account_id IS NULL AND not exists (select 1 from account_move_line aml where aml.statement_line_id = line.id) """, (tuple(self.ids), )) number_to_reconcile = self.env.cr.fetchone()[0] # optimization to read sum of balance from account_move_line account_ids = tuple(ac for ac in [ self.default_debit_account_id.id, self.default_credit_account_id.id ] if ac) if account_ids: amount_field = 'aml.balance' if ( not self.currency_id or self.currency_id == self.company_id.currency_id) else 'aml.amount_currency' query = """SELECT sum(%s) FROM account_move_line aml LEFT JOIN account_move move ON aml.move_id = move.id WHERE aml.account_id in %%s AND move.date <= %%s AND move.state = 'posted';""" % ( amount_field, ) self.env.cr.execute(query, ( account_ids, fields.Date.context_today(self), )) query_results = self.env.cr.dictfetchall() if query_results and query_results[0].get('sum') != None: account_sum = query_results[0].get('sum') #TODO need to check if all invoices are in the same currency than the journal!!!! elif self.type in ['sale', 'purchase']: title = _('Bills to pay') if self.type == 'purchase' else _( 'Invoices owed to you') (query, query_args) = self._get_open_bills_to_pay_query() self.env.cr.execute(query, query_args) query_results_to_pay = self.env.cr.dictfetchall() (query, query_args) = self._get_draft_bills_query() self.env.cr.execute(query, query_args) query_results_drafts = self.env.cr.dictfetchall() today = fields.Date.today() query = """SELECT residual_signed as amount_total, currency_id AS currency, type, date_invoice, company_id FROM account_invoice WHERE journal_id = %s AND date <= %s AND state = 'open';""" self.env.cr.execute(query, (self.id, today)) late_query_results = self.env.cr.dictfetchall() curr_cache = {} (number_waiting, sum_waiting) = self._count_results_and_sum_amounts( query_results_to_pay, currency, curr_cache=curr_cache) (number_draft, sum_draft) = self._count_results_and_sum_amounts( query_results_drafts, currency, curr_cache=curr_cache) (number_late, sum_late) = self._count_results_and_sum_amounts( late_query_results, currency, curr_cache=curr_cache) difference = currency.round(last_balance - account_sum) + 0.0 return { 'number_to_reconcile': number_to_reconcile, 'account_balance': formatLang(self.env, currency.round(account_sum) + 0.0, currency_obj=currency), 'last_balance': formatLang(self.env, currency.round(last_balance) + 0.0, currency_obj=currency), 'difference': formatLang(self.env, difference, currency_obj=currency) if difference else False, 'number_draft': number_draft, 'number_waiting': number_waiting, 'number_late': number_late, 'sum_draft': formatLang(self.env, currency.round(sum_draft) + 0.0, currency_obj=currency), 'sum_waiting': formatLang(self.env, currency.round(sum_waiting) + 0.0, currency_obj=currency), 'sum_late': formatLang(self.env, currency.round(sum_late) + 0.0, currency_obj=currency), 'currency_id': currency.id, 'bank_statements_source': self.bank_statements_source, 'title': title, }
def _prepare_move_lines(self, move_lines, target_currency=False, target_date=False, recs_count=0): """ Returns move lines formatted for the manual/bank reconciliation widget :param move_line_ids: :param target_currency: currency (browse) you want the move line debit/credit converted into :param target_date: date to use for the monetary conversion """ context = dict(self._context or {}) ret = [] for line in move_lines: company_currency = line.company_id.currency_id line_currency = (line.currency_id and line.amount_currency) and line.currency_id or company_currency ret_line = { 'id': line.id, 'name': line.name and line.name != '/' and line.move_id.name + ': ' + line.name or line.move_id.name, 'ref': line.move_id.ref or '', # For reconciliation between statement transactions and already registered payments (eg. checks) # NB : we don't use the 'reconciled' field because the line we're selecting is not the one that gets reconciled 'account_id': [line.account_id.id, line.account_id.display_name], 'already_paid': line.account_id.internal_type == 'liquidity', 'account_code': line.account_id.code, 'account_name': line.account_id.name, 'account_type': line.account_id.internal_type, 'date_maturity': line.date_maturity, 'date': line.date, 'journal_id': [line.journal_id.id, line.journal_id.display_name], 'partner_id': line.partner_id.id, 'partner_name': line.partner_id.name, 'currency_id': line_currency.id, } debit = line.debit credit = line.credit amount = line.amount_residual amount_currency = line.amount_residual_currency # For already reconciled lines, don't use amount_residual(_currency) if line.account_id.internal_type == 'liquidity': amount = debit - credit amount_currency = line.amount_currency target_currency = target_currency or company_currency # Use case: # Let's assume that company currency is in USD and that we have the 3 following move lines # Debit Credit Amount currency Currency # 1) 25 0 0 NULL # 2) 17 0 25 EUR # 3) 33 0 25 YEN # # If we ask to see the information in the reconciliation widget in company currency, we want to see # The following information # 1) 25 USD (no currency information) # 2) 17 USD [25 EUR] (show 25 euro in currency information, in the little bill) # 3) 33 USD [25 YEN] (show 25 yen in currency information) # # If we ask to see the information in another currency than the company let's say EUR # 1) 35 EUR [25 USD] # 2) 25 EUR (no currency information) # 3) 50 EUR [25 YEN] # In that case, we have to convert the debit-credit to the currency we want and we show next to it # the value of the amount_currency or the debit-credit if no amount currency if target_currency == company_currency: if line_currency == target_currency: amount = amount amount_currency = "" total_amount = debit - credit total_amount_currency = "" else: amount = amount amount_currency = amount_currency total_amount = debit - credit total_amount_currency = line.amount_currency if target_currency != company_currency: if line_currency == target_currency: amount = amount_currency amount_currency = "" total_amount = line.amount_currency total_amount_currency = "" else: amount_currency = line.currency_id and amount_currency or amount company = line.account_id.company_id date = target_date or line.date amount = company_currency._convert(amount, target_currency, company, date) total_amount = company_currency._convert((line.debit - line.credit), target_currency, company, date) total_amount_currency = line.currency_id and line.amount_currency or (line.debit - line.credit) ret_line['recs_count'] = recs_count ret_line['debit'] = amount > 0 and amount or 0 ret_line['credit'] = amount < 0 and -amount or 0 ret_line['amount_currency'] = amount_currency ret_line['amount_str'] = formatLang(self.env, abs(amount), currency_obj=target_currency) ret_line['total_amount_str'] = formatLang(self.env, abs(total_amount), currency_obj=target_currency) ret_line['amount_currency_str'] = amount_currency and formatLang(self.env, abs(amount_currency), currency_obj=line_currency) or "" ret_line['total_amount_currency_str'] = total_amount_currency and formatLang(self.env, abs(total_amount_currency), currency_obj=line_currency) or "" ret.append(ret_line) return ret