Merge pull request #2212 from gradido/2198-adminarea-more-dates-on-created-transaction

2198 adminarea more dates on created transaction
This commit is contained in:
Alexander Friedland 2022-09-29 15:09:22 +02:00 committed by GitHub
commit d7dfa22134
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 177 additions and 132 deletions

View File

@ -20,7 +20,7 @@ describe('ContributionMessagesListItem', () => {
const propsData = {
contributionId: 42,
state: 'PENDING0',
state: 'PENDING',
message: {
id: 111,
message: 'asd asda sda sda',

View File

@ -6,30 +6,29 @@ const localVue = global.localVue
const apolloQueryMock = jest.fn().mockResolvedValue({
data: {
creationTransactionList: [
{
id: 1,
amount: 100,
balanceDate: 0,
creationDate: new Date(),
memo: 'Testing',
linkedUser: {
firstName: 'Gradido',
lastName: 'Akademie',
creationTransactionList: {
contributionCount: 2,
contributionList: [
{
id: 1,
amount: 5.8,
createdAt: '2022-09-21T11:09:51.000Z',
confirmedAt: null,
contributionDate: '2022-08-01T00:00:00.000Z',
memo: 'für deine Hilfe, Fräulein Rottenmeier',
state: 'PENDING',
},
},
{
id: 2,
amount: 200,
balanceDate: 0,
creationDate: new Date(),
memo: 'Testing 2',
linkedUser: {
firstName: 'Gradido',
lastName: 'Akademie',
{
id: 2,
amount: '47',
createdAt: '2022-09-21T11:09:28.000Z',
confirmedAt: '2022-09-21T11:09:28.000Z',
contributionDate: '2022-08-01T00:00:00.000Z',
memo: 'für deine Hilfe, Frau Holle',
state: 'CONFIRMED',
},
},
],
],
},
},
})
@ -43,7 +42,7 @@ const mocks = {
const propsData = {
userId: 1,
fields: ['date', 'balance', 'name', 'memo', 'decay'],
fields: ['createdAt', 'contributionDate', 'confirmedAt', 'amount', 'memo'],
}
describe('CreationTransactionList', () => {
@ -63,7 +62,7 @@ describe('CreationTransactionList', () => {
expect.objectContaining({
variables: {
currentPage: 1,
pageSize: 25,
pageSize: 10,
order: 'DESC',
userId: 1,
},

View File

@ -1,7 +1,44 @@
<template>
<div class="component-creation-transaction-list">
<div class="h3">{{ $t('transactionlist.title') }}</div>
<b-table striped hover :fields="fields" :items="items"></b-table>
<b-table striped hover :fields="fields" :items="items">
<template #cell(contributionDate)="data">
<div class="font-weight-bold">
{{ $d(new Date(data.item.contributionDate), 'month') }}
</div>
<div>{{ $d(new Date(data.item.contributionDate)) }}</div>
</template>
</b-table>
<div>
<b-pagination
pills
size="lg"
v-model="currentPage"
:per-page="perPage"
:total-rows="rows"
align="center"
:hide-ellipsis="true"
></b-pagination>
<b-button v-b-toggle.collapse-1 variant="light" size="sm">{{ $t('help.help') }}</b-button>
<b-collapse id="collapse-1" class="mt-2">
<div>
{{ $t('transactionlist.submitted') }} {{ $t('math.equals') }}
{{ $t('help.transactionlist.submitted') }}
</div>
<div>
{{ $t('transactionlist.period') }} {{ $t('math.equals') }}
{{ $t('help.transactionlist.periods') }}
</div>
<div>
{{ $t('transactionlist.confirmed') }} {{ $t('math.equals') }}
{{ $t('help.transactionlist.confirmed') }}
</div>
<div>
{{ $t('transactionlist.state') }} {{ $t('math.equals') }}
{{ $t('help.transactionlist.state') }}
</div>
</b-collapse>
</div>
</div>
</template>
<script>
@ -13,14 +50,37 @@ export default {
},
data() {
return {
items: [],
rows: 0,
currentPage: 1,
perPage: 10,
fields: [
{
key: 'creationDate',
label: this.$t('transactionlist.date'),
key: 'createdAt',
label: this.$t('transactionlist.submitted'),
formatter: (value, key, item) => {
return this.$d(new Date(value))
},
},
{
key: 'contributionDate',
label: this.$t('transactionlist.period'),
},
{
key: 'confirmedAt',
label: this.$t('transactionlist.confirmed'),
formatter: (value, key, item) => {
if (value) {
return this.$d(new Date(value))
} else {
return null
}
},
},
{
key: 'state',
label: this.$t('transactionlist.state'),
},
{
key: 'amount',
label: this.$t('transactionlist.amount'),
@ -28,23 +88,8 @@ export default {
return `${value} GDD`
},
},
{
key: 'linkedUser',
label: this.$t('transactionlist.community'),
formatter: (value, key, item) => {
return `${value.firstName} ${value.lastName}`
},
},
{ key: 'memo', label: this.$t('transactionlist.memo') },
{
key: 'balanceDate',
label: this.$t('transactionlist.balanceDate'),
formatter: (value, key, item) => {
return this.$d(new Date(value))
},
},
],
items: [],
}
},
methods: {
@ -53,14 +98,15 @@ export default {
.query({
query: creationTransactionList,
variables: {
currentPage: 1,
pageSize: 25,
currentPage: this.currentPage,
pageSize: this.perPage,
order: 'DESC',
userId: parseInt(this.userId),
},
})
.then((result) => {
this.items = result.data.creationTransactionList
this.rows = result.data.creationTransactionList.contributionCount
this.items = result.data.creationTransactionList.contributionList
})
.catch((error) => {
this.toastError(error.message)
@ -70,5 +116,10 @@ export default {
created() {
this.getTransactions()
},
watch: {
currentPage() {
this.getTransactions()
},
},
}
</script>

View File

@ -8,14 +8,15 @@ export const creationTransactionList = gql`
order: $order
userId: $userId
) {
id
amount
balanceDate
creationDate
memo
linkedUser {
firstName
lastName
contributionCount
contributionList {
id
amount
createdAt
confirmedAt
contributionDate
memo
state
}
}
}

View File

@ -75,10 +75,20 @@
"submit": "Senden"
},
"GDD": "GDD",
"help": {
"help": "Hilfe",
"transactionlist": {
"confirmed": "Wann wurde es von einem Moderator / Admin bestätigt.",
"periods": "Für welchen Zeitraum wurde vom Mitglied eingereicht.",
"state": "[PENDING = eingereicht, DELETED = gelöscht, IN_PROGRESS = im Dialog mit Moderator, DENIED = abgelehnt, CONFIRMED = bestätigt]",
"submitted": "Wann wurde es vom Mitglied eingereicht"
}
},
"hide_details": "Details verbergen",
"lastname": "Nachname",
"math": {
"colon": ":",
"equals": "=",
"exclaim": "!",
"pipe": "|",
"plus": "+"
@ -134,10 +144,11 @@
},
"transactionlist": {
"amount": "Betrag",
"balanceDate": "Schöpfungsdatum",
"community": "Gemeinschaft",
"date": "Datum",
"confirmed": "Bestätigt",
"memo": "Nachricht",
"period": "Zeitraum",
"state": "Status",
"submitted": "Eingereicht",
"title": "Alle geschöpften Transaktionen für den Nutzer"
},
"undelete_user": "Nutzer wiederherstellen",

View File

@ -75,10 +75,20 @@
"submit": "Send"
},
"GDD": "GDD",
"help": {
"help": "Help",
"transactionlist": {
"confirmed": "When was it confirmed by a moderator / admin.",
"periods": "For what period was it submitted by the member.",
"state": "[PENDING = submitted, DELETED = deleted, IN_PROGRESS = in dialogue with moderator, DENIED = denied, CONFIRMED = confirmed]",
"submitted": "When was it submitted by the member"
}
},
"hide_details": "Hide details",
"lastname": "Lastname",
"math": {
"colon": ":",
"equals": "=",
"exclaim": "!",
"pipe": "|",
"plus": "+"
@ -134,10 +144,11 @@
},
"transactionlist": {
"amount": "Amount",
"balanceDate": "Creation date",
"community": "Community",
"date": "Date",
"confirmed": "Confirmed",
"memo": "Message",
"period": "Period",
"state": "State",
"submitted": "Submitted",
"title": "All creation-transactions for the user"
},
"undelete_user": "Undelete User",

View File

@ -5,7 +5,7 @@ import { User } from '@entity/User'
@ObjectType()
export class Contribution {
constructor(contribution: dbContribution, user: User) {
constructor(contribution: dbContribution, user?: User | null) {
this.id = contribution.id
this.firstName = user ? user.firstName : null
this.lastName = user ? user.lastName : null

View File

@ -15,6 +15,7 @@ import { AdminCreateContributions } from '@model/AdminCreateContributions'
import { AdminUpdateContribution } from '@model/AdminUpdateContribution'
import { ContributionLink } from '@model/ContributionLink'
import { ContributionLinkList } from '@model/ContributionLinkList'
import { Contribution } from '@model/Contribution'
import { RIGHTS } from '@/auth/RIGHTS'
import { UserRepository } from '@repository/User'
import AdminCreateContributionArgs from '@arg/AdminCreateContributionArgs'
@ -23,12 +24,10 @@ import SearchUsersArgs from '@arg/SearchUsersArgs'
import ContributionLinkArgs from '@arg/ContributionLinkArgs'
import { Transaction as DbTransaction } from '@entity/Transaction'
import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
import { Transaction } from '@model/Transaction'
import { TransactionLink, TransactionLinkResult } from '@model/TransactionLink'
import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
import { TransactionRepository } from '@repository/Transaction'
import { calculateDecay } from '@/util/decay'
import { Contribution } from '@entity/Contribution'
import { Contribution as DbContribution } from '@entity/Contribution'
import { hasElopageBuys } from '@/util/hasElopageBuys'
import { User as dbUser } from '@entity/User'
import { User } from '@model/User'
@ -40,7 +39,6 @@ import { Decay } from '@model/Decay'
import Paginated from '@arg/Paginated'
import TransactionLinkFilters from '@arg/TransactionLinkFilters'
import { Order } from '@enum/Order'
import { communityUser } from '@/util/communityUser'
import { findUserByEmail, activationLink, printTimeDuration } from './UserResolver'
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver'
@ -66,6 +64,7 @@ import { ContributionMessageType } from '@enum/MessageType'
import { ContributionMessage } from '@model/ContributionMessage'
import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail'
import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail'
import { ContributionListResult } from '../model/Contribution'
// const EMAIL_OPT_IN_REGISTER = 1
// const EMAIL_OPT_UNKNOWN = 3 // elopage?
@ -248,7 +247,7 @@ export class AdminResolver {
const creationDateObj = new Date(creationDate)
logger.trace('creationDateObj:', creationDateObj)
validateContribution(creations, amount, creationDateObj)
const contribution = Contribution.create()
const contribution = DbContribution.create()
contribution.userId = emailContact.userId
contribution.amount = amount
contribution.createdAt = new Date()
@ -259,7 +258,7 @@ export class AdminResolver {
contribution.contributionStatus = ContributionStatus.PENDING
logger.trace('contribution to save', contribution)
await Contribution.save(contribution)
await DbContribution.save(contribution)
return getUserCreation(emailContact.userId)
}
@ -317,7 +316,7 @@ export class AdminResolver {
const moderator = getUser(context)
const contributionToUpdate = await Contribution.findOne({
const contributionToUpdate = await DbContribution.findOne({
where: { id, confirmedAt: IsNull() },
})
@ -350,7 +349,7 @@ export class AdminResolver {
contributionToUpdate.moderatorId = moderator.id
contributionToUpdate.contributionStatus = ContributionStatus.PENDING
await Contribution.save(contributionToUpdate)
await DbContribution.save(contributionToUpdate)
const result = new AdminUpdateContribution()
result.amount = amount
result.memo = contributionToUpdate.memo
@ -367,7 +366,7 @@ export class AdminResolver {
const contributions = await getConnection()
.createQueryBuilder()
.select('c')
.from(Contribution, 'c')
.from(DbContribution, 'c')
.leftJoinAndSelect('c.messages', 'm')
.where({ confirmedAt: IsNull() })
.getMany()
@ -399,7 +398,7 @@ export class AdminResolver {
@Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION])
@Mutation(() => Boolean)
async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise<boolean> {
const contribution = await Contribution.findOne(id)
const contribution = await DbContribution.findOne(id)
if (!contribution) {
logger.error(`Contribution not found for given id: ${id}`)
throw new Error('Contribution not found for given id.')
@ -416,7 +415,7 @@ export class AdminResolver {
@Arg('id', () => Int) id: number,
@Ctx() context: Context,
): Promise<boolean> {
const contribution = await Contribution.findOne(id)
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.')
@ -481,7 +480,7 @@ export class AdminResolver {
contribution.confirmedBy = moderatorUser.id
contribution.transactionId = transaction.id
contribution.contributionStatus = ContributionStatus.CONFIRMED
await queryRunner.manager.update(Contribution, { id: contribution.id }, contribution)
await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution)
await queryRunner.commitTransaction()
logger.info('creation commited successfuly.')
@ -506,24 +505,29 @@ export class AdminResolver {
}
@Authorized([RIGHTS.CREATION_TRANSACTION_LIST])
@Query(() => [Transaction])
@Query(() => ContributionListResult)
async creationTransactionList(
@Args()
{ currentPage = 1, pageSize = 25, order = Order.DESC }: Paginated,
@Arg('userId', () => Int) userId: number,
): Promise<Transaction[]> {
): Promise<ContributionListResult> {
const offset = (currentPage - 1) * pageSize
const transactionRepository = getCustomRepository(TransactionRepository)
const [userTransactions] = await transactionRepository.findByUserPaged(
userId,
pageSize,
offset,
order,
true,
)
const [contributionResult, count] = await getConnection()
.createQueryBuilder()
.select('c')
.from(DbContribution, 'c')
.leftJoinAndSelect('c.user', 'u')
.where(`user_id = ${userId}`)
.limit(pageSize)
.offset(offset)
.orderBy('c.created_at', order)
.getManyAndCount()
const user = await dbUser.findOneOrFail({ id: userId })
return userTransactions.map((t) => new Transaction(t, new User(user), communityUser))
return new ContributionListResult(
count,
contributionResult.map((contribution) => new Contribution(contribution, contribution.user)),
)
// return userTransactions.map((t) => new Transaction(t, new User(user), communityUser))
}
@Authorized([RIGHTS.SEND_ACTIVATION_EMAIL])
@ -744,7 +748,7 @@ export class AdminResolver {
await queryRunner.startTransaction('REPEATABLE READ')
const contributionMessage = DbContributionMessage.create()
try {
const contribution = await Contribution.findOne({
const contribution = await DbContribution.findOne({
where: { id: contributionId },
relations: ['user'],
})
@ -773,7 +777,7 @@ export class AdminResolver {
contribution.contributionStatus === ContributionStatus.PENDING
) {
contribution.contributionStatus = ContributionStatus.IN_PROGRESS
await queryRunner.manager.update(Contribution, { id: contributionId }, contribution)
await queryRunner.manager.update(DbContribution, { id: contributionId }, contribution)
}
await sendAddedContributionMessageEmail({

View File

@ -14,8 +14,8 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
\`type\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
\`user_id\` int(10) unsigned NOT NULL,
\`email\` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL UNIQUE,
\`email_verification_code\` bigint(20) unsigned NOT NULL UNIQUE,
\`email_opt_in_type_id\` int NOT NULL,
\`email_verification_code\` bigint(20) unsigned DEFAULT NULL UNIQUE,
\`email_opt_in_type_id\` int DEFAULT NULL,
\`email_resend_count\` int DEFAULT '0',
\`email_checked\` tinyint(4) NOT NULL DEFAULT 0,
\`phone\` varchar(255) COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
@ -41,47 +41,13 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
// merge values from login_email_opt_in table with users.email in new user_contacts table
await queryFn(`
INSERT INTO user_contacts
(type, user_id, email, email_verification_code, email_opt_in_type_id, email_resend_count, email_checked, created_at, updated_at, deleted_at)
SELECT
'EMAIL',
u.id as user_id,
u.email,
e.verification_code as email_verification_code,
e.email_opt_in_type_id,
e.resend_count as email_resend_count,
u.email_checked,
e.created as created_at,
e.updated as updated_at,
u.deletedAt as deleted_at\
FROM
users as u,
login_email_opt_in as e
WHERE
u.id = e.user_id AND
e.id in (
WITH opt_in AS (
SELECT
le.id, le.user_id, le.created, le.updated, ROW_NUMBER() OVER (PARTITION BY le.user_id ORDER BY le.created DESC) AS row_num
FROM
login_email_opt_in as le
)
SELECT
opt_in.id
FROM
opt_in
WHERE
row_num = 1);`)
/*
// SELECT
// le.id
// FROM
// login_email_opt_in as le
// WHERE
// le.user_id = u.id
// ORDER BY
// le.updated DESC, le.created DESC LIMIT 1);`)
*/
INSERT INTO user_contacts
(type, user_id, email, email_verification_code, email_opt_in_type_id, email_resend_count, email_checked, created_at, updated_at, deleted_at)
SELECT 'EMAIL', users.id, users.email, optin.verification_code, optin.email_opt_in_type_id, optin.resend_count, users.email_checked, users.created, null, users.deletedAt
FROM users LEFT JOIN
(SELECT le.id, le.user_id, le.verification_code, le.email_opt_in_type_id, le.resend_count, le.created, le.updated,
ROW_NUMBER() OVER (PARTITION BY le.user_id ORDER BY le.created DESC) AS row_num
FROM login_email_opt_in as le) AS optin ON users.id = optin.user_id AND row_num = 1;`)
// insert in users table the email_id of the new created email-contacts
const contacts = await queryFn(`SELECT c.id, c.user_id FROM user_contacts as c`)
@ -113,11 +79,13 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom
)
// reconstruct the previous email back from contacts to users table
const contacts = await queryFn(`SELECT c.id, c.email, c.user_id FROM user_contacts as c`)
const contacts = await queryFn(
`SELECT c.id, c.email, c.user_id, c.email_checked FROM user_contacts as c`,
)
for (const id in contacts) {
const contact = contacts[id]
await queryFn(
`UPDATE users SET email = "${contact.email}" WHERE id = "${contact.user_id}" and email_id = "${contact.id}"`,
`UPDATE users SET email = "${contact.email}", email_checked="${contact.email_checked}" WHERE id = "${contact.user_id}" and email_id = "${contact.id}"`,
)
}
await queryFn('ALTER TABLE users MODIFY COLUMN email varchar(255) NOT NULL UNIQUE;')