mirror of
https://github.com/bringout/oca-ocb-accounting.git
synced 2026-04-25 15:22:02 +02:00
account_reconcile_oca
This commit is contained in:
parent
64fdc5b0df
commit
a8804cdf59
95 changed files with 17541 additions and 0 deletions
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
|
|
@ -0,0 +1,467 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
|
||||
<title>README.rst</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
Despite the name, some widely supported CSS2 features are used.
|
||||
|
||||
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: gray; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic, pre.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
|
||||
</a>
|
||||
<div class="section" id="account-reconcile-oca">
|
||||
<h1>Account Reconcile OCA</h1>
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:f26494d38bbcd8158332ee518f6cf80c8a16f94c0043fc30645ea8f625ea1ce2
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/account-reconcile/tree/16.0/account_reconcile_oca"><img alt="OCA/account-reconcile" src="https://img.shields.io/badge/github-OCA%2Faccount--reconcile-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/account-reconcile-16-0/account-reconcile-16-0-account_reconcile_oca"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/account-reconcile&target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This addon allows to reconcile bank statements and account marked as <cite>reconcile</cite>.</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a><ul>
|
||||
<li><a class="reference internal" href="#bank-reconcile" id="toc-entry-2">Bank reconcile</a></li>
|
||||
<li><a class="reference internal" href="#account-reconcile" id="toc-entry-3">Account reconcile</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-4">Known issues / Roadmap</a></li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-5">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="toc-entry-6">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="toc-entry-7">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="toc-entry-8">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#other-credits" id="toc-entry-9">Other credits</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="toc-entry-10">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
|
||||
<div class="section" id="bank-reconcile">
|
||||
<h3><a class="toc-backref" href="#toc-entry-2">Bank reconcile</a></h3>
|
||||
<p>Access <cite>Invoicing / Dashboard</cite> with a user with Full Acounting capabilities.
|
||||
Select reconcile on the journal of your choice.</p>
|
||||
</div>
|
||||
<div class="section" id="account-reconcile">
|
||||
<h3><a class="toc-backref" href="#toc-entry-3">Account reconcile</a></h3>
|
||||
<p>Access <cite>Invoicing / Accounting / Actions / Reconcile</cite>
|
||||
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.</p>
|
||||
<p>Note : in case this module is installed on a migrated database, the reconciliation models will not be set by default. So they need to be set manually.</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="known-issues-roadmap">
|
||||
<h2><a class="toc-backref" href="#toc-entry-4">Known issues / Roadmap</a></h2>
|
||||
<p>The following bugs are already detected:</p>
|
||||
<ul class="simple">
|
||||
<li>Creation of activities on the chatter do show automatically</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h2><a class="toc-backref" href="#toc-entry-5">Bug Tracker</a></h2>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/account-reconcile/issues">GitHub Issues</a>.
|
||||
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
|
||||
<a class="reference external" href="https://github.com/OCA/account-reconcile/issues/new?body=module:%20account_reconcile_oca%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h2><a class="toc-backref" href="#toc-entry-6">Credits</a></h2>
|
||||
<div class="section" id="authors">
|
||||
<h3><a class="toc-backref" href="#toc-entry-7">Authors</a></h3>
|
||||
<ul class="simple">
|
||||
<li>CreuBlanca</li>
|
||||
<li>Dixmit</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h3><a class="toc-backref" href="#toc-entry-8">Contributors</a></h3>
|
||||
<ul class="simple">
|
||||
<li>Enric Tobella</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="other-credits">
|
||||
<h3><a class="toc-backref" href="#toc-entry-9">Other credits</a></h3>
|
||||
<p>The system has been improved to handle currency amounts more effectively with the financial support of Sygel Technology.</p>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h3><a class="toc-backref" href="#toc-entry-10">Maintainers</a></h3>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
|
||||
</a>
|
||||
<p>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.</p>
|
||||
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
|
||||
<p><a class="reference external image-reference" href="https://github.com/etobella"><img alt="etobella" src="https://github.com/etobella.png?size=40px" /></a></p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-reconcile/tree/16.0/account_reconcile_oca">OCA/account-reconcile</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 133 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
|
|
@ -0,0 +1,144 @@
|
|||
/** @odoo-module */
|
||||
const {onMounted, onWillStart, useState, useSubEnv} = owl;
|
||||
import {KanbanController} from "@web/views/kanban/kanban_controller";
|
||||
import {View} from "@web/views/view";
|
||||
import {formatMonetary} from "@web/views/fields/formatters";
|
||||
import {useService} from "@web/core/utils/hooks";
|
||||
|
||||
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;
|
||||
this.model.addEventListener("update", () => this.selectRecord(), {once: true});
|
||||
onWillStart(() => {
|
||||
this.updateJournalInfo();
|
||||
});
|
||||
onMounted(() => {
|
||||
this.selectRecord();
|
||||
});
|
||||
}
|
||||
get journalId() {
|
||||
if (this.props.context.active_model === "account.journal") {
|
||||
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();
|
||||
await this.updateJournalInfo();
|
||||
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 = 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
|
||||
);
|
||||
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 && 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 = {};
|
||||
|
|
@ -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?"];
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/** @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[aggregates.length - 1].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?"];
|
||||
|
|
@ -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);
|
||||
|
|
@ -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 (this.env.parentController) {
|
||||
// We will update the parent controller every time we reload the form.
|
||||
await this.env.parentController.model.root.load();
|
||||
await this.env.parentController.render(true);
|
||||
if (!is_reconciled && this.model.root.data.is_reconciled) {
|
||||
// This only happens when we press the reconcile button for 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
|
||||
this.env.parentController.selectRecord();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/** @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),
|
||||
});
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/** @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);
|
||||
}
|
||||
async clickAddAll() {
|
||||
await this.props.parentRecord.save();
|
||||
await this.orm.call(this.props.parentRecord.resModel, "add_multiple_lines", [
|
||||
this.props.parentRecord.resIds,
|
||||
this.model.root.domain,
|
||||
]);
|
||||
await this.props.parentRecord.load();
|
||||
this.props.parentRecord.model.notify();
|
||||
}
|
||||
}
|
||||
|
||||
ReconcileMoveLineController.template = `account_reconcile_oca.ReconcileMoveLineController`;
|
||||
ReconcileMoveLineController.props = {
|
||||
...ListController.props,
|
||||
parentRecord: {type: Object, optional: true},
|
||||
parentField: {type: String, optional: true},
|
||||
};
|
||||
|
|
@ -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",
|
||||
];
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/** @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,
|
||||
buttonTemplate: "reconcile_move_line.ListView.Buttons",
|
||||
};
|
||||
|
||||
registry.category("views").add("reconcile_move_line", ReconcileMoveLineView);
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {ChatterContainer} from "@mail/components/chatter_container/chatter_container";
|
||||
import {registry} from "@web/core/registry";
|
||||
|
||||
const {Component} = owl;
|
||||
|
||||
export class AccountReconcileChatterWidget extends Component {}
|
||||
AccountReconcileChatterWidget.template =
|
||||
"account_reconcile_oca.AccountReconcileChatterWidget";
|
||||
AccountReconcileChatterWidget.components = {...Component.components, ChatterContainer};
|
||||
|
||||
registry
|
||||
.category("fields")
|
||||
.add("account_reconcile_oca_chatter", AccountReconcileChatterWidget);
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import fieldUtils from "web.field_utils";
|
||||
import {float_is_zero} from "web.utils";
|
||||
import {registry} from "@web/core/registry";
|
||||
import session from "web.session";
|
||||
import {useService} from "@web/core/utils/hooks";
|
||||
|
||||
const {Component} = owl;
|
||||
|
||||
export class AccountReconcileDataWidget extends Component {
|
||||
setup() {
|
||||
super.setup(...arguments);
|
||||
this.orm = useService("orm");
|
||||
this.action = useService("action");
|
||||
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;
|
||||
const totals = {debit: 0, credit: 0};
|
||||
if (!data || !data.length) {
|
||||
return {lines: [], totals};
|
||||
}
|
||||
for (var line in data) {
|
||||
data[line].amount_format = fieldUtils.format.monetary(
|
||||
data[line].amount,
|
||||
undefined,
|
||||
{
|
||||
currency: session.get_currency(data[line].currency_id),
|
||||
}
|
||||
);
|
||||
data[line].debit_format = fieldUtils.format.monetary(
|
||||
data[line].debit,
|
||||
undefined,
|
||||
{
|
||||
currency: session.get_currency(data[line].currency_id),
|
||||
}
|
||||
);
|
||||
data[line].credit_format = fieldUtils.format.monetary(
|
||||
data[line].credit,
|
||||
undefined,
|
||||
{
|
||||
currency: session.get_currency(data[line].currency_id),
|
||||
}
|
||||
);
|
||||
data[line].amount_currency_format = fieldUtils.format.monetary(
|
||||
data[line].currency_amount,
|
||||
undefined,
|
||||
{
|
||||
currency: session.get_currency(data[line].line_currency_id),
|
||||
}
|
||||
);
|
||||
if (data[line].original_amount) {
|
||||
data[line].original_amount_format = fieldUtils.format.monetary(
|
||||
data[line].original_amount,
|
||||
{
|
||||
currency: session.get_currency(data[line].currency_id),
|
||||
}
|
||||
);
|
||||
}
|
||||
data[line].date_format = fieldUtils.format.date(
|
||||
fieldUtils.parse.date(data[line].date, undefined, {isUTC: true})
|
||||
);
|
||||
totals.debit += data[line].debit || 0;
|
||||
totals.credit += data[line].credit || 0;
|
||||
}
|
||||
totals.balance = totals.debit - totals.credit;
|
||||
const firstLine = Object.values(data)[0] || {};
|
||||
const currency = session.get_currency(firstLine.currency_id);
|
||||
const decimals = currency.digits[1];
|
||||
const hasOpenBalance = !float_is_zero(totals.balance, decimals);
|
||||
let openDebitFmt = null;
|
||||
let openCreditFmt = null;
|
||||
if (totals.balance < 0) {
|
||||
openDebitFmt = fieldUtils.format.monetary(Math.abs(totals.balance), {
|
||||
currency: currency,
|
||||
});
|
||||
} else {
|
||||
openCreditFmt = fieldUtils.format.monetary(totals.balance, {
|
||||
currency: currency,
|
||||
});
|
||||
}
|
||||
return {lines: data, hasOpenBalance, openDebitFmt, openCreditFmt};
|
||||
}
|
||||
onTrashLine(ev, line) {
|
||||
ev.stopPropagation();
|
||||
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);
|
||||
}
|
||||
async openMove(ev, moveId) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
console.log(moveId);
|
||||
const action = await this.orm.call("account.move", "get_formview_action", [
|
||||
[moveId],
|
||||
]);
|
||||
this.action.doAction(action);
|
||||
}
|
||||
}
|
||||
AccountReconcileDataWidget.template = "account_reconcile_oca.ReconcileDataWidget";
|
||||
|
||||
registry
|
||||
.category("fields")
|
||||
.add("account_reconcile_oca_data", AccountReconcileDataWidget);
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import {View} from "@web/views/view";
|
||||
import {registry} from "@web/core/registry";
|
||||
|
||||
const {Component, useSubEnv} = owl;
|
||||
|
||||
export class AccountReconcileMatchWidget extends Component {
|
||||
setup() {
|
||||
// Necessary in order to avoid a loop
|
||||
super.setup(...arguments);
|
||||
useSubEnv({
|
||||
config: {},
|
||||
parentController: this.env.parentController,
|
||||
});
|
||||
}
|
||||
get listViewProperties() {
|
||||
return {
|
||||
type: "list",
|
||||
display: {
|
||||
controlPanel: {
|
||||
// Hiding the control panel buttons
|
||||
"top-left": false,
|
||||
"bottom-left": true,
|
||||
},
|
||||
},
|
||||
resModel: this.props.record.fields[this.props.name].relation,
|
||||
searchMenuTypes: ["filter"],
|
||||
domain: this.props.record.getFieldDomain(this.props.name).toList(),
|
||||
context: {
|
||||
...this.props.record.getFieldContext(this.props.name),
|
||||
},
|
||||
// Disables de 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,
|
||||
showButtons: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
AccountReconcileMatchWidget.template = "account_reconcile_oca.ReconcileMatchWidget";
|
||||
|
||||
AccountReconcileMatchWidget.components = {
|
||||
...AccountReconcileMatchWidget.components,
|
||||
View,
|
||||
};
|
||||
|
||||
registry
|
||||
.category("fields")
|
||||
.add("account_reconcile_oca_match", AccountReconcileMatchWidget);
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/** @odoo-module **/
|
||||
import {
|
||||
BadgeSelectionField,
|
||||
preloadSelection,
|
||||
} from "@web/views/fields/badge_selection/badge_selection_field";
|
||||
import {registry} from "@web/core/registry";
|
||||
|
||||
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.supportedTypes = ["many2one", "selection"];
|
||||
FieldSelectionBadgeUncheck.additionalClasses = ["o_field_selection_badge"];
|
||||
registry.category("fields").add("selection_badge_uncheck", FieldSelectionBadgeUncheck);
|
||||
|
||||
registry.category("preloadedData").add("selection_badge_uncheck", {
|
||||
loadOnTypes: ["many2one"],
|
||||
preload: preloadSelection,
|
||||
});
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
.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;
|
||||
}
|
||||
}
|
||||
.row {
|
||||
// We need to add this in order to make remove horizontal scroll
|
||||
margin: 0;
|
||||
}
|
||||
margin: 0 0 0;
|
||||
min-width: fit-content;
|
||||
width: 100%;
|
||||
.o_reconcile_create_statement {
|
||||
position: absolute;
|
||||
height: 0px;
|
||||
margin: 0;
|
||||
padding: 0 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;
|
||||
overflow: auto;
|
||||
}
|
||||
.o_account_reconcile_oca_info {
|
||||
width: 70%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.o_form_view {
|
||||
.btn-info:not(.dropdown-toggle):not(.dropdown-item) {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.o_form_statusbar.o_account_reconcile_oca_statusbar {
|
||||
.btn:not(.dropdown-toggle):not(.dropdown-item) {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
height: 40px;
|
||||
> .o_statusbar_buttons {
|
||||
height: 100%;
|
||||
> .btn {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.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);
|
||||
}
|
||||
&.suspense {
|
||||
color: $o-gray-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.o_field_account_reconcile_oca_chatter {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t
|
||||
t-name="account_reconcile_oca.ReconcileRenderer"
|
||||
t-inherit="web.KanbanRenderer"
|
||||
t-inherit-mode="primary"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//t[@t-as='groupOrRecord']" position="before">
|
||||
<div class="m-2 d-flex w-100" t-if="env.parentController.journalId">
|
||||
<span
|
||||
class="flex-fill text-900 text-start ps-0 fw-bold fs-4 align-self-center"
|
||||
>Global Balance</span>
|
||||
<span
|
||||
class="pe-0 fw-bold fs-4 align-self-center"
|
||||
t-esc="env.parentController.journalBalanceStr"
|
||||
/>
|
||||
</div>
|
||||
<t t-set="aggregates" t-value="getAggregates()" />
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-else='']/KanbanRecord" position="before">
|
||||
<t
|
||||
t-if="aggregates.length and groupOrRecord.record.data.aggregate_id and aggregates[0].id == groupOrRecord.record.data.aggregate_id"
|
||||
>
|
||||
<t t-set="aggregate" t-value="aggregates.shift()" />
|
||||
<div class="m-2 d-flex w-100">
|
||||
<span
|
||||
class="flex-fill text-900 text-start ps-0 fw-bold fs-4 align-self-center"
|
||||
t-esc="aggregate.name"
|
||||
/>
|
||||
<span
|
||||
t-if="groupOrRecord.record.data.reconcile_aggregate == 'statement'"
|
||||
t-on-click="() => this.onClickStatement(aggregate.id)"
|
||||
class="pe-0 fw-bold fs-4 align-self-center btn btn-link"
|
||||
t-esc="aggregate.balanceStr"
|
||||
/>
|
||||
<!--
|
||||
<span
|
||||
t-if="groupOrRecord.record.data.reconcile_aggregate != 'statement'"
|
||||
class="pe-0 fw-bold fs-4 align-self-center text-link"
|
||||
t-esc="aggregate.balanceStr"
|
||||
/>-->
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
<xpath expr="div[hasclass('o_kanban_renderer')]" position="attributes">
|
||||
<attribute
|
||||
name="class"
|
||||
add="o_account_reconcile_oca_selector"
|
||||
separator=" "
|
||||
/>
|
||||
</xpath>
|
||||
<!-- Group by selector disabled on the view, so we need to find the one without group,
|
||||
then we pass to the component the selected record -->
|
||||
<xpath expr="//KanbanRecord[not(@group)]" position="attributes">
|
||||
<attribute name="selectedRecordId">props.selectedRecordId</attribute>
|
||||
</xpath>
|
||||
</t>
|
||||
<t
|
||||
t-name="account_reconcile_oca.ReconcileController"
|
||||
t-inherit="web.KanbanView"
|
||||
t-inherit-mode="primary"
|
||||
owl="1"
|
||||
>
|
||||
<!-- we pass to the component the selected record -->
|
||||
<xpath expr="//Layout/t[2]" position="attributes">
|
||||
<attribute name="selectedRecordId">state.selectedRecordId</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//Layout" position="attributes">
|
||||
<attribute
|
||||
name="className"
|
||||
>model.useSampleModel ? 'o_view_sample_data o_account_reconcile_oca' : 'o_account_reconcile_oca'</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//Layout" position="inside">
|
||||
<div class="o_account_reconcile_oca_info">
|
||||
<t t-if="state.selectedRecordId">
|
||||
<View t-props="viewReconcileInfo" t-key="state.selectedRecordId" />
|
||||
</t>
|
||||
</div>
|
||||
</xpath>
|
||||
</t>
|
||||
<t t-name="account_reconcile.ReconcileView.Buttons" owl="1">
|
||||
<button
|
||||
t-on-click="onClickNewButton"
|
||||
class="btn btn-primary"
|
||||
t-if="activeActions.create"
|
||||
>Create</button>
|
||||
</t>
|
||||
<t t-name="account_reconcile_oca.ReconcileMatchWidget" owl="1">
|
||||
<View t-props="listViewProperties" />
|
||||
</t>
|
||||
<t t-name="account_reconcile_oca.ReconcileDataWidget" owl="1">
|
||||
<table
|
||||
class="table table-sm position-relative mb-0 table-striped o_reconcile_widget_table"
|
||||
style="table-layout: auto"
|
||||
>
|
||||
<thead>
|
||||
<th>Account</th>
|
||||
<th>Partner</th>
|
||||
<th>Date</th>
|
||||
<th>Label</th>
|
||||
<th class="text-end" t-if="foreignCurrency">
|
||||
Amount in currency
|
||||
</th>
|
||||
<th class="text-end">Debit</th>
|
||||
<th class="text-end">Credit</th>
|
||||
<th t-if="! props.record.data.is_reconciled" />
|
||||
</thead>
|
||||
<t t-set="rec" t-value="getReconcileLines()" />
|
||||
<tbody>
|
||||
<t
|
||||
t-foreach="rec.lines"
|
||||
t-as="reconcile_line"
|
||||
t-key="reconcile_line_index"
|
||||
>
|
||||
<tr
|
||||
t-on-click="(ev) => this.selectReconcileLine(ev, reconcile_line)"
|
||||
t-att-class="'o_reconcile_widget_line ' + reconcile_line.kind + (props.record.data.manual_reference == reconcile_line.reference ? ' selected ' : ' ')"
|
||||
>
|
||||
<td>
|
||||
<div t-esc="reconcile_line.account_id[1]" />
|
||||
<div t-if="reconcile_line.move_id">
|
||||
<a
|
||||
t-att-href="'/web#id=' + reconcile_line.move_id + '&view_type=form&model=account.move'"
|
||||
class="o_form_uri"
|
||||
t-on-click="(ev) => this.openMove(ev, reconcile_line.move_id)"
|
||||
>
|
||||
<small t-esc="reconcile_line.move" />
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
t-esc="reconcile_line.partner_id[1]"
|
||||
t-if="reconcile_line.partner_id and reconcile_line.partner_id[1]"
|
||||
/>
|
||||
</td>
|
||||
<td t-esc="reconcile_line.date_format" />
|
||||
<td>
|
||||
<span
|
||||
t-esc="reconcile_line.name"
|
||||
t-if="reconcile_line.name"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
class="text-end o_field_account_reconcile_oca_balance_float"
|
||||
t-if="foreignCurrency"
|
||||
>
|
||||
<span t-esc="reconcile_line.amount_currency_format" />
|
||||
</td>
|
||||
<td
|
||||
class="text-end o_field_account_reconcile_oca_balance_float"
|
||||
>
|
||||
<div
|
||||
t-esc="reconcile_line.debit_format"
|
||||
t-if="reconcile_line.amount > 0"
|
||||
/>
|
||||
<div
|
||||
class="o_field_account_reconcile_oca_balance_original_float"
|
||||
t-esc="reconcile_line.original_amount_format"
|
||||
t-if="reconcile_line.amount > 0 and reconcile_line.original_amount"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
class="text-end o_field_account_reconcile_oca_balance_float"
|
||||
>
|
||||
<div
|
||||
t-esc="reconcile_line.credit_format"
|
||||
t-if="reconcile_line.amount < 0"
|
||||
/>
|
||||
<div
|
||||
class="o_field_account_reconcile_oca_balance_original_float"
|
||||
t-esc="reconcile_line.original_amount_format"
|
||||
t-if="reconcile_line.amount < 0 and reconcile_line.original_amount"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn fa fa-trash-o"
|
||||
role="button"
|
||||
t-on-click="(ev) => this.onTrashLine(ev, reconcile_line)"
|
||||
t-if="reconcile_line.kind == 'other' && ! props.record.data.is_reconciled"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
<tr class="text-muted" t-if="rec.hasOpenBalance">
|
||||
<td colspan="5">Open Balance</td>
|
||||
<td class="text-end" t-esc="rec.openDebitFmt" />
|
||||
<td class="text-end" t-esc="rec.openCreditFmt" />
|
||||
<td />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
<t t-name="account_reconcile_oca.AccountReconcileChatterWidget" owl="1">
|
||||
<ChatterContainer
|
||||
threadModel="this.props.record.fields[this.props.name].relation"
|
||||
threadId="this.props.value[0]"
|
||||
/>
|
||||
</t>
|
||||
<t
|
||||
t-name="account_reconcile_oca.ReconcileMoveLineController"
|
||||
t-inherit="web.ListView"
|
||||
t-inherit-mode="primary"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//t[@list='model.root']" position="attributes">
|
||||
<attribute name="parentRecord">props.parentRecord</attribute>
|
||||
<attribute name="parentField">props.parentField</attribute>
|
||||
</xpath>
|
||||
</t>
|
||||
<t
|
||||
t-name="reconcile_move_line.ListView.Buttons"
|
||||
t-inherit="web.ListView.Buttons"
|
||||
t-inherit-mode="primary"
|
||||
owl="1"
|
||||
>
|
||||
<xpath expr="//div[hasclass('o_list_buttons')]" position="inside">
|
||||
<button class="btn btn-primary" t-on-click="clickAddAll">Add all</button>
|
||||
</xpath>
|
||||
</t>
|
||||
</templates>
|
||||
Loading…
Add table
Add a link
Reference in a new issue