---
# System prepended metadata

title: Payments Journey flow
tags: [journey, payments, component-tests]

---

Payments Journey flow
===


## Table of Contents

[TOC]


# Stripe Test Journeys
---

```gherkin=
Feature: Create a Stripe Customer (Customer Stream)

  Scenario: Create a stripe customer (success)
    Given a customer.created/enrolled event
    And the BillingEngineId exists
    When the event is consumed from the Customers Stream
    Then the record is persisted with a stripe id in our db
    And stripeCustomer.created event gets fired onto payments stream
    
  Scenario: Create a stripe customer without BillingEngineId (failure)
    Given a customer.created/enrolled event
    And there is no BillingEngineId
    When the event is consumed from the Customers Stream
    Then a record is not created for this customer in our db
    
  Scenario: Error whilst creating a stripe customer (4xx)
    Given a customer.created event
    And the BillingEngineId exists
    And Stripe returns statusCode 4xx twice then a 200
    When the event is consumed from the Customers Stream
    Then the Stripe Api has been called once
    And the record is persisted without a stripe id in our db
        
  Scenario: Transient Error whilst creating a stripe customer (5xx)
    Given a customer.created event
    And the BillingEngineId exists
    And Stripe returns statusCode 5xx twice then a 200
    When the event is consumed from the Customers Stream
    Then the Stripe Api has been called thrice
    And the record is persisted with a stripe id in our db
    And stripeCustomer.created event gets fired onto payments stream
```

```gherkin=
Feature: Update a Stripe Customer (Customer Stream)
    
  Scenario: Update a stripe customer (success)
    Given a customer.updated event
    And the StripeCustomerId exists
    When the record metadata is updated (billingEngineId and billingEngineDisplayNumber)
    Then the record is updated in our db
    And the customer is updated in stripe wit the updated metadata
    And stripeCustomer.updted event gets fired onto payments stream
    
  Scenario: Error whilst updating a stripe customer (4xx)
    Given a customer.updated event
    And the StripeCustomerId exists
    And Stripe returns statusCode 4xx twice then a 200
    When the event is consumed from the Customers Stream
    Then the Stripe Api has been called once
    And the record is persisted without a stripe id in our db
        
  Scenario: Transient Error whilst updating a stripe customer (5xx)
    Given a customer.updated event
    And the StripeCustomerId exists
    And Stripe returns statusCode 5xx twice then a 200
    When the event is consumed from the Customers Stream
    Then the Stripe Api has been called thrice
    And the record is persisted with a stripe id in our db
    And stripeCustomer.created event gets fired onto payments stream
```

```gherkin=
Feature: Scheduler updates missing stripe customer ids (Scheduler)

  Scenario: Create a stripe customer (success)
    Given there are some customer records with no StripeCustomerId
    And the stripeCustomerCreated index is equal to awaiting-creation
    And the BillingEngineId exists
    When the scheduler is ran
    Then the records are populated with their StripeCustomerId
    And stripeCustomer.created event gets fired onto payments stream
    
  Scenario: Create a stripe customer (partial failure)
    Given there are some customer records with no StripeCustomerId
    And the stripeCustomerCreated index is equal to awaiting-creation
    And the BillingEngineId exists
    And some records fail to create due to invalid data
    When the scheduler is ran
    Then the unsuccessful records fail
    And the remainder of the records are populated with their StripeCustomerId
    And stripeCustomer.created event gets fired onto payments stream
```

```gherkin=
Feature: Create Payment Intent (API)

  Scenario: Create a payment intent (success)
    Given a valid payment payload is supplied
    And the request contains products
    When the endpoint is invoked
    Then the payment intent is created
    And a client secret and the payment id is returned
    
  Scenario: Create a payment intent (success with products)
    Given a valid payment payload is supplied
    And the request does not contains products
    When the endpoint is invoked
    Then the payment intent is created
    And a client secret and the payment id is returned

  Scenario: Create a payment intent (failure invalid signature)
    Given a payment payload is supplied
    And the request contains products with an invalid signature
    When the endpoint is invoked
    Then a 400 responce is returned

  Scenario: Create a payment intent (failure totals not matching up)
    Given a valid payment payload is supplied
    And the request contains products
    And the total products does not match the total amount
    When the endpoint is invoked
    Then a 400 responce is returned

  Scenario: Create a payment intent (failure invalid payload)
    Given an invalid payment payload is supplied
    When the endpoint is invoked
    Then a 400 response is returned
    
  Scenario: Create a payment intent (failure invalid stripeCustomerId)
    Given a payment payload is supplied
    And no stripeCustomerId exists for the customer
    When the endpoint is invoked
    Then a 400 error response is returned indicating the customer does not exist    
```

