diff --git a/src/common/constants/enums.ts b/src/common/constants/enums.ts index cbc3f9b..bc1600b 100644 --- a/src/common/constants/enums.ts +++ b/src/common/constants/enums.ts @@ -17,11 +17,35 @@ export enum UserType { PROVIDER = 'PROVIDER', } +export enum SenderType { + PAYER = 'PAYER', + PATIENT = 'PATIENT', + PROVIDER = 'PROVIDER', +} + +export enum ReceiverType { + PATIENT = 'PATIENT', + PROVIDER = 'PROVIDER', + WII_QARE = 'WII_QARE', +} + export enum VoucherStatus { - CLAIMED = 'CLAIMED', UNCLAIMED = 'UNCLAIMED', + CLAIMED = 'CLAIMED', + PENDING = 'PENDING', BURNED = 'BURNED', +} + +export enum TransactionStatus { PENDING = 'PENDING', + FAILED = 'FAILED', + SUCCESSFUL = 'SUCCESSFUL', + PAID_OUT = 'PAID_OUT', +} + +export enum ReferralStatus { + REDEEMED = 'REDEEMED', + NOT_REDEEMED = 'NOT_REDEEMED', } export enum InviteType { diff --git a/src/modules/patient-svc/patient-svc.service.test.ts b/src/modules/patient-svc/patient-svc.service.test.ts index cb48d4a..bc7fcec 100644 --- a/src/modules/patient-svc/patient-svc.service.test.ts +++ b/src/modules/patient-svc/patient-svc.service.test.ts @@ -5,6 +5,8 @@ import { User } from '../session/entities/user.entity'; import { Transaction } from '../smart-contract/entities/transaction.entity'; import { CreatePatientDto, PatientResponseDto } from './dto/patient.dto'; import { + ReceiverType, + TransactionStatus, UserRole, UserStatus, UserType, @@ -54,10 +56,8 @@ describe('PatientSvcService', () => { amount: 1, conversionRate: 1, currency: 'FC', - ownerType: UserType.PATIENT, - status: VoucherStatus.UNCLAIMED, - transactionHash: 'transactionHash1', - shortenHash: 'shortenHash1', + ownerType: ReceiverType.PATIENT, + status: TransactionStatus.PENDING, stripePaymentId: 'stripePaymentId1', voucher: { voucher: 'voucher1' }, }; diff --git a/src/modules/payer-svc/payer-svc.module.ts b/src/modules/payer-svc/payer-svc.module.ts index caa19e8..780f1ac 100644 --- a/src/modules/payer-svc/payer-svc.module.ts +++ b/src/modules/payer-svc/payer-svc.module.ts @@ -10,10 +10,11 @@ import { SMSModule } from '../sms/sms.module'; import { Payer } from './entities/payer.entity'; import { PayerSvcController } from './payer-svc.controller'; import { PayerService } from './payer.service'; +import { Voucher } from '../smart-contract/entities/voucher.entity'; @Module({ imports: [ - TypeOrmModule.forFeature([Payer, User, Patient, Transaction]), + TypeOrmModule.forFeature([Payer, User, Patient, Transaction, Voucher]), forwardRef(() => SessionModule), MailModule, PatientSvcModule, diff --git a/src/modules/payer-svc/payer-svc.service.test.ts b/src/modules/payer-svc/payer-svc.service.test.ts index 5a12f9e..3b03feb 100644 --- a/src/modules/payer-svc/payer-svc.service.test.ts +++ b/src/modules/payer-svc/payer-svc.service.test.ts @@ -6,8 +6,12 @@ import { Payer } from './entities/payer.entity'; import { User } from '../session/entities/user.entity'; import { Transaction } from '../smart-contract/entities/transaction.entity'; import { Patient } from '../patient-svc/entities/patient.entity'; +import { Voucher } from '../smart-contract/entities/voucher.entity'; import { InviteType, + ReceiverType, + SenderType, + TransactionStatus, UserRole, UserStatus, UserType, @@ -22,12 +26,14 @@ import { } from '@nestjs/common'; import { _400, _404, _403 } from '../../common/constants/errors'; + describe('PayerService', () => { let service: PayerService; let payerRepository: Repository; let transactionRepository: Repository; let patientRepository: Repository; let userRepository: Repository; + let voucherRepository: Repository; // Mock services const mockMailService = { @@ -88,14 +94,27 @@ describe('PayerService', () => { senderId: mockPayer.id, ownerId: mockPayer.id, hospitalId: null, - ownerType: UserType.PAYER, - status: VoucherStatus.UNCLAIMED, - transactionHash: 'transactionHash', - shortenHash: 'shortenHash', + ownerType: ReceiverType.PROVIDER, + status: TransactionStatus.PENDING, stripePaymentId: 'stripePaymentId', voucher: { voucher: 'voucher' }, }; + const mockVoucher: Voucher = { + id: '', + updatedAt: new Date(), + createdAt: new Date(), + voucherHash: '', + shortenHash: '', + value: 1, + senderId: mockPayer.id, + senderType: SenderType.PAYER, + receiverId: mockPatient.id, + receiverType: ReceiverType.PATIENT, + status: VoucherStatus.PENDING, + transaction: mockTransaction.id + } + beforeEach(async () => { jest.clearAllMocks(); @@ -123,11 +142,16 @@ describe('PayerService', () => { findOne: jest.fn().mockResolvedValue(mockTransaction), } as unknown as Repository; + voucherRepository = { + findOne: jest.fn().mockResolvedValue(mockVoucher), + } as unknown as Repository; + service = new PayerService( patientRepository, payerRepository, userRepository, transactionRepository, + voucherRepository, mockMailService as MailService, mockSmsService as SmsService, ); diff --git a/src/modules/payer-svc/payer.service.ts b/src/modules/payer-svc/payer.service.ts index 63cefdf..a636dff 100644 --- a/src/modules/payer-svc/payer.service.ts +++ b/src/modules/payer-svc/payer.service.ts @@ -19,6 +19,7 @@ import { Transaction } from '../smart-contract/entities/transaction.entity'; import { SmsService } from '../sms/sms.service'; import { CreatePayerAccountDto, SendInviteDto } from './dto/payer.dto'; import { Payer } from './entities/payer.entity'; +import { Voucher } from '../smart-contract/entities/voucher.entity'; @Injectable() export class PayerService { @@ -31,6 +32,8 @@ export class PayerService { private readonly userRepository: Repository, @InjectRepository(Transaction) private readonly transactionRepository: Repository, + @InjectRepository(Voucher) + private readonly voucherRepository: Repository, private readonly mailService: MailService, private readonly smsService: SmsService, ) {} @@ -158,31 +161,32 @@ export class PayerService { shortenHash: string, authUser: JwtClaimsDataDto, ): Promise { - const [payer, transaction] = await Promise.all([ + const [payer, voucher] = await Promise.all([ this.payerRepository .createQueryBuilder('payer') .leftJoinAndSelect('payer.user', 'user') .where('user.id = :userId', { userId: authUser.sub }) .getOne(), - this.transactionRepository.findOne({ where: { shortenHash } }), + this.voucherRepository.findOne({ where: { shortenHash } }), ]); + const transaction = await this.transactionRepository.findOne({ where: { id: voucher.transaction }}); if (!payer) throw new NotFoundException(_404.PAYER_NOT_FOUND); - if (!transaction) + if (!voucher) throw new NotFoundException(_404.INVALID_TRANSACTION_HASH); - if (transaction.senderId !== authUser.sub) + if (voucher.senderId !== authUser.sub) throw new ForbiddenException(_403.ONLY_OWNER_CAN_SEND_VOUCHER); const patient = await this.patientRepository.findOne({ - where: { id: transaction.ownerId }, + where: { id: voucher.receiverId }, }); if (!patient) throw new NotFoundException(_404.PATIENT_NOT_FOUND); await this.smsService.sendVoucherAsAnSMS( - transaction.shortenHash, + voucher.shortenHash, patient.phoneNumber, authUser.names, transaction.amount, diff --git a/src/modules/provider-svc/provider-svc.module.ts b/src/modules/provider-svc/provider-svc.module.ts index ebe8dca..9cd3f20 100644 --- a/src/modules/provider-svc/provider-svc.module.ts +++ b/src/modules/provider-svc/provider-svc.module.ts @@ -11,6 +11,7 @@ import { Provider } from './entities/provider.entity'; import { Service } from './entities/service.entity'; import { ProviderController } from './provider-svc.controller'; import { ProviderService } from './provider-svc.service'; +import { Voucher } from '../smart-contract/entities/voucher.entity'; @Module({ imports: [ @@ -21,6 +22,7 @@ import { ProviderService } from './provider-svc.service'; Patient, Package, Service, + Voucher ]), ObjectStorageModule, MailModule, diff --git a/src/modules/provider-svc/provider-svc.service.test.ts b/src/modules/provider-svc/provider-svc.service.test.ts index 049aa0b..9462d66 100644 --- a/src/modules/provider-svc/provider-svc.service.test.ts +++ b/src/modules/provider-svc/provider-svc.service.test.ts @@ -16,11 +16,15 @@ import { VoucherStatus, UserRole, UserStatus, + ReceiverType, + TransactionStatus, + SenderType, } from '../../common/constants/enums'; import { ForbiddenException, NotFoundException } from '@nestjs/common'; import { _403, _404 } from '../../common/constants/errors'; import { APP_NAME, DAY, HOUR } from '../../common/constants/constants'; import { RegisterProviderDto } from './dto/provider.dto'; +import { Voucher } from '../smart-contract/entities/voucher.entity'; describe('ProviderService', () => { let service: ProviderService; @@ -30,6 +34,7 @@ describe('ProviderService', () => { let userRepository: Repository; let packageRepository: Repository; let serviceRepository: Repository; + let voucherRepository: Repository; // Mock services const mockObjectStorageService = { @@ -110,10 +115,8 @@ describe('ProviderService', () => { senderId: 'senderId', ownerId: 'ownerId', hospitalId: 'hospitalId', - ownerType: UserType.PATIENT, - status: VoucherStatus.UNCLAIMED, - transactionHash: 'transactionHash', - shortenHash: 'shortenHash', + ownerType: ReceiverType.PATIENT, + status: TransactionStatus.PENDING, stripePaymentId: 'stripePaymentId', voucher: { voucher: 'voucher' }, }; @@ -144,6 +147,21 @@ describe('ProviderService', () => { country: 'country', }; + const mockVoucher: Voucher = { + id: '', + updatedAt: new Date(), + createdAt: new Date(), + voucherHash: '', + shortenHash: '', + value: 1, + senderId: mockProvider.id, + senderType: SenderType.PAYER, + receiverId: mockPatient.id, + receiverType: ReceiverType.PATIENT, + status: VoucherStatus.PENDING, + transaction: mockTransaction.id + } + // Mock relations mockProvider.user = mockUser; mockPackage.services = [mockService]; @@ -166,6 +184,15 @@ describe('ProviderService', () => { getMany: jest.fn().mockResolvedValue([mockTransaction]), }), } as unknown as Repository; + voucherRepository = { + findOne: jest.fn().mockResolvedValue(mockVoucher), + save: jest.fn().mockResolvedValue(mockVoucher), + createQueryBuilder: jest.fn().mockReturnValue({ + where: jest.fn().mockReturnThis(), + andWhere: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue([mockVoucher]), + }), + } as unknown as Repository; patientRepository = { findOne: jest.fn().mockResolvedValue(mockPatient), save: jest.fn().mockResolvedValue(mockPatient), @@ -187,6 +214,7 @@ describe('ProviderService', () => { userRepository, packageRepository, serviceRepository, + voucherRepository, mockObjectStorageService as ObjectStorageService, mockCachingService as CachingService, mockMailService as MailService, @@ -354,8 +382,6 @@ describe('ProviderService', () => { mockTransaction, ); expect(result).toEqual({ - hash: mockTransaction.transactionHash, - shortenHash: mockTransaction.shortenHash, amount: mockTransaction.amount, currency: mockTransaction.currency, patientNames: `${mockPatient.firstName} ${mockPatient.lastName}`, diff --git a/src/modules/provider-svc/provider-svc.service.ts b/src/modules/provider-svc/provider-svc.service.ts index a2d8fef..51de7a6 100644 --- a/src/modules/provider-svc/provider-svc.service.ts +++ b/src/modules/provider-svc/provider-svc.service.ts @@ -8,6 +8,8 @@ import * as bcrypt from 'bcrypt'; import * as _ from 'lodash'; import { APP_NAME, DAY, HOUR } from '../../common/constants/constants'; import { + ReceiverType, + TransactionStatus, UserRole, UserStatus, UserType, @@ -34,6 +36,7 @@ import { import { Package } from './entities/package.entity'; import { Provider } from './entities/provider.entity'; import { Service } from './entities/service.entity'; +import { Voucher } from '../smart-contract/entities/voucher.entity'; @Injectable() export class ProviderService { @@ -50,6 +53,8 @@ export class ProviderService { private packageRepository: Repository, @InjectRepository(Service) private servicesRepository: Repository, + @InjectRepository(Voucher) + private readonly voucherRepository: Repository, private objectStorageService: ObjectStorageService, private cachingService: CachingService, private mailService: MailService, @@ -203,8 +208,11 @@ export class ProviderService { async getTransactionByShortenHash( shortenHash: string, ): Promise> { + const voucher = await this.voucherRepository.findOne({ + where: { shortenHash } + }); const transaction = await this.transactionRepository.findOne({ - where: { shortenHash, ownerType: UserType.PATIENT }, + where: { id: voucher.transaction, ownerType: ReceiverType.PATIENT }, }); if (!transaction) @@ -219,8 +227,8 @@ export class ProviderService { await this.sendTxVerificationOTP(shortenHash, patient, transaction); return { - hash: transaction.transactionHash, - shortenHash: transaction.shortenHash, + hash: voucher.voucherHash, + shortenHash: voucher.shortenHash, amount: transaction.amount, currency: transaction.currency, patientNames: `${patient.firstName} ${patient.lastName}`, @@ -242,9 +250,12 @@ export class ProviderService { securityCode: string, ): Promise> { // verify the transaction exists and if securityCode is right! + const voucher = this.voucherRepository.findOne({ + where: { shortenHash } + }) const [transaction, provider] = await Promise.all([ this.transactionRepository.findOne({ - where: { shortenHash, ownerType: UserType.PATIENT }, + where: { id: (await voucher).transaction, ownerType: ReceiverType.PATIENT }, }), this.providerRepository.findOne({ where: { id: providerId } }), ]); @@ -268,7 +279,7 @@ export class ProviderService { // Update the transaction in the database const updatedTransaction = await this.transactionRepository.save({ ...transaction, - ownerType: UserType.PROVIDER, + ownerType: ReceiverType.PROVIDER, hospitalId: providerId, }); @@ -287,7 +298,14 @@ export class ProviderService { async getAllTransactions(providerId: string): Promise[]> { const transactions = await this.transactionRepository .createQueryBuilder('transaction') + .leftJoinAndMapOne( + 'transaction.voucherEntity', + Voucher, + 'voucherEntity', + 'voucherEntity.transaction = transaction.id' + ) .where('transaction.ownerId = :providerId', { providerId }) + .orWhere('transaction.hospitalId = :providerId', { providerId }) .orderBy('transaction.updatedAt', 'DESC') .getMany(); //TODO: paginate this!. @@ -312,11 +330,11 @@ export class ProviderService { totalUnclaimedAmount = 0; transactions.forEach((transaction) => { - if (transaction.status === VoucherStatus.PENDING) + if (transaction.status === TransactionStatus.PENDING) totalPendingAmount += transaction.amount; - if (transaction.status === VoucherStatus.CLAIMED) + if (transaction.status === TransactionStatus.PAID_OUT) totalRedeemedAmount += transaction.amount; - if (transaction.status === VoucherStatus.UNCLAIMED) + if (transaction.status === TransactionStatus.SUCCESSFUL) totalUnclaimedAmount += transaction.amount; }); @@ -346,7 +364,7 @@ export class ProviderService { const updatedTransactionList = transactions.map((transaction) => ({ ...transaction, - status: VoucherStatus.PENDING, + status: TransactionStatus.PENDING, })); //TODO: update the voucher details on chain. diff --git a/src/modules/smart-contract/entities/transaction.entity.ts b/src/modules/smart-contract/entities/transaction.entity.ts index 6de5552..664d2aa 100644 --- a/src/modules/smart-contract/entities/transaction.entity.ts +++ b/src/modules/smart-contract/entities/transaction.entity.ts @@ -1,12 +1,16 @@ import { BaseEntity } from '../../../db/base-entity'; import { Column, Entity } from 'typeorm'; -import { UserType, VoucherStatus } from '../../../common/constants/enums'; +// import { UserType, VoucherStatus } from '../../../common/constants/enums'; +import { + ReceiverType, + TransactionStatus, +} from '../../../common/constants/enums'; @Entity() export class Transaction extends BaseEntity { @Column({ type: 'double precision', - comment: 'sent amount before conversion', + comment: 'Sent amount before conversion', }) senderAmount: number; @@ -28,7 +32,7 @@ export class Transaction extends BaseEntity { @Column({ comment: 'local currency' }) currency: string; - @Column({ type: 'uuid', nullable: true }) + @Column({ type: 'uuid' }) senderId: string; @Column({ @@ -49,25 +53,18 @@ export class Transaction extends BaseEntity { @Column({ type: 'enum', - enum: UserType, + enum: ReceiverType, nullable: true, - default: UserType.PATIENT, + default: ReceiverType.PATIENT, }) - ownerType: UserType; + ownerType: ReceiverType; @Column({ type: 'enum', - enum: VoucherStatus, - default: VoucherStatus.UNCLAIMED, + enum: TransactionStatus, + default: TransactionStatus.PENDING, }) - status: VoucherStatus; - - @Column() - transactionHash: string; - - //TODO: @remove nullable later! - @Column({ nullable: true }) - shortenHash: string; + status: TransactionStatus; @Column() stripePaymentId: string; diff --git a/src/modules/smart-contract/entities/voucher.entity.ts b/src/modules/smart-contract/entities/voucher.entity.ts new file mode 100644 index 0000000..185efb8 --- /dev/null +++ b/src/modules/smart-contract/entities/voucher.entity.ts @@ -0,0 +1,43 @@ +import { BaseEntity } from 'src/db/base-entity'; +import { Column, Entity, JoinColumn, OneToOne } from 'typeorm'; +import { + ReceiverType, + SenderType, + VoucherStatus, +} from '../../../common/constants/enums'; +import { Transaction } from './transaction.entity'; + +@Entity() +export class Voucher extends BaseEntity { + @Column() + voucherHash: string; + + @Column() + shortenHash: string; + + @Column({ type: 'double precision' }) + value: number; + + @Column({ type: 'uuid' }) + senderId: string; + + @Column({ type: 'enum', enum: SenderType }) + senderType: SenderType; + + @Column() + receiverId: string; + + @Column({ type: 'enum', enum: ReceiverType }) + receiverType: ReceiverType; + + @Column({ + type: 'enum', + enum: VoucherStatus, + default: VoucherStatus.UNCLAIMED, + }) + status: VoucherStatus; + + @OneToOne(() => Transaction, (transaction) => transaction.id) + @JoinColumn() + transaction: string; +} \ No newline at end of file diff --git a/src/modules/smart-contract/payment.controller.ts b/src/modules/smart-contract/payment.controller.ts index 3518295..42708f9 100644 --- a/src/modules/smart-contract/payment.controller.ts +++ b/src/modules/smart-contract/payment.controller.ts @@ -14,7 +14,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Request } from 'express'; import _ from 'lodash'; import { InjectStripe } from 'nestjs-stripe'; -import { UserRole, VoucherStatus } from 'src/common/constants/enums'; +import { ReceiverType, SenderType, TransactionStatus, UserRole, VoucherStatus } from 'src/common/constants/enums'; import { AuthUser } from 'src/common/decorators/auth-user.decorator'; import { Public } from 'src/common/decorators/public.decorator'; import { Roles } from 'src/common/decorators/user-role.decorator'; @@ -29,6 +29,7 @@ import { Transaction } from './entities/transaction.entity'; import { SmartContractService } from './smart-contract.service'; import { TransactionService } from './transaction.service'; import { _400 } from 'src/common/constants/errors'; +import { Voucher } from './entities/voucher.entity'; @ApiTags('payment') @Controller('payment') @@ -39,6 +40,8 @@ export class PaymentController { private readonly smartContractService: SmartContractService, @InjectRepository(Transaction) private readonly transactionRepository: Repository, + @InjectRepository(Voucher) + private readonly voucherRepository: Repository, private readonly transactionService: TransactionService, ) { } @@ -114,7 +117,7 @@ export class PaymentController { patientId: patientId, }); - const voucherToSave = { + const voucherJSON = { id: _.get(voucherData, 'events.mintVoucherEvent.returnValues.0'), amount: _.get( voucherData, @@ -158,12 +161,25 @@ export class PaymentController { senderId, ownerId: patientId, stripePaymentId, - transactionHash, - shortenHash, - voucher: voucherToSave, + voucher: voucherJSON, + status: TransactionStatus.PENDING, + }); + const savedTransaction = await this.transactionRepository.save(transactionToSave); + + + // update this + const voucherToSave = this.voucherRepository.create({ + voucherHash: transactionHash, + shortenHash: shortenHash, + value: currencyPatientAmount, + senderId: senderId, + senderType: SenderType.PAYER, + receiverId: patientId, + receiverType: ReceiverType.PATIENT, status: VoucherStatus.UNCLAIMED, + transaction: savedTransaction.id }); - await this.transactionRepository.save(transactionToSave); + await this.voucherRepository.save(voucherToSave); break; case 'payment_intent.payment_failed': @@ -198,6 +214,12 @@ export class PaymentController { 'patient', 'patient.id = transaction.ownerId', ) + .leftJoinAndMapOne( + 'transaction.voucherEntity', + Voucher, + 'voucherEntity', + 'voucherEntity.transaction = transaction.id' + ) .select([ 'transaction', 'payer.firstName', @@ -206,10 +228,11 @@ export class PaymentController { 'patient.firstName', 'patient.lastName', 'patient.phoneNumber', + 'voucherEntity' ]) .where('transaction.stripePaymentId = :paymentId', { paymentId }) .getOne(); - + console.log( transaction ); if (!transaction) throw new NotFoundException('Resource not found') diff --git a/src/modules/smart-contract/smart-contract.module.ts b/src/modules/smart-contract/smart-contract.module.ts index 87c986c..a396101 100644 --- a/src/modules/smart-contract/smart-contract.module.ts +++ b/src/modules/smart-contract/smart-contract.module.ts @@ -7,6 +7,7 @@ import { SmartContractController } from './smart-contract.controller'; import { nodeProvider } from './smart-contract.providers'; import { SmartContractService } from './smart-contract.service'; import { TransactionService } from './transaction.service'; +import { Voucher } from './entities/voucher.entity'; @Module({ imports: [ @@ -15,7 +16,7 @@ import { TransactionService } from './transaction.service'; apiKey: 'my_secret_key', apiVersion: '2022-11-15', }), - TypeOrmModule.forFeature([Transaction]), + TypeOrmModule.forFeature([Transaction,Voucher]), ], controllers: [SmartContractController, PaymentController], providers: [SmartContractService, TransactionService, nodeProvider], diff --git a/src/modules/smart-contract/transaction.service.test.ts b/src/modules/smart-contract/transaction.service.test.ts index 270190a..1e87f27 100644 --- a/src/modules/smart-contract/transaction.service.test.ts +++ b/src/modules/smart-contract/transaction.service.test.ts @@ -2,7 +2,7 @@ import { TransactionService } from './transaction.service'; import { AppConfigService } from 'src/config/app-config.service'; import { Transaction } from './entities/transaction.entity'; import { Repository } from 'typeorm'; -import { UserType, VoucherStatus } from '../../common/constants/enums'; +import { ReceiverType, TransactionStatus, UserType, VoucherStatus } from '../../common/constants/enums'; describe('TransactionService', () => { // Mock transaction service @@ -24,10 +24,8 @@ describe('TransactionService', () => { amount: 1, conversionRate: 1, currency: 'FC', - ownerType: UserType.PATIENT, - status: VoucherStatus.UNCLAIMED, - transactionHash: 'transactionHash1', - shortenHash: 'shortenHash1', + ownerType: ReceiverType.PATIENT, + status: TransactionStatus.PENDING, stripePaymentId: 'stripePaymentId1', voucher: { voucher: 'voucher1' }, }; @@ -44,10 +42,8 @@ describe('TransactionService', () => { amount: 1, conversionRate: 1, currency: 'FC', - ownerType: UserType.PATIENT, - status: VoucherStatus.UNCLAIMED, - transactionHash: 'transactionHash2', - shortenHash: 'shortenHash2', + ownerType: ReceiverType.PATIENT, + status: TransactionStatus.PENDING, stripePaymentId: 'stripePaymentId2', voucher: { voucher: 'voucher2' }, };