diff --git a/package-lock.json b/package-lock.json index 4963751..1a58e38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3865,9 +3865,9 @@ } }, "node_modules/@prisma/client": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.16.0.tgz", - "integrity": "sha512-FYkFJtgwpwJRMxtmrB26y7gtpR372kyChw6lWng5TMmvn5V+uisy0OyllO5EJD1s8lX78V8X3XjhiXOoMLnu3w==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.0.tgz", + "integrity": "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==", "hasInstallScript": true, "engines": { "node": ">=18.18" @@ -3886,70 +3886,60 @@ } }, "node_modules/@prisma/config": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.16.0.tgz", - "integrity": "sha512-Q9TgfnllVehvQziY9lJwRJLGmziX0OimZUEQ/MhCUBoJMSScj2VivCjw/Of2vlO1FfyaHXxrvjZAr7ASl7DVcw==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz", + "integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==", "devOptional": true, "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", - "effect": "3.16.12", + "effect": "3.18.4", "empathic": "2.0.0" } }, - "node_modules/@prisma/config/node_modules/effect": { - "version": "3.16.12", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", - "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", - "devOptional": true, - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "fast-check": "^3.23.1" - } - }, "node_modules/@prisma/debug": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.16.0.tgz", - "integrity": "sha512-bxzro5vbVqAPkWyDs2A6GpQtRZunD8tyrLmSAchx9u0b+gWCDY6eV+oh5A0YtYT9245dIxQBswckayHuJG4u3w==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz", + "integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==", "devOptional": true }, "node_modules/@prisma/engines": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.16.0.tgz", - "integrity": "sha512-RHJGCH/zi017W4CWYWqg0Sv1pquGGFVo8T3auJ9sodDNaiRzbeNldydjaQzszVS8nscdtcvLuJzy7e65C3puqQ==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz", + "integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/debug": "6.16.0", - "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", - "@prisma/fetch-engine": "6.16.0", - "@prisma/get-platform": "6.16.0" + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/fetch-engine": "6.19.0", + "@prisma/get-platform": "6.19.0" } }, "node_modules/@prisma/engines-version": { - "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43.tgz", - "integrity": "sha512-ThvlDaKIVrnrv97ujNFDYiQbeMQpLa0O86HFA2mNoip4mtFqM7U5GSz2ie1i2xByZtvPztJlNRgPsXGeM/kqAA==", + "version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz", + "integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==", "devOptional": true }, "node_modules/@prisma/fetch-engine": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.16.0.tgz", - "integrity": "sha512-Mx5rml0XRIDizhB9eZxSP8c0nMoXYVITTiJJwxlWn9rNCel8mG8NAqIw+vJlN3gPR+kt3IBkP1SQVsplPPpYrA==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz", + "integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==", "devOptional": true, "dependencies": { - "@prisma/debug": "6.16.0", - "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", - "@prisma/get-platform": "6.16.0" + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/get-platform": "6.19.0" } }, "node_modules/@prisma/get-platform": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.16.0.tgz", - "integrity": "sha512-eaJOOvAoGslSUTjiQrtE9E0hoBdfL43j8SymOGD6LbdrKRNtIoiy6qiBaEr2fNYD+R/Qns7QOwPhl7SVHJayKA==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz", + "integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==", "devOptional": true, "dependencies": { - "@prisma/debug": "6.16.0" + "@prisma/debug": "6.19.0" } }, "node_modules/@sinclair/typebox": { @@ -7380,10 +7370,10 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/effect": { - "version": "3.19.6", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.19.6.tgz", - "integrity": "sha512-Eh1E/CI+xCAcMSDC5DtyE29yWJINC0zwBbwHappQPorjKyS69rCA8qzpsHpfhKnPDYgxdg8zkknii8mZ+6YMQA==", - "dev": true, + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", + "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "devOptional": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" @@ -11270,14 +11260,14 @@ } }, "node_modules/prisma": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.16.0.tgz", - "integrity": "sha512-TTh+H1Kw8N68KN9cDzdAyMroqMOvdCO/Z+kS2wKEVYR1nuR21qH5Q/Db/bZHsAgw7l/TPHtM/veG5VABcdwPDw==", + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.0.tgz", + "integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/config": "6.16.0", - "@prisma/engines": "6.16.0" + "@prisma/config": "6.19.0", + "@prisma/engines": "6.19.0" }, "bin": { "prisma": "build/index.js" diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b16904c..458da16 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -97,15 +97,15 @@ model UserAddressDetails { } model UserDocuments { - id Int @id @default(autoincrement()) - userXid Int @map("user_xid") - user User @relation(fields: [userXid], references: [id], onDelete: Cascade) + id Int @id @default(autoincrement()) + userXid Int @map("user_xid") + user User @relation(fields: [userXid], references: [id], onDelete: Cascade) // documentTypeName String @map("document_type_name") @db.VarChar(50) - fileName String @map("file_name") @db.VarChar(500) - isActive Boolean @default(true) @map("is_active") - createdAt DateTime @default(now()) @map("created_at") - updatedAt DateTime @updatedAt @map("updated_at") - deletedAt DateTime? @map("deleted_at") + fileName String @map("file_name") @db.VarChar(500) + isActive Boolean @default(true) @map("is_active") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + deletedAt DateTime? @map("deleted_at") @@map("user_documents") @@schema("usr") @@ -655,7 +655,7 @@ model HostHeader { cities Cities @relation(fields: [cityXid], references: [id], onDelete: Restrict) stateXid Int @map("state_xid") states States @relation(fields: [stateXid], references: [id], onDelete: Restrict) - countryXid Int? @map("country_xid") + countryXid Int? @map("country_xid") countries Countries? @relation(fields: [countryXid], references: [id], onDelete: Restrict) pinCode String @map("pin_code") @db.VarChar(30) logoPath String? @map("logo_path") @db.VarChar(400) @@ -670,14 +670,14 @@ model HostHeader { facebookUrl String? @map("facebook_url") @db.VarChar(80) linkedinUrl String? @map("linkedin_url") @db.VarChar(80) twitterUrl String? @map("twitter_url") @db.VarChar(80) - currencyXid Int? @map("currency_xid") - currencies Currencies? @relation(fields: [currencyXid], references: [id], onDelete: Restrict) - stepper Int? @default(1) @map("stepper") + currencyXid Int? @map("currency_xid") + currencies Currencies? @relation(fields: [currencyXid], references: [id], onDelete: Restrict) + stepper Int? @default(1) @map("stepper") hostStatusInternal String @default("pending") @map("host_status_internal") @db.VarChar(20) hostStatusDisplay String @default("pending") @map("host_status_Display") @db.VarChar(20) adminStatusInternal String @default("pending") @map("admin_status_internal") @db.VarChar(20) adminStatusDisplay String @default("pending") @map("admin_status_display") @db.VarChar(20) - amStatus String? @default("pending") @map("am_status") @db.VarChar(20) + amStatus String? @default("pending") @map("am_status") @db.VarChar(20) agreementAccepted Boolean @default(false) @map("agreement_accepted") accountManagerXid Int? @map("account_manager_xid") accountManager User? @relation("AccountManager", fields: [accountManagerXid], references: [id], onDelete: Restrict) @@ -819,16 +819,17 @@ model HostParenetDocuments { } model HostTrack { - id Int @id @default(autoincrement()) - hostXid Int @map("host_xid") - host HostHeader @relation(fields: [hostXid], references: [id], onDelete: Cascade) - trackStatus String @map("track_status") @db.VarChar(20) - updatedByXid Int @map("updated_by_xid") - updatedBy User @relation(fields: [updatedByXid], references: [id], onDelete: Restrict) - isActive Boolean @default(true) @map("is_active") - createdAt DateTime @default(now()) @map("created_at") - updatedAt DateTime @updatedAt @map("updated_at") - deletedAt DateTime? @map("deleted_at") + id Int @id @default(autoincrement()) + hostXid Int @map("host_xid") + host HostHeader @relation(fields: [hostXid], references: [id], onDelete: Cascade) + updatedByRole String @map("updated_by_role") @db.VarChar(50) + trackStatus String @map("track_status") @db.VarChar(20) + updatedByXid Int @map("updated_by_xid") + updatedBy User @relation(fields: [updatedByXid], references: [id], onDelete: Restrict) + isActive Boolean @default(true) @map("is_active") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + deletedAt DateTime? @map("deleted_at") @@map("host_track") @@schema("hst") diff --git a/serverless.yml b/serverless.yml index a15902c..8036020 100644 --- a/serverless.yml +++ b/serverless.yml @@ -5,19 +5,11 @@ provider: runtime: nodejs22.x region: ap-south-1 versionFunctions: false - iamRoleStatements: - - Effect: Allow - Action: - - s3:GetObject - - s3:ListBucket - Resource: - - arn:aws:s3:::minglar-dev-bucket - - arn:aws:s3:::minglar-dev-bucket/* - + memorySize: 512 # Default memory for all functions (can be overridden per function) apiGateway: binaryMediaTypes: - '*/*' - minimumCompressionSize: 0 + minimumCompressionSize: 1024 environment: DATABASE_URL: ${env:DATABASE_URL} @@ -51,11 +43,11 @@ provider: - s3:PutObject - s3:GetObject - s3:DeleteObject - Resource: 'arn:aws:s3:::${env:S3_BUCKET_NAME}/*' + - s3:ListBucket + Resource: + - 'arn:aws:s3:::${env:S3_BUCKET_NAME}' + - 'arn:aws:s3:::${env:S3_BUCKET_NAME}/*' -# ------------------------------------------------------------ -# ESBUILD -# ------------------------------------------------------------ custom: esbuild: bundle: true @@ -63,36 +55,40 @@ custom: sourcemap: false target: node20 platform: node - concurrency: 10 + concurrency: 5 external: - '@prisma/client' - '.prisma' exclude: - 'aws-sdk' -# ------------------------------------------------------------ -# GLOBAL PACKAGE CONFIG (EMPTY PACKAGE STRATEGY) -# ------------------------------------------------------------ package: individually: true patterns: - - '!**/*' # <-- DO NOT include anything globally + - '!node_modules/**' + - '!**/*.test.js' + - '!**/*.spec.js' + - '!**/test/**' + - '!**/__tests__/**' + - '!package-lock.json' + - '!yarn.lock' + - '!README.md' + - '!*.config.js' + - '!.git/**' + - '!.github/**' -# ------------------------------------------------------------ -# FUNCTIONS (ONLY required files included) -# ------------------------------------------------------------ functions: getHosts: handler: src/modules/host/handlers/host.handler + memorySize: 384 # Lower memory for simple GET operations package: patterns: - 'src/modules/host/handlers/host.*' - 'src/modules/host/services/**' - - 'common/**' - 'src/common/**' + - 'common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host @@ -100,15 +96,15 @@ functions: verifyOtp: handler: src/modules/host/handlers/verifyOtp.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/verifyOtp.*' - 'src/modules/host/services/**' - - 'common/**' - 'src/common/**' + - 'common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/verify-otp @@ -116,12 +112,13 @@ functions: loginForHost: handler: src/modules/host/handlers/loginForHost.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/loginForHost.*' - 'src/modules/host/services/**' - - 'common/**' - 'src/common/**' + - 'common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' events: @@ -131,12 +128,13 @@ functions: registrationOfHost: handler: src/modules/host/handlers/registration.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/registration.*' - 'src/modules/host/services/**' - - 'common/**' - 'src/common/**' + - 'common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' events: @@ -146,6 +144,7 @@ functions: createPasswordForHost: handler: src/modules/host/handlers/createPassword.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/createPassword.*' @@ -153,7 +152,6 @@ functions: - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/create-password @@ -161,15 +159,15 @@ functions: addPaymentDetailsForHost: handler: src/modules/host/handlers/addPaymentDetails.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/addPaymentDetails.*' - 'src/modules/host/services/**' - - 'common/**' - 'src/common/**' + - 'common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/add-payment-details @@ -177,6 +175,7 @@ functions: addActivity: handler: src/modules/host/handlers/addActivity.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/addActivity.*' @@ -184,7 +183,6 @@ functions: - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/add-activity @@ -192,6 +190,7 @@ functions: getHostById: handler: src/modules/host/handlers/getbyidhandler.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/getbyidhandler.*' @@ -199,7 +198,6 @@ functions: - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/getById @@ -207,6 +205,7 @@ functions: getPQQQuestionDetailsById: handler: src/modules/host/handlers/getByIdPQQ.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/getByIdPQQ.*' @@ -214,7 +213,6 @@ functions: - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/get-pqq-question-details @@ -222,6 +220,7 @@ functions: getLatestPQQQuestionDetails: handler: src/modules/host/handlers/getLatestQuestionDetailsPQQ.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/getLatestQuestionDetailsPQQ.*' @@ -229,7 +228,6 @@ functions: - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/get-latest-pqq-question-details @@ -237,6 +235,7 @@ functions: getActivityTypes: handler: src/modules/host/handlers/getActivity.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/getActivity.*' @@ -244,7 +243,6 @@ functions: - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/get-activity @@ -252,6 +250,7 @@ functions: acceptMinglarAgreement: handler: src/modules/host/handlers/acceptAgreement.handler + memorySize: 384 package: patterns: - 'src/modules/host/handlers/acceptAgreement.*' @@ -259,7 +258,6 @@ functions: - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /host/accept-agreement @@ -267,16 +265,16 @@ functions: getStepperInfo: handler: src/modules/host/handlers/getStepper.handler + memorySize: 384 package: patterns: - - 'src/modules/host/handlers/getStepper.handler.*' + - 'src/modules/host/handlers/getStepper.*' - 'src/common/utils/handlers/safeHandler.*' - 'src/common/database/**' - 'src/modules/host/services/**' - 'common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /stepper @@ -284,13 +282,13 @@ functions: getSuggestion: handler: src/modules/minglaradmin/handlers/getSuggestion.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/get-suggestion @@ -298,13 +296,13 @@ functions: minglarRegistration: handler: src/modules/minglaradmin/handlers/registration.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/registration @@ -312,13 +310,13 @@ functions: minglarLoginForAdmin: handler: src/modules/minglaradmin/handlers/loginForMinglar.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/login @@ -326,25 +324,27 @@ functions: minglarCreatePassword: handler: src/modules/minglaradmin/handlers/createPassword.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/create-password method: post + # Functions using AWS SDK - KEEP AS IS with higher memory updateMinglarProfile: handler: src/modules/minglaradmin/handlers/updateProfile.handler + memorySize: 512 # Higher memory for AWS SDK operations timeout: 30 package: patterns: - - 'src/modules/host/handlers/updateProfile.*' - - 'src/modules/host/services/**' + - 'src/modules/minglaradmin/handlers/updateProfile.*' + - 'src/modules/minglaradmin/services/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' @@ -352,7 +352,6 @@ functions: - 'node_modules/@smithy/**' - 'node_modules/tslib/**' - 'node_modules/fast-xml-parser/**' - events: - httpApi: path: /minglaradmin/update-profile @@ -360,13 +359,13 @@ functions: prepopulateTeammate: handler: src/modules/minglaradmin/handlers/prepopulateTeammate.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/prepopulate-Roles @@ -374,13 +373,13 @@ functions: inviteTeammate: handler: src/modules/minglaradmin/handlers/inviteTeammate.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/invite-teammate @@ -388,27 +387,55 @@ functions: getAllHostApplication: handler: src/modules/minglaradmin/handlers/getAllHostApplication.handler + memorySize: 512 # Higher memory for data-intensive operations package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: - path: /minglaradmin/get-all-host-applications + path: /minglaradmin/get-all-host-applications-am + method: get + + getAllOnboardingHostApplications: + handler: src/modules/minglaradmin/handlers/getAllOnboardingHosts.handler + memorySize: 512 # Higher memory for data-intensive operations + package: + patterns: + - 'src/modules/minglaradmin/**' + - 'src/common/**' + - 'node_modules/@prisma/client/**' + - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' + events: + - httpApi: + path: /minglaradmin/get-all-host-applications-admin + method: get + + getAllOnboardingHostApplications_New: + handler: src/modules/minglaradmin/handlers/getOnboardingNewApplications.handler + memorySize: 512 # Higher memory for data-intensive operations + package: + patterns: + - 'src/modules/minglaradmin/**' + - 'src/common/**' + - 'node_modules/@prisma/client/**' + - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' + events: + - httpApi: + path: /minglaradmin/get-all-host-applications-admin-new method: get getAllInvitationDetails: handler: src/modules/minglaradmin/handlers/getAllInvitationDetails.handler + memorySize: 512 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/get-all-invitation-details @@ -416,13 +443,13 @@ functions: addSuggestion: handler: src/modules/minglaradmin/handlers/addSuggestion.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/add-suggestion @@ -430,13 +457,13 @@ functions: getAllCoadminAndAMDetails: handler: src/modules/minglaradmin/handlers/getAllCoadminAndAM.handler + memorySize: 512 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/get-all-coadmin-and-am-details @@ -444,13 +471,13 @@ functions: getAllInvitedCoadminAndAMDetails: handler: src/modules/minglaradmin/handlers/getAllInvitedCoadminAndAM.handler + memorySize: 512 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/get-all-invited-coadmin-and-am @@ -458,27 +485,59 @@ functions: getAllBankAndCurrencyDetails: handler: src/modules/prepopulate/handlers/getAllBankDetails.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /prepopulate/get-all-bank-currency-details method: get + getCityByState: + handler: src/modules/prepopulate/handlers/getCityByState.handler + memorySize: 384 + package: + patterns: + - 'src/modules/prepopulate/handlers/getCityByState.*' + - 'src/modules/prepopulate/services/**' + - 'src/common/**' + - 'common/**' + - 'node_modules/@prisma/client/**' + - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' + events: + - httpApi: + path: /prepopulate/get-city-by-state + method: get + + getBranchByBankXid: + handler: src/modules/prepopulate/handlers/getBranchByBank.handler + memorySize: 384 + package: + patterns: + - 'src/modules/prepopulate/handlers/getBranchByBank.*' + - 'src/modules/prepopulate/services/**' + - 'src/common/**' + - 'common/**' + - 'node_modules/@prisma/client/**' + - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' + events: + - httpApi: + path: /prepopulate/get-branch-by-bank + method: get + getAllDocumentCountryStateCityDetails: handler: src/modules/prepopulate/handlers/getAllDocTypeWithCountryState.handler + memorySize: 512 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /prepopulate/get-all-doc-country @@ -486,13 +545,13 @@ functions: getAllPqqQuesAns: handler: src/modules/prepopulate/handlers/getAllPQQQuesWithAns.handler + memorySize: 512 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /prepopulate/get-all-pqq-ques-ans @@ -500,13 +559,13 @@ functions: getFrequenciesOfActivity: handler: src/modules/prepopulate/handlers/getAllFrequencies.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /prepopulate/get-all-Frequencies @@ -514,13 +573,13 @@ functions: assignAMToHost: handler: src/modules/minglaradmin/handlers/assignAM.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/assign-am-to-host @@ -528,13 +587,13 @@ functions: editAgreementDetails: handler: src/modules/minglaradmin/handlers/editAgreementDetails.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/edit-agreement-details @@ -542,13 +601,13 @@ functions: acceptHostApplication: handler: src/modules/minglaradmin/handlers/acceptHostApplication.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/accept-host-application @@ -556,13 +615,13 @@ functions: acceptHostApplicationMinglar: handler: src/modules/minglaradmin/handlers/acceptHostAppMinglar.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/accept-host-application-minglar @@ -570,13 +629,13 @@ functions: rejectHostApplication: handler: src/modules/minglaradmin/handlers/rejectHostApplication.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/reject-host-application @@ -584,20 +643,23 @@ functions: rejectHostApplicationAM: handler: src/modules/minglaradmin/handlers/rejectHostApplicationAM.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/**' - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - events: - httpApi: path: /minglaradmin/reject-host-application-am method: patch + # Functions using AWS SDK and S3 - KEEP AS IS with higher memory addCompanyDetails: handler: src/modules/host/handlers/addCompanyDetails.handler + memorySize: 512 + timeout: 30 package: patterns: - 'src/modules/host/handlers/addCompanyDetails.*' @@ -605,19 +667,26 @@ functions: - 'src/common/**' - 'node_modules/@prisma/client/**' - 'node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node' - - 'node_modules/@aws-sdk/**' + # Only include specific AWS SDK modules needed for S3 + - 'node_modules/@aws-sdk/client-s3/**' + - 'node_modules/@aws-sdk/s3-request-presigner/**' + - 'node_modules/@aws-sdk/types/**' + - 'node_modules/@aws-sdk/middleware-logger/**' + - 'node_modules/@aws-sdk/util-utf8-node/**' + - 'node_modules/@aws-sdk/util-utf8-browser/**' - 'node_modules/@smithy/**' - 'node_modules/tslib/**' - - 'node_modules/fast-xml-parser/**' - - 'node_modules/lambda-multipart-parser/**' + # Remove these large/unnecessary packages: + - 'node_modules/fast-xml-parser/**' # Remove if not used + - 'node_modules/lambda-multipart-parser/**' # You're using busboy directly - 'node_modules/busboy/**' + # Remove these AWS utility packages (included in main SDK): - 'node_modules/@aws-crypto/**' - - 'node_modules/uuid/**' - - 'node_modules/@aws/util-uri-escape/**' - - 'node_modules/@aws/util-middleware/**' + # - 'node_modules/uuid/**' # AWS SDK includes its own + # - 'node_modules/@aws/util-uri-escape/**' + # - 'node_modules/@aws/util-middleware/**' - 'node_modules/@aws/smithy-client/**' - - 'node_modules/@aws/lambda-invoke-store/**' - + # - 'node_modules/@aws/lambda-invoke-store/**' events: - httpApi: path: /host/add-company-details @@ -625,6 +694,8 @@ functions: submitPqqAnswer: handler: src/modules/host/handlers/submitPqqAns.handler + memorySize: 512 + timeout: 30 package: patterns: - 'src/modules/host/handlers/submitPqqAns.*' @@ -644,7 +715,6 @@ functions: - 'node_modules/@aws/util-middleware/**' - 'node_modules/@aws/smithy-client/**' - 'node_modules/@aws/lambda-invoke-store/**' - events: - httpApi: path: /host/submit-pqq-ans @@ -652,6 +722,8 @@ functions: submitFinalPqqAnswer: handler: src/modules/host/handlers/getPQQScore.handler + memorySize: 512 + timeout: 30 package: patterns: - 'src/modules/host/handlers/getPQQScore.*' @@ -671,14 +743,14 @@ functions: - 'node_modules/@aws/util-middleware/**' - 'node_modules/@aws/smithy-client/**' - 'node_modules/@aws/lambda-invoke-store/**' - events: - httpApi: path: /host/submit-final-pqq-ans method: patch addPQQSuggestion: - handler: src/modules/minglaradmin/handlers/addPQQSuggestion.handler + handler: src/modules/minglar/handlers/addPQQSuggestion.handler + memorySize: 384 package: patterns: - 'src/modules/minglaradmin/handlers/addPQQSuggestion.*' diff --git a/src/common/utils/constants/common.constant.ts b/src/common/utils/constants/common.constant.ts index b5fcb80..eec3934 100644 --- a/src/common/utils/constants/common.constant.ts +++ b/src/common/utils/constants/common.constant.ts @@ -7,6 +7,15 @@ export const ROLE = { USER: 6 } +export const ROLE_NAME = { + MINGLAR_ADMIN: 'Minglar Admin', + CO_ADMIN: 'Co-admin', + ACCOUNT_MANAGER: 'Account manager', + HOST: 'Host', + OPERATOR: 'Operator', + USER: 'User' +} + export const USER_STATUS = { INVITED: "Invited", ACTIVE: "Active", diff --git a/src/common/utils/constants/minglar.constant.ts b/src/common/utils/constants/minglar.constant.ts index a142291..896f4f5 100644 --- a/src/common/utils/constants/minglar.constant.ts +++ b/src/common/utils/constants/minglar.constant.ts @@ -5,6 +5,7 @@ export const MINGLAR_STATUS_INTERNAL = { AM_TO_REVIEW: 'AM To Review', AM_REJECTED: 'AM Rejected', AM_APPROVED: 'AM Approved', + DRAFT: 'Draft', }; export const MINGLAR_STATUS_DISPLAY = { @@ -14,6 +15,7 @@ export const MINGLAR_STATUS_DISPLAY = { ENHANCING: 'Enhancing', APPROVED: 'Approved', REJECTED: 'Rejected', + DRAFT: 'Draft' }; export const MINGLAR_INVITATION_STATUS = { diff --git a/src/modules/host/handlers/addCompanyDetails.ts b/src/modules/host/handlers/addCompanyDetails.ts index 4d61a2f..8ecde3c 100644 --- a/src/modules/host/handlers/addCompanyDetails.ts +++ b/src/modules/host/handlers/addCompanyDetails.ts @@ -65,7 +65,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< const fields: Record = {}; const files: Array<{ buffer: Buffer; mimeType: string; fileName: string; fieldName: string }> = []; - // 3) parse with Busboy - FIXED VERSION + // 3) parse with Busboy await new Promise((resolve, reject) => { const bb = Busboy({ headers: { @@ -105,7 +105,6 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< }); bb.on('field', (fieldname, val) => { - // Store as string initially, parse later in normalizeJsonField fields[fieldname] = val; }); @@ -121,6 +120,9 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< bb.end(); }); + // Extract isDraft flag from fields (default to false if not provided) + const isDraft = fields.isDraft === 'true' || fields.isDraft === true; + if (fields.userProfile) { const userProfileRaw = normalizeJsonField(fields, "userProfile"); if (userProfileRaw) { @@ -157,39 +159,31 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< if (existingHost) { hostId = existingHost.id; } else { - // For new hosts, we'll use user ID temporarily and update after host creation hostId = userInfo.id; } - // Define uploadToS3 function with proper folder structure using fieldName for filenames - // Define uploadToS3 function with proper folder structure using fieldName for filenames + // Define uploadToS3 function (same as before) async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, folderType: 'logo' | 'documents' | 'parent_company', documentTypeXid?: number, fieldName?: string) { let s3Key: string; - // Sanitize file name: remove special characters and spaces const sanitizeFileName = (name: string) => { return name .toLowerCase() - .replace(/[^a-z0-9.]/g, '_') // Replace special characters with underscore - .replace(/_+/g, '_') // Replace multiple underscores with single - .replace(/^_+|_+$/g, ''); // Remove leading/trailing underscores + .replace(/[^a-z0-9.]/g, '_') + .replace(/_+/g, '_') + .replace(/^_+|_+$/g, ''); }; - // Get file extension from original file name const fileExtension = originalName.split('.').pop() || 'pdf'; - // Determine folder structure based on type if (folderType === 'logo') { - // Logo: Documents/Host/logo/{HostID}/{sanitized_filename} const sanitizedFileName = sanitizeFileName(originalName); s3Key = `Documents/Host/${hostId}/logo/${sanitizedFileName}`; } else if (folderType === 'documents' && documentTypeXid && fieldName) { - // Host Documents: Documents/Host/documents/{HostID}/{documentTypeXid}_{fieldName}.{extension} const fileName = `${documentTypeXid}_${fieldName}.${fileExtension}`; const sanitizedFileName = sanitizeFileName(fileName); s3Key = `Documents/Host/${hostId}/documents/${sanitizedFileName}`; } else if (folderType === 'parent_company' && documentTypeXid && fieldName) { - // Parent Documents: Documents/Host/parent_company/{HostID}/{documentTypeXid}_{fieldName}.{extension} const fileName = `${documentTypeXid}_${fieldName}.${fileExtension}`; const sanitizedFileName = sanitizeFileName(fileName); s3Key = `Documents/Host/${hostId}/parent_company/${sanitizedFileName}`; @@ -197,7 +191,6 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< throw new ApiError(400, 'Invalid folder type or missing documentTypeXid/fieldName'); } - // Upload new file (S3 will automatically replace if same key exists) await s3 .upload({ Bucket: config.aws.bucketName, @@ -225,7 +218,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< console.log('Company logo uploaded:', logoPath); } - // 6) Zod validation for companyDetails (includes optional parentCompany) + // 6) Zod validation for companyDetails const companyValidation = hostCompanyDetailsSchema.safeParse(companyDetailsRaw); if (!companyValidation.success) { const message = companyValidation.error.issues.map((i) => i.message).join(', '); @@ -246,7 +239,7 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< } const documentsMetadata = documentsMetadataRaw.map((d: any) => ({ ...d, - owner: d.owner || 'host', // default to host + owner: d.owner || 'host', })); // 8) Map uploaded files to metadata @@ -260,12 +253,14 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< const hostDocs = documentMetadata.filter((d) => d.owner === 'host'); const parentDocs = documentMetadata.filter((d) => d.owner === 'parent'); - // 10) Ensure required docs for host exist (IDs 1,2,3,4) - const hostUploadedTypes = hostDocs.map((d) => d.documentTypeXid); - const requiredHostTypes = Object.values(REQUIRED_DOC_TYPES); - const missingHostDocs = requiredHostTypes.filter((typeId) => !hostUploadedTypes.includes(typeId)); - if (missingHostDocs.length > 0) { - throw new ApiError(400, `Missing mandatory documents for host: ${missingHostDocs.join(', ')}`); + // 10) If NOT draft, validate required documents + if (!isDraft) { + const hostUploadedTypes = hostDocs.map((d) => d.documentTypeXid); + const requiredHostTypes = Object.values(REQUIRED_DOC_TYPES); + const missingHostDocs = requiredHostTypes.filter((typeId) => !hostUploadedTypes.includes(typeId)); + if (missingHostDocs.length > 0) { + throw new ApiError(400, `Missing mandatory documents for host: ${missingHostDocs.join(', ')}`); + } } // 11) If isSubsidairy === true and parentCompany provided -> validate parent company & docs @@ -282,61 +277,65 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< } parsedParentCompany = parsedCompany.parentCompany; - const parentUploadedTypes = parentDocs.map((d) => d.documentTypeXid); - const requiredParentTypes = Object.values(REQUIRED_DOC_TYPES); - const missingParentDocs = requiredParentTypes.filter((typeId) => !parentUploadedTypes.includes(typeId)); - if (missingParentDocs.length > 0) { - throw new ApiError(400, `Missing mandatory documents for parent company: ${missingParentDocs.join(', ')}`); + // If NOT draft, validate required parent documents + if (!isDraft) { + const parentUploadedTypes = parentDocs.map((d) => d.documentTypeXid); + const requiredParentTypes = Object.values(REQUIRED_DOC_TYPES); + const missingParentDocs = requiredParentTypes.filter((typeId) => !parentUploadedTypes.includes(typeId)); + if (missingParentDocs.length > 0) { + throw new ApiError(400, `Missing mandatory documents for parent company: ${missingParentDocs.join(', ')}`); + } } } - // 12) Upload files to S3 with proper folder structure using fieldName for filenames + // 12) Upload files to S3 (same for both draft and final submission) const uploadedHostDocs: Array<{ documentTypeXid: number; documentName: string; filePath: string }> = []; const uploadedParentDocs: Array<{ documentTypeXid: number; documentName: string; filePath: string }> = []; - // Upload host documents with proper folder structure using fieldName + // Upload host documents for (const doc of hostDocs) { const filePath = await uploadToS3( doc.file.buffer, doc.file.mimeType, - doc.file.fileName, // Use original file name for extension + doc.file.fileName, 'documents', doc.documentTypeXid, - doc.fieldName // Use fieldName for the filename + doc.fieldName ); uploadedHostDocs.push({ documentTypeXid: doc.documentTypeXid, - documentName: doc.fieldName, // Keep documentName for database + documentName: doc.fieldName, filePath, }); } - // Upload parent company documents with proper folder structure using fieldName + // Upload parent company documents if (parentDocs.length > 0) { for (const doc of parentDocs) { const filePath = await uploadToS3( doc.file.buffer, doc.file.mimeType, - doc.file.fileName, // Use original file name for extension + doc.file.fileName, 'parent_company', doc.documentTypeXid, - doc.fieldName // Use fieldName for the filename + doc.fieldName ); uploadedParentDocs.push({ documentTypeXid: doc.documentTypeXid, - documentName: doc.documentName, // Keep documentName for database + documentName: doc.documentName, filePath, }); } } - // 13) Persist using hostService + // 13) Persist using hostService - PASS isDraft flag const createdOrUpdated = await hostService.addOrUpdateCompanyDetails( userInfo.id, parsedCompany, uploadedHostDocs, parsedParentCompany, - uploadedParentDocs + uploadedParentDocs, + isDraft // Pass the isDraft flag ); if (!createdOrUpdated) throw new ApiError(400, 'Failed to add/update company details.'); @@ -347,25 +346,28 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< console.log(`Host created with ID: ${hostId}`); } - const getSuggestionDetails = await hostService.getSuggestionDetails(userInfo.id) + // 14) Send emails only for FINAL submission (not draft) + if (!isDraft) { + const getSuggestionDetails = await hostService.getSuggestionDetails(userInfo.id) - if (getSuggestionDetails.hostDetails.accountManagerXid !== null) { - await sendEmailToAM( - getSuggestionDetails.hostDetails.accountManager.emailAddress, - getSuggestionDetails.hostDetails.accountManager.firstName, - getSuggestionDetails.hostDetails.companyName, - getSuggestionDetails.hostDetails.hostRefNumber - ); - } else { - await sendEmailToMinglarAdmin( - config.MinglarAdminEmail, - config.MinglarAdminName, - getSuggestionDetails.hostDetails.companyName, - getSuggestionDetails.hostDetails.hostRefNumber - ) + if (getSuggestionDetails.hostDetails.accountManagerXid !== null) { + await sendEmailToAM( + getSuggestionDetails.hostDetails.accountManager.emailAddress, + getSuggestionDetails.hostDetails.accountManager.firstName, + getSuggestionDetails.hostDetails.companyName, + getSuggestionDetails.hostDetails.hostRefNumber + ); + } else { + await sendEmailToMinglarAdmin( + config.MinglarAdminEmail, + config.MinglarAdminName, + getSuggestionDetails.hostDetails.companyName, + getSuggestionDetails.hostDetails.hostRefNumber + ) + } } - // 14) Success + // 15) Success response return { statusCode: 200, headers: { @@ -374,8 +376,14 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< }, body: JSON.stringify({ success: true, - message: 'Company (and parent if provided) details and documents uploaded successfully.', - data: { id: createdOrUpdated.id, hostRefNumber: (createdOrUpdated as any).hostRefNumber } + message: isDraft + ? 'Company details saved as draft successfully.' + : 'Company (and parent if provided) details and documents uploaded successfully.', + data: { + id: createdOrUpdated.id, + hostRefNumber: (createdOrUpdated as any).hostRefNumber, + isDraft + } }), }; } catch (error: any) { diff --git a/src/modules/host/handlers/getByIdPQQ.ts b/src/modules/host/handlers/getByIdPQQ.ts index def1575..8c016d4 100644 --- a/src/modules/host/handlers/getByIdPQQ.ts +++ b/src/modules/host/handlers/getByIdPQQ.ts @@ -22,17 +22,10 @@ export const handler = safeHandler(async ( const userInfo = await verifyMinglarAdminHostToken(token); const userId = Number(userInfo.id); - let body: { question_xid: number, activity_xid: number }; + const question_xid = Number(event.queryStringParameters?.question_xid); + const activity_xid = Number(event.queryStringParameters?.activity_xid); - try { - body = event.body ? JSON.parse(event.body) : {}; - } catch (error) { - throw new ApiError(400, 'Invalid JSON in request body'); - } - - const { question_xid, activity_xid } = body; - - if(!question_xid || !activity_xid){ + if (!question_xid || !activity_xid) { throw new ApiError(400, "Question and activity xid are required.") } diff --git a/src/modules/host/handlers/getPQQScore.ts b/src/modules/host/handlers/getPQQScore.ts index 24f9fc3..229272b 100644 --- a/src/modules/host/handlers/getPQQScore.ts +++ b/src/modules/host/handlers/getPQQScore.ts @@ -182,14 +182,14 @@ export const handler = safeHandler(async (event: APIGatewayProxyEvent): Promise< if (existingHeader) { console.log("🔄 Updating existing PQQ header"); // Update existing header (comments can be null) - const header = await pqqService.updateHeader( + header = await pqqService.updateHeader( existingHeader.id, comments ); } else { console.log("🆕 Creating new PQQ header"); // Create new header (comments can be null) - const header = await pqqService.createHeader( + header = await pqqService.createHeader( activityXid, pqqQuestionXid, pqqAnswerXid, diff --git a/src/modules/host/services/host.service.ts b/src/modules/host/services/host.service.ts index c413bb7..6fddf52 100644 --- a/src/modules/host/services/host.service.ts +++ b/src/modules/host/services/host.service.ts @@ -9,7 +9,7 @@ import { z } from 'zod'; import { hostCompanyDetailsSchema } from '@/common/utils/validation/host/hostCompanyDetails.validation'; import { HOST_STATUS_DISPLAY, HOST_STATUS_INTERNAL, STEPPER } from '@/common/utils/constants/host.constant'; import { MINGLAR_STATUS_DISPLAY, MINGLAR_STATUS_INTERNAL } from '@/common/utils/constants/minglar.constant'; -import { ROLE, USER_STATUS } from '@/common/utils/constants/common.constant'; +import { ROLE, ROLE_NAME, USER_STATUS } from '@/common/utils/constants/common.constant'; import { getPresignedUrl } from '@/common/middlewares/aws/getPreSignedUrl'; import config from '@/config/config'; @@ -281,7 +281,8 @@ export class HostService { companyData: HostCompanyDetailsInput, documents: HostDocumentInput[], parentCompanyData?: any | null, - parentDocuments?: HostDocumentInput[] + parentDocuments?: HostDocumentInput[], + isDraft: boolean = false // Add isDraft parameter with default false ) { return await this.prisma.$transaction(async (tx) => { // Check if host already has a company @@ -290,13 +291,32 @@ export class HostService { include: { hostParent: true }, }); + // Determine status based on isDraft flag + const hostStatusInternal = isDraft + ? HOST_STATUS_INTERNAL.DRAFT + : HOST_STATUS_INTERNAL.HOST_SUBMITTED; + + const hostStatusDisplay = isDraft + ? HOST_STATUS_DISPLAY.DRAFT + : HOST_STATUS_DISPLAY.UNDER_REVIEW; + + const minglarStatusInternal = isDraft + ? MINGLAR_STATUS_INTERNAL.DRAFT + : MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW; + + const minglarStatusDisplay = isDraft + ? MINGLAR_STATUS_DISPLAY.DRAFT + : MINGLAR_STATUS_DISPLAY.NEW; + // CREATE if (!existingHostCompany) { - // Optionally check unique registration number - const existingByPan = await tx.hostHeader.findFirst({ - where: { panNumber: companyData.panNumber }, - }); - if (existingByPan) throw new ApiError(400, 'Company already exists with this pan/bin number'); + // Optionally check unique registration number (only for final submission) + if (!isDraft) { + const existingByPan = await tx.hostHeader.findFirst({ + where: { panNumber: companyData.panNumber }, + }); + if (existingByPan) throw new ApiError(400, 'Company already exists with this pan/bin number'); + } const refNumber = await this.generateHostRefNumber(tx); @@ -323,12 +343,11 @@ export class HostService { facebookUrl: companyData.facebookUrl || null, linkedinUrl: companyData.linkedinUrl || null, twitterUrl: companyData.twitterUrl || null, - // currencyXid: companyData.currencyXid, stepper: STEPPER.UNDER_REVIEW, - hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, - hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, - adminStatusInternal: MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW, - adminStatusDisplay: MINGLAR_STATUS_DISPLAY.NEW, + hostStatusInternal: hostStatusInternal, + hostStatusDisplay: hostStatusDisplay, + adminStatusInternal: minglarStatusInternal, + adminStatusDisplay: minglarStatusDisplay, }, }); @@ -385,7 +404,6 @@ export class HostService { } // UPDATE existing - // Prevent changing hostRefNumber const updatedHost = await tx.hostHeader.update({ where: { id: existingHostCompany.id }, data: { @@ -408,9 +426,11 @@ export class HostService { facebookUrl: companyData.facebookUrl || null, linkedinUrl: companyData.linkedinUrl || null, twitterUrl: companyData.twitterUrl || null, - // currencyXid: companyData.currencyXid, - stepper: STEPPER.UNDER_REVIEW - // hostRefNumber: DO NOT UPDATE + stepper: STEPPER.UNDER_REVIEW, + hostStatusInternal: hostStatusInternal, + hostStatusDisplay: hostStatusDisplay, + adminStatusInternal: minglarStatusInternal, + adminStatusDisplay: minglarStatusDisplay }, }); @@ -428,7 +448,6 @@ export class HostService { // Parent company create/update and replace parent docs if (companyData.isSubsidairy) { - // existingHostCompany.hostParent may be array or single object depending on Prisma schema let parentRecord = (existingHostCompany as any).hostParent; if (Array.isArray(parentRecord)) parentRecord = parentRecord[0]; @@ -519,6 +538,19 @@ export class HostService { } } + const hostDetails = await this.prisma.hostHeader.findFirst({ + where: { userXid: user_xid }, + }) + + await this.prisma.hostTrack.create({ + data: { + hostXid: hostDetails.id, + updatedByRole: ROLE_NAME.HOST, + updatedByXid: user_xid, + trackStatus: hostDetails.hostStatusInternal, + } + }) + return updatedHost; }); } @@ -668,7 +700,12 @@ export class HostService { let totalMaxPoints = 0; // For category-wise scoring - const categories: any = {}; // { [categoryId]: { userPoints, maxPoints, name } } + const categories: Record = {}; for (const item of answers) { const question = item.pqqQuestions; @@ -680,7 +717,7 @@ export class HostService { totalUserPoints += userPoints; totalMaxPoints += maxPoints; - // Category info + // Category const category = question.pqqSubCategories.category; const categoryId = category.id; @@ -689,7 +726,7 @@ export class HostService { categoryId, categoryName: category.categoryName, userPoints: 0, - maxPoints: 0 + maxPoints: 0, }; } @@ -698,19 +735,26 @@ export class HostService { } // Overall percent - const overallPercentage = totalMaxPoints > 0 - ? (totalUserPoints / totalMaxPoints) * 100 - : 0; + const overallPercentage = + totalMaxPoints > 0 ? (totalUserPoints / totalMaxPoints) * 100 : 0; - // Category percentages - const categoryWise: any = {}; + // ---------- 🔥 ONLY FIRST 2 CATEGORIES ---------- + const categoryArray = Object.values(categories); - for (const catId in categories) { - const c = categories[catId]; + // Sort by categoryId (or change to displayOrder if needed) + categoryArray.sort((a, b) => a.categoryId - b.categoryId); + + // Take only first 2 categories + const topTwo = categoryArray.slice(0, 2); + + const categoryWise: Record = {}; + + for (const c of topTwo) { categoryWise[c.categoryName] = c.maxPoints > 0 ? (c.userPoints / c.maxPoints) * 100 : 0; } + // Return final score object return { overallPercentage, categoryWise @@ -718,6 +762,7 @@ export class HostService { } + async createHeader( activityXid: number, pqqQuestionXid: number, diff --git a/src/modules/minglaradmin/handlers/getAllOnboardingHosts.ts b/src/modules/minglaradmin/handlers/getAllOnboardingHosts.ts new file mode 100644 index 0000000..bb17d6e --- /dev/null +++ b/src/modules/minglaradmin/handlers/getAllOnboardingHosts.ts @@ -0,0 +1,53 @@ +import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin'; +import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; +import { PrismaService } from '../../../common/database/prisma.service'; +import { safeHandler } from '../../../common/utils/handlers/safeHandler'; +import ApiError from '../../../common/utils/helper/ApiError'; +import { MinglarService } from '../services/minglar.service'; + +const prismaService = new PrismaService(); +const minglarService = new MinglarService(prismaService); + +/** + * Get all host applications handler + * Returns host details with status, submission date, and account manager info + */ +export const handler = safeHandler(async ( + event: APIGatewayProxyEvent, + context?: Context +): Promise => { + // Verify authentication token + const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token']; + if (!token) { + throw new ApiError(401, 'This is a protected route. Please provide a valid token.'); + } + + // Verify token and get user info + const userInfo = await verifyOnlyMinglarAdminToken(token); + + // Get user details including role + const user = await prismaService.user.findUnique({ + where: { id: userInfo.id }, + select: { id: true, roleXid: true } + }); + + if (!user) { + throw new ApiError(404, 'User not found'); + } + + // Get all host applications from service based on user role + const hostApplications = await minglarService.getAllOnboardingHostApplications(); + + return { + statusCode: 200, + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }, + body: JSON.stringify({ + success: true, + message: 'Host applications retrieved successfully', + data: hostApplications, + }), + }; +}); diff --git a/src/modules/minglaradmin/handlers/getOnboardingNewApplications.ts b/src/modules/minglaradmin/handlers/getOnboardingNewApplications.ts new file mode 100644 index 0000000..34ca161 --- /dev/null +++ b/src/modules/minglaradmin/handlers/getOnboardingNewApplications.ts @@ -0,0 +1,53 @@ +import { verifyOnlyMinglarAdminToken } from '@/common/middlewares/jwt/authForOnlyMinglarAdmin'; +import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; +import { PrismaService } from '../../../common/database/prisma.service'; +import { safeHandler } from '../../../common/utils/handlers/safeHandler'; +import ApiError from '../../../common/utils/helper/ApiError'; +import { MinglarService } from '../services/minglar.service'; + +const prismaService = new PrismaService(); +const minglarService = new MinglarService(prismaService); + +/** + * Get all host applications handler + * Returns host details with status, submission date, and account manager info + */ +export const handler = safeHandler(async ( + event: APIGatewayProxyEvent, + context?: Context +): Promise => { + // Verify authentication token + const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token']; + if (!token) { + throw new ApiError(401, 'This is a protected route. Please provide a valid token.'); + } + + // Verify token and get user info + const userInfo = await verifyOnlyMinglarAdminToken(token); + + // Get user details including role + const user = await prismaService.user.findUnique({ + where: { id: userInfo.id }, + select: { id: true, roleXid: true } + }); + + if (!user) { + throw new ApiError(404, 'User not found'); + } + + // Get all host applications from service based on user role + const hostApplications = await minglarService.getAllOnboardingHostApplications_New(); + + return { + statusCode: 200, + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }, + body: JSON.stringify({ + success: true, + message: 'Host applications retrieved successfully', + data: hostApplications, + }), + }; +}); diff --git a/src/modules/minglaradmin/services/minglar.service.ts b/src/modules/minglaradmin/services/minglar.service.ts index 1fb9f29..c47b28d 100644 --- a/src/modules/minglaradmin/services/minglar.service.ts +++ b/src/modules/minglaradmin/services/minglar.service.ts @@ -1,4 +1,4 @@ -import { ROLE, USER_STATUS } from '@/common/utils/constants/common.constant'; +import { ROLE, ROLE_NAME, USER_STATUS } from '@/common/utils/constants/common.constant'; import { HOST_STATUS_DISPLAY, HOST_STATUS_INTERNAL, @@ -19,7 +19,7 @@ import { sendAMEmailForHostAssign } from './AMEmail.service'; @Injectable() export class MinglarService { - constructor(private prisma: PrismaService) {} + constructor(private prisma: PrismaService) { } async createPassword(user_xid: number, password: string): Promise { // Find user by id @@ -597,7 +597,7 @@ export class MinglarService { userStatus && userStatus.trim().toLowerCase() === MINGLAR_STATUS_DISPLAY.NEW.toLowerCase() ) { - filters.adminStatusDisplay = MINGLAR_STATUS_DISPLAY.NEW; + filters.adminStatusInternal = MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW; } /** ----------------------------------- @@ -670,6 +670,85 @@ export class MinglarService { })); } + async getAllOnboardingHostApplications() { + return await this.prisma.hostHeader.findMany({ + where: { isActive: true }, + select: { + id: true, + hostRefNumber: true, + companyName: true, + adminStatusDisplay: true, + assignedOn: true, + accountManagerXid: true, + createdAt: true, + user: { + select: { + id: true, + firstName: true, + lastName: true, + } + }, + accountManager: { + select: { + id: true, + firstName: true, + lastName: true, + profileImage: true + } + } + } + }) + } + + + async getAllOnboardingHostApplications_New() { + return await this.prisma.hostHeader.findMany({ + where: { isActive: true, adminStatusInternal: MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW }, + select: { + id: true, + hostRefNumber: true, + companyName: true, + adminStatusDisplay: true, + assignedOn: true, + accountManagerXid: true, + createdAt: true, + cities: { + select: { + id: true, + cityName: true + } + }, + countries: { + select: { + id: true, + countryName: true, + } + }, + states: { + select: { + id: true, + stateName: true + } + }, + user: { + select: { + id: true, + firstName: true, + lastName: true, + } + }, + accountManager: { + select: { + id: true, + firstName: true, + lastName: true, + profileImage: true + } + } + } + }) + } + async getAllCoadminAndAM() { // 1. Fetch all required users (Admin, Co-Admin, AM) @@ -770,7 +849,7 @@ export class MinglarService { if ( hostDetails.adminStatusInternal !== - MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED && + MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED && hostDetails.adminStatusDisplay !== MINGLAR_STATUS_DISPLAY.AM_NOT_ASSIGNED ) { throw new ApiError(400, 'Invalid host status'); @@ -861,7 +940,7 @@ export class MinglarService { ) { // Check if host exists const ActivityHeader = await this.prisma.activityPQQheader.findUnique({ - where: { id: activity_pqq_header_xid , isActive:true}, + where: { id: activity_pqq_header_xid, isActive: true }, select: { id: true }, }); @@ -934,41 +1013,65 @@ export class MinglarService { } async acceptHostApplication(host_xid: number, user_xid: number) { - return await this.prisma.hostHeader.update({ - where: { - id: host_xid, - hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, - hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, - adminStatusInternal: MINGLAR_STATUS_INTERNAL.AM_TO_REVIEW, - adminStatusDisplay: MINGLAR_STATUS_DISPLAY.TO_REVIEW, - }, - data: { - hostStatusInternal: HOST_STATUS_INTERNAL.APPROVED, - hostStatusDisplay: HOST_STATUS_DISPLAY.APPROVED, - adminStatusInternal: MINGLAR_STATUS_INTERNAL.AM_APPROVED, - adminStatusDisplay: MINGLAR_STATUS_DISPLAY.APPROVED, - stepper: STEPPER.COMPANY_DETAILS_APPROVED, - }, - }); + return await this.prisma.$transaction(async (tx) => { + await this.prisma.hostHeader.update({ + where: { + id: host_xid, + hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, + hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, + adminStatusInternal: MINGLAR_STATUS_INTERNAL.AM_TO_REVIEW, + adminStatusDisplay: MINGLAR_STATUS_DISPLAY.TO_REVIEW, + }, + data: { + hostStatusInternal: HOST_STATUS_INTERNAL.APPROVED, + hostStatusDisplay: HOST_STATUS_DISPLAY.APPROVED, + adminStatusInternal: MINGLAR_STATUS_INTERNAL.AM_APPROVED, + adminStatusDisplay: MINGLAR_STATUS_DISPLAY.APPROVED, + stepper: STEPPER.COMPANY_DETAILS_APPROVED, + }, + }); + + await this.prisma.hostTrack.create({ + data: { + hostXid: host_xid, + updatedByRole: ROLE_NAME.ACCOUNT_MANAGER, + updatedByXid: user_xid, + trackStatus: MINGLAR_STATUS_INTERNAL.AM_APPROVED, + } + }) + }) + + } async acceptHostApplicationMinglarAdmin(host_xid: number, user_xid: number) { - return await this.prisma.hostHeader.update({ - where: { - id: host_xid, - hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, - hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, - adminStatusInternal: MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW, - adminStatusDisplay: MINGLAR_STATUS_DISPLAY.NEW, - }, - data: { - isApproved: true, - hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, - hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, - adminStatusInternal: MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED, - adminStatusDisplay: MINGLAR_STATUS_DISPLAY.AM_NOT_ASSIGNED, - }, - }); + return await this.prisma.$transaction(async (tx) => { + await tx.hostHeader.update({ + where: { + id: host_xid, + hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, + hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, + adminStatusInternal: MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW, + adminStatusDisplay: MINGLAR_STATUS_DISPLAY.NEW, + }, + data: { + isApproved: true, + hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, + hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, + adminStatusInternal: MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED, + adminStatusDisplay: MINGLAR_STATUS_DISPLAY.AM_NOT_ASSIGNED, + }, + }); + + await this.prisma.hostTrack.create({ + data: { + hostXid: host_xid, + updatedByRole: ROLE_NAME.MINGLAR_ADMIN, + updatedByXid: user_xid, + trackStatus: MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED, + } + }) + }) } async rejectHostApplication(host_xid: number, user_xid: number) { @@ -994,6 +1097,15 @@ export class MinglarService { }, }); + await this.prisma.hostTrack.create({ + data: { + hostXid: hostDetails.id, + updatedByRole: ROLE_NAME.MINGLAR_ADMIN, + updatedByXid: user_xid, + trackStatus: MINGLAR_STATUS_INTERNAL.ADMIN_REJECTED, + } + }) + await tx.user.update({ where: { id: hostDetails.userXid }, data: { @@ -1004,25 +1116,36 @@ export class MinglarService { } async rejectHostApplicationAM(host_xid: number, user_xid: number) { - const hostDetails = await this.prisma.hostHeader.findFirst({ - where: { id: host_xid }, - select: { id: true, userXid: true }, - }); - if (!hostDetails) { - throw new Error('Host not found'); - } - await this.prisma.hostHeader.update({ - where: { - id: host_xid, - hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, - hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, - }, - data: { - hostStatusInternal: HOST_STATUS_INTERNAL.REJECTED, - hostStatusDisplay: HOST_STATUS_DISPLAY.REJECTED, - adminStatusInternal: MINGLAR_STATUS_INTERNAL.ADMIN_REJECTED, - adminStatusDisplay: MINGLAR_STATUS_DISPLAY.REJECTED, - }, - }); + return await this.prisma.$transaction(async (tx) => { + const hostDetails = await this.prisma.hostHeader.findFirst({ + where: { id: host_xid }, + select: { id: true, userXid: true }, + }); + if (!hostDetails) { + throw new Error('Host not found'); + } + await this.prisma.hostHeader.update({ + where: { + id: host_xid, + hostStatusInternal: HOST_STATUS_INTERNAL.HOST_SUBMITTED, + hostStatusDisplay: HOST_STATUS_DISPLAY.UNDER_REVIEW, + }, + data: { + hostStatusInternal: HOST_STATUS_INTERNAL.HOST_TO_UPDATE, + hostStatusDisplay: HOST_STATUS_DISPLAY.ENHANCING, + adminStatusInternal: MINGLAR_STATUS_INTERNAL.AM_REJECTED, + adminStatusDisplay: MINGLAR_STATUS_DISPLAY.ENHANCING, + }, + }); + + await this.prisma.hostTrack.create({ + data: { + hostXid: hostDetails.id, + updatedByRole: ROLE_NAME.ACCOUNT_MANAGER, + updatedByXid: user_xid, + trackStatus: MINGLAR_STATUS_INTERNAL.AM_REJECTED, + } + }) + }) } } diff --git a/src/modules/prepopulate/handlers/getBranchByBank.ts b/src/modules/prepopulate/handlers/getBranchByBank.ts new file mode 100644 index 0000000..89d99e3 --- /dev/null +++ b/src/modules/prepopulate/handlers/getBranchByBank.ts @@ -0,0 +1,53 @@ +import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from "aws-lambda"; +import { PrismaService } from "../../../common/database/prisma.service"; +import { safeHandler } from "../../../common/utils/handlers/safeHandler"; +import ApiError from "../../../common/utils/helper/ApiError"; +import { PrePopulateService } from "../services/prepopulate.service"; +import { verifyHostToken } from "@/common/middlewares/jwt/authForHost"; + +const prismaService = new PrismaService(); +const prePopulateService = new PrePopulateService(prismaService); + +export const handler = safeHandler(async ( + event: APIGatewayProxyEvent, + context?: Context +): Promise => { + + // 1) Token check + const token = + event.headers["x-auth-token"] || + event.headers["X-Auth-Token"]; + + if (!token) { + throw new ApiError( + 400, + "This is a protected route. Please provide a valid token." + ); + } + + // 2) Authenticate user + await verifyHostToken(token); + + // 3) Get bankXid from query params + const bankXid = Number(event.queryStringParameters?.bankXid); + + if (!bankXid || isNaN(bankXid)) { + throw new ApiError(400, "Valid bankXid is required in query params."); + } + + // 4) Fetch branches for the bank + const branches = await prePopulateService.getBankBranchesByBankId(bankXid); + + return { + statusCode: 200, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, + body: JSON.stringify({ + success: true, + message: "Bank branches retrieved successfully", + data: branches + }), + }; +}); diff --git a/src/modules/prepopulate/handlers/getCityByState.ts b/src/modules/prepopulate/handlers/getCityByState.ts new file mode 100644 index 0000000..26982fa --- /dev/null +++ b/src/modules/prepopulate/handlers/getCityByState.ts @@ -0,0 +1,53 @@ +import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from "aws-lambda"; +import { PrismaService } from "../../../common/database/prisma.service"; +import { safeHandler } from "../../../common/utils/handlers/safeHandler"; +import ApiError from "../../../common/utils/helper/ApiError"; +import { PrePopulateService } from "../services/prepopulate.service"; +import { verifyHostToken } from "@/common/middlewares/jwt/authForHost"; + +const prismaService = new PrismaService(); +const prePopulateService = new PrePopulateService(prismaService); + +export const handler = safeHandler(async ( + event: APIGatewayProxyEvent, + context?: Context +): Promise => { + + // 1) Token check + const token = + event.headers["x-auth-token"] || + event.headers["X-Auth-Token"]; + + if (!token) { + throw new ApiError( + 400, + "This is a protected route. Please provide a valid token." + ); + } + + // 2) Authenticate user + await verifyHostToken(token); + + // 3) Get bankXid from query params + const stateXid = Number(event.queryStringParameters?.stateXid); + + if (!stateXid || isNaN(stateXid)) { + throw new ApiError(400, "Valid stateXid is required in query params."); + } + + // 4) Fetch branches for the bank + const branches = await prePopulateService.getCityByStateId(stateXid); + + return { + statusCode: 200, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, + body: JSON.stringify({ + success: true, + message: "Bank branches retrieved successfully", + data: branches + }), + }; +}); diff --git a/src/modules/prepopulate/services/prepopulate.service.ts b/src/modules/prepopulate/services/prepopulate.service.ts index f264326..17428d5 100644 --- a/src/modules/prepopulate/services/prepopulate.service.ts +++ b/src/modules/prepopulate/services/prepopulate.service.ts @@ -3,7 +3,7 @@ import { PrismaService } from '../../../common/database/prisma.service'; @Injectable() export class PrePopulateService { - constructor(private prisma: PrismaService) {} + constructor(private prisma: PrismaService) { } async getAllBankDetails() { return await this.prisma.banks.findMany({ @@ -23,6 +23,37 @@ export class PrePopulateService { }); } + async getBankBranchesByBankId(bankXid: number) { + return await this.prisma.bankBranches.findMany({ + where: { + bankXid, + isActive: true, + deletedAt: null + }, + select: { + id: true, + branchAddress: true, + ifscCode: true, + } + }); + } + + + async getCityByStateId(stateXid: number) { + return await this.prisma.cities.findMany({ + where: { + stateXid, + isActive: true, + deletedAt: null + }, + select: { + id: true, + cityName: true, + } + }); + } + + async getAllCurrencyDetails() { return await this.prisma.currencies.findMany({ where: { @@ -32,31 +63,31 @@ export class PrePopulateService { }); } - async getAllPQQQuesAndAns() { - return await this.prisma.pQQCategories.findMany({ - where: { isActive: true }, - include: { - pqqsubCategories: { - include: { - questions: { - include: { - PQQAnswers: { - orderBy: { - displayOrder: 'asc' - } - } - }, - orderBy: { - displayOrder: 'asc' - } - } - }, - orderBy: { displayOrder: 'asc' } + async getAllPQQQuesAndAns() { + return await this.prisma.pQQCategories.findMany({ + where: { isActive: true }, + include: { + pqqsubCategories: { + include: { + questions: { + include: { + PQQAnswers: { + orderBy: { + displayOrder: 'asc' + } } - }, - orderBy: { displayOrder: 'asc' } - }); - } + }, + orderBy: { + displayOrder: 'asc' + } + } + }, + orderBy: { displayOrder: 'asc' } + } + }, + orderBy: { displayOrder: 'asc' } + }); + } async getAllDocumentTypeWithCountryStateCity() { const [documentDetails, countryDetails, stateDetails, cityDetails] =