payments/src/lib/actions/request.ts

import { Payment } from '../types';
import { tracer } from '@capchase/tracer';
import {
  request,
  Channel,
  PaymentRequestResponse,
} from '@capchase/messaging-system';
import { currentDescriptor } from '../utils';
import { format } from 'date-fns';
import { callLog } from '../call_log';
import { incrementMetric } from '@capchase/metrics';

const internalRequestPayment = async (
  payment: Payment,
  actionBy: string
): Promise<PaymentRequestResponse> => {
  await callLog({
    callName: 'requestPayment',
    actionBy,
    args: [payment, actionBy],
  });

  const span = tracer?.scope()?.active();

  // TODO(SHI-1454): Validate actual user permissions
  if (actionBy.length === 0) {
    throw new Error('Action by should be set');
  }

  span?.addTags({
    action_by: actionBy,
  });

  const response = await request<PaymentRequestResponse>(
    Channel.PAYMENT_REQUEST,
    {
      id: payment.key,
      amount: {
        amount: payment.amount,
        currency: payment.currency,
      },
      originating_bank_account_id: payment.originatingAccount,
      // Counterparty information
      bank_account_id: payment.receivingAccount,
      company: {
        id: payment.companyId,
      },
      description:
        payment.description ||
        `PS - ${payment.contractName.toUpperCase()} - ${payment.companyId}`,
      direction: (payment.direction as string).toLowerCase(),
      effective_date: format(payment.effectiveDate, 'yyyy-MM-dd'),
      transfer_descriptor: currentDescriptor(payment.effectiveDate),
      metadata: {
        contract_name: payment.contractName,
        source: 'payment_system',
      },
    },
    10_000
  );

  incrementMetric('payment_system.payment.request', {
    success: response.ok ? 'true' : 'false',
  });

  return response;
};

/**
 * Requests the given payment to the messaging system via a req-reply flow.
 *
 * Currently this is done via NATS to Orchestrator.
 *
 * @param {Payment} payment The payment to be requested
 * @param {string} actionBy The action executor
 * @return {Promise<PaymentRequestResponse>} The request response by the external service
 *
 * @async
 * @function
 * @memberOf module:payments/actions
 * @access public
 */
const requestPayment =
  tracer?.wrap('payments.requestPayment', internalRequestPayment) ||
  internalRequestPayment;

export { requestPayment };