235 lines
6.6 KiB
TypeScript
235 lines
6.6 KiB
TypeScript
// src/modules/host/services/host.service.ts
|
|
import { Injectable } from '@nestjs/common';
|
|
import { PrismaService } from '../../../common/database/prisma.service';
|
|
import { AddPaymentDetailsDTO, CreateHostDto, UpdateHostDto } from '../dto/host.dto';
|
|
import * as bcrypt from 'bcryptjs';
|
|
import ApiError from '../../../common/utils/helper/ApiError';
|
|
import { User } from '@prisma/client';
|
|
import { z } from 'zod';
|
|
import { hostCompanyDetailsSchema } from '@/common/utils/validation/host/hostCompanyDetails.validation';
|
|
|
|
type HostCompanyDetailsInput = z.infer<typeof hostCompanyDetailsSchema>;
|
|
|
|
// Document input after S3 upload (with S3 URL as filePath)
|
|
interface HostDocumentInput {
|
|
documentTypeXid: number;
|
|
documentName: string;
|
|
filePath: string; // S3 URL
|
|
}
|
|
|
|
@Injectable()
|
|
export class HostService {
|
|
constructor(private prisma: PrismaService) { }
|
|
|
|
async createHost(data: CreateHostDto) {
|
|
return this.prisma.user.create({ data });
|
|
}
|
|
|
|
async getAllHosts() {
|
|
return this.prisma.user.findMany({ where: { roleXid: 3 } });
|
|
}
|
|
|
|
async getHostById(id: number) {
|
|
const host = await this.prisma.user.findUnique({ where: { id } });
|
|
if (!host || host.roleXid !== 4) {
|
|
throw new ApiError(404, 'Host not found');
|
|
}
|
|
return host;
|
|
}
|
|
|
|
async updateHost(id: number, data: UpdateHostDto) {
|
|
return this.prisma.user.update({
|
|
where: { id },
|
|
data,
|
|
});
|
|
}
|
|
|
|
async deleteHost(id: number) {
|
|
return this.prisma.user.delete({ where: { id } });
|
|
}
|
|
|
|
async getHostByEmail(email: string): Promise<User> {
|
|
return this.prisma.user.findUnique({ where: { emailAddress: email } });
|
|
}
|
|
|
|
async verifyHostOtp(email: string, otp: string): Promise<boolean> {
|
|
const user = await this.prisma.user.findUnique({
|
|
where: { emailAddress: email },
|
|
select: {
|
|
id: true,
|
|
emailAddress: true,
|
|
UserOtp: {
|
|
where: { isActive: true, isVerified: false },
|
|
orderBy: { createdAt: 'desc' },
|
|
take: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!user) {
|
|
throw new ApiError(404, 'User not found.');
|
|
}
|
|
|
|
const userOtp = user.UserOtp[0];
|
|
|
|
if (!userOtp) {
|
|
throw new ApiError(400, 'No OTP found.');
|
|
}
|
|
|
|
if (new Date() > userOtp.expiresOn) {
|
|
throw new ApiError(400, 'OTP has expired.');
|
|
}
|
|
|
|
const isMatch = await bcrypt.compare(otp, userOtp.otpCode);
|
|
|
|
if (!isMatch) {
|
|
throw new ApiError(400, 'Invalid OTP.');
|
|
}
|
|
|
|
await this.prisma.userOtp.update({
|
|
where: { id: userOtp.id },
|
|
data: {
|
|
isVerified: true,
|
|
verifiedOn: new Date(),
|
|
isActive: false,
|
|
},
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
async loginForHost(emailAddress: string, userPassword: string) {
|
|
const existingUser = await this.prisma.user.findUnique({
|
|
where: { emailAddress: emailAddress },
|
|
});
|
|
|
|
if (!existingUser) {
|
|
throw new ApiError(404, 'User not found');
|
|
}
|
|
|
|
if (existingUser.roleXid !== 4) {
|
|
throw new ApiError(403, 'Access denied. Not a host user.');
|
|
}
|
|
|
|
const matchPassword = await bcrypt.compare(userPassword, existingUser.userPassword);
|
|
if (!matchPassword) {
|
|
throw new ApiError(401, 'Invalid credentials');
|
|
}
|
|
|
|
return existingUser;
|
|
}
|
|
|
|
async createHostUser(email: string) {
|
|
const newUser = await this.prisma.user.create({
|
|
data: { emailAddress: email, roleXid: 4 },
|
|
});
|
|
return newUser;
|
|
}
|
|
|
|
async createPassword(user_xid: number, password: string): Promise<boolean> {
|
|
// Find user by id
|
|
const user = await this.prisma.user.findUnique({
|
|
where: { id: user_xid },
|
|
select: { id: true, emailAddress: true, userPassword: true },
|
|
});
|
|
|
|
if (!user) {
|
|
throw new ApiError(404, 'User not found');
|
|
}
|
|
|
|
// Check if password already exists
|
|
if (user.userPassword) {
|
|
throw new ApiError(400, 'Password already exists. Use update password instead.');
|
|
}
|
|
|
|
// Hash the password
|
|
const saltRounds = parseInt(process.env.SALT_ROUNDS || '10', 10);
|
|
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
|
|
|
// Update user with hashed password
|
|
await this.prisma.user.update({
|
|
where: { id: user.id },
|
|
data: { userPassword: hashedPassword },
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
async addPaymentDetails(id: number, data: AddPaymentDetailsDTO): Promise<AddPaymentDetailsDTO> {
|
|
const existingUser = await this.prisma.user.findUnique({
|
|
where: { id },
|
|
});
|
|
|
|
if (!existingUser) {
|
|
throw new ApiError(404, 'User not found');
|
|
}
|
|
|
|
const addedPaymentDetails = await this.prisma.hostBankDetails.create({
|
|
data,
|
|
});
|
|
|
|
if (!addedPaymentDetails) {
|
|
throw new ApiError(400, 'Failed to add payment details');
|
|
}
|
|
|
|
return addedPaymentDetails;
|
|
}
|
|
|
|
async addCompanyDetails(
|
|
companyData: HostCompanyDetailsInput,
|
|
documents: HostDocumentInput[] // Documents with S3 URLs
|
|
) {
|
|
return await this.prisma.$transaction(async (tx) => {
|
|
// ✅ Check for existing company
|
|
const existingHost = await tx.hostHeader.findFirst({
|
|
where: { registrationNumber: companyData.registrationNumber },
|
|
});
|
|
|
|
if (existingHost) {
|
|
throw new ApiError(400, 'Company already exists with this registration number');
|
|
}
|
|
|
|
// ✅ Create company record
|
|
const createdHost = await tx.hostHeader.create({
|
|
data: {
|
|
companyName: companyData.companyName,
|
|
hostRefNumber: companyData.hostRefNumber,
|
|
address1: companyData.address1,
|
|
address2: companyData.address2,
|
|
cityXid: companyData.cityXid,
|
|
stateXid: companyData.stateXid,
|
|
countryXid: companyData.countryXid,
|
|
pinCode: companyData.pinCode,
|
|
logoPath: companyData.logoPath,
|
|
isSubsidairy: companyData.isSubsidairy,
|
|
registrationNumber: companyData.registrationNumber,
|
|
panNumber: companyData.panNumber,
|
|
gstNumber: companyData.gstNumber,
|
|
formationDate: new Date(companyData.formationDate),
|
|
companyType: companyData.companyType,
|
|
websiteUrl: companyData.websiteUrl,
|
|
instagramUrl: companyData.instagramUrl,
|
|
facebookUrl: companyData.facebookUrl,
|
|
linkedinUrl: companyData.linkedinUrl,
|
|
twitterUrl: companyData.twitterUrl,
|
|
currencyXid: companyData.currencyXid,
|
|
},
|
|
});
|
|
|
|
// ✅ Create documents (if provided)
|
|
if (documents && documents.length > 0) {
|
|
const docsData = documents.map((doc) => ({
|
|
hostXid: createdHost.id,
|
|
documentTypeXid: doc.documentTypeXid,
|
|
documentName: doc.documentName,
|
|
filePath: doc.filePath,
|
|
}));
|
|
|
|
await tx.hostDocuments.createMany({ data: docsData });
|
|
}
|
|
|
|
return createdHost;
|
|
});
|
|
}
|
|
}
|