Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Document Status

Status
colourBlueGreen
titleIN REVIEWREVIEWED

Document Owner(s)

Capovilla, Evandro

Reviewers

Table of Contents

✅ Proposed Solution

...

After the user makes a payment request and closes the app, we need to ensure the user knows what happened to their order. This involves two developments: one is a new component to handle pending payments, and the other is a page to which the user will be redirected when attempting to view their there are pending payments available.

Create a reusable component to search for pending payment

On the main screen of the Whitelabel app, we will add a component similar to the order tracking feature. However, this component will specifically monitor pending payments that are still within the payment deadline.

The primary goal of this component is to provide clarity to users who may close the Whitelabel

Info

Remember that waiting for payment is a feature for all payment methods, but for it to be displayed, two conditions must be met:

  • The order must not be paid yet. (PRICE_SUCESSFUL and PAYMENT_REQUIRED)

  • The request must contain the paymentRequestTimeLimit property in the payment property.

Create Reusable Waiting Payment Page for order pending

This page reuses the same component as the mb payment details ensuring that users are familiar with the layout and can easily find the information they need. The primary objective of this page is to offer users comprehensive details about their pending MBWay payments, in scenarios where they might have closed the whitelabel app during the payment process. It ensures that users do not mistakenly believe their payment has been canceled. Even if the user closes the app, we do not have the capability to cancel their payment request in the MBWay application.

This component will include a button labeled SHOW which will redirect the user to a new MBWay page, that will be detailed in the next topic.

...

Info

Remember that waiting for payment is a feature for all payment methods, but for it to be displayed, two conditions must be met:

  • The order must not be paid yet. (PRICE_SUCESSFUL and PAYMENT_REQUIRED)

  • The request must contain the paymentRequestCreatedAt property in the payment property.

Create Reusable Waiting Payment Page for order pending

This page reuses the same component as the mb payment details ensuring that users are familiar with the layout and can easily find the information they need. The primary objective of this page is to offer users comprehensive details about their pending MBWay payments, in scenarios where they might have closed the whitelabel app during the payment process. It helps clarify the payment status and guides users on completing their transactions successfully.

Info

Importantly, only the most recent pending order will be displayed to the user, focusing their attention on the latest transaction.

...

Backend

Create Payment Request

To create a payment request for MBWay, it is necessary to add a new endpoint called InitiatePayment that handles the initialization of a new payment. Unlike the GenerateCheckoutLink, which is used for other payment methods, in the case of MBWay, we will not generate a link. Instead, we will request Paycomet to create a payment request in the customer's MBWay account.

Info

The InitiatePayment endpoint was created specifically for this purpose: to request or initiate a payment that will be processed outside the whitelabel.

...

helps clarify the payment status and guides users on completing their transactions successfully.

Info

Importantly, only the most recent pending order will be displayed to the user, focusing their attention on the latest transaction.

...

Backend

Create Payment Request

To create a payment request for MBWay, it is necessary to add a new endpoint called InitiatePayment that handles the initialization of a new payment. Unlike the GenerateCheckoutLink, which is used for other payment methods, in the case of MBWay, we will not generate a link. Instead, we will request Paycomet to create a payment request in the customer's MBWay account.

Info

The InitiatePayment endpoint was created specifically for this purpose: to request or initiate a payment that will be processed outside the whitelabel.

...

Expand
titlehttps://sequencediagram.org/ - Create Payment Request
Code Block
title Create Payment Request

participant Frontend
participant Graphql/Fulfillment
participant DB
participant Payment Service
participant PSP Service
participant Paycomet External

Frontend->Graphql/Fulfillment: Initiate Payment
Graphql/Fulfillment->Payment Service: Initiate Payment
Payment Service->PSP Service:Initiate Payment
PSP Service->Paycomet External:Payments Endpoint
PSP Service<-Paycomet External:Result
Payment Service<-PSP Service:Result
Payment Service->DB: Update Order \n(PaymentRequestTimeLimit)
Payment Service<-DB: Order Updated
DB<-Payment Service: Create Payment in Payment Table
DB->Payment Service: Payment Created
Graphql/Fulfillment<-Payment Service:Result
Frontend<-Graphql/Fulfillment:Result

