Skip to content

Commit 906ae62

Browse files
committed
solves RED-21
1 parent a7b2479 commit 906ae62

File tree

7 files changed

+107
-42
lines changed

7 files changed

+107
-42
lines changed

service-node-koa/app/config/db/migrations/20240319214705_alter_table_recorrencia.mjs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
export const up = async (knex) => {
66
return knex.schema.table('recorrencia', tb => {
77
tb.dropColumn('valor')
8+
tb.dropColumn('usuario_id')
89
tb.string('cor').notNullable().defaultTo('#f00')
910
tb.integer('parcelas').notNullable().defaultTo(1)
1011
tb.decimal('valorParcela', 10, 2).notNullable().defaultTo(0)
1112
tb.integer('categoria_id').unsigned()
1213
.references('categoria.id')
1314
.onDelete('set null')
15+
tb.integer('conta_id').notNullable().unsigned()
16+
.references('conta.id')
17+
.onDelete('cascade')
18+
tb.integer('tipo_movimentacao_id').notNullable().unsigned()
19+
.references('tipo_movimentacao.id').defaultTo(2)
1420
})
1521
}
1622

@@ -21,9 +27,14 @@ export const up = async (knex) => {
2127
export const down = async (knex) => {
2228
return knex.schema.table('recorrencia', tb => {
2329
tb.decimal('valor', 10, 2).notNullable().defaultTo(0)
30+
tb.integer('usuario_id').notNullable().unsigned()
31+
.references('usuario.id')
32+
.onDelete('cascade')
2433
tb.dropColumn('cor')
2534
tb.dropColumn('parcelas')
2635
tb.dropColumn('valorParcela')
2736
tb.dropColumn('categoria_id')
37+
tb.dropColumn('conta_id')
38+
tb.dropColumn('tipo_movimentacao_id')
2839
})
2940
}
Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,41 @@
11
import {
22
delRecorrencia,
3-
findRecorrencia,
3+
findRecorrencia, geraLancamentos,
44
insertRecorrencia,
55
listRecorrencia,
66
updateRecorrencia
7-
} from "../services/index.mjs";
7+
} from '../services/index.mjs'
88

99
export const listRecorrenciaRequest = async ctx => {
10-
const {usuario_id} = ctx.request.params;
11-
const {q = "", limit = 10, offset = 0} = ctx.request.query;
12-
ctx.body = await listRecorrencia({usuario_id, q, limit, offset});
13-
};
10+
const { usuario_id } = ctx.request.params
11+
const { q = '', limit = 10, offset = 0 } = ctx.request.query
12+
ctx.body = await listRecorrencia({ usuario_id, q, limit, offset })
13+
}
1414

1515
export const insertRecorrenciaRequest = async ctx => {
16-
const {usuario_id} = ctx.request.params;
17-
const recorrencia = ctx.request.body;
18-
ctx.body = await insertRecorrencia({usuario_id, recorrencia})
16+
const { usuario_id } = ctx.request.params
17+
const recorrencia = ctx.request.body
18+
ctx.body = await insertRecorrencia({ usuario_id, recorrencia })
1919
}
2020

2121
export const findRecorrenciaRequest = async ctx => {
22-
const {usuario_id, id} = ctx.request.params;
23-
ctx.body = await findRecorrencia({usuario_id, id})
22+
const { usuario_id, id } = ctx.request.params
23+
ctx.body = await findRecorrencia({ usuario_id, id })
2424
}
2525

2626
export const updateRecorrenciaRequest = async ctx => {
27-
const {usuario_id, id} = ctx.request.params;
28-
const recorrencia = ctx.request.body;
29-
ctx.body = await updateRecorrencia({usuario_id, id, recorrencia})
27+
const { usuario_id, id } = ctx.request.params
28+
const recorrencia = ctx.request.body
29+
ctx.body = await updateRecorrencia({ usuario_id, id, recorrencia })
3030
}
3131

3232
export const delRecorrenciaRequest = async ctx => {
33-
const {usuario_id, id} = ctx.request.params;
34-
ctx.body = await delRecorrencia({usuario_id, id})
33+
const { usuario_id, id } = ctx.request.params
34+
ctx.body = await delRecorrencia({ usuario_id, id })
35+
}
36+
37+
export const geraLancamentosRequest = async ctx => {
38+
const { usuario_id, id } = ctx.request.params
39+
const result = await geraLancamentos({ usuario_id, id })
40+
ctx.body = result
3541
}

service-node-koa/app/controllers/recorrencia.spec.mjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe("Recorrencia API requests", () => {
3636
})
3737

