Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

G2P-1499: Able to send payments without preparing payment batch, Add… #145

Merged
merged 1 commit into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion g2p_payment_cash/models/payment_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class G2PPaymentManagerCash(models.Model):
def _send_payments(self, batches):
if not batches:
message = _("No payment batches to process.")
kind = "danger" # Use a valid type like "danger" for an error message
kind = "warning"
else:
_logger.info("DEBUG! send_payments Manager: Payment via CASH")
for batch in batches:
Expand Down
148 changes: 78 additions & 70 deletions g2p_payment_g2p_connect/models/payment_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,77 +81,85 @@ def _onchange_payee_id_type(self):
self.payee_prefix = prefix_mapping.get(self.payee_id_type)

def _send_payments(self, batches):
_logger.info("DEBUG! send_payments Manager: G2P Connect.")
for batch in batches:
if batch.batch_has_started:
continue
batch.batch_has_started = True
batch_data = {
"signature": 'Signature: namespace="g2p", kidId="{sender_id}|{unique_key_id}|{algorithm}", '
'algorithm="ed25519", created="1606970629", expires="1607030629", '
'headers="(created) (expires) digest", signature="Base64(signing content)',
"header": {
"version": "1.0.0",
"message_id": "123",
"message_ts": "",
"action": "search",
"sender_id": "spp.example.org",
"sender_uri": "https://spp.example.org/{namespace}/callback/on-search",
"receiver_id": "pymts.example.org",
"total_count": 21800,
"is_msg_encrypted": False,
"meta": {},
},
"message": {"transaction_id": batch.name, "disbursements": []},
}
headers = {
"Content-Type": "application/json",
}
for payment in batch.payment_ids:
batch_data["message"]["disbursements"].append(
{
"reference_id": payment.name,
"payer_fa": self.payer_fa,
"payee_fa": self._get_payee_fa(payment),
"amount": payment.amount_issued,
"scheduled_timestamp": "",
"payer_name": self.payer_name,
"payee_name": payment.partner_id.name,
"note": "string",
"purpose": self.program_id.name,
"instruction": "string",
"currency_code": payment.currency_id.name,
"locale": self.locale,
}
)
try:
response = requests.post(
self.payment_endpoint_url, json=batch_data, headers=headers
)
_logger.info("G2P Connect Disbursement response: %s", response.content)
response.raise_for_status()

# TODO: Do Status check rather than hardcoding
if not batches:
message = _("No payment batches to process.")
kind = "warning"
else:
_logger.info("DEBUG! send_payments Manager: G2P Connect.")
for batch in batches:
if batch.batch_has_started:
continue
batch.batch_has_started = True
batch_data = {
"signature": 'Signature: namespace="g2p", kidId="{sender_id}|{unique_key_id}|{algorithm}", '
'algorithm="ed25519", created="1606970629", expires="1607030629", '
'headers="(created) (expires) digest", signature="Base64(signing content)',
"header": {
"version": "1.0.0",
"message_id": "123",
"message_ts": "",
"action": "search",
"sender_id": "spp.example.org",
"sender_uri": "https://spp.example.org/{namespace}/callback/on-search",
"receiver_id": "pymts.example.org",
"total_count": 21800,
"is_msg_encrypted": False,
"meta": {},
},
"message": {"transaction_id": batch.name, "disbursements": []},
}
headers = {
"Content-Type": "application/json",
}
for payment in batch.payment_ids:
payment.state = "sent"
payment.status = "paid"
payment.amount_paid = payment.amount_issued
payment.payment_datetime = datetime.utcnow()

except Exception as e:
_logger.error(
"G2P Connect Payment Failed with unknown reason: %s", str(e)
)
error_msg = "G2P Connect Payment Failed with unknown reason: " + str(e)
self.message_post(
body=error_msg, subject=_("G2P Connect Payment Disbursement")
)

# TODO: Compute status of disbursement from API
batch.batch_has_completed = True

message = _("Payment sent successfully")
kind = "success"
batch_data["message"]["disbursements"].append(
{
"reference_id": payment.name,
"payer_fa": self.payer_fa,
"payee_fa": self._get_payee_fa(payment),
"amount": payment.amount_issued,
"scheduled_timestamp": "",
"payer_name": self.payer_name,
"payee_name": payment.partner_id.name,
"note": "string",
"purpose": self.program_id.name,
"instruction": "string",
"currency_code": payment.currency_id.name,
"locale": self.locale,
}
)
try:
response = requests.post(
self.payment_endpoint_url, json=batch_data, headers=headers
)
_logger.info(
"G2P Connect Disbursement response: %s", response.content
)
response.raise_for_status()

# TODO: Do Status check rather than hardcoding
for payment in batch.payment_ids:
payment.state = "sent"
payment.status = "paid"
payment.amount_paid = payment.amount_issued
payment.payment_datetime = datetime.utcnow()

except Exception as e:
_logger.error(
"G2P Connect Payment Failed with unknown reason: %s", str(e)
)
error_msg = (
"G2P Connect Payment Failed with unknown reason: " + str(e)
)
self.message_post(
body=error_msg, subject=_("G2P Connect Payment Disbursement")
)

# TODO: Compute status of disbursement from API
batch.batch_has_completed = True