group Commit Order
Frontend->Graphql/Fulfillment:     Commit Order\n(SaveCommitOnly)
Frontend<-Graphql/Fulfillment: Commit Order Result
end

loop
Frontend->DB:Order Polling
Frontend<-DB:Order Result
end

For this communication, it is necessary to transmit two important pieces of information to the Paycomet service: the amount and the cellphone. The cellphone will be used by Paycomet to create a request in the user's MBWay account. Once the data reaches the Paycomet service, we will create a payload as mentioned below for the /payments endpoint of Paycomet.

With this, Paycomet will return whether the request was created or not, allowing us to handle this data at the beginning of the request in the frontend, ensuring direct communication of the responses. If the endpoint returns success, it means that the user received a payment request. Otherwise, the user did not receive any request, and we should inform the user to try again, either because they entered an unregistered number or due to an issue on Paycomet's side.

Expand
titlePayload

Endpoint POST: https://rest.paycomet.com/v1/payments

Code Block
"payment": {
    "terminal": XXXXX,
    "order": "000012345", // from request
    "amount": "202", // from request
    "currency": "EUR",
    "methodId": "38",
    "secure": 1,
    "urlOk": "https://www.paycomet.com", // psp-outcome-endpoint
    "urlKo": "https://www.paycomet.com", // psp-outcome-endpoint
    "merchantData": {
        "customer": {
            "name": "John", // from request
            "surname": "Doe", // from request
            "email": "john@doe.com", // from request
            "mobilePhone": {
                "cc": "351", // from request
                "subscriber": "931301715" // from request
            }
        },
        "billing": {
            "billAddrCountry": 620 // Portugual ISO 
        }
    }
}

Retrieve Payment Status

The retrieval of payment status data is performed through an order polling process that waits for the order to reach the status: PAYMENT_SUCCESSFUL. To facilitate this process, we utilize a webhook in the Paycomet service, which is triggered whenever the payment status is updated in the Paycomet payment service provider.

When the Paycomet service receives this information about the status change, it will trigger the payment services to notify that there has been a change. This will, in turn, trigger all other services so that the order is updated in the database and this information is reflected on the frontend.

...

title

Create Payment Request participant Frontend participant

Payment Status

participant Frontend
participant Graphql/Fulfillment


participant

DB


participant

Payment

Service


participant

PSP

Service


participant

Paycomet

External

Frontend->Graphql/Fulfillment: Initiate Payment Graphql/Fulfillment->Payment Service: Initiate Payment Payment Service->PSP Service:Initiate Payment PSP Service->Paycomet External:Payments Endpoint PSP Service<-Paycomet External:Result Payment Service<-PSP Service:Result Graphql/Fulfillment<-Payment Service:Result Frontend<-Graphql/Fulfillment:Result Frontend->Frontend:Order Polling

Frontend->Frontend:Order Polling
PSP Service<-Paycomet External:Payment Status
Payment Service<-PSP Service:Payment Status
DB<-Payment Service: Update Order
Frontend<-DB:Order

Result

Expand
titlehttps://sequencediagram.org/ - Create Retrieve Payment RequestStatus
Code Block

For this communication, it is necessary to transmit two important pieces of information to the Paycomet service: the amount and the cellphone. The cellphone will be used by Paycomet to create a request in the user's MBWay account. Once the data reaches the Paycomet service, we will create a payload as mentioned below for the /payments endpoint of Paycomet.

With this, Paycomet will return whether the request was created or not, allowing us to handle this data at the beginning of the request in the frontend, ensuring direct communication of the responses. If the endpoint returns success, it means that the user received a payment request. Otherwise, the user did not receive any request, and we should inform the user to try again, either because they entered an unregistered number or due to an issue on Paycomet's side.

Expand
titlePayload

Endpoint POST: https://rest.paycomet.com/v1/payments

