diff --git a/account_reconcile_oca/__manifest__.py b/account_reconcile_oca/__manifest__.py index 7402d4a1..69551d6e 100644 --- a/account_reconcile_oca/__manifest__.py +++ b/account_reconcile_oca/__manifest__.py @@ -27,17 +27,14 @@ "post_init_hook": "post_init_hook", "assets": { "web.assets_backend": [ - "account_reconcile_oca/static/src/js/reconcile_manual_view.esm.js", - "account_reconcile_oca/static/src/js/reconcile_data_widget.esm.js", - "account_reconcile_oca/static/src/js/reconcile_chatter_field.esm.js", - "account_reconcile_oca/static/src/js/selection_badge_uncheck.esm.js", - "account_reconcile_oca/static/src/js/reconcile_move_line_view.esm.js", - "account_reconcile_oca/static/src/js/reconcile_move_line_widget.esm.js", - "account_reconcile_oca/static/src/js/reconcile_kanban_record.esm.js", - "account_reconcile_oca/static/src/js/reconcile_renderer.esm.js", - "account_reconcile_oca/static/src/js/reconcile_controller.esm.js", - "account_reconcile_oca/static/src/js/reconcile_view.esm.js", - "account_reconcile_oca/static/src/js/reconcile_form_view.esm.js", + "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/models/account_account_reconcile.py b/account_reconcile_oca/models/account_account_reconcile.py index 6a33d786..991230c6 100644 --- a/account_reconcile_oca/models/account_account_reconcile.py +++ b/account_reconcile_oca/models/account_account_reconcile.py @@ -17,11 +17,11 @@ class AccountAccountReconcile(models.Model): reconcile_data_info = fields.Serialized(inverse="_inverse_reconcile_data_info") - partner_id = fields.Many2one("res.partner") - account_id = fields.Many2one("account.account") - name = fields.Char() - is_reconciled = fields.Boolean() - currency_id = fields.Many2one("res.currency") + 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) + currency_id = fields.Many2one("res.currency", readonly=True) @property def _table_query(self): diff --git a/account_reconcile_oca/models/account_bank_statement_line.py b/account_reconcile_oca/models/account_bank_statement_line.py index 617390ef..4fc7b683 100644 --- a/account_reconcile_oca/models/account_bank_statement_line.py +++ b/account_reconcile_oca/models/account_bank_statement_line.py @@ -40,12 +40,23 @@ class AccountBankStatementLine(models.Model): ) manual_partner_id = fields.Many2one( "res.partner", - domain=[('parent_id', '=', False)], + 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, @@ -54,13 +65,21 @@ class AccountBankStatementLine(models.Model): prefetch=False, domain=[("rule_type", "=", "writeoff_button")], ) - manual_delete = fields.Boolean( - store=False, - default=False, - prefetch=False, - ) manual_name = fields.Char(store=False, default=False, prefetch=False) manual_amount = fields.Monetary(store=False, default=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") def save(self): @@ -86,7 +105,8 @@ class AccountBankStatementLine(models.Model): data, self.manual_model_id, self.reconcile_data_info["reconcile_auxiliary_id"], - ) + ), + self.manual_reference ) else: # Refreshing data @@ -116,12 +136,14 @@ class AccountBankStatementLine(models.Model): ) ) self.reconcile_data_info = self._recompute_suspense_line( - new_data, self.reconcile_data_info["reconcile_auxiliary_id"] + new_data, + self.reconcile_data_info["reconcile_auxiliary_id"], + self.manual_reference, ) 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): + def _recompute_suspense_line(self, data, reconcile_auxiliary_id, manual_reference): can_reconcile = True total_amount = 0 new_data = [] @@ -175,6 +197,7 @@ class AccountBankStatementLine(models.Model): "counterparts": counterparts, "reconcile_auxiliary_id": reconcile_auxiliary_id, "can_reconcile": can_reconcile, + "manual_reference": manual_reference, } def _check_line_changed(self, line): @@ -208,7 +231,11 @@ class AccountBankStatementLine(models.Model): "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, + "analytic_distribution": False, } ) continue @@ -220,10 +247,17 @@ class AccountBankStatementLine(models.Model): 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"] + new_data, + self.reconcile_data_info["reconcile_auxiliary_id"], + self.manual_reference, ) self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) @@ -232,6 +266,7 @@ class AccountBankStatementLine(models.Model): "manual_partner_id", "manual_name", "manual_amount", + "analytic_distribution", ) def _onchange_manual_reconcile_vals(self): self.ensure_one() @@ -256,6 +291,7 @@ class AccountBankStatementLine(models.Model): "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", @@ -265,7 +301,9 @@ class AccountBankStatementLine(models.Model): 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"] + new_data, + self.reconcile_data_info["reconcile_auxiliary_id"], + self.manual_reference, ) self.can_reconcile = self.reconcile_data_info.get("can_reconcile", False) @@ -310,21 +348,26 @@ class AccountBankStatementLine(models.Model): for line in reconcile_model._apply_lines_for_bank_widget( -liquidity_amount, self._retrieve_partner(), self ): - amount = line["amount_currency"] - new_line = { - "reference": "reconcile_auxiliary;%s" % reconcile_auxiliary_id, - "id": False, - "amount": amount, - "debit": amount if amount > 0 else 0.0, - "credit": -amount if amount < 0 else 0.0, - "kind": "other", - "account_id": self.env["account.account"] - .browse(line["account_id"]) - .name_get()[0], - "date": fields.Date.to_string(self.date), - "name": line.get("name"), - "currency_id": line.get("currency_id"), - } + new_line = line.copy() + amount = line.get("amount_currency") + 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": self.env["account.account"] + .browse(line["account_id"]) + .name_get()[0], + "date": fields.Date.to_string(self.date), + } + ) reconcile_auxiliary_id += 1 if line.get("partner_id"): new_line["partner_id"] = ( @@ -377,7 +420,8 @@ class AccountBankStatementLine(models.Model): return self._recompute_suspense_line( *self._reconcile_data_by_model( data, res["model"], reconcile_auxiliary_id - ) + ), + self.manual_reference ) elif res and res.get("amls"): amount = self.amount @@ -387,10 +431,13 @@ class AccountBankStatementLine(models.Model): ) amount -= line_data.get("amount") data.append(line_data) - return self._recompute_suspense_line(data, reconcile_auxiliary_id) + return self._recompute_suspense_line( + data, reconcile_auxiliary_id, self.manual_reference + ) return self._recompute_suspense_line( data + [self._get_reconcile_line(line, "other") for line in other_lines], reconcile_auxiliary_id, + self.manual_reference, ) def clean_reconcile(self): @@ -414,7 +461,9 @@ class AccountBankStatementLine(models.Model): to_reconcile = [] with move._check_balanced(container): move.with_context( - skip_account_move_synchronization=True, force_delete=True + skip_account_move_synchronization=True, + force_delete=True, + skip_invoice_sync=True, ).write( { "line_ids": lines_to_remove, @@ -425,7 +474,11 @@ class AccountBankStatementLine(models.Model): continue line = ( self.env["account.move.line"] - .with_context(check_move_validity=False) + .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_id"): @@ -461,7 +514,11 @@ class AccountBankStatementLine(models.Model): ).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_invoice_sync=True) + .with_context( + check_move_validity=False, + skip_sync_invoice=True, + skip_invoice_sync=True, + ) .create(line_data) ) move.write( @@ -509,17 +566,7 @@ class AccountBankStatementLine(models.Model): ) def _unreconcile_bank_line_edit(self, data): - self.move_id.button_draft() - self.move_id.line_ids.unlink() - self.move_id.write( - { - "line_ids": [ - (0, 0, line_vals) - for line_vals in self._prepare_move_line_default_vals() - ] - } - ) - self.move_id.action_post() + self.action_undo_reconciliation() def _unreconcile_bank_line_keep(self, data): raise UserError(_("Keep suspense move lines mode cannot be unreconciled")) @@ -531,6 +578,13 @@ class AccountBankStatementLine(models.Model): "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 @@ -556,7 +610,8 @@ class AccountBankStatementLine(models.Model): data = record._recompute_suspense_line( *record._reconcile_data_by_model( data, res["model"], reconcile_auxiliary_id - ) + ), + self.manual_reference ) elif res.get("amls"): amount = self.amount @@ -566,10 +621,65 @@ class AccountBankStatementLine(models.Model): ) amount -= line_data.get("amount") data.append(line_data) - data = record._recompute_suspense_line(data, reconcile_auxiliary_id) + data = record._recompute_suspense_line( + data, reconcile_auxiliary_id, self.manual_reference + ) 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"], + } + ) + 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 + ) + 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 diff --git a/account_reconcile_oca/models/account_journal.py b/account_reconcile_oca/models/account_journal.py index 56e3bf34..780621a2 100644 --- a/account_reconcile_oca/models/account_journal.py +++ b/account_reconcile_oca/models/account_journal.py @@ -13,14 +13,6 @@ class AccountJournal(models.Model): required=True, ) - def action_open_reconcile_to_check(self): - self.ensure_one() - action = self.env["ir.actions.act_window"]._for_xml_id( - "account_reconcile_oca.action_bank_statement_line_reconcile" - ) - action["domain"] = [("id", "=", self.to_check_ids().ids)] - return action - def get_rainbowman_message(self): self.ensure_one() if self.get_journal_dashboard_datas()["number_to_reconcile"] > 0: diff --git a/account_reconcile_oca/models/account_reconcile_abstract.py b/account_reconcile_oca/models/account_reconcile_abstract.py index 659ae5c8..59fdc03f 100644 --- a/account_reconcile_oca/models/account_reconcile_abstract.py +++ b/account_reconcile_oca/models/account_reconcile_abstract.py @@ -53,12 +53,14 @@ class AccountReconcileAbstract(models.AbstractModel): "credit": -amount if amount < 0 else 0.0, "amount": amount, "currency_id": line.currency_id.id, + "analytic_distribution": line.analytic_distribution, "kind": kind, } 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_id"] = line.id return vals diff --git a/account_reconcile_oca/static/src/js/reconcile_controller.esm.js b/account_reconcile_oca/static/src/js/reconcile/reconcile_controller.esm.js similarity index 92% rename from account_reconcile_oca/static/src/js/reconcile_controller.esm.js rename to account_reconcile_oca/static/src/js/reconcile/reconcile_controller.esm.js index 90756cfc..801f233f 100644 --- a/account_reconcile_oca/static/src/js/reconcile_controller.esm.js +++ b/account_reconcile_oca/static/src/js/reconcile/reconcile_controller.esm.js @@ -17,6 +17,7 @@ export class ReconcileController extends KanbanController { this.effect = useService("effect"); this.orm = useService("orm"); this.action = useService("action"); + this.router = useService("router"); this.activeActions = this.props.archInfo.activeActions; this.model.addEventListener("update", () => this.selectRecord(), {once: true}); } @@ -55,7 +56,9 @@ export class ReconcileController extends KanbanController { } async selectRecord(record) { var resId = undefined; - if (record === undefined) { + 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 @@ -85,10 +88,14 @@ export class ReconcileController extends KanbanController { 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, diff --git a/account_reconcile_oca/static/src/js/reconcile_kanban_record.esm.js b/account_reconcile_oca/static/src/js/reconcile/reconcile_kanban_record.esm.js similarity index 100% rename from account_reconcile_oca/static/src/js/reconcile_kanban_record.esm.js rename to account_reconcile_oca/static/src/js/reconcile/reconcile_kanban_record.esm.js diff --git a/account_reconcile_oca/static/src/js/reconcile_renderer.esm.js b/account_reconcile_oca/static/src/js/reconcile/reconcile_renderer.esm.js similarity index 100% rename from account_reconcile_oca/static/src/js/reconcile_renderer.esm.js rename to account_reconcile_oca/static/src/js/reconcile/reconcile_renderer.esm.js diff --git a/account_reconcile_oca/static/src/js/reconcile_view.esm.js b/account_reconcile_oca/static/src/js/reconcile/reconcile_view.esm.js similarity index 100% rename from account_reconcile_oca/static/src/js/reconcile_view.esm.js rename to account_reconcile_oca/static/src/js/reconcile/reconcile_view.esm.js diff --git a/account_reconcile_oca/static/src/js/reconcile_form_view.esm.js b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_controller.esm.js similarity index 86% rename from account_reconcile_oca/static/src/js/reconcile_form_view.esm.js rename to account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_controller.esm.js index 7a49f3f9..571b4673 100644 --- a/account_reconcile_oca/static/src/js/reconcile_form_view.esm.js +++ b/account_reconcile_oca/static/src/js/reconcile_form/reconcile_form_controller.esm.js @@ -1,8 +1,6 @@ /** @odoo-module */ import {FormController} from "@web/views/form/form_controller"; -import {formView} from "@web/views/form/form_view"; -import {registry} from "@web/core/registry"; import {useService} from "@web/core/utils/hooks"; import {useViewButtons} from "@web/views/view_button/view_button_hook"; const {useRef} = owl; @@ -42,10 +40,3 @@ export class ReconcileFormController extends FormController { } } } - -export const ReconcileFormView = { - ...formView, - Controller: ReconcileFormController, -}; - -registry.category("views").add("reconcile_form", ReconcileFormView); 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_view.esm.js b/account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_controller.esm.js similarity index 74% rename from account_reconcile_oca/static/src/js/reconcile_manual_view.esm.js rename to account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_controller.esm.js index 99be2b66..ea49dbdb 100644 --- a/account_reconcile_oca/static/src/js/reconcile_manual_view.esm.js +++ b/account_reconcile_oca/static/src/js/reconcile_manual/reconcile_manual_controller.esm.js @@ -1,14 +1,13 @@ /** @odoo-module */ import {FormController} from "@web/views/form/form_controller"; -import {formView} from "@web/views/form/form_view"; -import {registry} from "@web/core/registry"; import {useViewButtons} from "@web/views/view_button/view_button_hook"; const {useRef} = owl; -export class FormManualReconcileController extends FormController { +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), @@ -29,10 +28,3 @@ export class FormManualReconcileController extends FormController { } } } - -export const FormManualReconcileView = { - ...formView, - Controller: FormManualReconcileController, -}; - -registry.category("views").add("reconcile_manual", FormManualReconcileView); 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..10958e49 --- /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"; + } + 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/reconcile_move_line_view.esm.js b/account_reconcile_oca/static/src/js/reconcile_move_line_view.esm.js deleted file mode 100644 index 158f8afa..00000000 --- a/account_reconcile_oca/static/src/js/reconcile_move_line_view.esm.js +++ /dev/null @@ -1,46 +0,0 @@ -/** @odoo-module */ - -import {ListController} from "@web/views/list/list_controller"; -import {ListRenderer} from "@web/views/list/list_renderer"; -import {listView} from "@web/views/list/list_view"; -import {registry} from "@web/core/registry"; - -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"; - } - return classes; - } -} -ReconcileMoveLineRenderer.props = [ - ...ListRenderer.props, - "parentRecord", - "parentField", -]; -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}, -}; -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/reconcile_chatter_field.esm.js b/account_reconcile_oca/static/src/js/widgets/reconcile_chatter_field.esm.js similarity index 100% rename from account_reconcile_oca/static/src/js/reconcile_chatter_field.esm.js rename to account_reconcile_oca/static/src/js/widgets/reconcile_chatter_field.esm.js index c9e6f4e0..e53a0b09 100644 --- a/account_reconcile_oca/static/src/js/reconcile_chatter_field.esm.js +++ b/account_reconcile_oca/static/src/js/widgets/reconcile_chatter_field.esm.js @@ -1,7 +1,7 @@ /** @odoo-module **/ -import {registry} from "@web/core/registry"; import {ChatterContainer} from "@mail/components/chatter_container/chatter_container"; +import {registry} from "@web/core/registry"; const {Component} = owl; diff --git a/account_reconcile_oca/static/src/js/reconcile_data_widget.esm.js b/account_reconcile_oca/static/src/js/widgets/reconcile_data_widget.esm.js similarity index 89% rename from account_reconcile_oca/static/src/js/reconcile_data_widget.esm.js rename to account_reconcile_oca/static/src/js/widgets/reconcile_data_widget.esm.js index 87f63fa7..177f51a3 100644 --- a/account_reconcile_oca/static/src/js/reconcile_data_widget.esm.js +++ b/account_reconcile_oca/static/src/js/widgets/reconcile_data_widget.esm.js @@ -1,8 +1,8 @@ /** @odoo-module **/ import fieldUtils from "web.field_utils"; -import session from "web.session"; import {registry} from "@web/core/registry"; +import session from "web.session"; const {Component} = owl; @@ -56,6 +56,13 @@ export class AccountReconcileDataWidget extends Component { 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"; diff --git a/account_reconcile_oca/static/src/js/reconcile_move_line_widget.esm.js b/account_reconcile_oca/static/src/js/widgets/reconcile_move_line_widget.esm.js similarity index 100% rename from account_reconcile_oca/static/src/js/reconcile_move_line_widget.esm.js rename to account_reconcile_oca/static/src/js/widgets/reconcile_move_line_widget.esm.js diff --git a/account_reconcile_oca/static/src/js/selection_badge_uncheck.esm.js b/account_reconcile_oca/static/src/js/widgets/selection_badge_uncheck.esm.js similarity index 100% rename from account_reconcile_oca/static/src/js/selection_badge_uncheck.esm.js rename to account_reconcile_oca/static/src/js/widgets/selection_badge_uncheck.esm.js diff --git a/account_reconcile_oca/static/src/scss/reconcile.scss b/account_reconcile_oca/static/src/scss/reconcile.scss index 840ceb23..bd33d4c2 100644 --- a/account_reconcile_oca/static/src/scss/reconcile.scss +++ b/account_reconcile_oca/static/src/scss/reconcile.scss @@ -63,6 +63,9 @@ &.liquidity { font-weight: bold; } + &.selected { + background-color: rgba($o-brand-primary, 0.2); + } } } } diff --git a/account_reconcile_oca/static/src/xml/reconcile.xml b/account_reconcile_oca/static/src/xml/reconcile.xml index 63801923..9da79bde 100644 --- a/account_reconcile_oca/static/src/xml/reconcile.xml +++ b/account_reconcile_oca/static/src/xml/reconcile.xml @@ -74,7 +74,7 @@ > diff --git a/account_reconcile_oca/tests/test_bank_account_reconcile.py b/account_reconcile_oca/tests/test_bank_account_reconcile.py index 7d124f2c..1ab30ded 100644 --- a/account_reconcile_oca/tests/test_bank_account_reconcile.py +++ b/account_reconcile_oca/tests/test_bank_account_reconcile.py @@ -64,6 +64,87 @@ class TestReconciliationWidget(TestAccountReconciliationCommon): # 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 l: l.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 l: l.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. @@ -348,6 +429,85 @@ class TestReconciliationWidget(TestAccountReconciliationCommon): 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 l: l.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): @@ -545,10 +705,6 @@ class TestReconciliationWidget(TestAccountReconciliationCommon): # Testing actions - def test_bank_statement_action_to_check(self): - action = self.bank_journal_euro.action_open_reconcile_to_check() - self.assertFalse(self.env[action["res_model"]].search(action["domain"])) - def test_bank_statement_rainbowman(self): message = self.bank_journal_euro.get_rainbowman_message() self.assertTrue(message) diff --git a/account_reconcile_oca/views/account_bank_statement_line.xml b/account_reconcile_oca/views/account_bank_statement_line.xml index e271609d..a1823623 100644 --- a/account_reconcile_oca/views/account_bank_statement_line.xml +++ b/account_reconcile_oca/views/account_bank_statement_line.xml @@ -11,6 +11,7 @@ +
+
+ To check +
@@ -135,7 +143,8 @@ . +
@@ -268,6 +330,28 @@

+ + 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'} + tree + + +

+ Nothing to check +

+
+
diff --git a/account_reconcile_oca/views/account_move_line.xml b/account_reconcile_oca/views/account_move_line.xml index 2d87c460..9f8c163d 100644 --- a/account_reconcile_oca/views/account_move_line.xml +++ b/account_reconcile_oca/views/account_move_line.xml @@ -41,7 +41,7 @@ - + + +