Skip to content

Feat(connector): [Fiuu] Add Card Flows#5786

Merged
Gnanasundari24 merged 6 commits intomainfrom
6437-featconnector-fiuu-add-payment-flow-cards-for-fiuu
Sep 4, 2024
Merged

Feat(connector): [Fiuu] Add Card Flows#5786
Gnanasundari24 merged 6 commits intomainfrom
6437-featconnector-fiuu-add-payment-flow-cards-for-fiuu

Conversation

@awasthi21
Copy link
Contributor

@awasthi21 awasthi21 commented Sep 3, 2024

Type of Change

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

Description

Added Card Flows for Fiuu

Additional Changes

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

Motivation and Context

Card Flows for Fiuu

How did you test it?

Added Cypress test
For 3DS
Request

curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_LmRPQdsND4XAyLmzxtJ569V9xKZCVXhErF3hf2FNJolGW7bS8ERq9SsUuN2isYZe' \
--data '{
    "amount": 1222,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "return_url": "https://google.com",
    "authentication_type": "three_ds",
    "payment_method": "card",
    "payment_method_type": "debit",
    "payment_method_data": {
        "card": {
            "card_number": "5105105105105100",
            "card_exp_month": "12",
            "card_exp_year": "2030",
            "card_holder_name": "Malay Awasthi",
            "card_cvc": "444"
        }
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "count_tickets": 1,
        "transaction_number": "5590045"
    }
}'

Response

{
    "payment_id": "pay_PovGP2AaF9IMa6R6eJln",
    "merchant_id": "postman_merchant_GHAction_e825c712-dd2c-41e9-b188-19af337cf4f5",
    "status": "requires_customer_action",
    "amount": 1222,
    "net_amount": 1222,
    "amount_capturable": 1222,
    "amount_received": null,
    "connector": "fiuu",
    "client_secret": "pay_PovGP2AaF9IMa6R6eJln_secret_VIAXZjbEPEBrIw2mXaIV",
    "created": "2024-09-04T11:23:59.672Z",
    "currency": "USD",
    "customer_id": null,
    "customer": null,
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "5100",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "510510",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "2030",
            "card_holder_name": null,
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "return_url": "https://google.com/",
    "authentication_type": "three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": {
        "type": "redirect_to_url",
        "redirect_to_url": "http://localhost:8080/payments/redirect/pay_PovGP2AaF9IMa6R6eJln/postman_merchant_GHAction_e825c712-dd2c-41e9-b188-19af337cf4f5/pay_PovGP2AaF9IMa6R6eJln_1"
    },
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "debit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": null,
    "connector_transaction_id": "30870898",
    "frm_message": null,
    "metadata": {
        "count_tickets": 1,
        "transaction_number": "5590045"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_CGIaytFeGnEuuGhk7PM1",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_14f6QbFgMJ8anv8X9D8i",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-04T11:38:59.672Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-09-04T11:24:00.218Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null
}

Redirection Response(after Sync)

{
    "payment_id": "pay_PovGP2AaF9IMa6R6eJln",
    "merchant_id": "postman_merchant_GHAction_e825c712-dd2c-41e9-b188-19af337cf4f5",
    "status": "succeeded",
    "amount": 1222,
    "net_amount": 1222,
    "amount_capturable": 0,
    "amount_received": 1222,
    "connector": "fiuu",
    "client_secret": "pay_PovGP2AaF9IMa6R6eJln_secret_VIAXZjbEPEBrIw2mXaIV",
    "created": "2024-09-04T11:23:59.672Z",
    "currency": "USD",
    "customer_id": null,
    "customer": null,
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "5100",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "510510",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "2030",
            "card_holder_name": null,
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "return_url": "https://google.com/",
    "authentication_type": "three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "debit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "30870898",
    "frm_message": null,
    "metadata": {
        "count_tickets": 1,
        "transaction_number": "5590045"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_CGIaytFeGnEuuGhk7PM1",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_14f6QbFgMJ8anv8X9D8i",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-04T11:38:59.672Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-09-04T11:31:18.619Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null
}
Screenshot 2024-09-04 at 5 02 20 PM

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

@awasthi21 awasthi21 requested review from a team as code owners September 3, 2024 14:04
@semanticdiff-com
Copy link

semanticdiff-com bot commented Sep 3, 2024

Review changes with SemanticDiff.

Analyzed 14 of 20 files.

Overall, the semantic diff is 8% smaller than the GitHub diff.

Filename Status
Cargo.lock Unsupported file format
✔️ cypress-tests/cypress/e2e/PaymentUtils/Commons.js Analyzed
cypress-tests/cypress/e2e/PaymentUtils/Fiuu.js Unsupported file format
✔️ cypress-tests/cypress/e2e/PaymentUtils/Utils.js Analyzed
✔️ crates/router/src/types/api.rs Analyzed
✔️ crates/router/src/types/transformers.rs Analyzed
✔️ crates/router/src/core/admin.rs Analyzed
✔️ crates/router/src/configs/defaults.rs Analyzed
crates/hyperswitch_connectors/Cargo.toml Unsupported file format
✔️ crates/hyperswitch_connectors/src/types.rs 18.03% smaller
✔️ crates/hyperswitch_connectors/src/connectors/fiuu.rs 4.97% smaller
✔️ crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs 9.41% smaller
crates/connector_configs/toml/development.toml Unsupported file format
crates/connector_configs/toml/production.toml Unsupported file format
crates/connector_configs/toml/sandbox.toml Unsupported file format
✔️ crates/connector_configs/src/connector.rs Analyzed
✔️ crates/common_enums/src/enums.rs Analyzed
✔️ crates/api_models/src/enums.rs Analyzed
✔️ api-reference-v2/openapi_spec.json Analyzed
✔️ api-reference/openapi_spec.json Analyzed

@awasthi21 awasthi21 self-assigned this Sep 3, 2024
@awasthi21 awasthi21 added the A-connector-integration Area: Connector integration label Sep 3, 2024
@hyperswitch-bot hyperswitch-bot bot added the M-api-contract-changes Metadata: This PR involves API contract changes label Sep 3, 2024
@awasthi21 awasthi21 changed the title card flow Feat(connector): [Fiuu] Add Card Flows Sep 3, 2024
Comment on lines +123 to +124
"fiuu",
"fiuu",
Copy link
Member

Choose a reason for hiding this comment

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

This has been repeated twice.

Comment on lines +585 to +589
impl Display for StringMajorUnit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if we'd want to implement Display here, or if we're to use one of the methods already available.

CC: @jarnura @sahkal

Comment on lines +49 to +60
let response_str = String::from_utf8_lossy(data);
let mut map = HashMap::new();
for line in response_str.lines() {
if let Some((key, value)) = line.split_once('=') {
map.insert(key.to_string(), value.to_string());
}
}
let json = serde_json::to_string(&map)
.map_err(|_| errors::ConnectorError::ResponseDeserializationFailed)?;

let response: T = serde_json::from_str(&json)
.map_err(|_| errors::ConnectorError::ResponseDeserializationFailed)?;
Copy link
Member

Choose a reason for hiding this comment

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

  1. We may be losing some information because we're calling from_utf8_lossy().
  2. Can we avoid the split by = and find a better way to deserialize the response if possible?
  3. The 3 step process where we collect key-values to a map, serialize it as JSON, then deserialize it into T must preferably be avoided, if we can find a better way to deserialize the response.
  4. If we end sticking with this, then at least log the errors, do not ignore them.

Comment on lines +151 to +152
let serialized = serde_json::to_value(&data)
.map_err(|_| common_errors::ParsingError::EncodeError("json-value"))?;
Copy link
Member

Choose a reason for hiding this comment

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

Do not ignore errors, log them at the very least.

Comment on lines +159 to +162
Value::String(s) => s.clone(),
Value::Number(n) => n.to_string(),
Value::Bool(b) => b.to_string(),
_ => "".to_string(),
Copy link
Member

Choose a reason for hiding this comment

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

We'd end up serializing arrays and nested object with an empty string value. I'm sure we shouldn't be doing that?

Comment on lines +205 to +209
#[derive(Debug, Serialize, Deserialize)]
pub enum RequestType {
REDIRECT,
RESPONSE,
}
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Can we use PascalCase names instead with serde(rename_all = "UPPERCASE") (or screaming snake case, as required)?

Comment on lines +336 to +337
pub enum RefundType {
P,
Copy link
Member

Choose a reason for hiding this comment

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

Can we preferably use a verbose name with serde(rename = "P") here, instead of using a single character enum variant?

Comment on lines +469 to +473
if stat_name == "settled" || stat_name == "captured" {
Ok(enums::AttemptStatus::Charged)
} else {
Ok(enums::AttemptStatus::Authorized)
}
Copy link
Member

Choose a reason for hiding this comment

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

Can't we use an enum instead for the stat_name field?

})
}
}
// Reminder
Copy link
Member

