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(router): add list payment link support #2805

Merged
merged 51 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
cd818a2
feat(router): added merchant custom name support for payment link
sahkal Oct 25, 2023
30590d6
docs(openapi): re-generate OpenAPI specification
github-actions[bot] Oct 25, 2023
865741d
refactor(router): addressed pr comments
sahkal Oct 27, 2023
be0e8e3
Merge branch 'add-merchant-custom-name-payment-link' of https://githu…
sahkal Oct 27, 2023
214675e
feat: add currency symbols (#2709)
kashif-m Oct 28, 2023
80996c2
feat(router): added new design along with sdk theme for payment link
sahkal Oct 30, 2023
d507ed0
docs(openapi): re-generate OpenAPI specification
github-actions[bot] Oct 30, 2023
e05614d
feat(router): added payment_link_config support for each payment
sahkal Oct 31, 2023
4f501aa
refactor(router): addressed pr comments
sahkal Oct 31, 2023
dde38e0
refactor(router): merged with latest changes
sahkal Oct 31, 2023
4c37414
feat(payment_link): added payment link list support
sahkal Nov 6, 2023
77cd091
feat(router): added status support to list payment link
sahkal Nov 6, 2023
43e057d
feat(router): added currency and status support for payment link list
sahkal Nov 6, 2023
5efb34c
refactor(router): addressed pr comments
sahkal Nov 6, 2023
310217c
refactor(router): syned with main
sahkal Nov 6, 2023
bd53ef6
refactor(router): addressed pr comments
sahkal Nov 7, 2023
47e7dba
Merge branch 'payment-link-new-design' of https://github.com/juspay/h…
sahkal Nov 7, 2023
9441b5f
refactor(router): syned with latest design
sahkal Nov 8, 2023
eec8f33
refactor(router): fixed spell check issue
sahkal Nov 8, 2023
b138667
refactor(router): syned with latest changes
sahkal Nov 10, 2023
62a0d04
refactor(router): resolved merge conflicts synced with main
sahkal Nov 10, 2023
3155c84
refactor(router): resolved merge conflicts
sahkal Nov 10, 2023
46799d5
refactor(router): removed commented code
sahkal Nov 10, 2023
f504235
refactor(router): removed unwanted change
sahkal Nov 10, 2023
8d7d812
refactor(router): removed extra unwanted data from readme
sahkal Nov 10, 2023
40a8b36
refactor(router): fixed schema.rs issue
sahkal Nov 10, 2023
6529659
refactor(router): fixed db mismatch issue
sahkal Nov 10, 2023
8f5fb07
refactor(router): fixed spell check issue
sahkal Nov 10, 2023
8a3d77f
refactor(router): fixed open-api and clippy issue
sahkal Nov 10, 2023
847b356
refactor(router): fixed features olap oltp
sahkal Nov 10, 2023
e6ac23d
refactor(router): fixed cargo clippy issue
sahkal Nov 14, 2023
7a09b37
refactor(router): resolved merge conflicts
sahkal Nov 14, 2023
bef803b
refactor(router): fixed openapi issue
sahkal Nov 16, 2023
3ba27b4
refactor(router): fixed open api issue
sahkal Nov 16, 2023
a0da25c
Merge branch 'main' of https://github.com/juspay/hyperswitch into lis…
sahkal Nov 16, 2023
84dd4f9
fix(payment_link): fix status page UI
Nov 16, 2023
eb41e6f
refactor(router): resolved merge conflicts
sahkal Nov 17, 2023
f9a19fc
fix(router): added scroll view for ios
sahkal Nov 17, 2023
ed3e2a3
refactor(router): addressed pr comments
sahkal Nov 18, 2023
d16f31b
refactor(router): addressed pr comments
sahkal Nov 21, 2023
7618aa8
Merge branch 'main' into list-payment-link-support
sahkal Nov 21, 2023
cd7d1b4
refactor(router): fixed error message for payment which already has s…
sahkal Nov 21, 2023
b45a902
Merge branch 'list-payment-link-support' of https://github.com/juspay…
sahkal Nov 21, 2023
837887d
refactor(router): fixed func name for fetching list payment link
sahkal Nov 21, 2023
bccedec
refactor(router): addressed pr comments
sahkal Nov 21, 2023
9cb4ed1
Merge branch 'main' into list-payment-link-support
sahkal Nov 21, 2023
fd4ffa9
Merge branch 'main' of github.com:juspay/hyperswitch into list-paymen…
sahkal Nov 21, 2023
9bc027c
Merge branch 'list-payment-link-support' of github.com:juspay/hypersw…
sahkal Nov 21, 2023
e49cb6b
refactor(router): addressed pr comments
sahkal Nov 22, 2023
6ff8791
Merge branch 'list-payment-link-support' of https://github.com/juspay…
sahkal Nov 22, 2023
0453bf6
Merge branch 'main' into list-payment-link-support
Gnanasundari24 Nov 22, 2023
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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ The fastest and easiest way to try hyperswitch is via our CDK scripts

&emsp;&emsp; <a href="https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?stackName=HyperswitchBootstarp&templateURL=https://hyperswitch-synth.s3.eu-central-1.amazonaws.com/hs-starter-config.yaml"><img src="./docs/imgs/aws_button.png" height="35"></a>


2. Sign-in to your AWS console.

3. Follow the instructions provided on the console to successfully deploy Hyperswitch
Expand Down
1 change: 1 addition & 0 deletions crates/api_models/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl_misc_api_event_type!(
MandateResponse,
MandateRevokedResponse,
RetrievePaymentLinkRequest,
PaymentLinkListConstraints,
MandateId,
DisputeListConstraints,
RetrieveApiKeyResponse,
Expand Down
63 changes: 58 additions & 5 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3194,18 +3194,17 @@ pub struct PaymentLinkResponse {
#[derive(Clone, Debug, serde::Serialize, ToSchema)]
pub struct RetrievePaymentLinkResponse {
pub payment_link_id: String,
pub payment_id: String,
pub merchant_id: String,
pub link_to_pay: String,
pub amount: i64,
#[schema(value_type = Option<Currency>, example = "USD")]
pub currency: Option<api_enums::Currency>,
#[serde(with = "common_utils::custom_serde::iso8601")]
pub created_at: PrimitiveDateTime,
#[serde(with = "common_utils::custom_serde::iso8601")]
pub last_modified_at: PrimitiveDateTime,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub link_expiry: Option<PrimitiveDateTime>,
pub description: Option<String>,
pub status: String,
#[schema(value_type = Option<Currency>)]
pub currency: Option<api_enums::Currency>,
}

#[derive(Clone, Debug, serde::Deserialize, ToSchema, serde::Serialize)]
Expand All @@ -3230,3 +3229,57 @@ pub struct PaymentLinkDetails {
pub max_items_visible_after_collapse: i8,
pub sdk_theme: Option<String>,
}

#[derive(Clone, Debug, serde::Deserialize, ToSchema, serde::Serialize)]
#[serde(deny_unknown_fields)]

pub struct PaymentLinkListConstraints {
/// limit on the number of objects to return
pub limit: Option<i64>,

/// The time at which payment link is created
#[schema(example = "2022-09-10T10:11:12Z")]
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub created: Option<PrimitiveDateTime>,

/// Time less than the payment link created time
#[schema(example = "2022-09-10T10:11:12Z")]
#[serde(
default,
with = "common_utils::custom_serde::iso8601::option",
rename = "created.lt"
)]
pub created_lt: Option<PrimitiveDateTime>,

/// Time greater than the payment link created time
#[schema(example = "2022-09-10T10:11:12Z")]
#[serde(
default,
with = "common_utils::custom_serde::iso8601::option",
rename = "created.gt"
)]
pub created_gt: Option<PrimitiveDateTime>,

