-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
src/vault: Add possibility to decrement many vaults as well
In future situations, we might need to decrement many vaults at once as well,(e.g. payment refund etc..) - Added some unit tests to cover vaults updates -Did some refactoring on commonly used types, as well as test mocks
- Loading branch information
1 parent
e61b2ec
commit 7e37d19
Showing
17 changed files
with
288 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,16 +11,26 @@ import { VaultService } from '../vault/vault.service' | |
import { NotificationModule } from '../sockets/notifications/notification.module' | ||
import { MarketingNotificationsModule } from '../notifications/notifications.module' | ||
import { ExportService } from '../export/export.service' | ||
import { Affiliate, Campaign, CampaignState, Donation, Prisma, Vault } from '@prisma/client' | ||
import { | ||
Affiliate, | ||
AffiliateStatus, | ||
Campaign, | ||
CampaignState, | ||
PaymentStatus, | ||
Payments, | ||
Prisma, | ||
Vault, | ||
} from '@prisma/client' | ||
import { KeycloakTokenParsed } from '../auth/keycloak' | ||
import { BadRequestException, ConflictException, ForbiddenException } from '@nestjs/common' | ||
import { AffiliateStatusUpdateDto } from './dto/affiliate-status-update.dto' | ||
import * as afCodeGenerator from './utils/affiliateCodeGenerator' | ||
import { CreateAffiliateDonationDto } from './dto/create-affiliate-donation.dto' | ||
import { mockPayment } from '../donations/__mocks__/paymentMock' | ||
|
||
type PersonWithPayload = Prisma.PersonGetPayload<{ include: { company: true } }> | ||
type AffiliateWithPayload = Prisma.AffiliateGetPayload<{ | ||
include: { company: { include: { person: true } }; donations: true } | ||
include: { company: { include: { person: true } }; payments: true } | ||
}> | ||
|
||
describe('AffiliateController', () => { | ||
|
@@ -126,28 +136,10 @@ describe('AffiliateController', () => { | |
countryCode: null, | ||
person: { ...mockIndividualProfile }, | ||
}, | ||
donations: [], | ||
payments: [], | ||
} | ||
|
||
const donationResponseMock: Donation = { | ||
id: 'donation-id', | ||
type: 'donation', | ||
status: 'guaranteed', | ||
amount: 5000, | ||
affiliateId: activeAffiliateMock.id, | ||
personId: null, | ||
extCustomerId: '', | ||
extPaymentIntentId: '123456', | ||
extPaymentMethodId: '1234', | ||
billingEmail: '[email protected]', | ||
billingName: 'John Doe', | ||
targetVaultId: vaultMock.id, | ||
chargedAmount: 0, | ||
currency: 'BGN', | ||
createdAt: new Date(), | ||
updatedAt: new Date(), | ||
provider: 'bank', | ||
} | ||
const mockGuaranteedPayment = { ...mockPayment, status: PaymentStatus.guaranteed } | ||
|
||
const userMock = { | ||
sub: 'testKeycloackId', | ||
|
@@ -232,13 +224,13 @@ describe('AffiliateController', () => { | |
|
||
const activeAffiliateMock: Affiliate = { | ||
...affiliateMock, | ||
status: 'active', | ||
status: AffiliateStatus.active, | ||
id: '12345', | ||
affiliateCode: affiliateCodeMock, | ||
} | ||
|
||
const mockCancelledStatus: AffiliateStatusUpdateDto = { | ||
newStatus: 'cancelled', | ||
newStatus: AffiliateStatus.cancelled, | ||
} | ||
jest.spyOn(service, 'findOneById').mockResolvedValue(activeAffiliateMock) | ||
|
||
|
@@ -265,7 +257,7 @@ describe('AffiliateController', () => { | |
jest.spyOn(service, 'findOneById').mockResolvedValue(activeAffiliateMock) | ||
|
||
const updateStatusDto: AffiliateStatusUpdateDto = { | ||
newStatus: 'active', | ||
newStatus: AffiliateStatus.active, | ||
} | ||
const codeGenerationSpy = jest | ||
.spyOn(afCodeGenerator, 'affiliateCodeGenerator') | ||
|
@@ -305,7 +297,7 @@ describe('AffiliateController', () => { | |
jest.spyOn(service, 'findOneByCode').mockResolvedValue(activeAffiliateMock) | ||
const createAffiliateDonationSpy = jest | ||
.spyOn(donationService, 'createAffiliateDonation') | ||
.mockResolvedValue(donationResponseMock) | ||
.mockResolvedValue(mockGuaranteedPayment) | ||
jest.spyOn(prismaMock.vault, 'findMany').mockResolvedValue([vaultMock]) | ||
prismaMock.campaign.findFirst.mockResolvedValue({ | ||
id: '123', | ||
|
@@ -318,34 +310,34 @@ describe('AffiliateController', () => { | |
affiliateId: activeAffiliateMock.id, | ||
}) | ||
expect(await donationService.createAffiliateDonation(affiliateDonationDto)).toEqual( | ||
donationResponseMock, | ||
mockGuaranteedPayment, | ||
) | ||
}) | ||
it('should cancel', async () => { | ||
const cancelledDonationResponse: Donation = { | ||
...donationResponseMock, | ||
status: 'cancelled', | ||
const cancelledDonationResponse: Payments = { | ||
...mockGuaranteedPayment, | ||
status: PaymentStatus.cancelled, | ||
} | ||
jest | ||
.spyOn(donationService, 'getAffiliateDonationById') | ||
.mockResolvedValue(donationResponseMock) | ||
.mockResolvedValue(mockGuaranteedPayment) | ||
jest.spyOn(donationService, 'update').mockResolvedValue(cancelledDonationResponse) | ||
expect( | ||
await controller.cancelAffiliateDonation(affiliateCodeMock, donationResponseMock.id), | ||
await controller.cancelAffiliateDonation(affiliateCodeMock, mockGuaranteedPayment.id), | ||
).toEqual(cancelledDonationResponse) | ||
}) | ||
it('should throw error if donation status is succeeded', async () => { | ||
const succeededDonationResponse: Donation = { | ||
...donationResponseMock, | ||
status: 'succeeded', | ||
const succeededDonationResponse: Payments = { | ||
...mockGuaranteedPayment, | ||
status: PaymentStatus.succeeded, | ||
} | ||
|
||
jest | ||
.spyOn(donationService, 'getAffiliateDonationById') | ||
.mockResolvedValue(succeededDonationResponse) | ||
const updateDonationStatus = jest.spyOn(donationService, 'update') | ||
expect( | ||
controller.cancelAffiliateDonation(affiliateCodeMock, donationResponseMock.id), | ||
controller.cancelAffiliateDonation(affiliateCodeMock, mockGuaranteedPayment.id), | ||
).rejects.toThrow(new BadRequestException("Donation status can't be updated")) | ||
expect(updateDonationStatus).not.toHaveBeenCalled() | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Prisma } from '@prisma/client' | ||
|
||
export type AffiliateWithDonation = Prisma.AffiliateGetPayload<{ | ||
include: { payments: { include: { donations: true } } } | ||
}> | ||
|
||
export type AffiliateWithCompanyPayload = Prisma.AffiliateGetPayload<{ | ||
include: { company: { include: { person: true } }; donations: true } | ||
}> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,18 +23,19 @@ import { MarketingNotificationsService } from '../notifications/notifications.se | |
import { EmailService } from '../email/email.service' | ||
import { TemplateService } from '../email/template.service' | ||
import { CampaignNewsService } from '../campaign-news/campaign-news.service' | ||
import { personMock } from '../person/__mock__/peronMock' | ||
|
||
describe('CampaignController', () => { | ||
let controller: CampaignController | ||
let prismaService: PrismaService | ||
let campaignService: CampaignService | ||
let marketingProvider: NotificationsProviderInterface<unknown> | ||
let marketingProvider: NotificationsProviderInterface | ||
let marketingService: MarketingNotificationsService | ||
const personServiceMock = { | ||
findOneByKeycloakId: jest.fn(() => { | ||
return { id: personIdMock } | ||
}), | ||
findByEmail: jest.fn(async () => { | ||
findByEmail: jest.fn(async (): Promise<Person | null> => { | ||
return person | ||
}), | ||
update: jest.fn(async () => { | ||
|
@@ -51,24 +52,7 @@ describe('CampaignController', () => { | |
}), | ||
} | ||
|
||
const person: Person | null = { | ||
id: 'e43348aa-be33-4c12-80bf-2adfbf8736cd', | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
keycloakId: 'some-id', | ||
email: '[email protected]', | ||
emailConfirmed: false, | ||
companyId: null, | ||
phone: null, | ||
picture: null, | ||
createdAt: new Date('2021-10-07T13:38:11.097Z'), | ||
updatedAt: new Date('2021-10-07T13:38:11.097Z'), | ||
newsletter: true, | ||
address: null, | ||
birthday: null, | ||
personalNumber: null, | ||
stripeCustomerId: null, | ||
} | ||
const person: Person = personMock | ||
|
||
const mockCreateCampaign = { | ||
slug: 'test-slug', | ||
|
@@ -428,7 +412,7 @@ describe('CampaignController', () => { | |
describe('subscribeToCampaignNotifications', () => { | ||
it('should throw if no consent is provided', async () => { | ||
const data: CampaignSubscribeDto = { | ||
email: person.email, | ||
email: person.email!, | ||
consent: false, | ||
} | ||
|
||
|
@@ -439,7 +423,7 @@ describe('CampaignController', () => { | |
|
||
it('should throw if the campaign is not active', async () => { | ||
const data: CampaignSubscribeDto = { | ||
email: person.email, | ||
email: person.email!, | ||
consent: true, | ||
} | ||
|
||
|
@@ -458,7 +442,7 @@ describe('CampaignController', () => { | |
jest.spyOn(marketingService, 'sendConfirmEmail') | ||
|
||
const data: CampaignSubscribeDto = { | ||
email: person.email, | ||
email: person.email!, | ||
// Valid consent | ||
consent: true, | ||
} | ||
|
@@ -497,7 +481,7 @@ describe('CampaignController', () => { | |
jest.spyOn(campaignService, 'createCampaignNotificationList') | ||
|
||
const data: CampaignSubscribeDto = { | ||
email: person.email, | ||
email: person.email!, | ||
// Valid consent | ||
consent: true, | ||
} | ||
|
@@ -538,7 +522,7 @@ describe('CampaignController', () => { | |
jest.spyOn(marketingService, 'sendConfirmEmail') | ||
|
||
const data: CampaignSubscribeDto = { | ||
email: person.email, | ||
email: person.email!, | ||
// Valid consent | ||
consent: true, | ||
} | ||
|
@@ -566,7 +550,7 @@ describe('CampaignController', () => { | |
expect(marketingService.sendConfirmEmail).not.toHaveBeenCalled() | ||
}) | ||
|
||
it('should create a saparate notification consent record for non-registered emails', async () => { | ||
it('should create a separate notification consent record for non-registered emails', async () => { | ||
jest.spyOn(marketingProvider, 'addContactsToList').mockImplementation(async () => '') | ||
jest.spyOn(campaignService, 'createCampaignNotificationList') | ||
jest.spyOn(marketingService, 'sendConfirmEmail') | ||
|
@@ -577,7 +561,7 @@ describe('CampaignController', () => { | |
}) | ||
|
||
const data: CampaignSubscribeDto = { | ||
email: person.email, | ||
email: person.email!, | ||
// Valid consent | ||
consent: true, | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Currency, DonationType, PaymentProvider, PaymentStatus } from '@prisma/client' | ||
import { PaymentWithDonation } from '../types/donation' | ||
import { DonationWithPerson } from '../types/donation' | ||
import { personMock } from '../../person/__mock__/peronMock' | ||
|
||
export const mockDonation: DonationWithPerson = { | ||
id: '1234', | ||
paymentId: '123', | ||
type: DonationType.donation, | ||
amount: 10, | ||
targetVaultId: 'vault-1', | ||
createdAt: new Date('2022-01-01'), | ||
updatedAt: new Date('2022-01-02'), | ||
personId: '1', | ||
person: personMock, | ||
} | ||
|
||
//Mock donation to different vault | ||
const mockDonationWithDiffVaultId: DonationWithPerson = { | ||
...mockDonation, | ||
targetVaultId: 'vault-2', | ||
} | ||
|
||
//Mock donation to same vault as mockDonation, but different amount | ||
const mockDonationWithDiffAmount: DonationWithPerson = { ...mockDonation, amount: 50 } | ||
|
||
export const mockPayment: PaymentWithDonation = { | ||
id: '123', | ||
provider: PaymentProvider.bank, | ||
currency: Currency.BGN, | ||
type: 'single', | ||
status: PaymentStatus.initial, | ||
amount: 10, | ||
affiliateId: null, | ||
extCustomerId: 'hahaha', | ||
extPaymentIntentId: 'pm1', | ||
extPaymentMethodId: 'bank', | ||
billingEmail: '[email protected]', | ||
billingName: 'Test', | ||
chargedAmount: 10.5, | ||
createdAt: new Date('2022-01-01'), | ||
updatedAt: new Date('2022-01-02'), | ||
donations: [mockDonation, mockDonationWithDiffVaultId, mockDonationWithDiffAmount], | ||
} | ||
|
||
export const mockSucceededPayment: PaymentWithDonation = { | ||
...mockPayment, | ||
status: PaymentStatus.succeeded, | ||
} | ||
export const mockGuaranteedPayment: PaymentWithDonation = { | ||
...mockPayment, | ||
status: PaymentStatus.guaranteed, | ||
} | ||
export const mockCancelledPayment: PaymentWithDonation = { | ||
...mockPayment, | ||
status: PaymentStatus.cancelled, | ||
} |
Oops, something went wrong.