Skip to content

Commit

Permalink
feat: add duplicates v2 feature
Browse files Browse the repository at this point in the history
* refactor: create duplicates pages

* refactor: update applications link

* refactor: refactor application routes

* refactor: update active path detection

* fix: export SideNav component and add className

* refactor: cleanup & update table cols

* refactor: refactor application export and pages structure

* feat: create reusable sidenav component

* feat: update header active paths

* feat: integrate side nav

* feat: adding backend for applicaiton sidenav

* feat: changes applicaiton seeeds

* fix: updates per morgan

* fix: update the "all applications" translation

* refactor: create helper file and move shared part

* feat: integrate resolved apps view

* refactor: cleanup

* feat: hides pending subcats and footer with scan

* style: childrenItems comment

* feat: adds includeDemographics param to useApplicationsExport

Co-authored-by: Yazeed Loonat <[email protected]>
Co-authored-by: Sean Albert <[email protected]>

refactor: create duplicates pages

fix: remove export button from duplicate pages, fix table widths (#3006)

2835/async duplicates processing (#2961)

* feat(backend): add bull job scheduler for afs processing

* feat(backend): move AFS processing logic to async consumer

* feat(backend): improve afs async processing

* test: updates imports

* perf: select fields for listings afs

* fix: undo app repo select

* feat: sets rule_key for existing afs

* Fix code style issues with Prettier

* feat: adds afs process controller

* fix: updates seed and afs duplicate procesing call

* perf: clean up afs migration

Co-authored-by: Michal Plebanski <[email protected]>
Co-authored-by: Lint Action <[email protected]>

fix: add-afs migration update

build: debug migration

build: debug migration

feat: allow marking status for application flagged sets (#3020)

Syncs dev into duplicates branch (via rebase) (#3093)

* fix: add a11y linting tools and fix errors (#2974)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* 2513/email markup fixes from qa (#2909)

* fix: address QA testing issues for confirmation email template

* fix: use the right keys for the translation update

Co-authored-by: Sean Albert <[email protected]>

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* 2918/add button group (#2958)

* feat: add ButtonGroup component

* feat: add ButtonGroup component

Also add a title tooltip to swatch in docs
Update 2nd Generation badge to primary blue instead of red

* Fix code style issues with Prettier

* fix: clean up button group styles, add react key

* test: ButtonGroup, add to exports

Co-authored-by: Lint Action <[email protected]>

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* refactor!: preferences & programs data model merged (#2904)

BREAKING CHANGE: The preference and program entities have been merged into a single entity called MultiselectQuestion

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: update to get migration to run on dev (#2987)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: Migration hotfix 2 (#2990)

* fix: update to get migration to run on dev

* fix: updates to migrations

* fix: updates to migrations

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* feat: show preference details on listing form (#2989)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: update to fix some lingering migration issues (#2991)

* fix: update to fix some lingering migration issues

* test: updates enablePartnerSettings seed

* test: update to tests

Co-authored-by: Sean Albert <[email protected]>

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* feat: adds the ability to manage preference for partner admins (#2985)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: styling precedence issues in preferences (#2994)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: updates translation migration files (#2995)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: add margin in contact section (#2999)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* 2919/progress bar update (#2950)

* fix: added a11y labeling

* fix: base view for bar progress

* fix: support for different colors

* fix: style passed as prop

* fix: wip conversion to vanilla css

* fix: completed conversion to vanilla css

* fix: testing different mobile views

* fix: drop labels on mobile

* fix: removing remaining tailwind

* fix: cleaner css class construction

* fix: added css variables

* fix: align label font color

* fix: refining css theming

* fix: added documentation

* fix: added missing css var

* fix: align default sizing

* fix: stricter typing for nav style

* fix: removed empty linking

* fix: remove clickable ux

* fix: removed unused css

* fix: style updates per Jesse

* fix: integrating a11y updates

* fix: removed unneccessary tabbing

* fix: bar label css updates

* fix: sr a11y for progress states

* fix: gen 2 flagging + removed unused strings

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* 2940/media modal sync (#2968)

* fix: media card sync

* fix: modal padding to prevent overlap

* fix: added media card documentation

* fix: minor documentation change

* fix: replace a11y css

* fix: consistent css spacing

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* refactor: code cleanliness improvements (#2784)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix(login): too many login attempts fix (#2988)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: null app fee showing null string (#3016)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* 2891/add sign up to beginning of application flow (#3018)

* feat: add sign-up to beginning of application flow

* refactor: change login panel in beginning of application flow to use ActionBlock

* feat: test create account should redirect to /create-account

* feat: design improvements for choose language panel

* test: remove redundant test

* chore(release): version

 - @bloom-housing/[email protected]

* fix: remove select text from multiselect application questions (#3017)

* chore(release): version

 - @bloom-housing/[email protected]

* fix: table columns should take up full width (#3005)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* refactor: allow custom strings in all components (#3012)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* refactor: alert box v2 styling refactor (#3014)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* chore: axe core a11y dynamic linting (#3000)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix(application): remove programs from autofill (#3021)

* chore(release): version

 - @bloom-housing/[email protected]

* chore: remove all dependecies of moment (#3027)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: migration for application export clean up (#3036)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: add unit tests to partners (#3023)

* fix: add unit tests to partners

* Fix code style issues with Prettier

Co-authored-by: Lint Action <[email protected]>

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: return N/A string if rent and income is NaN (#3040)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* 2920/bordered field option (#3054)

* fix: border css

* fix: removed unused lines

* fix: dynamic background

* fix: corrected class position

* fix: color correction

* fix: reformatted css approach

* fix: improved storybook testing

* fix: removed duplicate css

* fix: minimize tailwind variables

* fix: css theming

* fix: box color correction

* fix: css variable typo

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* feat: allow alerts to be sticky under page header (#3050)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: updated css class naming (#483) (#3073)

Co-authored-by: ColinBuyck <[email protected]>

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* Update dropzone for single upload (#3070)

* fix: default dropzone upload to single file, add maxFiles

* fix: simplify boolean expression

* fix: sync latest style updates from Detroit

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* feat: add confirm modal when copying a preference (#3041)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: complete app section while navigating

* chore(release): version

 - @bloom-housing/[email protected]

* fix: update email confirmation what to expect copy (#3061)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* chore: add tests back to eslint (#3077)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* 3030/what to expect visual updates (#3063)

* feat: change available units to vacant units

* feat: show vacant units, open waitlist as pill tags in listings

* feat: change units to vacant units in summary table

* feat: update translations to use new key that refers to vacant units

* feat: use customClass as last prop in getHeader function

* refactor: change style to styleType

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* fix: append copy text to copied preferences (#3084)

* chore(release): version

 - @bloom-housing/[email protected]

* fix: make pill style on listing card optional (#3088)

* chore(release): version

 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]
 - @bloom-housing/[email protected]

* 2853/duplicates pages (#2892)

* refactor: create duplicates pages

* refactor: update applications link

* refactor: refactor application routes

* refactor: update active path detection

* fix: export SideNav component and add className

* refactor: cleanup & update table cols

* refactor: refactor application export and pages structure

* feat: create reusable sidenav component

* feat: update header active paths

* feat: integrate side nav

* feat: adding backend for applicaiton sidenav

* feat: changes applicaiton seeeds

* fix: updates per morgan

* fix: update the "all applications" translation

* refactor: create helper file and move shared part

* feat: integrate resolved apps view

* refactor: cleanup

* feat: hides pending subcats and footer with scan

* style: childrenItems comment

* feat: adds includeDemographics param to useApplicationsExport

Co-authored-by: Yazeed Loonat <[email protected]>
Co-authored-by: Sean Albert <[email protected]>

* refactor: create duplicates pages

* fix: remove export button from duplicate pages, fix table widths (#3006)

* 2835/async duplicates processing (#2961)

* feat(backend): add bull job scheduler for afs processing

* feat(backend): move AFS processing logic to async consumer

* feat(backend): improve afs async processing

* test: updates imports

* perf: select fields for listings afs

* fix: undo app repo select

* feat: sets rule_key for existing afs

* Fix code style issues with Prettier

* feat: adds afs process controller

* fix: updates seed and afs duplicate procesing call

* perf: clean up afs migration

Co-authored-by: Michal Plebanski <[email protected]>
Co-authored-by: Lint Action <[email protected]>

* fix: add-afs migration update

* build: debug migration

* build: debug migration

* feat: allow marking status for application flagged sets (#3020)

* chore: merge cleanup

* style: fix linter issue with duplicate export

* test: fix email test

Co-authored-by: Emily Jablonski <[email protected]>
Co-authored-by: github.context.workflow <[email protected]>
Co-authored-by: Jared White <[email protected]>
Co-authored-by: Lint Action <[email protected]>
Co-authored-by: Yazeed Loonat <[email protected]>
Co-authored-by: ColinBuyck <[email protected]>
Co-authored-by: ludtkemorgan <[email protected]>
Co-authored-by: Krzysztof Zięcina <[email protected]>
Co-authored-by: Krzysztof Zięcina <[email protected]>
Co-authored-by: dominikx96 <[email protected]>
Co-authored-by: Michal Plebanski <[email protected]>
Co-authored-by: Emily Jablonski <[email protected]>

chore: standardize the typescript version (#3086)

feat: adds setsAfsLastRunAt1664300247901 migration (#3102)

fix: duplicates ux issues (#3101)

fix: updates csv export (#3104)

3099/AFS Pagination (#3105)

* fix: afs list pagination

* fix: resolved afs pagination

* style: linter issue with afs limit
  • Loading branch information
dominikx96 authored and ludtkemorgan committed Sep 28, 2022
1 parent 816ec86 commit 8031c90
Show file tree
Hide file tree
Showing 79 changed files with 2,670 additions and 1,253 deletions.
4 changes: 4 additions & 0 deletions backend/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"dependencies": {
"@anchan828/nest-sendgrid": "^0.3.25",
"@google-cloud/translate": "^6.2.6",
"@nestjs/bull": "^0.5.0",
"@nestjs/cli": "^8.2.1",
"@nestjs/common": "^8.3.1",
"@nestjs/config": "^1.2.0",
Expand All @@ -54,6 +55,7 @@
"@types/cache-manager": "^3.4.0",
"async-retry": "^1.3.1",
"axios": "0.21.2",
"bull": "^4.8.4",
"cache-manager": "^3.4.0",
"cache-manager-redis-store": "^2.0.0",
"casbin": "5.13.0",
Expand Down Expand Up @@ -96,6 +98,8 @@
"@nestjs/schematics": "^8.0.7",
"@nestjs/testing": "^8.3.1",
"@types/axios": "^0.14.0",
"@types/bull": "^3.15.8",
"@types/cron": "^1.7.3",
"@types/express": "^4.17.8",
"@types/node": "^12.12.67",
"@types/passport-jwt": "^3.0.3",
Expand Down
12 changes: 0 additions & 12 deletions backend/core/src/ami-charts/dto/ami-chart.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,4 @@ export class AmiChartUpdateDto extends AmiChartCreateDto {
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsUUID(4, { groups: [ValidationsGroupsEnum.default] })
id?: string

@Expose()
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsDate({ groups: [ValidationsGroupsEnum.default] })
@Type(() => Date)
createdAt?: Date

@Expose()
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsDate({ groups: [ValidationsGroupsEnum.default] })
@Type(() => Date)
updatedAt?: Date
}
3 changes: 3 additions & 0 deletions backend/core/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// dotenv is a dev dependency, so conditionally import it (don't need it in Prod).
import { BullModule } from "@nestjs/bull"

try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
require("dotenv").config()
Expand Down Expand Up @@ -38,6 +40,7 @@ import { PaperApplicationsModule } from "./paper-applications/paper-applications
import { ActivityLogModule } from "./activity-log/activity-log.module"
import { logger } from "./shared/middlewares/logger.middleware"
import { CatchAllFilter } from "./shared/filters/catch-all-filter"
import { AFSProcessingQueueNames } from "./application-flagged-sets/constants/applications-flagged-sets-constants"

export function applicationSetup(app: INestApplication) {
const { httpAdapter } = app.get(HttpAdapterHost)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { InjectQueue } from "@nestjs/bull"
import { Injectable } from "@nestjs/common"
import { Queue } from "bull"
import { AFSProcessingQueueNames } from "./constants/applications-flagged-sets-constants"
import { ConfigService } from "@nestjs/config"

@Injectable()
export class ApplicationFlaggedSetsCronjobBoostrapService {
constructor(
@InjectQueue(AFSProcessingQueueNames.afsProcessing) private afsProcessingQueue: Queue,
private readonly config: ConfigService
) {
void this.afsProcessingQueue.add(null, {
repeat: {
cron: config.get<string>("AFS_PROCESSING_CRON_STRING"),
},
// NOTE: This is not unique on purpose because Bull will not add a job twice with an ID
// which already exists.
id: "afs-process",
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
import { Process, Processor } from "@nestjs/bull"
import { AFSProcessingQueueNames } from "./constants/applications-flagged-sets-constants"
import { Brackets, LessThan, MoreThanOrEqual, Repository, SelectQueryBuilder } from "typeorm"
import { Application } from "../applications/entities/application.entity"
import { Rule } from "./types/rule-enum"
import { InjectRepository } from "@nestjs/typeorm"
import { ListingRepository } from "../listings/db/listing.repository"
import { Listing } from "../listings/entities/listing.entity"
import { ApplicationFlaggedSet } from "./entities/application-flagged-set.entity"
import { FlaggedSetStatus } from "./types/flagged-set-status-enum"
import { getView } from "../applications/views/view"

@Processor(AFSProcessingQueueNames.afsProcessing)
export class ApplicationFlaggedSetsCronjobConsumer {
constructor(
@InjectRepository(ListingRepository) private readonly listingRepository: ListingRepository,
@InjectRepository(ApplicationFlaggedSet)
private readonly afsRepository: Repository<ApplicationFlaggedSet>,
@InjectRepository(Application) private readonly applicationRepository: Repository<Application>
) {}

@Process({ concurrency: 1 })
async process() {
const outOfDateListings = await this.listingRepository
.createQueryBuilder("listings")
.select(["listings.id", "listings.afsLastRunAt"])
.where("listings.lastApplicationUpdateAt IS NOT NULL")
.andWhere(
new Brackets((qb) => {
qb.where("listings.afsLastRunAt IS NULL").orWhere(
"listings.afsLastRunAt <= listings.lastApplicationUpdateAt"
)
})
)
.getMany()

for (const outOfDateListing of outOfDateListings) {
try {
await this.generateAFSesForListingRules(outOfDateListing)
outOfDateListing.afsLastRunAt = new Date()
await this.listingRepository.save(outOfDateListing)
} catch (e) {
console.error(e)
}
}
}

private async generateAFSesForListingRules(listing: Pick<Listing, "id" | "afsLastRunAt">) {
const qbView = getView(this.applicationRepository.createQueryBuilder("application"))
const qb = qbView.getViewQb(true)
qb.where("application.listing_id = :id", { id: listing.id })
qb.andWhere("application.updatedAt >= :afsLastRunAt", {
afsLastRunAt: listing.afsLastRunAt,
})
const newApplications = await qb.getMany()

for (const newApplication of newApplications) {
await this.addApplication(newApplication)
}

const existingApplications = await this.applicationRepository.find({
where: {
listing: {
id: listing.id,
},
createdAt: LessThan(listing.afsLastRunAt),
updatedAt: MoreThanOrEqual(listing.afsLastRunAt),
},
})

for (const existingApplication of existingApplications) {
await this.updateApplication(existingApplication)
}
}

async updateApplication(application: Application) {
application.markedAsDuplicate = false
await this.applicationRepository.save(application)

let afses = await this.afsRepository
.createQueryBuilder("afs")
.leftJoin("afs.applications", "applications")
.select(["afs", "applications.id"])
.where(`afs.listing_id = :listingId`, { listingId: application.listingId })
.getMany()

afses = afses.filter((afs) => afs.applications.map((app) => app.id).includes(application.id))

const afsesToBeSaved: Array<ApplicationFlaggedSet> = []
const afsesToBeRemoved: Array<ApplicationFlaggedSet> = []

for (const afs of afses) {
afs.status = FlaggedSetStatus.pending
afs.resolvedTime = null
afs.resolvingUser = null

const applicationIndex = afs.applications.findIndex((app) => app.id === application.id)

if (applicationIndex == -1) {
continue
}

afs.applications.splice(applicationIndex, 1)

if (afs.applications.length > 1) {
afsesToBeSaved.push(afs)
} else {
afsesToBeRemoved.push(afs)
}
}
if (afsesToBeSaved.length) {
await this.afsRepository.save(afsesToBeSaved)
}
if (afsesToBeRemoved.length) {
await this.afsRepository.remove(afsesToBeRemoved)
}

await this.addApplication(application)
}

/**
*
* This method checks if the new application matches others based on the rules.
* If there are applications that match, this application is added to the AFS set (creating a new one or updating an existing set)
*/
async addApplication(newApplication: Application): Promise<void> {
const rules = [Rule.email, Rule.nameAndDOB]

for (const rule of rules) {
const applicationsMatchingRule = await this.fetchDuplicatesMatchingRule(newApplication, rule)
if (applicationsMatchingRule.length === 0) {
// continue to the next rule
continue
}

const afses = await this.afsRepository
.createQueryBuilder("afs")
.leftJoin("afs.applications", "applications")
.select(["afs", "applications.id"])
.where(`afs.ruleKey = :ruleKey`, { ruleKey: this.getRuleKeyForRule(newApplication, rule) })
.getMany()

if (afses.length === 0) {
await this.afsRepository.save({
rule: rule,
ruleKey: this.getRuleKeyForRule(newApplication, rule),
resolvedTime: null,
resolvingUser: null,
status: FlaggedSetStatus.pending,
applications: [newApplication, ...applicationsMatchingRule],
listing: { id: newApplication.listingId },
})
} else if (afses.length === 1) {
const afs = afses[0]

if (!afs.applications.map((app) => app.id).includes(newApplication.id)) {
afs.applications.push(newApplication)
await this.afsRepository.save(afs)
}
} else {
console.error(
"There should be up to one AFS matching a rule for given application, " +
"probably a logic error when creating AFSes"
)
}
// there was a match so we don't need to check the next rule
break
}
}

private async fetchDuplicatesMatchingRule(application: Application, rule: Rule) {
switch (rule) {
case Rule.nameAndDOB:
return await this.fetchDuplicatesMatchingNameAndDOBRule(application)
case Rule.email:
return await this.fetchDuplicatesMatchingEmailRule(application)
}
}

private async fetchDuplicatesMatchingEmailRule(newApplication: Application) {
return await this.applicationRepository.find({
select: ["id"],
where: (qb: SelectQueryBuilder<Application>) => {
qb.where("Application.id != :id", {
id: newApplication.id,
})
.andWhere("Application.listing.id = :listingId", {
listingId: newApplication.listingId,
})
.andWhere("Application__applicant.emailAddress = :emailAddress", {
emailAddress: newApplication.applicant.emailAddress,
})
.andWhere("Application.status = :status", { status: "submitted" })
},
})
}

private getRuleKeyForRule(newApplication: Application, rule: Rule): string {
if (rule == Rule.email) {
return `${newApplication.listingId}-email-${newApplication.applicant.emailAddress}`
} else if (rule == Rule.nameAndDOB) {
return (
`${newApplication.listingId}-nameAndDOB-${newApplication.applicant.firstName}-${newApplication.applicant.lastName}-${newApplication.applicant.birthMonth}-` +
`${newApplication.applicant.birthDay}-${newApplication.applicant.birthYear}`
)
} else {
throw new Error("Invalid rule")
}
}

private async fetchDuplicatesMatchingNameAndDOBRule(newApplication: Application) {
const firstNames = [
newApplication.applicant.firstName,
...newApplication.householdMembers.map((householdMember) => householdMember.firstName),
]

const lastNames = [
newApplication.applicant.lastName,
...newApplication.householdMembers.map((householdMember) => householdMember.lastName),
]

const birthMonths = [
newApplication.applicant.birthMonth,
...newApplication.householdMembers.map((householdMember) => householdMember.birthMonth),
]

const birthDays = [
newApplication.applicant.birthDay,
...newApplication.householdMembers.map((householdMember) => householdMember.birthDay),
]

const birthYears = [
newApplication.applicant.birthYear,
...newApplication.householdMembers.map((householdMember) => householdMember.birthYear),
]

return await this.applicationRepository.find({
select: ["id"],
where: (qb: SelectQueryBuilder<Application>) => {
qb.where("Application.id != :id", {
id: newApplication.id,
})
.andWhere("Application.listing.id = :listingId", {
listingId: newApplication.listingId,
})
.andWhere("Application.status = :status", { status: "submitted" })
.andWhere(
new Brackets((subQb) => {
subQb.where("Application__householdMembers.firstName IN (:...firstNames)", {
firstNames: firstNames,
})
subQb.orWhere("Application__applicant.firstName IN (:...firstNames)", {
firstNames: firstNames,
})
})
)
.andWhere(
new Brackets((subQb) => {
subQb.where("Application__householdMembers.lastName IN (:...lastNames)", {
lastNames: lastNames,
})
subQb.orWhere("Application__applicant.lastName IN (:...lastNames)", {
lastNames: lastNames,
})
})
)
.andWhere(
new Brackets((subQb) => {
subQb.where("Application__householdMembers.birthMonth IN (:...birthMonths)", {
birthMonths: birthMonths,
})
subQb.orWhere("Application__applicant.birthMonth IN (:...birthMonths)", {
birthMonths: birthMonths,
})
})
)
.andWhere(
new Brackets((subQb) => {
subQb.where("Application__householdMembers.birthDay IN (:...birthDays)", {
birthDays: birthDays,
})
subQb.orWhere("Application__applicant.birthDay IN (:...birthDays)", {
birthDays: birthDays,
})
})
)
.andWhere(
new Brackets((subQb) => {
subQb.where("Application__householdMembers.birthYear IN (:...birthYears)", {
birthYears: birthYears,
})
subQb.orWhere("Application__applicant.birthYear IN (:...birthYears)", {
birthYears: birthYears,
})
})
)
},
})
}
}
Loading

0 comments on commit 8031c90

Please sign in to comment.