diff --git a/account_reconcile_model_oca/README.rst b/account_reconcile_model_oca/README.rst new file mode 100644 index 00000000..5da1edf5 --- /dev/null +++ b/account_reconcile_model_oca/README.rst @@ -0,0 +1,80 @@ +=========================== +Account Reconcile Model Oca +=========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:62683a913039d5afe96202b49fdd537d57edf8ac49edc89bf9c9e4512971888f + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--reconcile-lightgray.png?logo=github + :target: https://github.com/OCA/account-reconcile/tree/17.0/account_reconcile_model_oca + :alt: OCA/account-reconcile +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/account-reconcile-17-0/account-reconcile-17-0-account_reconcile_model_oca + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/account-reconcile&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module restores account reconciliation models functions moved from +Odoo community to enterpise in V. 17.0 + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Dixmit +* Odoo + +Contributors +------------ + +- Dixmit + + - Enric Tobella + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/account-reconcile `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_reconcile_model_oca/__init__.py b/account_reconcile_model_oca/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/account_reconcile_model_oca/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_reconcile_model_oca/__manifest__.py b/account_reconcile_model_oca/__manifest__.py new file mode 100644 index 00000000..9dec6a1a --- /dev/null +++ b/account_reconcile_model_oca/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Account Reconcile Model Oca", + "summary": """ + This includes the logic moved from Odoo Community to Odoo Enterprise""", + "version": "17.0.1.0.0", + "license": "LGPL-3", + "author": "Dixmit,Odoo,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/account-reconcile", + "depends": ["account"], + "data": [], + "demo": [], +} diff --git a/account_reconcile_model_oca/models/__init__.py b/account_reconcile_model_oca/models/__init__.py new file mode 100644 index 00000000..cbaab70a --- /dev/null +++ b/account_reconcile_model_oca/models/__init__.py @@ -0,0 +1,2 @@ +from . import account_reconcile_model +from . import account_bank_statement_line diff --git a/account_reconcile_model_oca/models/account_bank_statement_line.py b/account_reconcile_model_oca/models/account_bank_statement_line.py new file mode 100644 index 00000000..234f76bf --- /dev/null +++ b/account_reconcile_model_oca/models/account_bank_statement_line.py @@ -0,0 +1,128 @@ +# Copyright 2023 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models +from odoo.osv.expression import get_unaccent_wrapper +from odoo.tools import html2plaintext + +from odoo.addons.base.models.res_bank import sanitize_account_number + + +class AccountBankStatementLine(models.Model): + _inherit = ("account.bank.statement.line",) + + def _retrieve_partner(self): + self.ensure_one() + + # Retrieve the partner from the statement line. + if self.partner_id: + return self.partner_id + + # Retrieve the partner from the bank account. + if self.account_number: + account_number_nums = sanitize_account_number(self.account_number) + if account_number_nums: + domain = [("sanitized_acc_number", "ilike", account_number_nums)] + for extra_domain in ([("company_id", "=", self.company_id.id)], []): + bank_accounts = self.env["res.partner.bank"].search( + extra_domain + domain + ) + if len(bank_accounts.partner_id) == 1: + return bank_accounts.partner_id + + # Retrieve the partner from the partner name. + if self.partner_name: + domain = [ + ("parent_id", "=", False), + ("name", "ilike", self.partner_name), + ] + for extra_domain in ([("company_id", "=", self.company_id.id)], []): + partner = self.env["res.partner"].search(extra_domain + domain, limit=1) + if partner: + return partner + + # Retrieve the partner from the 'reconcile models'. + rec_models = self.env["account.reconcile.model"].search( + [ + ("rule_type", "!=", "writeoff_button"), + ("company_id", "=", self.company_id.id), + ] + ) + for rec_model in rec_models: + partner = rec_model._get_partner_from_mapping(self) + if partner and rec_model._is_applicable_for(self, partner): + return partner + + # Retrieve the partner from statement line text values. + st_line_text_values = self._get_st_line_strings_for_matching() + unaccent = get_unaccent_wrapper(self._cr) + sub_queries = [] + params = [] + for text_value in st_line_text_values: + if not text_value: + continue + + # Find a partner having a name contained inside the statement line values. + # Take care a partner could contain some special characters in its name that needs to be escaped. + sub_queries.append( + rf""" + {unaccent("%s")} ~* ('^' || ( + SELECT STRING_AGG(CONCAT('(?=.*\m', chunk[1], '\M)'), '') + FROM regexp_matches({unaccent('partner.name')}, '\w{{3,}}', 'g') AS chunk + )) + """ + ) + params.append(text_value) + + if sub_queries: + self.env["res.partner"].flush_model(["company_id", "name"]) + self.env["account.move.line"].flush_model(["partner_id", "company_id"]) + self._cr.execute( + """ + SELECT aml.partner_id + FROM account_move_line aml + JOIN res_partner partner ON + aml.partner_id = partner.id + AND partner.name IS NOT NULL + AND partner.active + AND ((""" + + ") OR (".join(sub_queries) + + """)) + WHERE aml.company_id = %s + LIMIT 1 + """, + params + [self.company_id.id], + ) + row = self._cr.fetchone() + if row: + return self.env["res.partner"].browse(row[0]) + + return self.env["res.partner"] + + def _get_st_line_strings_for_matching(self, allowed_fields=None): + """Collect the strings that could be used on the statement line to perform some matching. + :param allowed_fields: A explicit list of fields to consider. + :return: A list of strings. + """ + self.ensure_one() + + def _get_text_value(field_name): + if self._fields[field_name].type == "html": + return self[field_name] and html2plaintext(self[field_name]) + else: + return self[field_name] + + st_line_text_values = [] + if allowed_fields is None or "payment_ref" in allowed_fields: + value = _get_text_value("payment_ref") + if value: + st_line_text_values.append(value) + if allowed_fields is None or "narration" in allowed_fields: + value = _get_text_value("narration") + if value: + st_line_text_values.append(value) + if allowed_fields is None or "ref" in allowed_fields: + value = _get_text_value("ref") + if value: + st_line_text_values.append(value) + return st_line_text_values diff --git a/account_reconcile_model_oca/models/account_reconcile_model.py b/account_reconcile_model_oca/models/account_reconcile_model.py new file mode 100644 index 00000000..2ad17fa4 --- /dev/null +++ b/account_reconcile_model_oca/models/account_reconcile_model.py @@ -0,0 +1,667 @@ +import re +from collections import defaultdict + +from dateutil.relativedelta import relativedelta + +from odoo import Command, fields, models, tools + + +class AccountReconcileModel(models.Model): + _inherit = "account.reconcile.model" + + #################################################### + # RECONCILIATION PROCESS + #################################################### + + def _apply_lines_for_bank_widget(self, residual_amount_currency, partner, st_line): + """Apply the reconciliation model lines to the statement line passed as parameter. + :param residual_amount_currency: The open balance of the statement line in the bank reconciliation widget + expressed in the statement line currency. + :param partner: The partner set on the wizard. + :param st_line: The statement line processed by the bank reconciliation widget. + :return: A list of python dictionaries (one per reconcile model line) representing + the journal items to be created by the current reconcile model. + """ + self.ensure_one() + currency = ( + st_line.foreign_currency_id + or st_line.journal_id.currency_id + or st_line.company_currency_id + ) + if currency.is_zero(residual_amount_currency): + return [] + + vals_list = [] + for line in self.line_ids: + vals = line._apply_in_bank_widget( + residual_amount_currency, partner, st_line + ) + amount_currency = vals["amount_currency"] + + if currency.is_zero(amount_currency): + continue + + vals_list.append(vals) + residual_amount_currency -= amount_currency + + return vals_list + + def _get_taxes_move_lines_dict(self, tax, base_line_dict): + """Get move.lines dict (to be passed to the create()) corresponding to a tax. + :param tax: An account.tax record. + :param base_line_dict: A dict representing the move.line containing the base amount. + :return: A list of dict representing move.lines to be created corresponding to the tax. + """ + self.ensure_one() + balance = base_line_dict["balance"] + + tax_type = tax.type_tax_use + is_refund = (tax_type == "sale" and balance < 0) or ( + tax_type == "purchase" and balance > 0 + ) + + res = tax.compute_all(balance, is_refund=is_refund) + + new_aml_dicts = [] + for tax_res in res["taxes"]: + tax = self.env["account.tax"].browse(tax_res["id"]) + balance = tax_res["amount"] + name = " ".join( + [x for x in [base_line_dict.get("name", ""), tax_res["name"]] if x] + ) + new_aml_dicts.append( + { + "account_id": tax_res["account_id"] or base_line_dict["account_id"], + "journal_id": base_line_dict.get("journal_id", False), + "name": name, + "partner_id": base_line_dict.get("partner_id"), + "balance": balance, + "debit": balance > 0 and balance or 0, + "credit": balance < 0 and -balance or 0, + "analytic_distribution": tax.analytic + and base_line_dict["analytic_distribution"], + "tax_repartition_line_id": tax_res["tax_repartition_line_id"], + "tax_ids": [(6, 0, tax_res["tax_ids"])], + "tax_tag_ids": [(6, 0, tax_res["tag_ids"])], + "group_tax_id": tax_res["group"].id if tax_res["group"] else False, + "currency_id": False, + "reconcile_model_id": self.id, + } + ) + + # Handle price included taxes. + base_balance = tax_res["base"] + base_line_dict.update( + { + "balance": base_balance, + "debit": base_balance > 0 and base_balance or 0, + "credit": base_balance < 0 and -base_balance or 0, + } + ) + + base_line_dict["tax_tag_ids"] = [(6, 0, res["base_tags"])] + return new_aml_dicts + + def _get_write_off_move_lines_dict(self, residual_balance, partner_id): + """Get move.lines dict corresponding to the reconciliation model's write-off lines. + :param residual_balance: The residual balance of the account on the manual reconciliation widget. + :return: A list of dict representing move.lines to be created corresponding to the write-off lines. + """ + self.ensure_one() + + if self.rule_type == "invoice_matching" and ( + not self.allow_payment_tolerance or self.payment_tolerance_param == 0 + ): + return [] + + currency = self.company_id.currency_id + + lines_vals_list = [] + for line in self.line_ids: + balance = 0 + if line.amount_type == "percentage": + balance = currency.round(residual_balance * (line.amount / 100.0)) + elif line.amount_type == "fixed": + balance = currency.round( + line.amount * (1 if residual_balance > 0.0 else -1) + ) + + if currency.is_zero(balance): + continue + + writeoff_line = { + "name": line.label, + "balance": balance, + "debit": balance > 0 and balance or 0, + "credit": balance < 0 and -balance or 0, + "account_id": line.account_id.id, + "currency_id": currency.id, + "analytic_distribution": line.analytic_distribution, + "reconcile_model_id": self.id, + "journal_id": line.journal_id.id, + "tax_ids": [], + } + lines_vals_list.append(writeoff_line) + + residual_balance -= balance + + if line.tax_ids: + taxes = line.tax_ids + detected_fiscal_position = self.env[ + "account.fiscal.position" + ]._get_fiscal_position(self.env["res.partner"].browse(partner_id)) + if detected_fiscal_position: + taxes = detected_fiscal_position.map_tax(taxes) + writeoff_line["tax_ids"] += [Command.set(taxes.ids)] + # Multiple taxes with force_tax_included results in wrong computation, so we + # only allow to set the force_tax_included field if we have one tax selected + if line.force_tax_included: + taxes = taxes[0].with_context(force_price_include=True) + tax_vals_list = self._get_taxes_move_lines_dict(taxes, writeoff_line) + lines_vals_list += tax_vals_list + if not line.force_tax_included: + for tax_line in tax_vals_list: + residual_balance -= tax_line["balance"] + + return lines_vals_list + + #################################################### + # RECONCILIATION CRITERIA + #################################################### + + def _apply_rules(self, st_line, partner): + """Apply criteria to get candidates for all reconciliation models. + This function is called in enterprise by the reconciliation widget to match + the statement line with the available candidates (using the reconciliation models). + :param st_line: The statement line to match. + :param partner: The partner to consider. + :return: A dict mapping each statement line id with: + * aml_ids: A list of account.move.line ids. + * model: An account.reconcile.model record (optional). + * status: 'reconciled' if the lines has been already reconciled, 'write_off' if the write-off + must be applied on the statement line. + * auto_reconcile: A flag indicating if the match is enough significant to auto reconcile the candidates. + """ + available_models = self.filtered( + lambda m: m.rule_type != "writeoff_button" + ).sorted() + + for rec_model in available_models: + if not rec_model._is_applicable_for(st_line, partner): + continue + + if rec_model.rule_type == "invoice_matching": + rules_map = rec_model._get_invoice_matching_rules_map() + for rule_index in sorted(rules_map.keys()): + for rule_method in rules_map[rule_index]: + candidate_vals = rule_method(st_line, partner) + if not candidate_vals: + continue + + if candidate_vals.get("amls"): + res = rec_model._get_invoice_matching_amls_result( + st_line, partner, candidate_vals + ) + if res: + return { + **res, + "model": rec_model, + } + else: + return { + **candidate_vals, + "model": rec_model, + } + + elif rec_model.rule_type == "writeoff_suggestion": + return { + "model": rec_model, + "status": "write_off", + "auto_reconcile": rec_model.auto_reconcile, + } + return {} + + def _is_applicable_for(self, st_line, partner): + """Returns true iff this reconciliation model can be used to search for matches + for the provided statement line and partner. + """ + self.ensure_one() + + # Filter on journals, amount nature, amount and partners + # All the conditions defined in this block are non-match conditions. + if ( + ( + self.match_journal_ids + and st_line.move_id.journal_id not in self.match_journal_ids + ) + or (self.match_nature == "amount_received" and st_line.amount < 0) + or (self.match_nature == "amount_paid" and st_line.amount > 0) + or ( + self.match_amount == "lower" + and abs(st_line.amount) >= self.match_amount_max + ) + or ( + self.match_amount == "greater" + and abs(st_line.amount) <= self.match_amount_min + ) + or ( + self.match_amount == "between" + and ( + abs(st_line.amount) > self.match_amount_max + or abs(st_line.amount) < self.match_amount_min + ) + ) + or (self.match_partner and not partner) + or ( + self.match_partner + and self.match_partner_ids + and partner not in self.match_partner_ids + ) + or ( + self.match_partner + and self.match_partner_category_ids + and partner.category_id not in self.match_partner_category_ids + ) + ): + return False + + # Filter on label, note and transaction_type + for record, rule_field, record_field in [ + (st_line, "label", "payment_ref"), + (st_line.move_id, "note", "narration"), + (st_line, "transaction_type", "transaction_type"), + ]: + rule_term = (self["match_" + rule_field + "_param"] or "").lower() + record_term = (record[record_field] or "").lower() + + # This defines non-match conditions + if ( + ( + self["match_" + rule_field] == "contains" + and rule_term not in record_term + ) + or ( + self["match_" + rule_field] == "not_contains" + and rule_term in record_term + ) + or ( + self["match_" + rule_field] == "match_regex" + and not re.match(rule_term, record_term) + ) + ): + return False + + return True + + def _get_invoice_matching_amls_domain(self, st_line, partner): + aml_domain = st_line._get_default_amls_matching_domain() + + if st_line.amount > 0.0: + aml_domain.append(("balance", ">", 0.0)) + else: + aml_domain.append(("balance", "<", 0.0)) + + currency = st_line.foreign_currency_id or st_line.currency_id + if self.match_same_currency: + aml_domain.append(("currency_id", "=", currency.id)) + + if partner: + aml_domain.append(("partner_id", "=", partner.id)) + + if self.past_months_limit: + date_limit = fields.Date.context_today(self) - relativedelta( + months=self.past_months_limit + ) + aml_domain.append(("date", ">=", fields.Date.to_string(date_limit))) + + return aml_domain + + def _get_invoice_matching_st_line_tokens(self, st_line): + """Parse the textual information from the statement line passed as parameter + in order to extract from it the meaningful information in order to perform the matching. + :param st_line: A statement line. + :return: A list of tokens, each one being a string. + """ + st_line_text_values = st_line._get_st_line_strings_for_matching( + allowed_fields=( + "payment_ref" if self.match_text_location_label else None, + "narration" if self.match_text_location_note else None, + "ref" if self.match_text_location_reference else None, + ) + ) + significant_token_size = 4 + tokens = [] + for text_value in st_line_text_values: + for token in (text_value or "").split(): + # The token is too short to be significant. + if len(token) < significant_token_size: + continue + + formatted_token = "".join(x for x in token if x.isdecimal()) + + # The token is too short after formatting to be significant. + if len(formatted_token) < significant_token_size: + continue + + tokens.append(formatted_token) + return tokens + + def _get_invoice_matching_amls_candidates(self, st_line, partner): + """Returns the match candidates for the 'invoice_matching' rule, with respect to the provided parameters. + :param st_line: A statement line. + :param partner: The partner associated to the statement line. + """ + assert self.rule_type == "invoice_matching" + self.env["account.move"].flush_model() + self.env["account.move.line"].flush_model() + + if self.matching_order == "new_first": + order_by = "sub.date_maturity DESC, sub.date DESC, sub.id DESC" + else: + order_by = "sub.date_maturity ASC, sub.date ASC, sub.id ASC" + + aml_domain = self._get_invoice_matching_amls_domain(st_line, partner) + query = self.env["account.move.line"]._where_calc(aml_domain) + tables, where_clause, where_params = query.get_sql() + + tokens = self._get_invoice_matching_st_line_tokens(st_line) + if tokens: + sub_queries = [] + for table_alias, field in ( + ("account_move_line", "name"), + ("account_move_line__move_id", "name"), + ("account_move_line__move_id", "ref"), + ): + sub_queries.append( + rf""" + SELECT + account_move_line.id, + account_move_line.date, + account_move_line.date_maturity, + UNNEST( + REGEXP_SPLIT_TO_ARRAY( + SUBSTRING( + REGEXP_REPLACE({table_alias}.{field}, '[^0-9\s]', '', 'g'), + '\S(?:.*\S)*' + ), + '\s+' + ) + ) AS token + FROM {tables} + JOIN account_move account_move_line__move_id ON account_move_line__move_id.id = account_move_line.move_id + WHERE {where_clause} AND {table_alias}.{field} IS NOT NULL + """ + ) + + self._cr.execute( + """ + SELECT + sub.id, + COUNT(*) AS nb_match + FROM (""" + + " UNION ALL ".join(sub_queries) + + """) AS sub + WHERE sub.token IN %s + GROUP BY sub.date_maturity, sub.date, sub.id + HAVING COUNT(*) > 0 + ORDER BY nb_match DESC, """ + + order_by + + """ + """, + (where_params * 3) + [tuple(tokens)], + ) + candidate_ids = [r[0] for r in self._cr.fetchall()] + if candidate_ids: + return { + "allow_auto_reconcile": True, + "amls": self.env["account.move.line"].browse(candidate_ids), + } + + # Search without any matching based on textual information. + if partner: + if self.matching_order == "new_first": + order = "date_maturity DESC, date DESC, id DESC" + else: + order = "date_maturity ASC, date ASC, id ASC" + + amls = self.env["account.move.line"].search(aml_domain, order=order) + if amls: + return { + "allow_auto_reconcile": False, + "amls": amls, + } + + def _get_invoice_matching_rules_map(self): + """Get a mapping that could be overridden in others modules. + :return: a mapping where: + * priority_order: Defines in which order the rules will be evaluated, the lowest comes first. + This is extremely important since the algorithm stops when a rule returns some candidates. + * rule: Method taking as parameters and returning the candidates journal items found. + """ + rules_map = defaultdict(list) + rules_map[10].append(self._get_invoice_matching_amls_candidates) + return rules_map + + def _get_partner_from_mapping(self, st_line): + """Find partner with mapping defined on model. + For invoice matching rules, matches the statement line against each + regex defined in partner mapping, and returns the partner corresponding + to the first one matching. + :param st_line (Model): + The statement line that needs a partner to be found + :return Model: + The partner found from the mapping. Can be empty an empty recordset + if there was nothing found from the mapping or if the function is + not applicable. + """ + self.ensure_one() + + if self.rule_type not in ("invoice_matching", "writeoff_suggestion"): + return self.env["res.partner"] + + for partner_mapping in self.partner_mapping_line_ids: + match_payment_ref = ( + re.match(partner_mapping.payment_ref_regex, st_line.payment_ref) + if partner_mapping.payment_ref_regex + else True + ) + match_narration = ( + re.match( + partner_mapping.narration_regex, + tools.html2plaintext(st_line.narration or "").rstrip(), + ) + if partner_mapping.narration_regex + else True + ) + + if match_payment_ref and match_narration: + return partner_mapping.partner_id + return self.env["res.partner"] + + def _get_invoice_matching_amls_result(self, st_line, partner, candidate_vals): # noqa: C901 + def _create_result_dict(amls_values_list, status): + if "rejected" in status: + return + + result = {"amls": self.env["account.move.line"]} + for aml_values in amls_values_list: + result["amls"] |= aml_values["aml"] + + if "allow_write_off" in status and self.line_ids: + result["status"] = "write_off" + + if ( + "allow_auto_reconcile" in status + and candidate_vals["allow_auto_reconcile"] + and self.auto_reconcile + ): + result["auto_reconcile"] = True + + return result + + st_line_currency = st_line.foreign_currency_id or st_line.currency_id + st_line_amount = st_line._prepare_move_line_default_vals()[1]["amount_currency"] + sign = 1 if st_line_amount > 0.0 else -1 + + amls = candidate_vals["amls"] + amls_values_list = [] + amls_with_epd_values_list = [] + same_currency_mode = amls.currency_id == st_line_currency + for aml in amls: + aml_values = { + "aml": aml, + "amount_residual": aml.amount_residual, + "amount_residual_currency": aml.amount_residual_currency, + } + + amls_values_list.append(aml_values) + + # Manage the early payment discount. + if ( + same_currency_mode + and aml.move_id.move_type + in ("out_invoice", "out_receipt", "in_invoice", "in_receipt") + and not aml.matched_debit_ids + and not aml.matched_credit_ids + and aml.discount_date + and st_line.date <= aml.discount_date + ): + rate = ( + abs(aml.amount_currency) / abs(aml.balance) if aml.balance else 1.0 + ) + amls_with_epd_values_list.append( + { + **aml_values, + "amount_residual": st_line.company_currency_id.round( + aml.discount_amount_currency / rate + ), + "amount_residual_currency": aml.discount_amount_currency, + } + ) + else: + amls_with_epd_values_list.append(aml_values) + + def match_batch_amls(amls_values_list): + if not same_currency_mode: + return None, [] + + kepts_amls_values_list = [] + sum_amount_residual_currency = 0.0 + for aml_values in amls_values_list: + if ( + st_line_currency.compare_amounts( + st_line_amount, -aml_values["amount_residual_currency"] + ) + == 0 + ): + # Special case: the amounts are the same, submit the line directly. + return "perfect", [aml_values] + + if ( + st_line_currency.compare_amounts( + sign * (st_line_amount + sum_amount_residual_currency), 0.0 + ) + > 0 + ): + # Here, we still have room for other candidates ; so we add the current one to the list we keep. + # Then, we continue iterating, even if there is no room anymore, just in case one of the following candidates + # is an exact match, which would then be preferred on the current candidates. + kepts_amls_values_list.append(aml_values) + sum_amount_residual_currency += aml_values[ + "amount_residual_currency" + ] + + if st_line_currency.is_zero( + sign * (st_line_amount + sum_amount_residual_currency) + ): + return "perfect", kepts_amls_values_list + elif kepts_amls_values_list: + return "partial", kepts_amls_values_list + else: + return None, [] + + # Try to match a batch with the early payment feature. Only a perfect match is allowed. + match_type, kepts_amls_values_list = match_batch_amls(amls_with_epd_values_list) + if match_type != "perfect": + kepts_amls_values_list = [] + + # Try to match the amls having the same currency as the statement line. + if not kepts_amls_values_list: + _match_type, kepts_amls_values_list = match_batch_amls(amls_values_list) + + # Try to match the whole candidates. + if not kepts_amls_values_list: + kepts_amls_values_list = amls_values_list + + # Try to match the amls having the same currency as the statement line. + if kepts_amls_values_list: + status = self._check_rule_propositions(st_line, kepts_amls_values_list) + result = _create_result_dict(kepts_amls_values_list, status) + if result: + return result + + def _check_rule_propositions(self, st_line, amls_values_list): + """Check restrictions that can't be handled for each move.line separately. + Note: Only used by models having a type equals to 'invoice_matching'. + :param st_line: The statement line. + :param amls_values_list: The candidates account.move.line as a list of dict: + * aml: The record. + * amount_residual: The amount residual to consider. + * amount_residual_currency: The amount residual in foreign currency to consider. + :return: A string representing what to do with the candidates: + * rejected: Reject candidates. + * allow_write_off: Allow to generate the write-off from the reconcile model lines if specified. + * allow_auto_reconcile: Allow to automatically reconcile entries if 'auto_validate' is enabled. + """ + self.ensure_one() + + if not self.allow_payment_tolerance: + return {"allow_write_off", "allow_auto_reconcile"} + + st_line_currency = st_line.foreign_currency_id or st_line.currency_id + st_line_amount_curr = st_line._prepare_move_line_default_vals()[1][ + "amount_currency" + ] + amls_amount_curr = sum( + st_line._prepare_counterpart_amounts_using_st_line_rate( + aml_values["aml"].currency_id, + aml_values["amount_residual"], + aml_values["amount_residual_currency"], + )["amount_currency"] + for aml_values in amls_values_list + ) + sign = 1 if st_line_amount_curr > 0.0 else -1 + amount_curr_after_rec = sign * (amls_amount_curr + st_line_amount_curr) + + # The statement line will be fully reconciled. + if st_line_currency.is_zero(amount_curr_after_rec): + return {"allow_auto_reconcile"} + + # The payment amount is higher than the sum of invoices. + # In that case, don't check the tolerance and don't try to generate any write-off. + if amount_curr_after_rec > 0.0: + return {"allow_auto_reconcile"} + + # No tolerance, reject the candidates. + if self.payment_tolerance_param == 0: + return {"rejected"} + + # If the tolerance is expressed as a fixed amount, check the residual payment amount doesn't exceed the + # tolerance. + if ( + self.payment_tolerance_type == "fixed_amount" + and -amount_curr_after_rec <= self.payment_tolerance_param + ): + return {"allow_write_off", "allow_auto_reconcile"} + + # The tolerance is expressed as a percentage between 0 and 100.0. + reconciled_percentage_left = ( + abs(amount_curr_after_rec / amls_amount_curr) + ) * 100.0 + if ( + self.payment_tolerance_type == "percentage" + and reconciled_percentage_left <= self.payment_tolerance_param + ): + return {"allow_write_off", "allow_auto_reconcile"} + + return {"rejected"} diff --git a/account_reconcile_model_oca/pyproject.toml b/account_reconcile_model_oca/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/account_reconcile_model_oca/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/account_reconcile_model_oca/readme/CONTRIBUTORS.md b/account_reconcile_model_oca/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..becca427 --- /dev/null +++ b/account_reconcile_model_oca/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- Dixmit + + - Enric Tobella diff --git a/account_reconcile_model_oca/readme/DESCRIPTION.md b/account_reconcile_model_oca/readme/DESCRIPTION.md new file mode 100644 index 00000000..f296e000 --- /dev/null +++ b/account_reconcile_model_oca/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module restores account reconciliation models functions moved from Odoo community to enterpise in V. 17.0 diff --git a/account_reconcile_model_oca/static/description/icon.png b/account_reconcile_model_oca/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/account_reconcile_model_oca/static/description/icon.png differ diff --git a/account_reconcile_model_oca/static/description/index.html b/account_reconcile_model_oca/static/description/index.html new file mode 100644 index 00000000..b0ab3f40 --- /dev/null +++ b/account_reconcile_model_oca/static/description/index.html @@ -0,0 +1,426 @@ + + + + + + +Account Reconcile Model Oca + + + +
+