/// Time less than or equals to the payment link created time
#[schema(example = "2022-09-10T10:11:12Z")]
#[serde(
default,
with = "common_utils::custom_serde::iso8601::option",
rename = "created.lte"
)]
pub created_lte: Option<PrimitiveDateTime>,

/// Time greater than or equals to the payment link created time
#[schema(example = "2022-09-10T10:11:12Z")]
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
#[serde(rename = "created.gte")]
pub created_gte: Option<PrimitiveDateTime>,
}

#[derive(Clone, Debug, serde::Serialize, ToSchema)]
pub struct PaymentLinkListResponse {
/// The number of payment links included in the list
pub size: usize,
// The list of payment link response objects
pub data: Vec<PaymentLinkResponse>,
}
3 changes: 3 additions & 0 deletions crates/common_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pub const PAYMENTS_LIST_MAX_LIMIT_V1: u32 = 100;
/// Maximum limit for payments list post api with filters
pub const PAYMENTS_LIST_MAX_LIMIT_V2: u32 = 20;

/// Maximum limit for payment link list get api
pub const PAYMENTS_LINK_LIST_LIMIT: u32 = 100;

/// surcharge percentage maximum precision length
pub const SURCHARGE_PERCENTAGE_PRECISION_LENGTH: u8 = 2;