Code Block
"payment": {
    "terminal": XXXXX,
    "order": "000012345", // from request
    "amount": "202", // from request
    "currency": "EUR",
    "methodId": "38",
    "secure": 1,
    "urlOk": "https://www.paycomet.com", // psp-outcome-endpoint
    "urlKo": "https://www.paycomet.com", // psp-outcome-endpoint
    "merchantData": {
        "customer": {
            "name": "John", // from request
            "surname": "Doe", // from request
            "email": "john@doe.com", // from request
            "mobilePhone": {
                "cc": "351", // from request
                "subscriber": "931301715" // from request
            }
        },
        "billing": {
            "billAddrCountry": 620 // Portugual ISO 
        }
    }
}

Retrieve Payment Status

The retrieval of payment status data is performed through an order polling process that waits for the order to reach the status: PAYMENT_SUCCESSFUL. To facilitate this process, we utilize a webhook in the Paycomet service, which is triggered whenever the payment status is updated in the Paycomet payment service provider.

When the Paycomet service receives this information about the status change, it will trigger the payment services to notify that there has been a change. This will, in turn, trigger all other services so that the order is updated in the database and this information is reflected on the frontend.

...

Expand
titlehttps://sequencediagram.org/ - Retrieve Payment Status

title Payment Status

participant Frontend
participant Graphql/Fulfillment
participant DB
participant Payment Service
participant PSP Service
participant Paycomet External

Frontend->Frontend:Order Polling
PSP Service<-Paycomet External:Payment Status
Payment Service<-PSP Service:Payment Status
DB<-Payment Service: Update Order
Frontend<-DB:Order Result

Development

This first stage involves adding the main foundation for the new payment method. Since this task is repeated for all new payment methods, I will only provide the reference for each stage. This should be the first part of the frontend development; without it, it will not be possible to continue with the development of the subsequent screens.

New payment method support

Add new payment method icon

ref: https://github.com/rbilabs/ctg-components-library/pull/399

Expand
titlesrc/svgs/mbway/index.tsx
Code Block
import { SVGIconComponent } from '../types';

export const endered: SVGIconComponent = ({ title = '', ...props }) => (
//svg code
);
Expand
titlesrc/svgs/index.ts
Code Block
export * from './mbway';
Expand
titlesrc/themes/common/icon.ts
Code Block
mbway: 'mbway',
Expand
titlesrc/themes/types/icon.ts
Code Block
mbway: string;

Create a new feature flag

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-1%3A-Create-a-new-feature-flag

ref:

Jira Legacy
serverSystem Jira
serverId255417eb-03fa-3e2f-a6ba-05d325fec50d
keyIBFEC-1758

time: 1h

Add the new payment method in the payment state and structure

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-2%3A-Add-the-new-payment-method-in-the-payment-state-and-structure

ref:

Jira Legacy
serverSystem Jira
serverId255417eb-03fa-3e2f-a6ba-05d325fec50d
keyIBFEC-1761

time: 8h

Add the new method in payment-method structure and payment list

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-3%3A-Add-the-new-method-in-payment-method-structure

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-4%3A-Create-and-add-a-new-method-in-payment-method-option-structure

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-5%3A-Adjust--account-payment-method-lists-to-deal-with-the-new-method

ref:

Jira Legacy
serverSystem Jira
serverId255417eb-03fa-3e2f-a6ba-05d325fec50d
keyIBFEC-1760

time: 2d

Adjust the receipt email to show the correct message for the new payment method

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4449861673/Technical+refinement+-+Frontend#Task-6%3A-Adjust-the-receipt-email-to-show-the-correct-message-for-the-new-payment-method

ref:

Jira Legacy
serverSystem Jira
serverId255417eb-03fa-3e2f-a6ba-05d325fec50d
keyIBFEC-1765

time: 2h

Setup MBWay Payment

This is the second stage of the development tasks in the frontend. This phase involves the development of MBWay, where the screens and payment handling will be developed.

Create a mb way payment method

This is the first payment screen via MBWay. After selecting this payment method from the dropdown, the screen with the phone number input field should appear. This involves both the development of the screen and the validation and masking of the input.

...

Expand
titleMBWay Form
Code Block
export interface IPaycometMBWayFormProps {
  onResult: (outcome: OutcomeResult) => void;
  rbiOrderId: string;
}