Account Reconcile Model Oca

+ + +

Beta License: LGPL-3 OCA/account-reconcile Translate me on Weblate Try me on Runboat

+

This module restores account reconciliation models functions moved from +Odoo community to enterpise in V. 17.0

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Dixmit
  • +
  • Odoo
  • +
+
+
+

Contributors

+
    +
  • Dixmit
      +
    • Enric Tobella
    • +
    +
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/account-reconcile project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/account_reconcile_model_oca/tests/__init__.py b/account_reconcile_model_oca/tests/__init__.py new file mode 100644 index 00000000..4198497c --- /dev/null +++ b/account_reconcile_model_oca/tests/__init__.py @@ -0,0 +1 @@ +from . import test_reconciliation_match diff --git a/account_reconcile_model_oca/tests/common.py b/account_reconcile_model_oca/tests/common.py new file mode 100644 index 00000000..7b9a804c --- /dev/null +++ b/account_reconcile_model_oca/tests/common.py @@ -0,0 +1,243 @@ +import time + +from odoo import Command + +from odoo.addons.account.tests.common import AccountTestInvoicingCommon + + +class TestAccountReconciliationCommon(AccountTestInvoicingCommon): + + """Tests for reconciliation (account.tax) + + Test used to check that when doing a sale or purchase invoice in a different currency, + the result will be balanced. + """ + + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + + cls.company = cls.company_data["company"] + cls.company.currency_id = cls.env.ref("base.EUR") + + cls.partner_agrolait = cls.env["res.partner"].create( + { + "name": "Deco Addict", + "is_company": True, + "country_id": cls.env.ref("base.us").id, + } + ) + cls.partner_agrolait_id = cls.partner_agrolait.id + cls.currency_swiss_id = cls.env.ref("base.CHF").id + cls.currency_usd_id = cls.env.ref("base.USD").id + cls.currency_euro_id = cls.env.ref("base.EUR").id + cls.account_rcv = cls.company_data["default_account_receivable"] + cls.account_rsa = cls.company_data["default_account_payable"] + cls.product = cls.env["product.product"].create( + { + "name": "Product Product 4", + "standard_price": 500.0, + "list_price": 750.0, + "type": "consu", + "categ_id": cls.env.ref("product.product_category_all").id, + } + ) + + cls.bank_journal_euro = cls.env["account.journal"].create( + {"name": "Bank", "type": "bank", "code": "BNK67"} + ) + cls.account_euro = cls.bank_journal_euro.default_account_id + + cls.bank_journal_usd = cls.env["account.journal"].create( + { + "name": "Bank US", + "type": "bank", + "code": "BNK68", + "currency_id": cls.currency_usd_id, + } + ) + cls.account_usd = cls.bank_journal_usd.default_account_id + + cls.fx_journal = cls.company.currency_exchange_journal_id + cls.diff_income_account = cls.company.income_currency_exchange_account_id + cls.diff_expense_account = cls.company.expense_currency_exchange_account_id + + cls.expense_account = cls.company_data["default_account_expense"] + # cash basis intermediary account + cls.tax_waiting_account = cls.env["account.account"].create( + { + "name": "TAX_WAIT", + "code": "TWAIT", + "account_type": "liability_current", + "reconcile": True, + "company_id": cls.company.id, + } + ) + # cash basis final account + cls.tax_final_account = cls.env["account.account"].create( + { + "name": "TAX_TO_DEDUCT", + "code": "TDEDUCT", + "account_type": "asset_current", + "company_id": cls.company.id, + } + ) + cls.tax_base_amount_account = cls.env["account.account"].create( + { + "name": "TAX_BASE", + "code": "TBASE", + "account_type": "asset_current", + "company_id": cls.company.id, + } + ) + cls.company.account_cash_basis_base_account_id = cls.tax_base_amount_account.id + + # Journals + cls.purchase_journal = cls.company_data["default_journal_purchase"] + cls.cash_basis_journal = cls.env["account.journal"].create( + { + "name": "Test CABA", + "code": "tCABA", + "type": "general", + } + ) + cls.general_journal = cls.company_data["default_journal_misc"] + + # Tax Cash Basis + cls.tax_cash_basis = cls.env["account.tax"].create( + { + "name": "cash basis 20%", + "type_tax_use": "purchase", + "company_id": cls.company.id, + "country_id": cls.company.account_fiscal_country_id.id, + "amount": 20, + "tax_exigibility": "on_payment", + "cash_basis_transition_account_id": cls.tax_waiting_account.id, + "invoice_repartition_line_ids": [ + ( + 0, + 0, + { + "repartition_type": "base", + }, + ), + ( + 0, + 0, + { + "repartition_type": "tax", + "account_id": cls.tax_final_account.id, + }, + ), + ], + "refund_repartition_line_ids": [ + ( + 0, + 0, + { + "repartition_type": "base", + }, + ), + ( + 0, + 0, + { + "repartition_type": "tax", + "account_id": cls.tax_final_account.id, + }, + ), + ], + } + ) + cls.env["res.currency.rate"].create( + [ + { + "currency_id": cls.env.ref("base.EUR").id, + "name": "2010-01-02", + "rate": 1.0, + }, + { + "currency_id": cls.env.ref("base.USD").id, + "name": "2010-01-02", + "rate": 1.2834, + }, + { + "currency_id": cls.env.ref("base.USD").id, + "name": time.strftime("%Y-06-05"), + "rate": 1.5289, + }, + ] + ) + + def _create_invoice( + self, + move_type="out_invoice", + invoice_amount=50, + currency_id=None, + partner_id=None, + date_invoice=None, + payment_term_id=False, + auto_validate=False, + ): + date_invoice = date_invoice or time.strftime("%Y") + "-07-01" + + invoice_vals = { + "move_type": move_type, + "partner_id": partner_id or self.partner_agrolait_id, + "invoice_date": date_invoice, + "date": date_invoice, + "invoice_line_ids": [ + ( + 0, + 0, + { + "name": "product that cost %s" % invoice_amount, + "quantity": 1, + "price_unit": invoice_amount, + "tax_ids": [Command.set([])], + }, + ) + ], + } + + if payment_term_id: + invoice_vals["invoice_payment_term_id"] = payment_term_id + + if currency_id: + invoice_vals["currency_id"] = currency_id + + invoice = ( + self.env["account.move"] + .with_context(default_move_type=move_type) + .create(invoice_vals) + ) + if auto_validate: + invoice.action_post() + return invoice + + def create_invoice( + self, move_type="out_invoice", invoice_amount=50, currency_id=None + ): + return self._create_invoice( + move_type=move_type, + invoice_amount=invoice_amount, + currency_id=currency_id, + auto_validate=True, + ) + + def create_invoice_partner( + self, + move_type="out_invoice", + invoice_amount=50, + currency_id=None, + partner_id=False, + payment_term_id=False, + ): + return self._create_invoice( + move_type=move_type, + invoice_amount=invoice_amount, + currency_id=currency_id, + partner_id=partner_id, + payment_term_id=payment_term_id, + auto_validate=True, + ) diff --git a/account_reconcile_model_oca/tests/test_reconciliation_match.py b/account_reconcile_model_oca/tests/test_reconciliation_match.py new file mode 100644 index 00000000..26704d15 --- /dev/null +++ b/account_reconcile_model_oca/tests/test_reconciliation_match.py @@ -0,0 +1,1491 @@ +from freezegun import freeze_time + +from odoo import Command +from odoo.tests import tagged +from odoo.tests.common import Form + +from odoo.addons.account.tests.common import AccountTestInvoicingCommon + + +@tagged("post_install", "-at_install") +class TestReconciliationMatchingRules(AccountTestInvoicingCommon): + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + + ################# + # Company setup # + ################# + cls.currency_data_2 = cls.setup_multi_currency_data( + { + "name": "Dark Chocolate Coin", + "symbol": "🍫", + "currency_unit_label": "Dark Choco", + "currency_subunit_label": "Dark Cacao Powder", + }, + rate2016=10.0, + rate2017=20.0, + ) + + cls.company = cls.company_data["company"] + + cls.account_pay = cls.company_data["default_account_payable"] + cls.current_assets_account = cls.env["account.account"].search( + [ + ("account_type", "=", "asset_current"), + ("company_id", "=", cls.company.id), + ], + limit=1, + ) + + cls.bank_journal = cls.env["account.journal"].search( + [("type", "=", "bank"), ("company_id", "=", cls.company.id)], limit=1 + ) + cls.cash_journal = cls.env["account.journal"].search( + [("type", "=", "cash"), ("company_id", "=", cls.company.id)], limit=1 + ) + + cls.tax21 = cls.env["account.tax"].create( + { + "name": "21%", + "type_tax_use": "purchase", + "amount": 21, + } + ) + + cls.tax12 = cls.env["account.tax"].create( + { + "name": "12%", + "type_tax_use": "purchase", + "amount": 12, + } + ) + + cls.partner_1 = cls.env["res.partner"].create( + {"name": "partner_1", "company_id": cls.company.id} + ) + cls.partner_2 = cls.env["res.partner"].create( + {"name": "partner_2", "company_id": cls.company.id} + ) + cls.partner_3 = cls.env["res.partner"].create( + {"name": "partner_3", "company_id": cls.company.id} + ) + + ############### + # Rules setup # + ############### + cls.rule_1 = cls.env["account.reconcile.model"].create( + { + "name": "Invoices Matching Rule", + "sequence": "1", + "rule_type": "invoice_matching", + "auto_reconcile": False, + "match_nature": "both", + "match_same_currency": True, + "allow_payment_tolerance": True, + "payment_tolerance_type": "percentage", + "payment_tolerance_param": 0.0, + "match_partner": True, + "match_partner_ids": [ + (6, 0, (cls.partner_1 + cls.partner_2 + cls.partner_3).ids) + ], + "company_id": cls.company.id, + "line_ids": [(0, 0, {"account_id": cls.current_assets_account.id})], + } + ) + cls.rule_2 = cls.env["account.reconcile.model"].create( + { + "name": "write-off model", + "rule_type": "writeoff_suggestion", + "match_partner": True, + "match_partner_ids": [], + "line_ids": [(0, 0, {"account_id": cls.current_assets_account.id})], + } + ) + + ################## + # Invoices setup # + ################## + cls.invoice_line_1 = cls._create_invoice_line(100, cls.partner_1, "out_invoice") + cls.invoice_line_2 = cls._create_invoice_line(200, cls.partner_1, "out_invoice") + cls.invoice_line_3 = cls._create_invoice_line( + 300, cls.partner_1, "in_refund", name="RBILL/2019/09/0013" + ) + cls.invoice_line_4 = cls._create_invoice_line(1000, cls.partner_2, "in_invoice") + cls.invoice_line_5 = cls._create_invoice_line(600, cls.partner_3, "out_invoice") + cls.invoice_line_6 = cls._create_invoice_line( + 600, cls.partner_3, "out_invoice", ref="RF12 3456" + ) + cls.invoice_line_7 = cls._create_invoice_line( + 200, cls.partner_3, "out_invoice", pay_reference="RF12 3456" + ) + + #################### + # Statements setup # + #################### + # TODO : account_number, partner_name, transaction_type, narration + invoice_number = cls.invoice_line_1.move_id.name + ( + cls.bank_line_1, + cls.bank_line_2, + cls.bank_line_3, + cls.bank_line_4, + cls.bank_line_5, + cls.cash_line_1, + ) = cls.env["account.bank.statement.line"].create( + [ + { + "journal_id": cls.bank_journal.id, + "date": "2020-01-01", + "payment_ref": "invoice {}-{}".format( + *invoice_number.split("/")[1:] + ), + "partner_id": cls.partner_1.id, + "amount": 100, + "sequence": 1, + }, + { + "journal_id": cls.bank_journal.id, + "date": "2020-01-01", + "payment_ref": "xxxxx", + "partner_id": cls.partner_1.id, + "amount": 600, + "sequence": 2, + }, + { + "journal_id": cls.bank_journal.id, + "date": "2020-01-01", + "payment_ref": "nawak", + "narration": "Communication: RF12 3456", + "partner_id": cls.partner_3.id, + "amount": 600, + "sequence": 1, + }, + { + "journal_id": cls.bank_journal.id, + "date": "2020-01-01", + "payment_ref": "RF12 3456", + "partner_id": cls.partner_3.id, + "amount": 600, + "sequence": 2, + }, + { + "journal_id": cls.bank_journal.id, + "date": "2020-01-01", + "payment_ref": "baaaaah", + "ref": "RF12 3456", + "partner_id": cls.partner_3.id, + "amount": 600, + "sequence": 2, + }, + { + "journal_id": cls.cash_journal.id, + "date": "2020-01-01", + "payment_ref": "yyyyy", + "partner_id": cls.partner_2.id, + "amount": -1000, + "sequence": 1, + }, + ] + ) + + @classmethod + def _create_invoice_line( + cls, + amount, + partner, + move_type, + currency=None, + pay_reference=None, + ref=None, + name=None, + inv_date="2019-09-01", + ): + """Create an invoice on the fly.""" + invoice_form = Form( + cls.env["account.move"].with_context( + default_move_type=move_type, + default_invoice_date=inv_date, + default_date=inv_date, + ) + ) + invoice_form.partner_id = partner + if currency: + invoice_form.currency_id = currency + if pay_reference: + invoice_form.payment_reference = pay_reference + if ref: + invoice_form.ref = ref + if name: + invoice_form.name = name + with invoice_form.invoice_line_ids.new() as invoice_line_form: + invoice_line_form.name = "xxxx" + invoice_line_form.quantity = 1 + invoice_line_form.price_unit = amount + invoice_line_form.tax_ids.clear() + invoice = invoice_form.save() + invoice.action_post() + lines = invoice.line_ids + return lines.filtered( + lambda line: line.account_id.account_type + in ("asset_receivable", "liability_payable") + ) + + @classmethod + def _create_st_line( + cls, amount=1000.0, date="2019-01-01", payment_ref="turlututu", **kwargs + ): + st_line = cls.env["account.bank.statement.line"].create( + { + "journal_id": kwargs.get("journal_id", cls.bank_journal.id), + "amount": amount, + "date": date, + "payment_ref": payment_ref, + "partner_id": cls.partner_a.id, + **kwargs, + } + ) + return st_line + + @classmethod + def _create_reconcile_model(cls, **kwargs): + return cls.env["account.reconcile.model"].create( + { + "name": "test", + "rule_type": "invoice_matching", + "allow_payment_tolerance": True, + "payment_tolerance_type": "percentage", + "payment_tolerance_param": 0.0, + **kwargs, + "line_ids": [ + Command.create( + { + "account_id": cls.company_data[ + "default_account_revenue" + ].id, + "amount_type": "percentage", + "label": f"test {i}", + **line_vals, + } + ) + for i, line_vals in enumerate(kwargs.get("line_ids", [])) + ], + "partner_mapping_line_ids": [ + Command.create(line_vals) + for i, line_vals in enumerate( + kwargs.get("partner_mapping_line_ids", []) + ) + ], + } + ) + + @freeze_time("2020-01-01") + def _check_statement_matching(self, rules, expected_values_list): + for statement_line, expected_values in expected_values_list.items(): + res = rules._apply_rules(statement_line, statement_line._retrieve_partner()) + self.assertDictEqual(res, expected_values) + + def test_matching_fields(self): + # Check without restriction. + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {"amls": self.invoice_line_1, "model": self.rule_1}, + self.bank_line_2: { + "amls": self.invoice_line_1 + + self.invoice_line_2 + + self.invoice_line_3, + "model": self.rule_1, + }, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + + @freeze_time("2020-01-01") + def test_matching_fields_match_text_location(self): + st_line = self._create_st_line( + payment_ref="1111", ref="2222 3333", narration="4444 5555 6666" + ) + + inv1 = self._create_invoice_line( + 1000, self.partner_a, "out_invoice", pay_reference="bernard 1111 gagnant" + ) + inv2 = self._create_invoice_line( + 1000, self.partner_a, "out_invoice", pay_reference="2222 turlututu 3333" + ) + inv3 = self._create_invoice_line( + 1000, + self.partner_a, + "out_invoice", + pay_reference="4444 tsoin 5555 tsoin 6666", + ) + + rule = self._create_reconcile_model( + allow_payment_tolerance=False, + match_text_location_label=True, + match_text_location_reference=False, + match_text_location_note=False, + ) + self.assertDictEqual( + rule._apply_rules(st_line, st_line._retrieve_partner()), + {"amls": inv1, "model": rule}, + ) + + rule.match_text_location_reference = True + self.assertDictEqual( + rule._apply_rules(st_line, st_line._retrieve_partner()), + {"amls": inv2, "model": rule}, + ) + + rule.match_text_location_note = True + self.assertDictEqual( + rule._apply_rules(st_line, st_line._retrieve_partner()), + {"amls": inv3, "model": rule}, + ) + + def test_matching_fields_match_text_location_no_partner(self): + self.bank_line_2.unlink() # One line is enough for this test + self.bank_line_1.partner_id = None + + self.partner_1.name = "Bernard Gagnant" + + self.rule_1.write( + { + "match_partner": False, + "match_partner_ids": [(5, 0, 0)], + "line_ids": [(5, 0, 0)], + } + ) + + st_line_initial_vals = { + "ref": None, + "payment_ref": "nothing", + "narration": None, + } + recmod_initial_vals = { + "match_text_location_label": False, + "match_text_location_note": False, + "match_text_location_reference": False, + } + + rec_mod_options_to_fields = { + "match_text_location_label": "payment_ref", + "match_text_location_note": "narration", + "match_text_location_reference": "ref", + } + + for rec_mod_field, st_line_field in rec_mod_options_to_fields.items(): + self.rule_1.write({**recmod_initial_vals, rec_mod_field: True}) + # Fully reinitialize the statement line + self.bank_line_1.write(st_line_initial_vals) + + # Nothing should match + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + }, + ) + + # Test matching with the invoice ref + self.bank_line_1.write( + {st_line_field: self.invoice_line_1.move_id.payment_reference} + ) + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: { + "amls": self.invoice_line_1, + "model": self.rule_1, + }, + }, + ) + + # Test matching with the partner name (reinitializing the statement line first) + self.bank_line_1.write( + {**st_line_initial_vals, st_line_field: self.partner_1.name} + ) + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: { + "amls": self.invoice_line_1, + "model": self.rule_1, + }, + }, + ) + + def test_matching_fields_match_journal_ids(self): + self.rule_1.match_journal_ids |= self.cash_line_1.journal_id + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: {}, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + + def test_matching_fields_match_nature(self): + self.rule_1.match_nature = "amount_received" + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {"amls": self.invoice_line_1, "model": self.rule_1}, + self.bank_line_2: { + "amls": self.invoice_line_2 + + self.invoice_line_3 + + self.invoice_line_1, + "model": self.rule_1, + }, + self.cash_line_1: {}, + }, + ) + self.rule_1.match_nature = "amount_paid" + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: {}, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + + def test_matching_fields_match_amount(self): + self.rule_1.match_amount = "lower" + self.rule_1.match_amount_max = 150 + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {"amls": self.invoice_line_1, "model": self.rule_1}, + self.bank_line_2: {}, + self.cash_line_1: {}, + }, + ) + self.rule_1.match_amount = "greater" + self.rule_1.match_amount_min = 200 + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: { + "amls": self.invoice_line_1 + + self.invoice_line_2 + + self.invoice_line_3, + "model": self.rule_1, + }, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + self.rule_1.match_amount = "between" + self.rule_1.match_amount_min = 200 + self.rule_1.match_amount_max = 800 + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: { + "amls": self.invoice_line_1 + + self.invoice_line_2 + + self.invoice_line_3, + "model": self.rule_1, + }, + self.cash_line_1: {}, + }, + ) + + def test_matching_fields_match_label(self): + self.rule_1.match_label = "contains" + self.rule_1.match_label_param = "yyyyy" + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: {}, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + self.rule_1.match_label = "not_contains" + self.rule_1.match_label_param = "xxxxx" + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {"amls": self.invoice_line_1, "model": self.rule_1}, + self.bank_line_2: {}, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + self.rule_1.match_label = "match_regex" + self.rule_1.match_label_param = "xxxxx|yyyyy" + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: { + "amls": self.invoice_line_1 + + self.invoice_line_2 + + self.invoice_line_3, + "model": self.rule_1, + }, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + + @freeze_time("2019-01-01") + def test_zero_payment_tolerance(self): + rule = self._create_reconcile_model(line_ids=[{}]) + + for inv_type, bsl_sign in (("out_invoice", 1), ("in_invoice", -1)): + invl = self._create_invoice_line( + 1000.0, self.partner_a, inv_type, inv_date="2019-01-01" + ) + + # Exact matching. + st_line = self._create_st_line(amount=bsl_sign * 1000.0) + self._check_statement_matching( + rule, + {st_line: {"amls": invl, "model": rule}}, + ) + + # No matching because there is no tolerance. + st_line = self._create_st_line(amount=bsl_sign * 990.0) + self._check_statement_matching( + rule, + {st_line: {}}, + ) + + # The payment amount is higher than the invoice one. + st_line = self._create_st_line(amount=bsl_sign * 1010.0) + self._check_statement_matching( + rule, + {st_line: {"amls": invl, "model": rule}}, + ) + + @freeze_time("2019-01-01") + def test_zero_payment_tolerance_auto_reconcile(self): + rule = self._create_reconcile_model( + auto_reconcile=True, + line_ids=[{}], + ) + + for inv_type, bsl_sign in (("out_invoice", 1), ("in_invoice", -1)): + invl = self._create_invoice_line( + 1000.0, + self.partner_a, + inv_type, + pay_reference="123456", + inv_date="2019-01-01", + ) + + # No matching because there is no tolerance. + st_line = self._create_st_line(amount=bsl_sign * 990.0) + self._check_statement_matching( + rule, + {st_line: {}}, + ) + + # The payment amount is higher than the invoice one. + st_line = self._create_st_line( + amount=bsl_sign * 1010.0, payment_ref="123456" + ) + self._check_statement_matching( + rule, + {st_line: {"amls": invl, "model": rule, "auto_reconcile": True}}, + ) + + @freeze_time("2019-01-01") + def test_not_enough_payment_tolerance(self): + rule = self._create_reconcile_model( + payment_tolerance_param=0.5, + line_ids=[{}], + ) + + for inv_type, bsl_sign in (("out_invoice", 1), ("in_invoice", -1)): + with self.subTest(inv_type=inv_type, bsl_sign=bsl_sign): + invl = self._create_invoice_line( + 1000.0, self.partner_a, inv_type, inv_date="2019-01-01" + ) + + # No matching because there is no enough tolerance. + st_line = self._create_st_line(amount=bsl_sign * 990.0) + self._check_statement_matching( + rule, + {st_line: {}}, + ) + + # The payment amount is higher than the invoice one. + # However, since the invoice amount is lower than the payment amount, + # the tolerance is not checked and the invoice line is matched. + st_line = self._create_st_line(amount=bsl_sign * 1010.0) + self._check_statement_matching( + rule, + {st_line: {"amls": invl, "model": rule}}, + ) + + @freeze_time("2019-01-01") + def test_enough_payment_tolerance(self): + rule = self._create_reconcile_model( + payment_tolerance_param=1.0, + line_ids=[{}], + ) + + for inv_type, bsl_sign in (("out_invoice", 1), ("in_invoice", -1)): + invl = self._create_invoice_line( + 1000.0, self.partner_a, inv_type, inv_date="2019-01-01" + ) + + # Enough tolerance to match the invoice line. + st_line = self._create_st_line(amount=bsl_sign * 990.0) + self._check_statement_matching( + rule, + {st_line: {"amls": invl, "model": rule, "status": "write_off"}}, + ) + + # The payment amount is higher than the invoice one. + # However, since the invoice amount is lower than the payment amount, + # the tolerance is not checked and the invoice line is matched. + st_line = self._create_st_line(amount=bsl_sign * 1010.0) + self._check_statement_matching( + rule, + {st_line: {"amls": invl, "model": rule}}, + ) + + @freeze_time("2019-01-01") + def test_enough_payment_tolerance_auto_reconcile_not_full(self): + rule = self._create_reconcile_model( + payment_tolerance_param=1.0, + auto_reconcile=True, + line_ids=[{"amount_type": "percentage_st_line", "amount_string": "200.0"}], + ) + + for inv_type, bsl_sign in (("out_invoice", 1), ("in_invoice", -1)): + invl = self._create_invoice_line( + 1000.0, + self.partner_a, + inv_type, + pay_reference="123456", + inv_date="2019-01-01", + ) + + # Enough tolerance to match the invoice line. + st_line = self._create_st_line( + amount=bsl_sign * 990.0, payment_ref="123456" + ) + self._check_statement_matching( + rule, + { + st_line: { + "amls": invl, + "model": rule, + "status": "write_off", + "auto_reconcile": True, + } + }, + ) + + @freeze_time("2019-01-01") + def test_allow_payment_tolerance_lower_amount(self): + rule = self._create_reconcile_model( + line_ids=[{"amount_type": "percentage_st_line"}] + ) + + for inv_type, bsl_sign in (("out_invoice", 1), ("in_invoice", -1)): + invl = self._create_invoice_line( + 990.0, self.partner_a, inv_type, inv_date="2019-01-01" + ) + st_line = self._create_st_line(amount=bsl_sign * 1000) + + # Partial reconciliation. + self._check_statement_matching( + rule, + {st_line: {"amls": invl, "model": rule}}, + ) + + @freeze_time("2019-01-01") + def test_enough_payment_tolerance_auto_reconcile(self): + rule = self._create_reconcile_model( + payment_tolerance_param=1.0, + auto_reconcile=True, + line_ids=[{}], + ) + + for inv_type, bsl_sign in (("out_invoice", 1), ("in_invoice", -1)): + invl = self._create_invoice_line( + 1000.0, + self.partner_a, + inv_type, + pay_reference="123456", + inv_date="2019-01-01", + ) + + # Enough tolerance to match the invoice line. + st_line = self._create_st_line( + amount=bsl_sign * 990.0, payment_ref="123456" + ) + self._check_statement_matching( + rule, + { + st_line: { + "amls": invl, + "model": rule, + "status": "write_off", + "auto_reconcile": True, + } + }, + ) + + @freeze_time("2019-01-01") + def test_percentage_st_line_auto_reconcile(self): + rule = self._create_reconcile_model( + payment_tolerance_param=1.0, + rule_type="writeoff_suggestion", + auto_reconcile=True, + line_ids=[ + { + "amount_type": "percentage_st_line", + "amount_string": "100.0", + "label": "A", + }, + { + "amount_type": "percentage_st_line", + "amount_string": "-100.0", + "label": "B", + }, + { + "amount_type": "percentage_st_line", + "amount_string": "100.0", + "label": "C", + }, + ], + ) + + for bsl_sign in (1, -1): + st_line = self._create_st_line(amount=bsl_sign * 1000.0) + self._check_statement_matching( + rule, + { + st_line: { + "model": rule, + "status": "write_off", + "auto_reconcile": True, + } + }, + ) + + def test_matching_fields_match_partner_category_ids(self): + test_category = self.env["res.partner.category"].create( + {"name": "Consulting Services"} + ) + self.partner_2.category_id = test_category + self.rule_1.match_partner_category_ids |= test_category + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: {}, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + self.rule_1.match_partner_category_ids = False + + def test_mixin_rules(self): + """Test usage of rules together.""" + # rule_1 is used before rule_2. + self.rule_1.sequence = 1 + self.rule_2.sequence = 2 + + self._check_statement_matching( + self.rule_1 + self.rule_2, + { + self.bank_line_1: { + "amls": self.invoice_line_1, + "model": self.rule_1, + }, + self.bank_line_2: { + "amls": self.invoice_line_2 + + self.invoice_line_3 + + self.invoice_line_1, + "model": self.rule_1, + }, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + + # rule_2 is used before rule_1. + self.rule_1.sequence = 2 + self.rule_2.sequence = 1 + + self._check_statement_matching( + self.rule_1 + self.rule_2, + { + self.bank_line_1: { + "model": self.rule_2, + "auto_reconcile": False, + "status": "write_off", + }, + self.bank_line_2: { + "model": self.rule_2, + "auto_reconcile": False, + "status": "write_off", + }, + self.cash_line_1: { + "model": self.rule_2, + "auto_reconcile": False, + "status": "write_off", + }, + }, + ) + + # rule_2 is used before rule_1 but only on partner_1. + self.rule_2.match_partner_ids |= self.partner_1 + + self._check_statement_matching( + self.rule_1 + self.rule_2, + { + self.bank_line_1: { + "model": self.rule_2, + "auto_reconcile": False, + "status": "write_off", + }, + self.bank_line_2: { + "model": self.rule_2, + "auto_reconcile": False, + "status": "write_off", + }, + self.cash_line_1: {"amls": self.invoice_line_4, "model": self.rule_1}, + }, + ) + + def test_auto_reconcile(self): + """Test auto reconciliation.""" + self.bank_line_1.amount += 5 + + self.rule_1.sequence = 2 + self.rule_1.auto_reconcile = True + self.rule_1.payment_tolerance_param = 10.0 + self.rule_2.sequence = 1 + self.rule_2.match_partner_ids |= self.partner_2 + self.rule_2.auto_reconcile = True + + self._check_statement_matching( + self.rule_1 + self.rule_2, + { + self.bank_line_1: { + "amls": self.invoice_line_1, + "model": self.rule_1, + "auto_reconcile": True, + }, + self.bank_line_2: { + "amls": self.invoice_line_1 + + self.invoice_line_2 + + self.invoice_line_3, + "model": self.rule_1, + }, + self.cash_line_1: { + "model": self.rule_2, + "status": "write_off", + "auto_reconcile": True, + }, + }, + ) + + def test_larger_invoice_auto_reconcile(self): + """Test auto reconciliation with an invoice with larger amount than the + statement line's, for rules without write-offs.""" + self.bank_line_1.amount = 40 + self.invoice_line_1.move_id.payment_reference = self.bank_line_1.payment_ref + + self.rule_1.sequence = 2 + self.rule_1.allow_payment_tolerance = False + self.rule_1.auto_reconcile = True + self.rule_1.line_ids = [(5, 0, 0)] + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: { + "amls": self.invoice_line_1, + "model": self.rule_1, + "auto_reconcile": True, + }, + self.bank_line_2: { + "amls": self.invoice_line_1 + + self.invoice_line_2 + + self.invoice_line_3, + "model": self.rule_1, + }, + }, + ) + + def test_auto_reconcile_with_tax(self): + """Test auto reconciliation with a tax amount included in the bank statement line""" + self.rule_1.write( + { + "auto_reconcile": True, + "rule_type": "writeoff_suggestion", + "line_ids": [ + ( + 1, + self.rule_1.line_ids.id, + { + "amount": 50, + "force_tax_included": True, + "tax_ids": [(6, 0, self.tax21.ids)], + }, + ), + ( + 0, + 0, + { + "amount": 100, + "force_tax_included": False, + "tax_ids": [(6, 0, self.tax12.ids)], + "account_id": self.current_assets_account.id, + }, + ), + ], + } + ) + + self.bank_line_1.amount = -121 + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: { + "model": self.rule_1, + "status": "write_off", + "auto_reconcile": True, + }, + self.bank_line_2: { + "model": self.rule_1, + "status": "write_off", + "auto_reconcile": True, + }, + }, + ) + + def test_auto_reconcile_with_tax_fpos(self): + """Test the fiscal positions are applied by reconcile models when using taxes.""" + self.rule_1.write( + { + "auto_reconcile": True, + "rule_type": "writeoff_suggestion", + "line_ids": [ + ( + 1, + self.rule_1.line_ids.id, + { + "amount": 100, + "force_tax_included": True, + "tax_ids": [(6, 0, self.tax21.ids)], + }, + ) + ], + } + ) + + self.partner_1.country_id = self.env.ref("base.lu") + belgium = self.env.ref("base.be") + self.partner_2.country_id = belgium + + self.bank_line_2.partner_id = self.partner_2 + + self.bank_line_1.amount = -121 + self.bank_line_2.amount = -112 + + self.env["account.fiscal.position"].create( + { + "name": "Test", + "country_id": belgium.id, + "auto_apply": True, + "tax_ids": [ + Command.create( + { + "tax_src_id": self.tax21.id, + "tax_dest_id": self.tax12.id, + } + ), + ], + } + ) + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: { + "model": self.rule_1, + "status": "write_off", + "auto_reconcile": True, + }, + self.bank_line_2: { + "model": self.rule_1, + "status": "write_off", + "auto_reconcile": True, + }, + }, + ) + + def test_reverted_move_matching(self): + partner = self.partner_1 + AccountMove = self.env["account.move"] + move = AccountMove.create( + { + "journal_id": self.bank_journal.id, + "line_ids": [ + ( + 0, + 0, + { + "account_id": self.account_pay.id, + "partner_id": partner.id, + "name": "One of these days", + "debit": 10, + }, + ), + ( + 0, + 0, + { + "account_id": self.bank_journal.company_id.account_journal_payment_credit_account_id.id, + "partner_id": partner.id, + "name": "I'm gonna cut you into little pieces", + "credit": 10, + }, + ), + ], + } + ) + + payment_bnk_line = move.line_ids.filtered( + lambda line: line.account_id + == self.bank_journal.company_id.account_journal_payment_credit_account_id + ) + + move.action_post() + move_reversed = move._reverse_moves() + self.assertTrue(move_reversed.exists()) + + self.bank_line_1.write( + { + "payment_ref": "8", + "partner_id": partner.id, + "amount": -10, + } + ) + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {"amls": payment_bnk_line, "model": self.rule_1}, + self.bank_line_2: { + "amls": self.invoice_line_1 + + self.invoice_line_2 + + self.invoice_line_3, + "model": self.rule_1, + }, + }, + ) + + def test_match_different_currencies(self): + partner = self.env["res.partner"].create({"name": "Bernard Gagnant"}) + self.rule_1.write( + {"match_partner_ids": [(6, 0, partner.ids)], "match_same_currency": False} + ) + + currency_inv = self.env.ref("base.EUR") + currency_inv.active = True + currency_statement = self.env.ref("base.JPY") + + currency_statement.active = True + + invoice_line = self._create_invoice_line( + 100, partner, "out_invoice", currency=currency_inv + ) + + self.bank_line_1.write( + { + "partner_id": partner.id, + "foreign_currency_id": currency_statement.id, + "amount_currency": 100, + "payment_ref": "test", + } + ) + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {"amls": invoice_line, "model": self.rule_1}, + self.bank_line_2: {}, + }, + ) + + def test_invoice_matching_rule_no_partner(self): + """Tests that a statement line without any partner can be matched to the + right invoice if they have the same payment reference. + """ + self.invoice_line_1.move_id.write({"payment_reference": "Tournicoti66"}) + self.rule_1.allow_payment_tolerance = False + + self.bank_line_1.write( + { + "payment_ref": "Tournicoti66", + "partner_id": None, + "amount": 95, + } + ) + + self.rule_1.write( + { + "line_ids": [(5, 0, 0)], + "match_partner": False, + "match_label": "contains", + "match_label_param": "Tournicoti", # So that we only match what we want to test + } + ) + + # TODO: 'invoice_line_1' has no reason to match 'bank_line_1' here... to check + # self._check_statement_matching(self.rule_1, { + # self.bank_line_1: {'amls': self.invoice_line_1, 'model': self.rule_1}, + # self.bank_line_2: {'amls': []}, + # }, self.bank_st) + + def test_inv_matching_rule_auto_rec_no_partner_with_writeoff(self): + self.invoice_line_1.move_id.ref = "doudlidou3555" + + self.bank_line_1.write( + { + "payment_ref": "doudlidou3555", + "partner_id": None, + "amount": 95, + } + ) + + self.rule_1.write( + { + "match_partner": False, + "match_label": "contains", + "match_label_param": "doudlidou", # So that we only match what we want to test + "payment_tolerance_param": 10.0, + "auto_reconcile": True, + } + ) + + # Check bank reconciliation + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: { + "amls": self.invoice_line_1, + "model": self.rule_1, + "status": "write_off", + "auto_reconcile": True, + }, + self.bank_line_2: {}, + }, + ) + + def test_partner_mapping_rule(self): + st_line = self._create_st_line(partner_id=None, payment_ref="toto42") + + rule = self._create_reconcile_model( + partner_mapping_line_ids=[ + { + "partner_id": self.partner_1.id, + "payment_ref_regex": "toto.*", + } + ], + ) + + # Matching using the regex on payment_ref. + self.assertEqual(st_line._retrieve_partner(), self.partner_1) + + rule.partner_mapping_line_ids.narration_regex = ".*coincoin" + + # No match because the narration is not matching the regex. + self.assertEqual(st_line._retrieve_partner(), self.env["res.partner"]) + + st_line.narration = "42coincoin" + + # Matching is back thanks to "coincoin". + self.assertEqual(st_line._retrieve_partner(), self.partner_1) + + def test_partner_name_in_communication(self): + self.invoice_line_1.partner_id.write({"name": "Archibald Haddock"}) + self.bank_line_1.write( + {"partner_id": None, "payment_ref": "1234//HADDOCK-Archibald"} + ) + self.bank_line_2.write({"partner_id": None}) + self.rule_1.write({"match_partner": False}) + + # bank_line_1 should match, as its communication contains the invoice's partner name + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {"amls": self.invoice_line_1, "model": self.rule_1}, + self.bank_line_2: {}, + }, + ) + + def test_partner_name_with_regexp_chars(self): + self.invoice_line_1.partner_id.write({"name": "Archibald + Haddock"}) + self.bank_line_1.write( + {"partner_id": None, "payment_ref": "1234//HADDOCK+Archibald"} + ) + self.bank_line_2.write({"partner_id": None}) + self.rule_1.write({"match_partner": False}) + + # The query should still work + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {"amls": self.invoice_line_1, "model": self.rule_1}, + self.bank_line_2: {}, + }, + ) + + def test_match_multi_currencies(self): + """Ensure the matching of candidates is made using the right statement line currency. + In this test, the value of the statement line is 100 USD = 300 GOL = 900 DAR and we want to match two journal + items of: + - 100 USD = 200 GOL (= 600 DAR from the statement line point of view) + - 14 USD = 280 DAR + Both journal items should be suggested to the user because they represents 98% of the statement line amount + (DAR). + """ + partner = self.env["res.partner"].create({"name": "Bernard Perdant"}) + + journal = self.env["account.journal"].create( + { + "name": "test_match_multi_currencies", + "code": "xxxx", + "type": "bank", + "currency_id": self.currency_data["currency"].id, + } + ) + + matching_rule = self.env["account.reconcile.model"].create( + { + "name": "test_match_multi_currencies", + "rule_type": "invoice_matching", + "match_partner": True, + "match_partner_ids": [(6, 0, partner.ids)], + "allow_payment_tolerance": True, + "payment_tolerance_type": "percentage", + "payment_tolerance_param": 5.0, + "match_same_currency": False, + "company_id": self.company_data["company"].id, + "past_months_limit": False, + } + ) + + statement_line = self.env[ + "account.bank.statement.line" + ].create( + { + "journal_id": journal.id, + "date": "2016-01-01", + "payment_ref": "line", + "partner_id": partner.id, + "foreign_currency_id": self.currency_data_2["currency"].id, + "amount": 300.0, # Rate is 3 GOL = 1 USD in 2016. + "amount_currency": 900.0, # Rate is 10 DAR = 1 USD in 2016 but the rate used by the bank is 9:1. + } + ) + + move = self.env["account.move"].create( + { + "move_type": "entry", + "date": "2017-01-01", + "journal_id": self.company_data["default_journal_misc"].id, + "line_ids": [ + # Rate is 2 GOL = 1 USD in 2017. + # The statement line will consider this line equivalent to 600 DAR. + ( + 0, + 0, + { + "account_id": self.company_data[ + "default_account_receivable" + ].id, + "partner_id": partner.id, + "currency_id": self.currency_data["currency"].id, + "debit": 100.0, + "credit": 0.0, + "amount_currency": 200.0, + }, + ), + # Rate is 20 GOL = 1 USD in 2017. + ( + 0, + 0, + { + "account_id": self.company_data[ + "default_account_receivable" + ].id, + "partner_id": partner.id, + "currency_id": self.currency_data_2["currency"].id, + "debit": 14.0, + "credit": 0.0, + "amount_currency": 280.0, + }, + ), + # Line to balance the journal entry: + ( + 0, + 0, + { + "account_id": self.company_data[ + "default_account_revenue" + ].id, + "debit": 0.0, + "credit": 114.0, + }, + ), + ], + } + ) + move.action_post() + + move_line_1 = move.line_ids.filtered(lambda line: line.debit == 100.0) + move_line_2 = move.line_ids.filtered(lambda line: line.debit == 14.0) + + self._check_statement_matching( + matching_rule, + { + statement_line: { + "amls": move_line_1 + move_line_2, + "model": matching_rule, + } + }, + ) + + @freeze_time("2020-01-01") + def test_matching_with_write_off_foreign_currency(self): + journal_foreign_curr = self.company_data["default_journal_bank"].copy() + journal_foreign_curr.currency_id = self.currency_data["currency"] + + reco_model = self._create_reconcile_model( + auto_reconcile=True, + rule_type="writeoff_suggestion", + line_ids=[ + { + "amount_type": "percentage", + "amount": 100.0, + "account_id": self.company_data["default_account_revenue"].id, + } + ], + ) + + st_line = self._create_st_line( + amount=100.0, payment_ref="123456", journal_id=journal_foreign_curr.id + ) + self._check_statement_matching( + reco_model, + { + st_line: { + "model": reco_model, + "status": "write_off", + "auto_reconcile": True, + }, + }, + ) + + def test_payment_similar_communications(self): + def create_payment_line(amount, memo, partner): + payment = self.env["account.payment"].create( + { + "amount": amount, + "payment_type": "inbound", + "partner_type": "customer", + "partner_id": partner.id, + "ref": memo, + "destination_account_id": self.company_data[ + "default_account_receivable" + ].id, + } + ) + payment.action_post() + + return payment.line_ids.filtered( + lambda x: x.account_id.account_type + not in {"asset_receivable", "liability_payable"} + ) + + payment_partner = self.env["res.partner"].create( + { + "name": "Bernard Gagnant", + } + ) + + self.rule_1.match_partner_ids = [(6, 0, payment_partner.ids)] + + pmt_line_1 = create_payment_line(500, "a1b2c3", payment_partner) + pmt_line_2 = create_payment_line(500, "a1b2c3", payment_partner) + create_payment_line(500, "d1e2f3", payment_partner) + + self.bank_line_1.write( + { + "amount": 1000, + "payment_ref": "a1b2c3", + "partner_id": payment_partner.id, + } + ) + self.bank_line_2.unlink() + self.rule_1.allow_payment_tolerance = False + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: { + "amls": pmt_line_1 + pmt_line_2, + "model": self.rule_1, + "status": "write_off", + }, + }, + ) + + def test_no_amount_check_keep_first(self): + """In case the reconciliation model doesn't check the total amount of the candidates, + we still don't want to suggest more than are necessary to match the statement. + For example, if a statement line amounts to 250 and is to be matched with three invoices + of 100, 200 and 300 (retrieved in this order), only 100 and 200 should be proposed. + """ + self.rule_1.allow_payment_tolerance = False + self.bank_line_2.amount = 250 + self.bank_line_1.partner_id = None + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: { + "amls": self.invoice_line_1 + self.invoice_line_2, + "model": self.rule_1, + "status": "write_off", + }, + }, + ) + + def test_no_amount_check_exact_match(self): + """If a reconciliation model finds enough candidates for a full reconciliation, + it should still check the following candidates, in case one of them exactly + matches the amount of the statement line. If such a candidate exist, all the + other ones are disregarded. + """ + self.rule_1.allow_payment_tolerance = False + self.bank_line_2.amount = 300 + self.bank_line_1.partner_id = None + + self._check_statement_matching( + self.rule_1, + { + self.bank_line_1: {}, + self.bank_line_2: { + "amls": self.invoice_line_3, + "model": self.rule_1, + "status": "write_off", + }, + }, + ) diff --git a/account_reconcile_oca/README.rst b/account_reconcile_oca/README.rst new file mode 100644 index 00000000..63f7ae71 --- /dev/null +++ b/account_reconcile_oca/README.rst @@ -0,0 +1,109 @@ +===================== +Account Reconcile Oca +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0259c9d504534b4ee88e7b929ddb6c524dd35cb217811c87b8dd02e0a433f1f1 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--reconcile-lightgray.png?logo=github + :target: https://github.com/OCA/account-reconcile/tree/17.0/account_reconcile_oca + :alt: OCA/account-reconcile +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/account-reconcile-17-0/account-reconcile-17-0-account_reconcile_oca + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/account-reconcile&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This addon allows to reconcile bank statements and account marked as +reconcile. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Bank reconcile +-------------- + +Access Invoicing / Dashboard with a user with Full Acounting +capabilities. Select reconcile on the journal of your choice. + +Account reconcile +----------------- + +Access Invoicing / Accounting / Actions / Reconcile All the possible +reconcile options will show and you will be able to reconcile properly. +You can access the same widget from accounts and Partners. + +Known issues / Roadmap +====================== + +The following bugs are already detected: + +- Creation of activities on the chatter do show automatically + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* CreuBlanca +* Dixmit + +Contributors +------------ + +- Enric Tobella + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-etobella| image:: https://github.com/etobella.png?size=40px + :target: https://github.com/etobella + :alt: etobella + +Current `maintainer `__: + +|maintainer-etobella| + +This module is part of the `OCA/account-reconcile `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_reconcile_oca/__init__.py b/account_reconcile_oca/__init__.py new file mode 100644 index 00000000..cc6b6354 --- /dev/null +++ b/account_reconcile_oca/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import post_init_hook diff --git a/account_reconcile_oca/__manifest__.py b/account_reconcile_oca/__manifest__.py new file mode 100644 index 00000000..2e53b4fa --- /dev/null +++ b/account_reconcile_oca/__manifest__.py @@ -0,0 +1,45 @@ +# Copyright 2023 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Account Reconcile Oca", + "summary": """ + Reconcile addons for Odoo CE accounting""", + "version": "17.0.1.0.0", + "license": "AGPL-3", + "author": "CreuBlanca,Dixmit,Odoo Community Association (OCA)", + "maintainers": ["etobella"], + "website": "https://github.com/OCA/account-reconcile", + "depends": [ + "account_statement_base", + "account_reconcile_model_oca", + "base_sparse_field", + ], + "data": [ + "views/res_config_settings.xml", + "security/ir.model.access.csv", + "views/account_account_reconcile.xml", + "views/account_bank_statement_line.xml", + "views/account_move_line.xml", + "views/account_journal.xml", + "views/account_move.xml", + "views/account_account.xml", + "views/account_bank_statement.xml", + ], + "demo": ["demo/demo.xml"], + "post_init_hook": "post_init_hook", + "assets": { + "web.assets_backend": [ + "account_reconcile_oca/static/src/js/widgets/reconcile_data_widget.esm.js", + "account_reconcile_oca/static/src/js/widgets/reconcile_chatter_field.esm.js", + "account_reconcile_oca/static/src/js/widgets/selection_badge_uncheck.esm.js", + "account_reconcile_oca/static/src/js/widgets/reconcile_move_line_widget.esm.js", + "account_reconcile_oca/static/src/js/reconcile_move_line/*.esm.js", + "account_reconcile_oca/static/src/js/reconcile_form/*.esm.js", + "account_reconcile_oca/static/src/js/reconcile_manual/*.esm.js", + "account_reconcile_oca/static/src/js/reconcile/*.esm.js", + "account_reconcile_oca/static/src/xml/reconcile.xml", + "account_reconcile_oca/static/src/scss/reconcile.scss", + ], + }, +} diff --git a/account_reconcile_oca/demo/demo.xml b/account_reconcile_oca/demo/demo.xml new file mode 100644 index 00000000..a27a51e8 --- /dev/null +++ b/account_reconcile_oca/demo/demo.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/account_reconcile_oca/hooks.py b/account_reconcile_oca/hooks.py new file mode 100644 index 00000000..ce21fab5 --- /dev/null +++ b/account_reconcile_oca/hooks.py @@ -0,0 +1,8 @@ +def post_init_hook(env): + env.cr.execute( + """ + UPDATE account_bank_statement_line + SET reconcile_mode = 'edit' + WHERE is_reconciled + """ + ) diff --git a/account_reconcile_oca/i18n/account_reconcile_oca.pot b/account_reconcile_oca/i18n/account_reconcile_oca.pot new file mode 100644 index 00000000..eee93284 --- /dev/null +++ b/account_reconcile_oca/i18n/account_reconcile_oca.pot @@ -0,0 +1,583 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "" diff --git a/account_reconcile_oca/i18n/ca.po b/account_reconcile_oca/i18n/ca.po new file mode 100644 index 00000000..ca91484e --- /dev/null +++ b/account_reconcile_oca/i18n/ca.po @@ -0,0 +1,590 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-20 17:34+0000\n" +"Last-Translator: Enric Tobella \n" +"Language-Team: none\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" +".\n" +"
\n" +" Potser vols definir la factura com" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "Compte" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "Conciliació de compte comptable" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "Conciliació de Compte abstracte" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "Afegir un apunt comptable" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "Afegir una línea d'extracte bancari" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "Import" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "Import en divisa" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "Dsitribució analítica" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "Precisió analítica" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "Estas segur que vols desconciliar aquest apunt?" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "Banc" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Línea d'extracte bancari" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "Concilicació bancària" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "Es pot conciliar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "Cancel·la" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "Efectiu" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "Missatges" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "Neteja" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "Companyia" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "Companyia relacionada amb el diari" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "Crea" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "Creat per" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "Creat el" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "Crèdit" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "Moneda" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "Dades" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "Data" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "Dèbit" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "Nóm a mostrar" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "Edita moviment" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "Moneda extrangera" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "De comptes a pagar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "De comptes a cobrar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "ID" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "Factura" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "Conciliat" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "Elements" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "Diari" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "Divisa del diari" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "Entrada del diari" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "Element del diari" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "Mantenir comptes transitoris" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "La modalitat mantenir els comptes transitoris no permet desconciliar" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "Etiqueta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "Última modificació el" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "Última actualització per" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "Última actualització per" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "Compte manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "Import manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "Divisa manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "Esborrat manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "Tipus manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "Línea manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "Model manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "Assentament manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "Tipus d'assentament manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "Nom manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "Import original manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "Contacte manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "Referencia manual" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "Operació manual" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "Variat" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "Nom" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "Narració" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "No està permés usar líneas transitòries" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "Res a comprobar" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "Res a conciliar" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "Empresa" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "A pagar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "Compres" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "A cobrar" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "Conciliar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "Data de concilicació" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "Informació de conciliació" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "Mode de concilicació" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "Conciliar líneas d'extracte bancari" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "" +"Model de dades per emmagatzemar dades de concilicació a nivell d'usuari" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "Conciliat" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "Restablir concilicació" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "Ventes" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "Guardar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "Buscar apunts comptables" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "Marcar com revisat" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "L'altra divisa opcional si es tracta d'una entrada multidivisa." + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "A revisar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "A revisar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "Transaccions" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "Indefinit" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "Desconciliar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "Usuari" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "Validar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "Veure" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "Veure assentament" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "Ben fet! Tot s'ha conciliat" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "Completament pagat" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "a revisar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "será reduit en" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "amb un import pendent" diff --git a/account_reconcile_oca/i18n/es.po b/account_reconcile_oca/i18n/es.po new file mode 100644 index 00000000..26ffe4a5 --- /dev/null +++ b/account_reconcile_oca/i18n/es.po @@ -0,0 +1,596 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-12-28 20:35+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" +".\n" +"
\n" +" Podrías querer establecer la factura como" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "Cuenta" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "Conciliación de cuenta contable" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "Resumen de conciliación de cuenta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "Añadir apunte contable" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "Añadir línea de extracto bancario" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "Importe" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "Importe en Divisa" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "Distribución analítica" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "Precisión analítica" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "¿Estás seguro de que el apunte se debería desconciliar?" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "Banco" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Línea de extracto bancario" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "Conciliación bancaria" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "Se puede conciliar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "Cancelar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "Efectivo" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "Charla" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "Limpiar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "Compañía" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "Compañía relacionada al diario" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "Crear" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "Creado en" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "Haber" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "Moneda" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "Datos" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "Fecha" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "Debe" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "Nombre Mostrado" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "Editar movimiento" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "Moneda Extranjera" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "De cuentas comerciales por pagar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "De cuentas comerciales por cobrar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "ID" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "Factura" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "Conciliado" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "Elementos" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "Diario" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "Divisa del diario" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "Entrada de diario" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "Elemento de diario" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "Mantener cuentas transitorias" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "Mantener en modo suspenso las líneas que no pueden ser desconciliadas" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "Etiqueta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "Última modficación en" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "Última modficación por" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "Cuenta manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "Importe manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "Divisa manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "Borrado manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "Tipo manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "Apunte manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "Modelo manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "Asiento manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "Tipo de asiento manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "Nombre manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "Importe original manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "Partner manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "Referencia manual" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "Operación manual" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "Vario" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "Nombre" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "Narración" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "No se permiten líneas en suspenso al conciliar" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "Nada que comprobar" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "Nada para conciliar" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "Empresa" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "A pagar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "Compras" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "A cobrar" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "Conciliar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "Fecha de conciliación" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "Información de Conciliación de Datos" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "Modo de conciliación" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "Conciliar líneas de extracto bancario" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "Modelo de datos de conciliación para almacenar información de usuarios" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "Conciliado" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "Restablecer reconciliación" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "Ventas" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "Guardar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "Buscar apuntes" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "Marcar como revisado" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "La otra divisa opcional si se trata de una entrada multidivisa." + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "Para revisar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "Para revisar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "Transacciones" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "Indefinido" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "No Conciliado" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "Usuario" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "Validar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "Ver" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "Ver asiento" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "¡Bien hecho! Todo ha sido conciliado" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "totalmente pagado" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "Para revisar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "será disminuido por" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "con un importe pendiente" + +#, python-format +#~ msgid "You must reconcile information on the same partner" +#~ msgstr "Debe conciliar la información sobre el mismo socio" + +#~ msgid "Reset" +#~ msgstr "Restablecer" diff --git a/account_reconcile_oca/i18n/fr.po b/account_reconcile_oca/i18n/fr.po new file mode 100644 index 00000000..e69ee8bb --- /dev/null +++ b/account_reconcile_oca/i18n/fr.po @@ -0,0 +1,596 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-01-01 13:49+0000\n" +"Last-Translator: \"Stéphane Bidoul (ACSONE)\" \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" +".\n" +"
\n" +" Vous pouvez définir la facture comme" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "Compte" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "Lettrage" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "Modèle Abstrait de lettrage" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "Ajouter une écriture comptable" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "Ajouter une ligne de relevé de compte" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "Montant" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "Montant en devise" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "Distribution analytique" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "Précision analytique" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "Êtes-vous sûr que la ligne doit être délettrée ?" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "Banque" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Ligne de relevé bancaire" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "Lettrage des comptes bancaires" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "Peut se lettrer" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "Annuler" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "Espèces" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "Chatter" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "Nettoyer" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "Société" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "Société liée à ce journal" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "Créer" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "Créé le" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "Crédit" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "Devise" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "Données" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "Date" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "Débit" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "Modifier la pièce" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "Devise étrangère" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "Depuis comptes fournisseur" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "Depuis comptes client" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "ID" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "Facture" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "Est lettré" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "Articles" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "Journal" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "Devise du journal" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "Pièce comptable" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "Écriture comptable" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "Conserver les comptes d'attente" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "" +"Conserver les comptes d'attente sur les écritures qui ne peuvent être " +"délettrées" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "Libellé" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "Compte manuel" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "Montant manuel" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "Devise manuelle" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "Suppression manuelle" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "Type manuel" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "Écriture manuelle" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "Modèle manuel" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "Pièce manuelle" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "Type de pièce manuelle" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "Libellé manuel" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "Montant original manuel" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "Partenaire manuel" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "Référence manuelle" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "Opération manuelle" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "Divers" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "Nom" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "Commentaire" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "Aucune ligne d'attente n'est autorisée lors du lettrage" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "Rien à vérifier" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "Rien à lettrer" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "Partenaire" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "Compte fournisseur" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "Achats" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "Compte client" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "Lettrer" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "Données de lettrage" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "Informations de données de lettrage" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "Mode de lettrage" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "Lettrer les lignes de relevé de compte" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "" +"Modèle de données de lettrage pour stocker les informations relatives à " +"l'utilisateur" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "Lettré" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "Réinitialiser le rapprochement" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "Ventes" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "Sauvegarder" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "Rechercher des écritures comptables" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "Marquer comme vérifié" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "L'autre devise facultative s'il s'agit d'une entrée multidevise." + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "À vérifier" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "À vérifier" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "Transactions" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "Non défini" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "Délettrer" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "Utilisateur" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "Valider" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "Voir" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "Voir la pièce" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "Bravo ! Tout a été lettré" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "entièrement payé" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "à vérifier" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "sera réduite de" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "avec un montant ouvert" + +#~ msgid "Reset" +#~ msgstr "Réinitialiser" diff --git a/account_reconcile_oca/i18n/hr.po b/account_reconcile_oca/i18n/hr.po new file mode 100644 index 00000000..a8a334f7 --- /dev/null +++ b/account_reconcile_oca/i18n/hr.po @@ -0,0 +1,590 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-05-25 13:09+0000\n" +"Last-Translator: Bole \n" +"Language-Team: none\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.17\n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" +".\n" +"
\n" +" Možda želite postaviti račun kao" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "Konto" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "Zatvaranje konta" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "Apstraktno zatvaranje konta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "Dodaj stavku temeljnice" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "Dodaj stavku izvoda" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "Iznos" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "Analitička distribucija" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "Preciznost analitike" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "Jeste li sigurni da temeljnica treba biti rastvorena?" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "Banka" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Stavka izvoda banke" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "Zatvaranje banke" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "Može zatvoriti" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "Otkaži" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "Gotovina" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "Razgovor" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "Očisti" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "Tvrtka" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "Tvrtka povezana sa ovim dnevnikom" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "Kreiraj" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "Kreirao" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "Kreirano" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "Potražuje" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "Valuta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "Podaci" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "Datum" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "Duguje" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "Prikazani naziv" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "Uredi temeljnicu" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "Iz konta dugovanja" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "Iz konta potraživanja" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "ID" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "Račun" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "Je zatvoren" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "Stavke" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "Dnevnik" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "Zapis dnevnika" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "Stavka dnevnika" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "Natpis" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "Zadnje modificirano" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "Zadnji ažurirao" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "Zadnje ažuriranje" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "Ručni konto" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "Ručni iznos" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "Ručno brisanje" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "Vrsta ručne obrade" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "Stavka ručne obrade" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "Model ručne obrade" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "Partner" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "Za plaćanje" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "Nabave" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "Za naplatu" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "Zatvori" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "Podaci zatvaranja" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "Info podataka o zatvaranju" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "Način zatvaranja" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "Zatvori stavke izvoda" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "Model podataka o zatvaranju za pohranu korisničkih informacija" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "Zatvoreno" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "Prodaje" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "Spremi" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "Pretraži stavke dnevnika" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "Postavi kao Provjereno" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "Za provjeru" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "Za provjeru" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "Transakcije" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "Nedefinirano" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "Korisnik" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "Potvrdi" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "Pogled" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "Pregledaj temeljnicu" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "Odlično! Sve je pozatvarano" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "potpuno plaćeno" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "za provjeru" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "će biti umanjeno za" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "pa početnim iznosom" diff --git a/account_reconcile_oca/i18n/nl.po b/account_reconcile_oca/i18n/nl.po new file mode 100644 index 00000000..f99d2a07 --- /dev/null +++ b/account_reconcile_oca/i18n/nl.po @@ -0,0 +1,591 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-28 17:34+0000\n" +"Last-Translator: Yung-Wa \n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" +".\n" +"
\n" +" Je kunt de factuur instellen als" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "Rekening" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "Boekhouding Rekening Aflettering" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "Rekening Aflettering Samenvatting" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "Toevoegen Boekingsregel" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "Toevoegen Bankafschriftregel" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "Bedrag" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "Valutabedrag" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "Analytische Verdeling" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "Analytische Precisie" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "Weet je zeker dat de boeking niet moet worden afgeletterd?" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "Bank" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Bankafschriftregel" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "Bank aflettering" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "Kan Afletteren" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "Annuleer" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "Contant" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "Logging" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "Opschonen" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "Bedrijf" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "Bedrijf gerelateerd aan dit dagboek" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "Aanmaken" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "Aangemaakt door" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "Aangemaakt op" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "Credit" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "Valuta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "Data" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "Datum" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "Debet" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "Weergavenaam" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "Bewerk Boeking" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "Vreemde valuta" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "Van Crediteurenrekeningen" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "Van debiteurenrekeningen" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "ID" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "Factuur" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "Is Afgeletterd" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "Regels" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "Dagboek" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "Dagboek Valuta" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "Boeking" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "Boekingsregel" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "Tussenrekeningen aanhouden" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "" +"De modes, houd tussenrekening boekingsregels, kan niet ongedaan worden " +"gemaakt" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "Label" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "Laatst gewijzigd op" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "Laatst gewijzigd door" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "Laatst gewijzigd op" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "Handmatige Rekening" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "Handmatige Bedrag" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "Handmatige Valuta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "Handmatig Verwijderen" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "Handmatige Soort" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "Handmatige Regel" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "Handmatige Model" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "Handmatige Boeking" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "Handmatige Boekingstype" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "Handmatige Naam" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "Handmatige Origineel Bedrag" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "Handmatige Partner" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "Handmatige Referentie" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "Handmatige Verwerking" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "Diverse" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "Naam" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "Notitie" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "Bij aflettering zijn tussenrekening regels niet toegestaan" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "Niets te controleren" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "Niet af te letteren" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "Partner" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "Crediteuren" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "Inkopen" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "Debiteuren" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "Afletteren" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "Afletteringsdata" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "Afletteringsdata informatie" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "Afletteringsmodus" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "Bankafschriftregels afletteren" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "Afletteringsmodel aanpassen om gebruikersinfo op te slaan" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "Afgeletterd" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "Herstel aflettering" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "Verkoop" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "Opslaan" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "Zoek in boekingsregels" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "Stel in als Gecontroleerd" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "De optionele andere valuta als het invoer in meerdere valuta is." + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "Te Controleren" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "Te controleren" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "Transacties" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "Ongedefinieerd" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "Afletteren ongedaan maken" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "Gebruiker" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "Bevestig" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "Weergave" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "Boeking weergeven" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "Goed gedaan! Alles is afgeletterd" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "volledig betaald" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "Te controleren" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "wordt verminderd met" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "met een open bedrag" diff --git a/account_reconcile_oca/i18n/pt_BR.po b/account_reconcile_oca/i18n/pt_BR.po new file mode 100644 index 00000000..19f540ee --- /dev/null +++ b/account_reconcile_oca/i18n/pt_BR.po @@ -0,0 +1,596 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-12-28 23:54+0000\n" +"Last-Translator: Adriano Prado \n" +"Language-Team: none\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" +".\n" +"
\n" +" Voce pode querer definir a fatura como" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "Conta" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "Reconciliação de conta" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "Resumo de reconciliação de conta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "Add Linha de Movimentação da Conta" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "Add Linha Extrato Bancário" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "Valor" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "Valor na moeda" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "Distribuição Analítica" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "Precisão Analítica" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "Tem certeza de que a mudança deve ser irreconciliável?" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "Banco" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Linha Extrato Banco" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "Reconciliar Banco" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "Pode Reconciliar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "Cancelar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "Dinheiro" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "Conversa" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "Limpar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "Empresa" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "Empresa relacionada a este diário" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "Criar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "Criado por" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "Criado em" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "Crédito" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "Moeda" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "Dados" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "Data" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "Débito" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "Nome Exibição" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "Editar Movimento" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "Moeda Estrangeira" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "De contas a Pagar comerciais" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "De contas a Receber comerciais" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "ID" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "Fatura" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "Reconciliado" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "Itens" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "Diário" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "Moeda Diário" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "Entrada Diário" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "Item Diário" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "Manter contas suspensas" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "O modo Manter suspenso linhas de movimento não pode ser irreconciliado" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "Rótulo" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "Última modificação em" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "Última atualização por" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "Última atualização em" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "Conta Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "Valor Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "Moeda Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "Exclusão Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "Tipo Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "Linha Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "Modelo Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "Movimento Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "Tipo Movimento Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "Nome Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "Valor Original Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "Parceiro Manual" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "Referencia Manual" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "Operação Manual" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "Outros" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "Nome" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "Narração" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "Nenhuma linha supensa é permitida ao reconciliar" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "Nada para verificar" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "Nada para Reconciliar" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "Parceiro" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "Pagavel" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "Compras" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "Recebíveis" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "Reconciliar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "Reconciliar dados" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "Reconciliar Informações dos Dados" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "Modo de reconciliação" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "Reconciliar linhas de extrato bancário" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "Reconciliar modelo de dados para armazenar informações do usuário" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "Reconciliado" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "Redefinir Reconciliação" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "Vendas" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "Salvar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "Procurar Itens do Diário" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "Def. como Verificado" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "A outra moeda opcional se for uma entrada em várias moedas." + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "Para Verificar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "Para Verificar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "Transações" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "Indefinido" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "Desconciliar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "Usuário" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "Validar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "Ver" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "Ver movimento" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "Bom trabalho! Tudo foi reconciliado" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "totalmente pago" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "para verificar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "será reduzido em" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "com um valor em aberto" + +#, python-format +#~ msgid "You must reconcile information on the same partner" +#~ msgstr "Você deve reconciliar informações sobre o mesmo parceiro" + +#~ msgid "Reset" +#~ msgstr "Reiniciar" diff --git a/account_reconcile_oca/i18n/sv.po b/account_reconcile_oca/i18n/sv.po new file mode 100644 index 00000000..196c3856 --- /dev/null +++ b/account_reconcile_oca/i18n/sv.po @@ -0,0 +1,589 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-28 13:19+0000\n" +"Last-Translator: jakobkrabbe \n" +"Language-Team: none\n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" +".\n" +"
\n" +" Du kanske vill ställa in fakturan som" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "Konto" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "Kontoavstämning" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "Sammanfattning av kontoavstämning" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "Lägg till konto, move_line" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "Lägg till kontoutdragsrad" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "Belopp" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "Belopp i valuta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "Analytisk distribution" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "Analytisk precision" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "Är du säker på att flytten borde vara oförenlig?" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "Bank" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Bankkontoutdragsrad" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "Bankavstämning" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "Kan förenas" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "Avbryt" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "Cash" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "Chatter" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "Rensa" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "Företag" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "Företag relaterad till denna journalen" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "Skapa" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "Skapad av" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "Skapad den" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "Kreditera" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "Valuta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "Data" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "Datum" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "Debitera" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "Visningsnamn" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "Redigera Move" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "Utländsk valuta" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "Från Leverantörsskulder" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "Från kundfordringar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "ID" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "Faktura" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "Är försonad" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "Föremål" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "Dagbok" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "Dagboksvaluta" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "Dagboksanteckning" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "Dagboksanteckning" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "Håll avstängningskonton" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "Etikett" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "Senast ändrad den" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "Senast uppdaterad den" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "Senast uppdaterad på" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "Manuellt konto" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "Manuellt belopp" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "Manuell valuta" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "Manuell radering" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "Manuell typ" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "Manuell Linje" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "Manuell modell" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "Manuell Move" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "Manuellt namn" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "Manuell ursprunglig summa" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "Manuell partner" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "Manuell referens" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "Manuell operation" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "Diverse" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "Namn" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "Berättande" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "Inga supensrader är tillåtna vid avstämning" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "Inget att kontrollera" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "Inget att förena" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "Partner" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "Betalbar" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "Inköp" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "Mottagningsbar" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "Avstämma" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "Avstämning av data" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "Avstämma datainfo" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "Avstämningsläge" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "Stämma av kontoutdragsrader" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "Avstämma datamodell för att lagra användarinformation" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "Avstämnd" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "Återställ avstämning" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "Försäljning" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "Spara" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "Sök journalföremål" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "Ställ in som markerad" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "Den valfria andra valutan om det är en post i flera valutor." + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "Att kontrollera" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "Att kontrollera" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "Transaktioner" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "Odefinierad" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "Användare" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "Bekräfta" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "Vy" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "Visa move" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "Bra gjort! Allt har blivit avstämmt" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "fullt betald" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "att kontrollera" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "kommer att reduceras med" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "med ett valfritt belopp" diff --git a/account_reconcile_oca/i18n/tr.po b/account_reconcile_oca/i18n/tr.po new file mode 100644 index 00000000..a356081d --- /dev/null +++ b/account_reconcile_oca/i18n/tr.po @@ -0,0 +1,589 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_reconcile_oca +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-06-13 18:09+0000\n" +"Last-Translator: Ediz Duman \n" +"Language-Team: none\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "" +".\n" +"
\n" +" You might want to set the invoice as" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__account_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Account" +msgstr "Hesap" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile +msgid "Account Account Reconcile" +msgstr "Hesap Hesap Mutabakatı" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_reconcile_abstract +msgid "Account Reconcile Abstract" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__add_account_move_line_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__add_account_move_line_id +msgid "Add Account Move Line" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_create +msgid "Add Bank Statement Line" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Amount" +msgstr "Tutar" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Amount in currency" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_distribution +msgid "Analytic Distribution" +msgstr "Analitik Dağıtım" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__analytic_precision +msgid "Analytic Precision" +msgstr "Analitik Hassasiyet" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Are you sure that the move should be unreconciled?" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Bank" +msgstr "Banka" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_bank_statement_line +msgid "Bank Statement Line" +msgstr "Banka Ekstre Satırı" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_form_view +msgid "Bank reconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__can_reconcile +msgid "Can Reconcile" +msgstr "Uzlaşabilir" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Cancel" +msgstr "İptal" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Cash" +msgstr "Nakit" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Chatter" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +msgid "Clean" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_id +msgid "Company" +msgstr "Firma" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__company_id +msgid "Company related to this journal" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Create" +msgstr "Oluştur" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_uid +msgid "Created by" +msgstr "Oluşturan" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__create_date +msgid "Created on" +msgstr "Oluşturuldu" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Credit" +msgstr "Alacak" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__company_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__currency_id +msgid "Currency" +msgstr "Para Birimi" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__data +msgid "Data" +msgstr "Veri" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Date" +msgstr "Tarih" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Debit" +msgstr "Borç" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__display_name +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__display_name +msgid "Display Name" +msgstr "Ad Görünümü" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__edit +msgid "Edit Move" +msgstr "Hareketi Düzenle" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__foreign_currency_id +msgid "Foreign Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Payable accounts" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "From Trade Receivable accounts" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__id +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__id +msgid "ID" +msgstr "ID" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Invoice" +msgstr "Fatura" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__is_reconciled +msgid "Is Reconciled" +msgstr "Uzlaştırıldı mı" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Items" +msgstr "Öğe" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_journal +msgid "Journal" +msgstr "Yevmiye" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__currency_id +msgid "Journal Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Entry" +msgstr "Yevmiye Girişi" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_move_line +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Journal Item" +msgstr "Yevmiye Öğesi" + +#. module: account_reconcile_oca +#: model:ir.model.fields.selection,name:account_reconcile_oca.selection__account_journal__reconcile_mode__keep +msgid "Keep Suspense Accounts" +msgstr "Askı Hesapları Tutun" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Keep suspense move lines mode cannot be unreconciled" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#, python-format +msgid "Label" +msgstr "Etiket" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile____last_update +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data____last_update +msgid "Last Modified on" +msgstr "Son Değiştirilme" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_uid +msgid "Last Updated by" +msgstr "Son Güncelleyen" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__write_date +msgid "Last Updated on" +msgstr "Son Güncelleme" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_account_id +msgid "Manual Account" +msgstr "Manuel Hesap" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_amount +msgid "Manual Amount" +msgstr "Manuel Tutar" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_currency_id +msgid "Manual Currency" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_delete +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_delete +msgid "Manual Delete" +msgstr "Manuel Silme" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_kind +msgid "Manual Kind" +msgstr "Manuel Tür" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_line_id +msgid "Manual Line" +msgstr "Manuel Satır" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_model_id +msgid "Manual Model" +msgstr "Manuel Model" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_id +msgid "Manual Move" +msgstr "Manuel Hareket" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_move_type +msgid "Manual Move Type" +msgstr "Manuel Hareket Türü" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_name +msgid "Manual Name" +msgstr "Manuel Adı" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_original_amount +msgid "Manual Original Amount" +msgstr "Manuel Orijinal Miktarı" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_partner_id +msgid "Manual Partner" +msgstr "Manuel İş Ortağı" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__manual_reference +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__manual_reference +msgid "Manual Reference" +msgstr "Manuel Referans" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Manual operation" +msgstr "Manuel İşlem" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Miscellaneous" +msgstr "Çeşitli" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__name +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Name" +msgstr "Adı" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Narration" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "No supense lines are allowed when reconciling" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Nothing to check" +msgstr "Kontrol edilecek bir şey yok" + +#. module: account_reconcile_oca +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile +#: model_terms:ir.actions.act_window,help:account_reconcile_oca.action_bank_statement_line_reconcile_all +msgid "Nothing to reconcile" +msgstr "" + +#. module: account_reconcile_oca +#. odoo-javascript +#: code:addons/account_reconcile_oca/static/src/xml/reconcile.xml:0 +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__partner_id +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#, python-format +msgid "Partner" +msgstr "İş Ortağı" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Payable" +msgstr "Borç" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Purchases" +msgstr "Satınalma" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Receivable" +msgstr "Alacak" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.account_account_reconcile_act_window +#: model:ir.actions.act_window,name:account_reconcile_oca.res_partner_account_account_reconcile_act_window +#: model:ir.actions.server,name:account_reconcile_oca.action_reconcile +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__reconcile_id +#: model:ir.ui.menu,name:account_reconcile_oca.account_account_reconcile_menu +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_account_reconcile_form_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.view_account_list +msgid "Reconcile" +msgstr "Uzlaştırma" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data +msgid "Reconcile Data" +msgstr "Uzlaştırma Verisi" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_data_info +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_reconcile_abstract__reconcile_data_info +msgid "Reconcile Data Info" +msgstr "Uzlaştırma Veri Bilgisi" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_bank_statement_line__reconcile_mode +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_journal__reconcile_mode +msgid "Reconcile Mode" +msgstr "Uzlaştırma Modu" + +#. module: account_reconcile_oca +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_move_view_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_all +#: model:ir.actions.act_window,name:account_reconcile_oca.action_bank_statement_line_reconcile_to_check +msgid "Reconcile bank statement lines" +msgstr "Banka ekstresi satırlarını uzlaştırma" + +#. module: account_reconcile_oca +#: model:ir.model,name:account_reconcile_oca.model_account_account_reconcile_data +msgid "Reconcile data model to store user info" +msgstr "Kullanıcı bilgilerini depolamak için veri modelini uzlaştırın" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "Reconciled" +msgstr "Uzlaştırılan" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Reset reconciliation" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Sales" +msgstr "Satış" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_add_view +msgid "Save" +msgstr "Kaydet" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_search_reconcile_view +msgid "Search Journal Items" +msgstr "Yemiye Öğelerini Ara" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Set as Checked" +msgstr "Gözden Geçirme İşaretlendi" + +#. module: account_reconcile_oca +#: model:ir.model.fields,help:account_reconcile_oca.field_account_bank_statement_line__foreign_currency_id +msgid "The optional other currency if it is a multi-currency entry." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "To Check" +msgstr "Kontrol Edilecek" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_reconcile_view +msgid "To check" +msgstr "Kontrol edilecek" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "Transactions" +msgstr "İşlemler" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_bank_statement_line.py:0 +#, python-format +msgid "Undefined" +msgstr "Tanımsız" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Unreconcile" +msgstr "" + +#. module: account_reconcile_oca +#: model:ir.model.fields,field_description:account_reconcile_oca.field_account_account_reconcile_data__user_id +msgid "User" +msgstr "Kullanıcı" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "Validate" +msgstr "Doğrulama" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_move_line_tree_reconcile_view +msgid "View" +msgstr "Görme" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "View move" +msgstr "Hareketi görüntüle" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_journal.py:0 +#, python-format +msgid "Well done! Everything has been reconciled" +msgstr "Tebrikler! Her şey uzlaştırldı" + +#. module: account_reconcile_oca +#. odoo-python +#: code:addons/account_reconcile_oca/models/account_move_line.py:0 +#, python-format +msgid "You can only reconcile journal items belonging to the same account." +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "fully paid" +msgstr "tamamen ödenmiş" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.account_journal_dashboard_kanban_view +msgid "to check" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "will be reduced by" +msgstr "" + +#. module: account_reconcile_oca +#: model_terms:ir.ui.view,arch_db:account_reconcile_oca.bank_statement_line_form_reconcile_view +msgid "with an open amount" +msgstr "" + +#~ msgid "Reset" +#~ msgstr "Sıfırla" diff --git a/account_reconcile_oca/models/__init__.py b/account_reconcile_oca/models/__init__.py new file mode 100644 index 00000000..da04aa8d --- /dev/null +++ b/account_reconcile_oca/models/__init__.py @@ -0,0 +1,8 @@ +from . import account_reconcile_abstract +from . import account_journal +from . import account_bank_statement_line +from . import account_bank_statement +from . import account_account_reconcile +from . import account_move_line +from . import res_company +from . import res_config_settings diff --git a/account_reconcile_oca/models/account_account_reconcile.py b/account_reconcile_oca/models/account_account_reconcile.py new file mode 100644 index 00000000..4171315e --- /dev/null +++ b/account_reconcile_oca/models/account_account_reconcile.py @@ -0,0 +1,182 @@ +# Copyright 2023 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class CharId(fields.Id): + type = "string" + column_type = ("varchar", fields.pg_varchar()) + + +class AccountAccountReconcile(models.Model): + _name = "account.account.reconcile" + _description = "Account Account Reconcile" + _inherit = "account.reconcile.abstract" + _auto = False + + reconcile_data_info = fields.Serialized(inverse="_inverse_reconcile_data_info") + + partner_id = fields.Many2one("res.partner", readonly=True) + account_id = fields.Many2one("account.account", readonly=True) + name = fields.Char(readonly=True) + is_reconciled = fields.Boolean(readonly=True) + + @property + def _table_query(self): + return "{} {} {} {} {}".format( + self._select(), + self._from(), + self._where(), + self._groupby(), + self._having(), + ) + + def _select(self): + account_account_name_field = ( + self.env["ir.model.fields"] + .sudo() + .search([("model", "=", "account.account"), ("name", "=", "name")]) + ) + account_name = ( + f"a.name ->> '{self.env.user.lang}'" + if account_account_name_field.translate + else "a.name" + ) + return f""" + SELECT + min(aml.id) as id, + MAX({account_name}) as name, + aml.partner_id, + a.id as account_id, + FALSE as is_reconciled, + aml.currency_id as currency_id, + a.company_id, + null as foreign_currency_id + """ + + def _from(self): + return """ + FROM + account_account a + INNER JOIN account_move_line aml ON aml.account_id = a.id + INNER JOIN account_move am ON am.id = aml.move_id + """ + + def _where(self): + return """ + WHERE a.reconcile + AND am.state = 'posted' + AND aml.amount_residual != 0 + """ + + def _groupby(self): + return """ + GROUP BY + a.id, aml.partner_id, aml.currency_id, a.company_id + """ + + def _having(self): + return """ + HAVING + SUM(aml.debit) > 0 + AND SUM(aml.credit) > 0 + """ + + def _compute_reconcile_data_info(self): + data_obj = self.env["account.account.reconcile.data"] + for record in self: + if self.env.context.get("default_account_move_lines"): + data = { + "data": [], + "counterparts": self.env.context.get("default_account_move_lines"), + } + record.reconcile_data_info = self._recompute_data(data) + continue + data_record = data_obj.search( + [("user_id", "=", self.env.user.id), ("reconcile_id", "=", record.id)] + ) + if data_record: + record.reconcile_data_info = data_record.data + else: + record.reconcile_data_info = {"data": [], "counterparts": []} + + def _inverse_reconcile_data_info(self): + data_obj = self.env["account.account.reconcile.data"] + for record in self: + data_record = data_obj.search( + [("user_id", "=", self.env.user.id), ("reconcile_id", "=", record.id)] + ) + if data_record: + data_record.data = record.reconcile_data_info + else: + data_obj.create( + { + "reconcile_id": record.id, + "user_id": self.env.user.id, + "data": record.reconcile_data_info, + } + ) + + @api.onchange("add_account_move_line_id") + def _onchange_add_account_move_line(self): + if self.add_account_move_line_id: + data = self.reconcile_data_info + if self.add_account_move_line_id.id not in data["counterparts"]: + data["counterparts"].append(self.add_account_move_line_id.id) + else: + del data["counterparts"][ + data["counterparts"].index(self.add_account_move_line_id.id) + ] + self.reconcile_data_info = self._recompute_data(data) + self.add_account_move_line_id = False + + @api.onchange("manual_reference", "manual_delete") + def _onchange_manual_reconcile_reference(self): + self.ensure_one() + data = self.reconcile_data_info + counterparts = [] + for line in data["data"]: + if line["reference"] == self.manual_reference: + if self.manual_delete: + continue + counterparts.append(line["id"]) + data["counterparts"] = counterparts + self.reconcile_data_info = self._recompute_data(data) + self.manual_delete = False + self.manual_reference = False + + def _recompute_data(self, data): + new_data = {"data": [], "counterparts": data["counterparts"]} + counterparts = data["counterparts"] + amount = 0.0 + for line_id in counterparts: + line = self._get_reconcile_line( + self.env["account.move.line"].browse(line_id), "other", True, amount + ) + new_data["data"].append(line) + amount += line["amount"] + return new_data + + def clean_reconcile(self): + self.ensure_one() + self.reconcile_data_info = {"data": [], "counterparts": []} + + def reconcile(self): + lines = self.env["account.move.line"].browse( + self.reconcile_data_info["counterparts"] + ) + lines.reconcile() + data_record = self.env["account.account.reconcile.data"].search( + [("user_id", "=", self.env.user.id), ("reconcile_id", "=", self.id)] + ) + data_record.unlink() + + +class AccountAccountReconcileData(models.TransientModel): + _name = "account.account.reconcile.data" + _description = "Reconcile data model to store user info" + + user_id = fields.Many2one("res.users", required=True) + reconcile_id = fields.Integer(required=True) + data = fields.Serialized() diff --git a/account_reconcile_oca/models/account_bank_statement.py b/account_reconcile_oca/models/account_bank_statement.py new file mode 100644 index 00000000..19b9bec1 --- /dev/null +++ b/account_reconcile_oca/models/account_bank_statement.py @@ -0,0 +1,15 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import models + + +class AccountBankStatement(models.Model): + _inherit = "account.bank.statement" + + def action_open_statement(self): + self.ensure_one() + action = self.env["ir.actions.act_window"]._for_xml_id( + "account_reconcile_oca.account_bank_statement_action_edit" + ) + action["res_id"] = self.id + return action diff --git a/account_reconcile_oca/models/account_bank_statement_line.py b/account_reconcile_oca/models/account_bank_statement_line.py new file mode 100644 index 00000000..d51f2bd7 --- /dev/null +++ b/account_reconcile_oca/models/account_bank_statement_line.py @@ -0,0 +1,833 @@ +# Copyright 2023 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from collections import defaultdict + +from dateutil import rrule +from dateutil.relativedelta import relativedelta + +from odoo import Command, _, api, fields, models, tools +from odoo.exceptions import UserError +from odoo.tools import float_is_zero + + +class AccountBankStatementLine(models.Model): + _name = "account.bank.statement.line" + _inherit = ["account.bank.statement.line", "account.reconcile.abstract"] + + reconcile_data_info = fields.Serialized(inverse="_inverse_reconcile_data_info") + reconcile_mode = fields.Selection( + selection=lambda self: self.env["account.journal"] + ._fields["reconcile_mode"] + .selection + ) + company_id = fields.Many2one(related="journal_id.company_id") + reconcile_data = fields.Serialized() + manual_line_id = fields.Many2one( + "account.move.line", + store=False, + default=False, + prefetch=False, + ) + manual_kind = fields.Char( + store=False, + default=False, + prefetch=False, + ) + manual_account_id = fields.Many2one( + "account.account", + check_company=True, + store=False, + default=False, + prefetch=False, + ) + manual_partner_id = fields.Many2one( + "res.partner", + domain=[("parent_id", "=", False)], + check_company=True, + store=False, + default=False, + prefetch=False, + ) + analytic_distribution = fields.Json( + store=False, + default=False, + prefetch=False, + ) + analytic_precision = fields.Integer( + store=False, + default=lambda self: self.env["decimal.precision"].precision_get( + "Percentage Analytic" + ), + ) + manual_model_id = fields.Many2one( + "account.reconcile.model", + check_company=True, + store=False, + default=False, + prefetch=False, + domain=[("rule_type", "=", "writeoff_button")], + ) + manual_name = fields.Char(store=False, default=False, prefetch=False) + manual_amount = fields.Monetary( + store=False, default=False, prefetch=False, currency_field="manual_currency_id" + ) + manual_currency_id = fields.Many2one( + "res.currency", readonly=True, store=False, prefetch=False + ) + manual_original_amount = fields.Monetary( + default=False, store=False, prefetch=False, readonly=True + ) + manual_move_type = fields.Selection( + lambda r: r.env["account.move"]._fields["move_type"].selection, + default=False, + store=False, + prefetch=False, + readonly=True, + ) + manual_move_id = fields.Many2one( + "account.move", default=False, store=False, prefetch=False, readonly=True + ) + can_reconcile = fields.Boolean(sparse="reconcile_data_info") + reconcile_aggregate = fields.Char(compute="_compute_reconcile_aggregate") + aggregate_id = fields.Integer(compute="_compute_reconcile_aggregate") + aggregate_name = fields.Char(compute="_compute_reconcile_aggregate") + + @api.model + def _reconcile_aggregate_map(self): + lang = self.env["res.lang"]._lang_get(self.env.user.lang) + week_start = rrule.weekday(int(lang.week_start) - 1) + return { + False: lambda s: (False, False), + "statement": lambda s: (s.statement_id.id, s.statement_id.name), + "day": lambda s: (s.date.toordinal(), s.date.strftime(lang.date_format)), + "week": lambda s: ( + (s.date + relativedelta(weekday=week_start(-1))).toordinal(), + (s.date + relativedelta(weekday=week_start(-1))).strftime( + lang.date_format + ), + ), + "month": lambda s: ( + s.date.replace(day=1).toordinal(), + s.date.replace(day=1).strftime(lang.date_format), + ), + } + + @api.depends("company_id", "journal_id") + def _compute_reconcile_aggregate(self): + reconcile_aggregate_map = self._reconcile_aggregate_map() + for record in self: + reconcile_aggregate = ( + record.journal_id.reconcile_aggregate + or record.company_id.reconcile_aggregate + ) + record.reconcile_aggregate = reconcile_aggregate + print(record.date, reconcile_aggregate_map[reconcile_aggregate](record)) + record.aggregate_id, record.aggregate_name = reconcile_aggregate_map[ + reconcile_aggregate + ](record) + + def save(self): + return {"type": "ir.actions.act_window_close"} + + @api.model + def action_new_line(self): + action = self.env["ir.actions.act_window"]._for_xml_id( + "account_reconcile_oca.action_bank_statement_line_create" + ) + action["context"] = self.env.context + return action + + @api.onchange("manual_model_id") + def _onchange_manual_model_id(self): + if self.manual_model_id: + data = [] + for line in self.reconcile_data_info.get("data", []): + if line.get("kind") != "suspense": + data.append(line) + self.reconcile_data_info = self._recompute_suspense_line( + *self._reconcile_data_by_model( + data, + self.manual_model_id, + self.reconcile_data_info["reconcile_auxiliary_id"], + ), + self.manual_reference, + ) + else: + # Refreshing data + self.reconcile_data_info = self.browse( + self.id.origin + )._default_reconcile_data() + self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) + + @api.onchange("add_account_move_line_id") + def _onchange_add_account_move_line_id(self): + if self.add_account_move_line_id: + data = self.reconcile_data_info["data"] + new_data = [] + is_new_line = True + pending_amount = 0.0 + for line in data: + if line["kind"] != "suspense": + pending_amount += line["amount"] + if self.add_account_move_line_id.id in line.get( + "counterpart_line_ids", [] + ): + is_new_line = False + else: + new_data.append(line) + if is_new_line: + new_data.append( + self._get_reconcile_line( + self.add_account_move_line_id, "other", True, pending_amount + ) + ) + self.reconcile_data_info = self._recompute_suspense_line( + new_data, + self.reconcile_data_info["reconcile_auxiliary_id"], + self.manual_reference, + exchange_recompute=True, + ) + self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) + self.add_account_move_line_id = False + + def _recompute_suspense_line( + self, data, reconcile_auxiliary_id, manual_reference, exchange_recompute=False + ): + reconcile_auxiliary_id = self._compute_exchange_rate( + data, reconcile_auxiliary_id, exchange_recompute=exchange_recompute + ) + can_reconcile = True + total_amount = 0 + new_data = [] + suspense_line = False + counterparts = [] + for line in data: + if line.get("counterpart_line_ids"): + counterparts += line["counterpart_line_ids"] + if ( + line["account_id"][0] == self.journal_id.suspense_account_id.id + or not line["account_id"][0] + ) and line["kind"] != "suspense": + can_reconcile = False + if line["kind"] != "suspense": + new_data.append(line) + total_amount += line["amount"] + else: + suspense_line = line + if not float_is_zero( + total_amount, precision_digits=self.currency_id.decimal_places + ): + can_reconcile = False + if suspense_line: + suspense_line.update( + { + "amount": -total_amount, + "credit": total_amount if total_amount > 0 else 0.0, + "debit": -total_amount if total_amount < 0 else 0.0, + } + ) + else: + suspense_line = { + "reference": "reconcile_auxiliary;%s" % reconcile_auxiliary_id, + "id": False, + "account_id": [ + self.journal_id.suspense_account_id.id, + self.journal_id.suspense_account_id.display_name, + ], + "partner_id": self.partner_id + and [self.partner_id.id, self.partner_id.display_name] + or (self.partner_name and (False, self.partner_name)) + or False, + "date": fields.Date.to_string(self.date), + "name": self.payment_ref or self.name, + "amount": -total_amount, + "credit": total_amount if total_amount > 0 else 0.0, + "debit": -total_amount if total_amount < 0 else 0.0, + "kind": "suspense", + "currency_id": self.company_id.currency_id.id, + "line_currency_id": self.company_id.currency_id.id, + "currency_amount": -total_amount, + } + reconcile_auxiliary_id += 1 + new_data.append(suspense_line) + return { + "data": new_data, + "counterparts": counterparts, + "reconcile_auxiliary_id": reconcile_auxiliary_id, + "can_reconcile": can_reconcile, + "manual_reference": manual_reference, + } + + def _check_line_changed(self, line): + return ( + not float_is_zero( + self.manual_amount - line["amount"], + precision_digits=self.company_id.currency_id.decimal_places, + ) + or self.manual_account_id.id != line["account_id"][0] + or self.manual_name != line["name"] + or (self.manual_partner_id and self.manual_partner_id.display_name or False) + != line.get("partner_id") + ) + + @api.onchange("manual_reference", "manual_delete") + def _onchange_manual_reconcile_reference(self): + self.ensure_one() + data = self.reconcile_data_info.get("data", []) + new_data = [] + for line in data: + if line["reference"] == self.manual_reference: + if self.manual_delete: + self.update( + { + "manual_delete": False, + "manual_reference": False, + "manual_account_id": False, + "manual_amount": False, + "manual_name": False, + "manual_partner_id": False, + "manual_line_id": False, + "manual_move_id": False, + "manual_move_type": False, + "manual_kind": False, + "manual_original_amount": False, + "manual_currency_id": False, + "analytic_distribution": False, + } + ) + continue + else: + self.manual_account_id = line["account_id"][0] + self.manual_amount = line["amount"] + self.manual_currency_id = line["currency_id"] + self.manual_name = line["name"] + self.manual_partner_id = ( + line.get("partner_id") and line["partner_id"][0] + ) + self.manual_line_id = line["id"] + self.analytic_distribution = line.get("analytic_distribution", {}) + if self.manual_line_id: + self.manual_move_id = self.manual_line_id.move_id + self.manual_move_type = self.manual_line_id.move_id.move_type + self.manual_kind = line["kind"] + self.manual_original_amount = line.get("original_amount", 0.0) + new_data.append(line) + self.reconcile_data_info = self._recompute_suspense_line( + new_data, + self.reconcile_data_info["reconcile_auxiliary_id"], + self.manual_reference, + ) + self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) + + @api.onchange( + "manual_account_id", + "manual_partner_id", + "manual_name", + "manual_amount", + "analytic_distribution", + ) + def _onchange_manual_reconcile_vals(self): + self.ensure_one() + data = self.reconcile_data_info.get("data", []) + new_data = [] + for line in data: + if line["reference"] == self.manual_reference: + if self._check_line_changed(line): + line.update( + { + "name": self.manual_name, + "partner_id": self.manual_partner_id + and [ + self.manual_partner_id.id, + self.manual_partner_id.display_name, + ] + or (self.partner_name and (False, self.partner_name)) + or False, + "account_id": [ + self.manual_account_id.id, + self.manual_account_id.display_name, + ] + if self.manual_account_id + else [False, _("Undefined")], + "amount": self.manual_amount, + "credit": -self.manual_amount + if self.manual_amount < 0 + else 0.0, + "debit": self.manual_amount + if self.manual_amount > 0 + else 0.0, + "analytic_distribution": self.analytic_distribution, + "kind": line["kind"] + if line["kind"] != "suspense" + else "other", + } + ) + if line["kind"] == "liquidity": + self._update_move_partner() + new_data.append(line) + self.reconcile_data_info = self._recompute_suspense_line( + new_data, + self.reconcile_data_info["reconcile_auxiliary_id"], + self.manual_reference, + ) + self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) + + def _update_move_partner(self): + if self.partner_id == self.manual_partner_id: + return + self.partner_id = self.manual_partner_id + + @api.depends("reconcile_data") + def _compute_reconcile_data_info(self): + for record in self: + if record.reconcile_data: + record.reconcile_data_info = record.reconcile_data + else: + record.reconcile_data_info = record._default_reconcile_data( + from_unreconcile=record.is_reconciled + ) + record.can_reconcile = record.reconcile_data_info.get( + "can_reconcile", False + ) + + def action_show_move(self): + self.ensure_one() + action = self.env["ir.actions.act_window"]._for_xml_id( + "account.action_move_journal_line" + ) + action.update( + {"res_id": self.move_id.id, "views": [[False, "form"]], "view_mode": "form"} + ) + return action + + def _inverse_reconcile_data_info(self): + for record in self: + record.reconcile_data = record.reconcile_data_info + + def _reconcile_data_by_model(self, data, reconcile_model, reconcile_auxiliary_id): + new_data = [] + liquidity_amount = 0.0 + for line_data in data: + if line_data["kind"] == "suspense": + continue + new_data.append(line_data) + liquidity_amount += line_data["amount"] + for line in reconcile_model._get_write_off_move_lines_dict( + -liquidity_amount, self._retrieve_partner() + ): + new_line = line.copy() + amount = line.get("balance") + if self.foreign_currency_id: + amount = self.foreign_currency_id.compute( + amount, self.journal_id.currency_id or self.company_currency_id + ) + new_line.update( + { + "reference": "reconcile_auxiliary;%s" % reconcile_auxiliary_id, + "id": False, + "amount": amount, + "debit": amount if amount > 0 else 0, + "credit": -amount if amount < 0 else 0, + "kind": "other", + "account_id": [ + line["account_id"], + self.env["account.account"] + .browse(line["account_id"]) + .display_name, + ], + "date": fields.Date.to_string(self.date), + "line_currency_id": self.company_id.currency_id.id, + "currency_id": self.company_id.currency_id.id, + "currency_amount": amount, + } + ) + reconcile_auxiliary_id += 1 + if line.get("partner_id"): + new_line["partner_id"] = ( + line["partner_id"], + self.env["res.partner"].browse(line["partner_id"]).display_name, + ) + new_data.append(new_line) + return new_data, reconcile_auxiliary_id + + def _compute_exchange_rate( + self, data, reconcile_auxiliary_id, exchange_recompute=False + ): + if not exchange_recompute: + return reconcile_auxiliary_id + foreign_currency = ( + self.currency_id != self.company_id.currency_id + or self.foreign_currency_id + or any(line["currency_id"] != line["line_currency_id"] for line in data) + ) + if not foreign_currency or self.is_reconciled: + return reconcile_auxiliary_id + currency = self.journal_id.currency_id or self.company_id.currency_id + amount = sum(d.get("net_amount", 0) for d in data) + if not currency.is_zero(amount): + account = self.company_id.expense_currency_exchange_account_id + if amount > 0: + account = self.company_id.income_currency_exchange_account_id + data.append( + { + "reference": "reconcile_auxiliary;%s" % reconcile_auxiliary_id, + "id": False, + "account_id": [account.id, account.display_name], + "partner_id": False, + "date": fields.Date.to_string(self.date), + "name": self.payment_ref or self.name, + "amount": -amount, + "net_amount": -amount, + "credit": amount if amount > 0 else 0.0, + "debit": -amount if amount < 0 else 0.0, + "kind": "other", + "currency_id": self.currency_id.id, + "line_currency_id": self.currency_id.id, + "currency_amount": -amount, + } + ) + reconcile_auxiliary_id += 1 + return reconcile_auxiliary_id + + def _default_reconcile_data(self, from_unreconcile=False): + liquidity_lines, suspense_lines, other_lines = self._seek_for_lines() + data = [self._get_reconcile_line(line, "liquidity") for line in liquidity_lines] + reconcile_auxiliary_id = 1 + if not from_unreconcile: + res = ( + self.env["account.reconcile.model"] + .search( + [("rule_type", "in", ["invoice_matching", "writeoff_suggestion"])] + ) + ._apply_rules(self, self._retrieve_partner()) + ) + if res and res.get("status", "") == "write_off": + return self._recompute_suspense_line( + *self._reconcile_data_by_model( + data, res["model"], reconcile_auxiliary_id + ), + self.manual_reference, + exchange_recompute=True, + ) + elif res and res.get("amls"): + amount = self.amount_total_signed + for line in res.get("amls", []): + line_data = self._get_reconcile_line( + line, "other", is_counterpart=True, max_amount=amount + ) + amount -= line_data.get("amount") + data.append(line_data) + return self._recompute_suspense_line( + data, + reconcile_auxiliary_id, + self.manual_reference, + exchange_recompute=True, + ) + return self._recompute_suspense_line( + data + + [ + self._get_reconcile_line( + line, "other", from_unreconcile=from_unreconcile + ) + for line in other_lines + ], + reconcile_auxiliary_id, + self.manual_reference, + ) + + def clean_reconcile(self): + self.reconcile_data_info = self._default_reconcile_data() + self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) + + def reconcile_bank_line(self): + self.ensure_one() + self.reconcile_mode = self.journal_id.reconcile_mode + result = getattr(self, "_reconcile_bank_line_%s" % self.reconcile_mode)( + self.reconcile_data_info["data"] + ) + self.reconcile_data_info = False + return result + + def _reconcile_bank_line_edit(self, data): + _liquidity_lines, suspense_lines, other_lines = self._seek_for_lines() + lines_to_remove = [(2, line.id) for line in suspense_lines + other_lines] + + # Cleanup previous lines. + move = self.move_id + container = {"records": move, "self": move} + to_reconcile = [] + with move._check_balanced(container): + move.with_context( + skip_account_move_synchronization=True, + force_delete=True, + skip_invoice_sync=True, + ).write( + { + "line_ids": lines_to_remove, + } + ) + for line_vals in data: + if line_vals["kind"] == "liquidity": + continue + line = ( + self.env["account.move.line"] + .with_context( + check_move_validity=False, + skip_sync_invoice=True, + skip_invoice_sync=True, + ) + .create(self._reconcile_move_line_vals(line_vals)) + ) + if line_vals.get("counterpart_line_ids"): + to_reconcile.append( + self.env["account.move.line"].browse( + line_vals.get("counterpart_line_ids") + ) + + line + ) + for reconcile_items in to_reconcile: + reconcile_items.reconcile() + + def _reconcile_bank_line_keep_move_vals(self): + return { + "journal_id": self.journal_id.id, + } + + def _reconcile_bank_line_keep(self, data): + move = ( + self.env["account.move"] + .with_context(skip_invoice_sync=True) + .create(self._reconcile_bank_line_keep_move_vals()) + ) + _liquidity_lines, suspense_lines, other_lines = self._seek_for_lines() + container = {"records": move, "self": move} + to_reconcile = defaultdict(lambda: self.env["account.move.line"]) + with move._check_balanced(container): + for line in suspense_lines | other_lines: + to_reconcile[line.account_id.id] |= line + line_data = line.with_context( + active_test=False, + include_business_fields=True, + ).copy_data({"move_id": move.id})[0] + to_reconcile[line.account_id.id] |= ( + self.env["account.move.line"] + .with_context( + check_move_validity=False, + skip_sync_invoice=True, + skip_invoice_sync=True, + ) + .create(line_data) + ) + move.write( + { + "line_ids": [ + Command.update( + line.id, + { + "balance": -line.balance, + "amount_currency": -line.amount_currency, + }, + ) + for line in move.line_ids + if line.move_id.move_type == "entry" + or line.display_type == "cogs" + ] + } + ) + for line_vals in data: + if line_vals["kind"] == "liquidity": + continue + if line_vals["kind"] == "suspense": + raise UserError(_("No supense lines are allowed when reconciling")) + line = ( + self.env["account.move.line"] + .with_context(check_move_validity=False, skip_invoice_sync=True) + .create(self._reconcile_move_line_vals(line_vals, move.id)) + ) + if line_vals.get("counterpart_line_ids") and line.account_id.reconcile: + to_reconcile[line.account_id.id] |= ( + self.env["account.move.line"].browse( + line_vals.get("counterpart_line_ids") + ) + | line + ) + move.invalidate_recordset() + move._post() + for _account, lines in to_reconcile.items(): + lines.reconcile() + + def unreconcile_bank_line(self): + self.ensure_one() + return getattr( + self, "_unreconcile_bank_line_%s" % (self.reconcile_mode or "edit") + )() + + def _unreconcile_bank_line_edit(self): + self.reconcile_data_info = self._default_reconcile_data(from_unreconcile=True) + self.action_undo_reconciliation() + + def _unreconcile_bank_line_keep(self): + raise UserError(_("Keep suspense move lines mode cannot be unreconciled")) + + def _reconcile_move_line_vals(self, line, move_id=False): + return { + "move_id": move_id or self.move_id.id, + "account_id": line["account_id"][0], + "partner_id": line.get("partner_id") and line["partner_id"][0], + "credit": line["credit"], + "debit": line["debit"], + "tax_ids": line.get("tax_ids", []), + "tax_tag_ids": line.get("tax_tag_ids", []), + "group_tax_id": line.get("group_tax_id"), + "tax_repartition_line_id": line.get("tax_repartition_line_id"), + "analytic_distribution": line.get("analytic_distribution"), + "name": line.get("name"), + "reconcile_model_id": line.get("reconcile_model_id"), + } + + @api.model_create_multi + def create(self, mvals): + result = super().create(mvals) + if tools.config["test_enable"] and not self.env.context.get( + "_test_account_reconcile_oca" + ): + return result + models = self.env["account.reconcile.model"].search( + [ + ("rule_type", "in", ["invoice_matching", "writeoff_suggestion"]), + ("auto_reconcile", "=", True), + ] + ) + for record in result: + res = models._apply_rules(record, record._retrieve_partner()) + if not res: + continue + liquidity_lines, suspense_lines, other_lines = record._seek_for_lines() + data = [ + record._get_reconcile_line(line, "liquidity") + for line in liquidity_lines + ] + reconcile_auxiliary_id = 1 + if res.get("status", "") == "write_off": + data = record._recompute_suspense_line( + *record._reconcile_data_by_model( + data, res["model"], reconcile_auxiliary_id + ), + self.manual_reference, + exchange_recompute=True, + ) + elif res.get("amls"): + amount = self.amount + for line in res.get("amls", []): + line_data = record._get_reconcile_line( + line, "other", is_counterpart=True, max_amount=amount + ) + amount -= line_data.get("amount") + data.append(line_data) + data = record._recompute_suspense_line( + data, + reconcile_auxiliary_id, + self.manual_reference, + exchange_recompute=True, + ) + if not data.get("can_reconcile"): + continue + getattr( + record, "_reconcile_bank_line_%s" % record.journal_id.reconcile_mode + )(data["data"]) + return result + + def button_manual_reference_full_paid(self): + self.ensure_one() + if not self.reconcile_data_info["manual_reference"]: + return + manual_reference = self.reconcile_data_info["manual_reference"] + data = self.reconcile_data_info.get("data", []) + new_data = [] + reconcile_auxiliary_id = self.reconcile_data_info["reconcile_auxiliary_id"] + for line in data: + if line["reference"] == manual_reference and line.get("id"): + total_amount = -line["amount"] + line["original_amount_unsigned"] + original_amount = line["original_amount_unsigned"] + new_data.append( + self._get_reconcile_line( + self.env["account.move.line"].browse(line["id"]), + "other", + is_counterpart=True, + max_amount=original_amount, + ) + ) + new_data.append( + { + "reference": "reconcile_auxiliary;%s" % reconcile_auxiliary_id, + "id": False, + "account_id": line["account_id"], + "partner_id": line.get("partner_id"), + "date": line["date"], + "name": line["name"], + "amount": -total_amount, + "credit": total_amount if total_amount > 0 else 0.0, + "debit": -total_amount if total_amount < 0 else 0.0, + "kind": "other", + "currency_id": line["currency_id"], + "line_currency_id": line["currency_id"], + "currency_amount": -total_amount, + } + ) + reconcile_auxiliary_id += 1 + else: + new_data.append(line) + self.reconcile_data_info = self._recompute_suspense_line( + new_data, + reconcile_auxiliary_id, + self.manual_reference, + exchange_recompute=True, + ) + self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) + + def action_to_check(self): + self.ensure_one() + self.move_id.to_check = True + if self.can_reconcile and self.journal_id.reconcile_mode == "edit": + self.reconcile_bank_line() + + def action_checked(self): + self.ensure_one() + self.move_id.to_check = False + + def _get_reconcile_line( + self, line, kind, is_counterpart=False, max_amount=False, from_unreconcile=False + ): + vals = super()._get_reconcile_line( + line, + kind, + is_counterpart=is_counterpart, + max_amount=max_amount, + from_unreconcile=from_unreconcile, + ) + if vals["partner_id"] is False and self.partner_name: + vals["partner_id"] = (False, self.partner_name) + return vals + + def add_statement(self): + self.ensure_one() + action = self.env["ir.actions.act_window"]._for_xml_id( + "account_reconcile_oca.account_bank_statement_action_edit" + ) + previous_line_with_statement = self.env["account.bank.statement.line"].search( + [ + ("internal_index", "<", self.internal_index), + ("journal_id", "=", self.journal_id.id), + ("state", "=", "posted"), + ("statement_id", "!=", self.statement_id.id), + ("statement_id", "!=", False), + ], + limit=1, + ) + action["context"] = { + "default_journal_id": self.journal_id.id, + "default_balance_start": previous_line_with_statement.statement_id.balance_end_real, + "split_line_id": self.id, + } + return action diff --git a/account_reconcile_oca/models/account_journal.py b/account_reconcile_oca/models/account_journal.py new file mode 100644 index 00000000..a88e106f --- /dev/null +++ b/account_reconcile_oca/models/account_journal.py @@ -0,0 +1,34 @@ +# Copyright 2023 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, fields, models + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + reconcile_mode = fields.Selection( + [("edit", "Edit Move"), ("keep", "Keep Suspense Accounts")], + default="edit", + required=True, + ) + company_currency_id = fields.Many2one(related="company_id.currency_id") + reconcile_aggregate = fields.Selection( + [ + ("statement", "Statement"), + ("day", "Day"), + ("week", "Week"), + ("month", "Month"), + ], + string="Reconcile aggregation", + help="Aggregation to use on reconcile view", + ) + + def get_rainbowman_message(self): + self.ensure_one() + if ( + self._get_journal_dashboard_data_batched()[self.id]["number_to_reconcile"] + > 0 + ): + return False + return _("Well done! Everything has been reconciled") diff --git a/account_reconcile_oca/models/account_move_line.py b/account_reconcile_oca/models/account_move_line.py new file mode 100644 index 00000000..7e38f627 --- /dev/null +++ b/account_reconcile_oca/models/account_move_line.py @@ -0,0 +1,35 @@ +# Copyright 2023 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, fields, models +from odoo.exceptions import ValidationError + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + invoice_due_date = fields.Date( + related="move_id.invoice_date_due", + readonly=True, + ) + + def action_reconcile_manually(self): + if not self: + return {} + accounts = self.mapped("account_id") + if len(accounts) > 1: + raise ValidationError( + _("You can only reconcile journal items belonging to the same account.") + ) + partner = self.mapped("partner_id") + action = self.env["ir.actions.act_window"]._for_xml_id( + "account_reconcile_oca.account_account_reconcile_act_window" + ) + action["domain"] = [("account_id", "=", self.mapped("account_id").id)] + if len(partner) == 1: + action["domain"] += [("partner_id", "=", partner.id)] + action["context"] = self.env.context.copy() + action["context"]["default_account_move_lines"] = self.filtered( + lambda r: not r.reconciled + ).ids + return action diff --git a/account_reconcile_oca/models/account_reconcile_abstract.py b/account_reconcile_oca/models/account_reconcile_abstract.py new file mode 100644 index 00000000..026b57c8 --- /dev/null +++ b/account_reconcile_oca/models/account_reconcile_abstract.py @@ -0,0 +1,104 @@ +# Copyright 2023 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models +from odoo.tools import float_is_zero + + +class AccountReconcileAbstract(models.AbstractModel): + _name = "account.reconcile.abstract" + _description = "Account Reconcile Abstract" + + reconcile_data_info = fields.Serialized( + compute="_compute_reconcile_data_info", + prefetch=False, + ) + company_id = fields.Many2one("res.company") + add_account_move_line_id = fields.Many2one( + "account.move.line", + check_company=True, + store=False, + default=False, + prefetch=False, + ) + manual_reference = fields.Char(store=False, default=False, prefetch=False) + manual_delete = fields.Boolean( + store=False, + default=False, + prefetch=False, + ) + currency_id = fields.Many2one("res.currency", readonly=True) + foreign_currency_id = fields.Many2one("res.currency") + company_currency_id = fields.Many2one( + "res.currency", related="company_id.currency_id" + ) + + def _get_reconcile_line( + self, line, kind, is_counterpart=False, max_amount=False, from_unreconcile=False + ): + date = self.date if "date" in self._fields else line.date + original_amount = amount = net_amount = line.debit - line.credit + amount_currency = self.company_id.currency_id + if is_counterpart: + amount = line.amount_residual_currency or line.amount_residual + amount_currency = line.currency_id or self.company_id.currency_id + original_amount = net_amount = line.amount_residual + if max_amount: + currency_max_amount = self.company_id.currency_id._convert( + max_amount, amount_currency, self.company_id, line.date + ) + if amount > currency_max_amount > 0: + amount = currency_max_amount + net_amount = max_amount + if amount < currency_max_amount < 0: + amount = currency_max_amount + net_amount = max_amount + amount = -amount + original_amount = -original_amount + net_amount = -net_amount + else: + amount_currency = line.currency_id + amount = self.company_id.currency_id._convert( + amount, amount_currency, self.company_id, date + ) + currency_amount = amount + amount = amount_currency._convert( + amount, self.company_id.currency_id, self.company_id, date + ) + vals = { + "reference": "account.move.line;%s" % line.id, + "id": line.id, + "account_id": [line.account_id.id, line.account_id.display_name], + "partner_id": [line.partner_id.id, line.partner_id.display_name] + if line.partner_id + else False, + "date": fields.Date.to_string(line.date), + "name": line.name, + "debit": amount if amount > 0 else 0.0, + "credit": -amount if amount < 0 else 0.0, + "amount": amount, + "net_amount": amount - net_amount, + "currency_id": self.company_id.currency_id.id, + "line_currency_id": line.currency_id.id, + "currency_amount": currency_amount, + "analytic_distribution": line.analytic_distribution, + "kind": kind, + } + if from_unreconcile: + vals.update( + { + "id": False, + "counterpart_line_ids": ( + line.matched_debit_ids.mapped("debit_move_id") + | line.matched_credit_ids.mapped("credit_move_id") + ).ids, + } + ) + if not float_is_zero( + amount - original_amount, precision_digits=line.currency_id.decimal_places + ): + vals["original_amount"] = abs(original_amount) + vals["original_amount_unsigned"] = original_amount + if is_counterpart: + vals["counterpart_line_ids"] = line.ids + return vals diff --git a/account_reconcile_oca/models/res_company.py b/account_reconcile_oca/models/res_company.py new file mode 100644 index 00000000..3ed88cb6 --- /dev/null +++ b/account_reconcile_oca/models/res_company.py @@ -0,0 +1,14 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + reconcile_aggregate = fields.Selection( + selection=lambda self: self.env["account.journal"] + ._fields["reconcile_aggregate"] + .selection + ) diff --git a/account_reconcile_oca/models/res_config_settings.py b/account_reconcile_oca/models/res_config_settings.py new file mode 100644 index 00000000..8bcc2185 --- /dev/null +++ b/account_reconcile_oca/models/res_config_settings.py @@ -0,0 +1,12 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + reconcile_aggregate = fields.Selection( + related="company_id.reconcile_aggregate", readonly=False + ) diff --git a/account_reconcile_oca/pyproject.toml b/account_reconcile_oca/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/account_reconcile_oca/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/account_reconcile_oca/readme/CONTRIBUTORS.md b/account_reconcile_oca/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..c84bf49d --- /dev/null +++ b/account_reconcile_oca/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Enric Tobella diff --git a/account_reconcile_oca/readme/DESCRIPTION.md b/account_reconcile_oca/readme/DESCRIPTION.md new file mode 100644 index 00000000..ddb97394 --- /dev/null +++ b/account_reconcile_oca/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This addon allows to reconcile bank statements and account marked as +reconcile. diff --git a/account_reconcile_oca/readme/ROADMAP.md b/account_reconcile_oca/readme/ROADMAP.md new file mode 100644 index 00000000..41273336 --- /dev/null +++ b/account_reconcile_oca/readme/ROADMAP.md @@ -0,0 +1,3 @@ +The following bugs are already detected: + +- Creation of activities on the chatter do show automatically diff --git a/account_reconcile_oca/readme/USAGE.md b/account_reconcile_oca/readme/USAGE.md new file mode 100644 index 00000000..2a053a39 --- /dev/null +++ b/account_reconcile_oca/readme/USAGE.md @@ -0,0 +1,10 @@ +## Bank reconcile + +Access Invoicing / Dashboard with a user with Full Acounting +capabilities. Select reconcile on the journal of your choice. + +## Account reconcile + +Access Invoicing / Accounting / Actions / Reconcile All the possible +reconcile options will show and you will be able to reconcile properly. +You can access the same widget from accounts and Partners. diff --git a/account_reconcile_oca/security/ir.model.access.csv b/account_reconcile_oca/security/ir.model.access.csv new file mode 100644 index 00000000..d73fa145 --- /dev/null +++ b/account_reconcile_oca/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_account_account_reconcile,account.account.reconcile,model_account_account_reconcile,account.group_account_user,1,1,0,0 +access_account_account_reconcile_data,account.account.reconcile,model_account_account_reconcile_data,account.group_account_user,1,1,1,1 diff --git a/account_reconcile_oca/static/description/icon.png b/account_reconcile_oca/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/account_reconcile_oca/static/description/icon.png differ diff --git a/account_reconcile_oca/static/description/index.html b/account_reconcile_oca/static/description/index.html new file mode 100644 index 00000000..379e58cc --- /dev/null +++ b/account_reconcile_oca/static/description/index.html @@ -0,0 +1,452 @@ + + + + + + +Account Reconcile Oca + + + +
+