3838
it("Should insert recorrencia", async () => {
39-
const novaRecorrencia = {tipo_recorrencia_id: 1, descricao: "nova", valorParcela: 100.50}
39+
const novaRecorrencia = {tipo_recorrencia_id: 1, conta_id: conta.id, descricao: "nova", valorParcela: 100.50}
4040
const res = await chai
4141
.request(app.callback())
4242
.post(`/${user.id}/recorrencia`)
@@ -48,7 +48,7 @@ describe("Recorrencia API requests", () => {
4848

4949
it("Should find recorrencia", async () => {
5050
const [{id}] = await insertRecorrencia({
51-
usuario_id: user.id, recorrencia: {tipo_recorrencia_id: 1, descricao: "nova", valorParcela: 100.50}
51+
usuario_id: user.id, recorrencia: {tipo_recorrencia_id: 1, conta_id: conta.id, descricao: "nova", valorParcela: 100.50}
5252
})
5353
const res = await chai
5454
.request(app.callback())
@@ -61,7 +61,7 @@ describe("Recorrencia API requests", () => {
6161

6262
it("Should update recorrencia", async () => {
6363
const [{id}] = await insertRecorrencia({
64-
usuario_id: user.id, recorrencia: {tipo_recorrencia_id: 1, descricao: "nova", valorParcela: 100.50}
64+
usuario_id: user.id, recorrencia: {tipo_recorrencia_id: 1, conta_id: conta.id, descricao: "nova", valorParcela: 100.50}
6565
})
6666
const res = await chai
6767
.request(app.callback())
@@ -76,7 +76,7 @@ describe("Recorrencia API requests", () => {
7676

7777
it("should delete recorrencia", async () => {
7878
const [{id}] = await insertRecorrencia({
79-
usuario_id: user.id, recorrencia: {tipo_recorrencia_id: 1, descricao: "nova", valorParcela: 100.50}
79+
usuario_id: user.id, recorrencia: {tipo_recorrencia_id: 1, conta_id: conta.id, descricao: "nova", valorParcela: 100.50}
8080
})
8181
const res = await chai
8282
.request(app.callback())

service-node-koa/app/main.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
findCategoriaRequest,
1313
findContaRequest,
1414
findMovimentacaoRequest,
15-
findRecorrenciaRequest,
15+
findRecorrenciaRequest, geraLancamentosRequest,
1616
insertCategoriaRequest,
1717
insertContaRequest,
1818
insertMovimentacaoRequest,
@@ -106,7 +106,7 @@ new ApiBuilder({router}).path(b => {
106106
b.get(findRecorrenciaRequest)
107107
b.put(updateRecorrenciaRequest)
108108
b.del(delRecorrenciaRequest)
109-
b.get("/lancamentos", ctx => ctx.body = "TBD")
109+
b.get("/lancamentos", geraLancamentosRequest)
110110
})
111111
});
112112
});
Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,65 @@
1-
import {knex} from "../config/db/index.mjs";
1+
import { knex } from '../config/db/index.mjs'
2+
import { addMonths, differenceInDays, differenceInMonths, differenceInYears } from 'date-fns'
23

3-
export const listRecorrencia = ({usuario_id = -1, q = "", limit = 10, offset = 0}) => {
4-
return knex("recorrencia")
5-
.where({usuario_id})
6-
.andWhereLike("descricao", `%${q}%`)
4+
export const listRecorrencia = ({ usuario_id = -1, q = '', limit = 10, offset = 0 }) => {
5+
return knex('recorrencia')
6+
.whereIn('conta_id', knex('conta').select('id').where({ usuario_id }))
7+
.andWhereLike('descricao', `%${q}%`)
78
.offset(offset)
8-
.limit(limit);
9-
};
9+
.limit(limit)
10+
}
1011

11-
export const findRecorrencia = ({usuario_id = -1, id = -1}) => {
12-
return knex("recorrencia")
13-
.where({usuario_id, id})
12+
export const findRecorrencia = ({ id = -1 }) => {
13+
return knex('recorrencia')
14+
.where({ id })
1415
.first()
1516
}
1617

17-
export const insertRecorrencia = ({usuario_id, recorrencia}) => {
18-
recorrencia.usuario_id = usuario_id
19-
return knex("recorrencia").insert(recorrencia, ["id"])
18+
export const insertRecorrencia = ({ recorrencia }) => {
19+
return knex('recorrencia').insert(recorrencia, ['id'])
20+
}
21+
22+
export const updateRecorrencia = ({ usuario_id, id, recorrencia }) => {
23+
recorrencia.id = id
24+
return knex('recorrencia').update(recorrencia).where({ id })
25+
}
26+
27+
export const delRecorrencia = ({ id }) => {
28+
return knex('recorrencia').del().where({ id })
29+
}
30+
31+
export const geraLancamentos = async ({ usuario_id, id }) => {
32+
const recorrencia = await findRecorrencia({ usuario_id, id })
33+
if (!recorrencia) throw new Error('recorrencia não encontrada!')
34+
await limparParcelas(recorrencia)
35+
const numParcelas = calculaParcelas(recorrencia)
36+
const lancamentos = []
37+
for (let i = 0; i < numParcelas; i++) {
38+
lancamentos.push({
39+
descricao: `${recorrencia.descricao} (${i + 1}/${numParcelas})`,
40+
categoria_id: recorrencia.categoria_id,
41+
recorrencia_id: recorrencia.id,
42+
conta_id: recorrencia.conta_id,
43+
tipo_movimentacao_id: recorrencia.tipo_movimentacao_id,
44+
vencimento: addMonths(recorrencia.inicial, i).toISOString(),
45+
valor: recorrencia.valorParcela
46+
})
47+
}
48+
const result = await knex('movimentacao').insert(lancamentos)
49+
return { success: true }
2050
}
2151

22-
export const updateRecorrencia = ({usuario_id, id, recorrencia}) => {
23-
recorrencia.usuario_id = usuario_id;
24-
recorrencia.id = id;
25-
return knex("recorrencia").update(recorrencia).where({usuario_id, id})
52+
const limparParcelas = async (recorrencia) => {
53+
return await knex('movimentacao').del().where({ recorrencia_id: recorrencia.id })
2654
}
2755

28-
export const delRecorrencia = ({usuario_id, id}) => {
29-
return knex("recorrencia").del().where({usuario_id, id})
56+
const calculaParcelas = ({ tipo_recorrencia_id, inicial, final }) => {
57+
switch (tipo_recorrencia_id) {
58+
case 1:
59+
return 1 + differenceInMonths(final, inicial)
60+
case 2:
61+
return 1 + differenceInYears(final, inicial)
62+
default:
63+
return 1 + differenceInDays(final, inicial)
64+
}
3065
}

web-app-vue/src/components/movimentacao/lista-movimentacoes.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
rounded
88
size="large"
99
color="green-accent-2"
10-
prepend-icon="mdi-currency-usd"
10+
prepend-icon="mdi-cash"
1111
append-icon="mdi-playlist-plus"
1212
@click="router.push('/nova-movimentacao')"
1313
>

web-app-vue/src/components/recorrencia/detalhe-recorrencia.vue

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
:color="props.recorrencia?.cor || 'green-accent-2'"
77
class="ma-2"
88
size="x-large"
9+
:prepend-icon="props.recorrencia?.id ? props.recorrencia?.tipo_movimentacao_id == 1 ? 'mdi-cash-plus' : 'mdi-cash-minus' : 'mdi-cash'"
910
:append-icon="props.recorrencia?.id ? 'mdi-playlist-edit' : 'mdi-playlist-plus'"
1011
@click="edit = !edit"
1112
>
@@ -15,12 +16,21 @@
1516
<v-form v-model="valid" @submit.prevent.stop="doSave">
1617
<v-container>
1718
<v-color-picker v-model="rec.cor"></v-color-picker>
19+
20+
<v-row align="center">
21+
<!-- movEdit.tipo_movimentacao_id-->
22+
<v-radio-group v-model="rec.tipo_movimentacao_id" inline>
23+
<v-radio :value="1" label="Entrada"></v-radio>
24+
<v-radio :value="2" label="Saída"></v-radio>
25+
</v-radio-group>
26+
</v-row>
1827
<v-text-field
1928
:rules="[requiredRule]"
2029
v-model="rec.descricao"
2130
label="Descrição"
2231
></v-text-field>
2332
<categoria-autocomplete v-model="rec.categoria_id" />
33+
<conta-autocomplete :rules="[requiredRule]" v-model="rec.conta_id" />
2434
<v-select
2535
v-model="rec.tipo_recorrencia_id"
2636
:items="recorrenciaStore.store.tiposRecorrencia"
@@ -87,6 +97,7 @@ import ButtonDate from '@/shared/button-date.vue'
8797
import CategoriaAutocomplete from '@/shared/categoria-autocomplete.vue'
8898
import { useRecorrenciaStore } from '@/stores/recorrenciaStore'
8999
import { useCategoriaStore } from '@/stores/categoriaStore'
100+
import ContaAutocomplete from '@/shared/conta-autocomplete.vue'
90101
91102
const recorrenciaStore = useRecorrenciaStore()
92103
const categoriaStore = useCategoriaStore()
@@ -102,7 +113,9 @@ const reset = () => ({
102113
tipo_recorrencia_id: 1,
103114
inicial: startOfMonth(new Date()),
104115
final: endOfMonth(new Date()),
116+
tipo_movimentacao_id: 2,
105117
categoria_id: null,
118+
conta_id: null,
106119
valorParcela: 0,
107120
descricao: '',
108121
parcelas: 1,

0 commit comments

Comments
 (0)