Expand Down
2 changes: 2 additions & 0 deletions crates/diesel_models/src/payment_link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct PaymentLink {
pub fulfilment_time: Option<PrimitiveDateTime>,
pub custom_merchant_name: Option<String>,
pub payment_link_config: Option<serde_json::Value>,
pub description: Option<String>,
}

#[derive(
Expand Down Expand Up @@ -51,4 +52,5 @@ pub struct PaymentLinkNew {
pub fulfilment_time: Option<PrimitiveDateTime>,
pub custom_merchant_name: Option<String>,
pub payment_link_config: Option<serde_json::Value>,
pub description: Option<String>,
}
2 changes: 2 additions & 0 deletions crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,8 @@ diesel::table! {
#[max_length = 64]
custom_merchant_name -> Nullable<Varchar>,
payment_link_config -> Nullable<Jsonb>,
#[max_length = 255]
description -> Nullable<Varchar>,
}
}

Expand Down
45 changes: 41 additions & 4 deletions crates/router/src/core/payment_link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ use common_utils::{
ext_traits::{OptionExt, ValueExt},
};
use error_stack::{IntoReport, ResultExt};
use futures::future;
use masking::{PeekInterface, Secret};
use time::PrimitiveDateTime;

use super::errors::{self, RouterResult, StorageErrorExt};
use crate::{
core::payments::helpers,
errors::RouterResponse,
routes::AppState,
services,
types::{domain, storage::enums as storage_enums, transformers::ForeignFrom},
types::{
api::payment_link::PaymentLinkResponseExt, domain, storage::enums as storage_enums,
transformers::ForeignFrom,
},
};

pub async fn retrieve_payment_link(
Expand All @@ -27,8 +32,12 @@ pub async fn retrieve_payment_link(
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentLinkNotFound)?;

let response =
api_models::payments::RetrievePaymentLinkResponse::foreign_from(payment_link_object);
let status = check_payment_link_status(payment_link_object.fulfilment_time);

let response = api_models::payments::RetrievePaymentLinkResponse::foreign_from((
payment_link_object,
status,
));
Ok(services::ApplicationResponse::Json(response))
}

Expand Down Expand Up @@ -62,7 +71,7 @@ pub async fn intiate_payment_link_flow(
storage_enums::IntentStatus::RequiresCapture,
storage_enums::IntentStatus::RequiresMerchantAction,
],
"create payment link",
"use payment link for",
)?;

let payment_link = db
Expand Down Expand Up @@ -197,6 +206,34 @@ fn validate_sdk_requirements(
Ok((pub_key, currency, client_secret))
}

