File

src/profile/summary.service.ts

Index

Properties
Methods

Methods

Async getDealerSummary
getDealerSummary(userJwtPayload: UserJwtPayload)
Parameters :
Name Type Optional
userJwtPayload UserJwtPayload No
Returns : unknown
Async getInvestorSummary
getInvestorSummary(userJwtPayload: UserJwtPayload)
Parameters :
Name Type Optional
userJwtPayload UserJwtPayload No
Returns : unknown

Properties

Private Readonly docuSignService
Type : DocuSignService
Decorators :
@Inject(DocuSignService)
Private Readonly fundAdminService
Type : FundAdminService
Decorators :
@Inject(FundAdminService)
Private Readonly orderBookService
Type : OrderBookService
Decorators :
@Inject(OrderBookService)
Private Readonly userService
Type : UserService
Decorators :
@Inject(UserService)
import {
  EndUserRoles,
  IGeDealerIdQuery,
  IGetDealerTxsQuery,
  IOrder,
  RequestStatus,
  UserJwtPayload,
} from "src/common/interfaces";
import {
  Inject,
  Injectable,
  ServiceUnavailableException,
} from "@nestjs/common";

import { UserService } from "src/user/user.service";

import { DocuSignService } from "src/docusign/docusign.service";
import { encodeBytes32String } from "ethers";
import { ApolloQueryResult } from "@apollo/client";
import {
  apolloClient,
  getCurrentDealerIdQuery,
  getDealerTxsQuery,
  getInvestorTxsByDealerIdQuery,
} from "src/common/provider";
import { IOrderRequestWithDocusignStatus } from "src/docusign/docusign.interface";
import { FundAdminService } from "src/user/fundAdmin.service";
import { UserWithOnChainFields } from "src/user/user.interface";
import { OrderBookService } from "src/orderbook/orderbook.service";

@Injectable()
export class SummaryService {
  @Inject(UserService)
  private readonly userService: UserService;

  @Inject(DocuSignService)
  private readonly docuSignService: DocuSignService;

  @Inject(FundAdminService)
  private readonly fundAdminService: FundAdminService;

  @Inject(OrderBookService)
  private readonly orderBookService: OrderBookService;

