Skip to content
Permalink
Browse files

[ADD] account: add ocr to customer invoices

Task 1942983
Accounting firms need to upload PDF of customer invoices and refunds (not only vendor bills).
  • Loading branch information...
william-andre committed Mar 6, 2019
1 parent 39e7135 commit dad9b7795ddc0a00c5652ecfdb6c89821f9ad175
@@ -484,10 +484,10 @@ def _get_bank_statements_available_sources(self):
bank_id = fields.Many2one('res.bank', related='bank_account_id.bank_id', readonly=False)
post_at_bank_rec = fields.Boolean(string="Post At Bank Reconciliation", help="Whether or not the payments made in this journal should be generated in draft state, so that the related journal entries are only posted when performing bank reconciliation.")

# alias configuration for 'purchase' type journals
# alias configuration for journals
alias_id = fields.Many2one('mail.alias', string='Alias', copy=False)
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.", readonly=False)
alias_name = fields.Char('Alias Name', related='alias_id.alias_name', help="It creates draft invoices and bills by sending an email.", readonly=False)

journal_group_ids = fields.Many2many('account.journal.group', string="Journal Groups")

@@ -8,10 +8,11 @@ class ImportInvoiceImportWizard(models.TransientModel):
_description = 'Import Your Vendor Bills from Files.'

def _get_default_journal_id(self):
return self.env['account.journal'].search([('type', '=', 'purchase')], limit=1)
type = self.env.context.get('type') == 'out_invoice' and 'sale' or 'purchase'
return self.env['account.journal'].search([('type', '=', type)], limit=1)

attachment_ids = fields.Many2many('ir.attachment', string='Files')
journal_id = fields.Many2one(string="Journal", comodel_name="account.journal", required=True, domain="[('type', '=', 'purchase')]", default=_get_default_journal_id, help="Journal where to generate the bills")
journal_id = fields.Many2one(string="Journal", comodel_name="account.journal", required=True, domain="[('type', 'in', ('sale', 'purchase'))]", default=_get_default_journal_id, help="Journal where to generate the bills")