pub async fn list_payment_link(
state: AppState,
merchant: domain::MerchantAccount,
constraints: api_models::payments::PaymentLinkListConstraints,
) -> RouterResponse<Vec<api_models::payments::RetrievePaymentLinkResponse>> {
let db = state.store.as_ref();
let payment_link = db
.list_payment_link_by_merchant_id(&merchant.merchant_id, constraints)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to retrieve payment link")?;
let payment_link_list = future::try_join_all(payment_link.into_iter().map(|payment_link| {
api_models::payments::RetrievePaymentLinkResponse::from_db_payment_link(payment_link)
}))
.await?;
Ok(services::ApplicationResponse::Json(payment_link_list))
}

pub fn check_payment_link_status(fulfillment_time: Option<PrimitiveDateTime>) -> String {
let curr_time = Some(common_utils::date_time::now());

if curr_time > fulfillment_time {
"expired".to_string()
} else {
"active".to_string()
}
}

fn validate_order_details(
order_details: Option<Vec<Secret<serde_json::Value>>>,
) -> Result<
Expand Down
7 changes: 6 additions & 1 deletion crates/router/src/core/payment_link/payment_link.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
width: 100%;
height: 100%;
max-width: 1900px;
overflow: scroll;
}

#hyper-footer {
Expand Down Expand Up @@ -418,6 +419,7 @@
margin-top: 20px;
border-radius: 3px;
border: 1px solid #e6e6e6;
width: 90vw;
}

.hyper-checkout-status-item {
Expand All @@ -432,12 +434,15 @@
}

.hyper-checkout-item-header {
width: 15ch;
min-width: 13ch;
font-size: 12px;
}

.hyper-checkout-item-value {
font-size: 12px;
overflow-x: hidden;
overflow-y: auto;
word-wrap: break-word;
}

