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: added ACH Bank debit #162

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

feat: added ACH Bank debit #162

wants to merge 1 commit into from

Conversation

Pradeep-kumar1202
Copy link

@Pradeep-kumar1202 Pradeep-kumar1202 commented Dec 4, 2024

Description

  • Integrated ACH Debit with dynamicFields support.

  • Passing of mandate data should be done from redirect.res as the customer_acceptance object should be inside the
    mandate_data object.

  • Mandate_data object has been taken from the Hyperswitch API reference.

    NOTE: The mandate_type should be passed from create-payment-intent

  • Validations:

    1. The account number should contain only 12 digits
    2. The routing number should contain only 9 digits
      These are validated by a customValidationFunc for validation and for user input restriction by using customOnChangeFunc
  • Added Local Strings for validations

    1. if not matching with validations Please enter valid X digits Bank Routing Number.
    2. on confirm click with empty fields, Please enter valid details.
      NOTE: The localeStrings are taken reference from ChatGPT and copilot
  • Added icons for ach debit, which can be moved to maven central.

  • Users need to manually close the web/redirect page in order to see the status i.e.,Payment Pending - the status will be updated after 1-4 days usually this flow takes 1-4 days for confirmation.

Note

If the user cancels/closes the page without entering the data will also show the status as Payment Pending - the status will be updated after 1-4 days.

ACH Debit payment flow video :

ACH_Debit_Payment_flow.mp4

Final Message after completing the payment :

Image

About ACH micro deposits

The ACH debit payment flow uses microdeposits for user authentication instead of a synchronous redirection URL like Card 3DS. Stripe deposits small amounts into the user’s bank account, including a 4-character alphanumeric descriptor code (prefixed with "SM.") that the user must enter for verification. Upon successful entry, the event "elements.payment_intent_verify_microdeposits.success" is triggered, confirming ownership and updating the payment status. This flow ensures secure and asynchronous account verification, adhering to Stripe's API requirements for ACH payments. Reference: Stripe ACH Direct Debit.

status: "failed",
},
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

add this in else

user_agent: ?nativeProp.hyperParams.userAgent,
},
},
// mandate_type: {
Copy link
Contributor

Choose a reason for hiding this comment

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

remove unwanted code

Copy link
Contributor

@manideepk90 manideepk90 left a comment

Choose a reason for hiding this comment

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

Everything fine, remove those suggestions

@@ -88,6 +97,17 @@ type customer_acceptance = {
accepted_at: string,
online: online,
}
// type metadata = {frequency: string}
Copy link
Contributor

Choose a reason for hiding this comment

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

remove unwanted comment

Comment on lines 342 to 358
if paymentMethod->Option.getOr("") == "ach" {
responseCallback(
~paymentStatus=ProcessingPayments(None),
~status={
message: "Bank Debit Payment Method: Transactions through this method typically take 1-4 business days to process. Please ensure a valid descriptor code, starting with 'SM,' is provided to initiate the payment successfully.",
code: "",
type_: "",
status: "failed",
},
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why you are closing the SDK with failed status. Isn't this the happy flow?
Returning the status as "failed" to merchant will be not be correct in this case.

Copy link
Author

Choose a reason for hiding this comment

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

@manideepk90 and i thought to add new status as pending.
discussed with akash

~errorCallback,
~processor,
~paymentMethod=?,
) => {
BrowserHook.openUrl(openUrl, nativeProp.hyperParams.appId, intervalId)
->Promise.then(res => {
if res.error === Success {
Copy link
Contributor

Choose a reason for hiding this comment

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

@sh-iv-am can we do some refactoring in BrowserHook? . This promise should resolve with a proper object.
This promise is currently resolved with the following object in case of success in BrowserHook.res

 let browserRes = {
          paymentID: (resP[1]->Option.getOr("")->String.split("="))[1]->Option.getOr(""),
          amount: am,
          error: Success,
        }

@manideepk90 @Pradeep-kumar1202 please look into this and make a proper type for this object. The key name can be something else here. error:Success doesn't make any sense here.

Comment on lines 4 to 7
type customValidationFunc =
| Error(string)
| OtherValidation
| NoError
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems if customValidationFunc is passed you need to call it. Can it be done by making customValidationFunc an optional prop? Instead of making it's type a complex variant?

Copy link
Author

Choose a reason for hiding this comment

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

The function is optional, but we need to validate only some data, other data should follow the default data, if we pass a function it will validate all data and this will fail. so we decided to use a variant

Copy link
Author

Choose a reason for hiding this comment

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

The variant is needed as per @manideepk90 suggestion or else we need to validate externally if we pass the function

Copy link
Contributor

Choose a reason for hiding this comment

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

Make it more readable. The function i.e. customValidationFunc should be an optional prop in this component which return a variant based on validation. We can connect regarding this if needed.

Copy link
Author

Choose a reason for hiding this comment

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

sure let's connect tomorrow

Comment on lines 106 to 116
let tempValid = switch switch customValidationFunc {
| Some(validation) =>
validation(
~text,
~field_type=required_fields_type.field_type,
~display_name=Some(required_fields_type.display_name),
)
| None => OtherValidation
} {
| Error(errorMessage) => Some(errorMessage)
| OtherValidation =>
RequiredFieldsTypes.checkIsValid(
~text,
~field_type=required_fields_type.field_type,
~localeObject,
)
| NoError => None
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Refactor this if it can be done without a variant.

Copy link
Author

Choose a reason for hiding this comment

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

bro, we need this for default validation. or else we need to call the default validation from here only

Copy link
Author

Choose a reason for hiding this comment

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

i am working on bacs, sepa and becs. which have same fields like account number but different validations. such that passing a optional function will not be a good idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants