[IMP] account: improve invoice UX and bank addition
When using the wizard to add a bank account, it should be added to an existing journal only if the journal has no bank account set and no journal entries. We also want to be able to remove a set bank account. When using the wizard to add a bank account (Create it button ; not Connect button), it should be added to an existing journal only if the journal has no bank account set and no journal entries. We remove an unwanted constraint on the bank journals that prevented the removal of an Account Number (IBAN). Some UX changes. In the Journal Items list view, specific views open depending on their move type. This commit also changes the "View" button of the invoice payment widget on the Journal Entry's form view in order to align behaviours. The core open_move method is also moved from the account move line model to the account move's one for more flexibility. The "1 Statement" button of the payment's form view now links to the new reconciliation widget. The Journal Items lists accessed from the Journal report now show the partner by default. The "Unreconciled" filter now filter out partial reconciliations which have a residual amount != 0. The Partner column should almost always be shown by default in a Journal Items list view. task-2893208 closes odoo/odoo#94923 Related: odoo/enterprise#29092 Signed-off-by: Florian Gilbert (flg) <flg@odoo.com>
This commit is contained in:
@@ -538,9 +538,7 @@ class AccountJournal(models.Model):
|
||||
if journal.bank_account_id:
|
||||
journal.bank_account_id.currency_id = vals['currency_id']
|
||||
if 'bank_account_id' in vals:
|
||||
if not vals.get('bank_account_id'):
|
||||
raise UserError(_('You cannot remove the bank account from the journal once set.'))
|
||||
else:
|
||||
if vals.get('bank_account_id'):
|
||||
bank_account = self.env['res.partner.bank'].browse(vals['bank_account_id'])
|
||||
if bank_account.partner_id != company.partner_id:
|
||||
raise UserError(_("The partners of the journal's company and the related bank account mismatch."))
|
||||
|
||||
@@ -1818,7 +1818,6 @@ class AccountMove(models.Model):
|
||||
'digits': [69, reconciled_partial['currency'].decimal_places],
|
||||
'position': reconciled_partial['currency'].position,
|
||||
'date': counterpart_line.date,
|
||||
'payment_id': counterpart_line.id,
|
||||
'partial_id': reconciled_partial['partial_id'],
|
||||
'account_payment_id': counterpart_line.payment_id.id,
|
||||
'payment_method_name': counterpart_line.payment_id.payment_method_line_id.name,
|
||||
@@ -2946,6 +2945,18 @@ class AccountMove(models.Model):
|
||||
'views': [(self.env.ref('account.view_move_tree').id, 'tree'), (False, 'form')],
|
||||
}
|
||||
|
||||
def open_move(self):
|
||||
if self.payment_id:
|
||||
return self.open_payment_view()
|
||||
else:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'account.move',
|
||||
'view_mode': 'form',
|
||||
'res_id': self.id,
|
||||
'views': [(False, 'form')],
|
||||
}
|
||||
|
||||
def post(self):
|
||||
warnings.warn(
|
||||
"RedirectWarning method 'post()' is a deprecated alias to 'action_post()' or _post()",
|
||||
@@ -6068,23 +6079,7 @@ class AccountMoveLine(models.Model):
|
||||
return action
|
||||
|
||||
def open_move(self):
|
||||
if self.payment_id:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'account.payment',
|
||||
'view_mode': 'form',
|
||||
'res_id': self.payment_id.id,
|
||||
'views': [(False, 'form')],
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'account.move',
|
||||
'view_mode': 'form',
|
||||
'res_id': self.move_id.id,
|
||||
'views': [(False, 'form')],
|
||||
}
|
||||
|
||||
return self.move_id.open_move()
|
||||
|
||||
def action_automatic_entry(self):
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('account.account_automatic_entry_wizard_action')
|
||||
|
||||
@@ -88,28 +88,16 @@ var ShowPaymentLineWidget = AbstractField.extend({
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onOpenPaymentOrMove: function (event) {
|
||||
var paymentId = parseInt($(event.target).attr('payment-id'));
|
||||
var moveId = parseInt($(event.target).attr('move-id'));
|
||||
var resModel;
|
||||
var id;
|
||||
if (paymentId !== undefined && !isNaN(paymentId)){
|
||||
resModel = "account.payment";
|
||||
id = paymentId;
|
||||
} else if (moveId !== undefined && !isNaN(moveId)){
|
||||
resModel = "account.move";
|
||||
id = moveId;
|
||||
}
|
||||
//Open form view of account.move with id = move_id
|
||||
//viewAlreadyopened is a flag to prevent the user from clicking on another account.move/account.payment
|
||||
//while the first one he clicked on is loading
|
||||
if (!this.viewAlreadyOpened && resModel && id) {
|
||||
if (!this.viewAlreadyOpened && moveId !== undefined && !isNaN(moveId)) {
|
||||
this.viewAlreadyOpened = true;
|
||||
this.do_action({
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: resModel,
|
||||
res_id: id,
|
||||
views: [[false, 'form']],
|
||||
target: 'current'
|
||||
var self = this;
|
||||
this._rpc({
|
||||
model: 'account.move',
|
||||
method: 'open_move',
|
||||
args: [moveId],
|
||||
}).then(function (actionData) {
|
||||
return self.do_action(actionData);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
</table>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary js_unreconcile_payment float-start" 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-payment-id="account_payment_id" t-att-move-id="move_id" style="margin-top:5px; margin-bottom:5px;">View</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>
|
||||
|
||||
@@ -25,7 +25,7 @@ QUnit.module('account', {
|
||||
}, function () {
|
||||
QUnit.module('Reconciliation');
|
||||
|
||||
QUnit.test('Reconciliation form field', async function (assert) {
|
||||
QUnit.test('Reconciliation form field [REQUIRES FOCUS]', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var form = await createView({
|
||||
@@ -46,37 +46,31 @@ QUnit.module('account', {
|
||||
assert.deepEqual(args.args, [4, 20], "should call js_assign_outstanding_line {warning: required focus}");
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (args.method === 'open_move') {
|
||||
assert.deepEqual(args.args, [10], "should call open_move {warning: required focus}");
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
intercepts: {
|
||||
do_action: function (event) {
|
||||
assert.deepEqual(event.data.action, {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'account.move',
|
||||
'res_id': 10,
|
||||
'views': [[false, 'form']],
|
||||
'target': 'current'
|
||||
},
|
||||
"should open the form view");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(form.$('.o_field_widget[name="payments_widget"]').text().replace(/[\s\n\r]+/g, ' '),
|
||||
" Paid on 04/25/2017 $ 555.00 ",
|
||||
"should display payment information");
|
||||
|
||||
form.$('.o_field_widget[name="outstanding_credits_debits_widget"] .outstanding_credit_assign').trigger('click');
|
||||
await testUtils.dom.click(form.$('.o_field_widget[name="outstanding_credits_debits_widget"] .outstanding_credit_assign'));
|
||||
|
||||
assert.strictEqual(form.$('.o_field_widget[name="outstanding_credits_debits_widget"]').text().replace(/[\s\n\r]+/g, ' '),
|
||||
" Outstanding credits Add INV/2017/0004 $ 100.00 ",
|
||||
"should display outstanding information");
|
||||
|
||||
form.$('.o_field_widget[name="payments_widget"] .js_payment_info').trigger('focus');
|
||||
form.$('.popover .js_open_payment').trigger('click');
|
||||
form.$('.o_field_widget[name="payments_widget"] .js_payment_info').focus();
|
||||
await testUtils.nextTick();
|
||||
await testUtils.dom.click(form.$('.popover .js_open_payment'));
|
||||
|
||||
form.$('.o_field_widget[name="payments_widget"] .js_payment_info').trigger('focus');
|
||||
form.$('.popover .js_unreconcile_payment').trigger('click');
|
||||
form.$('.o_field_widget[name="payments_widget"] .js_payment_info').focus();
|
||||
await testUtils.nextTick();
|
||||
await testUtils.dom.click(form.$('.popover .js_unreconcile_payment'));
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
@@ -166,9 +166,9 @@
|
||||
<field name="date" readonly="1"/>
|
||||
<field name="company_id" groups="base.group_multi_company" optional="hide"/>
|
||||
<field name="journal_id" options='{"no_open":True}' optional="hide"/>
|
||||
<field name="move_name" string="Journal Entry" optional="show" widget="open_move_widget"/>
|
||||
<field name="move_name" string="Journal Entry" widget="open_move_widget"/>
|
||||
<field name="account_id" options="{'no_open': True, 'no_create': True}" domain="[('company_id', '=', company_id)]" groups="account.group_account_readonly"/>
|
||||
<field name="partner_id" optional="hide" attrs="{'readonly':[('account_type','in', ('liability_payable','asset_receivable'))]}"/>
|
||||
<field name="partner_id" optional="show" attrs="{'readonly':[('account_type','in', ('liability_payable','asset_receivable'))]}"/>
|
||||
<field name="ref" optional="hide"/>
|
||||
<field name="product_id" optional="hide"/>
|
||||
<field name="name" optional="show"/>
|
||||
@@ -184,8 +184,8 @@
|
||||
<field name="balance" sum="Total Balance" optional="hide" readonly="1"/>
|
||||
<field name="cumulated_balance" optional="hide"/>
|
||||
<field name="matching_number" optional="show"/>
|
||||
<field name="amount_residual" string="Residual" optional="hide" attrs="{'invisible':[('account_type', 'not in', ('liability_payable','asset_receivable'))]}"/>
|
||||
<field name="amount_residual_currency" string="Residual in Currency" optional="hide" attrs="{'invisible':['|', ('is_same_currency', '=', True), ('account_type', 'not in', ('liability_payable','asset_receivable'))]}"/>
|
||||
<field name="amount_residual" sum="Total Residual" string="Residual" optional="hide" attrs="{'invisible':[('is_account_reconcile', '=', False)]}"/>
|
||||
<field name="amount_residual_currency" sum="Total Residual in Currency" string="Residual in Currency" optional="hide" attrs="{'invisible':['|', ('is_same_currency', '=', True), ('account_type', 'not in', ('liability_payable','asset_receivable'))]}"/>
|
||||
|
||||
<field name="parent_state" invisible="1"/>
|
||||
<field name="account_type" invisible="1"/>
|
||||
@@ -194,6 +194,7 @@
|
||||
<field name="reconcile_model_id" invisible="1"/>
|
||||
<field name="reconciled" invisible="1"/>
|
||||
<field name="is_same_currency" invisible="1"/>
|
||||
<field name="is_account_reconcile" invisible="1"/>
|
||||
<groupby name="partner_id">
|
||||
<button name="edit" type="edit" icon="fa-edit" title="Edit"/>
|
||||
</groupby>
|
||||
@@ -208,7 +209,6 @@
|
||||
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date" position="attributes"><attribute name="optional">hide</attribute></field>
|
||||
<field name="move_name" position="attributes"><attribute name="optional">hide</attribute></field>
|
||||
<field name="tax_tag_ids" position="attributes"><attribute name="optional">show</attribute></field>
|
||||
</field>
|
||||
</record>
|
||||
@@ -220,7 +220,6 @@
|
||||
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date" position="attributes"><attribute name="optional">hide</attribute></field>
|
||||
<field name="move_name" position="attributes"><attribute name="optional">hide</attribute></field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -231,7 +230,6 @@
|
||||
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date" position="attributes"><attribute name="optional">hide</attribute></field>
|
||||
<field name="move_name" position="attributes"><attribute name="optional">hide</attribute></field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -267,12 +265,10 @@
|
||||
<field name="mode">primary</field>
|
||||
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="move_name" position="replace"/>
|
||||
<field name="matching_number" position="replace">
|
||||
<field name="tax_line_id" string="Tax"/>
|
||||
<field name="tax_base_amount" sum="Total Base Amount"/>
|
||||
<field name="tax_audit"/>
|
||||
<field name="move_name"/>
|
||||
</field>
|
||||
<field name="analytic_account_id" position="attributes">
|
||||
<attribute name="optional">hide</attribute>
|
||||
@@ -286,9 +282,6 @@
|
||||
<field name="journal_id" position="attributes">
|
||||
<attribute name="optional">show</attribute>
|
||||
</field>
|
||||
<field name="move_name" position="attributes">
|
||||
<attribute name="optional">hide</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -330,7 +323,7 @@
|
||||
<separator/>
|
||||
<filter string="To Check" name="to_check" domain="[('move_id.to_check', '=', True)]"/>
|
||||
<separator/>
|
||||
<filter string="Unreconciled" domain="[('full_reconcile_id', '=', False), ('balance', '!=', 0), ('account_id.reconcile', '=', True)]" help="Journal items where matching number isn't set" name="unreconciled"/>
|
||||
<filter string="Unreconciled" domain="[('amount_residual', '!=', 0), ('account_id.reconcile', '=', True)]" help="Journal items where matching number isn't set" name="unreconciled"/>
|
||||
<separator/>
|
||||
<filter string="Sales" name="sales" domain="[('journal_id.type', '=', 'sale')]" context="{'default_journal_type': 'sale'}"/>
|
||||
<filter string="Purchases" name="purchases" domain="[('journal_id.type', '=', 'purchase')]" context="{'default_journal_type': 'purchase'}"/>
|
||||
@@ -476,10 +469,6 @@
|
||||
<xpath expr="//field[@name='ref']" position="attributes">
|
||||
<attribute name="optional">show</attribute>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//field[@name='payment_state']" position="attributes">
|
||||
<attribute name="optional">hide</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -672,7 +661,7 @@
|
||||
</div>
|
||||
<sheet>
|
||||
<div name="button_box" class="oe_button_box">
|
||||
<button name="open_bank_statement_view"
|
||||
<button name="open_move"
|
||||
class="oe_stat_button"
|
||||
icon="fa-bars"
|
||||
type="object"
|
||||
|
||||
@@ -116,8 +116,11 @@ class SetupBarBankConfigWizard(models.TransientModel):
|
||||
record.linked_journal_id = record.journal_id and record.journal_id[0] or record.default_linked_journal_id()
|
||||
|
||||
def default_linked_journal_id(self):
|
||||
default = self.env['account.journal'].search([('type', '=', 'bank'), ('bank_account_id', '=', False)], limit=1)
|
||||
return default[:1].id
|
||||
for journal_id in self.env['account.journal'].search([('type', '=', 'bank'), ('bank_account_id', '=', False)]):
|
||||
empty_journal_count = self.env['account.move'].search_count([('journal_id', '=', journal_id.id)])
|
||||
if empty_journal_count == 0:
|
||||
return journal_id.id
|
||||
return False
|
||||
|
||||
def set_linked_journal_id(self):
|
||||
""" Called when saving the wizard.
|
||||
|
||||
Reference in New Issue
Block a user