*Desafio M5 - Projeto de aplicativo de cobranças*
**O que o usuário pode fazer ?**
- Cadastrar-se
- Logar-se
- Recuperar senha
- Ver cobranças pagas (Dados estáticos)
- Ver cobranças vencidas (Dados estáticos)
- Ver cobranças previstas (Dados estáticos)
- Ver clientes inadimplentes (Dados estáticos)
- Ver clientes em dia (Dados estáticos)
- Editar cadastro
- Listar clientes
- Adicionar clientes
- Adicionar cobranças para os clientes
**O que o usuário não pode fazer ? (Nessa sprint)**
- Cadastrar cobrança
- Editar cobrança
- Ver todas as cobranças
- Ver todos clientes em dia
- Ver todos clientes inadimplentes
<h1>Sprint 1</h1>
***Endpoints***
**Cadastro - POST**
***URL:*** /cadastro
***Método:*** POST
***Dados de entrada***
```
{"name":"Jose Silva",
"email":"josesilva@email.com"
"password":"hashSenha"}
```
***Dados de saída***
*Sucesso*
```
{"Usuário cadastrado com sucesso"}
```
*Falha*
```
{"message":"email já cadastrado"}
```
*Validações / Regras de negócio*
- Verficar se existe algum campo não informado
- Verificar se o email informado não é igual ao de outro cliente.
- Verificar se as senhas coincidem
- Usar criptografia para envio da senha(hash)
**Login - POST**
***URL:*** /login
***Método:*** POST
*Dados de entrada*
```
{
"email": "josesilva@email.com",
"password": "hashSenha"
}
```
*Dados de saída*
*Sucesso*
```
{
"user_id": "1",
"name":"Jose Silva",
"email":"josesilva@email.com",
"token":"c0ce7f40-e12b-393e-bb7c-5ad1fc3c9841"
}
```
*Falha*
```
{"message":"Usuário não existe"}
```
```
{"message":"Senha incorreta"}
```
*Validações / Regras de negócio*
- Verficar se existe algum campo não informado
- Usar criptografia para envio da senha(hash)
**Usuário - GET**
***Necessário autenticação***
***Token no header da requisição***
***URL:*** /usuario
***Método:*** GET
*Dados de entrada*
```json
{"token":"c0ce7f40-e12b-393e-bb7c-5ad1fc3c9841",
"user_id":"1"}
```
*Dados de saída*
*Sucesso*
```json
{"name":"Jose Silva",
"email":"josesilva@email.com"}
```
*Falha*
{"mensagem":"O usuário informado não existe"}
*Validações / Regras de negócio*
- Verificar se o usuário informado existe no banco de dados
- O token tem que ser passado no front no headers athorization
**Usuário - PUT**
***Necessário autenticação***
***Token no header da requisição***
***URL:*** /usuario
***Método:*** PUT
*Dados de entrada*
```json
{
"name": "Jose Silva Lima",
"email": "josesl@email.com",
"password": "hashSenha"
}
```
*Falha*
```json
{"message":"email já cadastrado"}
```
*Validações / Regras de negócio*
-Verificar se o email informado não é igual ao de outro usuario.
**Cadastro cliente - POST**
***Necessário autenticação***
***Token no header da requisição***
***URL:*** /clients
***Método:*** POST
*Dados de entrada*
```json
{
"name": "Bruna",
"email": "bruna.silahty@hotmail.com",
"cpf": "1234567890",
"phone_client": "7184958568",
"cep": "52041550",
"address": "Rua sem nome",
"complement": "Apatarmento do lado esquerdo",
"neighborhood": "Fim",
"city": "Marte",
"state": "sr"
}
```
*Dados de saída*
*Sucesso*
```json
{"mensagem": "Usuário cadastrado com sucesso"}
```
*Falha*
```json
{"message":"email já cadastrado"}
```
```json
{"message":"Telefone cadastrado por outro cliente"}
```
*Validações / Regras de negócio*
-Verificar se o email informado não é igual ao de outro cliente.
-Verificar se o telefone informado não é igual ao de outro cliente
<h1>Sprint 2</h1>
<h2>Listagem de clientes - GET</h2>
Na posição de usuário do sistema, desejo visualizar uma listagem com todos os clientes cadastrados.
**Obs:** O dados status tem que ser criado a parti da pesquisa do BD de charges e se houver alguma cobrança vencida (com status pendente e com data de vencimento anterior a data atual), deverá exibir true, caso contrário, deverá exibir false.
***Necessaário autenticação***
***Token no header da requisição***
***URL:*** /listclients
***Método:*** GET
*Dados de saída*
```jsonl
{
"clientsWithStatus": [
{
"id": 1,
"name_client": "Bruna carla",
"email_client": "bruna.silahty@hotmail.com",
"cpf_client": "1234567890 ",
"phone_client": "7184958568",
"status": true
},
{
"id": 2,
"name_client": "tayanna kelly",
"email_client": "amorim.tayanna@gmail.com",
"cpf_client": "10278487345",
"phone_client": "546373838",
"status": false
},
{
"id": 3,
"name_client": "Thaysa Ketlen",
"email_client": "thaysa.ketlen@hotmail.com",
"cpf_client": "10290999 ",
"phone_client": "85678900",
"status": false
}
],
"totalPages": 1
}
```
<h2>Detalhamento do Cliente- GET</h2>
Na posição de usuário do sistema, desejo visualizar todos os detalhes de um cliente cadastrado, a fim de consultar seus dados e suas respectivas cobranças.
***Necessaário autenticação***
***Token no header da requisição***
***URL:*** /detailclient/:id
***Método:*** GET
*Dados de saída*
```json
{
"name_client": "Jose Silva",
"cpf_client": "88051533461",
"email_client": "josesilva@email.com",
"phone_client": "1234567890",
"address_complete": {
"address": "rua sem nome",
"cep": "52041550",
"complement": "Grand Line",
"neighborhood": "Barra de Jangada",
"city": "São Paulo",
"state": "São Paulo"
},
"charges": [
{
"id_charges": "1",
"description ": "lorem ipsum, lorem ipsum, lorem ipsum, lorem ipsum",
"due_date": "12/05/23",
"amount": "5000",
"status": true
},
{
"id_charges": "2",
"description ": "lorem ipsum, lorem ipsum, lorem ipsum, lorem ipsum",
"due_date": "12/05/23",
"amount": "3000",
"status": false
}
]
}
```
<h2>Atualização do cliente - PUT</h2>
Na posição de usuário do sistema, desejo atualizar os dados de um cliente cadastrado.
***Necessaário autenticação***
***Token no header da requisição***
***URL:***/clients/:identification
***Método:*** PUT
- Campos Obrigatórios
- nome
- email
- cpf
- phone
*Dados de entrada*
```json
{
"name_client": "Bruna carla",
"email_client": "bruna.silahty@hotmail.com",
"cpf_client": "1234567890",
"phone_client": "7184958568",
"cep": "52041550",
"address": "Rua sem nome",
"complement": "Apatarmento do lado esquerdo",
"neighborhood": "Fim",
"city": "Marte",
"state": "sr"
}
```
*Dados de saída*
*Sucesso*
```json
{
"id": 22,
"id_user": 34,
"name_client": "Wuso Pedro",
"email_client": "jose.silahty@hotmail.com",
"cpf_client": "01790525093",
"phone_client": "81983498923",
"cep": "65095205",
"address": "Rua Doze",
"complement": "Apatarmento do lado esquerdo",
"neighborhood": "Tibiri",
"city": "São Luís",
"state": "PE"
}
```
*Falha*
```json
{"message":"Campos obrigatórios passados em branco"}
```
```json
{"message":"email já existe"}
```
*Mensagem de Erro em caso de:*
- Campos obrigatórios passados em branco
- E-mail informado for diferente do cliente em questão e já existir cadastrado para outro cliente.
- CPF informado for diferente do cliente em questão e já existir cadastrado para outro cliente
- Após realizado a atualização com sucesso o usuário deverá receber uma mensagem de confirmação
<h2>Cadastro de cobranças - POST</h2>
Na posição de usuário do sistema, desejo cadastrar cobranças para um cliente, afim de acessar suas informações no futuro.
***Necessário autenticação***
***Token no header da requisição***
***URL:*** /charges
***Método:*** POST
- Todos os campos são obrigatórios
- O id_customer é o do cliente em questão e não do usuário logado
*Dados de entrada*
```json
{
"id_customer": "2",
"name_client": "Heberty",
"description": "Calça Jeans",
"status": true,
"amount": 26000,
"due_date": "2023-10-01"
}
```
*Dados de saída*
```json
{
"id_charges": 5,
"id_customer": 2,
"name_client": "Heberty",
"amount": 26000,
"due_date": "2023-10-01T03:00:00.000Z",
"registration_date": "2023-09-23T03:00:00.000Z",
"description": "Calça Jeans",
"status": true
}
```
*Observações:*
- A validação para saber se está vencida pode ser feita no front
- O valor da cobrança também deve ser persistida no banco como centavos
*Mensagem de Erro em caso de:*
- Campos obrigatórios em branco
<h2>Listagem de cobranças - GET</h2>
Na posição de usuário do sistema, desejo visualizar uma listagem com todos as cobranças cadastradas.
***Necessário autenticação***
***Token no header da requisição***
***URL:*** /cobranca
***Método:*** GET
*Dados de saída*
```json
{
"id": "4234234",
"id_customer": "id que vem do req.user",
"name_client": "Juliana Paiva",
"description": "lorem ipsum",
"cpf_client": "1234567890",
"due_date": "1695168000",
"amount": "20000",
"status_charge": true || false
}
```
- A cobrança recebe Vencido (Caso o status seja pendente e a data de vencimento for anterior a data atual)
<h1>Sprint 3</h1>
<h2>Edição de Cobrança - PUT</h2>
### `Na posição de usuário do sistema, desejo atualizar os dados de uma cobrança cadastrada.`
***Necessário autenticação***
***Token no header da requisição***
***URL:*** /updatecharge
***Método:*** PUT
- Campos Obrigatórios
- Descrição (<b>\*</b>)
- Status (<b>\*</b>)
- Valor (<b>\*</b>)
- Vencimento (<b>\*</b>)
*Dados de entrada*
```json
{
"id_charges": 2,
"name_client": "Heberty",
"description": "Calça Jeans",
"status": true,
"amount": 26000,
"due_date": "2023-10-01"
}
```
*Dados de saída*
```json
{
"id_charges": 2,
"name_client": "Heberty",
"description": "Calça Jeans",
"status": true,
"amount": 26000,
"due_date": "2023-10-01",
"registration_date": "2023-09-27"
}
```
*Mensagem de Erro em caso de:*
- Campos obrigatórios passados em branco
- Após realizado a atualização com sucesso o usuário deverá receber uma mensagem de confirmação (FRONT-END)
<h2>Exclusão de cobranças - DELETE</h2>
#### `Na posição de usuário do sistema, desejo excluir uma cobrança cadastrada.`
***Necessário autenticação***
***Token no header da requisição***
***URL:*** /deletecharge:idChages
***Método:*** DELETE
- Só poderá excluir a cobrança, se:
- A cobrança estiver com status <b>pendente</b>
- A data de vencimento for <b>igual</b> ou <b>posterior a data atual</b>
- Cobranças com status <b>"pagas"</b>, não poderão ser apagadas
- OBS: Essa validações podem ser feitas no front e o back só receberia o id da cobrança que seria excluída.
*Dados de saída*
```json
{
mensage: "Cobrança deletada com sucesso"
}
```
<h2>[Cobranças/Clientes] Busca e ordenação</h2>
#### `Na posição de usuário do sistema, desejo buscar cobranças e clientes a partir de suas respectivas listagens.`
<h4>
Listagem Cobrança:
</h4>
- Na listagem de cobranças deverá possibilitar a <b>ordenação dos registros</b> pelo <b>nome do cliente</b> ou <b>ID da Cobrança</b> (front-end)
- Campo de busca que permitirá buscar cobranças pelos seguintes campos:
- Nome do cliente
- Id da cobrança
- OBS: esse filtro pode ser adicionado como uma verificação na rota já criada de listagem de cobranças
- Ex: Por exemplo, se na requisição existir um parâmetro de query que seja diferente de undefined para campos como id_charges ou name_client, a API realizará uma pesquisa correspondente com base no parâmetro fornecido.
***Lembre-se de que a pesquisa será sensível a maiúsculas e minúsculas, caso não seja definido nenhum critério de busca.***
```javascript
const { id_charges, name_client, page } = req.query;
if (nome !== undefined) {
try {
const chargesList = // aqui você pode pegar o mesmo objeto de pequisa para o Bd para listar todas as cobranças, mas tirando a paginação
const chargeFilter = chargesList.filter(
(charge) => charge.name_client === nome
);
return res.json(chargeFilter);
} catch (error) {
res.status(500).json({
mensagem: "Erro interno do servidor",
detalhes: error.message,
});
}
}
```
<h4>
Listagem Clientes:
</h4>
- Nas <b>listagens de clientes</b> deverá possibilitar a <b>ordenação</b> dos registros pelo <b>nome</b> (FRONT-END)
- Campo de busca que permitirá bucasr Clientes pelos seguintes campos:
- Nome do cliente
- CPF do cliente
- E-mail do cliente
```javascript
const { name, email, cpf, page } = req.query;
if (name !== undefined) {
try {
const clientsList = // aqui você pode pegar o mesmo objeto de pequisa para o Bd para listar todas as cobranças, mas tirando a paginação
const clientsFilter = clientsFilter.filter(
(client) => client.name_client === name
);
return res.json(chargeFilter);
} catch (error) {
res.status(500).json({
mensagem: "Erro interno do servidor",
detalhes: error.message,
});
}
}
```
- Em caso de não retornar <b>nenhum resultado</b> uma mensagem adequada deverá ser exibida.(FRONT-END)
<h2>
[Cobranças/Clientes] Botão "ver todos" - Home
</h2>
#### `Na posição de usuário do sistema, desejo visualizar um relatório personalizado de cobranças e clientes.`
***Necessário autenticação***
***Token no header da requisição***
***URL:*** /custom-report
***Método:*** GET
- Nos dados de saída deverá retornar dois objetos, sendo eles
- Objeto que contenha informação sobre todas as ***cobranças*** agrupadas em tres categorias
- ***paid*** - se a cobrança possuir o ```status = false```
- ***preview*** - se o ```status = true``` e ```due_date > ``` que a data atual
- ***Overdue*** - ```status = true``` e ``due_date < ``` que data atual
*xemplo de objeto de Charges*
```json
{
"paid": [
{ "amount": 6500 },
{ "total": 7 },
{
"charges": [
{
"id_charges": 1,
"name_client": "Bruna carla",
"amount": 2000
},
{
"id_charges": 2,
"name_client": "tayanna kelly",
"amount": 4500
}
]
}
],
"preview": [
{ "amount": 24000 },
{ "total": 8 },
{
"charges": [
{
"id_charges": 1,
"name_client": "Bruna carla",
"amount": 2000
},
{
"id_charges": 2,
"name_client": "tayanna kelly",
"amount": 4500
}
]
}
],
"overdue": [
{ "amount": 24000 },
{ "total": 5 },
{
"id_charges": 1,
"name_client": "Bruna carla",
"amount": 2000
},
{
"id_charges": 2,
"name_client": "tayanna kelly",
"amount": 4500
}
],
}
```
- Objeto que contenha informação sobre todas as ***clientes*** agrupadas pelo seu status
- ***defaulters*** - se o cliente possuir o ```status = true```
- - ***compliant*** - se o cliente possuir o ```status = false```
*Exemplo de objeto de Clients*
```json
{
"defaulters": [
{ "total": 4 },
{
"clients": [
{
"id": 16,
"name_client": "Tayanna",
"cpf_client": "123146456"
},
{
"id": 17,
"name_client": "Oriana",
"cpf_client": "123145353"
}
]
}
],
"compliant": [
{ "total": 6 },
{
"clients": [
{
"id": 17,
"name_client": "Oriana",
"cpf_client": "123145353"
},
{
"id": 17,
"name_client": "Oriana",
"cpf_client": "123145353"
}
]
}
]
}
```
*Dados saída*
```json
{
"paid": [
{ "amount": 6500 },
{ "total": 7 },
{
"charges": [
{
"id_charges": 1,
"name_client": "Bruna carla",
"amount": 2000
},
{
"id_charges": 2,
"name_client": "tayanna kelly",
"amount": 4500
}
]
}
],
"preview": [
{ "amount": 24000 },
{ "total": 8 },
{
"charges": [
{
"id_charges": 1,
"name_client": "Bruna carla",
"amount": 2000
},
{
"id_charges": 2,
"name_client": "tayanna kelly",
"amount": 4500
}
]
}
],
"Overdue": [
{ "amount": 24000 },
{ "total": 5 },
{
"id_charges": 1,
"name_client": "Bruna carla",
"amount": 2000
},
{
"id_charges": 2,
"name_client": "tayanna kelly",
"amount": 4500
}
],
"defaulters": [
{ "total": 4 },
{
"clients": [
{
"id": 16,
"name_client": "Tayanna",
"cpf_client": "123146456"
},
{
"id": 17,
"name_client": "Oriana",
"cpf_client": "123145353"
}
]
}
],
"compliant": [
{ "total": 6 },
{
"clients": [
{
"id": 17,
"name_client": "Oriana",
"cpf_client": "123145353"
},
{
"id": 17,
"name_client": "Oriana",
"cpf_client": "123145353"
}
]
}
]
}
```
***OBS: Adicionar uma ordenação do maior para o menor id, e só precisa retornar para o front os 4 primeiros resultados, tanto do objeto de charge como do de clients***