From 6e33b9168eab4077953552fa4680c20253bc6f07 Mon Sep 17 00:00:00 2001
From: Kamile Vainiute <kamile@igem.org>
Date: Thu, 13 Apr 2023 14:01:35 +0300
Subject: [PATCH] Performance improvement on all orders fetch

---
 src/lib/stripe/stripe.library.ts              |  5 +++
 .../payments-management.service.ts            | 39 ++++++++++++-------
 2 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/src/lib/stripe/stripe.library.ts b/src/lib/stripe/stripe.library.ts
index 60bb64c96..c55730914 100644
--- a/src/lib/stripe/stripe.library.ts
+++ b/src/lib/stripe/stripe.library.ts
@@ -26,6 +26,11 @@ export class StripeLibrary {
     return await this.client.customers.retrieve(id, params, options)
   }
 
+  async listCustomers (options?: Stripe.RequestOptions): Promise<Stripe.Customer[]> {
+    return await this.client.customers.list(options)
+      .then(({ data }) => data)
+  }
+
   async updateCustomer (id: string, params?: Stripe.CustomerUpdateParams, options?: Stripe.RequestOptions): Promise<Stripe.Customer> {
     return await this.client.customers.update(id, params, options)
   }
diff --git a/src/modules/payments-management/payments-management.service.ts b/src/modules/payments-management/payments-management.service.ts
index 327521640..10070ebbc 100644
--- a/src/modules/payments-management/payments-management.service.ts
+++ b/src/modules/payments-management/payments-management.service.ts
@@ -65,20 +65,18 @@ export class PaymentsManagementService {
       validateAccessID(checksum, order.id)
     }
     const customer = await this.stripeLibrary.retrieveCustomer(order.customerID)
-    return await this.mapOrderToDTO(order, customer, accessID, session)
+    return await this.mapOrderToDTO(order, customer, undefined, accessID, session)
   }
 
   async searchOrdersByUser (session: SessionDto): Promise<OrderDTO[]> {
     const teams: Team[] = (await this.teamsService.findUserTeamsAndRoles(session.id)).map((teamAndRole) => teamAndRole[0])
-    const orders: OrderDTO[] = []
+    const orders: Order[] = []
     for (const team of teams) {
-      const teamOrders = await this.mapOrdersToDTOs(
-        await this.ordersService.searchEntityOrders(EntityType.TEAM, team.id, undefined), session
-      )
+      const teamOrders = await this.ordersService.searchEntityOrders(EntityType.TEAM, team.id, undefined)
       orders.push(...teamOrders)
     }
 
-    return orders
+    return await this.mapOrdersToDTOs(orders, session)
   }
 
   async searchOrders (query: OrderSearchParams, session: SessionDto): Promise<OrderDTO[]> {
@@ -136,7 +134,7 @@ export class PaymentsManagementService {
       metadata: { id: order.id }
     })
 
-    return await this.mapOrderToDTO(order, customer, undefined, session)
+    return await this.mapOrderToDTO(order, customer, undefined, undefined, session)
   }
 
   //
@@ -291,9 +289,9 @@ export class PaymentsManagementService {
     }
   }
 
-  private async mapOrderItemToDTO (item: OrderItem): Promise<OrderItemDTO> {
+  private async mapOrderItemToDTO (item: OrderItem, _product?: Stripe.Product): Promise<OrderItemDTO> {
     const { teamID, team } = item
-    const product = await this.stripeLibrary.retrieveProduct(item.productID)
+    const product = _product ?? await this.stripeLibrary.retrieveProduct(item.productID)
 
     let itemTeam: OrderTeamDTO | undefined
     if (teamID != null && team != null) {
@@ -319,10 +317,11 @@ export class PaymentsManagementService {
     }
   }
 
-  private async mapOrderToDTO (order: Order, customer: Stripe.Customer | Stripe.DeletedCustomer, accessID?: string, session?: SessionDto): Promise<OrderDTO> {
+  private async mapOrderToDTO (order: Order, customer: Stripe.Customer | Stripe.DeletedCustomer, productsByID?: Record<string, Stripe.Product>, accessID?: string, session?: SessionDto): Promise<OrderDTO> {
     const items: OrderItemDTO[] = []
-    for (let i = 0; i < order.items.length; i++) {
-      items.push(await this.mapOrderItemToDTO(order.items[i]))
+
+    for (const item of order.items) {
+      items.push(await this.mapOrderItemToDTO(item, productsByID?.[item.productID]))
     }
 
     const isPrimaryPI = items.every((item) => item.team?.primaryPI.user.id === session?.id)
@@ -332,9 +331,21 @@ export class PaymentsManagementService {
 
   private async mapOrdersToDTOs (orders: Order[], session?: SessionDto): Promise<OrderDTO[]> {
     const result = []
+
+    const customersByID = (await this.stripeLibrary.listCustomers())
+      .reduce<Record<string, Stripe.Customer>>((_customersByID, customer) => {
+      _customersByID[customer.id] = customer
+      return _customersByID
+    }, {})
+
+    const productsByID = (await this.stripeLibrary.retrieveProducts())
+      .reduce<Record<string, Stripe.Product>>((_productsByID, product) => {
+      _productsByID[product.id] = product
+      return _productsByID
+    }, {})
+
     for (const order of orders) {
-      const customer = await this.stripeLibrary.retrieveCustomer(order.customerID)
-      result.push(await this.mapOrderToDTO(order, customer, undefined, session))
+      result.push(await this.mapOrderToDTO(order, customersByID[order.customerID], productsByID, undefined, session))
     }
     return result
   }
-- 
GitLab