Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
feat(143): Publica msg pagamento confirmado
Browse files Browse the repository at this point in the history
  • Loading branch information
dannevesdantas committed Jun 30, 2024
1 parent 7b8f037 commit 56aeb7c
Show file tree
Hide file tree
Showing 23 changed files with 212 additions and 162 deletions.
8 changes: 3 additions & 5 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
MONGO_URL="mongodb://admin:pass@localhost:27017/"

URL_API_PEDIDOS=http://localhost:3002/pedido

# AWS SDK
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
Expand All @@ -20,9 +18,9 @@ NOME_FILA_COBRANCA_GERADA=cobranca-gerada
URL_FILA_COBRANCA_GERADA=http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/cobranca-gerada
REGION_FILA_COBRANCA_GERADA=us-east-1
# Fila de falha na cobrança
NOME_FILA_FALHA_COBRANCA=falha-cobranca
URL_FILA_FALHA_COBRANCA=http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/falha-cobranca
REGION_FILA_FALHA_COBRANCA=us-east-1
NOME_FILA_PAGAMENTO_CONFIRMADO=pagamento-confirmado
URL_FILA_PAGAMENTO_CONFIRMADO=http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/pagamento-confirmado
REGION_FILA_PAGAMENTO_CONFIRMADO=us-east-1

LOCALSTACK_ENDPOINT=http://sqs.us-east-1.localhost.localstack.cloud:4566