export const PaycometMBWayForm = ({ rbiOrderId, onResult }:IPaycometMBWayFormProps) => {
  .....
  .....
  .....
  
  const handlePayment = () => {
    setIsLoading(true)
    handleInitiate();
  }
  
  return(
    {isWaitingPayment ? 
      <TimerForm/> :
      <CellphoneForm onClick={handlePayment}/>
    }
  )
}
Info

It is important to note that the development of this form will be reused in the new MBWay Pending Payments page.

Handle Fulfillment Initiate

This task focuses more on handling the information after the user enters the phone number and clicks "Continue." This stage involves communication with the "Initiate Payment" endpoint and returning the result. Additionally, this screen includes the invocation of the error modal.

handleInitiateMBWayPayment(

Expand
titleMBWay Component
Code Block

Development

This section includes some code examples that will be developed. The examples serve as a guide for development, and good practices as well as testing should be adopted.

New payment method support

This first stage involves adding the main foundation for the new payment method. Since this task is repeated for all new payment methods, I will only provide the reference for each stage. This should be the first part of the frontend development; without it, it will not be possible to continue with the development of the subsequent screens.

Add new payment method icon

This task involves adding the icon to be used later by the whitelabel

Expand
titlesrc/svgs/mbway/index.tsx
Code Block
import { SVGIconComponent } from '../types';

export const endered: SVGIconComponent = ({ title = '', ...props }) => (
//svg code
);
Expand
titlesrc/svgs/index.ts
Code Block
export * from './mbway';
Expand
titlesrc/themes/common/icon.ts
Code Block
mbway: 'mbway',
Expand
titlesrc/themes/types/icon.ts
Code Block
mbway: string;

ref: https://github.com/rbilabs/ctg-components-library/pull/399

Create a new feature flag

This task aims to create the feature flag in both launchdarkly and whitelabel

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-1%3A-Create-a-new-feature-flag

ref:

Jira Legacy
serverSystem Jira
serverId255417eb-03fa-3e2f-a6ba-05d325fec50d
keyIBFEC-1758

time: 1h

Add the new payment method in the payment state and structure

This task aims to create the mbway in payment state and structure

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-2%3A-Add-the-new-payment-method-in-the-payment-state-and-structure

ref:

Jira Legacy
serverSystem Jira
serverId255417eb-03fa-3e2f-a6ba-05d325fec50d
keyIBFEC-1761

time: 8h

Add the new method in payment-method structure and payment list

This task aims to add mbway to the payment dropdown

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-3%3A-Add-the-new-method-in-payment-method-structure

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-4%3A-Create-and-add-a-new-method-in-payment-method-option-structure

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4362960979/Technical+refinement+-+Front+end#Task-5%3A-Adjust--account-payment-method-lists-to-deal-with-the-new-method

ref:

Jira Legacy
serverSystem Jira
serverId255417eb-03fa-3e2f-a6ba-05d325fec50d
keyIBFEC-1760

time: 2d

Adjust the receipt email to show the correct message for the new payment method

This task aims to adjust the email to include mbway as a payment method

https://rbictg.atlassian.net/wiki/spaces/IBC/pages/4449861673/Technical+refinement+-+Frontend#Task-6%3A-Adjust-the-receipt-email-to-show-the-correct-message-for-the-new-payment-method

ref:

Jira Legacy
serverSystem Jira
serverId255417eb-03fa-3e2f-a6ba-05d325fec50d
keyIBFEC-1765

time: 2h

Setup MBWay Payment

This is the second stage of the development tasks in the frontend. This phase involves the development of MBWay, where the screens and payment handling will be developed.

Create a mb way payment method

This is the first payment screen via MBWay. After selecting this payment method from the dropdown, the screen with the phone number input field should appear. This involves both the development of the screen and the validation and masking of the input.

...

Expand
titleMBWay Form
Code Block
export interface IPaycometMBWayFormProps {
  onResult: (outcome: OutcomeResult) => void;
  rbiOrderId: string;
}

export const PaycometMBWayForm = ({ rbiOrderId, onResult }:IPaycometMBWayFormProps) => {
  .....
  .....
  .....
  
  const handlePayment = () => {
    setIsLoading(true)
    handleInitiate();
  }
  
  return(
    {isWaitingPayment ? 
      <TimerForm/> :
      <CellphoneForm onClick={handlePayment}/>
    }
  )
}
Info

It is important to note that the development of this form will be reused in the new MBWay Pending Payments page.

Handle Fulfillment Initiate

This task focuses more on handling the information after the user enters the phone number and clicks "Continue." This stage involves communication with the "Initiate Payment" endpoint and returning the result. Additionally, this screen includes the invocation of the error modal.

Expand
titleMBWay Component
Code Block
handleInitiateMBWayPayment(() => {
  const result = initiatePayment({
    cellphone: input.cellphone,
    amount: order.amount,
    rbiOrderId: order.id,
  })
  
  if(response.graphqlErrors[0]){
    showModal(true);
    return
  }
  
  LocalStorage.setItem(
    StorageKeys.PENDING_PAYMENTS,
    JSON.stringify({orderId: order.id})
  );  
  
  isProcessingMbWayPayment(true);
  placeOrder(true); // it is necessary placeOrder to enable backend commit order
})

Handle Commit Order

This task covers the order commit, where we will add a new field called paymentRequestTimeLimit, which will be responsible for recording when the payment request was generated. This field will be used in the future on the "Waiting for Payment" screen. It is important to remember that saveCommitOnly must be enabled for the order commit in the backend to be activated.

Expand
titleCommit Order
Code Block
commitInput = {
  ...commitInput,
  payment: {
    paymentRequestTimeLimit: 1627383253213, //timestamp
    ...commitInput.paymemt
  }
}
Info

Even though we are just requesting a payment, we must place the order so that we can receive the transaction data in the psp-service notification endpoint. Without this, the order will never be completed.

Payment Pending Tracking

...

Tracking Page

This task involves handling the information for the "Waiting for Payment" screen when the payment request is made. Therefore, a generic screen should be developed that can be used by other future payment methods. Additionally, this screen should be displayed when the user closes the app and returns to the homepage, as long as there is still an active payment to be completed.

...

Expand
titlesrc/utils/routing/routes/routes.ts
Code Block
export const routes = {
  pendingPage: 'pendingPage'
}
Expand
titlesrc/components/layout/index.tsx
Code Block
const MBWayPaymentPage: LazyRoute = lazyWithFallback(() => import('pages/mbway'));

return(
  ...
      <Route
        noIndex
        path={`${routes.pendingPage}/:orderId`}
        element={<pendingPage />}
      />
  ...
)
Expand
titlesrc/pages/mbway/index.tsx
Code Block
const pendingPage = () => {
  const result{ orderId } = initiatePaymentuseParams({);
  const MBWayPendingPayment cellphone: input.cellphone,= LocalStorage.getItem(StorageKeys.PENDING_PAYMENT);
  
 amount: order.amount,
 let data;
   rbiOrderId: order.id,
  })
if(MBWayPendingPayment && MBWayPendingPayment.id === orderId){
    data = MBWayPendingPayment;
  } else {
    try{
    if(response.graphqlErrors[0]){  const orders = showModalGetUserOrders(true); 
   return   }// map the order list to LocalStorage.setItem(show only the latest  StorageKeys.PENDING_PAYMENTS,information needed
    JSON.stringify({orderId: order.id}) data = )orders[0];
    }
  }
  
