mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into open-creations-call
This commit is contained in:
commit
0c65d8c4ab
@ -32,7 +32,7 @@ export class BalanceResolver {
|
|||||||
|
|
||||||
const lastTransaction = context.lastTransaction
|
const lastTransaction = context.lastTransaction
|
||||||
? context.lastTransaction
|
? context.lastTransaction
|
||||||
: await dbTransaction.findOne({ userId: user.id }, { order: { balanceDate: 'DESC' } })
|
: await dbTransaction.findOne({ userId: user.id }, { order: { id: 'DESC' } })
|
||||||
|
|
||||||
logger.debug(`lastTransaction=${lastTransaction}`)
|
logger.debug(`lastTransaction=${lastTransaction}`)
|
||||||
|
|
||||||
|
|||||||
@ -1947,6 +1947,23 @@ describe('ContributionResolver', () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('confirm same contribution again', () => {
|
||||||
|
it('throws an error', async () => {
|
||||||
|
await expect(
|
||||||
|
mutate({
|
||||||
|
mutation: confirmContribution,
|
||||||
|
variables: {
|
||||||
|
id: creation ? creation.id : -1,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('Contribution already confirmd.')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('confirm two creations one after the other quickly', () => {
|
describe('confirm two creations one after the other quickly', () => {
|
||||||
|
|||||||
@ -555,108 +555,116 @@ export class ContributionResolver {
|
|||||||
@Arg('id', () => Int) id: number,
|
@Arg('id', () => Int) id: number,
|
||||||
@Ctx() context: Context,
|
@Ctx() context: Context,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const clientTimezoneOffset = getClientTimezoneOffset(context)
|
|
||||||
const contribution = await DbContribution.findOne(id)
|
|
||||||
if (!contribution) {
|
|
||||||
logger.error(`Contribution not found for given id: ${id}`)
|
|
||||||
throw new Error('Contribution not found to given id.')
|
|
||||||
}
|
|
||||||
const moderatorUser = getUser(context)
|
|
||||||
if (moderatorUser.id === contribution.userId) {
|
|
||||||
logger.error('Moderator can not confirm own contribution')
|
|
||||||
throw new Error('Moderator can not confirm own contribution')
|
|
||||||
}
|
|
||||||
const user = await DbUser.findOneOrFail(
|
|
||||||
{ id: contribution.userId },
|
|
||||||
{ withDeleted: true, relations: ['emailContact'] },
|
|
||||||
)
|
|
||||||
if (user.deletedAt) {
|
|
||||||
logger.error('This user was deleted. Cannot confirm a contribution.')
|
|
||||||
throw new Error('This user was deleted. Cannot confirm a contribution.')
|
|
||||||
}
|
|
||||||
const creations = await getUserCreation(contribution.userId, clientTimezoneOffset, false)
|
|
||||||
validateContribution(
|
|
||||||
creations,
|
|
||||||
contribution.amount,
|
|
||||||
contribution.contributionDate,
|
|
||||||
clientTimezoneOffset,
|
|
||||||
)
|
|
||||||
|
|
||||||
// acquire lock
|
// acquire lock
|
||||||
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
const releaseLock = await TRANSACTIONS_LOCK.acquire()
|
||||||
|
|
||||||
const receivedCallDate = new Date()
|
|
||||||
const queryRunner = getConnection().createQueryRunner()
|
|
||||||
await queryRunner.connect()
|
|
||||||
await queryRunner.startTransaction('REPEATABLE READ') // 'READ COMMITTED')
|
|
||||||
try {
|
try {
|
||||||
const lastTransaction = await queryRunner.manager
|
const clientTimezoneOffset = getClientTimezoneOffset(context)
|
||||||
.createQueryBuilder()
|
const contribution = await DbContribution.findOne(id)
|
||||||
.select('transaction')
|
if (!contribution) {
|
||||||
.from(DbTransaction, 'transaction')
|
logger.error(`Contribution not found for given id: ${id}`)
|
||||||
.where('transaction.userId = :id', { id: contribution.userId })
|
throw new Error('Contribution not found to given id.')
|
||||||
.orderBy('transaction.id', 'DESC')
|
|
||||||
.getOne()
|
|
||||||
logger.info('lastTransaction ID', lastTransaction ? lastTransaction.id : 'undefined')
|
|
||||||
|
|
||||||
let newBalance = new Decimal(0)
|
|
||||||
let decay: Decay | null = null
|
|
||||||
if (lastTransaction) {
|
|
||||||
decay = calculateDecay(
|
|
||||||
lastTransaction.balance,
|
|
||||||
lastTransaction.balanceDate,
|
|
||||||
receivedCallDate,
|
|
||||||
)
|
|
||||||
newBalance = decay.balance
|
|
||||||
}
|
}
|
||||||
newBalance = newBalance.add(contribution.amount.toString())
|
if (contribution.confirmedAt) {
|
||||||
|
logger.error(`Contribution already confirmd: ${id}`)
|
||||||
|
throw new Error('Contribution already confirmd.')
|
||||||
|
}
|
||||||
|
const moderatorUser = getUser(context)
|
||||||
|
if (moderatorUser.id === contribution.userId) {
|
||||||
|
logger.error('Moderator can not confirm own contribution')
|
||||||
|
throw new Error('Moderator can not confirm own contribution')
|
||||||
|
}
|
||||||
|
const user = await DbUser.findOneOrFail(
|
||||||
|
{ id: contribution.userId },
|
||||||
|
{ withDeleted: true, relations: ['emailContact'] },
|
||||||
|
)
|
||||||
|
if (user.deletedAt) {
|
||||||
|
logger.error('This user was deleted. Cannot confirm a contribution.')
|
||||||
|
throw new Error('This user was deleted. Cannot confirm a contribution.')
|
||||||
|
}
|
||||||
|
const creations = await getUserCreation(contribution.userId, clientTimezoneOffset, false)
|
||||||
|
validateContribution(
|
||||||
|
creations,
|
||||||
|
contribution.amount,
|
||||||
|
contribution.contributionDate,
|
||||||
|
clientTimezoneOffset,
|
||||||
|
)
|
||||||
|
|
||||||
const transaction = new DbTransaction()
|
const receivedCallDate = new Date()
|
||||||
transaction.typeId = TransactionTypeId.CREATION
|
const queryRunner = getConnection().createQueryRunner()
|
||||||
transaction.memo = contribution.memo
|
await queryRunner.connect()
|
||||||
transaction.userId = contribution.userId
|
await queryRunner.startTransaction('REPEATABLE READ') // 'READ COMMITTED')
|
||||||
transaction.previous = lastTransaction ? lastTransaction.id : null
|
try {
|
||||||
transaction.amount = contribution.amount
|
const lastTransaction = await queryRunner.manager
|
||||||
transaction.creationDate = contribution.contributionDate
|
.createQueryBuilder()
|
||||||
transaction.balance = newBalance
|
.select('transaction')
|
||||||
transaction.balanceDate = receivedCallDate
|
.from(DbTransaction, 'transaction')
|
||||||
transaction.decay = decay ? decay.decay : new Decimal(0)
|
.where('transaction.userId = :id', { id: contribution.userId })
|
||||||
transaction.decayStart = decay ? decay.start : null
|
.orderBy('transaction.id', 'DESC')
|
||||||
await queryRunner.manager.insert(DbTransaction, transaction)
|
.getOne()
|
||||||
|
logger.info('lastTransaction ID', lastTransaction ? lastTransaction.id : 'undefined')
|
||||||
|
|
||||||
contribution.confirmedAt = receivedCallDate
|
let newBalance = new Decimal(0)
|
||||||
contribution.confirmedBy = moderatorUser.id
|
let decay: Decay | null = null
|
||||||
contribution.transactionId = transaction.id
|
if (lastTransaction) {
|
||||||
contribution.contributionStatus = ContributionStatus.CONFIRMED
|
decay = calculateDecay(
|
||||||
await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution)
|
lastTransaction.balance,
|
||||||
|
lastTransaction.balanceDate,
|
||||||
|
receivedCallDate,
|
||||||
|
)
|
||||||
|
newBalance = decay.balance
|
||||||
|
}
|
||||||
|
newBalance = newBalance.add(contribution.amount.toString())
|
||||||
|
|
||||||
await queryRunner.commitTransaction()
|
const transaction = new DbTransaction()
|
||||||
logger.info('creation commited successfuly.')
|
transaction.typeId = TransactionTypeId.CREATION
|
||||||
sendContributionConfirmedEmail({
|
transaction.memo = contribution.memo
|
||||||
firstName: user.firstName,
|
transaction.userId = contribution.userId
|
||||||
lastName: user.lastName,
|
transaction.previous = lastTransaction ? lastTransaction.id : null
|
||||||
email: user.emailContact.email,
|
transaction.amount = contribution.amount
|
||||||
language: user.language,
|
transaction.creationDate = contribution.contributionDate
|
||||||
senderFirstName: moderatorUser.firstName,
|
transaction.balance = newBalance
|
||||||
senderLastName: moderatorUser.lastName,
|
transaction.balanceDate = receivedCallDate
|
||||||
contributionMemo: contribution.memo,
|
transaction.decay = decay ? decay.decay : new Decimal(0)
|
||||||
contributionAmount: contribution.amount,
|
transaction.decayStart = decay ? decay.start : null
|
||||||
})
|
await queryRunner.manager.insert(DbTransaction, transaction)
|
||||||
} catch (e) {
|
|
||||||
await queryRunner.rollbackTransaction()
|
contribution.confirmedAt = receivedCallDate
|
||||||
logger.error('Creation was not successful', e)
|
contribution.confirmedBy = moderatorUser.id
|
||||||
throw new Error('Creation was not successful.')
|
contribution.transactionId = transaction.id
|
||||||
|
contribution.contributionStatus = ContributionStatus.CONFIRMED
|
||||||
|
await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution)
|
||||||
|
|
||||||
|
await queryRunner.commitTransaction()
|
||||||
|
logger.info('creation commited successfuly.')
|
||||||
|
sendContributionConfirmedEmail({
|
||||||
|
firstName: user.firstName,
|
||||||
|
lastName: user.lastName,
|
||||||
|
email: user.emailContact.email,
|
||||||
|
language: user.language,
|
||||||
|
senderFirstName: moderatorUser.firstName,
|
||||||
|
senderLastName: moderatorUser.lastName,
|
||||||
|
contributionMemo: contribution.memo,
|
||||||
|
contributionAmount: contribution.amount,
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
await queryRunner.rollbackTransaction()
|
||||||
|
logger.error('Creation was not successful', e)
|
||||||
|
throw new Error('Creation was not successful.')
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release()
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = new Event()
|
||||||
|
const eventContributionConfirm = new EventContributionConfirm()
|
||||||
|
eventContributionConfirm.userId = user.id
|
||||||
|
eventContributionConfirm.amount = contribution.amount
|
||||||
|
eventContributionConfirm.contributionId = contribution.id
|
||||||
|
await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm))
|
||||||
} finally {
|
} finally {
|
||||||
await queryRunner.release()
|
|
||||||
releaseLock()
|
releaseLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = new Event()
|
|
||||||
const eventContributionConfirm = new EventContributionConfirm()
|
|
||||||
eventContributionConfirm.userId = user.id
|
|
||||||
eventContributionConfirm.amount = contribution.amount
|
|
||||||
eventContributionConfirm.contributionId = contribution.id
|
|
||||||
await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm))
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -211,7 +211,7 @@ export class TransactionResolver {
|
|||||||
// find current balance
|
// find current balance
|
||||||
const lastTransaction = await dbTransaction.findOne(
|
const lastTransaction = await dbTransaction.findOne(
|
||||||
{ userId: user.id },
|
{ userId: user.id },
|
||||||
{ order: { balanceDate: 'DESC' }, relations: ['contribution'] },
|
{ order: { id: 'DESC' }, relations: ['contribution'] },
|
||||||
)
|
)
|
||||||
logger.debug(`lastTransaction=${lastTransaction}`)
|
logger.debug(`lastTransaction=${lastTransaction}`)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user