|
@ -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 |
|
|
|
|
|
}) |
|
|
|
|
|