diff --git a/odk-connector/models/odk_submissions_model.py b/odk-connector/models/odk_submissions_model.py
index 65710ee..c18c60f 100644
--- a/odk-connector/models/odk_submissions_model.py
+++ b/odk-connector/models/odk_submissions_model.py
@@ -172,6 +172,7 @@ def create_registration_from_submission(self, data, extra_data=None):
].create_registration_from_odk(data)
return registration
except BaseException as e:
+ print(e)
print("Failed in creating registration!")
return None
diff --git a/openg2p/models/beneficiary_to_batch_wizard.py b/openg2p/models/beneficiary_to_batch_wizard.py
index 1607bb2..5303b17 100644
--- a/openg2p/models/beneficiary_to_batch_wizard.py
+++ b/openg2p/models/beneficiary_to_batch_wizard.py
@@ -124,6 +124,7 @@ def task_create_batch(self, batch_name, beneficiary_ids):
"date_end": datetime.now(),
"currency_id": bank_id[0].currency_id.id,
"payment_mode": bank_id[0].payment_mode,
+ "payment_address": b.payment_address,
}
)
m.generate_uuid()
diff --git a/openg2p/models/openg2p_beneficiary.py b/openg2p/models/openg2p_beneficiary.py
index 8d854ec..3ca6047 100644
--- a/openg2p/models/openg2p_beneficiary.py
+++ b/openg2p/models/openg2p_beneficiary.py
@@ -349,6 +349,7 @@ def _default_image(self):
)
odk_batch_id = fields.Char(default=lambda *args: uuid.uuid4().hex)
+ payment_address = fields.Char(string="Payment Address", required=False)
def api_json(self):
return {
@@ -466,7 +467,7 @@ def _compute_org_fields(self):
[
"&",
("beneficiary_id", "=", rec.id),
- ("field_name", "=", "grand_total_le"),
+ ("field_name", "=", "grand_total"),
]
)
try:
@@ -731,7 +732,7 @@ def _compute_email_formatted(self):
for beneficiary in self:
if beneficiary.email:
beneficiary.email_formatted = tools.formataddr(
- (beneficiary.name or u"False", beneficiary.email or u"False")
+ (beneficiary.name or "False", beneficiary.email or "False")
)
else:
beneficiary.email_formatted = ""
diff --git a/openg2p/services/matching_service.py b/openg2p/services/matching_service.py
index 083a929..2caf76d 100644
--- a/openg2p/services/matching_service.py
+++ b/openg2p/services/matching_service.py
@@ -83,7 +83,7 @@ def match(self, query):
for ID, number in query.get_identities()
)
matches = (
- self.with_context(active_test=False)
+ query.with_context(active_test=False)
.env["openg2p.beneficiary.id_number"]
.search(domain)
)
diff --git a/openg2p/views/openg2p_beneficiary.xml b/openg2p/views/openg2p_beneficiary.xml
index a41b899..2ce446e 100644
--- a/openg2p/views/openg2p_beneficiary.xml
+++ b/openg2p/views/openg2p_beneficiary.xml
@@ -160,10 +160,11 @@
+
+
-
@@ -190,7 +191,7 @@
-
+
diff --git a/openg2p_disbursement/models/openg2p_disbursement_batch.py b/openg2p_disbursement/models/openg2p_disbursement_batch.py
index 6ce54d6..f59f947 100644
--- a/openg2p_disbursement/models/openg2p_disbursement_batch.py
+++ b/openg2p_disbursement/models/openg2p_disbursement_batch.py
@@ -161,16 +161,12 @@ def _compute_can_generate(self):
@api.multi
def _compute_can_cancel(self):
self.ensure_one()
- self.can_cancel = (
- self.state
- in (
- "generating",
- "draft",
- "confirm",
- "approved",
- )
- and not isinstance(self.id, models.NewId)
- )
+ self.can_cancel = self.state in (
+ "generating",
+ "draft",
+ "confirm",
+ "approved",
+ ) and not isinstance(self.id, models.NewId)
@api.multi
def _compute_can_confirm(self):
diff --git a/openg2p_disbursement/models/openg2p_disbursement_rule.py b/openg2p_disbursement/models/openg2p_disbursement_rule.py
index f90687f..69d3755 100644
--- a/openg2p_disbursement/models/openg2p_disbursement_rule.py
+++ b/openg2p_disbursement/models/openg2p_disbursement_rule.py
@@ -25,7 +25,7 @@ class Openg2pDisbursementRule(models.Model):
default="1.0",
help="It is used in computation for percentage and fixed amount. "
"For e.g. A rule for Meal Voucher having fixed amount of "
- u"1€ per worked day can have its quantity defined in expression "
+ "1€ per worked day can have its quantity defined in expression "
"like days.WORK100.number_of_days.",
required=True,
)
diff --git a/openg2p_disbursement_advice/models/openg2p_disbursement_main.py b/openg2p_disbursement_advice/models/openg2p_disbursement_main.py
index ea025ca..3cea1a7 100644
--- a/openg2p_disbursement_advice/models/openg2p_disbursement_main.py
+++ b/openg2p_disbursement_advice/models/openg2p_disbursement_main.py
@@ -84,6 +84,7 @@ class DisbursementMain(models.Model):
required=False,
default="",
)
+ payment_address = fields.Char(string="Payment Address", required=False)
def generate_uuid(self):
for rec in self:
diff --git a/openg2p_disbursement_advice/views/openg2p_disbursement_main.xml b/openg2p_disbursement_advice/views/openg2p_disbursement_main.xml
index aa951f3..cf3a4d7 100644
--- a/openg2p_disbursement_advice/views/openg2p_disbursement_main.xml
+++ b/openg2p_disbursement_advice/views/openg2p_disbursement_main.xml
@@ -25,6 +25,7 @@
+
diff --git a/openg2p_registration/models/__init__.py b/openg2p_registration/models/__init__.py
index 03e5d68..7bc0deb 100644
--- a/openg2p_registration/models/__init__.py
+++ b/openg2p_registration/models/__init__.py
@@ -11,3 +11,4 @@
from . import openg2p_registration_org_map
from . import openg2p_registration_api
from . import openg2p_deduplication
+from . import openg2p_demographic_authentication
diff --git a/openg2p_registration/models/openg2p_demographic_authentication.py b/openg2p_registration/models/openg2p_demographic_authentication.py
new file mode 100644
index 0000000..26cbef5
--- /dev/null
+++ b/openg2p_registration/models/openg2p_demographic_authentication.py
@@ -0,0 +1,175 @@
+import requests
+import json
+import logging
+from odoo import models
+
+_logger = logging.getLogger(__name__)
+
+UN_SUCCESS_WITH_ERRORS = "Unsuccessful with Errors"
+SUCCESS_WITH_ERRORS = "Successful with Errors"
+SUCCESS = "Successful"
+
+
+class Openg2pDemographicAuthentication(models.Model):
+ _inherit = "openg2p.registration"
+
+ def demo_auth(self, data):
+ import os
+
+ DEMO_AUTHENTICATE_URL = os.getenv(
+ "DEMO_AUTHENTICATE_URL",
+ "http://openg2p-mosip-auth-mediator.openg2p-mosip/demoAuth",
+ )
+ response = requests.post(DEMO_AUTHENTICATE_URL, json=data)
+ _logger.info("Demo Auth Response: " + str(response.content))
+ return json.loads(response.content)
+
+ def demo_auth_merge(self, data):
+ auth_res = self.demo_auth(data)
+ should_merge = False
+ should_create_beneficiary = False
+ stage_id = 0
+ if auth_res["authIdStatus"] == SUCCESS:
+ stage_id = 6
+ should_merge = self.post_auth_find_duplicate_beneficiary(
+ auth_res["authId"], auth_res["authIdType"]
+ )
+ if not should_merge:
+ should_create_beneficiary = True
+ elif auth_res["authIdStatus"] == SUCCESS_WITH_ERRORS:
+ stage_id = 2
+ elif auth_res["authIdStatus"] == UN_SUCCESS_WITH_ERRORS:
+ stage_id = 2
+ return {
+ "stage_id": stage_id,
+ "should_merge": should_merge,
+ "should_create_beneficiary": should_create_beneficiary,
+ "auth_id": auth_res["authId"],
+ "auth_id_type": auth_res["authIdType"],
+ "auth_id_status": auth_res["authIdStatus"],
+ "auth_id_message": auth_res["authIdMessage"],
+ }
+
+ def post_auth_create_id(self, response):
+ return self.env["openg2p.registration.identity"].create(
+ {
+ "name": response["auth_id"],
+ "type": response["auth_id_type"],
+ "status": response["auth_id_status"],
+ "message": response["auth_id_message"],
+ "registration_id": self.id,
+ }
+ )
+ res = self.env["openg2p.registration.identity"].search(
+ [("registration_id", "=", self.id)]
+ )
+ if res:
+ self.write({"identities": res.ids})
+
+ def post_auth_find_duplicate_beneficiary(self, auth_id, auth_id_type):
+ type_code_id = (
+ self.env["openg2p.beneficiary.id_category"]
+ .search([("code", "=", auth_id_type)], limit=1)
+ .id
+ )
+ length = len(
+ self.env["openg2p.beneficiary.id_number"].search(
+ [("name", "=", auth_id), ("category_id", "=", type_code_id)]
+ )
+ )
+ _logger.info(f"auth_id : {auth_id}. Post Auth. Size of duplicates: {length}")
+ return length > 0
+
+ def post_auth_merge(self, response):
+ auth_id = response["auth_id"]
+ auth_id_type = response["auth_id_type"]
+
+ type_code_id = (
+ self.env["openg2p.beneficiary.id_category"]
+ .search([("code", "=", auth_id_type)], limit=1)
+ .id
+ )
+ auth_id_object = self.env["openg2p.beneficiary.id_number"].search(
+ [("name", "=", auth_id), ("category_id", "=", type_code_id)]
+ )
+ existing_beneficiary = auth_id_object.beneficiary_id
+ _logger.info(f"auth_id: {auth_id}. Entered Post Auth Merge.")
+ # Fields to be merged
+ overwrite_data = {
+ "firstname": self.firstname,
+ "lastname": self.lastname,
+ "location_id": self.location_id.id,
+ "street": self.street,
+ "street2": self.street2,
+ "city": self.city,
+ "state_id": self.state_id.id,
+ "zip": self.zip,
+ "country_id": self.country_id.id,
+ "phone": self.phone,
+ "mobile": self.mobile,
+ "email": self.email,
+ "lang": self.lang,
+ "image": self.image,
+ "marital": self.marital,
+ "bank_account_id": self.bank_account_id.id,
+ "emergency_contact": self.emergency_contact,
+ "emergency_phone": self.emergency_phone,
+ }
+ program_ids = self.program_ids.ids
+ # Removing None fields
+ cleaned_overwrite_data = self.del_none(overwrite_data)
+
+ # Deriving existing fields to create new beneficiary
+ existing_data = {
+ "firstname": existing_beneficiary.firstname,
+ "lastname": existing_beneficiary.lastname,
+ "othernames": existing_beneficiary.othernames,
+ "location_id": existing_beneficiary.location_id.id,
+ "street": existing_beneficiary.street,
+ "street2": existing_beneficiary.street2,
+ "city": existing_beneficiary.city,
+ "state_id": existing_beneficiary.state_id.id,
+ "zip": existing_beneficiary.zip,
+ "country_id": existing_beneficiary.country_id.id,
+ "phone": existing_beneficiary.phone,
+ "mobile": existing_beneficiary.mobile,
+ "email": existing_beneficiary.email,
+ "title": existing_beneficiary.title.id,
+ "lang": existing_beneficiary.lang,
+ "gender": existing_beneficiary.gender,
+ "birthday": existing_beneficiary.birthday,
+ "image": existing_beneficiary.image,
+ "marital": existing_beneficiary.marital,
+ "bank_account_id": existing_beneficiary.bank_account_id.id,
+ "emergency_contact": existing_beneficiary.emergency_contact,
+ "emergency_phone": existing_beneficiary.emergency_phone,
+ "program_ids": [
+ (4, program) for program in existing_beneficiary.program_ids.ids
+ ],
+ }
+
+ cleaned_existing_data = self.del_none(existing_data)
+
+ # Merging specfic fields to beneficiary
+ existing_beneficiary.write(cleaned_overwrite_data)
+
+ # Creating new beneficiary whose active=False
+ new_beneficiary = self.env["openg2p.beneficiary"].create(cleaned_existing_data)
+ # Create new registration with existing data
+ self.write({"beneficiary_id": existing_beneficiary.id})
+
+ # Storing merged id's in fields
+ existing_beneficiary.write(
+ {"merged_beneficiary_ids": [(4, new_beneficiary.id)]}
+ )
+ existing_beneficiary.write(
+ {"program_ids": [(4, program) for program in program_ids]}
+ )
+
+ # Setting active false
+ new_beneficiary.active = False
+
+ # self.clear_beneficiaries()
+
+ # Archiving the current Registration
+ # self.archive_registration()
diff --git a/openg2p_registration/models/openg2p_registration.py b/openg2p_registration/models/openg2p_registration.py
index 85d483f..fd9b09b 100644
--- a/openg2p_registration/models/openg2p_registration.py
+++ b/openg2p_registration/models/openg2p_registration.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
import json
+import string
import uuid
+import logging
import requests
from odoo.addons.openg2p.services.matching_service import (
@@ -12,6 +14,8 @@
from odoo.exceptions import UserError, ValidationError
from odoo.tools.translate import _
+_logger = logging.getLogger(__name__)
+
AVAILABLE_PRIORITIES = [("0", "Urgent"), ("1", "High"), ("2", "Normal"), ("3", "Low")]
@@ -206,6 +210,7 @@ def _default_company_id(self):
store=True,
required=False,
)
+
# will be return registration details on api call
def api_json(self):
data = {
@@ -305,7 +310,7 @@ def _compute_org_fields(self):
rec.total_equity = 0
field = self.env["openg2p.registration.orgmap"].search(
- ["&", ("regd_id", "=", rec.id), ("field_name", "=", "grand_total_le")]
+ ["&", ("regd_id", "=", rec.id), ("field_name", "=", "grand_total")]
)
try:
rec.grand_total = int(field.field_value) if field else 0
@@ -325,7 +330,7 @@ def _compute_org_fields(self):
else:
rec.school_approved = "yes"
except BaseException as e:
- print(e)
+ _logger.error(e)
rec.school_approved = "no"
# example for filtering on org custom fields
@@ -468,7 +473,7 @@ def _search_approved(self, operator, val2):
try:
val = rec.school_approved
except BaseException as e:
- print(e)
+ _logger.error(e)
continue
if operator == "=":
if val == val2:
@@ -503,9 +508,7 @@ def create_registration_from_odk(self, odk_data):
if not str(k).startswith("_"):
temp[str(k).replace("-", "_").lower()] = v
- country_name = (
- temp["country"] if "country" in temp.keys() else "Sierra Leone"
- )
+ country_name = temp["country"] if "country" in temp.keys() else "Sierra Leone"
state_name = temp["state"] if "state" in temp.keys() else "Freetown"
country_id = self.env["res.country"].search([("name", "=", country_name)])[0].id
@@ -513,6 +516,41 @@ def create_registration_from_odk(self, odk_data):
self.env["res.country.state"].search([("name", "=", state_name)])[0].id
)
+ _logger.info("Country ID:" + str(country_id) + " State ID:" + str(state_id))
+ # calling demo auth url with data
+ temp["lang"] = "en_US"
+
+ _logger.debug("Raw Data From ODK: " + json.dumps(temp))
+ # check both Bank Account No and Payment address are empty or filled
+ if "bank_account_number" in temp.keys() and "payment_address" in temp.keys():
+ if temp["bank_account_number"] is None and temp["payment_address"] is None:
+ raise Exception("Both the fields are empty")
+ return None
+ elif (
+ temp["bank_account_number"] is not None
+ and temp["payment_address"] is not None
+ ):
+ raise Exception("Both the fields are present")
+ return None
+ elif (
+ "bank_account_number" not in temp.keys()
+ and "payment_address" not in temp.keys()
+ ):
+ raise Exception("Both the fields are empty")
+ return None
+
+ import os
+
+ should_merge = False
+ should_create_beneficiary = False
+ demo_auth_res = {}
+ if os.getenv("SHOULD_DEMO_AUTH", "true").lower() == "true":
+ demo_auth_res = self.demo_auth_merge(temp)
+ temp["stage_id"] = demo_auth_res["stage_id"]
+ should_merge = demo_auth_res["should_merge"]
+ should_create_beneficiary = demo_auth_res["should_create_beneficiary"]
+ temp["gender"] = temp["gender"].lower()
+
try:
regd = self.create(
{
@@ -530,12 +568,19 @@ def create_registration_from_odk(self, odk_data):
else "Freetown",
"country_id": country_id,
"state_id": state_id,
- "gender": "male",
+ "gender": (temp["gender"] if "gender" in temp.keys() else "male"),
+ "stage_id": (
+ temp["stage_id"] if "stage_id" in temp.keys() else "-"
+ ),
+ "marital": temp["status_sibil"]
+ if "status_sibil" in temp.keys()
+ and temp["status_sibil"] is not None
+ else "single",
}
)
id = regd.id
except BaseException as e:
- print(e)
+ _logger.error(e)
return None
from datetime import datetime
@@ -554,27 +599,23 @@ def create_registration_from_odk(self, odk_data):
]:
org_data[k] = v
continue
- if (
- k
- in [
- "Status",
- "AttachmentsExpected",
- "AttachmentsPresent",
- "SubmitterName",
- "SubmitterID",
- "KEY",
- "meta-instanceID",
- "__version__",
- "bank_name",
- "city",
- "district",
- "chiefdom",
- "region",
- ]
- or k.startswith("_")
- ):
+ if k in [
+ "Status",
+ "AttachmentsExpected",
+ "AttachmentsPresent",
+ "SubmitterName",
+ "SubmitterID",
+ "KEY",
+ "meta-instanceID",
+ "__version__",
+ "bank_name",
+ "city",
+ "district",
+ "chiefdom",
+ "region",
+ ] or k.startswith("_"):
continue
- if k == "bank_account_number":
+ if k == "bank_account_number" and v is not None:
if len(str(v) or "") != 0:
data["bank_account_number"] = str(v)
res = self.env["res.partner.bank"].search(
@@ -607,6 +648,8 @@ def create_registration_from_odk(self, odk_data):
}
)
data["bank_account_id"] = res.id
+ elif k == "payment_address" and v is not None:
+ data["payment_address"] = odk_data["payment_address"]
elif k == "phone":
data["phone"] = odk_data["phone"]
elif hasattr(self, k):
@@ -674,7 +717,7 @@ def create_registration_from_odk(self, odk_data):
else:
org_data.update({k: v})
except Exception as e:
- print(e)
+ _logger.error(e)
for k, v in org_data.items():
try:
self.env["openg2p.registration.orgmap"].create(
@@ -685,13 +728,21 @@ def create_registration_from_odk(self, odk_data):
}
)
except BaseException as e:
- print(e)
+ _logger.error(e)
try:
regd.write(data)
# Updating Program for Registration
regd.program_ids = [(6, 0, temp["program_ids"])]
except BaseException as e:
- print(e)
+ _logger.error(e)
+
+ if os.getenv("SHOULD_DEMO_AUTH", "true").lower() == "true":
+ regd.post_auth_create_id(demo_auth_res)
+ if should_merge:
+ regd.post_auth_merge(demo_auth_res)
+ if should_create_beneficiary:
+ regd.create_beneficiary_from_registration()
+
return regd
@api.depends("date_open", "date_closed")
@@ -890,6 +941,7 @@ def create_beneficiary_from_registration(self):
"emergency_contact": self.emergency_contact,
"emergency_phone": self.emergency_phone,
"odk_batch_id": self.odk_batch_id,
+ "payment_address": self.payment_address,
}
beneficiary = self.env["openg2p.beneficiary"].create(data)
@@ -909,7 +961,7 @@ def create_beneficiary_from_registration(self):
)
for code, number in self.get_identities():
category = self.env["openg2p.beneficiary.id_category"].search(
- [("type", "=", code)]
+ [("code", "=", code)]
)
self.env["openg2p.beneficiary.id_number"].create(
{
@@ -963,3 +1015,8 @@ def reset_registration(self):
)
default_stage_id = self._default_stage_id()
self.write({"active": True, "stage_id": default_stage_id})
+
+ @api.multi
+ @api.depends("identities", "identities.name", "identities.type")
+ def _compute_identification(self, field_name, category_code):
+ """Overriding from openg2p.beneficiary model."""
diff --git a/openg2p_registration/models/openg2p_registration_api.py b/openg2p_registration/models/openg2p_registration_api.py
index 9627d22..5703f9c 100644
--- a/openg2p_registration/models/openg2p_registration_api.py
+++ b/openg2p_registration/models/openg2p_registration_api.py
@@ -1,7 +1,10 @@
import json
import asyncio
+import logging
from odoo.http import Controller, route, request
+_logger = logging.getLogger(__name__)
+
class Openg2pRegistrationApi(Controller):
@route("/registrations", type="json", auth="user", methods=["GET"])
@@ -61,6 +64,9 @@ def create_registration(self, **kwargs):
response["id"] = new_regd.id
return response
except BaseException as e:
+ import traceback
+
+ _logger.error(traceback.format_exc())
return {"status": 400, "error": str(e)}
@route("/duplicates/", type="json", auth="user", methods=["GET"])
diff --git a/openg2p_registration/models/openg2p_registration_identification.py b/openg2p_registration/models/openg2p_registration_identification.py
index 3aba6e2..702b8ce 100644
--- a/openg2p_registration/models/openg2p_registration_identification.py
+++ b/openg2p_registration/models/openg2p_registration_identification.py
@@ -20,8 +20,10 @@ def _get_supported_id_categories(self):
type = fields.Selection(
selection=lambda x: x._get_supported_id_categories(), required=True
)
+ status = fields.Char("Status of ID", required=False)
+ message = fields.Char("Message from ID Provider", required=False)
registration_id = fields.Many2one("openg2p.registration", required=True, index=True)
_sql_constraints = [
- ("id_uniq", "unique (type, name)", "ID already exists !"),
+ ("id_uniq", "unique (type, name, registration_id)", "ID already exists !"),
]
diff --git a/openg2p_registration/views/openg2p_registration.xml b/openg2p_registration/views/openg2p_registration.xml
index 5c90457..efc64b6 100644
--- a/openg2p_registration/views/openg2p_registration.xml
+++ b/openg2p_registration/views/openg2p_registration.xml
@@ -157,11 +157,13 @@
+
+
-
+