@api.multi
def _create_invoice_from_file(self, attachment):
@@ -22,7 +22,6 @@ odoo.define('account.bills.tree', function (require) {
this.$buttons.on('click', '.o_button_upload_bill', function () {
var state = self.model.get(self.handle, {raw: true});
var context = state.getContext()
context['type'] = 'in_invoice'
self.do_action({
type: 'ir.actions.act_window',
res_model: 'account.invoice.import.wizard',
@@ -41,5 +40,5 @@ odoo.define('account.bills.tree', function (require) {
}),
});

viewRegistry.add('account_bills_tree', BillsListView);
viewRegistry.add('account_tree', BillsListView);
});
@@ -153,7 +153,7 @@
<field name="name">account.invoice.tree</field>
<field name="model">account.invoice</field>
<field name="arch" type="xml">
<tree decoration-info="state == 'draft'" decoration-muted="state == 'cancel'" string="Invoice">
<tree decoration-info="state == 'draft'" decoration-muted="state == 'cancel'" string="Invoice" js_class="account_tree">
<field name="partner_id" groups="base.group_user" string="Customer"/>
<field name="date_invoice"/>
<field name="number"/>
@@ -233,7 +233,7 @@
<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'" decoration-bf="not partner_id" string="Vendor Bill" js_class="account_bills_tree">
<tree decoration-info="state == 'draft'" decoration-muted="state == 'cancel'" decoration-bf="not partner_id" string="Vendor Bill" js_class="account_tree">
<field name="partner_id" invisible="1"/>
<field name="source_email" invisible="1"/>
<field name="invoice_icon" string=" "/>
@@ -631,6 +631,7 @@
</page>
</notebook>
</sheet>
<div class="o_attachment_preview" attrs="{'invisible': ['|',('type', '!=', 'out_invoice'),('state', '!=', 'draft')]}" />
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="activity_ids" widget="mail_activity"/>
@@ -280,13 +280,13 @@
<field name="inbound_payment_method_ids" widget="many2many_checkboxes"/>
<field name="outbound_payment_method_ids" widget="many2many_checkboxes"/>
</group>
<group string="Accounting App Options">
<group string="Accounting App Options" attrs="{'invisible': [('type', 'not in', ['bank', 'cash', 'sale', 'purchase'])]}">
<field name="profit_account_id" attrs="{'invisible': [('type', '!=', 'cash')]}"/>
<field name="loss_account_id" attrs="{'invisible': [('type', '!=', 'cash')]}"/>
<field name="group_invoice_lines" attrs="{'invisible': [('type', 'not in', ['sale', 'purchase'])]}"/>
<field name="post_at_bank_rec" attrs="{'invisible': [('type', 'not in', ['bank', 'cash'])]}"/>
</group>
<group name="group_alias" string="Email your Vendor Bills" attrs="{'invisible': [('type', '!=', 'purchase')]}">
<group name="group_alias" string="Email your Invoices/Bills" attrs="{'invisible': [('type', 'not in', ('sale' ,'purchase'))]}">
<label string="Email Alias" attrs="{'invisible': [('alias_domain', '=', False)]}" for="alias_id"/>
<div name="alias_def" attrs="{'invisible': [('alias_domain', '=', False)]}">
<field name="alias_id" class="oe_read_only oe_inline"/>
@@ -805,7 +805,7 @@
<div class="oe_button_box" name="button_box">
<button type="object" name="action_reconcile_stat"
class="oe_stat_button" icon="fa-book">
<field name="number_entries" string="Journal Entries" widget="statinfo"/>
<field name="number_entries" string="Journal Entries" widget="statinfo"/>
</button>
</div>
<div class="oe_title">
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
{
'name' : 'Import Vendor Bills From XML',
'name' : 'Import Bills/Invoices From XML',
'version' : '1.0',
'category': 'Accounting',
'depends' : ['account'],
@@ -12,6 +12,9 @@
import io
import base64

import logging
_logger = logging.getLogger(__name__)


DEFAULT_FACTURX_DATE_FORMAT = '%Y%m%d'

@@ -56,7 +59,8 @@ def _import_facturx_invoice(self, tree):

# type must be present in the context to get the right behavior of the _default_journal method (account.invoice).
# journal_id must be present in the context to get the right behavior of the _default_account method (account.invoice.line).
self_ctx = self.with_context(type='in_invoice')
print(self.env.context)
self_ctx = self.with_context(type=self.env.context.get('type') or self.env.context['default_type'])
journal_id = self_ctx._default_journal().id
self_ctx = self_ctx.with_context(journal_id=journal_id)

@@ -202,7 +206,10 @@ def _import_facturx_invoice(self, tree):
invoice_line_form.price_unit = amount_total_import

# Refund.
invoice_form.type = 'in_refund' if refund_sign == -1 else 'in_invoice'
if self_ctx.env.context['type'].startswith('in_'):
invoice_form.type = 'in_refund' if refund_sign == -1 else 'in_invoice'
else:
invoice_form.type = 'out_invoice' if refund_sign == -1 else 'out_refund'

return invoice_form.save()

@@ -221,7 +228,7 @@ def _get_attachment_content(attachment):
# Handle both _Attachment namedtuple in mail.thread or ir.attachment.
return hasattr(attachment, 'content') and getattr(attachment, 'content') or base64.b64decode(attachment.datas)

if 'default_res_id' not in self._context and len(self) == 1 and self.state == 'draft' and self.type in ('in_invoice', 'in_refund'):
if 'default_res_id' not in self._context and len(self) == 1 and self.state == 'draft':
# Get attachments.
# - 'attachments' is a namedtuple defined in mail.thread looking like:
# _Attachment = namedtuple('Attachment', ('fname', 'content', 'info'))
@@ -260,8 +267,9 @@ def _get_attachment_content(attachment):
self._import_facturx_invoice(tree)
buffer.close()
return res
except:
except Exception as e:
# Malformed PDF.
_logger.exception(e)
pass
buffer.close()
return res

0 comments on commit dad9b77

Please sign in to comment.
You can’t perform that action at this time.