@@ -13,7 +13,6 @@ use time::PrimitiveDateTime;
13
13
14
14
use super :: errors:: { self , RouterResult , StorageErrorExt } ;
15
15
use crate :: {
16
- core:: payments:: helpers,
17
16
errors:: RouterResponse ,
18
17
routes:: AppState ,
19
18
services,
@@ -68,18 +67,6 @@ pub async fn intiate_payment_link_flow(
68
67
. get_required_value ( "payment_link_id" )
69
68
. change_context ( errors:: ApiErrorResponse :: PaymentLinkNotFound ) ?;
70
69
71
- helpers:: validate_payment_status_against_not_allowed_statuses (
72
- & payment_intent. status ,
73
- & [
74
- storage_enums:: IntentStatus :: Cancelled ,
75
- storage_enums:: IntentStatus :: Succeeded ,
76
- storage_enums:: IntentStatus :: Processing ,
77
- storage_enums:: IntentStatus :: RequiresCapture ,
78
- storage_enums:: IntentStatus :: RequiresMerchantAction ,
79
- ] ,
80
- "use payment link for" ,
81
- ) ?;
82
-
83
70
let merchant_name_from_merchant_account = merchant_account
84
71
. merchant_name
85
72
. clone ( )
@@ -101,7 +88,7 @@ pub async fn intiate_payment_link_flow(
101
88
}
102
89
} ;
103
90
104
- let return_url = if let Some ( payment_create_return_url) = payment_intent. return_url {
91
+ let return_url = if let Some ( payment_create_return_url) = payment_intent. return_url . clone ( ) {
105
92
payment_create_return_url
106
93
} else {
107
94
merchant_account
@@ -114,23 +101,73 @@ pub async fn intiate_payment_link_flow(
114
101
let ( pub_key, currency, client_secret) = validate_sdk_requirements (
115
102
merchant_account. publishable_key ,
116
103
payment_intent. currency ,
117
- payment_intent. client_secret ,
104
+ payment_intent. client_secret . clone ( ) ,
118
105
) ?;
119
- let order_details = validate_order_details ( payment_intent. order_details , currency) ?;
106
+ let amount = currency
107
+ . to_currency_base_unit ( payment_intent. amount )
108
+ . into_report ( )
109
+ . change_context ( errors:: ApiErrorResponse :: CurrencyConversionFailed ) ?;
110
+ let order_details = validate_order_details ( payment_intent. order_details . clone ( ) , currency) ?;
120
111
121
112
let session_expiry = payment_link. fulfilment_time . unwrap_or_else ( || {
122
- common_utils:: date_time:: now ( )
113
+ payment_intent
114
+ . created_at
123
115
. saturating_add ( time:: Duration :: seconds ( DEFAULT_SESSION_EXPIRY ) )
124
116
} ) ;
125
117
126
118
// converting first letter of merchant name to upperCase
127
119
let merchant_name = capitalize_first_char ( & payment_link_config. seller_name ) ;
120
+ let css_script = get_color_scheme_css ( payment_link_config. clone ( ) ) ;
121
+ let payment_link_status = check_payment_link_status ( session_expiry) ;
122
+
123
+ if check_payment_link_invalid_conditions (
124
+ & payment_intent. status ,
125
+ & [
126
+ storage_enums:: IntentStatus :: Cancelled ,
127
+ storage_enums:: IntentStatus :: Failed ,
128
+ storage_enums:: IntentStatus :: Processing ,
129
+ storage_enums:: IntentStatus :: RequiresCapture ,
130
+ storage_enums:: IntentStatus :: RequiresMerchantAction ,
131
+ storage_enums:: IntentStatus :: Succeeded ,
132
+ ] ,
133
+ ) || payment_link_status == api_models:: payments:: PaymentLinkStatus :: Expired
134
+ {
135
+ let attempt_id = payment_intent. active_attempt . get_id ( ) . clone ( ) ;
136
+ let payment_attempt = db
137
+ . find_payment_attempt_by_payment_id_merchant_id_attempt_id (
138
+ & payment_intent. payment_id ,
139
+ & merchant_id,
140
+ & attempt_id. clone ( ) ,
141
+ merchant_account. storage_scheme ,
142
+ )
143
+ . await
144
+ . to_not_found_response ( errors:: ApiErrorResponse :: PaymentNotFound ) ?;
145
+ let payment_details = api_models:: payments:: PaymentLinkStatusDetails {
146
+ amount,
147
+ currency,
148
+ payment_id : payment_intent. payment_id ,
149
+ merchant_name,
150
+ merchant_logo : payment_link_config. clone ( ) . logo ,
151
+ created : payment_link. created_at ,
152
+ intent_status : payment_intent. status ,
153
+ payment_link_status,
154
+ error_code : payment_attempt. error_code ,
155
+ error_message : payment_attempt. error_message ,
156
+ } ;
157
+ let js_script = get_js_script (
158
+ api_models:: payments:: PaymentLinkData :: PaymentLinkStatusDetails ( payment_details) ,
159
+ ) ?;
160
+ let payment_link_error_data = services:: PaymentLinkStatusData {
161
+ js_script,
162
+ css_script,
163
+ } ;
164
+ return Ok ( services:: ApplicationResponse :: PaymenkLinkForm ( Box :: new (
165
+ services:: api:: PaymentLinkAction :: PaymentLinkStatus ( payment_link_error_data) ,
166
+ ) ) ) ;
167
+ } ;
128
168
129
169
let payment_details = api_models:: payments:: PaymentLinkDetails {
130
- amount : currency
131
- . to_currency_base_unit ( payment_intent. amount )
132
- . into_report ( )
133
- . change_context ( errors:: ApiErrorResponse :: CurrencyConversionFailed ) ?,
170
+ amount,
134
171
currency,
135
172
payment_id : payment_intent. payment_id ,
136
173
merchant_name,
@@ -145,29 +182,28 @@ pub async fn intiate_payment_link_flow(
145
182
merchant_description : payment_intent. description ,
146
183
} ;
147
184
148
- let js_script = get_js_script ( payment_details) ?;
149
- let css_script = get_color_scheme_css ( payment_link_config. clone ( ) ) ;
185
+ let js_script = get_js_script ( api_models:: payments:: PaymentLinkData :: PaymentLinkDetails (
186
+ payment_details,
187
+ ) ) ?;
150
188
let payment_link_data = services:: PaymentLinkFormData {
151
189
js_script,
152
190
sdk_url : state. conf . payment_link . sdk_url . clone ( ) ,
153
191
css_script,
154
192
} ;
155
193
Ok ( services:: ApplicationResponse :: PaymenkLinkForm ( Box :: new (
156
- payment_link_data,
194
+ services :: api :: PaymentLinkAction :: PaymentLinkFormData ( payment_link_data) ,
157
195
) ) )
158
196
}
159
197
160
198
/*
161
199
The get_js_script function is used to inject dynamic value to payment_link sdk, which is unique to every payment.
162
200
*/
163
201
164
- fn get_js_script (
165
- payment_details : api_models:: payments:: PaymentLinkDetails ,
166
- ) -> RouterResult < String > {
202
+ fn get_js_script ( payment_details : api_models:: payments:: PaymentLinkData ) -> RouterResult < String > {
167
203
let payment_details_str = serde_json:: to_string ( & payment_details)
168
204
. into_report ( )
169
205
. change_context ( errors:: ApiErrorResponse :: InternalServerError )
170
- . attach_printable ( "Failed to serialize PaymentLinkDetails " ) ?;
206
+ . attach_printable ( "Failed to serialize PaymentLinkData " ) ?;
171
207
Ok ( format ! ( "window.__PAYMENT_DETAILS = {payment_details_str};" ) )
172
208
}
173
209
@@ -218,11 +254,11 @@ pub async fn list_payment_link(
218
254
}
219
255
220
256
pub fn check_payment_link_status (
221
- max_age : PrimitiveDateTime ,
257
+ payment_link_expiry : PrimitiveDateTime ,
222
258
) -> api_models:: payments:: PaymentLinkStatus {
223
259
let curr_time = common_utils:: date_time:: now ( ) ;
224
260
225
- if curr_time > max_age {
261
+ if curr_time > payment_link_expiry {
226
262
api_models:: payments:: PaymentLinkStatus :: Expired
227
263
} else {
228
264
api_models:: payments:: PaymentLinkStatus :: Active
@@ -369,3 +405,10 @@ fn capitalize_first_char(s: &str) -> String {
369
405
s. to_owned ( )
370
406
}
371
407
}
408
+
409
+ fn check_payment_link_invalid_conditions (
410
+ intent_status : & storage_enums:: IntentStatus ,
411
+ not_allowed_statuses : & [ storage_enums:: IntentStatus ] ,
412
+ ) -> bool {
413
+ not_allowed_statuses. contains ( intent_status)
414
+ }
0 commit comments