[IMP] account: vendor bill creation upon email reception
This allows to set up a mail alias per purchase journal. Then share that email address to your supplier, or use it internally to forward the vendor bills received by mail, to automatically create an empty vendor bill with the mail attachments linked, and the partner might be filled if the source email matches a supplier. Thanks to the document preview on the side, it's now super easy and super fast to copy the vendor bill info from the received PDF into the account.invoice object. This would eventually be improved later on (IAP). Was task: 37703 Was PR #22158
This commit is contained in:
@@ -2,6 +2,15 @@
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Open Settings from Purchase Journal to configure mail servers -->
|
||||
<record id="action_open_settings" model="ir.actions.act_window">
|
||||
<field name="name">Settings</field>
|
||||
<field name="res_model">res.config.settings</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">inline</field>
|
||||
<field name="context" eval="{'module': 'general_settings'}"/>
|
||||
</record>
|
||||
|
||||
<!-- TAGS FOR CASH FLOW STATEMENT -->
|
||||
|
||||
<record id="account_tag_operating" model="account.account.tag">
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import time
|
||||
import math
|
||||
import re
|
||||
|
||||
from odoo.osv import expression
|
||||
from odoo.tools.float_utils import float_round as round
|
||||
@@ -427,10 +428,21 @@ class AccountJournal(models.Model):
|
||||
bank_acc_number = fields.Char(related='bank_account_id.acc_number')
|
||||
bank_id = fields.Many2one('res.bank', related='bank_account_id.bank_id')
|
||||
|
||||
# alias configuration for 'purchase' type journals
|
||||
alias_id = fields.Many2one('mail.alias', string='Alias')
|
||||
alias_domain = fields.Char('Alias domain', compute='_compute_alias_domain', default=lambda self: self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain"))
|
||||
alias_name = fields.Char('Alias Name for Vendor Bills', related='alias_id.alias_name', help="It creates draft vendor bill by sending an email.")
|
||||
|
||||
_sql_constraints = [
|
||||
('code_company_uniq', 'unique (code, name, company_id)', 'The code and name of the journal must be unique per company !'),
|
||||
]
|
||||
|
||||
@api.multi
|
||||
def _compute_alias_domain(self):
|
||||
alias_domain = self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain")
|
||||
for record in self:
|
||||
record.alias_domain = alias_domain
|
||||
|
||||
@api.multi
|
||||
# do not depend on 'sequence_id.date_range_ids', because
|
||||
# sequence_id._get_current_sequence() may invalidate it!
|
||||
@@ -509,6 +521,19 @@ class AccountJournal(models.Model):
|
||||
if not self.default_debit_account_id:
|
||||
self.default_debit_account_id = self.default_credit_account_id
|
||||
|
||||
@api.multi
|
||||
def _get_alias_values(self, alias_name=None):
|
||||
if not alias_name:
|
||||
alias_name = self.name
|
||||
if self.company_id != self.env.ref('base.main_company'):
|
||||
alias_name += '-' + str(self.company_id.name)
|
||||
return {
|
||||
'alias_defaults': {'type': 'in_invoice'},
|
||||
'alias_user_id': self.env.user.id,
|
||||
'alias_parent_thread_id': self.id,
|
||||
'alias_name': re.sub(r'[^\w]+', '-', alias_name)
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
bank_accounts = self.env['res.partner.bank'].browse()
|
||||
@@ -516,6 +541,7 @@ class AccountJournal(models.Model):
|
||||
accounts = self.search([('bank_account_id', '=', bank_account.id)])
|
||||
if accounts <= self:
|
||||
bank_accounts += bank_account
|
||||
self.mapped('alias_id').unlink()
|
||||
ret = super(AccountJournal, self).unlink()
|
||||
bank_accounts.unlink()
|
||||
return ret
|
||||
@@ -529,6 +555,19 @@ class AccountJournal(models.Model):
|
||||
name=_("%s (copy)") % (self.name or ''))
|
||||
return super(AccountJournal, self).copy(default)
|
||||
|
||||
def _update_mail_alias(self, vals):
|
||||
self.ensure_one()
|
||||
alias_values = self._get_alias_values(alias_name=vals.get('alias_name'))
|
||||
if self.alias_id:
|
||||
self.alias_id.write(alias_values)
|
||||
else:
|
||||
self.alias_id = self.env['mail.alias'].with_context(alias_model_name='account.invoice',
|
||||
alias_parent_model_name='account.journal').create(alias_values)
|
||||
|
||||
if vals.get('alias_name'):
|
||||
# remove alias_name to avoid useless write on alias
|
||||
del(vals['alias_name'])
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
for journal in self:
|
||||
@@ -564,7 +603,8 @@ class AccountJournal(models.Model):
|
||||
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."))
|
||||
|
||||
if vals.get('type') == 'purchase':
|
||||
self._update_mail_alias(vals)
|
||||
result = super(AccountJournal, self).write(vals)
|
||||
|
||||
# Create the bank_account_id if necessary
|
||||
@@ -676,8 +716,10 @@ class AccountJournal(models.Model):
|
||||
vals.update({'sequence_id': self.sudo()._create_sequence(vals).id})
|
||||
if vals.get('type') in ('sale', 'purchase') and vals.get('refund_sequence') and not vals.get('refund_sequence_id'):
|
||||
vals.update({'refund_sequence_id': self.sudo()._create_sequence(vals, refund=True).id})
|
||||
|
||||
journal = super(AccountJournal, self).create(vals)
|
||||
if journal.type == 'purchase':
|
||||
# create a mail alias for purchase journals (always, deactivated if alias_name isn't set)
|
||||
journal._update_mail_alias(vals)
|
||||
|
||||
# Create the bank_account_id if necessary
|
||||
if journal.type == 'bank' and not journal.bank_account_id and vals.get('bank_acc_number'):
|
||||
|
||||
@@ -10,7 +10,7 @@ from dateutil.relativedelta import relativedelta
|
||||
from werkzeug.urls import url_encode
|
||||
|
||||
from odoo import api, exceptions, fields, models, _
|
||||
from odoo.tools import float_is_zero, float_compare, pycompat
|
||||
from odoo.tools import email_re, email_split, email_escape_char, float_is_zero, float_compare, pycompat
|
||||
from odoo.tools.misc import formatLang
|
||||
|
||||
from odoo.exceptions import AccessError, UserError, RedirectWarning, ValidationError, Warning
|
||||
@@ -241,7 +241,7 @@ class AccountInvoice(models.Model):
|
||||
('in_invoice','Vendor Bill'),
|
||||
('out_refund','Customer Credit Note'),
|
||||
('in_refund','Vendor Credit Note'),
|
||||
], readonly=True, index=True, change_default=True,
|
||||
], readonly=True, states={'draft': [('readonly', False)]}, index=True, change_default=True,
|
||||
default=lambda self: self._context.get('type', 'out_invoice'),
|
||||
track_visibility='always')
|
||||
access_token = fields.Char(
|
||||
@@ -284,7 +284,7 @@ class AccountInvoice(models.Model):
|
||||
"term is not set on the invoice. If you keep the Payment terms and the due date empty, it "
|
||||
"means direct payment.")
|
||||
partner_id = fields.Many2one('res.partner', string='Partner', change_default=True,
|
||||
required=True, readonly=True, states={'draft': [('readonly', False)]},
|
||||
readonly=True, states={'draft': [('readonly', False)]},
|
||||
track_visibility='always')
|
||||
vendor_bill_id = fields.Many2one('account.invoice', string='Vendor Bill',
|
||||
help="Auto-complete from a past bill.")
|
||||
@@ -299,7 +299,7 @@ class AccountInvoice(models.Model):
|
||||
readonly=True, states={'draft': [('readonly', False)]})
|
||||
|
||||
account_id = fields.Many2one('account.account', string='Account',
|
||||
required=True, readonly=True, states={'draft': [('readonly', False)]},
|
||||
readonly=True, states={'draft': [('readonly', False)]},
|
||||
domain=[('deprecated', '=', False)], help="The partner account used for this invoice.")
|
||||
invoice_line_ids = fields.One2many('account.invoice.line', 'invoice_id', string='Invoice Lines', oldname='invoice_line',
|
||||
readonly=True, states={'draft': [('readonly', False)]}, copy=True)
|
||||
@@ -370,10 +370,24 @@ class AccountInvoice(models.Model):
|
||||
sequence_number_next = fields.Char(string='Next Number', compute="_get_sequence_number_next", inverse="_set_sequence_next")
|
||||
sequence_number_next_prefix = fields.Char(string='Next Number Prefix', compute="_get_sequence_prefix")
|
||||
|
||||
#fields related to vendor bills automated creation by email
|
||||
source_email = fields.Char(string='Source Email', track_visibility='onchange')
|
||||
vendor_display_name = fields.Char(compute='_get_vendor_display_info', store=True) # store=True to enable sorting on that column
|
||||
invoice_icon = fields.Char(compute='_get_vendor_display_info', store=False)
|
||||
|
||||
_sql_constraints = [
|
||||
('number_uniq', 'unique(number, company_id, journal_id, type)', 'Invoice Number must be unique per Company!'),
|
||||
]
|
||||
|
||||
@api.depends('partner_id', 'source_email')
|
||||
def _get_vendor_display_info(self):
|
||||
for invoice in self:
|
||||
vendor_display_name = invoice.partner_id.name
|
||||
if not vendor_display_name and invoice.source_email:
|
||||
vendor_display_name = _('From: ') + invoice.source_email
|
||||
invoice.vendor_display_name = vendor_display_name
|
||||
invoice.invoice_icon = invoice.source_email and '@' or ''
|
||||
|
||||
# Load all Vendor Bill lines
|
||||
@api.onchange('vendor_bill_id')
|
||||
def _onchange_vendor_bill(self):
|
||||
@@ -479,8 +493,6 @@ class AccountInvoice(models.Model):
|
||||
for field in changed_fields:
|
||||
if field not in vals and invoice[field]:
|
||||
vals[field] = invoice._fields[field].convert_to_write(invoice[field], invoice)
|
||||
if not vals.get('account_id',False):
|
||||
raise UserError(_('No account was found to create the invoice, be sure you have installed a chart of account.'))
|
||||
|
||||
invoice = super(AccountInvoice, self.with_context(mail_create_nolog=True)).create(vals)
|
||||
|
||||
@@ -611,6 +623,82 @@ class AccountInvoice(models.Model):
|
||||
self.filtered(lambda inv: not inv.sent).write({'sent': True})
|
||||
return super(AccountInvoice, self.with_context(mail_post_autofollow=True)).message_post(**kwargs)
|
||||
|
||||
@api.model
|
||||
def message_new(self, msg_dict, custom_values=None):
|
||||
""" Overrides mail_thread message_new(), called by the mailgateway through message_process,
|
||||
to complete values for vendor bills created by mails.
|
||||
"""
|
||||
# Split `From` and `CC` email address from received email to look for related partners to subscribe on the invoice
|
||||
subscribed_emails = email_split((msg_dict.get('from') or '') + ',' + (msg_dict.get('cc') or ''))
|
||||
subscribed_partner_ids = [pid for pid in self._find_partner_from_emails(subscribed_emails) if pid]
|
||||
|
||||
# Detection of the partner_id of the invoice:
|
||||
# 1) check if the email_from correspond to a supplier
|
||||
email_from = msg_dict.get('from') or ''
|
||||
email_from = email_escape_char(email_split(email_from)[0])
|
||||
partner_id = self._search_on_partner(email_from, extra_domain=[('supplier', '=', True)])
|
||||
|
||||
# 2) otherwise, if the email sender is from odoo internal users then it is likely that the vendor sent the bill
|
||||
# by mail to the internal user who, inturn, forwarded that email to the alias to automatically generate the bill
|
||||
# on behalf of the vendor.
|
||||
if not partner_id:
|
||||
user_partner_id = self._search_on_user(email_from)
|
||||
if user_partner_id and user_partner_id in self.env.ref('base.group_user').users.mapped('partner_id').ids:
|
||||
# In this case, we will look for the vendor's email address in email's body and assume if will come first
|
||||
email_addresses = email_re.findall(msg_dict.get('body'))
|
||||
if email_addresses:
|
||||
partner_ids = [pid for pid in self._find_partner_from_emails([email_addresses[0]], force_create=False) if pid]
|
||||
partner_id = partner_ids and partner_ids[0]
|
||||
# otherwise, there's no fallback on the partner_id found for the regular author of the mail.message as we want
|
||||
# the partner_id to stay empty
|
||||
|
||||
# If the partner_id can be found, subscribe it to the bill, otherwise it's left empty to be manually filled
|
||||
if partner_id:
|
||||
subscribed_partner_ids.append(partner_id)
|
||||
|
||||
# Find the right purchase journal based on the "TO" email address
|
||||
destination_emails = email_split((msg_dict.get('to') or '') + ',' + (msg_dict.get('cc') or ''))
|
||||
alias_names = [mail_to.split('@')[0] for mail_to in destination_emails]
|
||||
journal = self.env['account.journal'].search([
|
||||
('type', '=', 'purchase'), ('alias_name', 'in', alias_names)
|
||||
], limit=1)
|
||||
|
||||
# Create the message and the bill.
|
||||
values = dict(custom_values or {}, partner_id=partner_id, source_email=email_from)
|
||||
if journal:
|
||||
values['journal_id'] = journal.id
|
||||
# Passing `type` in context so that _default_journal(...) can correctly set journal for new vendor bill
|
||||
invoice = super(AccountInvoice, self.with_context(type=values.get('type'))).message_new(msg_dict, values)
|
||||
|
||||
# Subscribe people on the newly created bill
|
||||
if subscribed_partner_ids:
|
||||
invoice.message_subscribe(subscribed_partner_ids)
|
||||
return invoice
|
||||
|
||||
@api.model
|
||||
def complete_empty_list_help(self):
|
||||
# add help message about email alias in vendor bills empty lists
|
||||
Journal = self.env['account.journal']
|
||||
journals = Journal.browse(self._context.get('default_journal_id')) or Journal.search([('type', '=', 'purchase')])
|
||||
|
||||
if journals:
|
||||
links = ''
|
||||
alias_count = 0
|
||||
for journal in journals.filtered(lambda j: j.alias_domain and j.alias_id.alias_name):
|
||||
email = format(journal.alias_id.alias_name) + "@" + format(journal.alias_domain)
|
||||
links += "<a id='o_mail_test' href='mailto:{}'>{}</a>".format(email, email) + ", "
|
||||
alias_count += 1
|
||||
if links and alias_count == 1:
|
||||
help_message = _('Or share the email %s to your vendors: bills will be created automatically upon mail reception.') % (links[:-2])
|
||||
elif links:
|
||||
help_message = _('Or share the emails %s to your vendors: bills will be created automatically upon mail reception.') % (links[:-2])
|
||||
else:
|
||||
help_message = _('''Or set an <a data-oe-id=%s data-oe-model="account.journal" href=#id=%s&model=account.journal>email alias</a> '''
|
||||
'''to allow draft vendor bills to be created upon reception of an email.''') % (journals[0].id, journals[0].id)
|
||||
else:
|
||||
help_message = _('<p>You can control the invoice from your vendor based on what you purchased or received.</p>')
|
||||
return help_message
|
||||
|
||||
@api.multi
|
||||
def compute_taxes(self):
|
||||
"""Function used in other module to compute the taxes on a fresh invoice created (onchanges did not applied)"""
|
||||
@@ -799,10 +887,14 @@ class AccountInvoice(models.Model):
|
||||
def action_invoice_open(self):
|
||||
# lots of duplicate calls to action_invoice_open, so we remove those already open
|
||||
to_open_invoices = self.filtered(lambda inv: inv.state != 'open')
|
||||
for inv in to_open_invoices.filtered(lambda inv: not inv.partner_id):
|
||||
raise UserError(_("The field Vendor is required, please complete it to validate the Vendor Bill."))
|
||||
if to_open_invoices.filtered(lambda inv: inv.state != 'draft'):
|
||||
raise UserError(_("Invoice must be in draft state in order to validate it."))
|
||||
if to_open_invoices.filtered(lambda inv: inv.amount_total < 0):
|
||||
raise UserError(_("You cannot validate an invoice with a negative total amount. You should create a credit note instead."))
|
||||
if to_open_invoices.filtered(lambda inv: not inv.account_id):
|
||||
raise UserError(_('No account was found to create the invoice, be sure you have installed a chart of account.'))
|
||||
to_open_invoices.action_date_assign()
|
||||
to_open_invoices.action_move_create()
|
||||
return to_open_invoices.invoice_validate()
|
||||
|
||||
@@ -324,7 +324,7 @@ class account_journal(models.Model):
|
||||
elif self.type == 'sale':
|
||||
action_name = 'action_invoice_tree1'
|
||||
elif self.type == 'purchase':
|
||||
action_name = 'action_invoice_tree2'
|
||||
action_name = 'action_vendor_bill_template'
|
||||
else:
|
||||
action_name = 'action_move_journal_line'
|
||||
|
||||
@@ -354,11 +354,14 @@ class account_journal(models.Model):
|
||||
action['context'] = ctx
|
||||
action['domain'] = self._context.get('use_domain', [])
|
||||
account_invoice_filter = self.env.ref('account.view_account_invoice_filter', False)
|
||||
if action_name in ['action_invoice_tree1', 'action_invoice_tree2']:
|
||||
if action_name in ['action_invoice_tree1', 'action_vendor_bill_template']:
|
||||
action['search_view_id'] = account_invoice_filter and account_invoice_filter.id or False
|
||||
if action_name in ['action_bank_statement_tree', 'action_view_bank_statement_tree']:
|
||||
action['views'] = False
|
||||
action['view_id'] = False
|
||||
if self.type == 'purchase':
|
||||
new_help = self.env['account.invoice'].with_context(ctx).complete_empty_list_help()
|
||||
action.update({'help': action.get('help', '') + new_help})
|
||||
return action
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -23,4 +23,3 @@
|
||||
font-style: italic;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
|
||||
@@ -190,8 +190,11 @@
|
||||
<field name="name">account.invoice.supplier.tree</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree decoration-info="state == 'draft'" decoration-muted="state == 'cancel'" string="Invoice">
|
||||
<field name="partner_id" groups="base.group_user" string="Vendor"/>
|
||||
<tree decoration-info="state == 'draft'" decoration-muted="state == 'cancel'" decoration-bf="not partner_id" string="Vendor Bill">
|
||||
<field name="partner_id" invisible="1"/>
|
||||
<field name="source_email" invisible="1"/>
|
||||
<field name="invoice_icon" string=" "/>
|
||||
<field name="vendor_display_name" groups="base.group_user" string="Vendor"/>
|
||||
<field name="date_invoice" string="Bill Date"/>
|
||||
<field name="number"/>
|
||||
<field name="reference"/>
|
||||
@@ -250,7 +253,7 @@
|
||||
<group>
|
||||
<field string="Vendor" name="partner_id"
|
||||
context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1, 'default_company_type': 'company'}"
|
||||
domain="[('supplier', '=', True)]"/>
|
||||
domain="[('supplier', '=', True)]" required="1"/>
|
||||
<field name="reference" string="Vendor Reference"/>
|
||||
<field name="vendor_bill_id" attrs="{'invisible': [('state','not in',['draft'])]}"
|
||||
domain="[('partner_id','child_of', [partner_id]), ('state','in',('open','paid')), ('type','=','in_invoice')]"
|
||||
@@ -259,6 +262,7 @@
|
||||
</group>
|
||||
<group>
|
||||
<field name="origin" attrs="{'invisible': [('origin', '=', False)]}"/>
|
||||
<field name="source_email" widget="email" groups="base.group_no_one" attrs="{'invisible': [('source_email', '=', False)]}"/>
|
||||
<field name="date_invoice" string="Bill Date"/>
|
||||
<field name="date_due" attrs="{'readonly': ['|',('payment_term_id','!=',False), ('state', 'in', ['open', 'paid'])]}" force_save="1"/>
|
||||
<field name="move_name" invisible="1"/>
|
||||
@@ -348,7 +352,7 @@
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="o_attachment_preview" attrs="{'invisible': ['|',('type', '!=', 'in_invoice'),('state', '!=', 'draft')]}"/>
|
||||
<div class="o_attachment_preview" attrs="{'invisible': ['|',('type', '!=', 'in_invoice'),('state', '!=', 'draft')]}" options="{'preview_priority_type': 'pdf'}"/>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="activity_ids" widget="mail_activity"/>
|
||||
@@ -402,7 +406,7 @@
|
||||
<field string="Customer" name="partner_id"
|
||||
context="{'search_default_customer':1, 'show_address': 1, 'default_company_type': 'company'}"
|
||||
options='{"always_reload": True, "no_quick_create": True}'
|
||||
domain="[('customer', '=', True)]"/>
|
||||
domain="[('customer', '=', True)]" required="1"/>
|
||||
<field name="payment_term_id"/>
|
||||
<field name="cash_rounding_id" groups="account.group_cash_rounding"/>
|
||||
</group>
|
||||
@@ -707,7 +711,7 @@
|
||||
parent="menu_finance_receivables_documents"
|
||||
sequence="1"/>
|
||||
|
||||
<record id="action_invoice_tree2" model="ir.actions.act_window">
|
||||
<record id="action_vendor_bill_template" model="ir.actions.act_window">
|
||||
<field name="name">Vendor Bills</field>
|
||||
<field name="res_model">account.invoice</field>
|
||||
<field name="view_type">form</field>
|
||||
@@ -719,25 +723,36 @@
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Record a new vendor bill
|
||||
</p><p>
|
||||
You can control the invoice from your vendor based on
|
||||
what you purchased or received.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<!--
|
||||
server action opening the vendor bills and returning the right help tooltip
|
||||
-->
|
||||
<record id="action_invoice_tree2" model="ir.actions.server">
|
||||
<field name="name">Vendor Bills</field>
|
||||
<field name="model_id" ref="model_account_invoice"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
action_values = env.ref('account.action_vendor_bill_template').read()[0]
|
||||
new_help = model.complete_empty_list_help()
|
||||
action_values.update({'help': action_values.get('help', '') + new_help})
|
||||
action = action_values
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_invoice_supplier_tree1_view1" model="ir.actions.act_window.view">
|
||||
<field eval="1" name="sequence"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="invoice_supplier_tree"/>
|
||||
<field name="act_window_id" ref="action_invoice_tree2"/>
|
||||
<field name="act_window_id" ref="action_vendor_bill_template"/>
|
||||
</record>
|
||||
|
||||
<record id="action_invoice__supplier_tree1_view2" model="ir.actions.act_window.view">
|
||||
<field eval="2" name="sequence"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="invoice_supplier_form"/>
|
||||
<field name="act_window_id" ref="action_invoice_tree2"/>
|
||||
<field name="act_window_id" ref="action_vendor_bill_template"/>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_invoice_tree2" id="menu_action_invoice_tree2" parent="menu_finance_payables_documents" sequence="1"/>
|
||||
|
||||
@@ -333,6 +333,18 @@
|
||||
<field name="loss_account_id" attrs="{'invisible': [('type', '!=', 'cash')]}"/>
|
||||
<field name="show_on_dashboard" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<group name="group_alias" string="Email your Vendor Bills" attrs="{'invisible': [('type', '!=', 'purchase')]}">
|
||||
<label string="Email Alias" attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
<div name="alias_def" attrs="{'invisible': [('alias_domain', '=', False)]}">
|
||||
<field name="alias_id" class="oe_read_only oe_inline"/>
|
||||
<div class="oe_edit_only oe_inline" name="edit_alias" style="display: inline;" >
|
||||
<field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-group" attrs="{'invisible': [('alias_domain', '!=', False)]}">
|
||||
<a type='action' name='%(action_open_settings)d' class="btn btn-sm btn-link"><i class="fa fa-fw o_button_icon fa-arrow-right"/> Configure Email Servers</a>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page name="bank_account" string="Bank Account" attrs="{'invisible': [('type', '!=', 'bank')]}">
|
||||
|
||||
Reference in New Issue
Block a user