@@ -17,13 +17,15 @@ import {
1717 *
1818 * After each billing scheduler run, also triggers the payment scheduler
1919 * cron job and verifies that the resulting CustomerBill ends up 'settled'
20- * once the recurring charge against the stored Stripe payment method succeeds.
20+ * once the recurring charge against the stored payment method succeeds.
2121 *
2222 * Requires BAE_CB_BILLING_HTTP_ENABLED=true in the charging container.
2323 */
2424const CHARGING_URL = 'http://localhost:8006'
2525const TMF_URL = 'http://localhost:8633'
26+ const SCORPIO_URL = 'http://localhost:1026'
2627const BILLING_SERVER_URL = 'http://localhost:4201'
28+ const IS_REDSYS = Cypress . env ( 'PAYMENT_METHOD' ) === 'redsys'
2729
2830const runPaymentScheduler = ( ) => {
2931 cy . request ( { url : `${ CHARGING_URL } /charging/api/test/paymentScheduler` , method : 'POST' } ) . then ( ( res ) => {
@@ -41,6 +43,65 @@ const expectCustomerBillState = (billId: string, expectedState: string) => {
4143 } )
4244}
4345
46+ const patchCustomerBillAmountInScorpio = (
47+ billId : string ,
48+ taxIncludedAmount : { unit : string , value : number | string }
49+ ) => {
50+ const value = Number ( taxIncludedAmount . value )
51+
52+ cy . request ( {
53+ url : `${ SCORPIO_URL } /ngsi-ld/v1/entities/${ encodeURIComponent ( billId ) } /attrs` ,
54+ method : 'PATCH' ,
55+ headers : { 'Content-Type' : 'application/ld+json' } ,
56+ body : {
57+ taxIncludedAmount : {
58+ type : 'Property' ,
59+ tmfValue : { type : 'Property' , value } ,
60+ unit : { type : 'Property' , value : taxIncludedAmount . unit } ,
61+ value : { tmfValue : value , unit : taxIncludedAmount . unit } ,
62+ } ,
63+ '@context' : [ 'https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.7.jsonld' ] ,
64+ } ,
65+ } ) . then ( ( res ) => {
66+ expect ( res . status ) . to . eq ( 204 )
67+ } )
68+ }
69+
70+ const expectRecurringPaymentToRetry = (
71+ billId : string ,
72+ stripeStatus : 'processing' | 'requires_payment_method'
73+ ) => {
74+ const runAndVerifyRetry = ( restorePayment : ( ) => void = ( ) => { } ) => {
75+ runPaymentScheduler ( )
76+ expectCustomerBillState ( billId , 'new' )
77+
78+ restorePayment ( )
79+ runPaymentScheduler ( )
80+ expectCustomerBillState ( billId , 'settled' )
81+ }
82+
83+ if ( ! IS_REDSYS ) {
84+ cy . request ( `${ BILLING_SERVER_URL } /stripe/set-recurring-status/${ stripeStatus } ` )
85+ runAndVerifyRetry ( )
86+ return
87+ }
88+
89+ cy . request ( {
90+ url : `${ TMF_URL } /tmf-api/customerBillManagement/v4/customerBill/${ billId } ` ,
91+ method : 'GET' ,
92+ } ) . then ( ( res ) => {
93+ expect ( res . status ) . to . eq ( 200 )
94+ const originalAmount = res . body . taxIncludedAmount
95+ const rejectedAmount = {
96+ ...originalAmount ,
97+ value : `${ Math . floor ( Number ( originalAmount . value ) ) } .96` ,
98+ }
99+
100+ patchCustomerBillAmountInScorpio ( billId , rejectedAmount )
101+ runAndVerifyRetry ( ( ) => patchCustomerBillAmountInScorpio ( billId , originalAmount ) )
102+ } )
103+ }
104+
44105describe ( 'Billing Scheduler Period Coverage' , {
45106 viewportHeight : 1080 ,
46107 viewportWidth : 1920 ,
@@ -66,6 +127,7 @@ describe('Billing Scheduler Period Coverage', {
66127 cy . intercept ( 'GET' , '**/ordering/productOrder*' ) . as ( 'getOrders' )
67128 cy . intercept ( 'GET' , '**/account/billingAccount*' ) . as ( 'getBilling' )
68129 cy . intercept ( 'GET' , '**/shoppingCart/item/' ) . as ( 'cartItem' )
130+ cy . intercept ( 'GET' , '**/paymentInfo' ) . as ( 'getPaymentInfo' )
69131
70132 // ============================================
71133 // Verify catalog and product spec exist (from happy journey)
@@ -140,7 +202,12 @@ describe('Billing Scheduler Period Coverage', {
140202 cy . getBySel ( 'savePricePlan' ) . click ( )
141203 cy . getBySel ( 'offerNext' ) . click ( )
142204
143- cy . getBySel ( 'procurement' ) . select ( 'automatic' )
205+ cy . wait ( '@getPaymentInfo' )
206+ . its ( 'response.body.gatewaysCount' )
207+ . should ( 'be.greaterThan' , 0 )
208+ cy . getBySel ( 'procurement' )
209+ . select ( 'automatic' )
210+ . should ( 'have.value' , 'automatic' )
144211 cy . getBySel ( 'offerNext' ) . click ( )
145212
146213 waitForInitialPaginatedList ( '**/catalog/productOffering?*' , ( ) => {
@@ -189,16 +256,19 @@ describe('Billing Scheduler Period Coverage', {
189256 cy . getBySel ( 'cartPurchase' ) . click ( )
190257
191258 cy . wait ( '@getBilling' )
259+ cy . wait ( 2000 )
260+ cy . deferPaymentRedirect ( )
192261 cy . getBySel ( 'checkout' ) . should ( 'be.visible' ) . should ( 'not.be.disabled' ) . click ( )
193262 cy . wait ( '@createOrder' )
194- cy . wait ( '@getOrders' )
263+ cy . waitForOrdersBeforePayment ( )
195264
196265 // ============================================
197266 // Step 4: Complete payment (activation)
198267 // ============================================
199268 cy . intercept ( '**/charging/api/orderManagement/orders/confirm/' ) . as ( 'checkin' )
200- cy . completePayment ( )
269+ cy . completePayment ( { recurring : true } )
201270 cy . wait ( '@checkin' )
271+ cy . waitForOrdersAfterPayment ( )
202272
203273 cy . getBySel ( 'ordersTable' ) . should ( 'be.visible' )
204274 cy . getBySel ( 'ordersTable' ) . find ( 'tbody tr' ) . first ( ) . within ( ( ) => {
@@ -409,18 +479,12 @@ describe('Billing Scheduler Period Coverage', {
409479 expect ( new Date ( acbrs [ 0 ] . periodCoverage . endDateTime ) . getTime ( ) ) . to . equal ( week2End . getTime ( ) )
410480
411481 // ============================================
412- // Payment scheduler: recurring charge comes back pending on the
413- // first attempt, so the CB must be left untouched ('new'), then
414- // settles on the next scheduler run once the charge resolves.
482+ // Stripe leaves the first charge pending; Redsys uses a sandbox
483+ // rejection amount. Both must leave the bill 'new' and then settle.
415484 // ============================================
416485 const cbId = acbrs [ 0 ] . bill . id
417486
418- cy . request ( `${ BILLING_SERVER_URL } /stripe/set-recurring-status/processing` )
419- runPaymentScheduler ( )
420- expectCustomerBillState ( cbId , 'new' )
421-
422- runPaymentScheduler ( )
423- expectCustomerBillState ( cbId , 'settled' )
487+ expectRecurringPaymentToRetry ( cbId , 'processing' )
424488 } )
425489
426490 // — Week 3 —
@@ -465,18 +529,12 @@ describe('Billing Scheduler Period Coverage', {
465529 expect ( new Date ( acbrs [ 0 ] . periodCoverage . endDateTime ) . getTime ( ) ) . to . equal ( week4End . getTime ( ) )
466530
467531 // ============================================
468- // Payment scheduler: recurring charge fails on the first attempt,
469- // so the CB must be left untouched ('new'), then settles on the
470- // next scheduler run once the charge succeeds.
532+ // Stripe requires a new payment method; Redsys uses a sandbox
533+ // rejection amount. Both must leave the bill 'new' and then settle.
471534 // ============================================
472535 const cbId = acbrs [ 0 ] . bill . id
473536
474- cy . request ( `${ BILLING_SERVER_URL } /stripe/set-recurring-status/requires_payment_method` )
475- runPaymentScheduler ( )
476- expectCustomerBillState ( cbId , 'new' )
477-
478- runPaymentScheduler ( )
479- expectCustomerBillState ( cbId , 'settled' )
537+ expectRecurringPaymentToRetry ( cbId , 'requires_payment_method' )
480538 } )
481539
482540 // ============================================
0 commit comments