Choose a reason for hiding this comment

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

Can you remove this comment?

Comment on lines +340 to 346
impl RefundType {
pub fn as_str(&self) -> &'static str {
match self {
Self::Partial => "P",
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

You anyway derive strum::Display, you can add #[strum(serialize = "P")] on the enum variant, and take advantage of the Display implementation for generating the signature.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add the change in the next upcoming PR(for Duitnow,FPX payment Method)

Copy link
Contributor

@likhinbopanna likhinbopanna Sep 4, 2024

Choose a reason for hiding this comment

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

Please handle the redirection flows in the separate PR
other than that LGTM

@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Sep 4, 2024
Merged via the queue into main with commit ed0d816 Sep 4, 2024
@Gnanasundari24 Gnanasundari24 deleted the 6437-featconnector-fiuu-add-payment-flow-cards-for-fiuu branch September 4, 2024 14:48
pixincreate added a commit that referenced this pull request Sep 5, 2024
* 'main' of github.com:juspay/hyperswitch:
  feat(customer_v2): Add customer V2 delete api (#5518)
  chore(version): 2024.09.05.0
  feat(user_roles): get user role details (#5777)
  feat(users): Add profile level invites (#5793)
  refactor(router): profile based routes for payouts (#5794)
  Feat(connector): [Fiuu] Add Card Flows (#5786)
  fix(cypress): fix fiservemea configs for cypress (#5772)
  fix(cypress): `api_key` check in cypress (#5787)
  feat(payment_methods_v2): Implemented Diesel and Domain models for v2 (#5700)
  fix(payout): query for getting a list of active payout IDs (#5771)
  refactor(router): remove admin v2 intermediate features (#5780)
  feat(revert): populate payment method details in payments response (#5785)
  chore(version): 2024.09.04.0
  fix(connector): skip 3DS in `network_transaction_id` flow for cybersource (#5781)
  refactor(euclid): check the authenticity of profile_id being used (#5647)
  feat(analytics): refactor and introduce analytics APIs to accommodate OrgLevel, MerchantLevel and ProfileLevel authentication (#5729)
  fix(router): make customer details None in the `Psync` flow if the customer is deleted (#5732)
  feat(connector): [DEUTSCHE] Add template code (#5774)
  chore(version): 2024.09.03.1
  fix(router): send post message to window.parent instead of window.top in external 3ds flow (#5778)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-connector-integration Area: Connector integration M-api-contract-changes Metadata: This PR involves API contract changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants