diff --git a/backend/src/graphql/arg/CreateContributionLinkArgs.ts b/backend/src/graphql/arg/CreateContributionLinkArgs.ts index 3beda53e0..1e7523ee4 100644 --- a/backend/src/graphql/arg/CreateContributionLinkArgs.ts +++ b/backend/src/graphql/arg/CreateContributionLinkArgs.ts @@ -1,5 +1,4 @@ import { ArgsType, Field, Int, InputType } from 'type-graphql' -import Decimal from 'decimal.js-light' @InputType() @ArgsType() @@ -13,8 +12,8 @@ export default class CreateContributionLinkArgs { @Field(() => String) name: string - @Field(() => Decimal) - amount: Decimal + @Field(() => String) + amount: string @Field(() => String) memo: string @@ -22,9 +21,9 @@ export default class CreateContributionLinkArgs { @Field(() => String) cycle: string - @Field(() => Int) - repetition: number + @Field(() => String) + repetition: string - @Field(() => Decimal) - maxAmount: Decimal + @Field(() => String) + maxAmount: string } diff --git a/backend/src/graphql/model/ContributionLink.ts b/backend/src/graphql/model/ContributionLink.ts index 427def187..dd772dbb5 100644 --- a/backend/src/graphql/model/ContributionLink.ts +++ b/backend/src/graphql/model/ContributionLink.ts @@ -28,8 +28,8 @@ export class ContributionLink { @Field(() => Decimal) amount: Decimal - @Field(() => String) - code: string + @Field(() => String, { nullable: true }) + code: string | null @Field(() => Date) createdAt: Date @@ -49,8 +49,8 @@ export class ContributionLink { @Field(() => Boolean) linkEnabled: boolean - @Field(() => String) - link: string + @Field(() => String, { nullable: true }) + link: string | null @Field(() => Decimal, { nullable: true }) maxAccountBalance: Decimal | null diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index acf880efb..a2c4c3b82 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -1328,6 +1328,181 @@ describe('AdminResolver', () => { }) }) }) + // Tests for creating ContributionLinks + describe('createContributionLink', () => { + beforeAll(async () => { + const now = new Date() + creation = await creationFactory(testEnv, { + startDate: new Date(2022, 6, 18).toISOString(), + endDate, + name, + amount, + memo, + cycle, + repetition, + maxAmount, + + email: 'peter@lustig.de', + amount: 400, + memo: 'Herzlich Willkommen bei Gradido!', + creationDate: new Date(now.getFullYear(), now.getMonth() - 1, 1).toISOString(), + }) + }) + + describe('user to create for does not exist', () => { + it('throws an error', async () => { + await expect( + mutate({ mutation: createContributionLink, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Could not find user with email: bibi@bloxberg.de')], + }), + ) + }) + }) + + describe('user to create for is deleted', () => { + beforeAll(async () => { + user = await userFactory(testEnv, stephenHawking) + variables.email = 'stephen@hawking.uk' + }) + + it('throws an error', async () => { + await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('This user was deleted. Cannot make a creation.')], + }), + ) + }) + }) + + describe('user to create for has email not confirmed', () => { + beforeAll(async () => { + user = await userFactory(testEnv, garrickOllivander) + variables.email = 'garrick@ollivander.com' + }) + + it('throws an error', async () => { + await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Creation could not be saved, Email is not activated')], + }), + ) + }) + }) + + describe('valid user to create for', () => { + beforeAll(async () => { + user = await userFactory(testEnv, bibiBloxberg) + variables.email = 'bibi@bloxberg.de' + }) + + describe('date of creation is not a date string', () => { + it('throws an error', async () => { + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('No information for available creations for the given date'), + ], + }), + ) + }) + }) + + describe('date of creation is four months ago', () => { + it('throws an error', async () => { + const now = new Date() + variables.creationDate = new Date( + now.getFullYear(), + now.getMonth() - 4, + 1, + ).toString() + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('No information for available creations for the given date'), + ], + }), + ) + }) + }) + + describe('date of creation is in the future', () => { + it('throws an error', async () => { + const now = new Date() + variables.creationDate = new Date( + now.getFullYear(), + now.getMonth() + 4, + 1, + ).toString() + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('No information for available creations for the given date'), + ], + }), + ) + }) + }) + + describe('amount of creation is too high', () => { + it('throws an error', async () => { + variables.creationDate = new Date().toString() + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The amount (2000 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', + ), + ], + }), + ) + }) + }) + + describe('creation is valid', () => { + it('returns an array of the open creations for the last three months', async () => { + variables.amount = new Decimal(200) + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + createPendingCreation: [1000, 1000, 800], + }, + }), + ) + }) + }) + + describe('second creation surpasses the available amount ', () => { + it('returns an array of the open creations for the last three months', async () => { + variables.amount = new Decimal(1000) + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The amount (1000 GDD) to be created exceeds the amount (800 GDD) still available for this month.', + ), + ], + }), + ) + }) + }) + }) + }) + + }) }) }) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 7b6ceb906..829b9a705 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -519,7 +519,7 @@ export class AdminResolver { throw new Error(`The amount=${amount} must be initialized with a positiv value!`) } const contributionLink = dbContributionLinks.create() - contributionLink.amount = amount + contributionLink.amount = amountObj contributionLink.code = contributionLinkCode(startDateObj) contributionLink.createdAt = new Date() contributionLink.cycle = cycle // ? cycle : ContributionCycleType.NONE @@ -528,8 +528,8 @@ export class AdminResolver { /* not supported in the 1st expansion stage contributionLink.maxAccountBalance = null */ - contributionLink.maxAmountPerMonth = maxAmount - contributionLink.maxPerCycle = repetition + contributionLink.maxAmountPerMonth = null // maxAmount + contributionLink.maxPerCycle = Number(repetition) contributionLink.memo = memo /* not supported in the 1st expansion stage contributionLink.minGapHours = null @@ -669,4 +669,3 @@ const contributionLinkCode = (date: Date): string => { .substring(0, 24 - time.length) + time ) } - diff --git a/database/entity/index.ts b/database/entity/index.ts index 542333755..770fcdda7 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -6,9 +6,11 @@ import { TransactionLink } from './TransactionLink' import { User } from './User' import { UserSetting } from './UserSetting' import { AdminPendingCreation } from './AdminPendingCreation' +import { ContributionLinks } from './ContributionLinks' export const entities = [ AdminPendingCreation, + ContributionLinks, LoginElopageBuys, LoginEmailOptIn, Migration,