Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development #24

Open
wants to merge 6 commits into
base: main
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
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Database MySQL
DB_HOST=localhost
DB_NAME=invest
DB_USER=root
DB_PASS=pass
DB_PORT=3306
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### Composer template
composer.phar
/vendor/

### Dotenv
.env
.idea
15 changes: 15 additions & 0 deletions .htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
DirectoryIndex index.php

# enable apache rewrite engine
RewriteEngine on

# set your rewrite base
# Edit this in your init method too if you script lives in a subfolder
RewriteBase /

# Deliver the folder or file directly if it exists on the server
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# Push every request to index.php
RewriteRule ^(.*)$ index.php [QSA]
86 changes: 86 additions & 0 deletions Database.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
-- phpMyAdmin SQL Dump
-- version 5.1.3-2.fc35.remi
-- https://www.phpmyadmin.net/
--
-- Host: localhost
-- Tempo de geração: 08-Mar-2022 às 05:49
-- Versão do servidor: 8.0.28
-- versão do PHP: 7.4.28

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Banco de dados: `invest`
--

-- --------------------------------------------------------

--
-- Estrutura da tabela `investments`
--

CREATE TABLE `investments` (
`id` int NOT NULL,
`user_id` int NOT NULL,
`value` decimal(15,2) NOT NULL DEFAULT '0.00',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

-- --------------------------------------------------------

--
-- Estrutura da tabela `users`
--

CREATE TABLE `users` (
`id` int NOT NULL,
`name` varchar(255) NOT NULL,
`cpf` varchar(11) NOT NULL,
`token` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

--
-- Índices para tabelas despejadas
--

--
-- Índices para tabela `investments`
--
ALTER TABLE `investments`
ADD PRIMARY KEY (`id`);

--
-- Índices para tabela `users`
--
ALTER TABLE `users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `cpf` (`cpf`);

--
-- AUTO_INCREMENT de tabelas despejadas
--

--
-- AUTO_INCREMENT de tabela `investments`
--
ALTER TABLE `investments`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=54;

--
-- AUTO_INCREMENT de tabela `users`
--
ALTER TABLE `users`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
COMMIT;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
270 changes: 182 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,182 @@
# Back End Test Project <img src="https://coderockr.com/assets/images/coderockr.svg" align="right" height="50px" />

You should see this challenge as an opportunity to create an application following modern development best practices (given the stack of your choice), but also feel free to use your own architecture preferences (coding standards, code organization, third-party libraries, etc). It’s perfectly fine to use vanilla code or any framework or libraries.

## Scope

In this challenge you should build an API for an application that stores and manages investments, it should have the following features:

1. __Creation__ of an investment with an owner, a creation date and an amount.
1. The creation date of an investment can be today or a date in the past.
2. An investment should not be or become negative.
2. __View__ of an investment with its initial amount and expected balance.
1. Expected balance should be the sum of the invested amount and the [gains][].
3. __Withdrawal__ of a investment.
1. The withdraw will always be the sum of the initial amount and its gains,
partial withdrawn is not supported.
2. Withdrawals can happen in the past or today, but can't happen before the investment creation or the future.
3. [Taxes][taxes] need to be applied to the withdrawals before showing the
final value.
4. __List__ of a person's investments
1. This list should have pagination.

__NOTE:__ the implementation of an interface will not be evaluated.

### Gain Calculation

The investment will pay 0.52% every month in the same day of the investment creation.

Given that the gain is paid every month, it should be treated as [compound gain][], which means that every new period (month) the amount gained will become part of the investment balance for the next payment.

### Taxation

When money is withdrawn, tax is triggered. Taxes apply only to the profit/gain portion of the money withdrawn. For example, if the initial investment was 1000.00, the current balance is 1200.00, then the taxes will be applied to the 200.00.

The tax percentage changes according to the age of the investment:
* If it is less than one year old, the percentage will be 22.5% (tax = 45.00).
* If it is between one and two years old, the percentage will be 18.5% (tax = 37.00).
* If older than two years, the percentage will be 15% (tax = 30.00).

## Requirements
1. Create project using any technology of your preference. It’s perfectly OK to use vanilla code or any framework or libraries;
2. Although you can use as many dependencies as you want, you should manage them wisely;
3. It is not necessary to send the notification emails, however, the code required for that would be welcome;
4. The API must be documented in some way.

## Deliverables
The project source code and dependencies should be made available in GitHub. Here are the steps you should follow:
1. Fork this repository to your GitHub account (create an account if you don't have one, you will need it working with us).
2. Create a "development" branch and commit the code to it. Do not push the code to the main branch.
3. Include a README file that describes:
- Special build instructions, if any
- List of third-party libraries used and short description of why/how they were used
- A link to the API documentation.
4. Once the work is complete, create a pull request from "development" into "main" and send us the link.
5. Avoid using huge commits hiding your progress. Feel free to work on a branch and use `git rebase` to adjust your commits before submitting the final version.

## Coding Standards
When working on the project be as clean and consistent as possible.

## Project Deadline
Ideally you'd finish the test project in 5 days. It shouldn't take you longer than a entire week.

## Quality Assurance
Use the following checklist to ensure high quality of the project.

### General
- First of all, the application should run without errors.
- Are all requirements set above met?
- Is coding style consistent?
- The API is well documented?
- The API has unit tests?

## Submission
1. A link to the Github repository.
2. Briefly describe how you decided on the tools that you used.

## Have Fun Coding 🤘
- This challenge description is intentionally vague in some aspects, but if you need assistance feel free to ask for help.
- If any of the seems out of your current level, you may skip it, but remember to tell us about it in the pull request.

## Credits

This coding challenge was inspired on [kinvoapp/kinvo-back-end-test](https://github.com/kinvoapp/kinvo-back-end-test/blob/2f17d713de739e309d17a1a74a82c3fd0e66d128/README.md)

[gains]: #gain-calculation
[taxes]: #taxation
[interest]: #interest-calculation
[compound gain]: https://www.investopedia.com/terms/g/gain.asp
# Invest API
Dependências usadas:
- [PHP Dotenv](https://github.com/vlucas/phpdotenv) - Para ter a leitura do arquivo .env e aceitar variáveis de ambiente no projeto
- [ Simple Database Manager](https://github.com/william-costa/database-manager) - Uma pequena classe PHP para gerenciar bancos dados MySQL, que foi desenvolvido em live no YouTube.
- [Simple Route PHP](https://github.com/steampixel/simplePHPRouter) - Facilita a criação de rotas e os trabalhos com Request e Response das aplicações PHP
### Requisitos:
* PHP 8+
* [Composer 2.+](https://getcomposer.org/)
* Banco de dados MySQL 8+
## Instalação
```shell
git clone https://github.com/misterioso013/backend-test.git

cd backend-test

composer install

php -S localhost:8080
```
- Importe o arquivo `Database.sql` no seu banco de dados
- Agora é só renomear o arquivo `.env.example` para .`env` e alterar seus valores de acordo com o seu banco de dados MySQL.

## Documentação
- O único método aceito nas requisições é *POST*
- Exemplo de URL da API padrão: `localhost:8080/`
### Exemplo de uso:
```shell
curl -X POST http://localhost:8080/createUser -H "Content-Type: application/x-www-form-urlencoded" -d "name=Name+Aqui&cpf=12345678900"
```
### /createUser
Método resposável pela criação de um usuário no sistema

| Parâmetro| Tipo| Obrigatório | Descrição |
|----------|-----|----------|-----------------|
| name| string | Sim | Nome do cliente |
| cpf | number/string | Sim | CPF válido do cliente |

#### Resultado:
```json
{
"status": "ok",
"message": "User created successfully",
"credentials": {
"id": "1",
"token": "db953f68da472h7be995db04b4186dfg"
}
}
```
#### Sobre os campos
| Campo | Descrição |
|---------------------|---------------------------------------------------------|
| credentials > id | Indetificador único do usuário |
| credentials > token | Chave de acesso para acessar os ivestimentos do usuário |

### /investment/create
Método resposável pela criação do investimento

| Parâmetro| Tipo | Obrigatório | Descrição |
|----------|-------|--|--------------------------------------------------------------------|
| user_id | integer | Sim | Identificador do usuário |
| token | string | Sim | Token para validar a autenticação do usuário |
| value | float | Sim | Valor do investimento. Exemplo, para `R$1.234,56` digite `1234.56` |
| date | timestamp | Opcional | Data da criação do investimento. exemplo: 2022-03-06 21:20:37 |

#### Resultado:
```json
{
"status":"ok",
"message":"Investment created successfully",
"details":{
"investment_id":"1",
"created_at":"2022-03-07 21:21:37"
}
}
```
#### Sobre os campos
| Campo | Descrição |
|-------------------------|-------------------------------------|
| details > investment_id | Indetificador único do investimento |
| details > created_at | Data da criação do investimento |


### /investment/view
Este método retornará detalhes sobre um investimento

| Parâmetro| Tipo | Obrigatório | Descrição |
|----------|-------|--|--------------------------------------------------------------------|
| user_id | integer | Sim | Identificador do usuário |
| token | string | Sim | Token para validar a autenticação do usuário |
| id | integer | Sim | ID do investimento, que poderá ser recuperado através do método [listar](#/investment/list) |

#### Resultado:

```json
{
"status":"ok",
"id":"54",
"initial_investment":"20000.00",
"current_investment":"21248.00",
"income":"1248.00",
"withdrawal":"21017.12"
}
```
#### Sobre os campos

| Campo | Descrição |
|--------------------|-----------------------------------------------------|
| id | Indetificador único do investimento |
| initial_investment | Valor inicial do investimento |
| current_investment | Valor atual do investimento com juros acrescentados |
| income | Valor da renda total gerada até o momento |
| withdrawal | Valor disponível para a retirada |

### /investment/list
Este método retornará uma lista com todos os investimentos

| Parâmetro| Tipo | Obrigatório | Descrição |
|----------|-------|--|--------------------------------------------------------------------|
| user_id | integer | Sim | Identificador do usuário |
| token | string | Sim | Token para validar a autenticação do usuário |
| page | integer | Opcional | Número da página que deseja acessar, são exibidos 5 resultados por página |

#### Resultado:

```json
{
"status":"ok",
"pages":8,
"results":[
{
"id":"54",
"initial_investment":"20000.00",
"current_investment":"21248.00",
"income":"1248.00",
"withdrawal":"21017.12"
},
{
"id":"55",
"initial_investment":"100000.00",
"current_investment":"100000.00",
"income":"0.00",
"withdrawal":"100000.00"
}
]
}
```
#### Sobre os campos

| Campo | Descrição |
|-------------------------------------|------------------------------------------------------|
| pages | Número de páginas disponíveis |
| result | Retonar um Array com os detalhes de cada investimeto |
| result > valor > initial_investment | Valor inicial do investimento |
| result > valor > current_investment | Valor atual do investimento com juros acrescentados |
| result > valor > income | Valor da renda total gerada até o momento |
| result > valor > withdrawal | Valor disponível para a retirada |

### investment/withdrawal
Método resposável por fazer a retirada de um investimento

| Parâmetro| Tipo | Obrigatório | Descrição |
|---------|-------|--|------------------------------------|
| user_id | integer | Sim | Identificador do usuário |
| token | string | Sim | Token para validar a autenticação do usuário |
| id | integer | Sim | ID do investimento que deseja retirar |
| date | timestamp | Opcional | Data da retirada do investimento. Exemplo: 2022-03-06 21:20:37 |


#### Resultado:
```json
{
"status":"ok",
"message":"Withdrawal successful",
"initial_investment":"100000.00",
"withdrawal":"121216.00"
}
```
#### Sobre os campos
| Campo | Descrição |
|--------------------|------------------------------------------------|
| initial_investment | Valor do investimento inical |
| withdrawal | Valor da retirada já com os impostos aplicados |
Loading