Skip to content

Commit

Permalink
temp: POC on PayPal paritial refund with multiple items
Browse files Browse the repository at this point in the history
  • Loading branch information
syedsajjadkazmii committed Jan 6, 2025
1 parent 1772b10 commit 22687ef
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 18 deletions.
22 changes: 18 additions & 4 deletions commerce_coordinator/apps/commercetools/catalog_info/edx_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,27 @@ def get_edx_is_sanctioned(order: CTOrder) -> bool:
return get_edx_order_workflow_state_key(order) == TwoUKeys.SDN_SANCTIONED_ORDER_STATE


def get_edx_refund_info(payment: CTPayment) -> decimal:
refund_amount = decimal.Decimal(0.00)
def _cents_to_dollars(in_amount):
return in_amount.cent_amount / pow(
10, in_amount.fraction_digits
if hasattr(in_amount, 'fraction_digits')
else 2
)

def get_line_item_price(order: CTOrder, return_line_item_id: str):
for line_item in get_edx_items(order):
if line_item.id == return_line_item_id:
return _cents_to_dollars(line_item.price.value)
return decimal.Decimal(0.00)

def get_edx_refund_info(payment: CTPayment, order: CTOrder, return_line_item_id: str) -> (decimal.Decimal, str):
interaction_id = None

for transaction in payment.transactions:
if transaction.type == TransactionType.CHARGE: # pragma no cover
refund_amount += decimal.Decimal(typed_money_to_string(transaction.amount, money_as_decimal_string=True))
interaction_id = transaction.interaction_id
return refund_amount, interaction_id

refund_amount = get_line_item_price(order, return_line_item_id)
print('\n\n\n\n\n line item price = ',refund_amount, '\n\n\n\n\n')

return refund_amount, interaction_id
9 changes: 8 additions & 1 deletion commerce_coordinator/apps/commercetools/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ class OrderRefundRequested(OpenEdxPublicFilter):
filter_type = "org.edx.coordinator.commercetools.order.refund.requested.v1"

