diff --git a/pms_ocr_klippa/models/klippa_log.py b/pms_ocr_klippa/models/klippa_log.py index eeffdbf48..a3e0ddd0b 100644 --- a/pms_ocr_klippa/models/klippa_log.py +++ b/pms_ocr_klippa/models/klippa_log.py @@ -29,8 +29,8 @@ class KlippaLog(models.Model): help="Response", ) klippa_status = fields.Char( - string="Status", - help="Status", + string="Klippa Status", + help="Klippa Status", ) request_datetime = fields.Datetime( string="Request Date", @@ -84,6 +84,14 @@ class KlippaLog(models.Model): string="Error", help="Error", ) + nominatim_status = fields.Char( + string="Nominatim Status", + help="Nominatim Status", + ) + nominatim_response = fields.Text( + string="Nominatim Response", + help="Nominatim Response", + ) def clean_log_data(self, offset=60): """Clean log data older than the offset. diff --git a/pms_ocr_klippa/models/pms_property.py b/pms_ocr_klippa/models/pms_property.py index 082756413..ee5965506 100644 --- a/pms_ocr_klippa/models/pms_property.py +++ b/pms_ocr_klippa/models/pms_property.py @@ -12,6 +12,25 @@ _logger = logging.getLogger(__name__) NOMINATIM_URL = "https://nominatim.openstreetmap.org/search" +CHECKIN_FIELDS = { + "nationality": "partner_id.nationality_id.id", + "country_id": "partner_id.residence_country_id.id", + "firstname": "partner_id.firstname", + "lastname": "partner_id.lastname", + "lastname2": "partner_id.lastname2", + "gender": "partner_id.gender", + "birthdate": "partner_id.birthdate_date", + "document_type": "document_type_id.id", + "document_expedition_date": "document_expedition_date", + "document_support_number": "document_support_number", + "document_number": "name", + "residence_street": "partner_id.residence_street", + "residence_city": "partner_id.residence_city", + "country_state": "partner_id.residence_state_id.id", + "document_country_id": "document_country_id", + "zip": "partner_id.zip", +} + class PmsProperty(models.Model): _inherit = "pms.property" @@ -78,7 +97,24 @@ class PmsProperty(models.Model): raise ValidationError(_("Error calling Klippa OCR API")) document_data = json_data["data"]["parsed"] init_mapped_datetime = datetime.now() + mapped_data = self._map_klippa_data(document_data) + + if mapped_data.get("nominatim_status"): + log_data.update( + { + "nominatim_status": mapped_data["nominatim_status"], + } + ) + mapped_data.pop("nominatim_status") + if mapped_data.get("nominatim_response"): + log_data.update( + { + "nominatim_response": mapped_data["nominatim_response"], + } + ) + mapped_data.pop("nominatim_response") + log_data.update( { "service_response": mapped_data, @@ -107,18 +143,7 @@ class PmsProperty(models.Model): def _map_klippa_data(self, document_data): mapped_data = {} - found_partner = False - if document_data.get("personal_number", False): - found_partner = ( - self.env["res.partner.id_number"] - .search( - [ - ("name", "=", document_data["personal_number"]["value"]), - ], - limit=1, - ) - .partner_id - ) + key_document_number, key_personal_number = self._get_number_keys(document_data) for key, dict_value in document_data.items(): if dict_value and isinstance(dict_value, dict): value = dict_value.get("value", False) @@ -131,8 +156,6 @@ class PmsProperty(models.Model): # Document Data -------------------------------------------------- elif key == "issuing_country" and value: mapped_data["document_country_id"] = self._get_country_id(value) - elif key == "document_number" and value: - mapped_data["document_support_number"] = value elif key == "document_type" and value: mapped_data["document_type"] = self._get_document_type( klippa_type=value, @@ -141,9 +164,11 @@ class PmsProperty(models.Model): if document_data.get("issuing_country") else False ), - ) + ).id elif key == "personal_number" and value: - mapped_data["document_number"] = value + mapped_data[key_personal_number] = value + elif key == "document_number" and value: + mapped_data[key_document_number] = value elif key == "date_of_issue" and value: mapped_data["document_expedition_date"] = datetime.strptime( value, "%Y-%m-%dT%H:%M:%S" @@ -190,6 +215,21 @@ class PmsProperty(models.Model): ).date() elif key == "nationality" and value: mapped_data["nationality"] = self._get_country_id(value) + + # If the document number exist and not get the complete checkin information + # recovery the lost data from the found document + if mapped_data.get("document_number") and not all( + [mapped_data.get(field, False) for field in CHECKIN_FIELDS] + ): + document = self.env["res.partner.id_number"].search( + [ + ("name", "=", mapped_data["document_number"]), + ], + limit=1, + ) + if document: + mapped_data = self._complete_mapped_from_partner(document, mapped_data) + return mapped_data def _calc_expedition_date( @@ -220,23 +260,54 @@ class PmsProperty(models.Model): result = date_of_expiry - relativedelta(years=10) return result if result else False - def _get_document_type(self, klippa_type, country_id): - document_type_id = False - document_type_ids = self.env["res.partner.id_category"].search( - [ - ("klippa_code", "=", klippa_type), - ] - ) - if not document_type_ids: - raise ValidationError(_(f"Document type not found: {klippa_type}")) + def _get_number_keys(self, document_data): + # Heuristic to identify the mapping of document_number and document_support_number + # with respect to the personal_number and document_number fields of klippa + # If the klippa document type is "I", and it is Spanish, then the personal_number + # we map it against document_number and document_number against document_support_number + # otherwise, the document_number we map against document_number and the personal_number + # against document_support_number + key_document_number = "document_number" + key_personal_number = "document_support_number" + if ( + document_data.get("document_type", False) + and document_data.get("document_type").get("value") == "I" + and document_data.get("issuing_country", False) + and document_data.get("issuing_country").get("value") == "ESP" + ): + key_document_number = "document_support_number" + key_personal_number = "document_number" + return (key_document_number, key_personal_number) - if len(document_type_ids) > 1: - document_type_id = document_type_ids.filtered( - lambda r: country_id in r.country_ids.ids + def _get_document_type(self, klippa_type, country_id): + # If we hace the issuing country, and document type is configured in the system + # to be used with the country, we use the country to get the document type + # If have issuing country and not found document type, we search a document type + # without country + # If not have issuing country, we search the document only by klippa code + document_type = False + domain = [("klippa_code", "=", klippa_type)] + if country_id: + domain.append(("country_ids", "in", country_id)) + document_type = self.env["res.partner.id_category"].search(domain, limit=1) + if not document_type and country_id: + document_type = self.env["res.partner.id_category"].search( + [ + ("klippa_code", "=", klippa_type), + ("country_ids", "=", False), + ], + limit=1, ) - if not document_type_id: - document_type_id = document_type_ids[0] - return document_type_id[0] + elif not document_type: + document_type = self.env["res.partner.id_category"].search( + [ + ("klippa_code", "=", klippa_type), + ], + limit=1, + ) + if not document_type: + document_type = self.env.ref("pms.document_type_identification_document") + return document_type[0] if document_type else False def _get_country_id(self, country_code): if not country_code: @@ -346,86 +417,103 @@ class PmsProperty(models.Model): ) if address_data_dict.get("residence_city"): params["city"] = address_data_dict["residence_city"] + + # Try to complete the address with Nominatim API + try: + params = self._get_nominatim_address(params, street_name, mapped_data) + except Exception as e: + _logger.error(e) + mapped_data["nominatim_status"] = "error" + mapped_data["nominatim_response"] = str(e) + return mapped_data + + def _get_nominatim_address(self, params, street_name, mapped_data): + if street_name: + # Clean street name with mains words + street_words = street_name.split(" ") + params["street"] = " ".join( + [word for word in street_words if len(word) > 2] + ) + location = requests.get(NOMINATIM_URL, params=params) + if not location.json() or location.status_code != 200: + # If not found address, pop the street to try again if street_name: - # Clean street name with mains words - street_words = street_name.split(" ") - params["street"] = " ".join( - [word for word in street_words if len(word) > 2] - ) - location = requests.get(NOMINATIM_URL, params=params) - if not location.json() or location.status_code != 200: - # If not found address, pop the street to try again - if street_name: - params.pop("street") - location = requests.get(NOMINATIM_URL, params=params) - if location.json() and location.status_code == 200: - location = location.json()[0] - _logger.info(location) - if not mapped_data.get("zip", False): - mapped_data["zip"] = location.get("address", {}).get( - "postcode", False + params.pop("street") + location = requests.get(NOMINATIM_URL, params=params) + if location.json() and location.status_code == 200: + mapped_data["nominatim_response"] = location.json() + mapped_data["nominatim_status"] = "success" + location = location.json()[0] + _logger.info(location) + if not mapped_data.get("zip", False): + mapped_data["zip"] = location.get("address", {}).get("postcode", False) + if mapped_data["zip"]: + zip_code = self.env["res.city.zip"].search( + [("name", "=", mapped_data["zip"])] ) - if mapped_data["zip"]: - zip_code = self.env["res.city.zip"].search( - [("name", "=", mapped_data["zip"])] + if zip_code: + mapped_data["residence_city"] = zip_code.city_id.name + mapped_data["country_state"] = zip_code.city_id.state_id.id + mapped_data[ + "country_id" + ] = zip_code.city_id.state_id.country_id.id + if not mapped_data.get("country_id", False): + country_record = self.env["res.country"].search( + [ + ( + "code", + "=", + location.get("address", {}) + .get("country_code", False) + .upper(), ) - if zip_code: - mapped_data["residence_city"] = zip_code.city_id.name - mapped_data["country_state"] = zip_code.city_id.state_id.id - mapped_data[ - "country_id" - ] = zip_code.city_id.state_id.country_id.id - if not mapped_data.get("country_id", False): - country_record = self.env["res.country"].search( - [ - ( - "code", - "=", - location.get("address", {}) - .get("country_code", False) - .upper(), - ) - ] + ] + ) + if not country_record and location.get("address", {}).get( + "country", False + ): + country_match = process.extractOne( + location.get("address", {}).get("country", False), + self.env["res.country"] + .with_context(lang="en_US") + .search([]) + .mapped("name"), ) - if not country_record and location.get("address", {}).get( - "country", False - ): - country_match = process.extractOne( - location.get("address", {}).get("country", False), + if country_match[1] >= 90: + country_record = ( self.env["res.country"] .with_context(lang="en_US") - .search([]) - .mapped("name"), + .search([("name", "=", country_match[0])]) ) - if country_match[1] >= 90: - country_record = ( - self.env["res.country"] - .with_context(lang="en_US") - .search([("name", "=", country_match[0])]) - ) - mapped_data["country_id"] = country_record.id - if not mapped_data.get("country_state", False): - state_name = ( - location.get("address", {}).get("province") - if location.get("address", {}).get("province") - else location.get("address", {}).get("state") + mapped_data["country_id"] = country_record.id + if not mapped_data.get("country_state", False): + state_name = ( + location.get("address", {}).get("province") + if location.get("address", {}).get("province") + else location.get("address", {}).get("state") + ) + if state_name: + country_state_record = process.extractOne( + state_name, + self.env["res.country.state"].search([]).mapped("name"), ) - if state_name: - country_state_record = process.extractOne( - state_name, - self.env["res.country.state"].search([]).mapped("name"), + if country_state_record[1] >= 90: + country_state = self.env["res.country.state"].search( + [("name", "=", country_state_record[0])] ) - if country_state_record[1] >= 90: - country_state = self.env["res.country.state"].search( - [("name", "=", country_state_record[0])] - ) - mapped_data["country_state"] = country_state.id - if not mapped_data.get("residence_city", False): - mapped_data["residence_city"] = location.get("address", {}).get( - "city", False - ) - if not mapped_data.get("residence_street", False): - mapped_data["residence_street"] = location.get("address", {}).get( - "road", False - ) + mapped_data["country_state"] = country_state.id + if not mapped_data.get("residence_city", False): + mapped_data["residence_city"] = location.get("address", {}).get( + "city", False + ) + if not mapped_data.get("residence_street", False): + mapped_data["residence_street"] = location.get("address", {}).get( + "road", False + ) + return mapped_data + + def _complete_mapped_from_partner(self, document, mapped_data): + for key, field in CHECKIN_FIELDS.items(): + if not mapped_data.get(key, False) and document.mapped(field)[0]: + mapped_data[key] = document.mapped(field)[0] return mapped_data diff --git a/pms_ocr_klippa/views/klippa_log_views.xml b/pms_ocr_klippa/views/klippa_log_views.xml index 26e3d6035..8ca869a8c 100644 --- a/pms_ocr_klippa/views/klippa_log_views.xml +++ b/pms_ocr_klippa/views/klippa_log_views.xml @@ -27,6 +27,10 @@ + + + + @@ -34,6 +38,10 @@ + + + +