```gherkin=
Feature: Publish webhook to stream (Stripe Webhook)

  Scenario: Publish webhook to payment stream (success)
    Given any Event is recieved from stripe
    When the event is consumed
    Then the event is published to the payments stream

  Scenario: Publish webhook to payment stream (failure)
    Given any Event is recieved from stripe
    And the webhookSigningSecret is invalid
    When the event is consumed
    Then then a 401 invalid signature is returned 
```

```gherkin=
Feature: Save payment response (Payments Stream)

  Scenario: Save payment response (success)
    Given a payment intent succeeded event
    When the event is consumed
    Then the payment response is saved to our db
    And a payment.created event is fired onto the payments stream
    
  Scenario: Save payment response (failure)
    Given a payment intent paymentFailed event
    When the event is consumed
    Then the payment response is saved to our db 
    And a payment.created event is fired onto the payments stream   
```

```gherkin=
Feature: Get payment methods (API)

  Scenario: Get stripe payment methods (default limit of 10)
    Given a customer has more than 10 saved stripe payment methods
    And the limit query param is not specified
    When the endpoint is invoked
    Then 10 of their payments methods are returned by default
    
  Scenario: Get stripe payment methods (limit to 1)
    Given a customer has several stripe payment methods
    And the limit query param is set to 1
    When the endpoint is invoked
    Then only one of their payment methods is returned  
```
# Get Payments
```gherkin=
Feature: Get payments (API)

  Scenario: Get payments (default limit of 20)
    Given a customer has more than 20 saved payments
    And the limit query param is not specified
    When the endpoint is invoked
    Then the 20 most recent of their payments are returned
    
  Scenario: Get payments (limit to 1)
    Given a customer has more than 1 saved payment
    And the limit query param is set to 1
    When the endpoint is invoked
    Then only one of their payments is returned
    
  Scenario: Get payments (pagination)
    Given a customer has 4 saved payments
    And the limit query param is set to 2
    And the page query param is set to 2
    When the endpoint is invoked
    Then only the last 2 payment records should be displayed
    
  Scenario: Get payments (status filter)
    Given a customer has 3 saved payments
    And one has failed
    And the status query param is set to failed
    Then only the failed endpoint should be returned   

  Scenario: Get payments (no saved payments for the customer)
    Given a customer does not have any saved payments
    When the endpoint is invoked
    Then an empty result set is returned
```

# Junifer
```gherkin=
Feature: Save Junifer payment.accepted response (Billing Engine Stream)

  Scenario: Creates new payment for successful Junifer originating payments.
    Given the requestStatus on the event is 'Successful'
    And there is no apiIdempotency field on the payment object
    And no payment already exists for the BillingEngineId on the event
    When the event is handled
    Then a new payment record is created
    And the summary.status is 'success'
    And the source of the payment should be 'junifer'
    
  Scenario: Creates new payment for pending Junifer originating payments.
    Given the requestStatus on the event is 'Pending'
    And there is no apiIdempotency field on the payment object
    And no payment already exists for the BillingEngineId on the event
    When the event is handled
    Then a new payment record is created
    And the summary.status is 'pending'
    And the source of the payment should be 'junifer'

  Scenario: Creates new payment for cancelled Junifer originating payments.
    Given the requestStatus on the event is 'Cancelled'
    And there is no apiIdempotency field on the payment object
    And no payment already exists for the BillingEngineId on the event
    When the event is handled
    Then a new payment record is created
    And the summary.status is 'cancelled'
    And the source of the payment should be 'junifer'

  Scenario: Creates new payment for failing Junifer originating payments.
    Given the requestStatus on the event is 'FailedPendingRetry'
    And there is no apiIdempotency field on the payment object
    And no payment already exists for the BillingEngineId on the event
    When the event is handled
    Then a new payment record is created
    And the summary.status is 'failed'
    And the source of the payment should be 'junifer'
    
  Scenario: Creates new payment for failing Junifer originating payments.
    Given the requestStatus on the event is 'FailedRequestingAgain'
    And there is no apiIdempotency field on the payment object
    And no payment already exists for the BillingEngineId on the event
    When the event is handled
    Then a new payment record is created
    And the summary.status is 'failed'
    And the source of the payment should be 'junifer'
    
  Scenario: Missing account/customer id on the junifer originating payment
    Given a successful payment.accepted event
    And there is no customerId and accountId on the event
    When the event is handled
    Then a new payment record is NOT created (MissingAccountIdentifyingDataError error) 
    
  Scenario: Multiple records against a given BillingEngineId
    Given a successful payment.accepted event
    And there are two payment records with the given BillingEngineId
    When the event is handled
    Then a new payment record is NOT created (MultiplePaymentsForBillingEngineIdError error) 

  Scenario: Junifer payment.accepted event for an existing payment record
    Given a successful payment.accepted event
    And there is an apiIdempotency field on the payment object linking to a payment id 
    And that paymentId exists
    When the event is handled
    Then we update the record with the billingEngineId and billingEngineStatus
    And the source is not set to junifer  
    
  Scenario: Junifer event containing payment id that does not exist
    Given a successful payment.accepted event
    And there is an apiIdempotency field on the payment object linking to a payment id 
    And that paymentId that does not exist.
    When the event is handled
    Then  a new payment record is NOT created (PaymentNotFoundByPaymentIdError error) 
```


###### tags: `payments` `journey` `component-tests`

# Checklist:
## Stripe ✔

## Get payments ✔

## Junifer ✔

## Top ups
:::info
**Perhaps makes sense to be done as part of when integrating stripe refunds???**
:::

## Sagepay
```gherkin=
Feature: Get Sagepay merchant session keys (API)

  Scenario: Get Sagepay merchant session keys (success)
    Given a valid request
    When the endpoint is invoked
    Then the merchant session key and the expiry time of the key is returned
    
  Scenario: Get Sagepay merchant session keys (failure)
    Given  a valid request
    And there is an outage with sagepay
    When the endpoint is invoked
    Then an error is returned
```

```gherkin=
Feature: Make Sagepay Payment (API)

  Scenario: Post Sagepay Payment (success)
    Given a valid payment payload
    And no products is present
    And 3d auth is not required
    When the endpoint is invoked
    Then the transaction is returned
    And the status is set to 'success'
    And a payment.created event is fired onto the payments stream
    
  Scenario: Post Sagepay Payment (success)
    Given a valid payment payload
    And no products is present
    And 3d auth is required
    When the endpoint is invoked
    Then the transaction is returned
    And the status is set to '3D_secure' 
    
  Scenario: Post Sagepay Payment (failure)
    Given a valid payment payload
    And no products is present
    And a card with insufficient balance is supplied
    When the endpoint is invoked
    Then a 422 response is returned
    
  Scenario: Post Sagepay Payment (failure)
    Given a valid payment payload
    And no products is present
    And a card that does not meet the fraud rules is supplied
    When the endpoint is invoked
    Then a 400 response is returned   
    
  Scenario: Post Sagepay Payment (failure)
    Given a payment payload with no account id or customer id
    When the endpoint is invoked
    Then a validation error is returned
```

```gherkin=
Feature: Sagepay 3D Secure Authentication (API)

  Scenario: Callback Sagepay 3D Secure (success)
    Given redirect urls are not provided
    And a valid payment id, customer id and account id are provided
    And the PaRes response from the bank is successful
    When the endpoint is invoked
    Then a 200 response is returned
    And it contains the successful result of the authentication
    And a payment.created event is fired onto the payments stream
    
  Scenario: Callback Sagepay 3D Secure (success)
    Given redirect urls are provided
    And a valid payment id, customer id and account id are provided
    And the PaRes response from the bank is successful
    When the endpoint is invoked
    Then a 301 response is returned
    And the url contains the successful authentication result
    And a payment.created event is fired onto the payments stream
    
  Scenario: Callback Sagepay 3D Secure (failure)
    Given redirect urls are not provided
    And a valid payment id, customer id and account id are provided
    And the PaRes response from the bank is unsuccessful
    When the endpoint is invoked
    Then a 422 response is returned
    And contains the result of the failed authentication
    
  Scenario: Callback Sagepay 3D Secure (failure)
    Given redirect urls are provided
    And a valid payment id, customer id and account id are provided
    And the PaRes response from the bank is unsuccessful
    When the endpoint is invoked
    Then a 301 response is returned
    And the url contains the failed authentication result

  Scenario: Callback Sagepay 3D Secure (failure)
    Given no redirect urls are provided
    And the payment id supplied does not exist
    When the endpoint is invoked
    Then a 404 response is returned
    
  Scenario: Callback Sagepay 3D Secure (failure)
    Given no redirect urls are provided
    And no account id or customer is provided
    When the endpoint is invoked
    Then a 400 response is returned    
```