Skip to content

Instantly share code, notes, and snippets.

@joaovictorino
Last active January 22, 2024 22:29
Show Gist options
  • Save joaovictorino/dc7cb647e82d18779dbd20835260891e to your computer and use it in GitHub Desktop.
Save joaovictorino/dc7cb647e82d18779dbd20835260891e to your computer and use it in GitHub Desktop.
Fix

__tests__/application/TransferenciaServico.test.ts

import { TransferenciaServico } from "../../src/application/TransferenciaServico";
import { MemoriaContaRepositorio } from "../fake/MemoriaContaRepositorio";
import { TransferenciaDTO } from "../../src/application/dto/TransferenciaDTO";
import { Conta } from "../../src/model/Conta";
import { Repositorio } from "../../src/model/contract/Repositorio";

describe("Transferência Serviço", () =>{

    test("transferir com sucesso", async () => {
        const repositorio: Repositorio<string, Conta> = new MemoriaContaRepositorio();
        const contaOrigem: Conta = new Conta("123456", 5000);
        const contaDestino: Conta = new Conta("654321", 5000);
        repositorio.adicionar(contaOrigem);
        repositorio.adicionar(contaDestino);

        const transferenciaServico: TransferenciaServico = new TransferenciaServico(repositorio);
        const dto: TransferenciaDTO = new TransferenciaDTO("123456", "654321", 100.0);

        const recibo: string = await transferenciaServico.transferir(dto);
        
        const contaOrigemRepo = await repositorio.buscar("123456");
        const contaDestinoRepo = await repositorio.buscar("654321");
        expect(contaOrigemRepo!.saldo).toBe(4900.0);
        expect(contaDestinoRepo!.saldo).toBe(5100.0);
        expect(recibo.length).toBe(6);
    });
});

__tests__/fake/MemoriaContaRepositorio.ts

import { Repositorio } from "../../src/model/contract/Repositorio";
import { Conta } from "../../src/model/Conta";

export class MemoriaContaRepositorio implements Repositorio<string, Conta> {
    private _dicionario: Map<string, Conta>;

    public constructor(){
        this._dicionario = new Map<string, Conta>();
    }

    public async buscar(numero: string): Promise<Conta | undefined> {
        const promise = new Promise<Conta | undefined>((resolve, reject) => {
            resolve(this._dicionario.get(numero));
        });
        return promise;
    }

    public adicionar(conta: Conta): void {
        this._dicionario.set(conta.numero, conta);
    }
}

__tests__/model/service/TransferenciaValor.test.ts

import { Conta } from "../../../src/model/Conta";
import { Recibo } from "../../../src/model/Recibo";
import { TransferenciaValor } from "../../../src/model/service/TransferenciaValor";

describe("Transferencia Valor", () => {
    test("transferencia de valor entre contas com sucesso", async () => {
        const contaOrigem: Conta = new Conta("123456", 1000.0);
        const contaDestino: Conta = new Conta("654321", 1000.0);

        const transferenciaValor: TransferenciaValor = new TransferenciaValor();
        const recibo: Recibo = transferenciaValor.transferir(contaOrigem, contaDestino, 100.0);

        expect(contaOrigem.saldo).toBe(900.0);
        expect(contaDestino.saldo).toBe(1100.0);
        expect(recibo.codigo.length).toBe(6);
    });
});

src/application/TransferenciaServico.ts

import { Repositorio } from "../model/contract/Repositorio";
import { Conta } from "../model/Conta";
import { TransferenciaDTO } from "./dto/TransferenciaDTO";
import { TransferenciaValor } from "../model/service/TransferenciaValor";
import { Recibo } from "../model/Recibo";

export class TransferenciaServico {
    private _repositorio: Repositorio<string, Conta>;

    public constructor(repositorio: Repositorio<string, Conta>){
        this._repositorio = repositorio;
    }

    public async transferir(dto: TransferenciaDTO): Promise<string> {
        const contaOrigem = await this._repositorio.buscar(dto.contaOrigem);
        const contaDestino = await this._repositorio.buscar(dto.contaDestino);

        const transferencia: TransferenciaValor = new TransferenciaValor();
        const recibo: Recibo = transferencia.transferir(contaOrigem!, contaDestino!, dto.valor);

        this._repositorio.adicionar(contaOrigem!);
        this._repositorio.adicionar(contaDestino!);

        return recibo.codigo;
    }
}

src/error/NegocioErro.ts

export class NegocioErro extends Error {
    constructor(message: string) {
      super(message);
  
      Object.setPrototypeOf(this, NegocioErro.prototype);
    }
}

src/model/Conta.ts

import { NegocioErro } from "../error/NegocioErro";
import { NumeroConta } from "./NumeroConta";

export class Conta {
    private _numeroConta: NumeroConta;
    private _saldo: number;

    public constructor(numero: string, saldo: number) {
        this._numeroConta = new NumeroConta(numero);
        this._saldo = saldo;
    }

    public sacar(valor: number): void {
        this.validarValor(valor);

        if((this.saldo - valor) < 0)
            throw new NegocioErro("saldo indisponivel para a operação");

        this._saldo -= valor;
    }

    public depositar(valor: number): void {
        this.validarValor(valor);

        this._saldo += valor;
    }

    public get saldo(): number{
        return this._saldo;
    }

    public get numero(): string{
        return this._numeroConta.numero;
    }

    private validarValor(valor: number): void {
        if(valor <= 0)
            throw new NegocioErro("valor não pode ser igual ou menor que zero");
    }
}

src/model/NumeroConta.ts

import { NegocioErro } from "../error/NegocioErro";

export class NumeroConta {
    private _numero: string;

    public constructor(numero: string) {
        if(!this.temSeisDigitos(numero))
            throw new NegocioErro("número da conta inválido");

        this._numero = numero;
    }

    public get numero(): string {
        return this._numero;
    }

    private temSeisDigitos(numero: string): boolean {
        const regExp: RegExp = /^\d{6}$/;
        return regExp.test(numero);
    }
}

src/model/contract/Repositorio.ts

export interface Repositorio<I, T>{
    buscar(campo: I): Promise<T | undefined>;
    adicionar(entidade: T): void;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment