/* * Copyright (C) 2015 Arthur Gregorio, AG.Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package br.com.webbudget.domain.model.service; import br.com.webbudget.domain.model.entity.entries.Wallet; import br.com.webbudget.domain.model.entity.entries.WalletBalance; import br.com.webbudget.domain.model.entity.entries.WalletBalanceType; import br.com.webbudget.domain.model.entity.entries.WalletType; import br.com.webbudget.domain.misc.BalanceBuilder; import br.com.webbudget.domain.misc.ex.InternalServiceError; import br.com.webbudget.domain.model.repository.entries.IWalletBalanceRepository; import br.com.webbudget.domain.model.repository.entries.IWalletRepository; import java.math.BigDecimal; import java.util.List; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.inject.Inject; import javax.transaction.Transactional; import br.com.webbudget.domain.misc.events.UpdateBalance; import br.com.webbudget.application.component.table.Page; import br.com.webbudget.application.component.table.PageRequest; /** * Serice para manutencao dos processos relacionados a carteiras e saldos * * @author Arthur Gregorio * * @version 1.2.0 * @since 1.0.0, 12/03/2014 */ @ApplicationScoped public class WalletService { @Inject private IWalletRepository walletRepository; @Inject private IWalletBalanceRepository walletBalanceRepository; /** * * @param wallet */ @Transactional public void saveWallet(Wallet wallet) { final Wallet found = this.findWalletByNameAndBankAndType(wallet.getName(), wallet.getBank(), wallet.getWalletType()); if (found != null) { throw new InternalServiceError("error.wallet.duplicated"); } wallet = this.walletRepository.save(wallet); // se a carteira teve um saldo inicial != 0, entao ajustamos ela para o // saldo informado pelo usuario no momento da criacao if (wallet.getBalance().compareTo(BigDecimal.ZERO) != 0) { final BalanceBuilder builder = new BalanceBuilder(); builder.forWallet(wallet) .withOldBalance(BigDecimal.ZERO) .withActualBalance(wallet.getBalance()) .withMovementedValue(wallet.getBalance()) .andType(WalletBalanceType.ADJUSTMENT); this.updateBalance(builder); } } /** * * @param wallet * @return */ @Transactional public Wallet updateWallet(Wallet wallet) { final Wallet found = this.findWalletByNameAndBankAndType(wallet.getName(), wallet.getBank(), wallet.getWalletType()); if (found != null && !found.equals(wallet)) { throw new InternalServiceError("error.wallet.duplicated"); } return this.walletRepository.save(wallet); } /** * * @param wallet */ @Transactional public void deleteWallet(Wallet wallet) { // checa se a carteira nao tem saldo menor ou maior que zero // se houve, dispara o erro, comente carteiras zeradas sao deletaveis if (wallet.getBalance().compareTo(BigDecimal.ZERO) != 0) { throw new InternalServiceError("error.wallet.has-balance"); } final List<WalletBalance> balaces = this.listBalances(wallet); balaces.stream().forEach((balance) -> { this.walletBalanceRepository.delete(balance); }); this.walletRepository.delete(wallet); } /** * * @param walletBalance */ @Transactional public void transfer(WalletBalance walletBalance) { if (walletBalance.getSourceWallet().equals(walletBalance.getTargetWallet())) { throw new InternalServiceError("error.transfer.same-wallet"); } // atualizamos o destino final BalanceBuilder builderTarget = new BalanceBuilder(); final Wallet target = walletBalance.getTargetWallet(); final BigDecimal targetOldBalance = target.getBalance(); final BigDecimal targetNewBalance = targetOldBalance.add(walletBalance.getMovementedValue()); builderTarget.forWallet(target) .fromWallet(walletBalance.getSourceWallet()) .withOldBalance(targetOldBalance) .withActualBalance(targetNewBalance) .withMovementedValue(walletBalance.getMovementedValue()) .byTheReason(walletBalance.getReason()) .andType(WalletBalanceType.TRANSFERENCE); this.updateBalance(builderTarget); // atualizamos a origem final BalanceBuilder builderSource = new BalanceBuilder(); final Wallet source = walletBalance.getSourceWallet(); final BigDecimal sourceOldBalance = source.getBalance(); final BigDecimal sourceNewBalance = sourceOldBalance.subtract(walletBalance.getMovementedValue()); builderSource.forWallet(source) .withOldBalance(sourceOldBalance) .withActualBalance(sourceNewBalance) .withMovementedValue(walletBalance.getMovementedValue()) .andType(WalletBalanceType.TRANSFER_ADJUSTMENT); this.updateBalance(builderSource); } /** * Chamada para ajuste do saldo da carteira * * @param wallet a carteira a ser ajustada, dentro dela os dados do ajuste */ @Transactional public void adjustBalance(Wallet wallet) { // atualizamos o novo saldo final BigDecimal oldBalance = wallet.getBalance(); final BigDecimal newBalance = oldBalance.add(wallet.getAdjustmentValue()); final BalanceBuilder builder = new BalanceBuilder(); builder.forWallet(wallet) .withOldBalance(oldBalance) .withActualBalance(newBalance) .withMovementedValue(wallet.getAdjustmentValue()) .byTheReason(wallet.getReason()) .andType(WalletBalanceType.ADJUSTMENT); this.updateBalance(builder); } /** * Metodo que escuta por eventos de edicao do saldo das carteiras e entao * ao receber uma chamada, atualiza o saldo e grava o historico de saldo * * OBS: todas as atualizacoes de saldo dentro do sistema DEVEM seguir o * fluxo de evento chegando ate este metodo * * @param builder o builder para contrucao do saldo */ @Transactional public void updateBalance(@Observes @UpdateBalance BalanceBuilder builder) { final WalletBalance walletBalance = builder.build(); final Wallet wallet = walletBalance.getTargetWallet(); // seta o saldo na carteira wallet.setBalance(walletBalance.getActualBalance()); // salva carteira this.walletRepository.save(wallet); // salva o saldo this.walletBalanceRepository.save(walletBalance); } /** * * @param walletId * @return */ public Wallet findWalletById(long walletId) { return this.walletRepository.findById(walletId, false); } /** * * @param name * @param bank * @param walletType * @return */ public Wallet findWalletByNameAndBankAndType(String name, String bank, WalletType walletType) { return this.walletRepository.findByNameAndBankAndType(name, bank, walletType); } /** * * @param isBlocked * @param pageRequest * @return */ public Page<Wallet> listWalletsLazily(Boolean isBlocked, PageRequest pageRequest) { return this.walletRepository.listLazilyByStatus(isBlocked, pageRequest); } /** *S * @param isBlocked * @return */ public List<Wallet> listWallets(Boolean isBlocked) { return this.walletRepository.listByStatus(isBlocked); } /** * * @param wallet * @return */ public List<WalletBalance> listBalances(Wallet wallet) { return this.walletBalanceRepository.listByWallet(null, wallet); } /** * * @param source * @param target * @return */ public List<WalletBalance> listTransferences(Wallet source, Wallet target) { return this.walletBalanceRepository.listByWallet(source, target, WalletBalanceType.TRANSFERENCE); } }