isProcessingMbWayPayment(true);  return placeOrder(true);
 // it is necessary placeOrder to enable backend commit order
})

Handle Commit Order

This task covers the order commit, where we will add a new field called paymentRequestCreatedAt, which will be responsible for recording when the payment request was generated. This field will be used in the future on the "Waiting for Payment" screen. It is important to remember that saveCommitOnly must be enabled for the order commit in the backend to be activated.

Expand
titleCommit Order
Code Block
commitInput = {
  ...commitInput,
  payment: {
    paymentRequestCreatedAt: 1627383253213, //timestamp
    ...commitInput.paymemt
  }
}
Info

Even though we are just requesting a payment, we must place the order so that we can receive the transaction data in the psp-service notification endpoint. Without this, the order will never be completed.

Payment Pending Tracking

Tracking Page

This task involves handling the information for the "Waiting for Payment" screen when the payment request is made. Therefore, a generic screen should be developed that can be used by other future payment methods. Additionally, this screen should be displayed when the user closes the app and returns to the homepage, as long as there is still an active payment to be completed.

...

<MBWayComponent data={data} />
  )
}

Backend

Packages

This task aims to add mbway to the payment method enums

Expand
titleintl-apis-psp-service
Code Block
export declare enum PaymentMethodType {
    ...
    MBWay = 'MBWay'
}
Expand
titleintl-payments
Code Block
export declare enum RBIPaymentType {
    ...
    MBWay = 'MBWay'
}

