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

feat(core): [Payouts] Add retrieve flow for payouts #4936

Merged
merged 15 commits into from
Jul 15, 2024
Merged

Conversation

Sakilmostak
Copy link
Contributor

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates
  • Documentation
  • CI/CD

Description

Add retrieve call for payouts in case for transaction that need status update

Additional Changes

  • This PR modifies the API contract
  • This PR modifies the database schema
  • This PR modifies application configuration/environment variables

Motivation and Context

How did you test it?

Tested through Postman:

  • Create a MCA(Paypal):
{
    "connector_type": "payout_processor",
    "connector_name": "paypal",
    "connector_account_details": {
        "auth_type": "BodyKey",
        "api_key": "{{api_key}}",
        "key1": "{{key1}}"
    },
    "test_mode": false,
    "disabled": false,
    "payment_methods_enabled": [
        {
            "payment_method": "card",
            "payment_method_types": [
                {
                    "payment_method_type": "credit",
                    "card_networks": [
                        "Visa",
                        "Mastercard"
                    ],
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "debit",
                    "card_networks": [
                        "Visa",
                        "Mastercard"
                    ],
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        },
        {
            "payment_method": "pay_later",
            "payment_method_types": [
                {
                    "payment_method_type": "klarna",
                    "payment_experience": "redirect_to_url",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "affirm",
                    "payment_experience": "redirect_to_url",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "afterpay_clearpay",
                    "payment_experience": "redirect_to_url",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        },
        {
            "payment_method": "wallet",
            "payment_method_types": [
                {
                    "payment_method_type": "paypal",
                    "payment_experience": "redirect_to_url",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
                // {
                //     "payment_method_type": "venmo",
                //     "payment_experience": "redirect_to_url",
                //     "minimum_amount": 1,
                //     "maximum_amount": 68607706,
                //     "recurring_enabled": true,
                //     "installment_payment_enabled": true
                // }
            ]
        },
        {
            "payment_method": "bank_transfer",
            "payment_method_types": [
                {
                    "payment_method_type": "sepa",
                    //"payment_experience": "redirect_to_url",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "pix",
                    //"payment_experience": "redirect_to_url",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "bacs",
                    //"payment_experience": "redirect_to_url",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        }
    ],
    "metadata": {
        "merchant_id": "1087905",
        "name": "Mostak"
    },
    "business_country": "US",
    "business_label": "default"
}
  • Create a payout
{
    "amount": 1,
    "currency": "EUR",
    "customer_id": "payout_customer",
    "email": "[email protected]",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payout request",
    "payout_type": "wallet",
    "payout_method_data": {
        "wallet": {
            "paypal": {
                "email": "[email protected]"
                // "telephone_number": "16608213349"
                // "paypal_id": "G83KXTJ5EHCQ2"
            }
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "NY",
            "zip": "94122",
            "country": "US",
            "first_name": "John",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "entity_type": "NaturalPerson",
    "recurring": false,
    "metadata": {
        "ref": "123"
    },
    "routing": {
        "type": "single",
        "data": "paypal"
    },
    "confirm": true,
    "auto_fulfill": true
}
  • Create a retrieve call with force sync as true
curl --location '{{base_url}}/payouts/{{payout_id}}?force_sync=true' \
--header 'api-key: {{api_key}}'
  • The status of retrieve should be success

Checklist

  • I formatted the code cargo +nightly fmt --all
  • I addressed lints thrown by cargo clippy
  • I reviewed the submitted code
  • I added unit tests for my changes where possible

@Sakilmostak Sakilmostak requested review from a team as code owners June 10, 2024 12:47
@Sakilmostak Sakilmostak self-assigned this Jun 13, 2024
@Sakilmostak Sakilmostak added A-core Area: Core flows C-feature Category: Feature request or enhancement labels Jun 13, 2024
let payout_attempt = payout_data.payout_attempt.to_owned();

// Form connector data
let connector_call_type = get_connector_choice(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should call the underlying connector only when force_sync is true

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, do we need to run this logic again for retrieve call? We already have the connector where the payout was created, could we directly use that connector for doing a sync?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is being called to get the ConnectorData, as for using the already present connector, payout_attempt.connector is being passed as a parameter to set the call connector type as predetermined. Thus, we remove all the other cases of the call connector type

let payout_attempt = &payout_data.payout_attempt.to_owned();
let status = payout_attempt.status;

if matches!(req.force_sync, Some(true)) && helpers::should_call_retrieve(status) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this check to the main caller function?

Copy link
Contributor

@kashif-m kashif-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, added a few suggestions

}
}
Err(err) => {
let status = storage_enums::PayoutStatus::Failed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't update the status of payouts in case retrieval fails 🤔

@kashif-m kashif-m self-requested a review July 8, 2024 07:10
kashif-m
kashif-m previously approved these changes Jul 8, 2024
crates/router/src/core/payouts.rs Outdated Show resolved Hide resolved
crates/router/src/core/payouts.rs Show resolved Hide resolved
crates/router/src/core/payouts.rs Outdated Show resolved Hide resolved
crates/router/src/core/payouts.rs Show resolved Hide resolved
pub fn should_call_retrieve(status: api_enums::PayoutStatus) -> bool {
matches!(
status,
api_enums::PayoutStatus::Pending | api_enums::PayoutStatus::Initiated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have all the non-terminal states right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are the only two non-terminal status where we can retrieve, in case of require_creation/require_confirmation, since we don't hit the connector, we can't retrieve it. in case of require_fulfillment, we don't hit the connector for some of the connector ( creating payout object only at our end) thus not able to retrieve in those cases

kashif-m
kashif-m previously approved these changes Jul 12, 2024
@@ -18,3 +18,6 @@ pub struct PoRecipient;

#[derive(Debug, Clone)]
pub struct PoRecipientAccount;

#[derive(Debug, Clone)]
pub struct PoSync;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please name these types as PayoutsSync or PayoutSync instead. Can pick this change in a separate PR.

@likhinbopanna likhinbopanna added this pull request to the merge queue Jul 15, 2024
Merged via the queue into main with commit 693f08d Jul 15, 2024
13 checks passed
@likhinbopanna likhinbopanna deleted the payout_retrieve branch July 15, 2024 13:01
pixincreate added a commit that referenced this pull request Jul 16, 2024
* 'main' of github.com:juspay/hyperswitch: (25 commits)
  fix(logs): ignore request headers while logging (#5273)
  feat(webhooks): add support for custom outgoing webhook http headers (#5275)
  fix(payment_methods): set `requires_cvv` to false when either `connector_mandate_details` or `network_transaction_id` is present during MITs (#5331)
  chore: create justfile for running commands for v1 and v2 migrations (#5325)
  fix(routing): do not update `perform_session_flow_routing` output if the `SessionRoutingChoice` is none (#5336)
  fix(database): modified_at updated for every state change for Payment Attempts (#5312)
  feat(mca): Added recipient connector call for open banking connectors (#3758)
  chore(version): 2024.07.16.0
  refactor(connector): [Mifinity] add a field language_preference in payment request for mifinity payment method data (#5326)
  fix(router): store `customer_acceptance` in payment_attempt, use it in confirm flow for delayed authorizations like external 3ds flow (#5308)
  feat(proxy): add support to pass proxy bypass urls from configs (#5322)
  Docs: Updating Error codes in API-ref (#5296)
  feat(core): [Payouts] Add retrieve flow for payouts (#4936)
  fix(connector): [AUTHORIZEDOTNET] Populate error reason for failure transactions (#5319)
  chore(version): 2024.07.15.0
  feat(logging): Emit a setup error when a restricted keys are used for logging default keys (#5185)
  feat(payment_methods): add support to migrate existing customer PMs from processor to hyperswitch (#5306)
  feat(connector): [DATATRANS] Implement card payments (#5028)
  chore: making of function create_encrypted_data (#5251)
  fix(payments): populate merchant order ref id in list (#5310)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-core Area: Core flows C-feature Category: Feature request or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants