Browse Source

Feb 12 : [FIX] License Updated 'ocr_data_retrieval'

pull/267/merge
RisvanaCybro 1 year ago
parent
commit
b6be56cbab
  1. 10
      ocr_data_retrieval/README.rst
  2. 12
      ocr_data_retrieval/__init__.py
  3. 59
      ocr_data_retrieval/__manifest__.py
  4. 12
      ocr_data_retrieval/models/__init__.py
  5. 470
      ocr_data_retrieval/models/ocr_data_template.py

10
ocr_data_retrieval/README.rst

@ -1,6 +1,6 @@
.. image:: https://img.shields.io/badge/licence-LGPL--3-green.svg .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: LGPL-3 :alt: License: AGPL-3
OCR Data Retrieval OCR Data Retrieval
================== ==================
@ -18,8 +18,8 @@ Company
License License
------- -------
General Public License, Version 3 (LGPL v3). GNU AFFERO GENERAL PUBLIC LICENSE, Version 3 (AGPLv3)
(https://www.gnu.org/licenses/lgpl-3.0-standalone.html) (https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Credits Credits
------- -------

12
ocr_data_retrieval/__init__.py

@ -3,19 +3,19 @@
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) # Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Sruthi Renjith (odoo@cybrosys.com) # Author: Sruthi Renjith (odoo@cybrosys.com)
# #
# You can modify it under the terms of the GNU LESSER # You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. # GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. # GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
# #
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE # You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program. # (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################### ###############################################################################

59
ocr_data_retrieval/__manifest__.py

@ -3,49 +3,46 @@
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) # Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Sruthi Renjith (odoo@cybrosys.com) # Author: Sruthi Renjith (odoo@cybrosys.com)
# #
# You can modify it under the terms of the GNU LESSER # You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. # GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. # GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
# #
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE # You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program. # (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################### ###############################################################################
{ {
'name': 'OCR Data Retrieval', "name": "OCR Data Retrieval",
'version': '16.0.1.0.0', "version": "16.0.1.0.0",
'category': 'Productivity', "category": "Productivity",
'summary': 'Data retrieval from scanned documents', "summary": "Data retrieval from scanned documents",
'description': """Data retrieval from scanned documents with .jpg, "description": """Data retrieval from scanned documents with .jpg,
.jpeg, .png and .pdf files. Also mapping them to appropriate models""", .jpeg, .png and .pdf files. Also mapping them to appropriate models""",
'author': "Cybrosys Techno Solutions", "author": "Cybrosys Techno Solutions",
'company': 'Cybrosys Techno Solutions', "company": "Cybrosys Techno Solutions",
'maintainer': 'Cybrosys Techno Solutions', "maintainer": "Cybrosys Techno Solutions",
'website': "https://www.cybrosys.com", "website": "https://www.cybrosys.com",
'depends': ['base', 'hr_expense', 'bill_digitization', 'contacts', "depends": ["base", "hr_expense", "bill_digitization", "contacts", "purchase"],
'purchase'], "assets": {
'assets': { "web.assets_backend": [
'web.assets_backend': [ "/ocr_data_retrieval/static/src/js/image_field.js",
'/ocr_data_retrieval/static/src/js/image_field.js',
], ],
}, },
'data': ['security/ir.model.access.csv', "data": ["security/ir.model.access.csv", "views/ocr_data_template_views.xml"],
'views/ocr_data_template_views.xml'], "external_dependencies": {
'external_dependencies': { "python": ["pdf2image", "PIL", "pytesseract", "spacy", "en_core_web_sm"]
'python': ['pdf2image', 'PIL', 'pytesseract', 'spacy',
'en_core_web_sm']
}, },
'images': ['static/description/banner.jpg'], "images": ["static/description/banner.jpg"],
'license': 'LGPL-3', "license": "AGPL-3",
'installable': True, "installable": True,
'auto_install': False, "auto_install": False,
'application': False, "application": False,
} }