Commit Order Graphql/Fulfillment

This task aims to add mbway to the payment method enums and modify the commit order to accept this new payment method, in addition to including the new field: paymentRequestTimeLimit

Expand
titlesrc/utilsfunctions/routinggraphql/routesgenerated/routesgraphql.ts
Code Block
export enum CartPaymentType {
const routes =...
{  MBWay pendingPage:= 'pendingPageMBWay',
}
Expand
titlesrc/componentsfunctions/graphql/layoutproviders/indexpayments.tsxts
Code Block
constexport MBWayPaymentPage: LazyRoute = lazyWithFallback(() => import('pages/mbway'));

return(interface IPaycometPaymentSaleEvent extends IBaseSale {
  ...
  paymentRequestTimeLimit?: number;
}
Expand
titlesrc/functions/graphql/providers/payments.ts
Code Block
paycometSale = <Route{
  ...
  paymentRequestTimeLimit: payment?.paymentRequestTimeLimit,
 noIndex};
Expand
titlesrc/functions/graphql/utils/make-payment.ts
Code Block
private mapPaymentMethod(
    params: IPaycometPaymentSaleEvent,
  path={`${routes.pendingPage}/:orderId`}
 ): {
    paymentMethodType: string;
   element={<pendingPage />}
 paymentMethod: string;
  } {
 />   ...
)
Expand
titlesrc/pages/mbway/index.tsx
Code Block
const pendingPage = () =>

    return {
  const { orderId } = useParams();    paymentMethodType: params.paymentRequestTimeLimit &&
     const MBWayPendingPayment = LocalStorage.getItem(StorageKeys.PENDING_PAYMENT);      let data;   if(MBWayPendingPayment && MBWayPendingPayment.id === orderId){     dataparams.paymentMethodType = MBWayPendingPayment;
  } else {? 'MBWay' : 'scheme',
       trypaymentMethod: JSON.stringify({
      const orders = GetUserOrders();  type: 'scheme',
         // map the order list to show only the latest information needed
      data = orders[0];
    }
  }
  
  return (
    <MBWayComponent data={data} />
  )
}

Backend

Packages

Expand
titleintl-apis-psp-service
Code Block
export declare enum PaymentMethodType {
    ...
    MBWay = 'MBWay'
}
Expand
titleintl-payments
Code Block
export declare enum RBIPaymentType {
    ...
    MBWay = 'MBWay'
}

Commit Order Graphql/Fulfillment

Expand
titlesrc/functions/graphql/generated/graphql.ts
Code Block
export enum CartPaymentType {
  ...
  MBWay = 'MBWay',
}
Expand
titlesrc/functions/graphql/providers/payments.ts
Code Block
export interface IPaycometPaymentSaleEvent extends IBaseSale {
  ...
  paymentRequestCreatedAt?: number;
}subtype: 'onetime',
      }),
    };
  }
Expand
titleCommitOrder GraphQL
Code Block
//PaymentType = MBWay;
//PaymentMethodBrand = null;

CommitOrderInput
  Input.payment.mbway = {
    cellphone: string
    createdAt: number;
  }

Create a new request to Graphql/Fulfillment to handle MB Way on Initiate Endpoint

This task aims to add the paycometCaptureContext field to the initiatePayment endpoint

Expand
titleUpdate the Graphql Initiate Endpoint
Code Block
input PaycometCaptureContextInput {
  amount: number!
  rbiOrderId: String!
  cellphone: number
  method: string!
}