message = _("Payment sent successfully")
kind = "success"
return {
"type": "ir.actions.client",
"tag": "display_notification",
Expand Down
198 changes: 110 additions & 88 deletions g2p_payment_interop_layer/models/payment_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,98 +67,120 @@ class G2PPaymentInteropLayerManager(models.Model):
def _send_payments(self, batches):
payment_endpoint_url = self.payment_endpoint_url
all_paid_counter = 0
for batch in batches:
if batch.batch_has_started:
continue
else:
batch.batch_has_started = True

disbursement_id = batch.name

cycle_id = batch.cycle_id
disbursement_note = (
f"Program: {cycle_id.program_id.name}. Cycle ID - {cycle_id.name}"
)

final_json_request_dict = {
"note": disbursement_note,
"disbursementId": disbursement_id,
"payeeList": [],
}

for payment_id in batch.payment_ids:
payee_id_type, payee_id_value = self._get_dfsp_id_and_type(payment_id)
payee_item = {
"payeeIdType": payee_id_type,
"payeeIdValue": payee_id_value,
"amount": payment_id.amount_issued,
"currency": payment_id.currency_id.name,
}
final_json_request_dict["payeeList"].append(payee_item)

# TODO: Add authentication mechanism
try:
res = requests.post(payment_endpoint_url, json=final_json_request_dict)
res.raise_for_status()
jsonResponse = res.json()
_logger.info(
f"Interop Layer Disbursement API: jsonResponse: {jsonResponse}"
)
if not batches:
message = _("No payment batches to process.")
kind = "warning"
else:
for batch in batches:
if batch.batch_has_started:
continue
else:
batch.batch_has_started = True

except HTTPError as http_err:
_logger.error(
f"Interop Layer Disbursement API: HTTP error occurred: {http_err}. res: {res} - {res.content}"
)
continue
except Exception as err:
_logger.error(
f"Interop Layer Disbursement API: Other error occurred: {err}. res: {res} - {res.content}"
disbursement_id = batch.name

cycle_id = batch.cycle_id
disbursement_note = (
f"Program: {cycle_id.program_id.name}. Cycle ID - {cycle_id.name}"
)
continue

batch.payment_ids.write({"state": "sent"})

paid_counter = 0
for i, payee_result in enumerate(jsonResponse["payeeResults"]):
if payee_result["status"] == "COMPLETED":
paid_counter += 1
batch.payment_ids[i].update(
{
"state": "reconciled",
"status": "paid",
"amount_paid": payee_result["amountCredited"],
"payment_datetime": datetime.strptime(
payee_result["timestamp"], "%Y-%m-%dT%H:%M:%S.%fZ"
),
}

final_json_request_dict = {
"note": disbursement_note,
"disbursementId": disbursement_id,
"payeeList": [],
}

for payment_id in batch.payment_ids:
payee_id_type, payee_id_value = self._get_dfsp_id_and_type(
payment_id
)
elif payee_result["status"] in [
"REJECTED",
"ABORTED",
"ERROR_OCCURRED",
]:
batch.payment_ids[i].update(
{
"state": "reconciled",
"status": "failed",
}
payee_item = {
"payeeIdType": payee_id_type,
"payeeIdValue": payee_id_value,
"amount": payment_id.amount_issued,
"currency": payment_id.currency_id.name,
}
final_json_request_dict["payeeList"].append(payee_item)

# TODO: Add authentication mechanism
res = None
try:
res = requests.post(
payment_endpoint_url, json=final_json_request_dict
)
if paid_counter and paid_counter == len(batch.payment_ids):
batch.batch_has_completed = True
all_paid_counter += paid_counter

total_payments_counter = sum(len(batch.payment_ids) for batch in batches)
if all_paid_counter == total_payments_counter:
message = _(f"{all_paid_counter} Payments sent successfully")
kind = "success"
elif all_paid_counter == 0:
message = _("Failed to sent payments")
kind = "danger"
else:
message = _(
f"{all_paid_counter} Payments sent successfully out of {total_payments_counter}"
)
kind = "warning"
res.raise_for_status()
jsonResponse = res.json()
_logger.info(
f"Interop Layer Disbursement API: jsonResponse: {jsonResponse}"
)

except HTTPError as http_err:
if res is not None:
_logger.error(
"Interop Layer Disbursement API: HTTP error occurred: "
f"{http_err}. res: {res} - {res.content}"
)

else:
_logger.error(
f"Interop Layer Disbursement API: HTTP error occurred: {http_err}."
)
continue

except Exception as err:
if res is not None:
_logger.error(
f"Interop Layer Disbursement API: Other error occurred: {err}. res: {res} - {res.content}"
)
else:
_logger.error(
f"Interop Layer Disbursement API: Other error occurred: {err}."
)
continue

batch.payment_ids.write({"state": "sent"})

paid_counter = 0
for i, payee_result in enumerate(jsonResponse["payeeResults"]):
if payee_result["status"] == "COMPLETED":
paid_counter += 1
batch.payment_ids[i].update(
{
"state": "reconciled",
"status": "paid",
"amount_paid": payee_result["amountCredited"],
"payment_datetime": datetime.strptime(
payee_result["timestamp"], "%Y-%m-%dT%H:%M:%S.%fZ"
),
}
)
elif payee_result["status"] in [
"REJECTED",
"ABORTED",
"ERROR_OCCURRED",
]:
batch.payment_ids[i].update(
{
"state": "reconciled",
"status": "failed",
}
)
if paid_counter and paid_counter == len(batch.payment_ids):
batch.batch_has_completed = True
all_paid_counter += paid_counter

total_payments_counter = sum(len(batch.payment_ids) for batch in batches)
if all_paid_counter == total_payments_counter:
message = _(f"{all_paid_counter} Payments sent successfully")
kind = "success"
elif all_paid_counter == 0:
message = _("Failed to sent payments")
kind = "danger"
else:
message = _(
f"{all_paid_counter} Payments sent successfully out of {total_payments_counter}"
)
kind = "warning"

return {
"type": "ir.actions.client",
Expand Down
Loading
Loading