Untitled
unknown
plain_text
a year ago
7.6 kB
2
Indexable
import { add, compare, isZero } from "dinero.js"; import * as A from "fp-ts/Array"; import { flow } from "fp-ts/lib/function"; import * as ROA from "fp-ts/ReadonlyArray"; import { DateTime } from "luxon"; import { AumResult, RelatedUsersOfRep, } from "@lambdas/shared/businessLogic/collectFirmReportInfo/types"; import { FaFirm } from "@lambdas/shared/models/FaFirm"; import { ActiveFaRep } from "@lambdas/shared/models/FaRep"; import { RelationshipType, UserFaRelationshipWithUser, } from "@lambdas/shared/models/UserFaRelationship"; import { fromCode, SupportedCurrencies } from "@lambdas/shared/money"; import * as ReportData from "./ReportData"; import { FaReportData, FirmReportData } from "./types"; export const collectFirmReportData = ( faFirm: FaFirm, date: DateTime, currency: SupportedCurrencies, repInfos: ReadonlyArray< Readonly<{ relatedUserInfo: RelatedUsersOfRep; aumInfo: AumResult; }> >, unassignedLeadsInfo: Readonly<{ allTimeUnassignedLeads: UserFaRelationshipWithUser[]; monthlyUnassignedLeads: UserFaRelationshipWithUser[]; aumInfo: AumResult; }> ): FirmReportData => { const repReportData = filterEmptyFaRepData( repInfos.map(composeRepReportData(currency)) ); const totalMonthlyData = calculateTotalReportData(currency)( repReportData.map((report) => report.monthlyData) ); const totalAllTimeData = calculateTotalReportData(currency)( repReportData.map((report) => report.allTimeData) ); // const unassignedLeadReportData = composeUnassignedleadReportData(unassignedLeadsInfo.allTimeUnassignedLeads, unassignedLeadsInfo.monthlyUnassignedLeads, unassignedLeadsInfo.aumInfo, currency) const monthlyUnassignedLead = calculateReportFirmData( unassignedLeadsInfo.allTimeUnassignedLeads, unassignedLeadsInfo.aumInfo, currency ); const unassignedLeadReportData = nonEmptyFirmData(composeUnassignedleadReportData(unassignedLeadsInfo.allTimeUnassignedLeads, unassignedLeadsInfo.monthlyUnassignedLeads, unassignedLeadsInfo.aumInfo, currency)) return { date, currency, faFirmId: faFirm.id, faFirmName: faFirm.name, faReps: repReportData.sort((firstFaRep, secondFaRep) => compare(secondFaRep.allTimeData.totalAum, firstFaRep.allTimeData.totalAum) ), faFirmCreatedDate: faFirm.createdDate.toFormat("MM yy"), totalMonthlyData: { ...totalMonthlyData, numberOfDirect: totalMonthlyData.numberOfDirect + unassignedLeadReportData?.monthlyData.numberOfDirect, numberOfAssigned: totalMonthlyData.numberOfAssigned + unassignedLeadReportData?.monthlyData.numberOfAssigned, numberOfIndirect: totalMonthlyData.numberOfIndirect, aum: add(totalMonthlyData.aum, unassignedLeadReportData?.monthlyData.aum), }, totalAllTimeData: { ...totalAllTimeData, numberOfDirect: totalAllTimeData.numberOfDirect + allTimeUnassignedLead.numberOfDirect, numberOfAssigned: totalAllTimeData.numberOfAssigned + allTimeUnassignedLead.numberOfAssigned, numberOfIndirect: totalAllTimeData.numberOfIndirect, aum: add(totalAllTimeData.aum, allTimeUnassignedLead.aum), totalAum: add(totalAllTimeData.totalAum, allTimeUnassignedLead.aum), }, unassignedLeadsInfo: { monthlyData: monthlyUnassignedLead, allTimeData: allTimeUnassignedLead, }, }; }; const isNonEmptyFaRepData = ({ monthlyData, allTimeData }: FaReportData) => !isZero(monthlyData.aum) || monthlyData.numberOfDirect !== 0 || monthlyData.numberOfIndirect !== 0 || monthlyData.numberOfAssigned !== 0 || !isZero(allTimeData.personalInvest) || !isZero(allTimeData.aum) || allTimeData.numberOfDirect !== 0 || allTimeData.numberOfIndirect !== 0 || allTimeData.numberOfAssigned !== 0; const nonEmptyFirmData = ({ unassignedLeadsInfo }: Pick< FirmReportData, 'unassignedLeadsInfo' >) => (!isZero(unassignedLeadsInfo.monthlyData.aum) || unassignedLeadsInfo.monthlyData.numberOfAssigned !== 0 || unassignedLeadsInfo.monthlyData.numberOfDirect !== 0 || unassignedLeadsInfo.monthlyData.amount !== 0 || !isZero(unassignedLeadsInfo.allTimeData.aum) || unassignedLeadsInfo.allTimeData.amount !== 0 || unassignedLeadsInfo.allTimeData.numberOfAssigned !== 0 || unassignedLeadsInfo.allTimeData.numberOfDirect !== 0) ? unassignedLeadsInfo : undefined; const filterEmptyFaRepData = A.filter(isNonEmptyFaRepData); const calculateTotalReportData = (currency: SupportedCurrencies) => flow(ROA.reduce(ReportData.empty(currency), ReportData.plus)); const composeRepReportData = (currency: SupportedCurrencies) => ({ relatedUserInfo, aumInfo, }: { relatedUserInfo: RelatedUsersOfRep; aumInfo: AumResult; }): FaReportData => { const monthlyData = calculateReportData( relatedUserInfo.faRep, relatedUserInfo.currentMonthUsers, aumInfo, currency ); const allTimeData = calculateReportData( relatedUserInfo.faRep, relatedUserInfo.allTimeUsers, aumInfo, currency ); return { name: relatedUserInfo.faRep.name, email: relatedUserInfo.faRep.email, rnf: relatedUserInfo.faRep.rnf, monthlyData, allTimeData, }; }; const composeUnassignedleadReportData = ( allTimeUnassignedLeads: UserFaRelationshipWithUser[], monthlyUnassignedLeads: UserFaRelationshipWithUser[], aumInfo: AumResult, currency: SupportedCurrencies ): Pick< FirmReportData, 'unassignedLeadsInfo' > => { const monthlyData = calculateReportFirmData( monthlyUnassignedLeads, aumInfo, currency ); const allTimeData = calculateReportFirmData( allTimeUnassignedLeads, aumInfo, currency ); return { unassignedLeadsInfo: { monthlyData, allTimeData } } } const calculateReportData = ( faRep: ActiveFaRep, userRelationships: UserFaRelationshipWithUser[], aumInfo: AumResult, currency: SupportedCurrencies ): ReportData.ReportData => { const zero = fromCode(currency).zero; const numberOfDirect = userRelationships.filter( (user) => user.relationshipType === RelationshipType.DirectRep ).length; const numberOfIndirect = userRelationships.filter( (user) => user.relationshipType === RelationshipType.IndirectRep ).length; const numberOfAssigned = userRelationships.filter( (user) => user.relationshipType === RelationshipType.AssignedRep ).length; const personalInvest = aumInfo[faRep.userId!] || zero; const aum = userRelationships.reduce( (total, cur) => add(total, aumInfo[cur.user.id] || zero), fromCode(currency).zero ); const totalAum = add(personalInvest, aum); return { numberOfDirect, numberOfAssigned, numberOfIndirect, aum, personalInvest, totalAum, }; }; const calculateReportFirmData = ( userRelationships: UserFaRelationshipWithUser[], aumInfo: AumResult, currency: SupportedCurrencies ): ReportData.ReportFirmData => { const zero = fromCode(currency).zero; const numberOfDirect = userRelationships.filter( (user) => user.relationshipType === RelationshipType.DirectFirm ).length; const numberOfAssigned = userRelationships.filter( (user) => user.relationshipType === RelationshipType.AssignedFirm ).length; const aum = userRelationships.reduce( (total, cur) => add(total, aumInfo[cur.userId] || zero), fromCode(currency).zero ); return { numberOfDirect, numberOfAssigned, aum, amount: userRelationships.length, }; };