input InitiatePaymentInput {
  storeId: String!
  paymentMethodType: String!
  cybersourcePaSetup: CybersourcePaSetupInput
  cybersourceCaptureContext: CybersourceCaptureContextInput
  paycometCaptureContext: PaycometCaptureContextInput
}

Implementation example: https://github.com/rbilabs/intl-whitelabel-graphql/pull/1150

Create a new endpoint in Paycomet PSP Service

This task aims to create the initiatePayment endpoint on paycomet psp and also its functionality.

Expand
titlesrc/functionsoutcome/graphql/providers/paymentsdtos/outcome.dto.ts
Code Block
paycometSaleexport enum =TypePayment {
  ...
  MBWay paymentRequestCreatedAt: payment.paymentRequestCreatedAt,= 'MBWay'
};
Expand
titlesrc/functions/graphql/utils/make-payment.tsInitiate Payment DTO
Code Block
privateexport mapPaymentMethod(abstract class PspInitiateRequestDto {
 params: IPaycometPaymentSaleEvent, @AmountApiProperty()
  ): {
    paymentMethodType: string;
    paymentMethod: string;
  } {
    ...@IsOptional()
  @IsNumber()
  public amount: number;
  
  @RbiOrderIdApiProperty()
 return {@IsString()
  @IsNotEmpty()
  public paymentMethodType: params.paymentRequestCreatedAt &&rbiOrderId!: string;
  
  @IsOptional()
  @IsNumber()
  public cellphone: number;
  
  @IsString()
  @IsNotEmpty()
  public method!: string;
}
Expand
titleInitiate Payment Controller
Code Block
public initiatePayment(
params.paymentMethodType ? 'MBWay' : @Headers('schemeregion',)  region: string,
   paymentMethod: JSON.stringify@Body({) pspInitiateRequestDto: PspInitiateRequestDto,
      type): 'scheme',Promise<ApiResult<unknown>> {
    if(pspInitiateRequestDto.method === TypePayment.MBWAY){
subtype: 'onetime',     return initiatePaymentMBWay(region, }pspInitiateRequestDto),;
    };
  }
Expand
titleCommitOrder GraphQL
Code Block
//PaymentType = MBWay;
//PaymentMethodBrand = null;

CommitOrderInputreturn throw ApiErrorHttpException.createConflict(
     Input.payment.mbway = { new ApiError(501, 'Initiate Payment cellphone: string
request failed', 'initiatePayment'),
   createdAt: number);
  }

Create a new request to Graphql/Fulfillment to handle MB Way on Initiate Endpoint

...

Expand
titleUpdate the Graphql Initiate Endpoint
Code Block
input PaycometCaptureContextInput {
  amount: number!
  rbiOrderId: String!
  cellphone: number
  method: string!
}

input InitiatePaymentInput {
  storeId: String!
  paymentMethodType: String!
  cybersourcePaSetup: CybersourcePaSetupInput
  cybersourceCaptureContext: CybersourceCaptureContextInput
  paycometCaptureContext: PaycometCaptureContextInput
}

Create a new endpoint in Paycomet PSP Service

Expand
titlesrc/outcome/dtos/outcome.dto.ts
Code Block
export enum TypePayment {
  ...
  MBWay = 'MBWay'
}
Expand
titleInitiate Payment DTO
Code Block
export abstract class PspInitiateRequestDto {
  @AmountApiProperty()
  @IsOptional()
  @IsNumber()
  public amount: number;
  
  @RbiOrderIdApiProperty()
  @IsString()
  @IsNotEmpty()
  public rbiOrderId!: string;
  
  @IsOptional()
  @IsNumber()
  public cellphone: number;
  
  @IsString()
  @IsNotEmpty()
  public method!: string;
}
Expand
titleInitiate Payment Controller
Code Block
public initiatePayment(
    @Headers('region') region: string,
    @Body() pspInitiateRequestDto: PspInitiateRequestDto,
  ): Promise<ApiResult<unknown>> {
    if(pspInitiateRequestDto.method === TypePayment.MBWAY){
      return initiatePaymentMBWay(region, pspInitiateRequestDto);
    }
    return throw ApiErrorHttpException.createConflict(
        new ApiError(501, 'Initiate Payment request failed', 'initiatePayment'),
    );
  }
public async initiatePaymentMBWay( region: string, request: InitiateRequestDto, ): Promise<InitiateResult> { try{ const result = this.createPaymentMBWayRequest(request); // Add log about payment initiation attempt if(result.errorCode === TransactionStatus.SUCCESSFUL){
Expand
titleInitiate Payment Service
Code Block
Payment Service
Code Block
public async initiatePaymentMBWay(
    region: string,
    request: InitiateRequestDto,
  ): Promise<InitiateResult> {
    try{
      const result = this.createPaymentMBWayRequest(request);
      // Add log about payment initiation attempt
      if(result.errorCode === TransactionStatus.SUCCESSFUL){
        return this.handleSuccesful(region, request, result);
      }
      return this.handleFailure(region, request, result);
    } catch(error){
      return this.handleFailure(region, request, error);
    }
}

Update the makePayment endpoint in Paycomet PSP Service

Expand
titlesrc/payment/payment.service.ts
Code Block
private isOneTimePayment(paymentMethod: PaymentMethod): paymentMethod is OneTimeSchemeDto {
return (
    (paymentMethod.type === PaymentMethodType.Scheme ||
    paymentMethod.type === PaymentMethodType.MBWay) &&
    paymentMethod.subtype === SchemePaymentMethodType.OneTime
  );
}
Expand
titlesrc/paycomet-core/paycomet-helper.ts
Code Block
public getPaymentLinkId(
  ...
): TypePayment | undefined {
  if (!methodId) {
    const paymentLink = transaction?.payment?.history.find(
      (order) =>
        ... ||
        order.methodId === TransactionMethodId.APPLEPAYLINK ||
       return this.handleSuccesful(region, request, result);
order.methodId === TransactionMethodId.MBWAY ||,
    );
}
    methodId  return this.handleFailure(region, request, result= Number(paymentLink?.methodId);
   }
} catch(error){
   
Expand
titlesrc/paycomet-core/commons.types.ts
Code Block
export enum TransactionMethodId {
  return this.handleFailure(region, request, error);
    }
}

Update the order to include the time left to finish the MB Way Payment

...

APPLEPAYLINK = 1,
  MBWAY = 38
}

Admin App

Adding mbway within the translation enum so that the Admin App knows this new payment method and selects the correct translation.

Expand
titlesrc/components/order-details/order-details-card.tsx

ref: https://github.com/rbilabs/intl-admin-app/blob/6068cb1f1023cb5a588bd3a87e7cc3587d226397/src/components/order-details/order-details-card.tsx#L60-L86

Code Block
const paymentMethodType = order?.cart?.payment?.type;

if (paymentMethodType === 'MBWay') {
      return formatMessage({ id: paymentMethodBrandTranslationMap(paymentMethodType) });
    }
    
if (paymentMethodBrand) {
      return formatMessage({ id: paymentMethodBrandTranslationMap(paymentMethodBrand) });
    }

DOP

Adding mbway within the translation enum so that the DOP knows this new payment method and selects the correct translation

Expand
titlesrc/utils/orders.ts

ref: https://github.com/rbilabs/ctg-fz-portal/blob/75b71352d4049a2797c8e752def79807d40a4e07/workspaces/frontend/src/utils/orders.ts#L8-L26

Code Block
export const paymentMethodTranslation: Record<string, keyof LocalizedDictionary> = {
  MBWAY: `${pathPaymentTranslations}.mbway`,
};

Expeditor Tablet

Adding the mbway inside the enum so that the expeditor tablet knows this new payment method.

Expand
titlesrc/constants/paymentMethod.ts

ref: https://github.com/rbilabs/intl-expeditor-tablet/blob/b02805ed57a3d13dd4bc83dbdeac190ad2d2a106/workspaces/frontend/src/constants/paymentMethod.ts#L3-L19

Code Block
export enum PaymentMethod {
  ...,
  MBWAY = "MBWAY",
}

...