Expand Down
4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ services:
- .env
environment:
MONGO_URL: mongodb://admin:pass@db-pagamentos:27017/
URL_API_PEDIDOS: http://api-pedidos:3002/pedido
LOCALSTACK_ENDPOINT: http://localstack:4566
NOME_FILA_NOVA_COBRANCA: ${NOME_FILA_NOVA_COBRANCA:-nova-cobranca}
URL_FILA_NOVA_COBRANCA: http://localstack:4566/000000000000/nova-cobranca
Expand All @@ -26,6 +25,9 @@ services:
NOME_FILA_FALHA_COBRANCA: ${NOME_FILA_FALHA_COBRANCA:-falha-cobranca}
URL_FILA_FALHA_COBRANCA: http://localstack:4566/000000000000/falha-cobranca
REGION_FILA_FALHA_COBRANCA: ${REGION_FILA_FALHA_COBRANCA:-us-east-1}
NOME_FILA_PAGAMENTO_CONFIRMADO: pagamento-confirmado
URL_FILA_PAGAMENTO_CONFIRMADO: http://localstack:4566/000000000000/pagamento-confirmado
REGION_FILA_PAGAMENTO_CONFIRMADO: ${REGION_FILA_PAGAMENTO_CONFIRMADO:-us-east-1}
BASE_URL_API_MERCADOPAGO: ${BASE_URL_API_MERCADOPAGO:-https://api.mercadopago.com}
ACCESS_TOKEN_MERCADOPAGO: ${ACCESS_TOKEN_MERCADOPAGO:-}
USER_ID_MERCADOPAGO: ${USER_ID_MERCADOPAGO:-}
Expand Down
1 change: 0 additions & 1 deletion k8s/production/api/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ metadata:
labels:
app: rms-api-pagamentos
data:
URL_API_PEDIDOS: "http://rms-api-pedidos.rms.svc.cluster.local:80/pedido"
BASE_URL_API_MERCADOPAGO: "https://api.mercadopago.com"
IDEMPOTENCY_KEY_MERCADOPAGO: "a005986e-f97c-4274-91cf-b32d2672824f"
15 changes: 15 additions & 0 deletions k8s/production/api/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ spec:
secretKeyRef:
name: sqs-fila-falha-cobranca-secret
key: REGION_FILA_FALHA_COBRANCA
- name: NOME_FILA_PAGAMENTO_CONFIRMADO
valueFrom:
secretKeyRef:
name: sqs-fila-pagamento-confirmado-secret
key: NOME_FILA_PAGAMENTO_CONFIRMADO
- name: URL_FILA_PAGAMENTO_CONFIRMADO
valueFrom:
secretKeyRef:
name: sqs-fila-pagamento-confirmado-secret
key: URL_FILA_PAGAMENTO_CONFIRMADO
- name: REGION_FILA_PAGAMENTO_CONFIRMADO
valueFrom:
secretKeyRef:
name: sqs-fila-pagamento-confirmado-secret
key: REGION_FILA_PAGAMENTO_CONFIRMADO
ports:
- containerPort: 3003
resources:
Expand Down
20 changes: 20 additions & 0 deletions k8s/production/api/secret-provider.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ spec:
- secretName: mercadopago-secret # Nome do Secret que será montado automaticamente contendo os segredos do AWS Secrets Manager
type: Opaque
data:
- objectName: BASE_URL_API_MERCADOPAGO
key: BASE_URL_API_MERCADOPAGO
- objectName: ACCESS_TOKEN_MERCADOPAGO
key: ACCESS_TOKEN_MERCADOPAGO
- objectName: USER_ID_MERCADOPAGO
Expand Down Expand Up @@ -49,6 +51,15 @@ spec:
key: URL_FILA_FALHA_COBRANCA
- objectName: REGION_FILA_FALHA_COBRANCA
key: REGION_FILA_FALHA_COBRANCA
- secretName: sqs-fila-pagamento-confirmado-secret # Nome do Secret que será montado automaticamente contendo os segredos do AWS Secrets Manager
type: Opaque
data:
- objectName: NOME_FILA_PAGAMENTO_CONFIRMADO
key: NOME_FILA_PAGAMENTO_CONFIRMADO
- objectName: URL_FILA_PAGAMENTO_CONFIRMADO
key: URL_FILA_PAGAMENTO_CONFIRMADO
- objectName: REGION_FILA_PAGAMENTO_CONFIRMADO
key: REGION_FILA_PAGAMENTO_CONFIRMADO
parameters:
# Informe abaixo no campo objectName os nomes dos Segredos do AWS Secrets Manager que deseja acessar.
# Certifique-se de que as Keys declaradas abaixo existem e estão preenchidas na AWS, caso contrário receberá o erro "Failed to fetch secret from all regions"
Expand Down Expand Up @@ -98,3 +109,12 @@ spec:
objectAlias: "URL_FILA_FALHA_COBRANCA"
- path: "QUEUE_REGION"
objectAlias: "REGION_FILA_FALHA_COBRANCA"
- objectName: "prod/RMS/SQSPagamentoConfirmado"
objectType: "secretsmanager"
jmesPath:
- path: "QUEUE_NAME"
objectAlias: "NOME_FILA_PAGAMENTO_CONFIRMADO"
- path: "QUEUE_URL"
objectAlias: "URL_FILA_PAGAMENTO_CONFIRMADO"
- path: "QUEUE_REGION"
objectAlias: "REGION_FILA_PAGAMENTO_CONFIRMADO"
8 changes: 4 additions & 4 deletions src/application/use_cases/pedido/pedido.use_case.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { IPedidoFactory } from 'src/domain/pedido/interfaces/pedido.factory.port
import { IGatewayPagamentoService } from 'src/domain/pedido/interfaces/gatewaypag.service.port';
import { IPedidoDTOFactory } from 'src/domain/pedido/interfaces/pedido.dto.factory.port';
import {
apiPedidosServiceMock,
filaPagamentoConfirmadoAdapter,
criaPedidoDTOMock,
filaCobrancaGeradaAdapterMock,
filaFalhaCobrancaAdapter,
Expand All @@ -17,7 +17,7 @@ import {
pedidoModelMock,
pedidoRepositoryMock,
} from 'src/mocks/pedido.mock';
import { IApiPedidosService } from 'src/domain/pedido/interfaces/apipedido.service.port';
import { IFilaPagamentoConfirmadoAdapter } from 'src/domain/pedido/interfaces/pag_confirmado_adapter';
import { ConfigService } from '@nestjs/config';
import { Logger } from '@nestjs/common';
import { IFilaCobrancaGeradaAdapter } from 'src/domain/pedido/interfaces/cobranca_gerada.port';
Expand Down Expand Up @@ -45,8 +45,8 @@ describe('PedidoUseCase', () => {
useValue: gatewayPagamentoServiceMock,
},
{
provide: IApiPedidosService,
useValue: apiPedidosServiceMock,
provide: IFilaPagamentoConfirmadoAdapter,
useValue: filaPagamentoConfirmadoAdapter,
},
{
provide: IPedidoDTOFactory,
Expand Down
10 changes: 5 additions & 5 deletions src/application/use_cases/webhook/webhook.use_case.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { IPedidoFactory } from 'src/domain/pedido/interfaces/pedido.factory.port
import { IGatewayPagamentoService } from 'src/domain/pedido/interfaces/gatewaypag.service.port';
import { IPedidoDTOFactory } from 'src/domain/pedido/interfaces/pedido.dto.factory.port';
import {
apiPedidosServiceMock,
filaPagamentoConfirmadoAdapter,
gatewayPagamentoServiceMock,
pedidoDTOFactoryMock,
pedidoDTOMock,
Expand All @@ -16,7 +16,7 @@ import {
import { ConfigService } from '@nestjs/config';
import { WebhookUseCase } from './webhook.use_case';
import { Logger } from '@nestjs/common';
import { IApiPedidosService } from 'src/domain/pedido/interfaces/apipedido.service.port';
import { IFilaPagamentoConfirmadoAdapter } from 'src/domain/pedido/interfaces/pag_confirmado_adapter';

describe('WebhookUseCase', () => {
let webhookUseCase: WebhookUseCase;
Expand All @@ -41,8 +41,8 @@ describe('WebhookUseCase', () => {
useValue: gatewayPagamentoServiceMock,
},
{
provide: IApiPedidosService,
useValue: apiPedidosServiceMock,
provide: IFilaPagamentoConfirmadoAdapter,
useValue: filaPagamentoConfirmadoAdapter,
},
{
provide: IPedidoDTOFactory,
Expand Down Expand Up @@ -76,7 +76,7 @@ describe('WebhookUseCase', () => {
null,
);

expect(apiPedidosServiceMock.atualizarStatusPedido).toHaveBeenCalledWith(
expect(filaPagamentoConfirmadoAdapter.publicarPagamentoConfirmado).toHaveBeenCalledWith(
pedidoId,
);
expect(result).toStrictEqual({
Expand Down
29 changes: 10 additions & 19 deletions src/application/use_cases/webhook/webhook.use_case.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Inject, Injectable, Logger } from '@nestjs/common';
import { IApiPedidosService } from 'src/domain/pedido/interfaces/apipedido.service.port';
import { IFilaPagamentoConfirmadoAdapter } from 'src/domain/pedido/interfaces/pag_confirmado_adapter';
import { IGatewayPagamentoService } from 'src/domain/pedido/interfaces/gatewaypag.service.port';
import { IPedidoRepository } from 'src/domain/pedido/interfaces/pedido.repository.port';
import { IWebhookUseCase } from 'src/domain/pedido/interfaces/webhook.use_case.port';
import {
MensagemMercadoPagoDTO,
NotificacaoMercadoPagoDTO,
PedidoGatewayPagamentoDTO,
} from 'src/presentation/rest/v1/presenters/pedido/gatewaypag.dto';

Expand All @@ -16,44 +16,35 @@ export class WebhookUseCase implements IWebhookUseCase {
private readonly pedidoRepository: IPedidoRepository,
@Inject(IGatewayPagamentoService)
private readonly gatewayPagamentoService: IGatewayPagamentoService,
@Inject(IApiPedidosService)
private readonly apiPedidosService: IApiPedidosService,
) {}
@Inject(IFilaPagamentoConfirmadoAdapter)
private readonly filaPagamentoConfirmadoAdapter: IFilaPagamentoConfirmadoAdapter,
) { }

async consumirMensagem(
id: string,
topic: string,
mensagem: MensagemMercadoPagoDTO,
notificacao: NotificacaoMercadoPagoDTO,
): Promise<any> {
this.logger.debug(
`Processando request do Mercado Pago...`,
id,
topic,
mensagem,
);
this.logger.debug(`Processando request do Mercado Pago...`);
await this.pedidoRepository.guardarMsgWebhook(
id,
topic,
JSON.stringify(mensagem),
JSON.stringify(notificacao),
);

if (id && topic === 'merchant_order') {
const pedidoGatewayPag =
await this.gatewayPagamentoService.consultarPedido(id);
const idInternoPedido = pedidoGatewayPag.external_reference;

if (this.verificarPagamento(pedidoGatewayPag)) {
this.logger.log(
`O pedido ${idInternoPedido} foi pago`,
pedidoGatewayPag,
);

// TODO: Abaixo, ao invés de chamar a API de Pedidos, publicar msg na fila pagamento-confirmado ( ̶p̶a̶g̶a̶m̶e̶n̶t̶o̶-̶r̶e̶a̶l̶i̶z̶a̶d̶o̶)
this.apiPedidosService.atualizarStatusPedido(idInternoPedido);
this.filaPagamentoConfirmadoAdapter.publicarPagamentoConfirmado(idInternoPedido);
} else {
// TODO: Publicar msg na fila falha-pagamento
// TODO: Publicar msg na fila falha-pagamento?
}

this.logger.debug(`A request do Mercado Pago foi processada com sucesso`);
return {
mensagem: 'Request processada com sucesso',
Expand Down
5 changes: 0 additions & 5 deletions src/domain/pedido/interfaces/apipedido.service.port.ts

This file was deleted.

5 changes: 5 additions & 0 deletions src/domain/pedido/interfaces/pag_confirmado_adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface IFilaPagamentoConfirmadoAdapter {
publicarPagamentoConfirmado(idPedido: string): Promise<void>;
}

export const IFilaPagamentoConfirmadoAdapter = Symbol('IFilaPagamentoConfirmadoAdapter');
4 changes: 2 additions & 2 deletions src/domain/pedido/interfaces/webhook.use_case.port.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { MensagemMercadoPagoDTO } from 'src/presentation/rest/v1/presenters/pedido/gatewaypag.dto';
import { NotificacaoMercadoPagoDTO } from "src/presentation/rest/v1/presenters/pedido/gatewaypag.dto";

export interface IWebhookUseCase {
consumirMensagem(
id: string,
topic: string,
mensagem?: MensagemMercadoPagoDTO,
notificacao?: NotificacaoMercadoPagoDTO,
): Promise<any>;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { FilaPagamentoConfirmadoAdapter } from './pag_confirmado.adapter';
import { pedidoDTOMock } from 'src/mocks/pedido.mock';
import { SqsService } from '@ssut/nestjs-sqs';
import { Logger } from '@nestjs/common';

describe('FilaPagamentoConfirmadoAdapter', () => {
let filaPagamentoConfirmadoAdapter: FilaPagamentoConfirmadoAdapter;
let configService: ConfigService;
let sqsService: SqsService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
Logger,
FilaPagamentoConfirmadoAdapter,
{
provide: ConfigService,
useValue: {
get: jest.fn(),
getOrThrow: jest.fn(),
},
},
{
provide: SqsService,
useValue: {
send: jest.fn(),
},
},
],
}).compile();

filaPagamentoConfirmadoAdapter = module.get<FilaPagamentoConfirmadoAdapter>(
FilaPagamentoConfirmadoAdapter,
);
configService = module.get<ConfigService>(ConfigService);
sqsService = module.get<SqsService>(SqsService);
});

afterEach(() => {
jest.clearAllMocks();
});

it('deve publicar falha na cobrança', async () => {
jest.spyOn(configService, 'getOrThrow').mockReturnValue('falha-cobranca');
jest.spyOn(sqsService, 'send');

await filaPagamentoConfirmadoAdapter.publicarPagamentoConfirmado(pedidoDTOMock.id);
expect(sqsService.send).toHaveBeenCalled();
});

it('deve lançar exceção ao publicar falha na cobrança', async () => {
jest.spyOn(configService, 'getOrThrow').mockReturnValue('falha-cobranca');
jest.spyOn(sqsService, 'send').mockRejectedValue(new Error('Erro'));

await expect(
filaPagamentoConfirmadoAdapter.publicarPagamentoConfirmado(pedidoDTOMock.id),
).rejects.toThrow('Ocorreu um erro ao publicar a mensagem.');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { SqsService } from '@ssut/nestjs-sqs';
import { IFilaPagamentoConfirmadoAdapter } from 'src/domain/pedido/interfaces/pag_confirmado_adapter';

@Injectable()
export class FilaPagamentoConfirmadoAdapter implements IFilaPagamentoConfirmadoAdapter {
constructor(
private readonly logger: Logger,
private readonly configService: ConfigService,
private readonly sqsService: SqsService,
) { }
async publicarPagamentoConfirmado(idPedido: string) {
const queueName = this.configService.getOrThrow<string>(
'NOME_FILA_PAGAMENTO_CONFIRMADO',
);
try {
await this.sqsService.send(queueName, {
id: 'id',
body: idPedido,
});
this.logger.log(
`A confirmação de pagamento do pedido ${idPedido} foi publicada na fila ${queueName}`,
idPedido,
);
} catch (error) {
this.logger.error(
`Ocorreu um erro ao publicar o pedido ${idPedido} na fila ${queueName}`,
error,
);
throw new Error('Ocorreu um erro ao publicar a mensagem.');
}
}
}
Loading

0 comments on commit 56aeb7c

Please sign in to comment.