mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into test-softdeleted
This commit is contained in:
commit
947cbb659b
@ -10,7 +10,7 @@
|
||||
"scripts": {
|
||||
"build": "tsc --build",
|
||||
"clean": "tsc --build --clean",
|
||||
"start": "node build/index.js",
|
||||
"start": "node build/src/index.js",
|
||||
"dev": "nodemon -w src --ext ts --exec ts-node src/index.ts",
|
||||
"lint": "eslint . --ext .js,.ts",
|
||||
"test": "TZ=UTC NODE_ENV=development jest --runInBand --coverage --forceExit --detectOpenHandles"
|
||||
@ -31,7 +31,6 @@
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"module-alias": "^2.2.2",
|
||||
"moment": "^2.29.1",
|
||||
"mysql2": "^2.3.0",
|
||||
"nodemailer": "^6.6.5",
|
||||
"random-bigint": "^0.0.1",
|
||||
|
||||
@ -12,7 +12,6 @@ import { UserRepository } from '../../typeorm/repository/User'
|
||||
import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs'
|
||||
import UpdatePendingCreationArgs from '../arg/UpdatePendingCreationArgs'
|
||||
import SearchUsersArgs from '../arg/SearchUsersArgs'
|
||||
import moment from 'moment'
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
import { UserTransaction } from '@entity/UserTransaction'
|
||||
import { UserTransactionRepository } from '../../typeorm/repository/UserTransaction'
|
||||
@ -48,6 +47,7 @@ export class AdminResolver {
|
||||
if (notActivated) {
|
||||
filterCriteria.push({ emailChecked: false })
|
||||
}
|
||||
|
||||
if (isDeleted) {
|
||||
filterCriteria.push({ deletedAt: Not(IsNull()) })
|
||||
}
|
||||
@ -65,6 +65,8 @@ export class AdminResolver {
|
||||
pageSize,
|
||||
)
|
||||
|
||||
const creations = await getUserCreations(users.map((u) => u.id))
|
||||
|
||||
const adminUsers = await Promise.all(
|
||||
users.map(async (user) => {
|
||||
let emailConfirmationSend = ''
|
||||
@ -152,7 +154,7 @@ export class AdminResolver {
|
||||
if (!user.emailChecked) {
|
||||
throw new Error('Creation could not be saved, Email is not activated')
|
||||
}
|
||||
const creations = await getUserCreations(user.id)
|
||||
const creations = await getUserCreation(user.id)
|
||||
const creationDateObj = new Date(creationDate)
|
||||
if (isCreationValid(creations, amount, creationDateObj)) {
|
||||
const adminPendingCreation = AdminPendingCreation.create()
|
||||
@ -165,7 +167,7 @@ export class AdminResolver {
|
||||
|
||||
await AdminPendingCreation.save(adminPendingCreation)
|
||||
}
|
||||
return getUserCreations(user.id)
|
||||
return getUserCreation(user.id)
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.CREATE_PENDING_CREATION])
|
||||
@ -214,7 +216,7 @@ export class AdminResolver {
|
||||
}
|
||||
|
||||
const creationDateObj = new Date(creationDate)
|
||||
let creations = await getUserCreations(user.id)
|
||||
let creations = await getUserCreation(user.id)
|
||||
if (pendingCreationToUpdate.date.getMonth() === creationDateObj.getMonth()) {
|
||||
creations = updateCreations(creations, pendingCreationToUpdate)
|
||||
}
|
||||
@ -233,7 +235,8 @@ export class AdminResolver {
|
||||
result.memo = pendingCreationToUpdate.memo
|
||||
result.date = pendingCreationToUpdate.date
|
||||
result.moderator = pendingCreationToUpdate.moderator
|
||||
result.creation = await getUserCreations(user.id)
|
||||
|
||||
result.creation = await getUserCreation(user.id)
|
||||
|
||||
return result
|
||||
}
|
||||
@ -242,27 +245,27 @@ export class AdminResolver {
|
||||
@Query(() => [PendingCreation])
|
||||
async getPendingCreations(): Promise<PendingCreation[]> {
|
||||
const pendingCreations = await AdminPendingCreation.find()
|
||||
if (pendingCreations.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
const pendingCreationsPromise = await Promise.all(
|
||||
pendingCreations.map(async (pendingCreation) => {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const user = await userRepository.findOneOrFail({ id: pendingCreation.userId })
|
||||
const userIds = pendingCreations.map((p) => p.userId)
|
||||
const userCreations = await getUserCreations(userIds)
|
||||
const users = await User.find({ id: In(userIds) })
|
||||
|
||||
const parsedAmount = Number(parseInt(pendingCreation.amount.toString()) / 10000)
|
||||
// pendingCreation.amount = parsedAmount
|
||||
const newPendingCreation = {
|
||||
...pendingCreation,
|
||||
amount: parsedAmount,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
email: user.email,
|
||||
creation: await getUserCreations(user.id),
|
||||
}
|
||||
return pendingCreations.map((pendingCreation) => {
|
||||
const user = users.find((u) => u.id === pendingCreation.userId)
|
||||
const creation = userCreations.find((c) => c.id === pendingCreation.userId)
|
||||
|
||||
return newPendingCreation
|
||||
}),
|
||||
)
|
||||
return pendingCreationsPromise.reverse()
|
||||
return {
|
||||
...pendingCreation,
|
||||
amount: Number(parseInt(pendingCreation.amount.toString()) / 10000),
|
||||
firstName: user ? user.firstName : '',
|
||||
lastName: user ? user.lastName : '',
|
||||
email: user ? user.email : '',
|
||||
creation: creation ? creation.creations : [1000, 1000, 1000],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.DELETE_PENDING_CREATION])
|
||||
@ -282,6 +285,11 @@ export class AdminResolver {
|
||||
if (moderatorUser.id === pendingCreation.userId)
|
||||
throw new Error('Moderator can not confirm own pending creation')
|
||||
|
||||
const creations = await getUserCreation(pendingCreation.userId, false)
|
||||
if (!isCreationValid(creations, Number(pendingCreation.amount) / 10000, pendingCreation.date)) {
|
||||
throw new Error('Creation is not valid!!')
|
||||
}
|
||||
|
||||
const receivedCallDate = new Date()
|
||||
let transaction = new Transaction()
|
||||
transaction.transactionTypeId = TransactionTypeId.CREATION
|
||||
@ -335,129 +343,94 @@ export class AdminResolver {
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserCreations(id: number): Promise<number[]> {
|
||||
const dateNextMonth = moment().add(1, 'month').format('YYYY-MM') + '-01'
|
||||
const dateBeforeLastMonth = moment().subtract(2, 'month').format('YYYY-MM') + '-01'
|
||||
const beforeLastMonthNumber = moment().subtract(2, 'month').format('M')
|
||||
const lastMonthNumber = moment().subtract(1, 'month').format('M')
|
||||
const currentMonthNumber = moment().format('M')
|
||||
interface CreationMap {
|
||||
id: number
|
||||
creations: number[]
|
||||
}
|
||||
|
||||
const createdAmountsQuery = await Transaction.createQueryBuilder('transactions')
|
||||
.select('MONTH(transactions.creation_date)', 'target_month')
|
||||
.addSelect('SUM(transactions.amount)', 'sum')
|
||||
.where('transactions.user_id = :id', { id })
|
||||
.andWhere('transactions.transaction_type_id = :type', { type: TransactionTypeId.CREATION })
|
||||
.andWhere({
|
||||
creationDate: Raw((alias) => `${alias} >= :date and ${alias} < :endDate`, {
|
||||
date: dateBeforeLastMonth,
|
||||
endDate: dateNextMonth,
|
||||
async function getUserCreation(id: number, includePending = true): Promise<number[]> {
|
||||
const creations = await getUserCreations([id], includePending)
|
||||
return creations[0] ? creations[0].creations : [1000, 1000, 1000]
|
||||
}
|
||||
|
||||
async function getUserCreations(ids: number[], includePending = true): Promise<CreationMap[]> {
|
||||
const months = getCreationMonths()
|
||||
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
await queryRunner.connect()
|
||||
|
||||
const dateFilter = 'last_day(curdate() - interval 3 month) + interval 1 day'
|
||||
|
||||
const unionString = includePending
|
||||
? `
|
||||
UNION
|
||||
SELECT date AS date, amount AS amount, userId AS userId FROM admin_pending_creations
|
||||
WHERE userId IN (${ids.toString()})
|
||||
AND date >= ${dateFilter}`
|
||||
: ''
|
||||
|
||||
const unionQuery = await queryRunner.manager.query(`
|
||||
SELECT MONTH(date) AS month, sum(amount) AS sum, userId AS id FROM
|
||||
(SELECT creation_date AS date, amount AS amount, user_id AS userId FROM transactions
|
||||
WHERE user_id IN (${ids.toString()})
|
||||
AND transaction_type_id = ${TransactionTypeId.CREATION}
|
||||
AND creation_date >= ${dateFilter}
|
||||
${unionString}) AS result
|
||||
GROUP BY month, userId
|
||||
ORDER BY date DESC
|
||||
`)
|
||||
|
||||
await queryRunner.release()
|
||||
|
||||
return ids.map((id) => {
|
||||
return {
|
||||
id,
|
||||
creations: months.map((month) => {
|
||||
const creation = unionQuery.find(
|
||||
(raw: { month: string; id: string; creation: number[] }) =>
|
||||
parseInt(raw.month) === month && parseInt(raw.id) === id,
|
||||
)
|
||||
return 1000 - (creation ? Number(creation.sum) / 10000 : 0)
|
||||
}),
|
||||
})
|
||||
.groupBy('target_month')
|
||||
.orderBy('target_month', 'ASC')
|
||||
.getRawMany()
|
||||
|
||||
const pendingAmountsQuery = await AdminPendingCreation.createQueryBuilder(
|
||||
'admin_pending_creations',
|
||||
)
|
||||
.select('MONTH(admin_pending_creations.date)', 'target_month')
|
||||
.addSelect('SUM(admin_pending_creations.amount)', 'sum')
|
||||
.where('admin_pending_creations.userId = :id', { id })
|
||||
.andWhere({
|
||||
date: Raw((alias) => `${alias} >= :date and ${alias} < :endDate`, {
|
||||
date: dateBeforeLastMonth,
|
||||
endDate: dateNextMonth,
|
||||
}),
|
||||
})
|
||||
.groupBy('target_month')
|
||||
.orderBy('target_month', 'ASC')
|
||||
.getRawMany()
|
||||
|
||||
const map = new Map()
|
||||
if (Array.isArray(createdAmountsQuery) && createdAmountsQuery.length > 0) {
|
||||
createdAmountsQuery.forEach((createdAmount) => {
|
||||
if (!map.has(createdAmount.target_month)) {
|
||||
map.set(createdAmount.target_month, createdAmount.sum)
|
||||
} else {
|
||||
const store = map.get(createdAmount.target_month)
|
||||
map.set(createdAmount.target_month, Number(store) + Number(createdAmount.sum))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (Array.isArray(pendingAmountsQuery) && pendingAmountsQuery.length > 0) {
|
||||
pendingAmountsQuery.forEach((pendingAmount) => {
|
||||
if (!map.has(pendingAmount.target_month)) {
|
||||
map.set(pendingAmount.target_month, pendingAmount.sum)
|
||||
} else {
|
||||
const store = map.get(pendingAmount.target_month)
|
||||
map.set(pendingAmount.target_month, Number(store) + Number(pendingAmount.sum))
|
||||
}
|
||||
})
|
||||
}
|
||||
const usedCreationBeforeLastMonth = map.get(Number(beforeLastMonthNumber))
|
||||
? Number(map.get(Number(beforeLastMonthNumber))) / 10000
|
||||
: 0
|
||||
const usedCreationLastMonth = map.get(Number(lastMonthNumber))
|
||||
? Number(map.get(Number(lastMonthNumber))) / 10000
|
||||
: 0
|
||||
|
||||
const usedCreationCurrentMonth = map.get(Number(currentMonthNumber))
|
||||
? Number(map.get(Number(currentMonthNumber))) / 10000
|
||||
: 0
|
||||
|
||||
return [
|
||||
1000 - usedCreationBeforeLastMonth,
|
||||
1000 - usedCreationLastMonth,
|
||||
1000 - usedCreationCurrentMonth,
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function updateCreations(creations: number[], pendingCreation: AdminPendingCreation): number[] {
|
||||
const dateMonth = moment().format('YYYY-MM')
|
||||
const dateLastMonth = moment().subtract(1, 'month').format('YYYY-MM')
|
||||
const dateBeforeLastMonth = moment().subtract(2, 'month').format('YYYY-MM')
|
||||
const creationDateMonth = moment(pendingCreation.date).format('YYYY-MM')
|
||||
const index = getCreationIndex(pendingCreation.date.getMonth())
|
||||
|
||||
switch (creationDateMonth) {
|
||||
case dateMonth:
|
||||
creations[2] += parseInt(pendingCreation.amount.toString())
|
||||
break
|
||||
case dateLastMonth:
|
||||
creations[1] += parseInt(pendingCreation.amount.toString())
|
||||
break
|
||||
case dateBeforeLastMonth:
|
||||
creations[0] += parseInt(pendingCreation.amount.toString())
|
||||
break
|
||||
default:
|
||||
throw new Error('UpdatedCreationDate is not in the last three months')
|
||||
if (index < 0) {
|
||||
throw new Error('You cannot create GDD for a month older than the last three months.')
|
||||
}
|
||||
creations[index] += parseInt(pendingCreation.amount.toString())
|
||||
return creations
|
||||
}
|
||||
|
||||
function isCreationValid(creations: number[], amount: number, creationDate: Date) {
|
||||
const dateMonth = moment().format('YYYY-MM')
|
||||
const dateLastMonth = moment().subtract(1, 'month').format('YYYY-MM')
|
||||
const dateBeforeLastMonth = moment().subtract(2, 'month').format('YYYY-MM')
|
||||
const creationDateMonth = moment(creationDate).format('YYYY-MM')
|
||||
const index = getCreationIndex(creationDate.getMonth())
|
||||
|
||||
let openCreation
|
||||
switch (creationDateMonth) {
|
||||
case dateMonth:
|
||||
openCreation = creations[2]
|
||||
break
|
||||
case dateLastMonth:
|
||||
openCreation = creations[1]
|
||||
break
|
||||
case dateBeforeLastMonth:
|
||||
openCreation = creations[0]
|
||||
break
|
||||
default:
|
||||
throw new Error('CreationDate is not in last three months')
|
||||
if (index < 0) {
|
||||
throw new Error(`No Creation found!`)
|
||||
}
|
||||
|
||||
if (openCreation < amount) {
|
||||
throw new Error(`Open creation (${openCreation}) is less than amount (${amount})`)
|
||||
if (amount > creations[index]) {
|
||||
throw new Error(
|
||||
`The amount (${amount} GDD) to be created exceeds the available amount (${creations[index]} GDD) for this month.`,
|
||||
)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const getCreationMonths = (): number[] => {
|
||||
const now = new Date(Date.now())
|
||||
return [
|
||||
now.getMonth() + 1,
|
||||
new Date(now.getFullYear(), now.getMonth() - 1, 1).getMonth() + 1,
|
||||
new Date(now.getFullYear(), now.getMonth() - 2, 1).getMonth() + 1,
|
||||
].reverse()
|
||||
}
|
||||
|
||||
const getCreationIndex = (month: number): number => {
|
||||
return getCreationMonths().findIndex((el) => el === month + 1)
|
||||
}
|
||||
|
||||
@ -4092,11 +4092,6 @@ module-alias@^2.2.2:
|
||||
resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0"
|
||||
integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==
|
||||
|
||||
moment@^2.29.1:
|
||||
version "2.29.1"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
|
||||
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user