  async getInvestorSummary(userJwtPayload: UserJwtPayload) {
    const [investor] = await this.userService.findUsersByFilter(
      {
        email: userJwtPayload.email,
      },
      true,
    );

    const subscribedFundsByType: Record<string, number> = {};
    investor.subscribedFunds.forEach((fund) => {
      if (!subscribedFundsByType[fund.fundType]) {
        subscribedFundsByType[fund.fundType] = 1;
      } else {
        subscribedFundsByType[fund.fundType]++;
      }
    });
    const dealerSubgraph: ApolloQueryResult<IGeDealerIdQuery> =
      await apolloClient.query({
        query: getCurrentDealerIdQuery,
        variables: {
          investorId: encodeBytes32String(investor._id.toString()),
        },
      });
    if (dealerSubgraph.error) {
      throw new ServiceUnavailableException(dealerSubgraph.error);
    }
    const investorSubgraph: ApolloQueryResult<IGetDealerTxsQuery> =
      await apolloClient.query({
        query: getInvestorTxsByDealerIdQuery,
        variables: {
          dealerId: dealerSubgraph.data.investor.associatedDealer.id,
          investorId: encodeBytes32String(investor._id.toString()),
        },
      });

    const { awaitingTxs, pendingTxs } = investorSubgraph.data.dealer;
    let orderFromTime, orderToTime;
    if (awaitingTxs.length && pendingTxs.length) {
      orderFromTime =
        awaitingTxs[awaitingTxs.length - 1].lastTimeUpdated >
        pendingTxs[pendingTxs.length - 1].lastTimeUpdated
          ? pendingTxs[pendingTxs.length - 1].lastTimeUpdated
          : awaitingTxs[awaitingTxs.length - 1].lastTimeUpdated;

      orderToTime =
        awaitingTxs[0].lastTimeUpdated > pendingTxs[0].lastTimeUpdated
          ? awaitingTxs[0].lastTimeUpdated
          : pendingTxs[0].lastTimeUpdated;
    }
    if (!awaitingTxs.length && pendingTxs.length) {
      orderFromTime = pendingTxs[pendingTxs.length - 1].lastTimeUpdated;
      orderToTime = pendingTxs[0].lastTimeUpdated;
    }
    if (awaitingTxs.length && !pendingTxs.length) {
      orderFromTime = awaitingTxs[awaitingTxs.length - 1].lastTimeUpdated;
      orderToTime = awaitingTxs[0].lastTimeUpdated;
    }

    const pendingTxsAfterDocusign: IOrder[] = [];
    const awaitingTxsAfterDocusign: IOrder[] = [];
    if (!orderFromTime || !orderToTime) {
      return {
        yourActions: [],
        awaitingOthers: [],
        profile: investor,
      };
    }

    const ordersTimeFilter = {
      orderFromTime: new Date(
        (Number(orderFromTime) - 60 * 60) * 1000,
      ).toISOString(),
      orderToTime: new Date(
        (Number(orderToTime) + 60 * 60) * 1000,
      ).toISOString(),
    };
    const orderRequests =
      !awaitingTxs.length && !pendingTxs.length
        ? []
        : await this.docuSignService.getInvestorSubmittedDocuments({
            receiverEmail: investor.email,
            ...ordersTimeFilter,
          });
    const orderRequestById: Record<string, IOrderRequestWithDocusignStatus> =
      {};
    orderRequests.forEach((orderRequest) => {
      orderRequestById[orderRequest.orderId] = orderRequest;
    });

    pendingTxs.forEach((order) => {
      if (
        orderRequestById[order.id] &&
        orderRequestById[order.id].status === "underReview" &&
        orderRequestById[order.id].docuSignStatus === "completed"
      ) {
        awaitingTxsAfterDocusign.push(order);
        return;
      }
      if (
        orderRequestById[order.id] &&
        orderRequestById[order.id].status === "rejected"
      ) {
        return;
      }
      pendingTxsAfterDocusign.push(order);
    });

    awaitingTxs.forEach((order) => {
      if (!orderRequestById[order.id]) {
        pendingTxsAfterDocusign.push(order);
        return;
      }

      if (
        orderRequestById[order.id].status === "accepted" &&
        order.status !== "Locked" &&
        order.type === "Redemption"
      ) {
        pendingTxsAfterDocusign.push(order);
        return;
      }
      if (
        orderRequestById[order.id].status === "underReview" &&
        orderRequestById[order.id].docuSignStatus !== "completed"
      ) {
        pendingTxsAfterDocusign.push(order);
        return;
      }
      if (orderRequestById[order.id].status === "rejected") {
        return;
      }
      awaitingTxsAfterDocusign.push(order);
    });
    const [pendingOrders, awaitingOrders] = await Promise.all([
      this.orderBookService.addFundNameToOrder({
        orders: pendingTxsAfterDocusign,
        orderRequests,
      }),
      this.orderBookService.addFundNameToOrder({
        orders: awaitingTxsAfterDocusign,
        orderRequests,
      }),
    ]);
    return {
      yourActions: pendingOrders,
      awaitingOthers: awaitingOrders,
      profile: investor,
      subscribedFundsByType,
    };
  }

