[IMP] account: account_payment_field wowl migration

Part-of: odoo/odoo#96672
This commit is contained in:
Habib (ayh)
2022-08-27 19:01:11 +02:00
parent 5a21823f43
commit b0ee5be676
6 changed files with 385 additions and 192 deletions
+1
View File
@@ -97,6 +97,7 @@ You could use this simplified accounting in case you work with an (external) acc
'account/static/src/scss/bills_upload.scss',
'account/static/src/scss/group_view_widget.scss',
'account/static/src/js/account_payment_field.js',
'account/static/src/js/legacy_account_payment_field.js',
'account/static/src/js/account_resequence_field.js',
'account/static/src/js/grouped_view_widget.js',
'account/static/src/js/mail_activity.js',
+2 -6
View File
@@ -1069,11 +1069,9 @@ class AccountMove(models.Model):
payments_widget_vals['content'].append({
'journal_name': line.ref or line.move_id.name,
'amount': amount,
'currency': move.currency_id.symbol,
'currency_id': move.currency_id.id,
'id': line.id,
'move_id': line.move_id.id,
'position': move.currency_id.position,
'digits': [69, move.currency_id.decimal_places],
'date': fields.Date.to_string(line.date),
'account_payment_id': line.payment_id.id,
})
@@ -1103,9 +1101,7 @@ class AccountMove(models.Model):
'name': counterpart_line.name,
'journal_name': counterpart_line.journal_id.name,
'amount': reconciled_partial['amount'],
'currency': reconciled_partial['currency'].symbol,
'digits': [69, reconciled_partial['currency'].decimal_places],
'position': reconciled_partial['currency'].position,
'currency_id': reconciled_partial['currency'].id,
'date': counterpart_line.date,
'partial_id': reconciled_partial['partial_id'],
'account_payment_id': counterpart_line.payment_id.id,
@@ -1,149 +1,93 @@
odoo.define('account.payment', function (require) {
"use strict";
/** @odoo-module **/
var AbstractField = require('web.AbstractField');
var core = require('web.core');
var field_registry = require('web.field_registry');
var field_utils = require('web.field_utils');
import { registry } from "@web/core/registry";
import { usePopover } from "@web/core/popover/popover_hook";
import { useService } from "@web/core/utils/hooks";
import { localization } from "@web/core/l10n/localization";
import { parseDate, formatDate } from "@web/core/l10n/dates";
var QWeb = core.qweb;
var _t = core._t;
import { formatMonetary } from "@web/views/fields/formatters";
var ShowPaymentLineWidget = AbstractField.extend({
events: _.extend({
'click .outstanding_credit_assign': '_onOutstandingCreditAssign',
'click .open_account_move': '_onOpenPaymentOrMove',
}, AbstractField.prototype.events),
supportedFieldTypes: ['char'],
const { Component, onWillUpdateProps } = owl;
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
class AccountPaymentPopOver extends Component {}
AccountPaymentPopOver.template = "account.AccountPaymentPopOver";
/**
* @override
* @returns {boolean}
*/
isSet: function() {
return true;
},
export class AccountPaymentField extends Component {
setup() {
this.popover = usePopover();
this.orm = useService("orm");
this.action = useService("action");
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
this.formatData(this.props);
onWillUpdateProps((nextProps) => this.formatData(nextProps));
}
/**
* @private
* @override
*/
_render: function() {
this.viewAlreadyOpened = false;
var self = this;
var info = this.value;
if (!info) {
this.$el.html('');
return;
}
_.each(info.content, function (k, v){
k.index = v;
k.amount = field_utils.format.float(k.amount, {digits: k.digits});
if (k.date){
k.date = field_utils.format.date(field_utils.parse.date(k.date, {}, {isUTC: true}));
formatData(props) {
const info = props.value || {
content: [],
outstanding: false,
title: "",
move_id: this.props.record.data.id,
};
for (let [key, value] of Object.entries(info.content)) {
value.index = key;
value.amount_formatted = formatMonetary(value.amount, { currencyId: value.currency_id });
if (value.date) {
// value.date is a string, parse to date and format to the users date format
value.date = formatDate(parseDate(value.date));
}
});
this.$el.html(QWeb.render('ShowPaymentInfo', {
lines: info.content,
outstanding: info.outstanding,
title: info.title
}));
_.each(this.$('.js_payment_info'), function (k, v){
var isRTL = _t.database.parameters.direction === "rtl";
var content = info.content[v];
var options = {
content: function () {
var $content = $(QWeb.render('PaymentPopOver', content));
$content.filter('.js_unreconcile_payment').on('click', self._onRemoveMoveReconcile.bind(self));
$content.filter('.js_open_payment').on('click', self._onOpenPaymentOrMove.bind(self));
return $content;
},
html: true,
placement: isRTL ? 'bottom' : 'left',
title: 'Payment Information',
trigger: 'focus',
delay: { "show": 0, "hide": 100 },
container: $(k).parent(), // FIXME Ugly, should use the default body container but system & tests to adapt to properly destroy the popover
};
$(k).popover(options);
});
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onOpenPaymentOrMove: function (event) {
var moveId = parseInt($(event.target).attr('move-id'));
if (!this.viewAlreadyOpened && moveId !== undefined && !isNaN(moveId)) {
this.viewAlreadyOpened = true;
var self = this;
this._rpc({
model: 'account.move',
method: 'open_move',
args: [moveId],
}).then(function (actionData) {
return self.do_action(actionData);
});
}
},
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onOutstandingCreditAssign: function (event) {
event.stopPropagation();
event.preventDefault();
var self = this;
var id = $(event.target).data('id') || false;
this._rpc({
model: 'account.move',
method: 'js_assign_outstanding_line',
args: [this.value.move_id, id],
}).then(function () {
self.trigger_up('reload');
});
},
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onRemoveMoveReconcile: function (event) {
var self = this;
var moveId = parseInt($(event.target).attr('move-id'));
var partialId = parseInt($(event.target).attr('partial-id'));
if (partialId !== undefined && !isNaN(partialId)){
this._rpc({
model: 'account.move',
method: 'js_remove_outstanding_partial',
args: [moveId, partialId],
}).then(function () {
self.trigger_up('reload');
});
this.lines = info.content;
this.outstanding = info.outstanding;
this.title = info.title;
this.move_id = info.move_id;
}
onInfoClick(ev, idx) {
if (this.popoverCloseFn) {
this.closePopover();
}
},
});
this.popoverCloseFn = this.popover.add(
ev.currentTarget,
AccountPaymentPopOver,
{
title: this.env._t("Journal Entry Info"),
...this.lines[idx],
_onRemoveMoveReconcile: this.removeMoveReconcile.bind(this),
_onOpenMove: this.openMove.bind(this),
onClose: this.closePopover,
},
{
position: localization.direction === "rtl" ? "bottom" : "left",
},
);
}
field_registry.add('payment', ShowPaymentLineWidget);
closePopover() {
this.popoverCloseFn();
this.popoverCloseFn = null;
}
return {
ShowPaymentLineWidget: ShowPaymentLineWidget
};
async assignOutstandingCredit(id) {
await this.orm.call(this.props.record.resModel, 'js_assign_outstanding_line', [this.move_id, id], {});
await this.props.record.model.root.load();
this.props.record.model.notify();
}
});
async removeMoveReconcile(moveId, partialId) {
this.closePopover();
await this.orm.call(this.props.record.resModel, 'js_remove_outstanding_partial', [moveId, partialId], {});
await this.props.record.model.root.load();
this.props.record.model.notify();
}
async openMove(moveId) {
const action = await this.orm.call(this.props.record.resModel, 'open_move', [moveId], {});
this.action.doAction(action);
}
}
AccountPaymentField.template = "account.AccountPaymentField";
AccountPaymentField.supportedTypes = ["char"];
registry.category("fields").add("payment", AccountPaymentField);
@@ -0,0 +1,149 @@
odoo.define('account.payment', function (require) {
"use strict";
var AbstractField = require('web.AbstractField');
var core = require('web.core');
var field_registry = require('web.field_registry');
var field_utils = require('web.field_utils');
var QWeb = core.qweb;
var _t = core._t;
var ShowPaymentLineWidget = AbstractField.extend({
events: _.extend({
'click .outstanding_credit_assign': '_onOutstandingCreditAssign',
'click .open_account_move': '_onOpenPaymentOrMove',
}, AbstractField.prototype.events),
supportedFieldTypes: ['char'],
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* @override
* @returns {boolean}
*/
isSet: function() {
return true;
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
* @override
*/
_render: function() {
this.viewAlreadyOpened = false;
var self = this;
var info = this.value;
if (!info) {
this.$el.html('');
return;
}
_.each(info.content, function (k, v){
k.index = v;
k.amount = field_utils.format.float(k.amount, {digits: k.digits});
if (k.date){
k.date = field_utils.format.date(field_utils.parse.date(k.date, {}, {isUTC: true}));
}
});
this.$el.html(QWeb.render('ShowPaymentInfo', {
lines: info.content,
outstanding: info.outstanding,
title: info.title
}));
_.each(this.$('.js_payment_info'), function (k, v){
var isRTL = _t.database.parameters.direction === "rtl";
var content = info.content[v];
var options = {
content: function () {
var $content = $(QWeb.render('PaymentPopOver', content));
$content.filter('.js_unreconcile_payment').on('click', self._onRemoveMoveReconcile.bind(self));
$content.filter('.js_open_payment').on('click', self._onOpenPaymentOrMove.bind(self));
return $content;
},
html: true,
placement: isRTL ? 'bottom' : 'left',
title: 'Payment Information',
trigger: 'focus',
delay: { "show": 0, "hide": 100 },
container: $(k).parent(), // FIXME Ugly, should use the default body container but system & tests to adapt to properly destroy the popover
};
$(k).popover(options);
});
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onOpenPaymentOrMove: function (event) {
var moveId = parseInt($(event.target).attr('move-id'));
if (!this.viewAlreadyOpened && moveId !== undefined && !isNaN(moveId)) {
this.viewAlreadyOpened = true;
var self = this;
this._rpc({
model: 'account.move',
method: 'open_move',
args: [moveId],
}).then(function (actionData) {
return self.do_action(actionData);
});
}
},
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onOutstandingCreditAssign: function (event) {
event.stopPropagation();
event.preventDefault();
var self = this;
var id = $(event.target).data('id') || false;
this._rpc({
model: 'account.move',
method: 'js_assign_outstanding_line',
args: [this.value.move_id, id],
}).then(function () {
self.trigger_up('reload');
});
},
/**
* @private
* @override
* @param {MouseEvent} event
*/
_onRemoveMoveReconcile: function (event) {
var self = this;
var moveId = parseInt($(event.target).attr('move-id'));
var partialId = parseInt($(event.target).attr('partial-id'));
if (partialId !== undefined && !isNaN(partialId)){
this._rpc({
model: 'account.move',
method: 'js_remove_outstanding_partial',
args: [moveId, partialId],
}).then(function () {
self.trigger_up('reload');
});
}
},
});
field_registry.add('payment', ShowPaymentLineWidget);
return {
ShowPaymentLineWidget: ShowPaymentLineWidget
};
});
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="ShowPaymentInfo">
<t t-name="account.AccountPaymentField" owl="1">
<div>
<t t-if="outstanding">
<div>
@@ -10,7 +10,7 @@
</div>
</t>
<table style="width:100%;">
<t t-foreach="lines" t-as="line">
<t t-foreach="lines" t-as="line" t-key="line_index">
<tr>
<t t-if="outstanding">
<td>
@@ -20,7 +20,8 @@
t-att-data-id="line.id"
style="margin-right: 0px; padding-left: 5px; padding-right: 5px;"
href="#"
data-bs-toggle="tooltip">Add</a>
data-bs-toggle="tooltip"
t-on-click.prevent="() => this.assignOutstandingCredit(line.id)">Add</a>
</td>
<td style="max-width: 11em;">
<a t-att-title="line.date"
@@ -35,7 +36,7 @@
</t>
<t t-if="!outstanding">
<td>
<a role="button" tabindex="0" class="js_payment_info fa fa-info-circle" t-att-index="line.index" style="margin-right:5px;" aria-label="Info" title="Journal Entry Info" data-bs-toggle="tooltip"></a>
<a role="button" tabindex="0" class="js_payment_info fa fa-info-circle" t-att-index="line_index" style="margin-right:5px;" aria-label="Info" title="Journal Entry Info" data-bs-toggle="tooltip" t-on-click.stop="(ev) => this.onInfoClick(ev, line_index)"></a>
</td>
<td t-if="!line.is_exchange">
<i class="o_field_widget text-start o_payment_label">Paid on <t t-esc="line.date"></t></i>
@@ -43,27 +44,15 @@
<td t-if="line.is_exchange" colspan="2">
<i class="o_field_widget text-start text-muted text-start">
<span class="oe_form_field oe_form_field_float oe_form_field_monetary fw-bold">
<t t-if="line.position === 'before'">
<t t-esc="line.currency"/>
</t>
<t t-esc="line.amount"/>
<t t-if="line.position === 'after'">
<t t-esc="line.currency"/>
</t>
<t t-esc="line.amount_formatted"/>
</span>
<span>Exchange Difference</span>
<span> Exchange Difference</span>
</i>
</td>
</t>
<td t-if="!line.is_exchange" style="text-align:right;">
<span class="oe_form_field oe_form_field_float oe_form_field_monetary" style="margin-left: -10px;">
<t t-if="line.position === 'before'">
<t t-esc="line.currency"/>
</t>
<t t-esc="line.amount"/>
<t t-if="line.position === 'after'">
<t t-esc="line.currency"/>
</t>
<t t-esc="line.amount_formatted"/>
</span>
</td>
</tr>
@@ -72,38 +61,43 @@
</div>
</t>
<t t-name="PaymentPopOver">
<div>
<table>
<tr>
<td><strong>Amount: </strong></td>
<td>
<t t-esc="amount_company_currency"></t>
<t t-if="amount_foreign_currency">
(<span class="fa fa-money"/> <t t-esc="amount_foreign_currency"/>)
</t>
</td>
</tr>
<tr>
<td><strong>Memo: </strong></td>
<td>
<div style="width: 200px; word-wrap: break-word">
<t t-esc="ref"/>
</div>
</td>
</tr>
<tr>
<td><strong>Date: </strong></td>
<td><t t-esc="date"/></td>
</tr>
<tr>
<td><strong>Journal: </strong></td>
<td><t t-esc="journal_name"/><span t-if="payment_method_name"> (<t t-esc="payment_method_name"/>)</span></td>
</tr>
</table>
<t t-name="account.AccountPaymentPopOver" owl="1">
<div class="account_payment_popover">
<h3 t-if="props.title" class="o_popover_header"><t t-esc="props.title"/></h3>
<div class="px-2">
<div>
<table>
<tr>
<td><strong>Amount: </strong></td>
<td>
<t t-esc="props.amount_company_currency"></t>
<t t-if="props.amount_foreign_currency">
(<span class="fa fa-money"/> <t t-esc="props.amount_foreign_currency"/>)
</t>
</td>
</tr>
<tr>
<td><strong>Memo: </strong></td>
<td>
<div style="width: 200px; word-wrap: break-word">
<t t-esc="props.ref"/>
</div>
</td>
</tr>
<tr>
<td><strong>Date: </strong></td>
<td><t t-esc="props.date"/></td>
</tr>
<tr>
<td><strong>Journal: </strong></td>
<td><t t-esc="props.journal_name"/><span t-if="props.payment_method_name"> (<t t-esc="props.payment_method_name"/>)</span></td>
</tr>
</table>
</div>
<button class="btn btn-sm btn-primary js_unreconcile_payment float-start" t-if="!props.is_exchange" style="margin-top:5px; margin-bottom:5px;" groups="account.group_account_invoice" t-on-click="() => props._onRemoveMoveReconcile(props.move_id, props.partial_id)">Unreconcile</button>
<button class="btn btn-sm btn-secondary js_open_payment float-end" style="margin-top:5px; margin-bottom:5px;" t-on-click="() => props._onOpenMove(props.move_id)">View</button>
</div>
</div>
<button class="btn btn-sm btn-primary js_unreconcile_payment float-start" t-if="!is_exchange" t-att-partial-id="partial_id" t-att-payment-id="payment_id" t-att-move-id="move_id" style="margin-top:5px; margin-bottom:5px;" groups="account.group_account_invoice">Unreconcile</button>
<button class="btn btn-sm btn-secondary js_open_payment float-end" t-att-move-id="move_id" style="margin-top:5px; margin-bottom:5px;">View</button>
</t>
</templates>
@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="ShowPaymentInfo">
<div>
<t t-if="outstanding">
<div>
<strong class="float-start" id="outstanding" t-esc="title"/>
</div>
</t>
<table style="width:100%;">
<t t-foreach="lines" t-as="line">
<tr>
<t t-if="outstanding">
<td>
<a title="assign to invoice"
role="button"
class="oe_form_field btn btn-secondary outstanding_credit_assign"
t-att-data-id="line.id"
style="margin-right: 0px; padding-left: 5px; padding-right: 5px;"
href="#"
data-bs-toggle="tooltip">Add</a>
</td>
<td style="max-width: 11em;">
<a t-att-title="line.date"
role="button"
class="oe_form_field btn btn-link open_account_move"
t-att-move-id="line.move_id"
style="margin-right: 5px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; padding-left: 0px; width:100%; text-align:left;"
data-bs-toggle="tooltip"
t-att-payment-id="account_payment_id"
t-esc="line.journal_name"/>
</td>
</t>
<t t-if="!outstanding">
<td>
<a role="button" tabindex="0" class="js_payment_info fa fa-info-circle" t-att-index="line.index" style="margin-right:5px;" aria-label="Info" title="Journal Entry Info" data-bs-toggle="tooltip"></a>
</td>
<td t-if="!line.is_exchange">
<i class="o_field_widget text-start o_payment_label">Paid on <t t-esc="line.date"></t></i>
</td>
<td t-if="line.is_exchange" colspan="2">
<i class="o_field_widget text-start text-muted text-start">
<span class="oe_form_field oe_form_field_float oe_form_field_monetary fw-bold">
<t t-if="line.position === 'before'">
<t t-esc="line.currency"/>
</t>
<t t-esc="line.amount"/>
<t t-if="line.position === 'after'">
<t t-esc="line.currency"/>
</t>
</span>
<span>Exchange Difference</span>
</i>
</td>
</t>
<td t-if="!line.is_exchange" style="text-align:right;">
<span class="oe_form_field oe_form_field_float oe_form_field_monetary" style="margin-left: -10px;">
<t t-if="line.position === 'before'">
<t t-esc="line.currency"/>
</t>
<t t-esc="line.amount"/>
<t t-if="line.position === 'after'">
<t t-esc="line.currency"/>
</t>
</span>
</td>
</tr>
</t>
</table>
</div>
</t>
<t t-name="PaymentPopOver">
<div>
<table>
<tr>
<td><strong>Amount: </strong></td>
<td>
<t t-esc="amount_company_currency"></t>
<t t-if="amount_foreign_currency">
(<span class="fa fa-money"/> <t t-esc="amount_foreign_currency"/>)
</t>
</td>
</tr>
<tr>
<td><strong>Memo: </strong></td>
<td>
<div style="width: 200px; word-wrap: break-word">
<t t-esc="ref"/>
</div>
</td>
</tr>
<tr>
<td><strong>Date: </strong></td>
<td><t t-esc="date"/></td>
</tr>
<tr>
<td><strong>Journal: </strong></td>
<td><t t-esc="journal_name"/><span t-if="payment_method_name"> (<t t-esc="payment_method_name"/>)</span></td>
</tr>
</table>
</div>
<button class="btn btn-sm btn-primary js_unreconcile_payment float-start" t-if="!is_exchange" t-att-partial-id="partial_id" t-att-payment-id="payment_id" t-att-move-id="move_id" style="margin-top:5px; margin-bottom:5px;" groups="account.group_account_invoice">Unreconcile</button>
<button class="btn btn-sm btn-secondary js_open_payment float-end" t-att-move-id="move_id" style="margin-top:5px; margin-bottom:5px;">View</button>
</t>
</templates>