# Part of Odoo. See LICENSE file for full copyright and licensing details. from markupsafe import Markup from odoo.addons.iap.tools import iap_tools from odoo import api, fields, models, _ from odoo.exceptions import UserError from odoo.tools import is_html_empty from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT import time OCR_VERSION = 132 class HrExpense(models.Model): _name = 'hr.expense' _inherit = ['extract.mixin', 'hr.expense'] # We want to see the records that are just processed by OCR at the top of the list _order = "extract_state_processed desc, date desc, id desc" sample = fields.Boolean(help='Expenses created from sample receipt') def _needs_product_price_computation(self): # OVERRIDES 'hr_expense' self.ensure_one() is_extracted = self.extract_state in {'waiting_validation', 'to_validate', 'done'} and self.is_editable return self.product_has_cost and not is_extracted @api.depends('state') def _compute_is_in_extractable_state(self): for expense in self: expense.is_in_extractable_state = expense.state == 'draft' and not expense.sheet_id @api.model def _contact_iap_extract(self, pathinfo, params): params['version'] = OCR_VERSION params['account_token'] = self._get_iap_account().account_token endpoint = self.env['ir.config_parameter'].sudo().get_param('iap_extract_endpoint', 'https://extract.api.odoo.com') return iap_tools.iap_jsonrpc(endpoint + '/api/extract/expense/2/' + pathinfo, params=params) def _autosend_for_digitization(self): if self.env.company.expense_extract_show_ocr_option_selection == 'auto_send': self.filtered('extract_can_show_send_button')._send_batch_for_digitization() def _message_set_main_attachment_id(self, attachment_ids): super()._message_set_main_attachment_id(attachment_ids) self._autosend_for_digitization() def _get_validation(self, field): text_to_send = {} if field == "total": text_to_send["content"] = self.price_unit elif field == "date": text_to_send["content"] = str(self.date) if self.date else False elif field == "description": text_to_send["content"] = self.name elif field == "currency": text_to_send["content"] = self.currency_id.name return text_to_send def action_submit_expenses(self, **kwargs): res = super().action_submit_expenses(**kwargs) self._validate_ocr() return res def _fill_document_with_results(self, ocr_results, force_write=False): if ocr_results is not None: vals = {'state': 'draft'} description_ocr = self._get_ocr_selected_value(ocr_results, 'description', "") total_ocr = self._get_ocr_selected_value(ocr_results, 'total', 0.0) date_ocr = self._get_ocr_selected_value(ocr_results, 'date', fields.Date.context_today(self).strftime(DEFAULT_SERVER_DATE_FORMAT)) currency_ocr = self._get_ocr_selected_value(ocr_results, 'currency', self.env.company.currency_id.name) if description_ocr and not self.name or self.name == self.message_main_attachment_id.name.split('.')[0]: predicted_product_id = self._predict_product(description_ocr, category=True) if predicted_product_id: vals['product_id'] = predicted_product_id or self.product_id vals['name'] = description_ocr # We need to set the name after the product change as changing the product may change the name vals['predicted_category'] = description_ocr context_create_date = fields.Date.context_today(self, self.create_date) if not self.date or self.date == context_create_date: vals['date'] = date_ocr if not self.total_amount_currency: vals['total_amount_currency'] = total_ocr if not self.currency_id or self.currency_id == self.env.company.currency_id: for comparison in ['=ilike', 'ilike']: matched_currency = self.env["res.currency"].with_context(active_test=False).search([ '|', '|', ('currency_unit_label', comparison, currency_ocr), ('name', comparison, currency_ocr), ('symbol', comparison, currency_ocr), ]) if len(matched_currency) == 1: vals['currency_id'] = matched_currency.id if matched_currency != self.company_currency_id: vals['total_amount'] = matched_currency._convert( vals.get('total_amount_currency', self.total_amount_currency), self.company_currency_id, company=self.company_id, date=vals.get('date', self.date), ) self.write(vals) @api.model def get_empty_list_help(self, help_message): if self.env.user.has_group('hr_expense.group_hr_expense_manager'): expenses = self.search_count([ ('employee_id', 'in', self.env.user.employee_ids.ids), ('state', 'in', ['draft', 'reported', 'approved', 'done', 'refused']) ]) if is_html_empty(help_message): help_message = Markup(_("""
Or
Snap pictures of your receipts and let Odoo
automatically create expenses for you.