Add super manager role
This commit is contained in:
1
prisma/migrations/0007_super_manager/migration.sql
Normal file
1
prisma/migrations/0007_super_manager/migration.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TYPE "UserRole" ADD VALUE IF NOT EXISTS 'SUPER_MANAGER';
|
||||||
@@ -9,6 +9,7 @@ datasource db {
|
|||||||
enum UserRole {
|
enum UserRole {
|
||||||
CLIENT
|
CLIENT
|
||||||
MANAGER
|
MANAGER
|
||||||
|
SUPER_MANAGER
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RegistrationStatus {
|
enum RegistrationStatus {
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ const [, , emailArg, roleArg = 'MANAGER'] = process.argv;
|
|||||||
|
|
||||||
const email = String(emailArg || '').trim().toLowerCase();
|
const email = String(emailArg || '').trim().toLowerCase();
|
||||||
const role = String(roleArg || '').trim().toUpperCase();
|
const role = String(roleArg || '').trim().toUpperCase();
|
||||||
const allowedRoles = new Set(['CLIENT', 'MANAGER']);
|
const allowedRoles = new Set(['CLIENT', 'MANAGER', 'SUPER_MANAGER']);
|
||||||
|
|
||||||
if (!email) {
|
if (!email) {
|
||||||
throw new Error('Usage: node scripts/set-user-role.js <email> [CLIENT|MANAGER]');
|
throw new Error('Usage: node scripts/set-user-role.js <email> [CLIENT|MANAGER|SUPER_MANAGER]');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!allowedRoles.has(role)) {
|
if (!allowedRoles.has(role)) {
|
||||||
|
|||||||
278
src/resolvers.js
278
src/resolvers.js
@@ -14,6 +14,8 @@ import { dateTimeScalar, jsonScalar } from './scalars.js';
|
|||||||
import { fetchTelegramConnectionProfile } from './telegram.js';
|
import { fetchTelegramConnectionProfile } from './telegram.js';
|
||||||
|
|
||||||
const ACTIVE_ORDER_STATUSES = ['NEW', 'MANAGER_PROCESSING', 'WAITING_DOUBLE_CONFIRM', 'CONFIRMED', 'IN_PROGRESS'];
|
const ACTIVE_ORDER_STATUSES = ['NEW', 'MANAGER_PROCESSING', 'WAITING_DOUBLE_CONFIRM', 'CONFIRMED', 'IN_PROGRESS'];
|
||||||
|
const MANAGER_ROLES = ['MANAGER', 'SUPER_MANAGER'];
|
||||||
|
const NO_CLIENT_IDS = ['__no_managed_clients__'];
|
||||||
|
|
||||||
function toFloat(value) {
|
function toFloat(value) {
|
||||||
return value == null ? null : Number(value);
|
return value == null ? null : Number(value);
|
||||||
@@ -26,14 +28,131 @@ function requireUser(context) {
|
|||||||
return context.user;
|
return context.user;
|
||||||
}
|
}
|
||||||
|
|
||||||
function requireRole(context, role) {
|
function requireAnyRole(context, roles) {
|
||||||
const user = requireUser(context);
|
const user = requireUser(context);
|
||||||
if (user.role !== role) {
|
if (!roles.includes(user.role)) {
|
||||||
throw new Error(`Only ${role} can perform this operation.`);
|
throw new Error(`Only ${roles.join(', ')} can perform this operation.`);
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requireManagerAccess(context) {
|
||||||
|
return requireAnyRole(context, MANAGER_ROLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSuperManager(user) {
|
||||||
|
return user.role === 'SUPER_MANAGER';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isManagerRole(role) {
|
||||||
|
return MANAGER_ROLES.includes(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeManagedClientIds(clientIds) {
|
||||||
|
if (clientIds == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientIds.length ? clientIds : NO_CLIENT_IDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getManagedClientIds(prisma, manager) {
|
||||||
|
if (isSuperManager(manager)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [managedOrders, acceptedInvitations, reviewedRequests, reviewedWithdrawals] = await Promise.all([
|
||||||
|
prisma.order.findMany({
|
||||||
|
where: { managerId: manager.id },
|
||||||
|
select: { customerId: true },
|
||||||
|
}),
|
||||||
|
prisma.invitation.findMany({
|
||||||
|
where: {
|
||||||
|
managerId: manager.id,
|
||||||
|
acceptedById: { not: null },
|
||||||
|
},
|
||||||
|
select: { acceptedById: true },
|
||||||
|
}),
|
||||||
|
prisma.registrationRequest.findMany({
|
||||||
|
where: {
|
||||||
|
reviewedById: manager.id,
|
||||||
|
requesterId: { not: null },
|
||||||
|
},
|
||||||
|
select: { requesterId: true },
|
||||||
|
}),
|
||||||
|
prisma.rewardWithdrawalRequest.findMany({
|
||||||
|
where: { reviewedById: manager.id },
|
||||||
|
select: { requesterId: true },
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const clientIds = new Set();
|
||||||
|
|
||||||
|
for (const order of managedOrders) {
|
||||||
|
if (order.customerId) {
|
||||||
|
clientIds.add(order.customerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const invitation of acceptedInvitations) {
|
||||||
|
if (invitation.acceptedById) {
|
||||||
|
clientIds.add(invitation.acceptedById);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const request of reviewedRequests) {
|
||||||
|
if (request.requesterId) {
|
||||||
|
clientIds.add(request.requesterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const withdrawal of reviewedWithdrawals) {
|
||||||
|
if (withdrawal.requesterId) {
|
||||||
|
clientIds.add(withdrawal.requesterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...clientIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getManagedClientUserWhere(prisma, manager) {
|
||||||
|
const managedClientIds = normalizeManagedClientIds(await getManagedClientIds(prisma, manager));
|
||||||
|
|
||||||
|
if (managedClientIds == null) {
|
||||||
|
return { role: 'CLIENT' };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
role: 'CLIENT',
|
||||||
|
id: { in: managedClientIds },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function assertManagerCanAccessUser(prisma, manager, userId) {
|
||||||
|
if (isSuperManager(manager) || userId === manager.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const managedClientIds = await getManagedClientIds(prisma, manager);
|
||||||
|
if (!managedClientIds.includes(userId)) {
|
||||||
|
throw new Error('User is not available for this manager.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertManagerCanAccessOrder(order, manager) {
|
||||||
|
if (!order) {
|
||||||
|
throw new Error('Order was not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSuperManager(manager)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order.managerId && order.managerId !== manager.id) {
|
||||||
|
throw new Error('Order is assigned to another manager.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function appendOrderEvent(prisma, orderId, status, actorUserId, note = null) {
|
async function appendOrderEvent(prisma, orderId, status, actorUserId, note = null) {
|
||||||
return prisma.orderStatusEvent.create({
|
return prisma.orderStatusEvent.create({
|
||||||
data: {
|
data: {
|
||||||
@@ -425,7 +544,8 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
managerNotificationHistory: async (_, { userId, channel, limit }, context) => {
|
managerNotificationHistory: async (_, { userId, channel, limit }, context) => {
|
||||||
requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
|
await assertManagerCanAccessUser(context.prisma, manager, userId);
|
||||||
const normalizedLimit = Math.min(Math.max(limit ?? 50, 1), 200);
|
const normalizedLimit = Math.min(Math.max(limit ?? 50, 1), 200);
|
||||||
return collectNotificationHistory(context, userId, channel, normalizedLimit);
|
return collectNotificationHistory(context, userId, channel, normalizedLimit);
|
||||||
},
|
},
|
||||||
@@ -469,9 +589,10 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
managerUsers: async (_, __, context) => {
|
managerUsers: async (_, __, context) => {
|
||||||
requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
|
const managedUsersWhere = await getManagedClientUserWhere(context.prisma, manager);
|
||||||
const users = await context.prisma.user.findMany({
|
const users = await context.prisma.user.findMany({
|
||||||
where: { role: 'CLIENT' },
|
where: managedUsersWhere,
|
||||||
include: {
|
include: {
|
||||||
counterpartyProfile: {
|
counterpartyProfile: {
|
||||||
select: {
|
select: {
|
||||||
@@ -509,10 +630,10 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
managerOrders: (_, { status }, context) => {
|
managerOrders: (_, { status }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
return context.prisma.order.findMany({
|
return context.prisma.order.findMany({
|
||||||
where: {
|
where: {
|
||||||
managerId: manager.id,
|
...(isSuperManager(manager) ? {} : { managerId: manager.id }),
|
||||||
...(status ? { status } : {}),
|
...(status ? { status } : {}),
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
@@ -524,11 +645,12 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
managerBonusBalances: async (_, __, context) => {
|
managerBonusBalances: async (_, __, context) => {
|
||||||
requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
|
const managedUsersWhere = await getManagedClientUserWhere(context.prisma, manager);
|
||||||
|
|
||||||
const [users, transactionsAgg, pendingWithdrawalsAgg] = await Promise.all([
|
const [users, transactionsAgg, pendingWithdrawalsAgg] = await Promise.all([
|
||||||
context.prisma.user.findMany({
|
context.prisma.user.findMany({
|
||||||
where: { role: 'CLIENT' },
|
where: managedUsersWhere,
|
||||||
include: {
|
include: {
|
||||||
counterpartyProfile: {
|
counterpartyProfile: {
|
||||||
select: {
|
select: {
|
||||||
@@ -579,10 +701,71 @@ export const resolvers = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
managerWithdrawalRequests: async (_, { status }, context) => {
|
||||||
|
const manager = requireManagerAccess(context);
|
||||||
|
const managedUsersWhere = await getManagedClientUserWhere(context.prisma, manager);
|
||||||
|
|
||||||
|
const users = await context.prisma.user.findMany({
|
||||||
|
where: managedUsersWhere,
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
fullName: true,
|
||||||
|
counterpartyProfile: {
|
||||||
|
select: {
|
||||||
|
companyName: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!users.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const userMap = new Map(users.map((user) => [user.id, user]));
|
||||||
|
|
||||||
|
const withdrawals = await context.prisma.rewardWithdrawalRequest.findMany({
|
||||||
|
where: {
|
||||||
|
requesterId: { in: [...userMap.keys()] },
|
||||||
|
...(status ? { status } : {}),
|
||||||
|
},
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
});
|
||||||
|
|
||||||
|
return withdrawals.map((withdrawal) => {
|
||||||
|
const requester = userMap.get(withdrawal.requesterId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: withdrawal.id,
|
||||||
|
requesterId: withdrawal.requesterId,
|
||||||
|
requesterEmail: requester?.email ?? 'unknown@fregat.local',
|
||||||
|
requesterFullName: requester?.fullName ?? 'Неизвестный пользователь',
|
||||||
|
companyName: requester?.counterpartyProfile?.companyName ?? null,
|
||||||
|
amount: Number(withdrawal.amount),
|
||||||
|
status: withdrawal.status,
|
||||||
|
reviewedById: withdrawal.reviewedById,
|
||||||
|
reviewComment: withdrawal.reviewComment,
|
||||||
|
createdAt: withdrawal.createdAt,
|
||||||
|
updatedAt: withdrawal.updatedAt,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
registrationRequests: (_, { status }, context) => {
|
registrationRequests: (_, { status }, context) => {
|
||||||
requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
return context.prisma.registrationRequest.findMany({
|
return context.prisma.registrationRequest.findMany({
|
||||||
where: status ? { status } : undefined,
|
where: {
|
||||||
|
...(status ? { status } : {}),
|
||||||
|
...(isSuperManager(manager)
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
|
OR: [
|
||||||
|
{ reviewedById: manager.id },
|
||||||
|
{ reviewedById: null },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
},
|
||||||
orderBy: { createdAt: 'desc' },
|
orderBy: { createdAt: 'desc' },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -763,7 +946,19 @@ export const resolvers = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
reviewRegistrationRequest: async (_, { input }, context) => {
|
reviewRegistrationRequest: async (_, { input }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
|
const request = await context.prisma.registrationRequest.findUnique({
|
||||||
|
where: { id: input.requestId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!request) {
|
||||||
|
throw new Error('Registration request was not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSuperManager(manager) && request.reviewedById && request.reviewedById !== manager.id) {
|
||||||
|
throw new Error('Registration request is assigned to another manager.');
|
||||||
|
}
|
||||||
|
|
||||||
return context.prisma.registrationRequest.update({
|
return context.prisma.registrationRequest.update({
|
||||||
where: { id: input.requestId },
|
where: { id: input.requestId },
|
||||||
data: {
|
data: {
|
||||||
@@ -775,7 +970,7 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
createInvitation: async (_, { input }, context) => {
|
createInvitation: async (_, { input }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
const expiresInDays = input.expiresInDays > 0 ? input.expiresInDays : 7;
|
const expiresInDays = input.expiresInDays > 0 ? input.expiresInDays : 7;
|
||||||
const expiresAt = new Date(Date.now() + expiresInDays * 24 * 60 * 60 * 1000);
|
const expiresAt = new Date(Date.now() + expiresInDays * 24 * 60 * 60 * 1000);
|
||||||
|
|
||||||
@@ -1199,7 +1394,7 @@ export const resolvers = {
|
|||||||
code: orderCode(),
|
code: orderCode(),
|
||||||
kind: 'READY',
|
kind: 'READY',
|
||||||
customerId: customer.id,
|
customerId: customer.id,
|
||||||
managerId: customer.role === 'MANAGER' ? customer.id : null,
|
managerId: isManagerRole(customer.role) ? customer.id : null,
|
||||||
deliveryAddressId: selectedAddress.id,
|
deliveryAddressId: selectedAddress.id,
|
||||||
deliveryAddress: presentDeliveryAddress(selectedAddress),
|
deliveryAddress: presentDeliveryAddress(selectedAddress),
|
||||||
status: 'NEW',
|
status: 'NEW',
|
||||||
@@ -1237,7 +1432,7 @@ export const resolvers = {
|
|||||||
code: orderCode(),
|
code: orderCode(),
|
||||||
kind: 'CALCULATION',
|
kind: 'CALCULATION',
|
||||||
customerId: customer.id,
|
customerId: customer.id,
|
||||||
managerId: customer.role === 'MANAGER' ? customer.id : null,
|
managerId: isManagerRole(customer.role) ? customer.id : null,
|
||||||
deliveryAddressId: selectedAddress.id,
|
deliveryAddressId: selectedAddress.id,
|
||||||
deliveryAddress: presentDeliveryAddress(selectedAddress),
|
deliveryAddress: presentDeliveryAddress(selectedAddress),
|
||||||
status: 'NEW',
|
status: 'NEW',
|
||||||
@@ -1267,7 +1462,12 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
managerSetOrderOffer: async (_, { input }, context) => {
|
managerSetOrderOffer: async (_, { input }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
|
const existingOrder = await context.prisma.order.findUnique({
|
||||||
|
where: { id: input.orderId },
|
||||||
|
});
|
||||||
|
assertManagerCanAccessOrder(existingOrder, manager);
|
||||||
|
|
||||||
const order = await context.prisma.order.update({
|
const order = await context.prisma.order.update({
|
||||||
where: { id: input.orderId },
|
where: { id: input.orderId },
|
||||||
data: {
|
data: {
|
||||||
@@ -1289,7 +1489,7 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
clientReviewOrder: async (_, { orderId, decision }, context) => {
|
clientReviewOrder: async (_, { orderId, decision }, context) => {
|
||||||
const customer = requireRole(context, 'CLIENT');
|
const customer = requireUser(context);
|
||||||
const order = await context.prisma.order.findUnique({ where: { id: orderId } });
|
const order = await context.prisma.order.findUnique({ where: { id: orderId } });
|
||||||
|
|
||||||
if (!order || order.customerId !== customer.id) {
|
if (!order || order.customerId !== customer.id) {
|
||||||
@@ -1331,11 +1531,9 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
managerFinalizeOrder: async (_, { orderId, decision }, context) => {
|
managerFinalizeOrder: async (_, { orderId, decision }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
const order = await context.prisma.order.findUnique({ where: { id: orderId } });
|
const order = await context.prisma.order.findUnique({ where: { id: orderId } });
|
||||||
if (!order) {
|
assertManagerCanAccessOrder(order, manager);
|
||||||
throw new Error('Order was not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const status = decision === 'REJECT'
|
const status = decision === 'REJECT'
|
||||||
? 'MANAGER_REJECTED'
|
? 'MANAGER_REJECTED'
|
||||||
@@ -1373,7 +1571,12 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
blockOrder: async (_, { input }, context) => {
|
blockOrder: async (_, { input }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
|
const order = await context.prisma.order.findUnique({
|
||||||
|
where: { id: input.orderId },
|
||||||
|
});
|
||||||
|
assertManagerCanAccessOrder(order, manager);
|
||||||
|
|
||||||
const updated = await context.prisma.order.update({
|
const updated = await context.prisma.order.update({
|
||||||
where: { id: input.orderId },
|
where: { id: input.orderId },
|
||||||
data: {
|
data: {
|
||||||
@@ -1393,9 +1596,10 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
startOrderWork: async (_, { orderId }, context) => {
|
startOrderWork: async (_, { orderId }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
const order = await context.prisma.order.findUnique({ where: { id: orderId } });
|
const order = await context.prisma.order.findUnique({ where: { id: orderId } });
|
||||||
if (!order || order.status !== 'CONFIRMED') {
|
assertManagerCanAccessOrder(order, manager);
|
||||||
|
if (order.status !== 'CONFIRMED') {
|
||||||
throw new Error('Only confirmed order can be started.');
|
throw new Error('Only confirmed order can be started.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1417,9 +1621,10 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
completeOrder: async (_, { orderId }, context) => {
|
completeOrder: async (_, { orderId }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
const order = await context.prisma.order.findUnique({ where: { id: orderId } });
|
const order = await context.prisma.order.findUnique({ where: { id: orderId } });
|
||||||
if (!order || order.status !== 'IN_PROGRESS') {
|
assertManagerCanAccessOrder(order, manager);
|
||||||
|
if (order.status !== 'IN_PROGRESS') {
|
||||||
throw new Error('Only in-progress order can be completed.');
|
throw new Error('Only in-progress order can be completed.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1441,7 +1646,7 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
createReferral: (_, { input }, context) => {
|
createReferral: (_, { input }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
return context.prisma.referralLink.create({
|
return context.prisma.referralLink.create({
|
||||||
data: {
|
data: {
|
||||||
referrerId: manager.id,
|
referrerId: manager.id,
|
||||||
@@ -1451,7 +1656,8 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
addBonusTransaction: async (_, { input }, context) => {
|
addBonusTransaction: async (_, { input }, context) => {
|
||||||
requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
|
await assertManagerCanAccessUser(context.prisma, manager, input.userId);
|
||||||
const transaction = await context.prisma.bonusTransaction.create({
|
const transaction = await context.prisma.bonusTransaction.create({
|
||||||
data: {
|
data: {
|
||||||
userId: input.userId,
|
userId: input.userId,
|
||||||
@@ -1471,7 +1677,7 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
requestRewardWithdrawal: (_, { input }, context) => {
|
requestRewardWithdrawal: (_, { input }, context) => {
|
||||||
const client = requireRole(context, 'CLIENT');
|
const client = requireUser(context);
|
||||||
if (input.amount < 100) {
|
if (input.amount < 100) {
|
||||||
throw new Error('Minimum withdrawal amount is 100.');
|
throw new Error('Minimum withdrawal amount is 100.');
|
||||||
}
|
}
|
||||||
@@ -1485,7 +1691,17 @@ export const resolvers = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
reviewRewardWithdrawal: async (_, { input }, context) => {
|
reviewRewardWithdrawal: async (_, { input }, context) => {
|
||||||
const manager = requireRole(context, 'MANAGER');
|
const manager = requireManagerAccess(context);
|
||||||
|
const existingWithdrawal = await context.prisma.rewardWithdrawalRequest.findUnique({
|
||||||
|
where: { id: input.withdrawalId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existingWithdrawal) {
|
||||||
|
throw new Error('Withdrawal request was not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
await assertManagerCanAccessUser(context.prisma, manager, existingWithdrawal.requesterId);
|
||||||
|
|
||||||
const withdrawal = await context.prisma.rewardWithdrawalRequest.update({
|
const withdrawal = await context.prisma.rewardWithdrawalRequest.update({
|
||||||
where: { id: input.withdrawalId },
|
where: { id: input.withdrawalId },
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ scalar JSON
|
|||||||
enum UserRole {
|
enum UserRole {
|
||||||
CLIENT
|
CLIENT
|
||||||
MANAGER
|
MANAGER
|
||||||
|
SUPER_MANAGER
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MessengerType {
|
enum MessengerType {
|
||||||
@@ -306,6 +307,20 @@ type ManagerBonusBalance {
|
|||||||
transactionsCount: Int!
|
transactionsCount: Int!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ManagerWithdrawalRequest {
|
||||||
|
id: ID!
|
||||||
|
requesterId: ID!
|
||||||
|
requesterEmail: String!
|
||||||
|
requesterFullName: String!
|
||||||
|
companyName: String
|
||||||
|
amount: Float!
|
||||||
|
status: WithdrawalStatus!
|
||||||
|
reviewedById: ID
|
||||||
|
reviewComment: String
|
||||||
|
createdAt: DateTime!
|
||||||
|
updatedAt: DateTime!
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
healthcheck: String!
|
healthcheck: String!
|
||||||
me: User
|
me: User
|
||||||
@@ -321,6 +336,7 @@ type Query {
|
|||||||
managerUsers: [ManagerUser!]!
|
managerUsers: [ManagerUser!]!
|
||||||
managerOrders(status: OrderStatus): [Order!]!
|
managerOrders(status: OrderStatus): [Order!]!
|
||||||
managerBonusBalances: [ManagerBonusBalance!]!
|
managerBonusBalances: [ManagerBonusBalance!]!
|
||||||
|
managerWithdrawalRequests(status: WithdrawalStatus): [ManagerWithdrawalRequest!]!
|
||||||
registrationRequests(status: RegistrationStatus): [RegistrationRequest!]!
|
registrationRequests(status: RegistrationStatus): [RegistrationRequest!]!
|
||||||
referralStats: ReferralStats!
|
referralStats: ReferralStats!
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user