Account Reconcile Oca

+ + +

Beta License: AGPL-3 OCA/account-reconcile Translate me on Weblate Try me on Runboat

+

This addon allows to reconcile bank statements and account marked as +reconcile.

+

Table of contents

+ +
+

Usage

+
+

Bank reconcile

+

Access Invoicing / Dashboard with a user with Full Acounting +capabilities. Select reconcile on the journal of your choice.

+
+
+

Account reconcile

+

Access Invoicing / Accounting / Actions / Reconcile All the possible +reconcile options will show and you will be able to reconcile properly. +You can access the same widget from accounts and Partners.

+
+
+
+

Known issues / Roadmap

+

The following bugs are already detected:

+
    +
  • Creation of activities on the chatter do show automatically
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • CreuBlanca
  • +
  • Dixmit
  • +
+
+
+

Contributors

+
    +
  • Enric Tobella
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

etobella

+

This module is part of the OCA/account-reconcile project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/account_reconcile_oca/static/src/js/reconcile/reconcile_controller.esm.js b/account_reconcile_oca/static/src/js/reconcile/reconcile_controller.esm.js new file mode 100644 index 00000000..fd9f7cb9 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile/reconcile_controller.esm.js @@ -0,0 +1,146 @@ +/** @odoo-module */ +const {onMounted, onWillStart, useState, useSubEnv} = owl; +import {useBus, useService} from "@web/core/utils/hooks"; +import {KanbanController} from "@web/views/kanban/kanban_controller"; +import {View} from "@web/views/view"; +import {formatMonetary} from "@web/views/fields/formatters"; + +export class ReconcileController extends KanbanController { + async setup() { + super.setup(); + this.state = useState({ + selectedRecordId: null, + journalBalance: 0, + currency: false, + }); + useSubEnv({ + parentController: this, + exposeController: this.exposeController.bind(this), + }); + this.effect = useService("effect"); + this.orm = useService("orm"); + this.action = useService("action"); + this.router = useService("router"); + this.activeActions = this.props.archInfo.activeActions; + useBus(this.model.bus, "update", () => { + this.selectRecord(); + }); + onWillStart(() => { + this.updateJournalInfo(); + }); + onMounted(() => { + this.selectRecord(); + }); + } + get journalId() { + if (this.props.resModel === "account.bank.statement.line") { + return this.props.context.active_id; + } + return false; + } + async updateJournalInfo() { + var journalId = this.journalId; + if (!journalId) { + return; + } + var result = await this.orm.call("account.journal", "read", [ + [journalId], + ["current_statement_balance", "currency_id", "company_currency_id"], + ]); + this.state.journalBalance = result[0].current_statement_balance; + this.state.currency = (result[0].currency_id || + result[0].company_currency_id)[0]; + } + get journalBalanceStr() { + if (!this.state.journalBalance) { + return ""; + } + return formatMonetary(this.state.journalBalance, { + currencyId: this.state.currency, + }); + } + exposeController(controller) { + this.form_controller = controller; + } + async onClickNewButton() { + const action = await this.orm.call(this.props.resModel, "action_new_line", [], { + context: this.props.context, + }); + this.action.doAction(action, { + onClose: async () => { + await this.model.root.load(); + this.render(true); + }, + }); + } + async setRainbowMan(message) { + this.effect.add({ + message, + type: "rainbow_man", + }); + } + get viewReconcileInfo() { + return { + resId: this.state.selectedRecordId, + type: "form", + noBreadcrumbs: true, + context: { + ...(this.props.context || {}), + form_view_ref: this.props.context.view_ref, + }, + display: {controlPanel: false}, + mode: this.props.mode || "edit", + resModel: this.props.resModel, + }; + } + async selectRecord(record) { + var resId = false; + if (record === undefined && this.props.resId) { + resId = this.props.resId; + } else if (record === undefined) { + var records = this.model.root.records.filter( + (modelRecord) => + !modelRecord.data.is_reconciled || modelRecord.data.to_check + ); + if (records.length === 0) { + records = this.model.root.records; + if (records.length === 0) { + this.state.selectedRecordId = false; + return; + } + } + resId = records[0].resId; + } else { + resId = record.resId; + } + if (this.state.selectedRecordId && this.state.selectedRecordId !== resId) { + if (this.form_controller.model.root.isDirty) { + await this.form_controller.model.root.save({ + noReload: true, + stayInEdition: true, + useSaveErrorDialog: true, + }); + await this.model.root.load(); + await this.render(true); + } + } + if (!this.state.selectedRecordId || this.state.selectedRecordId !== resId) { + this.state.selectedRecordId = resId; + } + this.updateURL(resId); + } + async openRecord(record) { + this.selectRecord(record); + } + updateURL(resId) { + this.router.pushState({id: resId}); + } +} + +ReconcileController.components = { + ...ReconcileController.components, + View, +}; + +ReconcileController.template = "account_reconcile_oca.ReconcileController"; +ReconcileController.defaultProps = {}; diff --git a/account_reconcile_oca/static/src/js/reconcile/reconcile_kanban_record.esm.js b/account_reconcile_oca/static/src/js/reconcile/reconcile_kanban_record.esm.js new file mode 100644 index 00000000..a97c5258 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile/reconcile_kanban_record.esm.js @@ -0,0 +1,14 @@ +/** @odoo-module */ + +import {KanbanRecord} from "@web/views/kanban/kanban_record"; + +export class ReconcileKanbanRecord extends KanbanRecord { + getRecordClasses() { + var result = super.getRecordClasses(); + if (this.props.selectedRecordId === this.props.record.resId) { + result += " o_kanban_record_reconcile_oca_selected"; + } + return result; + } +} +ReconcileKanbanRecord.props = [...KanbanRecord.props, "selectedRecordId?"]; diff --git a/account_reconcile_oca/static/src/js/reconcile/reconcile_renderer.esm.js b/account_reconcile_oca/static/src/js/reconcile/reconcile_renderer.esm.js new file mode 100644 index 00000000..25fe2ac4 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile/reconcile_renderer.esm.js @@ -0,0 +1,63 @@ +/** @odoo-module */ + +import {KanbanRenderer} from "@web/views/kanban/kanban_renderer"; +import {ReconcileKanbanRecord} from "./reconcile_kanban_record.esm.js"; +import {formatMonetary} from "@web/views/fields/formatters"; +import {useService} from "@web/core/utils/hooks"; + +export class ReconcileRenderer extends KanbanRenderer { + setup() { + super.setup(); + this.action = useService("action"); + this.orm = useService("orm"); + } + getAggregates() { + if ( + this.env.parentController.props.resModel !== "account.bank.statement.line" + ) { + return []; + } + const {list} = this.props; + const aggregates = []; + for (const record of list.records) { + const aggregateId = record.data.aggregate_id && record.data.aggregate_id; + if ( + aggregateId && + (!aggregates.length || aggregates[0].id !== aggregateId) + ) { + aggregates.push({ + id: aggregateId, + name: record.data.aggregate_name, + balance: record.data.statement_balance_end_real, + balanceStr: formatMonetary(record.data.statement_balance_end_real, { + currencyId: record.data.currency_id[0], + }), + }); + } + } + return aggregates; + } + async onClickStatement(statementId) { + const action = await this.orm.call( + "account.bank.statement", + "action_open_statement", + [[statementId]], + { + context: this.props.context, + } + ); + const model = this.props.list.model; + this.action.doAction(action, { + async onClose() { + model.root.load(); + }, + }); + } +} + +ReconcileRenderer.components = { + ...KanbanRenderer.components, + KanbanRecord: ReconcileKanbanRecord, +}; +ReconcileRenderer.template = "account_reconcile_oca.ReconcileRenderer"; +ReconcileRenderer.props = [...KanbanRenderer.props, "selectedRecordId?"]; diff --git a/account_reconcile_oca/static/src/js/reconcile/reconcile_view.esm.js b/account_reconcile_oca/static/src/js/reconcile/reconcile_view.esm.js new file mode 100644 index 00000000..4bcb8ade --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile/reconcile_view.esm.js @@ -0,0 +1,16 @@ +/** @odoo-module */ + +import {ReconcileController} from "./reconcile_controller.esm.js"; +import {ReconcileRenderer} from "./reconcile_renderer.esm.js"; +import {kanbanView} from "@web/views/kanban/kanban_view"; +import {registry} from "@web/core/registry"; + +export const reconcileView = { + ...kanbanView, + Renderer: ReconcileRenderer, + Controller: ReconcileController, + buttonTemplate: "account_reconcile.ReconcileView.Buttons", + searchMenuTypes: ["filter"], +}; + +registry.category("views").add("reconcile", reconcileView); diff --git a/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_controller.esm.js b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_controller.esm.js new file mode 100644 index 00000000..d91b4bda --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_controller.esm.js @@ -0,0 +1,45 @@ +/** @odoo-module */ + +import {FormController} from "@web/views/form/form_controller"; +import {useService} from "@web/core/utils/hooks"; +import {useViewButtons} from "@web/views/view_button/view_button_hook"; +const {useRef} = owl; + +export class ReconcileFormController extends FormController { + setup() { + super.setup(...arguments); + this.env.exposeController(this); + this.orm = useService("orm"); + const rootRef = useRef("root"); + useViewButtons(this.model, rootRef, { + reload: this.reloadFormController.bind(this), + beforeExecuteAction: this.beforeExecuteActionButton.bind(this), + afterExecuteAction: this.afterExecuteActionButton.bind(this), + }); + } + displayName() { + return this.env.config.getDisplayName(); + } + async reloadFormController() { + var is_reconciled = this.model.root.data.is_reconciled; + await this.model.root.load(); + if (!is_reconciled && this.model.root.data.is_reconciled) { + // This only happens when we press the reconcile button + if (this.env.parentController) { + // Showing rainbow man + const message = await this.orm.call( + "account.journal", + "get_rainbowman_message", + [[this.model.root.data.journal_id[0]]] + ); + if (message) { + this.env.parentController.setRainbowMan(message); + } + // Refreshing + await this.env.parentController.model.root.load(); + await this.env.parentController.render(true); + this.env.parentController.selectRecord(); + } + } + } +} diff --git a/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_notebook.esm.js b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_notebook.esm.js new file mode 100644 index 00000000..1a89716f --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_notebook.esm.js @@ -0,0 +1,32 @@ +/** @odoo-module */ +import {Notebook} from "@web/core/notebook/notebook"; +import {onWillDestroy} from "@odoo/owl"; + +export class ReconcileFormNotebook extends Notebook { + setup() { + super.setup(...arguments); + const onPageNavigate = this.onPageNavigate.bind(this); + this.env.bus.addEventListener("RECONCILE_PAGE_NAVIGATE", onPageNavigate); + + onWillDestroy(() => { + this.env.bus.removeEventListener("RECONCILE_PAGE_NAVIGATE", onPageNavigate); + }); + } + onPageNavigate(ev) { + for (const page of this.pages) { + if ( + ev.detail.detail.name === page[1].name && + this.state.currentPage !== page[0] + ) { + ev.preventDefault(); + ev.detail.detail.originalEv.preventDefault(); + this.state.currentPage = page[0]; + return; + } + } + } +} + +ReconcileFormNotebook.props = { + ...Notebook.props, +}; diff --git a/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_renderer.esm.js b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_renderer.esm.js new file mode 100644 index 00000000..c0a0d138 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_renderer.esm.js @@ -0,0 +1,11 @@ +/** @odoo-module */ + +import {FormRenderer} from "@web/views/form/form_renderer"; +import {ReconcileFormNotebook} from "./reconcile_form_notebook.esm.js"; + +export class ReconcileFormRenderer extends FormRenderer {} + +ReconcileFormRenderer.components = { + ...ReconcileFormRenderer.components, + Notebook: ReconcileFormNotebook, +}; diff --git a/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_view.esm.js b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_view.esm.js new file mode 100644 index 00000000..3a2b0312 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_view.esm.js @@ -0,0 +1,14 @@ +/** @odoo-module */ + +import {ReconcileFormController} from "./reconcile_form_controller.esm.js"; +import {ReconcileFormRenderer} from "./reconcile_form_renderer.esm.js"; +import {formView} from "@web/views/form/form_view"; +import {registry} from "@web/core/registry"; + +export const ReconcileFormView = { + ...formView, + Controller: ReconcileFormController, + Renderer: ReconcileFormRenderer, +}; + +registry.category("views").add("reconcile_form", ReconcileFormView); diff --git a/account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_controller.esm.js b/account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_controller.esm.js new file mode 100644 index 00000000..f5feb11a --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_controller.esm.js @@ -0,0 +1,33 @@ +/** @odoo-module */ + +import {FormController} from "@web/views/form/form_controller"; +import {useViewButtons} from "@web/views/view_button/view_button_hook"; +const {useRef} = owl; + +export class ReconcileManualController extends FormController { + setup() { + super.setup(...arguments); + this.env.exposeController(this); + const rootRef = useRef("root"); + useViewButtons(this.model, rootRef, { + reload: this.reloadFormController.bind(this), + beforeExecuteAction: this.beforeExecuteActionButton.bind(this), + afterExecuteAction: this.afterExecuteActionButton.bind(this), + }); + } + displayName() { + return this.env.config.getDisplayName(); + } + async reloadFormController() { + try { + await this.model.root.load(); + } catch (error) { + // This should happen when we reconcile a line (no more possible data...) + if (this.env.parentController) { + await this.env.parentController.model.root.load(); + await this.env.parentController.render(true); + this.env.parentController.selectRecord(); + } + } + } +} diff --git a/account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_view.esm.js b/account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_view.esm.js new file mode 100644 index 00000000..36b974a2 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_view.esm.js @@ -0,0 +1,12 @@ +/** @odoo-module */ + +import {ReconcileManualController} from "./reconcile_manual_controller.esm.js"; +import {formView} from "@web/views/form/form_view"; +import {registry} from "@web/core/registry"; + +export const FormManualReconcileView = { + ...formView, + Controller: ReconcileManualController, +}; + +registry.category("views").add("reconcile_manual", FormManualReconcileView); diff --git a/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_controller.esm.js b/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_controller.esm.js new file mode 100644 index 00000000..af500eb9 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_controller.esm.js @@ -0,0 +1,18 @@ +/** @odoo-module */ + +import {ListController} from "@web/views/list/list_controller"; + +export class ReconcileMoveLineController extends ListController { + async openRecord(record) { + var data = {}; + data[this.props.parentField] = [record.resId, record.display_name]; + this.props.parentRecord.update(data); + } +} + +ReconcileMoveLineController.template = `account_reconcile_oca.ReconcileMoveLineController`; +ReconcileMoveLineController.props = { + ...ListController.props, + parentRecord: {type: Object, optional: true}, + parentField: {type: String, optional: true}, +}; diff --git a/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_renderer.esm.js b/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_renderer.esm.js new file mode 100644 index 00000000..682328b7 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_renderer.esm.js @@ -0,0 +1,22 @@ +/** @odoo-module */ + +import {ListRenderer} from "@web/views/list/list_renderer"; + +export class ReconcileMoveLineRenderer extends ListRenderer { + getRowClass(record) { + var classes = super.getRowClass(record); + if ( + this.props.parentRecord.data.reconcile_data_info.counterparts.includes( + record.resId + ) + ) { + classes += " o_field_account_reconcile_oca_move_line_selected table-info"; + } + return classes; + } +} +ReconcileMoveLineRenderer.props = [ + ...ListRenderer.props, + "parentRecord", + "parentField", +]; diff --git a/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_view.esm.js b/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_view.esm.js new file mode 100644 index 00000000..aebe7684 --- /dev/null +++ b/account_reconcile_oca/static/src/js/reconcile_move_line/reconcile_move_line_view.esm.js @@ -0,0 +1,15 @@ +/** @odoo-module */ + +import {ReconcileMoveLineController} from "./reconcile_move_line_controller.esm.js"; +import {ReconcileMoveLineRenderer} from "./reconcile_move_line_renderer.esm.js"; + +import {listView} from "@web/views/list/list_view"; +import {registry} from "@web/core/registry"; + +export const ReconcileMoveLineView = { + ...listView, + Controller: ReconcileMoveLineController, + Renderer: ReconcileMoveLineRenderer, +}; + +registry.category("views").add("reconcile_move_line", ReconcileMoveLineView); diff --git a/account_reconcile_oca/static/src/js/widgets/reconcile_chatter_field.esm.js b/account_reconcile_oca/static/src/js/widgets/reconcile_chatter_field.esm.js new file mode 100644 index 00000000..4f401d5c --- /dev/null +++ b/account_reconcile_oca/static/src/js/widgets/reconcile_chatter_field.esm.js @@ -0,0 +1,22 @@ +/** @odoo-module **/ + +// import {ChatterContainer} from "@mail/components/chatter_container/chatter_container"; +// import {Chatter} from "@mail/core/web/chatter"; +import {registry} from "@web/core/registry"; +import {standardFieldProps} from "@web/views/fields/standard_field_props"; +import {Chatter} from "@mail/core/web/chatter"; + +const {Component} = owl; + +export class AccountReconcileChatterWidget extends Component {} +AccountReconcileChatterWidget.props = {...standardFieldProps}; +AccountReconcileChatterWidget.template = + "account_reconcile_oca.AccountReconcileChatterWidget"; +AccountReconcileChatterWidget.components = {...Component.components, Chatter}; +export const AccountReconcileChatterWidgetField = { + component: AccountReconcileChatterWidget, + supportedTypes: [], +}; +registry + .category("fields") + .add("account_reconcile_oca_chatter", AccountReconcileChatterWidgetField); diff --git a/account_reconcile_oca/static/src/js/widgets/reconcile_data_widget.esm.js b/account_reconcile_oca/static/src/js/widgets/reconcile_data_widget.esm.js new file mode 100644 index 00000000..bc5cd475 --- /dev/null +++ b/account_reconcile_oca/static/src/js/widgets/reconcile_data_widget.esm.js @@ -0,0 +1,80 @@ +/** @odoo-module **/ +import {formatDate, parseDate} from "@web/core/l10n/dates"; +import {formatMonetary} from "@web/views/fields/formatters"; +import {registry} from "@web/core/registry"; + +const {Component} = owl; + +export class AccountReconcileDataWidget extends Component { + setup() { + super.setup(...arguments); + this.foreignCurrency = + this.props && + this.props.record && + (this.props.record.data.foreign_currency_id || + this.props.record.data.currency_id[0] !== + this.props.record.data.company_currency_id[0] || + this.props.record.data[this.props.name].data.some( + (item) => item.line_currency_id !== item.currency_id + )); + } + getReconcileLines() { + var data = this.props.record.data[this.props.name].data; + for (var line in data) { + data[line].amount_format = formatMonetary(data[line].amount, { + currencyId: data[line].currency_id, + }); + data[line].debit_format = formatMonetary(data[line].debit, { + currencyId: data[line].currency_id, + }); + data[line].credit_format = formatMonetary(data[line].credit, { + currencyId: data[line].currency_id, + }); + data[line].amount_currency_format = formatMonetary( + data[line].currency_amount, + { + currencyId: data[line].line_currency_id, + } + ); + if (data[line].original_amount) { + data[line].original_amount_format = formatMonetary( + data[line].original_amount, + { + currencyId: data[line].currency_id, + } + ); + } + data[line].date_format = formatDate( + parseDate(data[line].date, undefined, {isUTC: true}) + ); + } + return data; + } + onTrashLine(ev, line) { + this.props.record.update({ + manual_reference: line.reference, + manual_delete: true, + }); + } + selectReconcileLine(ev, line) { + this.props.record.update({ + manual_reference: line.reference, + }); + const triggerEv = new CustomEvent("reconcile-page-navigate", { + detail: { + name: "manual", + originalEv: ev, + }, + }); + this.env.bus.trigger("RECONCILE_PAGE_NAVIGATE", triggerEv); + } +} +AccountReconcileDataWidget.template = "account_reconcile_oca.ReconcileDataWidget"; + +export const AccountReconcileDataWidgetField = { + component: AccountReconcileDataWidget, + supportedTypes: [], +}; +registry + .category("fields") + .add("account_reconcile_oca_data", AccountReconcileDataWidgetField); diff --git a/account_reconcile_oca/static/src/js/widgets/reconcile_move_line_widget.esm.js b/account_reconcile_oca/static/src/js/widgets/reconcile_move_line_widget.esm.js new file mode 100644 index 00000000..05a62076 --- /dev/null +++ b/account_reconcile_oca/static/src/js/widgets/reconcile_move_line_widget.esm.js @@ -0,0 +1,107 @@ +/** @odoo-module **/ + +import {View} from "@web/views/view"; +import {evaluateBooleanExpr} from "@web/core/py_js/py"; +import {getFieldContext} from "@web/model/relational_model/utils"; +import {registry} from "@web/core/registry"; +import {standardFieldProps} from "@web/views/fields/standard_field_props"; + +const {Component, useSubEnv} = owl; + +export class AccountReconcileMatchWidget extends Component { + setup() { + // Necessary in order to avoid a loop + useSubEnv({ + config: {}, + parentController: this.env.parentController, + }); + } + + getDomain() { + let domain = this.props.domain; + if (typeof domain === "function") { + domain = domain(); + } + return domain; + } + get listViewProperties() { + return { + type: "list", + display: { + controlPanel: { + // Hiding the control panel buttons + "top-left": false, + "bottom-left": false, + layoutActions: false, + }, + }, + noBreadcrumbs: true, + resModel: this.props.record.fields[this.props.name].relation, + searchMenuTypes: ["filter"], + domain: this.getDomain(), + context: { + ...this.props.context, + ...getFieldContext(this.props.record, this.props.name), + }, + // Disables selector + allowSelectors: false, + // We need to force the search view in order to show the right one + searchViewId: false, + parentRecord: this.props.record, + parentField: this.props.name, + }; + } +} +AccountReconcileMatchWidget.props = { + ...standardFieldProps, + placeholder: {type: String, optional: true}, + canOpen: {type: Boolean, optional: true}, + canCreate: {type: Boolean, optional: true}, + canWrite: {type: Boolean, optional: true}, + canQuickCreate: {type: Boolean, optional: true}, + canCreateEdit: {type: Boolean, optional: true}, + context: {type: String, optional: true}, + domain: {type: [Array, Function], optional: true}, + nameCreateField: {type: String, optional: true}, + searchLimit: {type: Number, optional: true}, + relation: {type: String, optional: true}, + string: {type: String, optional: true}, + canScanBarcode: {type: Boolean, optional: true}, + update: {type: Function, optional: true}, + value: {optional: true}, + decorations: {type: Object, optional: true}, +}; +AccountReconcileMatchWidget.template = "account_reconcile_oca.ReconcileMatchWidget"; +AccountReconcileMatchWidget.components = { + ...AccountReconcileMatchWidget.components, + View, +}; + +export const AccountReconcileMatchWidgetField = { + component: AccountReconcileMatchWidget, + supportedTypes: [], + extractProps({attrs, context, decorations, options}, dynamicInfo) { + const hasCreatePermission = attrs.can_create + ? evaluateBooleanExpr(attrs.can_create) + : true; + const hasWritePermission = attrs.can_write + ? evaluateBooleanExpr(attrs.can_write) + : true; + const canCreate = options.no_create ? false : hasCreatePermission; + return { + placeholder: attrs.placeholder, + canOpen: !options.no_open, + canCreate, + canWrite: hasWritePermission, + canQuickCreate: canCreate && !options.no_quick_create, + canCreateEdit: canCreate && !options.no_create_edit, + context: context, + decorations, + domain: dynamicInfo.domain, + }; + }, +}; + +registry + .category("fields") + .add("account_reconcile_oca_match", AccountReconcileMatchWidgetField); diff --git a/account_reconcile_oca/static/src/js/widgets/selection_badge_uncheck.esm.js b/account_reconcile_oca/static/src/js/widgets/selection_badge_uncheck.esm.js new file mode 100644 index 00000000..4f27409b --- /dev/null +++ b/account_reconcile_oca/static/src/js/widgets/selection_badge_uncheck.esm.js @@ -0,0 +1,38 @@ +/** @odoo-module **/ +import { + BadgeSelectionField, + preloadSelection, +} from "@web/views/fields/badge_selection/badge_selection_field"; +import {registry} from "@web/core/registry"; +import {standardFieldProps} from "@web/views/fields/standard_field_props"; + +export class FieldSelectionBadgeUncheck extends BadgeSelectionField { + async onChange(value) { + var old_value = this.props.value; + if (this.props.type === "many2one") { + old_value = old_value[0]; + } + if (value === old_value) { + this.props.update(false); + return; + } + super.onChange(...arguments); + } +} + +FieldSelectionBadgeUncheck.props = {...standardFieldProps}; +FieldSelectionBadgeUncheck.supportedTypes = ["many2one", "selection"]; +FieldSelectionBadgeUncheck.additionalClasses = ["o_field_selection_badge"]; + +export const FieldSelectionBadgeUncheckField = { + component: FieldSelectionBadgeUncheck, + supportedTypes: ["many2one"], +}; +registry + .category("fields") + .add("selection_badge_uncheck", FieldSelectionBadgeUncheckField); + +registry.category("preloadedData").add("selection_badge_uncheck", { + loadOnTypes: ["many2one"], + preload: preloadSelection, +}); diff --git a/account_reconcile_oca/static/src/scss/reconcile.scss b/account_reconcile_oca/static/src/scss/reconcile.scss new file mode 100644 index 00000000..9a574985 --- /dev/null +++ b/account_reconcile_oca/static/src/scss/reconcile.scss @@ -0,0 +1,76 @@ +.o_account_reconcile_oca { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + height: 100%; + .o_kanban_renderer.o_kanban_ungrouped .o_kanban_record { + &:hover { + .o_reconcile_create_statement { + opacity: 100; + } + } + margin: 0 0 0; + min-width: fit-content; + width: 100%; + .o_reconcile_create_statement { + position: absolute; + height: 4px; + margin: 0; + padding: 2px 0 0 0; + border: 0; + top: -14px; + opacity: 0; + } + > div { + border-right: thick solid rgba(0, 0, 0, 0); + } + &.o_kanban_record_reconcile_oca_selected > div { + border-right: thick solid $o-brand-primary; + } + } + .o_account_reconcile_oca_selector { + width: 30%; + height: 100%; + padding: 0; + position: relative; + border-right: 1px solid $o-gray-300; + } + .o_account_reconcile_oca_info { + width: 70%; + height: 100%; + } + .o_form_view { + .o_form_statusbar.o_account_reconcile_oca_statusbar { + height: 40px; + } + .o_field_account_reconcile_oca_data { + .o_field_account_reconcile_oca_balance_float { + .o_field_account_reconcile_oca_balance_original_float { + text-decoration: line-through; + } + } + } + .o_field_widget.o_field_account_reconcile_oca_match { + display: inline; + } + .o_field_account_reconcile_oca_move_line_selected { + background-color: rgba($o-brand-primary, 0.2); + color: #000; + } + .o_reconcile_widget_table { + .o_reconcile_widget_line { + &.liquidity { + font-weight: bold; + } + &.selected { + background-color: rgba($o-brand-primary, 0.2); + } + } + } + } +} +.o_field_account_reconcile_oca_chatter { + width: 100%; +} diff --git a/account_reconcile_oca/static/src/xml/reconcile.xml b/account_reconcile_oca/static/src/xml/reconcile.xml new file mode 100644 index 00000000..5e8990d3 --- /dev/null +++ b/account_reconcile_oca/static/src/xml/reconcile.xml @@ -0,0 +1,192 @@ + + + + +
+ Global Balance + +
+ +
+ + + +
+ + + +
+
+
+ + + + + + props.selectedRecordId + +
+ + + + state.selectedRecordId + + + model.useSampleModel ? 'o_view_sample_data o_account_reconcile_oca' : 'o_account_reconcile_oca' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AccountPartnerDateLabel + Amount in currency + DebitCredit +
+ + + + + + +
+
+ + + + + + props.parentRecord + props.parentField + + +
diff --git a/account_reconcile_oca/tests/__init__.py b/account_reconcile_oca/tests/__init__.py new file mode 100644 index 00000000..17f193ed --- /dev/null +++ b/account_reconcile_oca/tests/__init__.py @@ -0,0 +1,2 @@ +from . import test_bank_account_reconcile +from . import test_account_reconcile diff --git a/account_reconcile_oca/tests/test_account_reconcile.py b/account_reconcile_oca/tests/test_account_reconcile.py new file mode 100644 index 00000000..114c7113 --- /dev/null +++ b/account_reconcile_oca/tests/test_account_reconcile.py @@ -0,0 +1,310 @@ +from odoo.tests import Form, tagged + +from odoo.addons.account_reconcile_model_oca.tests.common import ( + TestAccountReconciliationCommon, +) + + +@tagged("post_install", "-at_install") +class TestReconciliationWidget(TestAccountReconciliationCommon): + @classmethod + def _setup_context(cls): + return {**cls.env.context, "_test_account_reconcile_oca": True} + + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + cls.env = cls.env(context=cls._setup_context()) + cls.acc_bank_stmt_model = cls.env["account.bank.statement"] + cls.acc_bank_stmt_line_model = cls.env["account.bank.statement.line"] + cls.bank_journal_usd.suspense_account_id = ( + cls.env.company.account_journal_suspense_account_id + ) + cls.bank_journal_euro.suspense_account_id = ( + cls.env.company.account_journal_suspense_account_id + ) + cls.current_assets_account = ( + cls.env["account.account"] + .search( + [ + ("account_type", "=", "asset_current"), + ("company_id", "=", cls.env.company.id), + ], + limit=1, + ) + .copy() + ) + cls.current_assets_account.reconcile = True + cls.asset_receivable_account = ( + cls.env["account.account"] + .search( + [ + ("account_type", "=", "asset_receivable"), + ("company_id", "=", cls.env.company.id), + ], + limit=1, + ) + .copy() + ) + cls.asset_receivable_account.reconcile = True + cls.equity_account = ( + cls.env["account.account"] + .search( + [ + ("account_type", "=", "equity"), + ("company_id", "=", cls.env.company.id), + ], + limit=1, + ) + .copy() + ) + cls.non_current_assets_account = ( + cls.env["account.account"] + .search( + [ + ("account_type", "=", "asset_non_current"), + ("company_id", "=", cls.env.company.id), + ], + limit=1, + ) + .copy() + ) + cls.non_current_assets_account.reconcile = True + cls.move_1 = cls.env["account.move"].create( + { + "line_ids": [ + ( + 0, + 0, + { + "account_id": cls.current_assets_account.id, + "name": "DEMO", + "credit": 100, + }, + ), + ( + 0, + 0, + { + "account_id": cls.non_current_assets_account.id, + "name": "DEMO", + "debit": 100, + }, + ), + ] + } + ) + cls.move_1.action_post() + cls.move_2 = cls.env["account.move"].create( + { + "line_ids": [ + ( + 0, + 0, + { + "account_id": cls.non_current_assets_account.id, + "name": "DEMO", + "credit": 50, + }, + ), + ( + 0, + 0, + { + "account_id": cls.equity_account.id, + "name": "DEMO", + "debit": 50, + }, + ), + ] + } + ) + cls.move_2.action_post() + cls.move_3 = cls.env["account.move"].create( + { + "line_ids": [ + ( + 0, + 0, + { + "account_id": cls.non_current_assets_account.id, + "name": "DEMO", + "credit": 50, + }, + ), + ( + 0, + 0, + { + "account_id": cls.equity_account.id, + "name": "DEMO", + "debit": 50, + }, + ), + ] + } + ) + cls.move_3.action_post() + + def test_reconcile(self): + account = self.non_current_assets_account + reconcile_account = self.env["account.account.reconcile"].search( + [("account_id", "=", account.id)] + ) + self.assertTrue(reconcile_account) + with Form(reconcile_account) as f: + f.add_account_move_line_id = self.move_1.line_ids.filtered( + lambda r: r.account_id == account + ) + f.add_account_move_line_id = self.move_2.line_ids.filtered( + lambda r: r.account_id == account + ) + reconcile_account.reconcile() + reconcile_account = self.env["account.account.reconcile"].search( + [("account_id", "=", account.id)] + ) + self.assertTrue(reconcile_account) + with Form(reconcile_account) as f: + f.add_account_move_line_id = self.move_1.line_ids.filtered( + lambda r: r.account_id == account + ) + f.add_account_move_line_id = self.move_3.line_ids.filtered( + lambda r: r.account_id == account + ) + reconcile_account.reconcile() + reconcile_account = self.env["account.account.reconcile"].search( + [("account_id", "=", account.id)] + ) + self.assertFalse(reconcile_account) + + def test_clean_reconcile(self): + account = self.non_current_assets_account + reconcile_account = self.env["account.account.reconcile"].search( + [("account_id", "=", account.id)] + ) + self.assertTrue(reconcile_account) + with Form(reconcile_account) as f: + f.add_account_move_line_id = self.move_1.line_ids.filtered( + lambda r: r.account_id == account + ) + f.add_account_move_line_id = self.move_2.line_ids.filtered( + lambda r: r.account_id == account + ) + self.assertTrue(reconcile_account.reconcile_data_info.get("counterparts")) + reconcile_account.clean_reconcile() + self.assertFalse(reconcile_account.reconcile_data_info.get("counterparts")) + + def test_cannot_reconcile(self): + """ + There is not enough records to reconcile for this account + """ + reconcile_account = self.env["account.account.reconcile"].search( + [("account_id", "=", self.current_assets_account.id)] + ) + self.assertFalse(reconcile_account) + + def test_cannot_reconcile_different_partners(self): + """ + We can only reconcile lines with the same account and partner. + """ + reconcile_account = self.env["account.account.reconcile"].search( + [ + ("account_id", "=", self.asset_receivable_account.id), + ] + ) + self.assertFalse(reconcile_account) + move_1 = self.env["account.move"].create( + { + "line_ids": [ + ( + 0, + 0, + { + "account_id": self.current_assets_account.id, + "name": "DEMO", + "credit": 100, + }, + ), + ( + 0, + 0, + { + "account_id": self.asset_receivable_account.id, + "partner_id": self.env.user.partner_id.id, + "name": "DEMO", + "debit": 100, + }, + ), + ] + } + ) + move_1.action_post() + self.env.flush_all() + move_2 = self.env["account.move"].create( + { + "line_ids": [ + ( + 0, + 0, + { + "account_id": self.current_assets_account.id, + "name": "DEMO", + "debit": 100, + }, + ), + ( + 0, + 0, + { + "account_id": self.asset_receivable_account.id, + "partner_id": self.env.company.partner_id.id, + "name": "DEMO", + "credit": 100, + }, + ), + ] + } + ) + move_2.action_post() + self.env.flush_all() + reconcile_account = self.env["account.account.reconcile"].search( + [ + ("account_id", "=", self.asset_receivable_account.id), + ] + ) + self.assertFalse(reconcile_account) + + move_3 = self.env["account.move"].create( + { + "line_ids": [ + ( + 0, + 0, + { + "account_id": self.current_assets_account.id, + "name": "DEMO", + "debit": 100, + }, + ), + ( + 0, + 0, + { + "account_id": self.asset_receivable_account.id, + "partner_id": self.env.user.partner_id.id, + "name": "DEMO", + "credit": 100, + }, + ), + ] + } + ) + move_3.action_post() + self.env.flush_all() + reconcile_account = self.env["account.account.reconcile"].search( + [ + ("account_id", "=", self.asset_receivable_account.id), + ] + ) + self.assertTrue(reconcile_account) + self.assertEqual(reconcile_account.partner_id, self.env.user.partner_id) diff --git a/account_reconcile_oca/tests/test_bank_account_reconcile.py b/account_reconcile_oca/tests/test_bank_account_reconcile.py new file mode 100644 index 00000000..a94ba68b --- /dev/null +++ b/account_reconcile_oca/tests/test_bank_account_reconcile.py @@ -0,0 +1,1016 @@ +import time + +from odoo.exceptions import UserError +from odoo.tests import Form, tagged + +from odoo.addons.account_reconcile_model_oca.tests.common import ( + TestAccountReconciliationCommon, +) + + +@tagged("post_install", "-at_install") +class TestReconciliationWidget(TestAccountReconciliationCommon): + @classmethod + def _setup_context(cls): + return {**cls.env.context, "_test_account_reconcile_oca": True} + + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + cls.env = cls.env(context=cls._setup_context()) + + cls.acc_bank_stmt_model = cls.env["account.bank.statement"] + cls.acc_bank_stmt_line_model = cls.env["account.bank.statement.line"] + cls.bank_journal_usd.suspense_account_id = ( + cls.env.company.account_journal_suspense_account_id + ) + cls.bank_journal_euro.suspense_account_id = ( + cls.env.company.account_journal_suspense_account_id + ) + cls.current_assets_account = cls.env["account.account"].search( + [ + ("account_type", "=", "asset_current"), + ("company_id", "=", cls.env.company.id), + ], + limit=1, + ) + cls.current_assets_account.reconcile = True + + cls.rule = cls.env["account.reconcile.model"].create( + { + "name": "write-off model", + "rule_type": "writeoff_button", + "match_partner": True, + "match_partner_ids": [], + "line_ids": [(0, 0, {"account_id": cls.current_assets_account.id})], + } + ) + cls.tax_10 = cls.env["account.tax"].create( + { + "name": "tax_10", + "amount_type": "percent", + "amount": 10.0, + } + ) + # We need to make some fields visible in order to make the tests work + cls.env["ir.ui.view"].create( + { + "name": "DEMO Account bank statement", + "model": "account.bank.statement.line", + "inherit_id": cls.env.ref( + "account_reconcile_oca.bank_statement_line_form_reconcile_view" + ).id, + "arch": """ + + + 0 + + + 0 + + + 0 + + + """, + } + ) + + # Testing reconcile action + + def test_reconcile_invoice_currency(self): + inv1 = self.create_invoice(currency_id=self.currency_usd_id, invoice_amount=100) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 50, + "amount_currency": 100, + "foreign_currency_id": self.currency_usd_id, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(f.can_reconcile) + + def test_reconcile_invoice_reconcile_full(self): + """ + We want to test the reconcile widget for bank statements on invoices. + As we use edit mode by default, we will also check what happens when + we press unreconcile + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 50, + "date": time.strftime("%Y-07-15"), + } + ) + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable1 + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(f.can_reconcile) + f.manual_reference = "account.move.line;%s" % receivable1.id + self.assertEqual(-50, f.manual_amount) + self.assertEqual(2, len(bank_stmt_line.reconcile_data_info["data"])) + bank_stmt_line.button_manual_reference_full_paid() + self.assertEqual(3, len(bank_stmt_line.reconcile_data_info["data"])) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + f.manual_reference = "account.move.line;%s" % receivable1.id + self.assertEqual(-100, f.manual_amount) + + def test_reconcile_invoice_unreconcile(self): + """ + We want to test the reconcile widget for bank statements on invoices. + As we use edit mode by default, we will also check what happens when + we press unreconcile + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(f.can_reconcile) + self.assertFalse(bank_stmt_line.is_reconciled) + self.assertTrue( + bank_stmt_line.move_id.line_ids.filtered( + lambda r: r.account_id == self.bank_journal_euro.suspense_account_id + ) + ) + bank_stmt_line.reconcile_bank_line() + self.assertTrue(bank_stmt_line.is_reconciled) + self.assertFalse( + bank_stmt_line.move_id.line_ids.filtered( + lambda r: r.account_id == self.bank_journal_euro.suspense_account_id + ) + ) + bank_stmt_line.unreconcile_bank_line() + self.assertFalse(bank_stmt_line.is_reconciled) + self.assertTrue( + bank_stmt_line.move_id.line_ids.filtered( + lambda r: r.account_id == self.bank_journal_euro.suspense_account_id + ) + ) + + def test_reconcile_invoice_partial(self): + """ + We want to partially reconcile two invoices from a single payment. + As a result, both invoices must be partially reconciled + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + inv2 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + receivable2 = inv2.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable1 + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(f.can_reconcile) + f.manual_reference = "account.move.line;%s" % receivable1.id + self.assertEqual(f.manual_amount, -100) + f.manual_amount = -70 + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable2 + f.manual_reference = "account.move.line;%s" % receivable2.id + self.assertEqual(f.manual_amount, -30) + self.assertTrue(f.can_reconcile) + self.assertEqual(inv1.amount_residual_signed, 100) + self.assertEqual(inv2.amount_residual_signed, 100) + bank_stmt_line.reconcile_bank_line() + self.assertEqual(inv1.amount_residual_signed, 30) + self.assertEqual(inv2.amount_residual_signed, 70) + + def test_reconcile_invoice_partial_supplier(self): + """ + We want to partially reconcile two invoices from a single payment. + As a result, both invoices must be partially reconciled + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, + invoice_amount=100, + move_type="in_invoice", + ) + inv2 = self.create_invoice( + currency_id=self.currency_euro_id, + invoice_amount=100, + move_type="in_invoice", + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": -100, + "date": time.strftime("%Y-07-15"), + } + ) + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "liability_payable" + ) + receivable2 = inv2.line_ids.filtered( + lambda line: line.account_id.account_type == "liability_payable" + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable1 + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(f.can_reconcile) + f.manual_reference = "account.move.line;%s" % receivable1.id + self.assertEqual(f.manual_amount, 100) + f.manual_amount = 70 + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable2 + f.manual_reference = "account.move.line;%s" % receivable2.id + self.assertEqual(f.manual_amount, 30) + self.assertTrue(f.can_reconcile) + self.assertEqual(inv1.amount_residual_signed, -100) + self.assertEqual(inv2.amount_residual_signed, -100) + bank_stmt_line.reconcile_bank_line() + self.assertEqual(inv1.amount_residual_signed, -30) + self.assertEqual(inv2.amount_residual_signed, -70) + + def test_reconcile_model(self): + """ + We want to test what happens when we select an reconcile model to fill a + bank statement. + """ + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.manual_model_id = self.rule + self.assertTrue(f.can_reconcile) + bank_stmt_line.reconcile_bank_line() + self.assertEqual(2, len(bank_stmt_line.move_id.line_ids)) + self.assertTrue( + bank_stmt_line.move_id.line_ids.filtered( + lambda r: r.account_id == self.current_assets_account + ) + ) + + def test_reconcile_model_tax_included(self): + """ + We want to test what happens when we select an reconcile model to fill a + bank statement. + """ + self.rule.line_ids.write( + {"tax_ids": [(4, self.tax_10.id)], "force_tax_included": True} + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.manual_model_id = self.rule + self.assertTrue(f.can_reconcile) + bank_stmt_line.reconcile_bank_line() + self.assertEqual(3, len(bank_stmt_line.move_id.line_ids)) + self.assertTrue( + bank_stmt_line.move_id.line_ids.filtered( + lambda r: r.account_id == self.current_assets_account + and r.tax_ids == self.tax_10 + ) + ) + self.assertTrue( + bank_stmt_line.move_id.line_ids.filtered( + lambda r: r.tax_line_id == self.tax_10 + ) + ) + + def test_reconcile_invoice_model(self): + """ + We want to test what happens when we select a reconcile model to fill a + bank statement prefilled with an invoice. + + The result should be the reconcile of the invoice, and the rest set to the model + """ + + inv1 = self.create_invoice(currency_id=self.currency_euro_id) + + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable1 + self.assertFalse(f.can_reconcile) + f.manual_model_id = self.rule + self.assertTrue(f.can_reconcile) + bank_stmt_line.reconcile_bank_line() + self.assertNotEqual(self.current_assets_account, receivable1.account_id) + self.assertTrue( + bank_stmt_line.move_id.line_ids.filtered( + lambda r: r.account_id == self.current_assets_account + ) + ) + self.assertTrue( + bank_stmt_line.move_id.line_ids.filtered( + lambda r: r.account_id == receivable1.account_id + ) + ) + self.assertEqual(0, inv1.amount_residual) + + def test_reconcile_rule_on_create(self): + """ + Testing the fill of the bank statment line with + writeoff suggestion reconcile model with auto_reconcile + """ + self.env["account.reconcile.model"].create( + { + "name": "write-off model suggestion", + "rule_type": "writeoff_suggestion", + "match_label": "contains", + "match_label_param": "DEMO WRITEOFF", + "auto_reconcile": True, + "line_ids": [(0, 0, {"account_id": self.current_assets_account.id})], + } + ) + + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "DEMO WRITEOFF", + "payment_ref": "DEMO WRITEOFF", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + self.assertTrue(bank_stmt_line.is_reconciled) + + def test_reconcile_invoice_keep(self): + """ + We want to test how the keep mode works, keeping the original move lines. + However, the unreconcile will not work properly + """ + self.bank_journal_euro.reconcile_mode = "keep" + self.bank_journal_euro.suspense_account_id.reconcile = True + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable1 + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(bank_stmt_line.can_reconcile) + bank_stmt_line.reconcile_bank_line() + self.assertIn( + self.bank_journal_euro.suspense_account_id, + bank_stmt_line.mapped("move_id.line_ids.account_id"), + ) + with self.assertRaises(UserError): + bank_stmt_line.unreconcile_bank_line() + + # Testing to check functionality + + def test_reconcile_invoice_to_check_reconciled(self): + """ + We want to test the reconcile widget for bank statements on invoices. + As we use edit mode by default, we will also check what happens when + we press unreconcile + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable1 + self.assertTrue(f.can_reconcile) + self.assertFalse(bank_stmt_line.is_reconciled) + self.assertFalse(bank_stmt_line.to_check) + bank_stmt_line.action_to_check() + self.assertTrue(bank_stmt_line.is_reconciled) + self.assertTrue(bank_stmt_line.to_check) + bank_stmt_line.action_checked() + self.assertTrue(bank_stmt_line.is_reconciled) + self.assertFalse(bank_stmt_line.to_check) + + def test_reconcile_invoice_to_check_not_reconciled(self): + """ + We want to test the reconcile widget for bank statements on invoices. + As we use edit mode by default, we will also check what happens when + we press unreconcile + """ + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + self.assertFalse(bank_stmt_line.is_reconciled) + self.assertFalse(bank_stmt_line.to_check) + bank_stmt_line.action_to_check() + self.assertFalse(bank_stmt_line.is_reconciled) + self.assertTrue(bank_stmt_line.to_check) + bank_stmt_line.action_checked() + self.assertFalse(bank_stmt_line.is_reconciled) + self.assertFalse(bank_stmt_line.to_check) + + # Testing widget + + def test_widget_invoice_clean(self): + """ + We want to test how the clean works on an already defined bank statement + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable1 + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(bank_stmt_line.can_reconcile) + bank_stmt_line.clean_reconcile() + self.assertFalse(bank_stmt_line.can_reconcile) + + def test_widget_invoice_delete(self): + """ + We need to test the possibility to remove a line from the reconcile widget + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = receivable1 + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(f.can_reconcile) + f.manual_reference = "account.move.line;%s" % receivable1.id + self.assertEqual(f.manual_amount, -100) + f.manual_delete = True + self.assertFalse(f.can_reconcile) + + def test_widget_invoice_unselect(self): + """ + We want to test how selection and unselection of an account move lines is managed + by the system. + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(f.can_reconcile) + f.add_account_move_line_id = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + self.assertFalse(f.add_account_move_line_id) + self.assertFalse(f.can_reconcile) + + def test_widget_invoice_change_partner(self): + """ + We want to know how the change of partner of + a bank statement line is managed + """ + inv1 = self.create_invoice( + currency_id=self.currency_euro_id, invoice_amount=100 + ) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + liquidity_lines, suspense_lines, other_lines = bank_stmt_line._seek_for_lines() + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + self.assertFalse(f.partner_id) + f.manual_reference = "account.move.line;%s" % liquidity_lines.id + f.manual_partner_id = inv1.partner_id + self.assertEqual(f.partner_id, inv1.partner_id) + bank_stmt_line.clean_reconcile() + # As we have a set a partner, the cleaning should assign the invoice automatically + self.assertTrue(bank_stmt_line.can_reconcile) + + def test_widget_model_clean(self): + """ + We want to test what happens when we select an reconcile model to fill a + bank statement. + """ + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.manual_model_id = self.rule + self.assertTrue(f.can_reconcile) + # We need to check what happens when we uncheck it too + f.manual_model_id = self.env["account.reconcile.model"] + self.assertFalse(f.can_reconcile) + f.manual_model_id = self.rule + self.assertTrue(f.can_reconcile) + + # Testing actions + + def test_bank_statement_rainbowman(self): + message = self.bank_journal_euro.get_rainbowman_message() + self.assertTrue(message) + self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + self.env.flush_all() + message = self.bank_journal_euro.get_rainbowman_message() + self.assertFalse(message) + + def test_bank_statement_line_actions(self): + """ + Testing the actions of bank statement + """ + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + move_action = bank_stmt_line.action_show_move() + self.assertEqual( + bank_stmt_line.move_id, + self.env[move_action["res_model"]].browse(move_action["res_id"]), + ) + + # Testing filters + + def test_filter_partner(self): + """ + When a partner is set, the system might try to define an existent + invoice automatically + """ + inv1 = self.create_invoice(currency_id=self.currency_euro_id) + inv2 = self.create_invoice(currency_id=self.currency_euro_id) + partner = inv1.partner_id + + receivable1 = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + self.assertTrue(receivable1) + receivable2 = inv2.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + self.assertTrue(receivable2) + + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + + # Without a partner set, No default data + + bkstmt_data = bank_stmt_line.reconcile_data_info + mv_lines_ids = bkstmt_data["counterparts"] + self.assertNotIn(receivable1.id, mv_lines_ids) + self.assertNotIn(receivable2.id, mv_lines_ids) + + # This is like input a partner in the widget + + bank_stmt_line.partner_id = partner + bank_stmt_line.flush_recordset() + bank_stmt_line.invalidate_recordset() + bkstmt_data = bank_stmt_line.reconcile_data_info + mv_lines_ids = bkstmt_data["counterparts"] + + self.assertIn(receivable1.id, mv_lines_ids) + self.assertIn(receivable2.id, mv_lines_ids) + + # With a partner set, type the invoice reference in the filter + bank_stmt_line.payment_ref = inv1.payment_reference + bank_stmt_line.flush_recordset() + bank_stmt_line.invalidate_recordset() + bkstmt_data = bank_stmt_line.reconcile_data_info + mv_lines_ids = bkstmt_data["counterparts"] + + self.assertIn(receivable1.id, mv_lines_ids) + self.assertNotIn(receivable2.id, mv_lines_ids) + + def test_partner_name_with_parent(self): + parent_partner = self.env["res.partner"].create( + { + "name": "test", + } + ) + child_partner = self.env["res.partner"].create( + { + "name": "test", + "parent_id": parent_partner.id, + "type": "delivery", + } + ) + self.create_invoice_partner( + currency_id=self.currency_euro_id, partner_id=child_partner.id + ) + + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "statement_id": bank_stmt.id, + "journal_id": self.bank_journal_euro.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + "payment_ref": "test", + "partner_name": "test", + } + ) + + bkstmt_data = bank_stmt_line.reconcile_data_info + self.assertEqual(len(bkstmt_data["counterparts"]), 1) + self.assertEqual( + self.env["account.move.line"] + .browse(bkstmt_data["counterparts"]) + .partner_id, + parent_partner, + ) + + def test_journal_foreign_currency(self): + inv1 = self.create_invoice(currency_id=self.currency_usd_id, invoice_amount=100) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_usd.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_usd.id, + "statement_id": bank_stmt.id, + "amount": 100, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_account_move_line_id = inv1.line_ids.filtered( + lambda line: line.account_id.account_type == "asset_receivable" + ) + self.assertFalse(f.add_account_move_line_id) + self.assertTrue(f.can_reconcile) + self.assertTrue(bank_stmt_line.can_reconcile) + bank_stmt_line.reconcile_bank_line() + self.assertEqual(0, inv1.amount_residual) diff --git a/account_reconcile_oca/views/account_account.xml b/account_reconcile_oca/views/account_account.xml new file mode 100644 index 00000000..72bd824b --- /dev/null +++ b/account_reconcile_oca/views/account_account.xml @@ -0,0 +1,23 @@ + + + + + + account.account.tree (in account_reconcile_oca) + account.account + + + + . + + + + + + + + + + + + + + + + + Statement lines + account.bank.statement.line + [('journal_id', '=', active_id)] + + {'default_journal_id': active_id, 'search_default_not_reconciled': True, 'view_ref': 'account_reconcile_oca.bank_statement_line_form_reconcile_view'} + + kanban,tree + + +

+ Nothing to reconcile +

+
+
+ + Reconcile bank statement lines + account.bank.statement.line + [('journal_id', '=', active_id)] + {'default_journal_id': active_id, 'view_ref': 'account_reconcile_oca.bank_statement_line_form_reconcile_view'} + kanban,tree + + +

+ Nothing to reconcile +

+
+
+ + Reconcile bank statement lines + account.bank.statement.line + [('journal_id', '=', active_id)] + + {'default_journal_id': active_id, 'search_default_to_check': True, 'view_ref': 'account_reconcile_oca.bank_statement_line_form_reconcile_view'} + + kanban + + +

+ Nothing to check +

+
+
+ + + Reconcile bank statement lines + account.bank.statement.line + {'search_default_move_id': active_id} + kanban + + +

+ Nothing to reconcile +

+
+
+ + Add Bank Statement Line + account.bank.statement.line + form + + new + +
diff --git a/account_reconcile_oca/views/account_journal.xml b/account_reconcile_oca/views/account_journal.xml new file mode 100644 index 00000000..bbdd67e3 --- /dev/null +++ b/account_reconcile_oca/views/account_journal.xml @@ -0,0 +1,79 @@ + + + + + + account.journal.form.inherit + account.journal + + + + + + + + + + account.journal.kanban.inherit + account.journal + + + + + + + + + +
+ +
+ + + +
+
+
+
+ + + + +
+
+
diff --git a/account_reconcile_oca/views/account_move.xml b/account_reconcile_oca/views/account_move.xml new file mode 100644 index 00000000..c8de1da8 --- /dev/null +++ b/account_reconcile_oca/views/account_move.xml @@ -0,0 +1,26 @@ + + + + + + account.move.form (in account_reconcile_oca) + account.move + + +
+
+
+
+ + + +
diff --git a/account_reconcile_oca/views/account_move_line.xml b/account_reconcile_oca/views/account_move_line.xml new file mode 100644 index 00000000..9ad56ee7 --- /dev/null +++ b/account_reconcile_oca/views/account_move_line.xml @@ -0,0 +1,119 @@ + + + + + + account.move.line.tree.reconcile + account.move.line + 99 + + + + + + + + + + + + + + +