All files / apps/data-refreshments/src/refreshments-execute/sync directorySync.service.ts

42.85% Statements 36/84
33.33% Branches 1/3
50% Functions 1/2
42.85% Lines 36/84

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 851x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                                                                                 1x  
import { Injectable } from '@nestjs/common';
import { isEmpty, isNil, partition, uniqBy } from 'lodash-es';
 
import { type Company } from '@amalia/core/models';
import { DataRefreshmentValidationError } from '@amalia/core/types';
import {
  type DataConnector,
  type DataConnectorObject,
  type DataConnectorObjectRecord,
} from '@amalia/data-capture/connectors/types';
 
import { toExternalIdSource } from './mappers/users-id-source.mapper';
import { DataConnectorQuotaDefinition } from './quotaConnector/dataConnectorQuotaDefinition';
import { DataConnectorQuotaRecord } from './quotaConnector/dataConnectorQuotaRecord';
import { QuotaConnectorService } from './quotaConnector/quotaConnector.service';
import { UserConnectorService } from './userConnector/userConnector.service';
 
/**
 * Sync directory and user fields (quota) during data sync.
 */
@Injectable()
export class SyncDirectoryService {
  public constructor(
    private readonly userConnectorService: UserConnectorService,
    private readonly quotaConnectorService: QuotaConnectorService,
  ) {}
 
  /**
   *
   * @param company
   * @param connectorObject
   * @param records
   * @param connector
   */
  public async syncDirectoryAndQuota(
    company: Company,
    connectorObject: DataConnectorObject,
    records: DataConnectorObjectRecord[],
    connector: DataConnector,
  ): Promise<{ validationErrors: DataRefreshmentValidationError[] }> {
    const quotaVariables = await this.quotaConnectorService.findAllUserQuotas(company);
    const quotaDefinition = new DataConnectorQuotaDefinition(connectorObject, quotaVariables);
    const quotaRecords = records.map((record) => new DataConnectorQuotaRecord(quotaDefinition, record, connector.type));
    // Filter duplicates + check errors.

    const externalIdSource = toExternalIdSource(connector.type);

    // 1 -- Sync directory
    // Ensure we have uniq users to synchronize (we may have one line per quota for different periods).
    const users = uniqBy(
      quotaRecords.map((qr) => qr.user),
      quotaDefinition.userIdField,
    ).map((user) => ({
      ...user,
      ...('externalId' in user &&
        !isNil(user.externalId) && {
          // only update externalIdSource if externalId is not pristine
          externalIdSource,
        }),
    }));

    const { users: savedUsers, errors } = await this.userConnectorService.bulkSave(
      company,
      users,
      quotaDefinition.userIdField,
      connectorObject.synchronizeOnlyToExistantUser,
      externalIdSource,
      connector.type,
    );

    // 2 -- Sync quotas
    // We only need to do that for records matching users that have been synced
    const [quotaValues, validationErrors] = partition(
      quotaRecords.flatMap((quotaRecord) => quotaRecord.extractQuotaValues(savedUsers)),
      (quotaOrValidationError) => 'value' in quotaOrValidationError,
    );

    if (!isEmpty(quotaValues)) {
      await this.quotaConnectorService.saveQuotaValues(company, quotaValues, quotaVariables);
    }

    return { validationErrors: errors.concat(validationErrors) };
  }
}