12
ocr_data_retrieval/models/__init__.py

@ -3,19 +3,19 @@
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) # Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Sruthi Renjith (odoo@cybrosys.com) # Author: Sruthi Renjith (odoo@cybrosys.com)
# #
# You can modify it under the terms of the GNU LESSER # You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. # GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. # GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
# #
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE # You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program. # (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################### ###############################################################################

470
ocr_data_retrieval/models/ocr_data_template.py

@ -3,19 +3,19 @@
# #
# Cybrosys Technologies Pvt. Ltd. # Cybrosys Technologies Pvt. Ltd.
# #
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) # Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Sruthi Renjith (odoo@cybrosys.com) # Author: Sruthi Renjith (odoo@cybrosys.com)
# #
# You can modify it under the terms of the GNU LESSER # You can modify it under the terms of the GNU AFFERO
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. # GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. # GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
# #
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE # You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
# (LGPL v3) along with this program. # (AGPL v3) along with this program.
# If not, see <http://www.gnu.org/licenses/>. # If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################### ###############################################################################
@ -31,31 +31,36 @@ from odoo.exceptions import ValidationError
class OCRDataTemplate(models.TransientModel): class OCRDataTemplate(models.TransientModel):
""" Class to read document and extract the text from JPG, JPEG, PNG and """Class to read document and extract the text from JPG, JPEG, PNG and
PDF files. """ PDF files."""
_name = "ocr.data.template" _name = "ocr.data.template"
_description = "Data Retrieving Template" _description = "Data Retrieving Template"
_rec_name = "file_name" _rec_name = "file_name"
image = fields.Binary(string="Document", required=True, image = fields.Binary(
help="Upload .jpg, .jpeg, .png or .pdf files") string="Document", required=True, help="Upload .jpg, .jpeg, .png or .pdf files"
)
file_name = fields.Char(string="Document Name", help="Name of document") file_name = fields.Char(string="Document Name", help="Name of document")
image2 = fields.Image(string="Document", image2 = fields.Image(string="Document", help="Uploaded document", store=True)
help="Uploaded document", store=True) flag = fields.Boolean(
flag = fields.Boolean(string="Flag", default=False, string="Flag", default=False, help="Flag to check document read or not"
help="Flag to check document read or not") )
data = fields.Text(string="Data", readonly=True, data = fields.Text(string="Data", readonly=True, help="Content from the document")
help="Content from the document")
model_name_id = fields.Many2one( model_name_id = fields.Many2one(
'ir.model', string="Model", "ir.model",
string="Model",
domain="[('model', 'in', ['res.partner', 'account.move', " domain="[('model', 'in', ['res.partner', 'account.move', "
"'hr.employee', 'hr.expense', 'sale.order', " "'hr.employee', 'hr.expense', 'sale.order', "
"'purchase.order'])]", "'purchase.order'])]",
help="Model to which the data want to map") help="Model to which the data want to map",
)
model_field_ids = fields.Many2many( model_field_ids = fields.Many2many(
'ir.model.fields', string="Fields", "ir.model.fields",
string="Fields",
domain="[('model_id', '=', model_name_id)]", domain="[('model_id', '=', model_name_id)]",
help="Fields names to map data") help="Fields names to map data",
)
def data_segmentation(self, img): def data_segmentation(self, img):
""" """
@ -64,7 +69,7 @@ class OCRDataTemplate(models.TransientModel):
""" """
img = ImageOps.grayscale(img) img = ImageOps.grayscale(img)
threshold_value = 176 threshold_value = 176
img = img.point(lambda x: 255 if x > threshold_value else 0, '1') img = img.point(lambda x: 255 if x > threshold_value else 0, "1")
img_rgb = ImageOps.invert(img.convert("RGB")) img_rgb = ImageOps.invert(img.convert("RGB"))
segments = [] segments = []
segment_bounds = img_rgb.getbbox() segment_bounds = img_rgb.getbbox()
@ -84,23 +89,31 @@ class OCRDataTemplate(models.TransientModel):
try: try:
# Getting the file path from ir.attachments # Getting the file path from ir.attachments
file_attachment = self.env["ir.attachment"].search( file_attachment = self.env["ir.attachment"].search(
['|', ('res_field', '!=', False), ('res_field', '=', False), [
('res_id', '=', self.id), "|",
('res_model', '=', 'ocr.data.template')], ("res_field", "!=", False),
limit=1) ("res_field", "=", False),
("res_id", "=", self.id),
("res_model", "=", "ocr.data.template"),
],
limit=1,
)
file_path = file_attachment._full_path(file_attachment.store_fname) file_path = file_attachment._full_path(file_attachment.store_fname)
segmented_data = [] segmented_data = []
# Reading files in the format .jpg, .jpeg and .png # Reading files in the format .jpg, .jpeg and .png
if (split_tup[1] == '.jpg' or split_tup[1] == '.jpeg' or if (
split_tup[1] == '.png'): split_tup[1] == ".jpg"
with open(file_path, mode='rb') as f: or split_tup[1] == ".jpeg"
or split_tup[1] == ".png"
):
with open(file_path, mode="rb") as f:
binary_data = f.read() binary_data = f.read()
img = Image.open(io.BytesIO(binary_data)) img = Image.open(io.BytesIO(binary_data))
# Calling the function to do segmentation # Calling the function to do segmentation
segmented_data = self.data_segmentation(img) segmented_data = self.data_segmentation(img)
elif split_tup[1] == '.pdf': elif split_tup[1] == ".pdf":
# Reading files in the format .pdf # Reading files in the format .pdf
with open(file_path, mode='rb') as f: with open(file_path, mode="rb") as f:
pdf_data = f.read() pdf_data = f.read()
pages = convert_from_bytes(pdf_data) pages = convert_from_bytes(pdf_data)
# Making the contents in 2 or more pages into combined page # Making the contents in 2 or more pages into combined page
@ -110,7 +123,7 @@ class OCRDataTemplate(models.TransientModel):
for page in pages: for page in pages:
resized_page = page.resize((2400, 1800)) resized_page = page.resize((2400, 1800))
resized_images.append(resized_page) resized_images.append(resized_page)
combined_image = Image.new('RGB', (max_width, total_height)) combined_image = Image.new("RGB", (max_width, total_height))
y_offset = 0 y_offset = 0
for resized_page in resized_images: for resized_page in resized_images:
combined_image.paste(resized_page, (0, y_offset)) combined_image.paste(resized_page, (0, y_offset))
@ -118,8 +131,7 @@ class OCRDataTemplate(models.TransientModel):
# Calling the segmentation function # Calling the segmentation function
segmented_data = self.data_segmentation(combined_image) segmented_data = self.data_segmentation(combined_image)
except Exception: except Exception:
self.env['ocr.data.template'].search([], order="id desc", self.env["ocr.data.template"].search([], order="id desc", limit=1).unlink()
limit=1).unlink()
raise ValidationError(_("Cannot identify data")) raise ValidationError(_("Cannot identify data"))
# Converting the segmented image into text using pytesseract # Converting the segmented image into text using pytesseract
text = "" text = ""
@ -133,16 +145,16 @@ class OCRDataTemplate(models.TransientModel):
self.data = text self.data = text
self.flag = True self.flag = True
@api.onchange('model_name_id') @api.onchange("model_name_id")
def onchange_model_name_id(self): def onchange_model_name_id(self):
""" Function to update the Many2many field to empty """ """Function to update the Many2many field to empty"""
self.write({'model_field_ids': [(6, 0, [])]}) self.write({"model_field_ids": [(6, 0, [])]})
def find_person_name(self): def find_person_name(self):
""" """
Function to find person name from the retrieved text using 'spacy' Function to find person name from the retrieved text using 'spacy'
""" """
person = '' person = ""
nlp = spacy.load("en_core_web_sm") nlp = spacy.load("en_core_web_sm")
doc = nlp(self.data) doc = nlp(self.data)
for entity in doc.ents: for entity in doc.ents:
@ -158,7 +170,7 @@ class OCRDataTemplate(models.TransientModel):
product_line_list = [] product_line_list = []
quantities = [] quantities = []
unit_prices = [] unit_prices = []
product_regex = r'\[?(.+?)\]?\s*(.+)\n(?:HSN/SAC Code):\s+(\d+)' product_regex = r"\[?(.+?)\]?\s*(.+)\n(?:HSN/SAC Code):\s+(\d+)"
quantity_regex = r"Quantity Unit\n([\d.\s\S]+)" quantity_regex = r"Quantity Unit\n([\d.\s\S]+)"
unit_price_regex = r"Amount\n([\d.\s\S]+)" unit_price_regex = r"Amount\n([\d.\s\S]+)"
# Matching the pattern with the data # Matching the pattern with the data
@ -183,19 +195,25 @@ class OCRDataTemplate(models.TransientModel):
if number_of_product == number_of_qty == number_of_price: if number_of_product == number_of_qty == number_of_price:
for i in range(number_of_product): for i in range(number_of_product):
product_line_list.append( product_line_list.append(
{'product': products[i], 'quantity': quantities[i], {
'price': unit_prices[i]}) "product": products[i],
"quantity": quantities[i],
"price": unit_prices[i],
}
)
elif number_of_product == number_of_qty: elif number_of_product == number_of_qty:
for i in range(number_of_product): for i in range(number_of_product):
product_line_list.append( product_line_list.append(
{'product': products[i], 'quantity': quantities[i]}) {"product": products[i], "quantity": quantities[i]}
)
elif number_of_product == number_of_price: elif number_of_product == number_of_price:
for i in range(number_of_product): for i in range(number_of_product):
product_line_list.append( product_line_list.append(
{'product': products[i], 'price': unit_prices[i]}) {"product": products[i], "price": unit_prices[i]}
)
elif products: elif products:
for i in range(number_of_product): for i in range(number_of_product):
product_line_list.append({'product': products[i]}) product_line_list.append({"product": products[i]})
return product_line_list return product_line_list
def action_process_data(self): def action_process_data(self):
@ -203,27 +221,27 @@ class OCRDataTemplate(models.TransientModel):
Function to process the data after fetching it. Function to process the data after fetching it.
The fetched data are mapping into some models. The fetched data are mapping into some models.
""" """
phone_number = '' phone_number = ""
email_address = '' email_address = ""
person = '' person = ""
phone_pattern = r'\(\d{3}\) \d{3}-\d{4}|\d{3}-\d{3}-\d{4}|\+\d{1}-\d{3}-\d{3}-\d{4}|\d{11}|P \+\d{3} \d{6}' phone_pattern = r"\(\d{3}\) \d{3}-\d{4}|\d{3}-\d{3}-\d{4}|\+\d{1}-\d{3}-\d{3}-\d{4}|\d{11}|P \+\d{3} \d{6}"
email_pattern = r'[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' email_pattern = r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
if self.model_name_id.name == 'Contact': if self.model_name_id.name == "Contact":
# Mapping the data into Contact module by fetching person name, # Mapping the data into Contact module by fetching person name,
# phone number and email id from data # phone number and email id from data
field_value = False field_value = False
non_field_count = 0 non_field_count = 0
for field in self.model_field_ids: for field in self.model_field_ids:
if field.name == 'name' or field.name == 'display_name': if field.name == "name" or field.name == "display_name":
person = self.find_person_name() person = self.find_person_name()
if not person: if not person:
raise ValidationError(_("Partner name cannot find")) raise ValidationError(_("Partner name cannot find"))
field_value = True field_value = True
elif field.name == 'phone': elif field.name == "phone":
phone = re.findall(phone_pattern, self.data) phone = re.findall(phone_pattern, self.data)
if phone: if phone:
phone_number = phone[0] phone_number = phone[0]
elif field.name == 'email': elif field.name == "email":
email = re.findall(email_pattern, self.data) email = re.findall(email_pattern, self.data)
if email: if email:
email_address = email[0] email_address = email[0]
@ -232,54 +250,59 @@ class OCRDataTemplate(models.TransientModel):
if not field_value and non_field_count == 1: if not field_value and non_field_count == 1:
raise ValidationError(_("No data to map into the field")) raise ValidationError(_("No data to map into the field"))
if person: if person:
partner = self.env['res.partner'].search( partner = self.env["res.partner"].search(
[('name', '=', person)], limit=1) [("name", "=", person)], limit=1
)
if not partner: if not partner:
# Creating record in res.partner # Creating record in res.partner
partner_record = self.env['res.partner'].create({ partner_record = self.env["res.partner"].create(
'name': person, {"name": person, "email": email_address, "phone": phone_number}
'email': email_address, )
'phone': phone_number
})
else: else:
raise ValidationError(_("Partner already exist")) raise ValidationError(_("Partner already exist"))
else: else:
raise ValidationError(_("Name field is not chosen to create" raise ValidationError(
" partner")) _("Name field is not chosen to create" " partner")
)
if partner_record: if partner_record:
return { return {
'name': "Partner", "name": "Partner",
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'view_type': 'form', "view_type": "form",
'view_mode': 'form', "view_mode": "form",
'res_model': 'res.partner', "res_model": "res.partner",
'res_id': partner_record.id, "res_id": partner_record.id,
'view_id': self.env.ref('base.view_partner_form').id, "view_id": self.env.ref("base.view_partner_form").id,
'target': 'current', "target": "current",
} }
elif self.model_name_id.name == 'Journal Entry': elif self.model_name_id.name == "Journal Entry":
# Mapping data into Journal Entry. Creating a record in vendor bill # Mapping data into Journal Entry. Creating a record in vendor bill
vendor_bill_flag = False vendor_bill_flag = False
for field in self.model_field_ids: for field in self.model_field_ids:
# Taking the file path from ir.attachment # Taking the file path from ir.attachment
if field.name == 'invoice_vendor_bill_id': if field.name == "invoice_vendor_bill_id":
vendor_bill_flag = True vendor_bill_flag = True
try: try:
file_attachment = self.env["ir.attachment"].search( file_attachment = self.env["ir.attachment"].search(
['|', ('res_field', '!=', False), [
('res_field', '=', False), "|",
('res_id', '=', self.id), ("res_field", "!=", False),
('res_model', '=', 'ocr.data.template')], ("res_field", "=", False),
limit=1) ("res_id", "=", self.id),
("res_model", "=", "ocr.data.template"),
],
limit=1,
)
file_path = file_attachment._full_path( file_path = file_attachment._full_path(
file_attachment.store_fname) file_attachment.store_fname
with open(file_path, mode='rb') as f: )
with open(file_path, mode="rb") as f:
binary_data = f.read() binary_data = f.read()
img = Image.open(io.BytesIO(binary_data)) img = Image.open(io.BytesIO(binary_data))
# Resizing the image to improve the clarity # Resizing the image to improve the clarity
resized_img = img.resize( resized_img = img.resize(
(img.width * 2, img.height * 2), (img.width * 2, img.height * 2), resample=Image.BICUBIC
resample=Image.BICUBIC) )
except Exception: except Exception:
raise ValidationError(_("Can't create vendor bill")) raise ValidationError(_("Can't create vendor bill"))
# Converting the image into text using OCR python package # Converting the image into text using OCR python package
@ -288,41 +311,46 @@ class OCRDataTemplate(models.TransientModel):
text = pytesseract.image_to_string(resized_img) text = pytesseract.image_to_string(resized_img)
except Exception: except Exception:
raise ValidationError(_("Can't create vendor bill")) raise ValidationError(_("Can't create vendor bill"))
bill = self.env['digitize.bill'] bill = self.env["digitize.bill"]
# Calling the function to create vendor bill # Calling the function to create vendor bill
# from model digitize.bill # from model digitize.bill
bill_record = bill.create_record(text) bill_record = bill.create_record(text)
return { return {
'name': "Bill", "name": "Bill",
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'view_type': 'form', "view_type": "form",
'view_mode': 'form', "view_mode": "form",
'res_model': 'account.move', "res_model": "account.move",
'res_id': bill_record.id, "res_id": bill_record.id,
'view_id': self.env.ref('account.view_move_form').id, "view_id": self.env.ref("account.view_move_form").id,
'target': 'current', "target": "current",
} }
if not vendor_bill_flag: if not vendor_bill_flag:
raise ValidationError(_("No data to map into the field")) raise ValidationError(_("No data to map into the field"))
elif self.model_name_id.name == 'Employee': elif self.model_name_id.name == "Employee":
# Mapping the data into Employee module by fetching person name, # Mapping the data into Employee module by fetching person name,
# phone number and email # phone number and email
field_value = False field_value = False
non_field_count = 0 non_field_count = 0
for field in self.model_field_ids: for field in self.model_field_ids:
if field.name == 'name' or field.name == 'display_name' or \ if (
field.name == 'emergency_contact': field.name == "name"
or field.name == "display_name"
or field.name == "emergency_contact"
):
person = self.find_person_name() person = self.find_person_name()
if not person: if not person:
raise ValidationError(_("Employee name cannot find")) raise ValidationError(_("Employee name cannot find"))
field_value = True field_value = True
elif field.name == 'work_phone' or field.name == 'phone' or \ elif (
field.name == 'emergency_phone': field.name == "work_phone"
or field.name == "phone"
or field.name == "emergency_phone"
):
phone = re.findall(phone_pattern, self.data) phone = re.findall(phone_pattern, self.data)
if phone: if phone:
phone_number = phone[0] phone_number = phone[0]
elif field.name == 'private_email' or \ elif field.name == "private_email" or field.name == "work_email":
field.name == 'work_email':
email = re.findall(email_pattern, self.data) email = re.findall(email_pattern, self.data)
if email: if email:
email_address = email[0] email_address = email[0]
@ -331,177 +359,197 @@ class OCRDataTemplate(models.TransientModel):
if not field_value and non_field_count == 1: if not field_value and non_field_count == 1:
raise ValidationError(_("No data to map into the field")) raise ValidationError(_("No data to map into the field"))
if person: if person:
partner = self.env['hr.employee'].search( partner = self.env["hr.employee"].search(
[('name', '=', person)], limit=1) [("name", "=", person)], limit=1
)
if not partner: if not partner:
# Creating a record in hr.employee by mapping the # Creating a record in hr.employee by mapping the
# data into employee name, work phone and work email # data into employee name, work phone and work email
employee_record = self.env['hr.employee'].create({ employee_record = self.env["hr.employee"].create(
'name': person, {
'work_email': email_address, "name": person,
'work_phone': phone_number "work_email": email_address,
}) "work_phone": phone_number,
}
)
else: else:
raise ValidationError(_("Employee already exist")) raise ValidationError(_("Employee already exist"))
else: else:
raise ValidationError( raise ValidationError(_("Name field is not chosen to create employee"))
_("Name field is not chosen to create employee"))
if employee_record: if employee_record:
return { return {
'name': "Employee", "name": "Employee",
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'view_type': 'form', "view_type": "form",
'view_mode': 'form', "view_mode": "form",
'res_model': 'hr.employee', "res_model": "hr.employee",
'res_id': employee_record.id, "res_id": employee_record.id,
'view_id': self.env.ref('hr.view_employee_form').id, "view_id": self.env.ref("hr.view_employee_form").id,
'target': 'current', "target": "current",
} }
elif self.model_name_id.name == 'Expense': elif self.model_name_id.name == "Expense":
# Mapping the data into Expense module # Mapping the data into Expense module
expense_product = False expense_product = False
for field in self.model_field_ids: for field in self.model_field_ids:
if field.name == 'name' or field.name == 'product_id': if field.name == "name" or field.name == "product_id":
expense_product = True expense_product = True
product = self.env['product.product'].search( product = self.env["product.product"].search(
[('name', '=', 'BILL EXPENSE')], limit=1) [("name", "=", "BILL EXPENSE")], limit=1
)
if not product: if not product:
product = self.env['product.product'].create({ product = self.env["product.product"].create(
'name': 'BILL EXPENSE', {
}) "name": "BILL EXPENSE",
expense_record = self.env['hr.expense'].create({ }
'product_id': product.id, )
}) expense_record = self.env["hr.expense"].create(
{
"product_id": product.id,
}
)
return { return {
'name': "Expense", "name": "Expense",
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'view_type': 'form', "view_type": "form",
'view_mode': 'form', "view_mode": "form",
'res_model': 'hr.expense', "res_model": "hr.expense",
'res_id': expense_record.id, "res_id": expense_record.id,
'view_id': self.env.ref( "view_id": self.env.ref("hr_expense.hr_expense_view_form").id,
'hr_expense.hr_expense_view_form').id, "target": "current",
'target': 'current',
} }
if not expense_product: if not expense_product:
raise ValidationError(_("Can't create an expense without " raise ValidationError(
"description or category")) _("Can't create an expense without " "description or category")
elif self.model_name_id.name == 'Sales Order': )
elif self.model_name_id.name == "Sales Order":
# Mapping the data from PDF with proper format into Sale Order # Mapping the data from PDF with proper format into Sale Order
sale_order = '' sale_order = ""
partner = False partner = False
field_value = False field_value = False
non_field_value = 0 non_field_value = 0
for field in self.model_field_ids: for field in self.model_field_ids:
if field.name == 'order_line': if field.name == "order_line":
field_value = True field_value = True
person = self.find_person_name() person = self.find_person_name()
if person: if person:
partner = self.env['hr.employee'].search( partner = self.env["hr.employee"].search(
[('name', '=', person)], limit=1) [("name", "=", person)], limit=1
)
if not partner: if not partner:
partner = self.env['hr.employee'].create({ partner = self.env["hr.employee"].create(
'name': person, {
}) "name": person,
}
)
# Calling the function to get order lines # Calling the function to get order lines
product_line = self.get_order_line(self.data) product_line = self.get_order_line(self.data)
sale_order = self.env['sale.order'].create({ sale_order = self.env["sale.order"].create(
'partner_id': partner.id, {
}) "partner_id": partner.id,
}
)
if product_line: if product_line:
for item in product_line: for item in product_line:
if 'quantity' not in item.keys(): if "quantity" not in item.keys():
item.update({'quantity': 0}) item.update({"quantity": 0})
if 'price' not in item.keys(): if "price" not in item.keys():
item.update({'price': 0}) item.update({"price": 0})
product = self.env['product.product'].search( product = self.env["product.product"].search(
[('name', '=', item['product'])], limit=1) [("name", "=", item["product"])], limit=1
)
if not product: if not product:
product = self.env['product.product'].create({ product = self.env["product.product"].create(
'name': item['product'] {"name": item["product"]}
}) )
item.update({'product': product.id}) item.update({"product": product.id})
self.env['sale.order.line'].create({ self.env["sale.order.line"].create(
'order_id': sale_order.id, {
'product_id': item['product'], "order_id": sale_order.id,
'product_uom_qty': item['quantity'], "product_id": item["product"],
'price_unit': item['price'] "product_uom_qty": item["quantity"],
}) "price_unit": item["price"],
}
)
else: else:
non_field_value = 1 non_field_value = 1
if sale_order: if sale_order:
return { return {
'name': "Sale order", "name": "Sale order",
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'view_type': 'form', "view_type": "form",
'view_mode': 'form', "view_mode": "form",
'res_model': 'sale.order', "res_model": "sale.order",
'res_id': sale_order.id, "res_id": sale_order.id,
'view_id': self.env.ref('sale.view_order_form').id, "view_id": self.env.ref("sale.view_order_form").id,
'target': 'current', "target": "current",
} }
if not field_value and non_field_value == 1: if not field_value and non_field_value == 1:
raise ValidationError(_("No data to map into the field")) raise ValidationError(_("No data to map into the field"))
elif self.model_name_id.name == 'Purchase Order': elif self.model_name_id.name == "Purchase Order":
# Mapping the data from PDF with proper format into Purchase Order # Mapping the data from PDF with proper format into Purchase Order
purchase_order = '' purchase_order = ""
field_value = False field_value = False
non_field_value = 0 non_field_value = 0
partner = False partner = False
for field in self.model_field_ids: for field in self.model_field_ids:
if field.name == 'order_line': if field.name == "order_line":
field_value = True field_value = True
person = self.find_person_name() person = self.find_person_name()
if person: if person:
partner = self.env['hr.employee'].search( partner = self.env["hr.employee"].search(
[('name', '=', person)], limit=1) [("name", "=", person)], limit=1
)
if not partner: if not partner:
partner = self.env['hr.employee'].create({ partner = self.env["hr.employee"].create(
'name': person, {
}) "name": person,
}
)
# Calling the function to get order lines # Calling the function to get order lines
product_line = self.get_order_line(self.data) product_line = self.get_order_line(self.data)
purchase_order = self.env['purchase.order'].create({ purchase_order = self.env["purchase.order"].create(
'partner_id': partner.id, {
}) "partner_id": partner.id,
}
)
if product_line: if product_line:
for item in product_line: for item in product_line:
if 'quantity' not in item.keys(): if "quantity" not in item.keys():
item.update({'quantity': 0}) item.update({"quantity": 0})
if 'price' not in item.keys(): if "price" not in item.keys():
item.update({'price': 0}) item.update({"price": 0})
product = self.env['product.product'].search( product = self.env["product.product"].search(
[('name', '=', item['product'])], limit=1) [("name", "=", item["product"])], limit=1
)
if not product: if not product:
product = self.env['product.product'].create({ product = self.env["product.product"].create(
'name': item['product'] {"name": item["product"]}
}) )
item.update({'product': product.id}) item.update({"product": product.id})
self.env['purchase.order.line'].create({ self.env["purchase.order.line"].create(
'order_id': purchase_order.id, {
'product_id': item['product'], "order_id": purchase_order.id,
'product_uom_qty': item['quantity'], "product_id": item["product"],
'price_unit': item['price'] "product_uom_qty": item["quantity"],
}) "price_unit": item["price"],
}
)
else: else:
non_field_value = 1 non_field_value = 1
if purchase_order: if purchase_order:
return { return {
'name': "Purchase order", "name": "Purchase order",
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'view_type': 'form', "view_type": "form",
'view_mode': 'form', "view_mode": "form",
'res_model': 'purchase.order', "res_model": "purchase.order",
'res_id': purchase_order.id, "res_id": purchase_order.id,
'view_id': self.env.ref( "view_id": self.env.ref("purchase.purchase_order_form").id,
'purchase.purchase_order_form').id, "target": "current",
'target': 'current',
} }
if not field_value and non_field_value == 1: if not field_value and non_field_value == 1:
raise ValidationError(_("No data to map into the field")) raise ValidationError(_("No data to map into the field"))
@api.onchange('image') @api.onchange("image")
def _onchange_image(self): def _onchange_image(self):
self.write({ self.write({"image2": self.image})
'image2': self.image
})

Loading…
Cancel
Save