Untitled
unknown
plain_text
2 years ago
7.6 kB
12
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,
};
};
Editor is loading...