diff --git a/src/main/java/diegosneves/github/rachapedido/config/ControllerExceptionHandler.java b/src/main/java/diegosneves/github/rachapedido/config/ControllerExceptionHandler.java index 71e449e..528f6a3 100644 --- a/src/main/java/diegosneves/github/rachapedido/config/ControllerExceptionHandler.java +++ b/src/main/java/diegosneves/github/rachapedido/config/ControllerExceptionHandler.java @@ -24,12 +24,6 @@ public ResponseEntity generalError(Exception exception) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(dto); } - @ExceptionHandler(CloseOrderException.class) - public ResponseEntity orderRelatedFaileures(CloseOrderException exception) { - ExceptionDTO dto = new ExceptionDTO(exception.getMessage(), CloseOrderException.ERROR.getStatusCodeValue()); - return ResponseEntity.status(CloseOrderException.ERROR.getHttpStatusCode()).body(dto); - } - @ExceptionHandler(CalculateInvoiceException.class) public ResponseEntity orderRelatedFaileures(CalculateInvoiceException exception) { ExceptionDTO dto = new ExceptionDTO(exception.getMessage(), CalculateInvoiceException.ERROR.getStatusCodeValue()); diff --git a/src/main/java/diegosneves/github/rachapedido/controller/contract/SplitInvoiceControllerContract.java b/src/main/java/diegosneves/github/rachapedido/controller/contract/SplitInvoiceControllerContract.java index 17e20ec..da23eb5 100644 --- a/src/main/java/diegosneves/github/rachapedido/controller/contract/SplitInvoiceControllerContract.java +++ b/src/main/java/diegosneves/github/rachapedido/controller/contract/SplitInvoiceControllerContract.java @@ -20,8 +20,10 @@ public interface SplitInvoiceControllerContract { @PostMapping(value = "/invoice", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Receber os dados para realizar a divisão da fatura", tags = "Racha Pedido", parameters = { - @Parameter(name = "referencia", description = "Tipos de descontos que devem ser aplicado no `discountType` do body", - schema = @Schema(enumAsRef = true, defaultValue = "cash", allowableValues = {"cash", "percentage", "no discount"})) + @Parameter(name = "descontos", description = "Tipos de descontos a serem aplicados no campo `discountType` do corpo da requisição", + schema = @Schema(enumAsRef = true, defaultValue = "cash", allowableValues = {"cash", "percentage", "no discount"})), + @Parameter(name = "bancos", description = "Tipos de bancos aceitos que devem ser preenchidos no campo `selectedBank` do corpo da requisição", + schema = @Schema(enumAsRef = true, defaultValue = "nubank", allowableValues = {"nubank", "picpay"})) }) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Divisão da Fatura realizada com sucesso", content = @Content) diff --git a/src/main/java/diegosneves/github/rachapedido/core/BankAccount.java b/src/main/java/diegosneves/github/rachapedido/core/BankAccount.java index 7ba4b8b..688a22f 100644 --- a/src/main/java/diegosneves/github/rachapedido/core/BankAccount.java +++ b/src/main/java/diegosneves/github/rachapedido/core/BankAccount.java @@ -5,18 +5,32 @@ public enum BankAccount { @JsonProperty(value = "nubank") - NUBANK("https://nubank.com.br/cobrar/5h2au/658235a8-f38a-4cf5-881c-1de7114d66c7"), + NUBANK("NuBank", "https://nubank.com.br/cobrar/5h2au/658235a8-f38a-4cf5-881c-1de7114d66c7") { + @Override + public String paymentLink(Double amount) { + return NUBANK.billingLink; + } + }, @JsonProperty(value = "picpay") - PICPAY("https://app.picpay.com/user/diego.neves215"); + PICPAY("PicPay", "https://app.picpay.com/user/diego.neves215") { + @Override + public String paymentLink(Double amount) { + return String.format("%s/%.2f", PICPAY.billingLink, amount); + } + }; + private final String bankName; private final String billingLink; - BankAccount(String billingLink) { + BankAccount(String bankName, String billingLink) { + this.bankName = bankName; this.billingLink = billingLink; } - public String paymentLink() { - return this.billingLink; - } + public abstract String paymentLink(Double amount); + @Override + public String toString() { + return this.bankName; + } } diff --git a/src/main/java/diegosneves/github/rachapedido/core/CashDiscountStrategy.java b/src/main/java/diegosneves/github/rachapedido/core/CashDiscountStrategy.java index 7f25079..5227bb2 100644 --- a/src/main/java/diegosneves/github/rachapedido/core/CashDiscountStrategy.java +++ b/src/main/java/diegosneves/github/rachapedido/core/CashDiscountStrategy.java @@ -1,20 +1,26 @@ package diegosneves.github.rachapedido.core; -import diegosneves.github.rachapedido.dto.InvoiceDTO; import diegosneves.github.rachapedido.enums.DiscountType; import diegosneves.github.rachapedido.mapper.BuilderMapper; +import diegosneves.github.rachapedido.mapper.InvoiceFromPersonMapper; import diegosneves.github.rachapedido.model.Invoice; +import diegosneves.github.rachapedido.model.Item; +import diegosneves.github.rachapedido.model.Person; import diegosneves.github.rachapedido.utils.RoundUtil; public class CashDiscountStrategy extends DiscountStrategy { @Override - public Invoice calculateDiscount(InvoiceDTO dto, Double discountAmount, DiscountType type, Double total, Double deliveryFee) { + public Invoice calculateDiscount(Person person, Double discountAmount, DiscountType type, Double total, Double deliveryFee) { if(DiscountType.CASH.name().equals(type.name())) { - dto.setPercentageConsumedTotalBill(dto.getValueConsumed() / total); - dto.setTotalPayable(RoundUtil.round(((total - type.discountAmount(discountAmount) + deliveryFee) * dto.getPercentageConsumedTotalBill()))); - return BuilderMapper.builderMapper(Invoice.class, dto); + InvoiceFromPersonMapper mapper = new InvoiceFromPersonMapper(); + Double consumption = person.getItems().stream().mapToDouble(Item::getPrice).sum(); + Double percentageConsumedTotalBill = consumption / total; + Invoice newInvoice = BuilderMapper.builderMapper(Invoice.class, person, mapper); + newInvoice.setPercentageConsumedTotalBill(percentageConsumedTotalBill); + newInvoice.setTotalPayable(RoundUtil.round(((total - type.discountAmount(discountAmount) + deliveryFee) * percentageConsumedTotalBill))); + return newInvoice; } - return this.checkNext(dto, discountAmount, type, total, deliveryFee); + return this.checkNext(person, discountAmount, type, total, deliveryFee); } } diff --git a/src/main/java/diegosneves/github/rachapedido/core/DiscountStrategy.java b/src/main/java/diegosneves/github/rachapedido/core/DiscountStrategy.java index 48eb7d4..7399e01 100644 --- a/src/main/java/diegosneves/github/rachapedido/core/DiscountStrategy.java +++ b/src/main/java/diegosneves/github/rachapedido/core/DiscountStrategy.java @@ -1,8 +1,8 @@ package diegosneves.github.rachapedido.core; -import diegosneves.github.rachapedido.dto.InvoiceDTO; import diegosneves.github.rachapedido.enums.DiscountType; import diegosneves.github.rachapedido.model.Invoice; +import diegosneves.github.rachapedido.model.Person; public abstract class DiscountStrategy { @@ -16,13 +16,13 @@ public static DiscountStrategy link(DiscountStrategy first, DiscountStrategy... } return first; } - public abstract Invoice calculateDiscount(InvoiceDTO dto, Double discountAmount, DiscountType type, Double total, Double deliveryFee); + public abstract Invoice calculateDiscount(Person person, Double discountAmount, DiscountType type, Double total, Double deliveryFee); - protected Invoice checkNext(InvoiceDTO dto, Double discountAmount, DiscountType type, Double total, Double deliveryFee) { + protected Invoice checkNext(Person person, Double discountAmount, DiscountType type, Double total, Double deliveryFee) { if (this.next == null) { return new Invoice(); } - return next.calculateDiscount(dto, discountAmount, type, total, deliveryFee); + return next.calculateDiscount(person, discountAmount, type, total, deliveryFee); } } diff --git a/src/main/java/diegosneves/github/rachapedido/core/NoDiscountStrategy.java b/src/main/java/diegosneves/github/rachapedido/core/NoDiscountStrategy.java index 82a9bc5..78d0774 100644 --- a/src/main/java/diegosneves/github/rachapedido/core/NoDiscountStrategy.java +++ b/src/main/java/diegosneves/github/rachapedido/core/NoDiscountStrategy.java @@ -1,20 +1,26 @@ package diegosneves.github.rachapedido.core; -import diegosneves.github.rachapedido.dto.InvoiceDTO; import diegosneves.github.rachapedido.enums.DiscountType; import diegosneves.github.rachapedido.mapper.BuilderMapper; +import diegosneves.github.rachapedido.mapper.InvoiceFromPersonMapper; import diegosneves.github.rachapedido.model.Invoice; +import diegosneves.github.rachapedido.model.Item; +import diegosneves.github.rachapedido.model.Person; import diegosneves.github.rachapedido.utils.RoundUtil; public class NoDiscountStrategy extends DiscountStrategy { @Override - public Invoice calculateDiscount(InvoiceDTO dto, Double discountAmount, DiscountType type, Double total, Double deliveryFee) { + public Invoice calculateDiscount(Person person, Double discountAmount, DiscountType type, Double total, Double deliveryFee) { if (DiscountType.NO_DISCOUNT.name().equals(type.name())) { - dto.setPercentageConsumedTotalBill(dto.getValueConsumed() / total); - dto.setTotalPayable(RoundUtil.round((total - type.discountAmount(discountAmount) + deliveryFee) * dto.getPercentageConsumedTotalBill())); - return BuilderMapper.builderMapper(Invoice.class, dto); + Double consumption = person.getItems().stream().mapToDouble(Item::getPrice).sum(); + Double percentageConsumedTotalBill = consumption / total; + InvoiceFromPersonMapper mapper = new InvoiceFromPersonMapper(); + Invoice newInvoice = BuilderMapper.builderMapper(Invoice.class, person, mapper); + newInvoice.setPercentageConsumedTotalBill(percentageConsumedTotalBill); + newInvoice.setTotalPayable(RoundUtil.round((total - type.discountAmount(discountAmount) + deliveryFee) * percentageConsumedTotalBill)); + return newInvoice; } - return this.checkNext(dto, discountAmount, type, total, deliveryFee); + return this.checkNext(person, discountAmount, type, total, deliveryFee); } } diff --git a/src/main/java/diegosneves/github/rachapedido/core/PercentageDiscountStrategy.java b/src/main/java/diegosneves/github/rachapedido/core/PercentageDiscountStrategy.java index a178f17..7aee9f3 100644 --- a/src/main/java/diegosneves/github/rachapedido/core/PercentageDiscountStrategy.java +++ b/src/main/java/diegosneves/github/rachapedido/core/PercentageDiscountStrategy.java @@ -1,21 +1,27 @@ package diegosneves.github.rachapedido.core; -import diegosneves.github.rachapedido.dto.InvoiceDTO; import diegosneves.github.rachapedido.enums.DiscountType; import diegosneves.github.rachapedido.mapper.BuilderMapper; +import diegosneves.github.rachapedido.mapper.InvoiceFromPersonMapper; import diegosneves.github.rachapedido.model.Invoice; +import diegosneves.github.rachapedido.model.Item; +import diegosneves.github.rachapedido.model.Person; import diegosneves.github.rachapedido.utils.RoundUtil; public class PercentageDiscountStrategy extends DiscountStrategy { @Override - public Invoice calculateDiscount(InvoiceDTO dto, Double discountAmount, DiscountType type, Double total, Double deliveryFee) { + public Invoice calculateDiscount(Person person, Double discountAmount, DiscountType type, Double total, Double deliveryFee) { if (DiscountType.PERCENTAGE.name().equals(type.name())) { - dto.setPercentageConsumedTotalBill(dto.getValueConsumed() / total); - dto.setTotalPayable(RoundUtil.round((total - (total * type.discountAmount(discountAmount)) + deliveryFee) * dto.getPercentageConsumedTotalBill())); - return BuilderMapper.builderMapper(Invoice.class, dto); + Double consumption = person.getItems().stream().mapToDouble(Item::getPrice).sum(); + InvoiceFromPersonMapper mapper = new InvoiceFromPersonMapper(); + Double percentageConsumedTotalBill = consumption / total; + Invoice newInvoice = BuilderMapper.builderMapper(Invoice.class, person, mapper); + newInvoice.setPercentageConsumedTotalBill(percentageConsumedTotalBill); + newInvoice.setTotalPayable(RoundUtil.round((total - (total * type.discountAmount(discountAmount)) + deliveryFee) * percentageConsumedTotalBill)); + return newInvoice; } - return this.checkNext(dto, discountAmount, type, total, deliveryFee); + return this.checkNext(person, discountAmount, type, total, deliveryFee); } } diff --git a/src/main/java/diegosneves/github/rachapedido/dto/InvoiceDTO.java b/src/main/java/diegosneves/github/rachapedido/dto/InvoiceDTO.java index 8dac5d9..b2a24c5 100644 --- a/src/main/java/diegosneves/github/rachapedido/dto/InvoiceDTO.java +++ b/src/main/java/diegosneves/github/rachapedido/dto/InvoiceDTO.java @@ -1,7 +1,11 @@ package diegosneves.github.rachapedido.dto; +import diegosneves.github.rachapedido.model.Item; import lombok.*; +import java.util.ArrayList; +import java.util.List; + /** * A classe {@link InvoiceDTO} representa um objeto de transferência de dados de fatura (DTO). * Ela contém informações sobre o nome do consumidor, valor consumido, valor total a pagar e a porcentagem do total da fatura consumida. @@ -33,8 +37,8 @@ public class InvoiceDTO { private String consumerName; - private Double valueConsumed; + private List items = new ArrayList<>(); private Double totalPayable; - private Double percentageConsumedTotalBill; + private String paymentLink; } diff --git a/src/main/java/diegosneves/github/rachapedido/exceptions/CloseOrderException.java b/src/main/java/diegosneves/github/rachapedido/exceptions/CloseOrderException.java deleted file mode 100644 index f110687..0000000 --- a/src/main/java/diegosneves/github/rachapedido/exceptions/CloseOrderException.java +++ /dev/null @@ -1,33 +0,0 @@ -package diegosneves.github.rachapedido.exceptions; - -/** - * A classe {@link CloseOrderException} representa uma exceção que é acionada quando ocorre um erro - * durante o processo de fechamento de um pedido. Esta classe é uma extensão da classe {@link RuntimeException}. - * - * @author diegosneves - * @see RuntimeException - */ -public class CloseOrderException extends RuntimeException { - - public static final ErroHandler ERROR = ErroHandler.ORDER_FAILED; - - /** - * Constrói uma nova instância de {@link CloseOrderException} com a mensagem descritiva específica. - * - * @param message A mensagem detalhada. Deve fornecer informações complementares sobre a causa da exceção. - */ - public CloseOrderException(String message) { - super(ERROR.errorMessage(message)); - } - - /** - * Cria uma nova instância de {@link CloseOrderException} com a mensagem de detalhe especificada e a causa. - * - * @param message a mensagem de detalhes, fornecendo informações adicionais sobre a causa da exceção - * @param e a causa da exceção - */ - public CloseOrderException(String message, Throwable e) { - super(ERROR.errorMessage(message), e); - } - -} diff --git a/src/main/java/diegosneves/github/rachapedido/mapper/InvoiceFromPersonMapper.java b/src/main/java/diegosneves/github/rachapedido/mapper/InvoiceFromPersonMapper.java new file mode 100644 index 0000000..547fede --- /dev/null +++ b/src/main/java/diegosneves/github/rachapedido/mapper/InvoiceFromPersonMapper.java @@ -0,0 +1,17 @@ +package diegosneves.github.rachapedido.mapper; + +import diegosneves.github.rachapedido.model.Invoice; +import diegosneves.github.rachapedido.model.Person; + +public class InvoiceFromPersonMapper implements BuildingStrategy { + + @Override + public Invoice run(Person origem) { + return Invoice.builder() + .consumerName(origem.getPersonName()) + .email(origem.getEmail()) + .isBuyer(origem.getIsBuyer()) + .items(origem.getItems()) + .build(); + } +} diff --git a/src/main/java/diegosneves/github/rachapedido/mapper/NotificationEmailMapper.java b/src/main/java/diegosneves/github/rachapedido/mapper/NotificationEmailMapper.java index 512560c..18d5553 100644 --- a/src/main/java/diegosneves/github/rachapedido/mapper/NotificationEmailMapper.java +++ b/src/main/java/diegosneves/github/rachapedido/mapper/NotificationEmailMapper.java @@ -1,18 +1,19 @@ package diegosneves.github.rachapedido.mapper; +import diegosneves.github.rachapedido.model.Invoice; import diegosneves.github.rachapedido.model.Item; import diegosneves.github.rachapedido.model.NotificationEmail; import diegosneves.github.rachapedido.model.Person; -public class NotificationEmailMapper implements BuildingStrategy { +public class NotificationEmailMapper implements BuildingStrategy { @Override - public NotificationEmail run(Person origem) { + public NotificationEmail run(Invoice origem) { return NotificationEmail.builder() - .consumerName(origem.getPersonName()) + .consumerName(origem.getConsumerName()) .email(origem.getEmail()) .itens(origem.getItems()) - .total(origem.getItems().stream().mapToDouble(Item::getPrice).sum()) + .total(origem.getTotalPayable()) .build(); } diff --git a/src/main/java/diegosneves/github/rachapedido/model/BillSplit.java b/src/main/java/diegosneves/github/rachapedido/model/BillSplit.java index 1fcb76d..772de5d 100644 --- a/src/main/java/diegosneves/github/rachapedido/model/BillSplit.java +++ b/src/main/java/diegosneves/github/rachapedido/model/BillSplit.java @@ -1,5 +1,6 @@ package diegosneves.github.rachapedido.model; +import diegosneves.github.rachapedido.dto.InvoiceDTO; import lombok.*; import java.util.ArrayList; @@ -12,7 +13,7 @@ @Builder public class BillSplit { - private List invoices = new ArrayList<>(); + private List invoices = new ArrayList<>(); private Double totalPayable; } diff --git a/src/main/java/diegosneves/github/rachapedido/model/Invoice.java b/src/main/java/diegosneves/github/rachapedido/model/Invoice.java index 4813058..5efdc25 100644 --- a/src/main/java/diegosneves/github/rachapedido/model/Invoice.java +++ b/src/main/java/diegosneves/github/rachapedido/model/Invoice.java @@ -2,6 +2,9 @@ import lombok.*; +import java.util.ArrayList; +import java.util.List; + @NoArgsConstructor @AllArgsConstructor @Getter @@ -10,7 +13,9 @@ public class Invoice { private String consumerName; - private Double valueConsumed; + private String email; + private Boolean isBuyer = Boolean.FALSE; + private List items = new ArrayList<>(); private Double totalPayable; private Double percentageConsumedTotalBill; private String paymentLink; diff --git a/src/main/java/diegosneves/github/rachapedido/model/NotificationEmail.java b/src/main/java/diegosneves/github/rachapedido/model/NotificationEmail.java index 6aa9435..8ada98d 100644 --- a/src/main/java/diegosneves/github/rachapedido/model/NotificationEmail.java +++ b/src/main/java/diegosneves/github/rachapedido/model/NotificationEmail.java @@ -14,6 +14,7 @@ public class NotificationEmail { private String consumerName; private Double total; private List itens; + private String bank; private String link; } diff --git a/src/main/java/diegosneves/github/rachapedido/model/Order.java b/src/main/java/diegosneves/github/rachapedido/model/Order.java index 867bb8e..8ebbd9d 100644 --- a/src/main/java/diegosneves/github/rachapedido/model/Order.java +++ b/src/main/java/diegosneves/github/rachapedido/model/Order.java @@ -2,6 +2,9 @@ import lombok.*; +import java.util.ArrayList; +import java.util.List; + /** * A classe {@link Order} representa um pedido feito por um {@link Person consumidor}. * Cada pedido contém o {@link String nome do consumidor} e o {@link Double valor total consumido}. @@ -16,6 +19,9 @@ public class Order { private String consumerName; + private String email; + private Boolean isBuyer = Boolean.FALSE; private Double valueConsumed; + private List items = new ArrayList<>(); } diff --git a/src/main/java/diegosneves/github/rachapedido/response/SplitInvoiceResponse.java b/src/main/java/diegosneves/github/rachapedido/response/SplitInvoiceResponse.java index 17d8312..36c0620 100644 --- a/src/main/java/diegosneves/github/rachapedido/response/SplitInvoiceResponse.java +++ b/src/main/java/diegosneves/github/rachapedido/response/SplitInvoiceResponse.java @@ -1,5 +1,6 @@ package diegosneves.github.rachapedido.response; +import diegosneves.github.rachapedido.dto.InvoiceDTO; import diegosneves.github.rachapedido.model.Invoice; import lombok.*; @@ -12,6 +13,6 @@ @Builder public class SplitInvoiceResponse { - private List invoices; + private List invoices; private Double totalPayable; } diff --git a/src/main/java/diegosneves/github/rachapedido/service/InvoiceService.java b/src/main/java/diegosneves/github/rachapedido/service/InvoiceService.java index 39cf990..4265115 100644 --- a/src/main/java/diegosneves/github/rachapedido/service/InvoiceService.java +++ b/src/main/java/diegosneves/github/rachapedido/service/InvoiceService.java @@ -9,7 +9,6 @@ import diegosneves.github.rachapedido.model.*; import diegosneves.github.rachapedido.service.contract.EmailServiceContract; import diegosneves.github.rachapedido.service.contract.InvoiceServiceContract; -import diegosneves.github.rachapedido.service.contract.OrderServiceContract; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -22,37 +21,43 @@ public class InvoiceService implements InvoiceServiceContract { private static final String CALCULATION_ERROR_MESSAGE = "Houve um problema ao calcular o valor total do pedido."; private static final String NULL_PARAMETER_ERROR_MESSAGE = "Um dos parâmetros necessários para a operação de cálculo da fatura está ausente ou nulo."; - private final OrderServiceContract orderService; + public static final String VOID = ""; private final EmailServiceContract emailService; @Autowired - public InvoiceService(OrderServiceContract orderService, EmailServiceContract emailService) { - this.orderService = orderService; + public InvoiceService(EmailServiceContract emailService) { this.emailService = emailService; } @Override public BillSplit generateInvoice(List consumers, DiscountType discountType, Double discount, Double deliveryFee, BankAccount selectedBank) { this.validateParameters(consumers, discountType, discount, deliveryFee); - List closeOrder = this.orderService.closeOrder(consumers); - List notificationEmails = this.preparateSendingEmailNotification(consumers, selectedBank); - List unpaidInvoices = this.calculateDiscount(closeOrder, discountType, discount, deliveryFee); + List unpaidInvoices = this.calculateDiscount(consumers, discountType, discount, deliveryFee); + List notificationEmails = this.preparateSendingEmailNotification(unpaidInvoices, selectedBank); return this.statementForPayment(unpaidInvoices, selectedBank, notificationEmails); } - private List preparateSendingEmailNotification(List consumers, BankAccount selectedBank) { + private List preparateSendingEmailNotification(List invoices, BankAccount selectedBank) { NotificationEmailMapper mapper = new NotificationEmailMapper(); - List notificationEmailList = consumers.stream().map(person -> BuilderMapper.builderMapper(NotificationEmail.class, person, mapper)).toList(); - notificationEmailList.forEach(notificationEmail -> notificationEmail.setLink(selectedBank.paymentLink())); + List notificationEmailList = invoices.stream().filter(invoice -> invoice.getIsBuyer() == Boolean.FALSE).map(invoice -> BuilderMapper.builderMapper(NotificationEmail.class, invoice, mapper)).toList(); + notificationEmailList.forEach(notificationEmail -> notificationEmail.setLink(selectedBank.paymentLink(notificationEmail.getTotal()))); + notificationEmailList.forEach(notificationEmail -> notificationEmail.setBank(selectedBank.toString())); return notificationEmailList; //TODO - Falta Teste para esse metodo } private BillSplit statementForPayment(List unpaidInvoices, BankAccount selectedBank, List notificationEmails) { - unpaidInvoices.forEach(invoice -> invoice.setPaymentLink(selectedBank.paymentLink())); + unpaidInvoices.forEach(invoice -> { + if (invoice.getIsBuyer() == Boolean.FALSE) { + invoice.setPaymentLink(selectedBank.paymentLink(invoice.getTotalPayable())); + } else { + invoice.setPaymentLink(VOID); + } + }); notificationEmails.forEach(this.emailService::sendPaymentEmail); Double total = unpaidInvoices.stream().mapToDouble(Invoice::getTotalPayable).sum(); + List invoiceDTOs = unpaidInvoices.stream().map(this::convertToInvoiceDTO).toList(); return BillSplit.builder() - .invoices(unpaidInvoices) + .invoices(invoiceDTOs) .totalPayable(total) .build(); } @@ -63,29 +68,28 @@ private void validateParameters(List consumers, DiscountType discountTyp } } - private List calculateDiscount(List closeOrder, DiscountType discountType, Double discount, Double deliveryFee) throws CalculateInvoiceException { - List invoices = closeOrder.stream().map(this::convertToInvoiceDTO).toList(); + private List calculateDiscount(List persons, DiscountType discountType, Double discount, Double deliveryFee) throws CalculateInvoiceException { double total; try { - total = invoices.stream().mapToDouble(InvoiceDTO::getValueConsumed).sum(); + total = persons.stream().mapToDouble(p -> p.getItems().stream().mapToDouble(Item::getPrice).sum()).sum(); } catch (Exception e) { throw new CalculateInvoiceException(CALCULATION_ERROR_MESSAGE, e); } Double finalTotal = total; - return invoices.stream().map(dto -> this.calcDiscountForInvoice(dto, discountType, discount, finalTotal, deliveryFee)).toList(); + return persons.stream().map(dto -> this.calcDiscountForInvoice(dto, discountType, discount, finalTotal, deliveryFee)).toList(); } - private Invoice calcDiscountForInvoice(InvoiceDTO dto, DiscountType discountType, Double discount, Double total, Double deliveryFee){ + private Invoice calcDiscountForInvoice(Person person, DiscountType discountType, Double discount, Double total, Double deliveryFee) { DiscountStrategy strategy = DiscountStrategy.link( new CashDiscountStrategy(), new PercentageDiscountStrategy(), new NoDiscountStrategy()); - return strategy.calculateDiscount(dto,discount, discountType, total, deliveryFee); + return strategy.calculateDiscount(person, discount, discountType, total, deliveryFee); } - private InvoiceDTO convertToInvoiceDTO(Order order) { - return BuilderMapper.builderMapper(InvoiceDTO.class, order); + private InvoiceDTO convertToInvoiceDTO(Invoice invoice) { + return BuilderMapper.builderMapper(InvoiceDTO.class, invoice); } } diff --git a/src/main/java/diegosneves/github/rachapedido/service/OrderService.java b/src/main/java/diegosneves/github/rachapedido/service/OrderService.java deleted file mode 100644 index 774ed2b..0000000 --- a/src/main/java/diegosneves/github/rachapedido/service/OrderService.java +++ /dev/null @@ -1,59 +0,0 @@ -package diegosneves.github.rachapedido.service; - -import diegosneves.github.rachapedido.exceptions.CloseOrderException; -import diegosneves.github.rachapedido.model.Item; -import diegosneves.github.rachapedido.model.Order; -import diegosneves.github.rachapedido.model.Person; -import diegosneves.github.rachapedido.service.contract.OrderServiceContract; -import org.springframework.stereotype.Service; - -import java.util.List; - -import static java.util.Objects.isNull; - -/** - * A classe {@link OrderService} é responsável por fechar pedidos para cada consumidor fornecido. - * Ela implementa a interface {@link OrderServiceContract}. - * - * @author diegosneves - */ -@Service -public class OrderService implements OrderServiceContract { - - private static final String NULL_CONSTANT = "A lista de consumidores está nula, verifique se foram adicionados consumidores à lista."; - private static final String ORDER_CLOSE_FAILURE_MESSAGE = "Ao processar os cálculos do pedido, ocorreu um erro."; - - @Override - public List closeOrder(List allConsumers) throws CloseOrderException { - if (isNull(allConsumers)) { - throw new CloseOrderException(NULL_CONSTANT); - } - return allConsumers.stream().map(this::takeOrdersPerConsumers).toList(); - } - - /** - * Este método recebe um objeto {@link Person} como parâmetro e calcula o valor total de itens associados a essa pessoa. - * Em seguida, cria um objeto {@link Order} com o nome do consumidor e o valor total consumido e retorna esse objeto Order. - * Caso qualquer exceção ocorra durante o cálculo, uma exceção {@link CloseOrderException} será lançada com uma mensagem de erro apropriada. - * - * @param person O objeto {@link Person} para o qual o pedido precisa ser criado. - * @return Um objeto {@link Order} com o nome do consumidor e o valor total consumido. - * @throws CloseOrderException Se ocorrer alguma exceção durante o cálculo do valor total. - */ - private Order takeOrdersPerConsumers(Person person) throws CloseOrderException { - Double totalValue = null; - try { - totalValue = person.getItems().stream() - .mapToDouble(Item::getPrice) - .sum(); - } catch (Exception e) { - throw new CloseOrderException(ORDER_CLOSE_FAILURE_MESSAGE, e); - } - return Order.builder() - .consumerName(person.getPersonName()) - .valueConsumed(totalValue) - .build(); - } - - -} diff --git a/src/main/java/diegosneves/github/rachapedido/service/contract/OrderServiceContract.java b/src/main/java/diegosneves/github/rachapedido/service/contract/OrderServiceContract.java deleted file mode 100644 index 9ea78db..0000000 --- a/src/main/java/diegosneves/github/rachapedido/service/contract/OrderServiceContract.java +++ /dev/null @@ -1,27 +0,0 @@ -package diegosneves.github.rachapedido.service.contract; - -import diegosneves.github.rachapedido.exceptions.CloseOrderException; -import diegosneves.github.rachapedido.model.Order; -import diegosneves.github.rachapedido.model.Person; -import diegosneves.github.rachapedido.service.OrderService; - -import java.util.List; - -/** - * A interface {@link OrderServiceContract} representa o contrato para a classe {@link OrderService}. - * Fornece um método para fechar o {@link Order pedido} para cada {@link Person consumidor} fornecido. - * - * @author diegosneves - */ -public interface OrderServiceContract { - - /** - * Fecha o {@link Order pedido} para cada {@link Person consumidor} fornecido. - * - * @param allConsumers A lista de todos os {@link Person consumidores} para os quais o {@link Order pedido} precisa ser fechado. - * @return A lista contendo os {@link Order pedidos} fechados, com o valor total consumido por cada consumidor. - * @throws CloseOrderException se ocorrer algum erro durante o processo de finalização do pedido. - */ - List closeOrder(List allConsumers) throws CloseOrderException; - -} diff --git a/src/test/java/diegosneves/github/rachapedido/service/EmailServiceTest.java b/src/test/java/diegosneves/github/rachapedido/service/EmailServiceTest.java new file mode 100644 index 0000000..dec7170 --- /dev/null +++ b/src/test/java/diegosneves/github/rachapedido/service/EmailServiceTest.java @@ -0,0 +1,39 @@ +package diegosneves.github.rachapedido.service; + +import diegosneves.github.rachapedido.adapter.SendEmailAdapter; +import diegosneves.github.rachapedido.model.NotificationEmail; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(SpringExtension.class) +class EmailServiceTest { + + @InjectMocks + private EmailService service; + + @Mock + private SendEmailAdapter sendEmailAdapter; + + + @BeforeEach + void setUp() { + } + + @Test + void whenSendPaymentEmailReceiveNotificationEmailValidThenSendEmail() { + doNothing().when(this.sendEmailAdapter).sendNotificationEmail(any(NotificationEmail.class)); + + service.sendPaymentEmail(new NotificationEmail()); + + verify(this.sendEmailAdapter, times(1)).sendNotificationEmail(any(NotificationEmail.class)); + + } +} diff --git a/src/test/java/diegosneves/github/rachapedido/service/InvoiceServiceTest.java b/src/test/java/diegosneves/github/rachapedido/service/InvoiceServiceTest.java index 03a4927..e12bb6a 100644 --- a/src/test/java/diegosneves/github/rachapedido/service/InvoiceServiceTest.java +++ b/src/test/java/diegosneves/github/rachapedido/service/InvoiceServiceTest.java @@ -6,11 +6,12 @@ import diegosneves.github.rachapedido.exceptions.CalculateInvoiceException; import diegosneves.github.rachapedido.model.*; import diegosneves.github.rachapedido.service.contract.EmailServiceContract; -import diegosneves.github.rachapedido.service.contract.OrderServiceContract; import lombok.SneakyThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -28,36 +29,43 @@ class InvoiceServiceTest { private static final String CALCULATION_ERROR_MESSAGE = "Houve um problema ao calcular o valor total do pedido."; private static final String NULL_PARAMETER_ERROR_MESSAGE = "Um dos parâmetros necessários para a operação de cálculo da fatura está ausente ou nulo."; + public static final String PAYMENT_LINK = "https://nubank.com.br/cobrar/5h2au/658235a8-f38a-4cf5-881c-1de7114d66c7"; + public static final String VOID = ""; @InjectMocks private InvoiceService service; - - @Mock - private OrderServiceContract orderService; - @Mock private EmailServiceContract emailService; + @Captor + private ArgumentCaptor notificationEmailCaptor; private Person consumerI; private Person consumerII; - private Order orderI; - private Order orderII; - List orders; + private Invoice invoiceI; + private Invoice invoiceII; + + private Item itemI; + private Item itemII; + private Item itemIII; + + private NotificationEmail emailI; + private NotificationEmail emailII; + @BeforeEach void setUp() { - Item itemI = Item.builder() + this.itemI = Item.builder() .name("Hamburguer") .price(40.0) .build(); - Item itemII = Item.builder() + this.itemII = Item.builder() .name("Sobremesa") .price(2.0) .build(); - Item itemIII = Item.builder() + this.itemIII = Item.builder() .name("Sanduíche") .price(8.0) .build(); @@ -71,83 +79,119 @@ void setUp() { this.consumerII = Person.builder() .personName("Amigo") + .isBuyer(Boolean.FALSE) .email("amigo@gmail.com") .items(List.of(itemIII)) .build(); - this.orderI = Order.builder() + + this.invoiceI = Invoice.builder() .consumerName("Fulano") - .valueConsumed(42.0) + .email("fulano@gmail.com") + .isBuyer(Boolean.TRUE) + .items(List.of(itemI, itemII)) + .totalPayable(31.92) + .percentageConsumedTotalBill(0.84) + .paymentLink(PAYMENT_LINK) .build(); - this.orderII = Order.builder() + this.invoiceII = Invoice.builder() .consumerName("Amigo") - .valueConsumed(8.0) + .email("amigo@gmail.com") + .isBuyer(Boolean.FALSE) + .items(List.of(itemIII)) + .totalPayable(6.08) + .percentageConsumedTotalBill(0.16) + .paymentLink(PAYMENT_LINK) .build(); - this.orders = List.of(this.orderI, this.orderII); + this.emailI = NotificationEmail.builder() + .email(this.consumerI.getEmail()) + .consumerName(this.consumerI.getPersonName()) + .total(31.92) + .itens(List.of(itemI, itemII)) + .bank(BankAccount.NUBANK.toString()) + .link(PAYMENT_LINK) + .build(); + + this.emailII = NotificationEmail.builder() + .email(this.consumerII.getEmail()) + .consumerName(this.consumerII.getPersonName()) + .total(6.08) + .itens(List.of(itemIII)) + .bank(BankAccount.NUBANK.toString()) + .link(PAYMENT_LINK) + .build(); + + } @Test void whenReceiveInvoiceDataThenReturnBillSplit() { - String paymentLink = "https://nubank.com.br/cobrar/5h2au/658235a8-f38a-4cf5-881c-1de7114d66c7"; - - when(orderService.closeOrder(List.of(this.consumerI, this.consumerII))).thenReturn(orders); + doNothing().when(this.emailService).sendPaymentEmail(any(NotificationEmail.class)); BillSplit actual = this.service.generateInvoice(List.of(this.consumerI, this.consumerII), DiscountType.CASH, 20.0, 8.0, BankAccount.NUBANK); - verify(this.emailService, atLeastOnce()).sendPaymentEmail(any(NotificationEmail.class)); + verify(this.emailService, times(1)).sendPaymentEmail(this.notificationEmailCaptor.capture()); assertNotNull(actual); assertEquals(2, actual.getInvoices().size()); assertEquals("Fulano", actual.getInvoices().get(0).getConsumerName()); - assertEquals(42.0, actual.getInvoices().get(0).getValueConsumed()); + assertNotNull(actual.getInvoices()); + assertNotNull(actual.getInvoices().get(0).getItems()); + assertNotNull(actual.getInvoices().get(1).getItems()); + assertEquals(2, actual.getInvoices().get(0).getItems().size()); + assertEquals(1, actual.getInvoices().get(1).getItems().size()); assertEquals(31.92, actual.getInvoices().get(0).getTotalPayable()); - assertEquals(0.84, actual.getInvoices().get(0).getPercentageConsumedTotalBill()); - assertEquals(paymentLink, actual.getInvoices().get(0).getPaymentLink()); + assertEquals(VOID, actual.getInvoices().get(0).getPaymentLink()); assertEquals("Amigo", actual.getInvoices().get(1).getConsumerName()); - assertEquals(8.0, actual.getInvoices().get(1).getValueConsumed()); assertEquals(6.08, actual.getInvoices().get(1).getTotalPayable()); - assertEquals(0.16, actual.getInvoices().get(1).getPercentageConsumedTotalBill()); - assertEquals(paymentLink, actual.getInvoices().get(1).getPaymentLink()); + assertEquals(PAYMENT_LINK, actual.getInvoices().get(1).getPaymentLink()); assertEquals(38.0, actual.getTotalPayable()); + assertEquals(this.invoiceII.getConsumerName(), this.notificationEmailCaptor.getValue().getConsumerName()); + assertEquals(this.invoiceII.getEmail(), this.notificationEmailCaptor.getValue().getEmail()); + assertEquals(this.invoiceII.getTotalPayable(), this.notificationEmailCaptor.getValue().getTotal()); + assertEquals(BankAccount.NUBANK.toString(), this.notificationEmailCaptor.getValue().getBank()); + assertEquals(PAYMENT_LINK, this.notificationEmailCaptor.getValue().getLink()); + } @Test @SneakyThrows - void whenConvertToInvoiceReceiveOrderThenReturnInvoice() { - Method method = this.service.getClass().getDeclaredMethod("convertToInvoiceDTO", Order.class); + void whenConvertToInvoiceReceiveInvoiceThenReturnInvoiceDTO() { + Method method = this.service.getClass().getDeclaredMethod("convertToInvoiceDTO", Invoice.class); method.setAccessible(true); - InvoiceDTO actual = (InvoiceDTO) method.invoke(this.service, this.orderI); + InvoiceDTO actual = (InvoiceDTO) method.invoke(this.service, this.invoiceI); assertNotNull(actual); assertEquals("Fulano", actual.getConsumerName()); - assertEquals(42.0, actual.getValueConsumed()); - assertNull(actual.getTotalPayable()); - assertNull(actual.getPercentageConsumedTotalBill()); + assertFalse(actual.getItems().isEmpty()); + assertEquals(2, actual.getItems().size()); + assertEquals(this.itemI, actual.getItems().get(0)); + assertEquals(this.itemII, actual.getItems().get(1)); + assertEquals(31.92, actual.getTotalPayable()); + assertEquals(PAYMENT_LINK, actual.getPaymentLink()); + } @Test @SneakyThrows void whenCalculateDiscountReceiveInvoiceDataAndDiscountTypeCashThenApplyDiscount() { - List invoices = List.of(this.orderI, this.orderII); Method method = this.service.getClass().getDeclaredMethod("calculateDiscount", List.class, DiscountType.class, Double.class, Double.class); method.setAccessible(true); - List actual = (List) method.invoke(this.service, invoices, DiscountType.CASH, 20.0, 8.0); + List actual = (List) method.invoke(this.service, List.of(this.consumerI, this.consumerII), DiscountType.CASH, 20.0, 8.0); assertEquals("Fulano", actual.get(0).getConsumerName()); - assertEquals(42.0, actual.get(0).getValueConsumed()); assertEquals(31.92, actual.get(0).getTotalPayable()); assertEquals(0.84, actual.get(0).getPercentageConsumedTotalBill()); assertNull(actual.get(0).getPaymentLink()); assertEquals("Amigo", actual.get(1).getConsumerName()); - assertEquals(8.0, actual.get(1).getValueConsumed()); assertEquals(6.08, actual.get(1).getTotalPayable()); assertEquals(0.16, actual.get(1).getPercentageConsumedTotalBill()); assertNull(actual.get(1).getPaymentLink()); @@ -157,20 +201,17 @@ void whenCalculateDiscountReceiveInvoiceDataAndDiscountTypeCashThenApplyDiscount @Test @SneakyThrows void whenCalculateDiscountReceiveInvoiceDataAndDiscountTypePercentageThenApplyDiscount() { - List invoices = List.of(this.orderI, this.orderII); Method method = this.service.getClass().getDeclaredMethod("calculateDiscount", List.class, DiscountType.class, Double.class, Double.class); method.setAccessible(true); - List actual = (List) method.invoke(this.service, invoices, DiscountType.PERCENTAGE, 10.0, 8.0); + List actual = (List) method.invoke(this.service, List.of(this.consumerI, this.consumerII), DiscountType.PERCENTAGE, 10.0, 8.0); assertEquals("Fulano", actual.get(0).getConsumerName()); - assertEquals(42.0, actual.get(0).getValueConsumed()); assertEquals(44.52, actual.get(0).getTotalPayable()); assertEquals(0.84, actual.get(0).getPercentageConsumedTotalBill()); assertNull(actual.get(0).getPaymentLink()); assertEquals("Amigo", actual.get(1).getConsumerName()); - assertEquals(8.0, actual.get(1).getValueConsumed()); assertEquals(8.48, actual.get(1).getTotalPayable()); assertEquals(0.16, actual.get(1).getPercentageConsumedTotalBill()); assertNull(actual.get(1).getPaymentLink()); @@ -180,20 +221,17 @@ void whenCalculateDiscountReceiveInvoiceDataAndDiscountTypePercentageThenApplyDi @Test @SneakyThrows void whenCalculateDiscountReceiveInvoiceDataAndDiscountTypeNoDiscountThenNotApplyDiscount() { - List invoices = List.of(this.orderI, this.orderII); Method method = this.service.getClass().getDeclaredMethod("calculateDiscount", List.class, DiscountType.class, Double.class, Double.class); method.setAccessible(true); - List actual = (List) method.invoke(this.service, invoices, DiscountType.NO_DISCOUNT, 10.0, 8.0); + List actual = (List) method.invoke(this.service, List.of(this.consumerI, this.consumerII), DiscountType.NO_DISCOUNT, 10.0, 8.0); assertEquals("Fulano", actual.get(0).getConsumerName()); - assertEquals(42.0, actual.get(0).getValueConsumed()); assertEquals(48.72, actual.get(0).getTotalPayable()); assertEquals(0.84, actual.get(0).getPercentageConsumedTotalBill()); assertNull(actual.get(0).getPaymentLink()); assertEquals("Amigo", actual.get(1).getConsumerName()); - assertEquals(8.0, actual.get(1).getValueConsumed()); assertEquals(9.28, actual.get(1).getTotalPayable()); assertEquals(0.16, actual.get(1).getPercentageConsumedTotalBill()); assertNull(actual.get(1).getPaymentLink()); @@ -202,14 +240,12 @@ void whenCalculateDiscountReceiveInvoiceDataAndDiscountTypeNoDiscountThenNotAppl @Test @SneakyThrows - void whenCalculateDiscountReceiveInvoiceDataWithValueConsumedNullThenThrowsCalculateInvoiceException() { - this.orderI.setValueConsumed(null); - List invoices = List.of(this.orderI, this.orderII); - + void whenCalculateDiscountReceivePersonsDataWithItemPriceNullThenThrowsCalculateInvoiceException() { + this.itemIII.setPrice(null); Method method = this.service.getClass().getDeclaredMethod("calculateDiscount", List.class, DiscountType.class, Double.class, Double.class); method.setAccessible(true); - InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, invoices, DiscountType.NO_DISCOUNT, 10.0, 8.0)); + InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, List.of(this.consumerI, this.consumerII), DiscountType.NO_DISCOUNT, 10.0, 8.0)); assertInstanceOf(CalculateInvoiceException.class, exception.getTargetException()); assertEquals(CalculateInvoiceException.ERROR.errorMessage(CALCULATION_ERROR_MESSAGE), exception.getTargetException().getMessage()); @@ -237,7 +273,7 @@ void whenValidateParametersReceiveInvoiceDataWithDiscountTypeNullThenThrowsCalcu Method method = this.service.getClass().getDeclaredMethod("validateParameters", List.class, DiscountType.class, Double.class, Double.class); method.setAccessible(true); - InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, this.orders, null, 10.0, 8.0)); + InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, List.of(this.consumerI, this.consumerII), null, 10.0, 8.0)); assertInstanceOf(CalculateInvoiceException.class, exception.getTargetException()); assertEquals(CalculateInvoiceException.ERROR.errorMessage(NULL_PARAMETER_ERROR_MESSAGE), exception.getTargetException().getMessage()); @@ -251,7 +287,7 @@ void whenValidateParametersReceiveInvoiceDataWithDiscountNullThenThrowsCalculate Method method = this.service.getClass().getDeclaredMethod("validateParameters", List.class, DiscountType.class, Double.class, Double.class); method.setAccessible(true); - InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, this.orders, DiscountType.CASH, null, 8.0)); + InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, List.of(this.consumerI, this.consumerII), DiscountType.CASH, null, 8.0)); assertInstanceOf(CalculateInvoiceException.class, exception.getTargetException()); assertEquals(CalculateInvoiceException.ERROR.errorMessage(NULL_PARAMETER_ERROR_MESSAGE), exception.getTargetException().getMessage()); @@ -265,11 +301,82 @@ void whenValidateParametersReceiveInvoiceDataWithDeliveryFeeNullThenThrowsCalcul Method method = this.service.getClass().getDeclaredMethod("validateParameters", List.class, DiscountType.class, Double.class, Double.class); method.setAccessible(true); - InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, this.orders, DiscountType.CASH, 10.0, null)); + InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, List.of(this.consumerI, this.consumerII), DiscountType.CASH, 10.0, null)); assertInstanceOf(CalculateInvoiceException.class, exception.getTargetException()); assertEquals(CalculateInvoiceException.ERROR.errorMessage(NULL_PARAMETER_ERROR_MESSAGE), exception.getTargetException().getMessage()); } + @Test + @SneakyThrows + void whenValidateParametersReceiveInvoiceDataOkThenDoNothing() { + + Method method = this.service.getClass().getDeclaredMethod("validateParameters", List.class, DiscountType.class, Double.class, Double.class); + method.setAccessible(true); + + method.invoke(this.service, List.of(this.consumerI, this.consumerII), DiscountType.CASH, 10.0, 8.0); + + } + + @Test + @SneakyThrows + void whenPreparateSendingEmailNotificationReceivesInvoicesDataThenReturnNotificationEmailList() { + Method method = this.service.getClass().getDeclaredMethod("preparateSendingEmailNotification", List.class, BankAccount.class); + method.setAccessible(true); + + List actual = (List) method.invoke(this.service, List.of(this.invoiceI, this.invoiceII), BankAccount.NUBANK); + + assertNotNull(actual); + assertEquals(1, actual.size()); + assertEquals("Amigo", actual.get(0).getConsumerName()); + assertEquals("amigo@gmail.com", actual.get(0).getEmail()); + assertEquals(6.08, actual.get(0).getTotal()); + assertNotNull(actual.get(0).getItens()); + assertEquals(1, actual.get(0).getItens().size()); + assertEquals(this.itemIII, actual.get(0).getItens().get(0)); + assertEquals(BankAccount.NUBANK.toString(), actual.get(0).getBank()); + assertEquals(PAYMENT_LINK, actual.get(0).getLink()); + + } + + @Test + @SneakyThrows + void whenStatementForPaymentValidParametersThenReturnBillSplit() { + this.invoiceI.setPaymentLink(""); + this.invoiceII.setPaymentLink(""); + this.emailII.setLink(BankAccount.PICPAY.paymentLink(6.08)); + this.emailII.setBank(BankAccount.PICPAY.toString()); + + doNothing().when(this.emailService).sendPaymentEmail(any(NotificationEmail.class)); + + Method method = this.service.getClass().getDeclaredMethod("statementForPayment", List.class, BankAccount.class, List.class); + method.setAccessible(true); + + BillSplit actual = (BillSplit) method.invoke(this.service, List.of(this.invoiceI, this.invoiceII), BankAccount.PICPAY, List.of(this.emailII)); + + verify(this.emailService, times(1)).sendPaymentEmail(this.notificationEmailCaptor.capture()); + + assertNotNull(actual); + assertEquals(2, actual.getInvoices().size()); + assertEquals("Fulano", actual.getInvoices().get(0).getConsumerName()); + assertNotNull(actual.getInvoices()); + assertNotNull(actual.getInvoices().get(0).getItems()); + assertNotNull(actual.getInvoices().get(1).getItems()); + assertEquals(2, actual.getInvoices().get(0).getItems().size()); + assertEquals(1, actual.getInvoices().get(1).getItems().size()); + assertEquals(31.92, actual.getInvoices().get(0).getTotalPayable()); + assertEquals(VOID, actual.getInvoices().get(0).getPaymentLink()); + assertEquals("Amigo", actual.getInvoices().get(1).getConsumerName()); + assertEquals(6.08, actual.getInvoices().get(1).getTotalPayable()); + assertEquals(BankAccount.PICPAY.paymentLink(6.08), actual.getInvoices().get(1).getPaymentLink()); + assertEquals(38.0, actual.getTotalPayable()); + assertEquals(this.invoiceII.getConsumerName(), this.notificationEmailCaptor.getValue().getConsumerName()); + assertEquals(this.invoiceII.getEmail(), this.notificationEmailCaptor.getValue().getEmail()); + assertEquals(this.invoiceII.getTotalPayable(), this.notificationEmailCaptor.getValue().getTotal()); + assertEquals(BankAccount.PICPAY.toString(), this.notificationEmailCaptor.getValue().getBank()); + assertEquals(BankAccount.PICPAY.paymentLink(6.08), this.notificationEmailCaptor.getValue().getLink()); + + } + } diff --git a/src/test/java/diegosneves/github/rachapedido/service/OrderServiceTest.java b/src/test/java/diegosneves/github/rachapedido/service/OrderServiceTest.java deleted file mode 100644 index 9948d4e..0000000 --- a/src/test/java/diegosneves/github/rachapedido/service/OrderServiceTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package diegosneves.github.rachapedido.service; - -import diegosneves.github.rachapedido.exceptions.CloseOrderException; -import diegosneves.github.rachapedido.model.Item; -import diegosneves.github.rachapedido.model.Order; -import diegosneves.github.rachapedido.model.Person; -import lombok.SneakyThrows; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -@ExtendWith(SpringExtension.class) -class OrderServiceTest { - - private static final String NULL_CONSTANT = "A lista de consumidores está nula, verifique se foram adicionados consumidores à lista."; - private static final String ORDER_CLOSE_FAILURE_MESSAGE = "Ao processar os cálculos do pedido, ocorreu um erro."; - - @InjectMocks - private OrderService service; - - private Person personI; - private Person personII; - private Item itemI; - - @BeforeEach - void setUp() { - this.itemI = Item.builder() - .name("Item I") - .price(40.0) - .build(); - - Item itemII = Item.builder() - .name("Item II") - .price(2.0) - .build(); - - Item itemIII = Item.builder() - .name("Item III") - .price(8.0) - .build(); - - this.personI = Person.builder() - .personName("Buyer - Person I") - .isBuyer(Boolean.TRUE) - .email("buyer@teste.com") - .items(List.of(this.itemI, itemII)) - .build(); - - this.personII = Person.builder() - .personName("Consumer - Person II") - .email("consumer@teste.com") - .items(List.of(itemIII)) - .build(); - } - - @Test - void whenCloseOrderReceiveConsumerListThenReturnOrderListWithTotalValueConsumedPerConsumer(){ - List orders = this.service.closeOrder(List.of(this.personI, this.personII)); - - assertNotNull(orders); - assertEquals(2, orders.size()); - assertEquals("Buyer - Person I", orders.get(0).getConsumerName()); - assertEquals("Consumer - Person II", orders.get(1).getConsumerName()); - assertEquals(42.0, orders.get(0).getValueConsumed()); - assertEquals(8.0, orders.get(1).getValueConsumed()); - } - - @Test - @SneakyThrows - void whentakeOrdersPerConsumersReceivePersonThenReturnOrderWithTotalValueConsumedAndConsumerName(){ - Method method = this.service.getClass().getDeclaredMethod("takeOrdersPerConsumers", Person.class); - method.setAccessible(true); - - Order order = (Order) method.invoke(this.service, this.personI); - - assertNotNull(order); - assertEquals("Buyer - Person I", order.getConsumerName()); - assertEquals(42.0, order.getValueConsumed()); - } - - @Test - @SneakyThrows - void whentakeOrdersPerConsumersReceivePersonWithItemPriceNullThenThrowsNullPriceException(){ - this.itemI.setPrice(null); - - Method method = this.service.getClass().getDeclaredMethod("takeOrdersPerConsumers", Person.class); - method.setAccessible(true); - - - InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> method.invoke(this.service, this.personI)); - Throwable realException = exception.getTargetException(); - - assertInstanceOf(CloseOrderException.class, realException); - assertEquals(CloseOrderException.ERROR.errorMessage(ORDER_CLOSE_FAILURE_MESSAGE), realException.getMessage()); - } - - @Test - void whenCloseOrderReceiveConsumerListNullThenThrowsCloseOrderException(){ - - Exception exception = assertThrows(CloseOrderException.class, () -> this.service.closeOrder(null)); - - assertInstanceOf(CloseOrderException.class, exception); - assertEquals(CloseOrderException.ERROR.errorMessage(NULL_CONSTANT), exception.getMessage()); - } - -} diff --git a/src/test/java/diegosneves/github/rachapedido/service/SplitInvoiceServiceTest.java b/src/test/java/diegosneves/github/rachapedido/service/SplitInvoiceServiceTest.java index c7748e6..f5e3f27 100644 --- a/src/test/java/diegosneves/github/rachapedido/service/SplitInvoiceServiceTest.java +++ b/src/test/java/diegosneves/github/rachapedido/service/SplitInvoiceServiceTest.java @@ -1,6 +1,7 @@ package diegosneves.github.rachapedido.service; import diegosneves.github.rachapedido.core.BankAccount; +import diegosneves.github.rachapedido.dto.InvoiceDTO; import diegosneves.github.rachapedido.dto.PersonDTO; import diegosneves.github.rachapedido.enums.DiscountType; import diegosneves.github.rachapedido.model.*; @@ -34,7 +35,7 @@ class SplitInvoiceServiceTest { private PersonServiceContract personService; private SplitInvoiceRequest request; - private Item item; +// private Item item; private PersonDTO buyer; private PersonDTO friend; @@ -79,19 +80,15 @@ void setUp() { .items(List.of(new Item("Sanduíche", 8.0))) .build(); - Invoice invoiceI = Invoice.builder() + InvoiceDTO invoiceI = InvoiceDTO.builder() .consumerName("Fulano") - .valueConsumed(42.0) .totalPayable(31.92) - .percentageConsumedTotalBill(84.0) .paymentLink("n/a") .build(); - Invoice invoiceII = Invoice.builder() + InvoiceDTO invoiceII = InvoiceDTO.builder() .consumerName("Amigo") - .valueConsumed(8.0) .totalPayable(6.08) - .percentageConsumedTotalBill(16.0) .paymentLink("link") .build(); @@ -113,18 +110,14 @@ void whenReceivingInvoiceThenDivisionMustBeCarriedOut() { verify(invoiceService, times(1)).generateInvoice(eq(List.of(consumerI, consumerII)), eq(DiscountType.CASH), eq(20.0), eq(8.0), eq(BankAccount.NUBANK)); assertNotNull(response); - Invoice buyerInvoice = response.getInvoices().stream().filter(p -> p.getConsumerName().equals(this.buyer.getPersonName())).findFirst().orElse(null); - Invoice friendInvoice = response.getInvoices().stream().filter(p -> p.getConsumerName().equals(this.friend.getPersonName())).findFirst().orElse(null); + InvoiceDTO buyerInvoice = response.getInvoices().stream().filter(p -> p.getConsumerName().equals(this.buyer.getPersonName())).findFirst().orElse(null); + InvoiceDTO friendInvoice = response.getInvoices().stream().filter(p -> p.getConsumerName().equals(this.friend.getPersonName())).findFirst().orElse(null); assertNotNull(buyerInvoice); assertNotNull(friendInvoice); assertEquals(2, response.getInvoices().size()); - assertEquals(42.0,buyerInvoice.getValueConsumed()); assertEquals(31.92,buyerInvoice.getTotalPayable()); - assertEquals(84.0, buyerInvoice.getPercentageConsumedTotalBill()); assertEquals("n/a", buyerInvoice.getPaymentLink()); - assertEquals(8.0, friendInvoice.getValueConsumed()); assertEquals(6.08, friendInvoice.getTotalPayable()); - assertEquals(16.0, friendInvoice.getPercentageConsumedTotalBill()); assertEquals("link", friendInvoice.getPaymentLink()); assertEquals(38.0, response.getTotalPayable()); }