Add client bonus access flag
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "bonusProgramEnabled" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
@@ -60,6 +60,7 @@ model User {
|
||||
email String @unique
|
||||
fullName String
|
||||
role UserRole
|
||||
bonusProgramEnabled Boolean @default(false)
|
||||
companyId String?
|
||||
company Company? @relation(fields: [companyId], references: [id])
|
||||
counterpartyProfile CounterpartyProfile?
|
||||
|
||||
@@ -161,12 +161,14 @@ async function upsertClient(index) {
|
||||
update: {
|
||||
fullName: fullNameForIndex(index),
|
||||
role: 'CLIENT',
|
||||
bonusProgramEnabled: index % 2 === 1,
|
||||
companyId: company.id,
|
||||
},
|
||||
create: {
|
||||
email: buildClientEmail(index),
|
||||
fullName: fullNameForIndex(index),
|
||||
role: 'CLIENT',
|
||||
bonusProgramEnabled: index % 2 === 1,
|
||||
companyId: company.id,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -104,11 +104,16 @@ const manager = await prisma.user.upsert({
|
||||
|
||||
await prisma.user.upsert({
|
||||
where: { email: clientEmail },
|
||||
update: { fullName: 'Demo Client', companyId: company.id },
|
||||
update: {
|
||||
fullName: 'Demo Client',
|
||||
companyId: company.id,
|
||||
bonusProgramEnabled: true,
|
||||
},
|
||||
create: {
|
||||
email: clientEmail,
|
||||
fullName: 'Demo Client',
|
||||
role: 'CLIENT',
|
||||
bonusProgramEnabled: true,
|
||||
companyId: company.id,
|
||||
},
|
||||
});
|
||||
|
||||
177
src/resolvers.js
177
src/resolvers.js
@@ -148,10 +148,61 @@ function mapManagerReferralLink(link) {
|
||||
};
|
||||
}
|
||||
|
||||
const managerUserInclude = {
|
||||
messengerConnections: {
|
||||
where: {
|
||||
type: 'TELEGRAM',
|
||||
isActive: true,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 1,
|
||||
},
|
||||
counterpartyProfile: {
|
||||
select: {
|
||||
companyName: true,
|
||||
inn: true,
|
||||
},
|
||||
},
|
||||
clientOrders: {
|
||||
select: {
|
||||
createdAt: true,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 1,
|
||||
},
|
||||
_count: {
|
||||
select: {
|
||||
clientOrders: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function mapManagerUser(user) {
|
||||
return {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
fullName: user.fullName,
|
||||
role: user.role,
|
||||
bonusProgramEnabled: user.bonusProgramEnabled,
|
||||
companyName: user.counterpartyProfile?.companyName ?? null,
|
||||
inn: user.counterpartyProfile?.inn ?? null,
|
||||
createdAt: user.createdAt,
|
||||
orderCount: user._count.clientOrders,
|
||||
lastOrderAt: user.clientOrders[0]?.createdAt ?? null,
|
||||
telegramConnection: user.messengerConnections[0] ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
async function createReferralBonusTransaction(prisma, order) {
|
||||
const referralLink = await prisma.referralLink.findFirst({
|
||||
where: {
|
||||
refereeId: order.customerId,
|
||||
referrer: {
|
||||
bonusProgramEnabled: true,
|
||||
},
|
||||
referee: {
|
||||
bonusProgramEnabled: true,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
referrer: {
|
||||
@@ -1099,49 +1150,11 @@ export const resolvers = {
|
||||
const managedUsersWhere = await getManagedClientUserWhere(context.prisma, manager);
|
||||
const users = await context.prisma.user.findMany({
|
||||
where: managedUsersWhere,
|
||||
include: {
|
||||
messengerConnections: {
|
||||
where: {
|
||||
type: 'TELEGRAM',
|
||||
isActive: true,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 1,
|
||||
},
|
||||
counterpartyProfile: {
|
||||
select: {
|
||||
companyName: true,
|
||||
inn: true,
|
||||
},
|
||||
},
|
||||
clientOrders: {
|
||||
select: {
|
||||
createdAt: true,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 1,
|
||||
},
|
||||
_count: {
|
||||
select: {
|
||||
clientOrders: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
include: managerUserInclude,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
return users.map((user) => ({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
fullName: user.fullName,
|
||||
role: user.role,
|
||||
companyName: user.counterpartyProfile?.companyName ?? null,
|
||||
inn: user.counterpartyProfile?.inn ?? null,
|
||||
createdAt: user.createdAt,
|
||||
orderCount: user._count.clientOrders,
|
||||
lastOrderAt: user.clientOrders[0]?.createdAt ?? null,
|
||||
telegramConnection: user.messengerConnections[0] ?? null,
|
||||
}));
|
||||
return users.map(mapManagerUser);
|
||||
},
|
||||
|
||||
managerOrders: async (_, { status, customerId }, context) => {
|
||||
@@ -1197,7 +1210,11 @@ export const resolvers = {
|
||||
|
||||
const [users, transactionsAgg, pendingWithdrawalsAgg] = await Promise.all([
|
||||
context.prisma.user.findMany({
|
||||
where: managedUsersWhere,
|
||||
where: {
|
||||
...managedUsersWhere,
|
||||
role: 'CLIENT',
|
||||
bonusProgramEnabled: true,
|
||||
},
|
||||
include: {
|
||||
counterpartyProfile: {
|
||||
select: {
|
||||
@@ -1241,6 +1258,7 @@ export const resolvers = {
|
||||
email: user.email,
|
||||
fullName: user.fullName,
|
||||
companyName: user.counterpartyProfile?.companyName ?? null,
|
||||
bonusProgramEnabled: user.bonusProgramEnabled,
|
||||
balance: (tx?.balance ?? 0) - pendingWithdrawalAmount,
|
||||
pendingWithdrawalAmount,
|
||||
transactionsCount: tx?.transactionsCount ?? 0,
|
||||
@@ -1328,7 +1346,11 @@ export const resolvers = {
|
||||
const managedUsersWhere = await getManagedClientUserWhere(context.prisma, manager);
|
||||
|
||||
const users = await context.prisma.user.findMany({
|
||||
where: managedUsersWhere,
|
||||
where: {
|
||||
...managedUsersWhere,
|
||||
role: 'CLIENT',
|
||||
bonusProgramEnabled: true,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
@@ -2224,6 +2246,7 @@ export const resolvers = {
|
||||
select: {
|
||||
id: true,
|
||||
role: true,
|
||||
bonusProgramEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2235,6 +2258,10 @@ export const resolvers = {
|
||||
throw new Error('Referral links can only be created between client accounts.');
|
||||
}
|
||||
|
||||
if (users.some((user) => !user.bonusProgramEnabled)) {
|
||||
throw new Error('Bonus program must be enabled for both selected clients.');
|
||||
}
|
||||
|
||||
const existingRefereeLink = await context.prisma.referralLink.findFirst({
|
||||
where: {
|
||||
refereeId: refereeUserId,
|
||||
@@ -2259,10 +2286,56 @@ export const resolvers = {
|
||||
});
|
||||
},
|
||||
|
||||
setClientBonusProgramEnabled: async (_, { userId, enabled }, context) => {
|
||||
const manager = requireManagerAccess(context);
|
||||
await assertManagerCanAccessUser(context.prisma, manager, userId);
|
||||
|
||||
const existingUser = await context.prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
select: {
|
||||
role: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!existingUser) {
|
||||
throw new Error('User was not found.');
|
||||
}
|
||||
|
||||
if (existingUser.role !== 'CLIENT') {
|
||||
throw new Error('Bonus program can only be configured for client accounts.');
|
||||
}
|
||||
|
||||
const user = await context.prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
bonusProgramEnabled: enabled,
|
||||
},
|
||||
include: managerUserInclude,
|
||||
});
|
||||
|
||||
return mapManagerUser(user);
|
||||
},
|
||||
|
||||
createBonusProgramLink: async (_, { userId }, context) => {
|
||||
const manager = requireManagerAccess(context);
|
||||
await assertManagerCanAccessUser(context.prisma, manager, userId);
|
||||
|
||||
const user = await context.prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
select: {
|
||||
role: true,
|
||||
bonusProgramEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new Error('User was not found.');
|
||||
}
|
||||
|
||||
if (user.role !== 'CLIENT' || !user.bonusProgramEnabled) {
|
||||
throw new Error('Bonus program is not enabled for this client.');
|
||||
}
|
||||
|
||||
const issued = issueBonusProgramLinkToken({ userId });
|
||||
|
||||
return {
|
||||
@@ -2276,6 +2349,22 @@ export const resolvers = {
|
||||
addBonusTransaction: async (_, { input }, context) => {
|
||||
const manager = requireManagerAccess(context);
|
||||
await assertManagerCanAccessUser(context.prisma, manager, input.userId);
|
||||
const bonusUser = await context.prisma.user.findUnique({
|
||||
where: { id: input.userId },
|
||||
select: {
|
||||
role: true,
|
||||
bonusProgramEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!bonusUser) {
|
||||
throw new Error('User was not found.');
|
||||
}
|
||||
|
||||
if (bonusUser.role !== 'CLIENT' || !bonusUser.bonusProgramEnabled) {
|
||||
throw new Error('Bonus program is not enabled for this client.');
|
||||
}
|
||||
|
||||
const transaction = await context.prisma.bonusTransaction.create({
|
||||
data: {
|
||||
userId: input.userId,
|
||||
@@ -2319,6 +2408,10 @@ export const resolvers = {
|
||||
|
||||
requestRewardWithdrawal: (_, { input }, context) => {
|
||||
const client = requireUser(context);
|
||||
if (!client.bonusProgramEnabled) {
|
||||
throw new Error('Bonus program is not enabled for this client.');
|
||||
}
|
||||
|
||||
if (input.amount < 100) {
|
||||
throw new Error('Minimum withdrawal amount is 100.');
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ type User {
|
||||
email: String!
|
||||
fullName: String!
|
||||
role: UserRole!
|
||||
bonusProgramEnabled: Boolean!
|
||||
company: Company
|
||||
}
|
||||
|
||||
@@ -142,6 +143,7 @@ type ManagerUser {
|
||||
email: String!
|
||||
fullName: String!
|
||||
role: UserRole!
|
||||
bonusProgramEnabled: Boolean!
|
||||
companyName: String
|
||||
inn: String
|
||||
createdAt: DateTime!
|
||||
@@ -382,6 +384,7 @@ type ManagerBonusBalance {
|
||||
email: String!
|
||||
fullName: String!
|
||||
companyName: String
|
||||
bonusProgramEnabled: Boolean!
|
||||
balance: Float!
|
||||
pendingWithdrawalAmount: Float!
|
||||
transactionsCount: Int!
|
||||
@@ -607,6 +610,7 @@ type Mutation {
|
||||
clientReviewOrder(orderId: ID!, decision: Decision!): Order!
|
||||
|
||||
createReferral(input: CreateReferralInput!): ReferralLink!
|
||||
setClientBonusProgramEnabled(userId: ID!, enabled: Boolean!): ManagerUser!
|
||||
createBonusProgramLink(userId: ID!): BonusProgramLink!
|
||||
addBonusTransaction(input: AddBonusTransactionInput!): BonusTransaction!
|
||||
requestRewardWithdrawal(input: RequestRewardWithdrawalInput!): RewardWithdrawalRequest!
|
||||
|
||||
Reference in New Issue
Block a user