Analysis Pattern: Transação Contábil (Accounting Transaction)

O que é

Detalhes de funcionamento

Quando deve ser usado

Código Exemplo

Transações com dois lançamentos

public class TransacaoContabil {
private Collection lancamentos = new HashSet();
public TransacaoContabil(Money valor, Conta de, Conta para, Calendar data) {
Lancamento lancamentoDe = new Lancamento(valor.negate(), data);
de.addLancamento(lancamentoDe);
lancamentos.add(lancamentoDe);
Lancamento lancamentoPara = new Lancamento(valor, data);
para.addLancamento(lancamentoPara);
lancamentos.add(lancamentoPara);
}
}
void saque(Money valor, Conta alvo, Calendar data) {
new TransacaoContabil(valor, this, alvo, data);
}
public void testBalancoUsandoTransacoes() {
receitas = new Conta(Moeda.BR);
contasProteladas = new Conta(Moeda.BR);
contasAReceber = new Conta(Moeda.BR);
receitas.saque(Money.reais(500), contasAReceber, criaCalendar(2003, 10, 1));
receitas.saque(Money.reais(200), contasProteladas, criaCalendar(2003, 10, 1));
assertEquals(Money.reais(500), contasAReceber.saldo());
assertEquals(Money.reais(200), contasProteladas.saldo());
assertEquals(Money.reais(-700), receitas.saldo());
}

Transações multi-lançamento

public class TransacaoContabil {
private Calendar data;
private Collection lancamentos = new HashSet();
private boolean fechada = false;
public TransacaoContabil(Calendar data) {
this.data = data;
}
}
class TransacaoContabil {
...
public void add(Money valor, Conta Conta) {
if (fechada) {
throw new TransacaoImutavelException( "Nao pode adicionar lancamento numa transacao fechada"); }
lancamentos.add(new Lancamento(valor, data, Conta, this));
}
}
class Lancamento {
...
private Money valor;
private Calendar data;
private Conta conta;
private TransacaoContabil transacao;
Lancamento(
Money valor,
Calendar data,
Conta conta,
TransacaoContabil transacao) {
this.valor = valor;
this.data = data;
this.conta = Conta;
this.transacao = transacao;
}
}
class TransacaoContabil {
...
public void lançar() {
if (!podeLançar())
throw new NaoPodeLancarException();
Iterator it = lancamentos.iterator();
while (it.hasNext()) {
Lancamento umLancamento = (Lancamento) it.next();
umLancamento.lançar();
}
fechada = true;
}
public boolean podeLançar() {
return saldo().isZero();
}
private Money saldo() {
Money resultado = Money.reais(0);
Iterator it = lancamentos.iterator();
while(it.hasNext()) {
Lancamento umLancamento = (Lancamento) it.next();
resultado = resultado.add(umLancamento.valor());
}
return resultado;
}
}
class Lancamento {
...
void lançar() {
conta.addLancamento(this);
}
}
void testMulti() {
TransacaoContabil multi = new TransacaoContabil(criaCalendar(2003, 10, 25));
multi.add(Money.reais(-700), receitas);
multi.add(Money.reais(500), contasAReceber);
multi.add(Money.reais(200), contasProteladas);
multi.lançar();
assertEquals(Money.reais(500), contasAReceber.saldo());
assertEquals(Money.reais(200), contasProteladas.saldo());
assertEquals(Money.reais(-700), receitas.saldo());
}
class Conta {
...
void saque(Money valor, Conta alvo, Calendar data) {
TransacaoContabil trans = new TransacaoContabil(data);
trans.add(valor.negate(), this);
trans.add(valor, alvo);
trans.lançar();
}
}

programa