diff --git a/pms_api_rest/datamodels/pms_ocr.py b/pms_api_rest/datamodels/pms_ocr.py index 205e6dbb2..5e30cd700 100644 --- a/pms_api_rest/datamodels/pms_ocr.py +++ b/pms_api_rest/datamodels/pms_ocr.py @@ -5,7 +5,9 @@ from odoo.addons.datamodel.core import Datamodel class PmsOcrInput(Datamodel): _name = "pms.ocr.input" - imageBase64 = fields.String(required=True, allow_none=False) + imageBase64Front = fields.String(required=True, allow_none=False) + imageBase64Back = fields.String(required=False, allow_none=False) + pmsPropertyId = fields.Integer(required=True, allow_none=False) class PmsOcrCheckinResult(Datamodel): @@ -24,3 +26,5 @@ class PmsOcrCheckinResult(Datamodel): residenceStreet = fields.String(required=False, allow_none=True) residenceCity = fields.String(required=False, allow_none=True) countryState = fields.Integer(required=False, allow_none=True) + documentCountryId = fields.Integer(required=False, allow_none=True) + zip = fields.String(required=False, allow_none=True) diff --git a/pms_api_rest/datamodels/pms_property.py b/pms_api_rest/datamodels/pms_property.py index fb1c4e573..248a19b00 100644 --- a/pms_api_rest/datamodels/pms_property.py +++ b/pms_api_rest/datamodels/pms_property.py @@ -39,3 +39,4 @@ class PmsPropertyInfo(Datamodel): ineCategory = fields.String(required=False, allow_none=True) cardexWarning = fields.String(required=False, allow_none=True) companyPrivacyPolicy = fields.String(required=False, allow_none=True) + isUsedOCR = fields.Boolean(required=True, allow_none=False) diff --git a/pms_api_rest/models/pms_property.py b/pms_api_rest/models/pms_property.py index 384249d11..37a585839 100644 --- a/pms_api_rest/models/pms_property.py +++ b/pms_api_rest/models/pms_property.py @@ -111,6 +111,12 @@ class PmsProperty(models.Model): inverse_name="pms_property_id", ) + ocr_checkin_supplier = fields.Selection( + string="OCR Checkin Supplier", + help="Select ocr supplier for checkin documents", + selection=[], + ) + # PUSH API NOTIFICATIONS def get_payload_avail(self, avails, client): self.ensure_one() diff --git a/pms_api_rest/services/__init__.py b/pms_api_rest/services/__init__.py index f280265d1..be5f21758 100644 --- a/pms_api_rest/services/__init__.py +++ b/pms_api_rest/services/__init__.py @@ -44,3 +44,4 @@ from . import pms_avail_service from . import pms_user_service from . import pms_dashboard_service from . import feed_post_service +from . import ocr_document_service diff --git a/pms_ocr_regula/services/ocr_document_service.py b/pms_api_rest/services/ocr_document_service.py similarity index 58% rename from pms_ocr_regula/services/ocr_document_service.py rename to pms_api_rest/services/ocr_document_service.py index a11d48813..bb518e0ed 100644 --- a/pms_ocr_regula/services/ocr_document_service.py +++ b/pms_api_rest/services/ocr_document_service.py @@ -34,130 +34,33 @@ class PmsOcr(Component): output_param=Datamodel("pms.ocr.checkin.result", is_list=False), auth="jwt_api_pms", ) - def process_ocr_document_regula(self, input_param): - PmsOcrCheckinResult = self.env.datamodels["pms.ocr.checkin.result"] - pms_ocr_checkin_result = PmsOcrCheckinResult() - ocr_regula_url = ( - self.env["ir.config_parameter"].sudo().get_param("ocr_regula_url") + def process_ocr_document(self, input_param): + pms_property = self.env['pms.property'].browse(input_param.pmsPropertyId) + ocr_find_method_name = '_%s_document_process' % pms_property.ocr_checkin_supplier + checkin_data_dict = hasattr(self, ocr_find_method_name)( + input_param.imageBase64Front, + input_param.imageBase64Back + ) + PmsOcrCheckinResult = self.env.datamodels["pms.ocr.checkin.result"] + + return PmsOcrCheckinResult( + nationality=checkin_data_dict.get('nationality') or None, + countryId=checkin_data_dict.get('country_id') or None, + firstname=checkin_data_dict.get('firstname') or None, + lastname=checkin_data_dict.get('lastname') or None, + lastname2=checkin_data_dict.get('lastname2') or None, + gender=checkin_data_dict.get('gender') or None, + birthdate=checkin_data_dict.get('gender') or None, + documentType=checkin_data_dict.get('document_type') or None, + documentExpeditionDate=checkin_data_dict.get('document_expedition_date') or None, + documentSupportNumber=checkin_data_dict.get('document_support_number') or None, + documentNumber=checkin_data_dict.get('document_number') or None, + residenceStreet=checkin_data_dict.get('residence_street') or None, + residenceCity=checkin_data_dict.get('residence_city') or None, + countryState=checkin_data_dict.get('country_state') or None, + documentCountryId=checkin_data_dict.get('document_country_id') or None, + zip=checkin_data_dict.get('zip') or None ) - with DocumentReaderApi(host=ocr_regula_url) as api: - params = ProcessParams( - scenario=Scenario.FULL_PROCESS, - result_type_output=[ - Result.TEXT, - Result.STATUS, - Result.VISUAL_TEXT, - Result.DOCUMENT_TYPE, - ], - ) - request = RecognitionRequest( - process_params=params, images=[input_param.imageBase64] - ) - response = api.process(request) - if response.text and response.text.field_list: - # for elemento in response.text.field_list: - # print("campo: ", elemento.field_name) - # print("valor: ", elemento.value) - # print('-') - id_country_spain = ( - self.env["res.country"].search([("code", "=", "ES")]).id - ) - country_id = self.process_nationality( - response.text.get_field(TextFieldType.NATIONALITY), - response.text.get_field(TextFieldType.NATIONALITY_CODE), - response.text.get_field(TextFieldType.NATIONALITY_CODE_NUMERIC), - ) - firstname, lastname, lastname2 = self.process_name( - id_country_spain, - country_id, - response.text.get_field(TextFieldType.GIVEN_NAMES), - response.text.get_field(TextFieldType.FIRST_SURNAME), - response.text.get_field(TextFieldType.SECOND_SURNAME), - response.text.get_field(TextFieldType.SURNAME), - response.text.get_field(TextFieldType.SURNAME_AND_GIVEN_NAMES), - ) - if country_id: - pms_ocr_checkin_result.nationality = country_id - if firstname: - pms_ocr_checkin_result.firstname = firstname - if lastname: - pms_ocr_checkin_result.lastname = lastname - if lastname2: - pms_ocr_checkin_result.lastname2 = lastname2 - gender = response.text.get_field(TextFieldType.SEX) - if gender and gender.value != "": - pms_ocr_checkin_result.gender = ( - "male" - if gender.value == "M" - else "female" - if gender.value == "F" - else "other" - ) - date_of_birth = response.text.get_field(TextFieldType.DATE_OF_BIRTH) - if date_of_birth and date_of_birth.value != "": - pms_ocr_checkin_result.birthdate = ( - datetime.strptime( - date_of_birth.value.replace("-", "/"), "%Y/%m/%d" - ) - .date() - .isoformat() - ) - date_of_expiry = response.text.get_field(TextFieldType.DATE_OF_EXPIRY) - age = response.text.get_field(TextFieldType.AGE) - document_class_code = response.text.get_field( - TextFieldType.DOCUMENT_CLASS_CODE - ) - if ( - document_class_code - and document_class_code.value != "" - and document_class_code.value == "P" - ): - pms_ocr_checkin_result.documentType = ( - self.env["res.partner.id_category"] - .search([("code", "=", "P")]) - .id - ) - date_of_issue = response.text.get_field(TextFieldType.DATE_OF_ISSUE) - if country_id == id_country_spain and ( - not date_of_issue or date_of_issue.value == "" - ): - date_of_issue = self.calc_expedition_date( - document_class_code, - date_of_expiry, - age, - date_of_birth, - ) - pms_ocr_checkin_result.documentExpeditionDate = date_of_issue - elif date_of_issue and date_of_issue.value != "": - pms_ocr_checkin_result.documentExpeditionDate = ( - date_of_issue.value.replace("-", "/") - ) - support_number, document_number = self.proccess_document_number( - id_country_spain, - country_id, - document_class_code, - response.text.get_field(TextFieldType.DOCUMENT_NUMBER), - response.text.get_field(TextFieldType.PERSONAL_NUMBER), - ) - if support_number: - pms_ocr_checkin_result.documentSupportNumber = support_number - if document_number: - pms_ocr_checkin_result.documentNumber = document_number - address_street, address_city, address_area = self.process_address( - id_country_spain, - country_id, - response.text.get_field(TextFieldType.ADDRESS_STREET), - response.text.get_field(TextFieldType.ADDRESS_CITY), - response.text.get_field(TextFieldType.ADDRESS_AREA), - response.text.get_field(TextFieldType.ADDRESS), - ) - if address_street: - pms_ocr_checkin_result.residenceStreet = address_street - if address_city: - pms_ocr_checkin_result.residenceCity = address_city - if address_area: - pms_ocr_checkin_result.countryState = address_area - return pms_ocr_checkin_result def process_nationality( self, nationality, nationality_code, nationality_code_numeric diff --git a/pms_api_rest/services/pms_property_service.py b/pms_api_rest/services/pms_property_service.py index f8ba1489f..af59acc70 100644 --- a/pms_api_rest/services/pms_property_service.py +++ b/pms_api_rest/services/pms_property_service.py @@ -76,6 +76,7 @@ class PmsPropertyService(Component): simpleInColor=prop.simple_in_color, simpleFutureColor=prop.simple_future_color, language=prop.lang, + isUsedOCR=True if prop.ocr_checkin_supplier else False, hotelImageUrl=url_image_pms_api_rest( "pms.property", prop.id, "hotel_image_pms_api_rest" ), @@ -159,6 +160,7 @@ class PmsPropertyService(Component): companyPrivacyPolicy=privacy_policy if pms_property.company_id.privacy_policy else None, + isUsedOCR=True if pms_property.ocr_checkin_supplier else False, ) return res diff --git a/pms_ocr_regula/datamodels/__init__.py b/pms_ocr_regula/datamodels/__init__.py deleted file mode 100644 index 9216f6ffd..000000000 --- a/pms_ocr_regula/datamodels/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import pms_property diff --git a/pms_ocr_regula/datamodels/pms_property.py b/pms_ocr_regula/datamodels/pms_property.py deleted file mode 100644 index 15a988cb0..000000000 --- a/pms_ocr_regula/datamodels/pms_property.py +++ /dev/null @@ -1,8 +0,0 @@ -from marshmallow import fields - -from odoo.addons.datamodel.core import Datamodel - - -class PmsPropertyInfo(Datamodel): - _inherit = "pms.property.info" - isUsedRegula = fields.Boolean(required=False, allow_none=True) diff --git a/pms_ocr_regula/models/pms_property.py b/pms_ocr_regula/models/pms_property.py index c5530fcae..abd24850a 100644 --- a/pms_ocr_regula/models/pms_property.py +++ b/pms_ocr_regula/models/pms_property.py @@ -1,9 +1,337 @@ +from regula.documentreader.webclient import ( + DocumentReaderApi, + ProcessParams, + RecognitionRequest, + Result, + Scenario, + TextFieldType, +) +from datetime import date, datetime +from dateutil.relativedelta import relativedelta + from odoo import fields, models + class PmsProperty(models.Model): _inherit = "pms.property" - is_used_regula = fields.Boolean( - string="Used regula", help="True if this property uses regula's OCR" + ocr_checkin_supplier = fields.Selection( + selection_add=["regula", "Regula"] ) + + def _regula_document_process(self, image_base_64_front, image_base_64_back=False): + ocr_regula_url = ( + self.env["ir.config_parameter"].sudo().get_param("ocr_regula_url") + ) + with DocumentReaderApi(host=ocr_regula_url) as api: + params = ProcessParams( + scenario=Scenario.FULL_PROCESS, + result_type_output=[ + Result.TEXT, + Result.STATUS, + Result.VISUAL_TEXT, + Result.DOCUMENT_TYPE, + ], + ) + request = RecognitionRequest( + process_params=params, images=[image_base_64_front] + ) + response = api.process(request) + if response.text and response.text.field_list: + id_country_spain = ( + self.env["res.country"].search([("code", "=", "ES")]).id + ) + country_id = self._process_nationality( + response.text.get_field(TextFieldType.NATIONALITY), + response.text.get_field(TextFieldType.NATIONALITY_CODE), + response.text.get_field(TextFieldType.NATIONALITY_CODE_NUMERIC), + ) + firstname, lastname, lastname2 = self._process_name( + id_country_spain, + country_id, + response.text.get_field(TextFieldType.GIVEN_NAMES), + response.text.get_field(TextFieldType.FIRST_SURNAME), + response.text.get_field(TextFieldType.SECOND_SURNAME), + response.text.get_field(TextFieldType.SURNAME), + response.text.get_field(TextFieldType.SURNAME_AND_GIVEN_NAMES), + ) + pms_ocr_checkin_result = dict() + if country_id: + pms_ocr_checkin_result['nationality'] = country_id + if firstname: + pms_ocr_checkin_result['firstname'] = firstname + if lastname: + pms_ocr_checkin_result['lastname'] = lastname + if lastname2: + pms_ocr_checkin_result['lastname2'] = lastname2 + gender = response.text.get_field(TextFieldType.SEX) + if gender and gender.value != "": + pms_ocr_checkin_result['gender'] = ( + "male" + if gender.value == "M" + else "female" + if gender.value == "F" + else "other" + ) + date_of_birth = response.text.get_field(TextFieldType.DATE_OF_BIRTH) + if date_of_birth and date_of_birth.value != "": + pms_ocr_checkin_result['birthdate'] = ( + datetime.strptime( + date_of_birth.value.replace("-", "/"), "%Y/%m/%d" + ) + .date() + .isoformat() + ) + date_of_expiry = response.text.get_field(TextFieldType.DATE_OF_EXPIRY) + age = response.text.get_field(TextFieldType.AGE) + document_class_code = response.text.get_field( + TextFieldType.DOCUMENT_CLASS_CODE + ) + if ( + document_class_code + and document_class_code.value != "" + and document_class_code.value == "P" + ): + pms_ocr_checkin_result['documentType'] = ( + self.env["res.partner.id_category"] + .search([("code", "=", "P")]) + .id + ) + date_of_issue = response.text.get_field(TextFieldType.DATE_OF_ISSUE) + if country_id == id_country_spain and ( + not date_of_issue or date_of_issue.value == "" + ): + date_of_issue = self._calc_expedition_date( + document_class_code, + date_of_expiry, + age, + date_of_birth, + ) + pms_ocr_checkin_result['documentExpeditionDate'] = date_of_issue + elif date_of_issue and date_of_issue.value != "": + pms_ocr_checkin_result['documentExpeditionDate'] = ( + date_of_issue.value.replace("-", "/") + ) + support_number, document_number = self._proccess_document_number( + id_country_spain, + country_id, + document_class_code, + response.text.get_field(TextFieldType.DOCUMENT_NUMBER), + response.text.get_field(TextFieldType.PERSONAL_NUMBER), + ) + if support_number: + pms_ocr_checkin_result['documentSupportNumber'] = support_number + if document_number: + pms_ocr_checkin_result['documentNumber'] = document_number + address_street, address_city, address_area = self._process_address( + id_country_spain, + country_id, + response.text.get_field(TextFieldType.ADDRESS_STREET), + response.text.get_field(TextFieldType.ADDRESS_CITY), + response.text.get_field(TextFieldType.ADDRESS_AREA), + response.text.get_field(TextFieldType.ADDRESS), + ) + if address_street: + pms_ocr_checkin_result['residenceStreet'] = address_street + if address_city: + pms_ocr_checkin_result['residenceCity'] = address_city + if address_area: + pms_ocr_checkin_result['countryState'] = address_area + return pms_ocr_checkin_result + + def _process_nationality( + self, nationality, nationality_code, nationality_code_numeric + ): + country_id = False + country = False + if nationality_code_numeric and nationality_code_numeric.value != "": + country = self.env["res.country"].search( + [("code_numeric", "=", nationality_code_numeric.value)] + ) + elif nationality_code and nationality_code.value != "": + country = self.env["res.country"].search( + [("code_alpha3", "=", nationality_code.value)] + ) + elif nationality and nationality.value != "": + country = self.env["res.country"].search([("name", "=", nationality.value)]) + + if country: + country_id = country.id + + return country_id + + def _process_address( + self, + id_country_spain, + country_id, + address_street, + address_city, + address_area, + address, + ): + res_address_street = False + res_address_city = False + res_address_area = False + state = False + if country_id == id_country_spain: + if address_street and address_street.value != "": + res_address_street = address_street.value + if address_city and address_city.value != "": + res_address_city = address_city.value + if address_area and address_area.value != "": + res_address_area = address_area.value + if ( + address + and address != "" + and not (all([address_street, address_city, address_area])) + ): + address = address.value.replace("^", " ") + address_list = address.split(" ") + if not res_address_area: + res_address_area = address_list[-1] + if not res_address_city: + res_address_city = address_list[-2] + if not res_address_street: + res_address_street = address.replace( + res_address_area, "", 1 + ).replace(res_address_city, "", 1) + if res_address_area: + state = self.env["res.country.state"].search( + [("name", "ilike", res_address_area)] + ) + if state and len(state) == 1: + state = state.id + else: + if address and address.value != "": + res_address_street = address.value.replace("^", " ") + return res_address_street, res_address_city, state + + def _process_name( + self, + id_country_spain, + country_id, + given_names, + first_surname, + second_surname, + surname, + surname_and_given_names, + ): + firstname = False + lastname = False + lastname2 = False + + if surname_and_given_names.value and surname_and_given_names.value != "": + surname_and_given_names = surname_and_given_names.value.replace("^", " ") + + if given_names and given_names.value != "": + firstname = given_names.value + + if first_surname and first_surname.value != "": + lastname = first_surname.value + + if second_surname and second_surname.value != "": + lastname2 = second_surname.value + + if country_id == id_country_spain and not ( + all([firstname, lastname, lastname2]) + ): + if surname and surname.value != "": + lastname = lastname if lastname else surname.value.split(" ")[0] + lastname2 = lastname2 if lastname2 else surname.value.split(" ")[1:][0] + if ( + surname_and_given_names + and surname_and_given_names != "" + and not firstname + ): + firstname = surname_and_given_names.replace( + lastname, "", 1 + ).replace(lastname2, "", 1) + elif surname_and_given_names and surname_and_given_names != "": + lastname = ( + lastname if lastname else surname_and_given_names.split(" ")[0] + ) + lastname2 = ( + lastname2 if lastname2 else surname_and_given_names.split(" ")[1] + ) + firstname = ( + firstname + if firstname + else surname_and_given_names.replace(lastname, "", 1).replace( + lastname2, "", 1 + ) + ) + elif ( + country_id + and country_id != id_country_spain + and not (all([firstname, lastname])) + ): + if surname and surname.value != "": + lastname = lastname if lastname else surname.value + if ( + surname_and_given_names + and surname_and_given_names != "" + and not firstname + ): + firstname = surname_and_given_names.replace(lastname, "", 1) + elif surname_and_given_names and surname_and_given_names != "": + lastname = ( + lastname if lastname else surname_and_given_names.split(" ")[0] + ) + firstname = ( + firstname + if firstname + else surname_and_given_names.replace(lastname, "", 1) + ) + return firstname, lastname, lastname2 + + def _calc_expedition_date( + self, document_class_code, date_of_expiry, age, date_of_birth + ): + result = False + person_age = False + if age and age.value != "": + person_age = int(age.value) + elif date_of_birth and date_of_birth.value != "": + date_of_birth = datetime.strptime( + date_of_birth.value.replace("-", "/"), "%Y/%m/%d" + ).date() + person_age = relativedelta(date.today(), date_of_birth).years + if date_of_expiry and date_of_expiry.value != "" and person_age: + date_of_expiry = datetime.strptime( + date_of_expiry.value.replace("-", "/"), "%Y/%m/%d" + ).date() + if person_age < 30: + result = date_of_expiry - relativedelta(years=5) + elif ( + person_age >= 30 + and document_class_code + and document_class_code.value == "P" + ): + result = date_of_expiry - relativedelta(years=10) + elif 30 <= person_age < 70: + result = date_of_expiry - relativedelta(years=10) + return result.isoformat() if result else False + + def _proccess_document_number( + self, + id_country_spain, + country_id, + document_class_code, + document_number, + personal_number, + ): + res_support_number = False + res_document_number = False + if personal_number and personal_number.value != "": + res_document_number = personal_number.value + if document_number and document_number.value != "": + res_support_number = document_number.value + if ( + country_id == id_country_spain + and document_class_code + and document_class_code.value != "P" + ): + return res_support_number, res_document_number + else: + return False, res_support_number diff --git a/pms_ocr_regula/services/__init__.py b/pms_ocr_regula/services/__init__.py deleted file mode 100644 index 918dbaad5..000000000 --- a/pms_ocr_regula/services/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import ocr_document_service -from . import pms_property_service diff --git a/pms_ocr_regula/services/pms_property_service.py b/pms_ocr_regula/services/pms_property_service.py deleted file mode 100644 index 1e633dce8..000000000 --- a/pms_ocr_regula/services/pms_property_service.py +++ /dev/null @@ -1,26 +0,0 @@ -from odoo.addons.base_rest import restapi -from odoo.addons.base_rest_datamodel.restapi import Datamodel -from odoo.addons.component.core import Component - - -class PmsPropertyService(Component): - _inherit = "pms.property.service" - - @restapi.method( - [ - ( - [ - "/", - ], - "GET", - ) - ], - output_param=Datamodel("pms.property.info", is_list=True), - auth="jwt_api_pms", - ) - def get_properties(self): - result_properties = super(PmsPropertyService, self).get_properties() - for prop_info in result_properties: - pms_property = self.env["pms.property"].browse(prop_info.id) - prop_info.isUsedRegula = pms_property.is_used_regula - return result_properties