@classmethod
def run_filter(cls, order_id, return_line_item_return_id, message_id):
def run_filter(
cls,
order_id,
return_line_item_return_id,
return_line_item_id,
message_id
):
"""
Call the PipelineStep(s) defined for this filter.
Arguments:
Expand All @@ -21,4 +27,5 @@ def run_filter(cls, order_id, return_line_item_return_id, message_id):
"""
return super().run_pipeline(order_id=order_id,
return_line_item_return_id=return_line_item_return_id,
return_line_item_id=return_line_item_id,
message_id=message_id)
16 changes: 11 additions & 5 deletions commerce_coordinator/apps/commercetools/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@
)
from commerce_coordinator.apps.commercetools.catalog_info.edx_utils import (
get_edx_refund_info,
get_edx_successful_payment_info
get_edx_successful_payment_info, get_edx_items
)
from commerce_coordinator.apps.commercetools.clients import CommercetoolsAPIClient
from commerce_coordinator.apps.commercetools.constants import COMMERCETOOLS_ORDER_MANAGEMENT_SYSTEM
from commerce_coordinator.apps.commercetools.data import order_from_commercetools
from commerce_coordinator.apps.commercetools.utils import create_retired_fields, has_refund_transaction
from commerce_coordinator.apps.commercetools.utils import create_retired_fields, has_refund_transaction, \
has_full_refund_transaction
from commerce_coordinator.apps.core.constants import PipelineCommand
from commerce_coordinator.apps.core.exceptions import InvalidFilterType
from commerce_coordinator.apps.rollout.utils import (
Expand Down Expand Up @@ -132,7 +133,12 @@ def run_filter(self, active_order_management_system, order_number, **kwargs): #
class FetchOrderDetailsByOrderID(PipelineStep):
""" Fetch the order details and if we can, set the PaymentIntent """

def run_filter(self, active_order_management_system, order_id, **kwargs): # pylint: disable=arguments-differ
def run_filter(self,
active_order_management_system,
order_id,
return_line_item_id,
**kwargs
): # pylint: disable=arguments-differ
"""
Execute a filter with the signature specified.
Arguments:
Expand Down Expand Up @@ -169,10 +175,10 @@ def run_filter(self, active_order_management_system, order_id, **kwargs): # pyl

if payment:
ct_payment = ct_api_client.get_payment_by_key(payment.interface_id)
refund_amount, ct_transaction_interaction_id = get_edx_refund_info(ct_payment)
refund_amount, ct_transaction_interaction_id = get_edx_refund_info(ct_payment, ct_order, return_line_item_id)
ret_val['amount_in_cents'] = refund_amount
ret_val['ct_transaction_interaction_id'] = ct_transaction_interaction_id
ret_val['has_been_refunded'] = has_refund_transaction(ct_payment)
ret_val['has_been_refunded'] = is_commercetools_line_item_already_refunded(ct_order, return_line_item_id) or has_full_refund_transaction(ct_payment)
ret_val['payment_data'] = ct_payment
else:
ret_val['amount_in_cents'] = decimal.Decimal(0.00)
Expand Down
3 changes: 3 additions & 0 deletions commerce_coordinator/apps/commercetools/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,6 @@ def get_return_info(self):

def get_return_line_item_return_id(self):
return self.get_return_info().get('id', None)

def get_return_line_item_id(self):
return self.get_return_info().get('lineItemId', None)
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def fulfill_order_returned_signal(**kwargs):
async_result = fulfill_order_returned_signal_task.delay(
order_id=kwargs['order_id'],
return_line_item_return_id=kwargs['return_line_item_return_id'],
return_line_item_id=kwargs['return_line_item_id'],
message_id=kwargs['message_id']
)
return async_result.id
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ def fulfill_order_sanctioned_message_signal_task(
def fulfill_order_returned_signal_task(
order_id,
return_line_item_return_id,
return_line_item_id,
message_id
):
"""Celery task for an order return (and refunded) message."""
Expand Down Expand Up @@ -278,7 +279,10 @@ def _prepare_segment_event_properties(in_order, return_line_item_return_id):
# Return payment if payment id is set
if payment_intent_id is not None:
result = OrderRefundRequested.run_filter(
order_id=order_id, return_line_item_return_id=return_line_item_return_id, message_id=message_id
order_id=order_id,
return_line_item_return_id=return_line_item_return_id,
return_line_item_id=return_line_item_id,
message_id=message_id
)

if 'refund_response' in result and result['refund_response']:
Expand Down
6 changes: 4 additions & 2 deletions commerce_coordinator/apps/commercetools/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,18 +133,20 @@ def post(self, request):
message_details.is_valid(raise_exception=True)
order_id = message_details.data['order_id']
return_line_item_return_id = message_details.get_return_line_item_return_id()
return_line_item_id = message_details.get_return_line_item_id()
message_id = message_details.data['message_id']

if self._is_running(tag, order_id): # pragma no cover
if self._is_running(tag, return_line_item_return_id): # pragma no cover
self.meta_should_mark_not_running = False
return Response(status=status.HTTP_200_OK)
else:
self.mark_running(tag, order_id)
self.mark_running(tag, return_line_item_return_id)

fulfill_order_returned_signal.send_robust(
sender=self,
order_id=order_id,
return_line_item_return_id=return_line_item_return_id,
return_line_item_id=return_line_item_id,
message_id=message_id
)

Expand Down
13 changes: 11 additions & 2 deletions commerce_coordinator/apps/paypal/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def __init__(self):
),
)

def refund_order(self, capture_id):
def refund_order(self, capture_id, amount):
"""
Capture PayPal refund.
Expand All @@ -34,7 +34,16 @@ def refund_order(self, capture_id):
paypal_client = self.paypal_client
payments_controller: PaymentsController = paypal_client.payments

collect = {"capture_id": capture_id, "prefer": "return=representation"}
collect = {
"capture_id": capture_id,
"prefer": "return=representation",
"body": {
"amount": {
"value": amount,
"currency_code": "USD"
}
}
}
refund_response = payments_controller.captures_refund(collect)

if refund_response.body:
Expand Down
2 changes: 1 addition & 1 deletion commerce_coordinator/apps/paypal/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def run_filter(

try:
paypal_client = PayPalClient()
paypal_refund_response = paypal_client.refund_order(capture_id=ct_transaction_interaction_id)
paypal_refund_response = paypal_client.refund_order(capture_id=ct_transaction_interaction_id, amount=amount_in_cents)

return {
'refund_response': paypal_refund_response,
Expand Down
8 changes: 6 additions & 2 deletions commerce_coordinator/apps/rollout/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from commercetools.platform.models import Order as CTOrder
from commercetools.platform.models import ReturnItem as CTReturnItem
from commercetools.platform.models import ReturnPaymentState



def is_legacy_order(order_number: str) -> bool:
Expand Down Expand Up @@ -38,8 +40,10 @@ def is_commercetools_line_item_already_refunded(order: CTOrder, order_line_item_

return_info_return_items = get_order_return_info_return_items(order)

return len(list(filter(lambda item: item.line_item_id == order_line_item_id, return_info_return_items))) >= 1

return len(list(filter(
lambda item: item.line_item_id == order_line_item_id and item.payment_state == ReturnPaymentState.REFUNDED,
return_info_return_items
))) >= 1

def is_commercetools_stripe_refund(source_system: str) -> bool:
"""
Expand Down

0 comments on commit 22687ef

Please sign in to comment.