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 85 86 87 88 89 90 91 | 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 16x 16x 16x 16x 16x 16x 16x 16x 1x 1x 1x | import { Injectable, Logger } from '@nestjs/common';
import { isNil, pick, uniq } from 'lodash-es';
import { assert, toError } from '@amalia/ext/typescript';
import { AppLogger, InjectAppLogger, withLoggerContext } from '@amalia/kernel/logger/server';
import { type PaymentReleasePayload, type TaskHandler } from '@amalia/kernel/queue/core';
import { StatementCalculationCacheFactory } from '@amalia/payout-calculation/compute-engine/core-statement-calculation-cache';
import { PlansService, RulesService } from '@amalia/payout-definition/designer/core';
import { PeriodsService } from '@amalia/payout-definition/periods/core';
import { RuleType } from '@amalia/payout-definition/plans/types';
import { CompaniesService } from '@amalia/tenants/companies/core';
import { StatementSaveService } from '../statementSave/statementSave.service';
/**
* This event is called by the message queue to start the release of payments.
*
* Some payments are not released and won't be released if there is not any statement of the owner
* of that payment in the period. It means that we should periodically try to release payments of
* all the companies just in case it happens.
*/
@Injectable()
export class PaymentReleaseHandler implements TaskHandler<PaymentReleasePayload> {
private readonly logger = new Logger(PaymentReleaseHandler.name);
public constructor(
private readonly planService: PlansService,
private readonly rulesService: RulesService,
private readonly periodService: PeriodsService,
private readonly companiesService: CompaniesService,
private readonly statementSaveService: StatementSaveService,
private readonly statementCalculationCacheFactory: StatementCalculationCacheFactory,
@InjectAppLogger() private readonly appLogger: AppLogger,
) {}
public async handle({ companyId, periodId }: PaymentReleasePayload) {
assert(!isNil(companyId), 'Payment Release failed: Company Id not specified.');
const company = await this.companiesService.findById(companyId);
assert(company, `Payment release - Company ${companyId} not found.`);
return withLoggerContext(this.appLogger, { company: pick(company, ['id', 'name']) }, async () => {
const period = periodId
? // Try to get a period from the periodId given.
await this.periodService.findOne(company, periodId)
: // Or get the period we're currently in.
await this.periodService.findPeriod(company, new Date(), false).catch<null>(() => null);
if (!period) {
this.logger.warn(`Payment release - ${company.name}, no period found (${companyId}, ${periodId || 'N/A'})`);
return;
}
const companyHoldRules = await this.rulesService.findByType(company, RuleType.HOLD_AND_RELEASE);
const companyRulesPlans = await this.planService.findAll(company, {
relations: ['planAssignements', 'planAssignements.user'],
ids: companyHoldRules.map(({ planId }) => planId).filter(Boolean),
});
const activeUsers = uniq(
companyRulesPlans
.flatMap((p) => p.planAssignements)
.filter((pa) => !pa!.user!.clearedAt)
.map((pa) => pa!.userId),
);
const statementCalculationCache = await this.statementCalculationCacheFactory.instantiate(company, {
ruleIds: companyHoldRules.map((r) => r.id),
});
this.logger.log(`Company ${companyId} -- Payment Release : ${activeUsers.length} users to check -- STARTED`);
try {
await this.statementSaveService.releasePaymentsForUsers(
activeUsers,
period,
company,
statementCalculationCache,
);
} catch (e) {
const error = toError(e);
this.logger.error({
message: `Company ${companyId} -- Payment Release -- ERROR -- ${error.message}`,
error,
});
}
this.logger.log(`Company ${companyId} -- Payment Release -- ENDED`);
});
}
}
|