@keyframes loading {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
db,
state,
amount,
request.description.clone(),
)
.await?
} else {
Expand Down Expand Up @@ -779,6 +780,7 @@ pub fn payments_create_request_validation(
Ok((amount, currency))
}

#[allow(clippy::too_many_arguments)]
async fn create_payment_link(
request: &api::PaymentsRequest,
payment_link_object: api_models::payments::PaymentLinkObject,
Expand All @@ -787,6 +789,7 @@ async fn create_payment_link(
db: &dyn StorageInterface,
state: &AppState,
amount: api::Amount,
description: Option<String>,
) -> RouterResult<Option<api_models::payments::PaymentLinkResponse>> {
let created_at @ last_modified_at = Some(common_utils::date_time::now());
let domain = if let Some(domain_name) = payment_link_object.merchant_custom_domain_name {
Expand Down Expand Up @@ -817,6 +820,7 @@ async fn create_payment_link(
created_at,
last_modified_at,
fulfilment_time: payment_link_object.link_expiry,
description,
payment_link_config,
custom_merchant_name: payment_link_object.custom_merchant_name,
};
Expand Down
32 changes: 30 additions & 2 deletions crates/router/src/db/payment_link.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use error_stack::IntoReport;

use super::{MockDb, Store};
use crate::{
connection,
core::errors::{self, CustomResult},
types::storage,
db::MockDb,
services::Store,
types::storage::{self, PaymentLinkDbExt},
};

#[async_trait::async_trait]
Expand All @@ -18,6 +19,12 @@ pub trait PaymentLinkInterface {
&self,
_payment_link: storage::PaymentLinkNew,
) -> CustomResult<storage::PaymentLink, errors::StorageError>;

async fn list_payment_link_by_merchant_id(
&self,
merchant_id: &str,
payment_link_constraints: api_models::payments::PaymentLinkListConstraints,
) -> CustomResult<Vec<storage::PaymentLink>, errors::StorageError>;
}

#[async_trait::async_trait]
Expand All @@ -44,6 +51,18 @@ impl PaymentLinkInterface for Store {
.map_err(Into::into)
.into_report()
}

async fn list_payment_link_by_merchant_id(
&self,
merchant_id: &str,
payment_link_constraints: api_models::payments::PaymentLinkListConstraints,
) -> CustomResult<Vec<storage::PaymentLink>, errors::StorageError> {
let conn = connection::pg_connection_read(self).await?;
storage::PaymentLink::filter_by_constraints(&conn, merchant_id, payment_link_constraints)
.await
.map_err(Into::into)
.into_report()
}
}

#[async_trait::async_trait]
Expand All @@ -63,4 +82,13 @@ impl PaymentLinkInterface for MockDb {
// TODO: Implement function for `MockDb`x
Err(errors::StorageError::MockDbError)?
}

async fn list_payment_link_by_merchant_id(
&self,
_merchant_id: &str,
_payment_link_constraints: api_models::payments::PaymentLinkListConstraints,
) -> CustomResult<Vec<storage::PaymentLink>, errors::StorageError> {
// TODO: Implement function for `MockDb`x
Err(errors::StorageError::MockDbError)?
}
}
2 changes: 1 addition & 1 deletion crates/router/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ pub fn mk_app(
.service(routes::PaymentMethods::server(state.clone()))
.service(routes::EphemeralKey::server(state.clone()))
.service(routes::Webhooks::server(state.clone()))
.service(routes::PaymentLink::server(state.clone()));
}

#[cfg(feature = "olap")]
Expand All @@ -147,6 +146,7 @@ pub fn mk_app(
.service(routes::Routing::server(state.clone()))
.service(routes::LockerMigrate::server(state.clone()))
.service(routes::Gsm::server(state.clone()))
.service(routes::PaymentLink::server(state.clone()))
.service(routes::User::server(state.clone()))
}

Expand Down
10 changes: 7 additions & 3 deletions crates/router/src/routes/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ use super::routing as cloud_routing;
#[cfg(all(feature = "olap", feature = "kms"))]
use super::verification::{apple_pay_merchant_registration, retrieve_apple_pay_verified_domains};
#[cfg(feature = "olap")]
use super::{admin::*, api_keys::*, disputes::*, files::*, gsm::*, locker_migration, user::*};
use super::{cache::*, health::*, payment_link::*};
use super::{
admin::*, api_keys::*, disputes::*, files::*, gsm::*, locker_migration, payment_link::*,
user::*,
};
use super::{cache::*, health::*};
#[cfg(any(feature = "olap", feature = "oltp"))]
use super::{configs::*, customers::*, mandates::*, payments::*, refunds::*};
#[cfg(feature = "oltp")]
Expand Down Expand Up @@ -675,11 +678,12 @@ impl Cache {
}

pub struct PaymentLink;

#[cfg(feature = "olap")]
sahkal marked this conversation as resolved.
Show resolved Hide resolved
impl PaymentLink {
pub fn server(state: AppState) -> Scope {
web::scope("/payment_link")
.app_data(web::Data::new(state))
.service(web::resource("/list").route(web::post().to(payments_link_list)))
.service(
web::resource("/{payment_link_id}").route(web::get().to(payment_link_retrieve)),
)
Expand Down
5 changes: 4 additions & 1 deletion crates/router/src/routes/lock_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,12 @@ impl From<Flow> for ApiIdentifier {
| Flow::BusinessProfileDelete
| Flow::BusinessProfileList => Self::Business,

Flow::PaymentLinkRetrieve | Flow::PaymentLinkInitiate | Flow::PaymentLinkList => {
Self::PaymentLink
}

Flow::Verification => Self::Verification,

Flow::PaymentLinkInitiate | Flow::PaymentLinkRetrieve => Self::PaymentLink,
Flow::RustLockerMigration => Self::RustLockerMigration,
Flow::GsmRuleCreate
| Flow::GsmRuleRetrieve
Expand Down
Loading
Loading