Skip to content
This repository has been archived by the owner on Aug 30, 2021. It is now read-only.

Exercise-1-ap - Implementation of Wallet test assignment #9

Open
wants to merge 2 commits into
base: app/exercise-1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 2 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,6 @@ You can spend as much time as you need. We think you should not invest more than
You don't have to document your code, but you can write down anything you want to explain or anything you have skipped.


# Servicio de bono monedero
# Swagger

El ejercicio consiste en construir una prueba de concepto de un servicio de bono monedero.
El bono monedero funciona como un monedero "real":
- Almacena un saldo en euros, que el usuario puede utilizar para pagar otros servicios.
- El usuario puede recargar dinero desde una pasarela de pagos de terceros (stripe, paypal, redsys...).
- No existe la posibilidad de devolver ese dinero al medio de pago original.

La estructura básica del monedero es su identificador y su saldo actual. Si consideras que necesitas más campos,
añádelos sin problemas y lo discutiremos en la entrevista.

El ejercicio consiste en que programes endpoints para:
- Consultar un bono por su identificador.
- Descontar saldo del monedero (un cobro).
- Recargar dinero en ese bono a través de un servicio de pago de terceros.

Para que puedas ir al grano, te damos un proyecto maven con una aplicación Spring Boot, con las dependencias básicas y una
base de datos H2. Tienes perfiles de develop y test.

Tienes también una implementación del servicio que implementaría la pasarela de pago real (ThirdPartyPaymentService).
Esa parte no tienes que programarla, asume que el servicio hace la llamada remota dada una cantidad de dinero.
Está pensado para que devuelva error bajo ciertas condiciones.

Ten en cuenta que es un servicio que conviviría en un entorno de microservicios y alta concurrencia.

Le puedes dedicar el tiempo que quieras, pero hemos estimado que 3-4 horas es suficiente para demostrar [los requisitos del puesto.](OFERTA.md#requisitos)
No hace falta que lo documentes pero puedes anotar todo lo que quieras como explicación o justificación de lo que hagas o dejes sin hacer.
- http://localhost:8090/swagger-ui/
23 changes: 21 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<version>2.3.4.RELEASE</version>
<relativePath/>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<java.version>11</java.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -55,6 +55,25 @@
<artifactId>h2</artifactId>
<version>1.4.196</version>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>

<build>
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/playtomic/tests/wallet/Currency.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.playtomic.tests.wallet;

public enum Currency {
EUR,
USD,
BAM,
PLN,
GBP
}
30 changes: 27 additions & 3 deletions src/main/java/com/playtomic/tests/wallet/WalletApplication.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
package com.playtomic.tests.wallet;

import com.playtomic.tests.wallet.model.Wallet;
import com.playtomic.tests.wallet.repository.WalletRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.math.BigDecimal;

@SpringBootApplication
public class WalletApplication {

public static void main(String[] args) {
SpringApplication.run(WalletApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(WalletApplication.class, args);
}

@Bean
public CommandLineRunner loadData(WalletRepository walletRepository) {
return (args) -> {
walletRepository.save(
Wallet.builder()
.id("7a6ffed9-4252-427e-af7d-3dcaaf2db2df")
.balance(new BigDecimal("50.00"))
.currency("EUR")
.build());
walletRepository.save(
Wallet.builder()
.id("7a6ffed9-4252-427e-af7d-3dcaaf2db1eg")
.balance(new BigDecimal("69.00"))
.currency("EUR")
.build());
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.playtomic.tests.wallet.adapter;

import com.playtomic.tests.wallet.Currency;
import com.playtomic.tests.wallet.dto.WalletDTO;
import com.playtomic.tests.wallet.model.Wallet;

public class WalletAdapter {
public static Wallet ToWallet(WalletDTO.WalletReq walletReq) {
return Wallet.builder()
.id(walletReq.getId())
.balance(walletReq.getBalance())
.currency(walletReq.getCurrency().toString())
.build();
}

public static WalletDTO.WalletRes ToWalletRes(Wallet wallet) {
return WalletDTO.WalletRes.builder()
.id(wallet.getId())
.balance(wallet.getBalance())
.currency(Currency.valueOf(wallet.getCurrency()))
.build();
}

public static Wallet ToWallet(WalletDTO.WalletRes walletRes) {
return Wallet.builder()
.id(walletRes.getId())
.balance(walletRes.getBalance())
.currency(walletRes.getCurrency().toString())
.build();
}
}
16 changes: 0 additions & 16 deletions src/main/java/com/playtomic/tests/wallet/api/WalletController.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.playtomic.tests.wallet.contoller;

import com.playtomic.tests.wallet.dto.WalletDTO;
import com.playtomic.tests.wallet.dto.WalletTransactionDTO;
import com.playtomic.tests.wallet.exceptions.NotEnoughMoneyInWalletException;
import com.playtomic.tests.wallet.exceptions.PaymentServiceException;
import com.playtomic.tests.wallet.exceptions.WalletAlreadyExistsException;
import com.playtomic.tests.wallet.exceptions.WalletNotFoundException;
import com.playtomic.tests.wallet.model.Payment;
import com.playtomic.tests.wallet.service.WalletService;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Optional;

@RequestMapping("/api/v1/wallet")
@RestController
@AllArgsConstructor
@Api(tags = "Wallet")
public class WalletController {
private final Logger logger = LoggerFactory.getLogger(WalletController.class);

@Autowired private WalletService walletService;

@GetMapping(
path = "/{id}",
produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<WalletDTO.WalletRes> getById(@PathVariable(name = "id") final String id)
throws WalletNotFoundException {
logger.info("Fetching wallet with id: " + id);
Optional<WalletDTO.WalletRes> walletOpt = walletService.findById(id);
return walletOpt.map(ResponseEntity::ok).orElse(ResponseEntity.badRequest().build());
}

@GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<List<WalletDTO.WalletRes>> findAll() {
logger.info("Fetching all wallets");
Optional<List<WalletDTO.WalletRes>> walletsOpt = walletService.findAll();
return walletsOpt.map(ResponseEntity::ok).orElse(ResponseEntity.badRequest().build());
}

@GetMapping(
path = "/transactions/{walletId}",
produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<List<WalletTransactionDTO.WalletTransactionRes>> findAllWalletTrans(
@PathVariable(name = "walletId") final String walletId) {
logger.info("Fetching all wallet transactions");
Optional<List<WalletTransactionDTO.WalletTransactionRes>> walletsOpt =
walletService.findAllTransactionsForWalletId(walletId);
return walletsOpt.map(ResponseEntity::ok).orElse(ResponseEntity.badRequest().build());
}

@PostMapping(path = "/pay", consumes = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody ResponseEntity<WalletDTO.WalletRes> pay(@RequestBody Payment payment)
throws WalletNotFoundException, NotEnoughMoneyInWalletException {

Optional<WalletDTO.WalletRes> pay = walletService.pay(payment.getId(), payment.getBalance());
return pay.map(ResponseEntity::ok).orElse(ResponseEntity.badRequest().build());
}

@PostMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<WalletDTO.WalletRes> create(@RequestBody WalletDTO.WalletReq walletReq)
throws WalletAlreadyExistsException {
Optional<WalletDTO.WalletRes> walletRes = walletService.create(walletReq);

return walletRes.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.badRequest().build());
}

@PostMapping(path = "/recharge", consumes = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody ResponseEntity<WalletDTO.WalletRes> recharge(@RequestBody Payment payment)
throws WalletNotFoundException, PaymentServiceException {

Optional<WalletDTO.WalletRes> recharge =
walletService.recharge(payment.getId(), payment.getBalance());
return recharge.map(ResponseEntity::ok).orElse(ResponseEntity.badRequest().build());
}

@DeleteMapping(
path = "/{id}",
produces = {MediaType.APPLICATION_JSON_VALUE})
public boolean delete(@PathVariable String id) throws WalletNotFoundException {
return walletService.delete(id);
}
}
33 changes: 33 additions & 0 deletions src/main/java/com/playtomic/tests/wallet/dto/WalletDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.playtomic.tests.wallet.dto;

import com.playtomic.tests.wallet.Currency;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;

import static lombok.AccessLevel.PROTECTED;

public class WalletDTO {

@Data
@NoArgsConstructor(access = PROTECTED)
@AllArgsConstructor()
public static class WalletReq {
String id;
BigDecimal balance;
Currency currency;
}

@Data
@NoArgsConstructor(access = PROTECTED)
@AllArgsConstructor
@Builder
public static class WalletRes {
String id;
BigDecimal balance;
Currency currency;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.playtomic.tests.wallet.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;

import static lombok.AccessLevel.PROTECTED;

public class WalletTransactionDTO {
@Data
@NoArgsConstructor(access = PROTECTED)
@AllArgsConstructor()
public static class WalletTransactionReq {
Long id;
String walletId;
BigDecimal amount;
Long updatedAt;
}

@Data
@NoArgsConstructor(access = PROTECTED)
@AllArgsConstructor
@Builder
public static class WalletTransactionRes {
Long id;
String walletId;
BigDecimal amount;
Long updatedAt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.playtomic.tests.wallet.exceptions;

public class NotEnoughMoneyInWalletException extends Exception {

public NotEnoughMoneyInWalletException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.playtomic.tests.wallet.exceptions;

/** */
public class PaymentServiceException extends Exception {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.playtomic.tests.wallet.exceptions;

public class WalletAlreadyExistsException extends Exception {

public WalletAlreadyExistsException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.playtomic.tests.wallet.exceptions;

public class WalletNotFoundException extends Exception {

public WalletNotFoundException(String message) {
super(message);
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/playtomic/tests/wallet/model/Payment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.playtomic.tests.wallet.model;

import java.math.BigDecimal;

public class Payment extends Wallet {
BigDecimal amount;

Payment(String id, BigDecimal amount) {
super(id, amount);
this.amount = amount;
}
}
Loading