diff --git a/src/common/utils/constants/host.constant.ts b/src/common/utils/constants/host.constant.ts index c1d01e8..818d2f2 100644 --- a/src/common/utils/constants/host.constant.ts +++ b/src/common/utils/constants/host.constant.ts @@ -97,4 +97,5 @@ export const ACTIVITY_AM_DISPLAY_STATUS = { ACTIVITY_ENHANCING: 'Enhancing', NOT_LISTED: 'Not Listed', ACTIVITY_LISTED: 'Listed', + ACITIVITY_REVISED:'Activity Revised' }; diff --git a/src/modules/host/dto/createActivity.schema.ts b/src/modules/host/dto/createActivity.schema.ts index 98d2874..1477326 100644 --- a/src/modules/host/dto/createActivity.schema.ts +++ b/src/modules/host/dto/createActivity.schema.ts @@ -2,8 +2,8 @@ import { z } from 'zod'; /* ================= MEDIA ================= */ export const MediaDto = z.object({ - mediaType: z.string().optional(), // "image/jpeg", "video/mp4", etc. - mediaFileName: z.string(), // S3 file URL + mediaType: z.string().optional(), // "image/jpeg", "video/mp4", etc. + mediaFileName: z.string(), // S3 file URL }); /* ================= PRICE ================= @@ -143,8 +143,8 @@ export const CreateActivityDto = z.object({ taxXids: z.array(z.number().int()).optional().default([]), /* 🔥 MEDIA ARRAYS */ - media: z.array(MediaDto).optional().default([]), // Activity-level media - venues: z.array(VenueDto).optional().default([]), // Each venue’s media + prices + media: z.array(MediaDto).optional().default([]), // Activity-level media + venues: z.array(VenueDto).optional().default([]), // Each venue’s media + prices /* RELATION ARRAYS */ foodTypeIds: z.array(z.number().int()).optional().default([]), @@ -157,6 +157,8 @@ export const CreateActivityDto = z.object({ /* EXTRA OBJECTS */ eligibility: EligibilityDto.optional(), otherDetails: OtherDetailsDto.optional(), + + allowedEntryTypes: z.array(z.number().int()).optional().default([]), }); export type CreateActivityInput = z.infer; diff --git a/src/modules/host/services/host.service.ts b/src/modules/host/services/host.service.ts index 7539f37..48b8fe8 100644 --- a/src/modules/host/services/host.service.ts +++ b/src/modules/host/services/host.service.ts @@ -1,4 +1,3 @@ - // src/modules/host/services/host.service.ts import { Injectable } from '@nestjs/common'; import { @@ -106,7 +105,7 @@ const bucket = config.aws.bucketName; @Injectable() export class HostService { - constructor(private prisma: PrismaClient) { } + constructor(private prisma: PrismaClient) {} async createHost(data: CreateHostDto) { return this.prisma.user.create({ data }); @@ -761,7 +760,7 @@ export class HostService { if ( existingHostCompany && existingHostCompany.hostStatusInternal === - HOST_STATUS_INTERNAL.HOST_TO_UPDATE && + HOST_STATUS_INTERNAL.HOST_TO_UPDATE && !isDraft ) { hostStatusInternal = HOST_STATUS_INTERNAL.HOST_SUBMITTED; @@ -774,7 +773,7 @@ export class HostService { else if ( existingHostCompany && existingHostCompany.hostStatusInternal === - HOST_STATUS_INTERNAL.HOST_TO_UPDATE && + HOST_STATUS_INTERNAL.HOST_TO_UPDATE && isDraft ) { // keep original @@ -885,19 +884,19 @@ export class HostService { // Safely handle city connection - only connect if valid ID exists cities: parentCompanyData?.cityXid && - !isNaN(Number(parentCompanyData.cityXid)) + !isNaN(Number(parentCompanyData.cityXid)) ? { connect: { id: Number(parentCompanyData.cityXid) } } : undefined, states: parentCompanyData?.stateXid && - !isNaN(Number(parentCompanyData.stateXid)) + !isNaN(Number(parentCompanyData.stateXid)) ? { connect: { id: Number(parentCompanyData.stateXid) } } : undefined, countries: parentCompanyData?.countryXid && - !isNaN(Number(parentCompanyData.countryXid)) + !isNaN(Number(parentCompanyData.countryXid)) ? { connect: { id: Number(parentCompanyData.countryXid) } } : undefined, pinCode: parentCompanyData.pinCode || null, @@ -1047,19 +1046,19 @@ export class HostService { address2: parentCompanyData.address2 || null, cities: parentCompanyData?.cityXid && - !isNaN(Number(parentCompanyData.cityXid)) + !isNaN(Number(parentCompanyData.cityXid)) ? { connect: { id: Number(parentCompanyData.cityXid) } } : undefined, states: parentCompanyData?.stateXid && - !isNaN(Number(parentCompanyData.stateXid)) + !isNaN(Number(parentCompanyData.stateXid)) ? { connect: { id: Number(parentCompanyData.stateXid) } } : undefined, countries: parentCompanyData?.countryXid && - !isNaN(Number(parentCompanyData.countryXid)) + !isNaN(Number(parentCompanyData.countryXid)) ? { connect: { id: Number(parentCompanyData.countryXid) } } : undefined, pinCode: parentCompanyData.pinCode || null, @@ -1105,19 +1104,19 @@ export class HostService { address2: parentCompanyData.address2 || null, cities: parentCompanyData?.cityXid && - !isNaN(Number(parentCompanyData.cityXid)) + !isNaN(Number(parentCompanyData.cityXid)) ? { connect: { id: Number(parentCompanyData.cityXid) } } : undefined, states: parentCompanyData?.stateXid && - !isNaN(Number(parentCompanyData.stateXid)) + !isNaN(Number(parentCompanyData.stateXid)) ? { connect: { id: Number(parentCompanyData.stateXid) } } : undefined, countries: parentCompanyData?.countryXid && - !isNaN(Number(parentCompanyData.countryXid)) + !isNaN(Number(parentCompanyData.countryXid)) ? { connect: { id: Number(parentCompanyData.countryXid) } } : undefined, pinCode: parentCompanyData.pinCode || null, @@ -1726,21 +1725,21 @@ export class HostService { select: { id: true, activityTypeName: true, - } + }, }, ActivitiesMedia: { where: { - isActive: true + isActive: true, }, select: { id: true, mediaType: true, mediaFileName: true, - } + }, }, ActivityVenues: { where: { - isActive: true + isActive: true, }, select: { id: true, @@ -1755,10 +1754,10 @@ export class HostService { select: { id: true, mediaType: true, - mediaFileName: true - } - } - } + mediaFileName: true, + }, + }, + }, }, ActivityPickUpDetails: { where: { @@ -1766,9 +1765,9 @@ export class HostService { activityPickUpTransport: { isActive: true, transportMode: { - isActive: true - } - } + isActive: true, + }, + }, }, select: { id: true, @@ -1787,12 +1786,12 @@ export class HostService { transportMode: { select: { transportModeName: true, - transportModeIcon: true - } - } - } - } - } + transportModeIcon: true, + }, + }, + }, + }, + }, }, foodAvailable: true, foodIsChargeable: true, @@ -1803,40 +1802,40 @@ export class HostService { foodType: { select: { id: true, - foodTypeName: true - } + foodTypeName: true, + }, }, - } + }, }, activityCuisines: { where: { - isActive: true + isActive: true, }, select: { id: true, foodCuisine: { select: { id: true, - cuisineName: true - } - } - } + cuisineName: true, + }, + }, + }, }, alcoholAvailable: true, trainerAvailable: true, trainerIsChargeable: true, ActivityTrainers: { where: { - isActive: true + isActive: true, }, select: { id: true, - totalAmount: true - } + totalAmount: true, + }, }, ActivityNavigationModes: { where: { - isActive: true + isActive: true, }, select: { id: true, @@ -1846,27 +1845,27 @@ export class HostService { select: { id: true, navigationModeName: true, - navigationModeIcon: true - } - } - } + navigationModeIcon: true, + }, + }, + }, }, equipmentAvailable: true, equipmentIsChargeable: true, ActivityEquipments: { where: { - isActive: true + isActive: true, }, select: { id: true, equipmentName: true, isEquipmentChargeable: true, equipmentTotalPrice: true, - } + }, }, ActivityOtherDetails: { where: { - isActive: true + isActive: true, }, select: { id: true, @@ -1875,22 +1874,22 @@ export class HostService { dontsNotes: true, tipsNotes: true, termsAndCondition: true, - } + }, }, energyLevel: { where: { - isActive: true + isActive: true, }, select: { id: true, energyLevelName: true, energyIcon: true, - energyColor: true - } + energyColor: true, + }, }, ActivityEligibility: { where: { - isActive: true + isActive: true, }, select: { id: true, @@ -1901,7 +1900,7 @@ export class HostService { ageRestrictionName: true, minAge: true, maxAge: true, - } + }, }, isWeightRestriction: true, weightRestrictionName: true, @@ -1914,39 +1913,39 @@ export class HostService { heightEntered: true, heightIn: true, minHeight: true, - maxHeight: true - } + maxHeight: true, + }, }, ActivityAllowedEntry: { where: { - isActive: true + isActive: true, }, select: { id: true, allowedEntryType: { select: { id: true, - allowedEntryTypeName: true - } - } - } + allowedEntryTypeName: true, + }, + }, + }, }, ActivityAmenities: { where: { - isActive: true + isActive: true, }, select: { id: true, amenities: { select: { id: true, - amenitiesName: true - } - } - } + amenitiesName: true, + }, + }, + }, }, cancellationAvailable: true, - cancellationAllowedBeforeMins: true + cancellationAllowedBeforeMins: true, // accountManager: { // select: { // id: true, @@ -1965,9 +1964,8 @@ export class HostService { // adminStatusInternal: true, // } // } - - } - }) + }, + }); if (!activity) { throw new ApiError(404, 'Activity not found'); @@ -2280,11 +2278,7 @@ export class HostService { * ActivityPickUpTransport/Details + ActivityNavigationModes + ActivityEquipments + * ActivityAmenities + ActivityEligibility */ - async createOrUpdateActivity( - userId: number, - payload: any, - isDraft: boolean, - ) { + async createOrUpdateActivity(userId: number, payload: any, isDraft: boolean) { /* ===================================================== * HELPERS * ===================================================== */ @@ -2363,7 +2357,10 @@ export class HostService { } if (v.isMinPeopleReqMandatory && !v.minPeopleRequired) { - throw new ApiError(400, `venues[${idx}] min people requirement missing`); + throw new ApiError( + 400, + `venues[${idx}] min people requirement missing`, + ); } if (!Array.isArray(v.prices) || !v.prices.length) { @@ -2381,9 +2378,9 @@ export class HostService { const rootTaxes = taxIds.length > 0 ? await this.prisma.taxes.findMany({ - where: { id: { in: taxIds }, isActive: true }, - select: { id: true, taxPer: true }, - }) + where: { id: { in: taxIds }, isActive: true }, + select: { id: true, taxPer: true }, + }) : []; if (taxIds.length !== rootTaxes.length) { @@ -2438,7 +2435,7 @@ export class HostService { activityInternalStatus = ACTIVITY_INTERNAL_STATUS.ACTIVITY_SUBMITTED; activityDisplayStatus = ACTIVITY_DISPLAY_STATUS.ACTIVITY_IN_REVIEW; amInternalStatus = ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_TO_REVIEW; - amDisplayStatus = ACTIVITY_AM_DISPLAY_STATUS.ACTIVITY_NEW; + amDisplayStatus = ACTIVITY_AM_DISPLAY_STATUS.ACITIVITY_REVISED; } } else { if (isDraft) { @@ -2604,7 +2601,8 @@ export class HostService { noOfSession: price.noOfSession ?? 1, isPackage: price.isPackage ?? false, sessionValidity: price.sessionValidity ?? 0, - sessionValidityFrequency: price.sessionValidityFrequency ?? 'Days', + sessionValidityFrequency: + price.sessionValidityFrequency ?? 'Days', basePrice, sellPrice, }, @@ -2843,7 +2841,9 @@ export class HostService { data: { activityXid, navigationModeXid: modeId, - isInActivityChargeable: toBool(payload.navigationModeIsChargeable), + isInActivityChargeable: toBool( + payload.navigationModeIsChargeable, + ), navigationModesBasePrice: basePrice, navigationModesTotalPrice: totalPrice, }, @@ -2887,14 +2887,20 @@ export class HostService { activityXid, isAgeRestriction: toBool(payload.eligibility.isAgeRestriction), ageRestrictionXid: toNumber(payload.eligibility.ageRestrictionXid), - isWeightRestriction: toBool(payload.eligibility.isWeightRestriction), - weightRestrictionName: payload.eligibility.weightRestrictionName ?? null, + isWeightRestriction: toBool( + payload.eligibility.isWeightRestriction, + ), + weightRestrictionName: + payload.eligibility.weightRestrictionName ?? null, weightEntered: toNumber(payload.eligibility.weightEntered), weightIn: payload.eligibility.weightIn ?? null, minWeight: toNumber(payload.eligibility.minWeight), maxWeight: toNumber(payload.eligibility.maxWeight), - isHeightRestriction: toBool(payload.eligibility.isHeightRestriction), - heightRestrictionName: payload.eligibility.heightRestrictionName ?? null, + isHeightRestriction: toBool( + payload.eligibility.isHeightRestriction, + ), + heightRestrictionName: + payload.eligibility.heightRestrictionName ?? null, heightEntered: toNumber(payload.eligibility.heightEntered), heightIn: payload.eligibility.heightIn ?? null, minHeight: toNumber(payload.eligibility.minHeight), @@ -2949,6 +2955,33 @@ export class HostService { }); } + const allowedEntryIds = Array.isArray(payload.allowedEntryTypes) + ? payload.allowedEntryTypes.map(Number) + : []; + if (allowedEntryIds.length) { + const validEntryTypes = await this.prisma.allowedEntryTypes.findMany({ + where: { id: { in: allowedEntryIds }, isActive: true }, + select: { id: true }, + }); + if (validEntryTypes.length !== allowedEntryIds.length) + throw new ApiError( + 400, + 'Invalid or inactive allowed entry type(s) provided', + ); + } + /* -------------------------------- + * CLEAN & CREATE ALLOWED ENTRY + * -------------------------------- */ + await tx.activityAllowedEntry.deleteMany({ where: { activityXid } }); + if (allowedEntryIds.length) { + await tx.activityAllowedEntry.createMany({ + data: allowedEntryIds.map((entryId) => ({ + activityXid, + allowedEntryTypeXid: entryId, + })), + }); + } + /* -------------------------------- * 1️⃣8️⃣ ACTIVITY TRACK * -------------------------------- */ @@ -2969,10 +3002,13 @@ export class HostService { return { activityXid, activityRefNumber: activity.activityRefNumber, - status: isDraft ? ACTIVITY_INTERNAL_STATUS.ACTIVITY_DRAFT : ACTIVITY_INTERNAL_STATUS.ACTIVITY_SUBMITTED, + status: isDraft + ? ACTIVITY_INTERNAL_STATUS.ACTIVITY_DRAFT + : ACTIVITY_INTERNAL_STATUS.ACTIVITY_SUBMITTED, }; }); } + async getAllPQUpdatedResponse(activityXid: number) { const pqqHeaderData = await this.prisma.activityPQQheader.findMany({ where: {