  async getDealerSummary(userJwtPayload: UserJwtPayload) {
    const dealer = await this.userService.findUserByProperty(
      {
        email: userJwtPayload.email,
      },
      true,
    );
    const subscribedFundsByType: Record<string, number> = {};
    dealer.subscribedFunds.forEach((fund) => {
      if (!subscribedFundsByType[fund.fundType]) {
        subscribedFundsByType[fund.fundType] = 1;
      } else {
        subscribedFundsByType[fund.fundType]++;
      }
    });
    const dealerSubgraph: ApolloQueryResult<IGetDealerTxsQuery> =
      await apolloClient.query({
        query: getDealerTxsQuery,
        variables: {
          dealerId: encodeBytes32String(dealer._id.toString()),
        },
      });

    const investorIds = [];
    const investors = await this.userService.findUsersByFilter({
      onboardByEmail: userJwtPayload.email,
    });
    const investorsByIdBytes32: Record<string, UserWithOnChainFields> = {};

    investorIds.push(
      ...investors.map((investor) => {
        investorsByIdBytes32[encodeBytes32String(investor._id.toString())] =
          investor;
        return investor._id.toString();
      }),
    );

    const accessRequests = await this.fundAdminService.getRequestsByFundsId(
      EndUserRoles.dealer,
      dealer.subscribedFunds.map((fund) => fund._id.toString()),
      investorIds,
      {},
    );

    let approvedCount = 0;
    let waitingForApproval = 0;
    accessRequests.forEach((userAccessRequest) => {
      if (
        userAccessRequest.accessRequests[
          userAccessRequest.accessRequests.length - 1
        ].status === RequestStatus.accepted
      ) {
        approvedCount++;
      }
      if (
        userAccessRequest.accessRequests[
          userAccessRequest.accessRequests.length - 1
        ].status === RequestStatus.underReview
      ) {
        waitingForApproval++;
      }
    });
    const { awaitingTxs, pendingTxs } = dealerSubgraph.data.dealer;
    let orderFromTime, orderToTime;
    if (awaitingTxs.length && pendingTxs.length) {
      orderFromTime =
        awaitingTxs[awaitingTxs.length - 1].lastTimeUpdated >
        pendingTxs[pendingTxs.length - 1].lastTimeUpdated
          ? pendingTxs[pendingTxs.length - 1].lastTimeUpdated
          : awaitingTxs[awaitingTxs.length - 1].lastTimeUpdated;

      orderToTime =
        awaitingTxs[0].lastTimeUpdated > pendingTxs[0].lastTimeUpdated
          ? awaitingTxs[0].lastTimeUpdated
          : pendingTxs[0].lastTimeUpdated;
    }
    if (!awaitingTxs.length && pendingTxs.length) {
      orderFromTime = pendingTxs[pendingTxs.length - 1].lastTimeUpdated;
      orderToTime = pendingTxs[0].lastTimeUpdated;
    }
    if (awaitingTxs.length && !pendingTxs.length) {
      orderFromTime = awaitingTxs[awaitingTxs.length - 1].lastTimeUpdated;
      orderToTime = awaitingTxs[0].lastTimeUpdated;
    }

    const pendingTxsAfterDocusign: IOrder[] = [];
    const awaitingTxsAfterDocusign: IOrder[] = [];
    if (!orderFromTime || !orderToTime) {
      return {
        yourActions: [],
        awaitingOthers: [],
        approvedCount,
        waitingForApproval,
        subscribedFundsByType,
      };
    }
    const ordersTimeFilter = {
      orderFromTime: new Date(
        (Number(orderFromTime) - 60 * 60) * 1000,
      ).toISOString(),
      orderToTime: new Date(
        (Number(orderToTime) + 60 * 60) * 1000,
      ).toISOString(),
    };
    const orderRequests =
      !awaitingTxs.length && !pendingTxs.length
        ? []
        : await this.docuSignService.getDealerSubmittedDocuments({
            customFieldName: "dealerEmail",
            customFieldValue: userJwtPayload.email,
            ...ordersTimeFilter,
          });
    const orderRequestById: Record<string, IOrderRequestWithDocusignStatus> =
      {};
    orderRequests.forEach((orderRequest) => {
      orderRequestById[orderRequest.orderId] = orderRequest;
    });
    pendingTxs.forEach((order) => {
      if (
        orderRequestById[order.id] &&
        orderRequestById[order.id].status === "underReview" &&
        orderRequestById[order.id].docuSignStatus === "completed"
      ) {
        awaitingTxsAfterDocusign.push(order);
        return;
      }
      if (
        orderRequestById[order.id] &&
        orderRequestById[order.id].status === "rejected"
      ) {
        return;
      }
      pendingTxsAfterDocusign.push(order);
    });

    awaitingTxs.forEach((order) => {
      if (!orderRequestById[order.id]) {
        pendingTxsAfterDocusign.push(order);
        return;
      }

      if (
        orderRequestById[order.id].status === "accepted" &&
        order.status !== "Locked" &&
        order.type === "Redemption"
      ) {
        pendingTxsAfterDocusign.push(order);
        return;
      }
      if (
        orderRequestById[order.id].status === "underReview" &&
        orderRequestById[order.id].docuSignStatus !== "completed"
      ) {
        pendingTxsAfterDocusign.push(order);
        return;
      }
      if (orderRequestById[order.id].status === "rejected") {
        return;
      }
      awaitingTxsAfterDocusign.push(order);
    });
    const [pendingOrders, awaitingOrders] = await Promise.all([
      this.orderBookService.addFundNameToOrder({
        orders: pendingTxsAfterDocusign,
        orderRequests,
      }),
      this.orderBookService.addFundNameToOrder({
        orders: awaitingTxsAfterDocusign,
        orderRequests,
      }),
    ]);
    return {
      yourActions: pendingOrders.map((order) => {
        return {
          ...order,
          onBehalf: {
            ...order.onBehalf,
            ...investorsByIdBytes32[order.onBehalf.id],
          },
        };
      }),
      awaitingOthers: awaitingOrders.map((order) => {
        return {
          ...order,
          onBehalf: {
            ...order.onBehalf,
            ...investorsByIdBytes32[order.onBehalf.id],
          },
        };
      }),
      approvedCount,
      waitingForApproval,
      subscribedFundsByType,
    };
  }
}

results matching ""

    No results matching ""