Skip to content

Commit

Permalink
solves RED-21
Browse files Browse the repository at this point in the history
  • Loading branch information
sombriks committed Mar 24, 2024
1 parent a7b2479 commit 906ae62
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
export const up = async (knex) => {
return knex.schema.table('recorrencia', tb => {
tb.dropColumn('valor')
tb.dropColumn('usuario_id')
tb.string('cor').notNullable().defaultTo('#f00')
tb.integer('parcelas').notNullable().defaultTo(1)
tb.decimal('valorParcela', 10, 2).notNullable().defaultTo(0)
tb.integer('categoria_id').unsigned()
.references('categoria.id')
.onDelete('set null')
tb.integer('conta_id').notNullable().unsigned()
.references('conta.id')
.onDelete('cascade')
tb.integer('tipo_movimentacao_id').notNullable().unsigned()
.references('tipo_movimentacao.id').defaultTo(2)
})
}

Expand All @@ -21,9 +27,14 @@ export const up = async (knex) => {
export const down = async (knex) => {
return knex.schema.table('recorrencia', tb => {
tb.decimal('valor', 10, 2).notNullable().defaultTo(0)
tb.integer('usuario_id').notNullable().unsigned()
.references('usuario.id')
.onDelete('cascade')
tb.dropColumn('cor')
tb.dropColumn('parcelas')
tb.dropColumn('valorParcela')
tb.dropColumn('categoria_id')
tb.dropColumn('conta_id')
tb.dropColumn('tipo_movimentacao_id')
})
}
38 changes: 22 additions & 16 deletions service-node-koa/app/controllers/recorrencia.mjs
Original file line number Diff line number Diff line change
@@ -1,35 +1,41 @@
import {
delRecorrencia,
findRecorrencia,
findRecorrencia, geraLancamentos,
insertRecorrencia,
listRecorrencia,
updateRecorrencia
} from "../services/index.mjs";
} from '../services/index.mjs'

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

export const insertRecorrenciaRequest = async ctx => {
const {usuario_id} = ctx.request.params;
const recorrencia = ctx.request.body;
ctx.body = await insertRecorrencia({usuario_id, recorrencia})
const { usuario_id } = ctx.request.params
const recorrencia = ctx.request.body
ctx.body = await insertRecorrencia({ usuario_id, recorrencia })
}

export const findRecorrenciaRequest = async ctx => {
const {usuario_id, id} = ctx.request.params;
ctx.body = await findRecorrencia({usuario_id, id})
const { usuario_id, id } = ctx.request.params
ctx.body = await findRecorrencia({ usuario_id, id })
}

export const updateRecorrenciaRequest = async ctx => {
const {usuario_id, id} = ctx.request.params;
const recorrencia = ctx.request.body;
ctx.body = await updateRecorrencia({usuario_id, id, recorrencia})
const { usuario_id, id } = ctx.request.params
const recorrencia = ctx.request.body
ctx.body = await updateRecorrencia({ usuario_id, id, recorrencia })
}

export const delRecorrenciaRequest = async ctx => {
const {usuario_id, id} = ctx.request.params;
ctx.body = await delRecorrencia({usuario_id, id})
const { usuario_id, id } = ctx.request.params
ctx.body = await delRecorrencia({ usuario_id, id })
}

export const geraLancamentosRequest = async ctx => {
const { usuario_id, id } = ctx.request.params
const result = await geraLancamentos({ usuario_id, id })
ctx.body = result
}
8 changes: 4 additions & 4 deletions service-node-koa/app/controllers/recorrencia.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe("Recorrencia API requests", () => {
})

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

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

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

it("should delete recorrencia", async () => {
const [{id}] = await insertRecorrencia({
usuario_id: user.id, recorrencia: {tipo_recorrencia_id: 1, descricao: "nova", valorParcela: 100.50}
usuario_id: user.id, recorrencia: {tipo_recorrencia_id: 1, conta_id: conta.id, descricao: "nova", valorParcela: 100.50}
})
const res = await chai
.request(app.callback())
Expand Down
4 changes: 2 additions & 2 deletions service-node-koa/app/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
findCategoriaRequest,
findContaRequest,
findMovimentacaoRequest,
findRecorrenciaRequest,
findRecorrenciaRequest, geraLancamentosRequest,
insertCategoriaRequest,
insertContaRequest,
insertMovimentacaoRequest,
Expand Down Expand Up @@ -106,7 +106,7 @@ new ApiBuilder({router}).path(b => {
b.get(findRecorrenciaRequest)
b.put(updateRecorrenciaRequest)
b.del(delRecorrenciaRequest)
b.get("/lancamentos", ctx => ctx.body = "TBD")
b.get("/lancamentos", geraLancamentosRequest)
})
});
});
Expand Down
73 changes: 54 additions & 19 deletions service-node-koa/app/services/recorrencia.mjs
Original file line number Diff line number Diff line change
@@ -1,30 +1,65 @@
import {knex} from "../config/db/index.mjs";
import { knex } from '../config/db/index.mjs'
import { addMonths, differenceInDays, differenceInMonths, differenceInYears } from 'date-fns'

export const listRecorrencia = ({usuario_id = -1, q = "", limit = 10, offset = 0}) => {
return knex("recorrencia")
.where({usuario_id})
.andWhereLike("descricao", `%${q}%`)
export const listRecorrencia = ({ usuario_id = -1, q = '', limit = 10, offset = 0 }) => {
return knex('recorrencia')
.whereIn('conta_id', knex('conta').select('id').where({ usuario_id }))
.andWhereLike('descricao', `%${q}%`)
.offset(offset)
.limit(limit);
};
.limit(limit)
}

export const findRecorrencia = ({usuario_id = -1, id = -1}) => {
return knex("recorrencia")
.where({usuario_id, id})
export const findRecorrencia = ({ id = -1 }) => {
return knex('recorrencia')
.where({ id })
.first()
}

export const insertRecorrencia = ({usuario_id, recorrencia}) => {
recorrencia.usuario_id = usuario_id
return knex("recorrencia").insert(recorrencia, ["id"])
export const insertRecorrencia = ({ recorrencia }) => {
return knex('recorrencia').insert(recorrencia, ['id'])
}

export const updateRecorrencia = ({ usuario_id, id, recorrencia }) => {
recorrencia.id = id
return knex('recorrencia').update(recorrencia).where({ id })
}

export const delRecorrencia = ({ id }) => {
return knex('recorrencia').del().where({ id })
}

export const geraLancamentos = async ({ usuario_id, id }) => {
const recorrencia = await findRecorrencia({ usuario_id, id })
if (!recorrencia) throw new Error('recorrencia não encontrada!')
await limparParcelas(recorrencia)
const numParcelas = calculaParcelas(recorrencia)
const lancamentos = []
for (let i = 0; i < numParcelas; i++) {
lancamentos.push({
descricao: `${recorrencia.descricao} (${i + 1}/${numParcelas})`,
categoria_id: recorrencia.categoria_id,
recorrencia_id: recorrencia.id,
conta_id: recorrencia.conta_id,
tipo_movimentacao_id: recorrencia.tipo_movimentacao_id,
vencimento: addMonths(recorrencia.inicial, i).toISOString(),
valor: recorrencia.valorParcela
})
}
const result = await knex('movimentacao').insert(lancamentos)
return { success: true }
}

export const updateRecorrencia = ({usuario_id, id, recorrencia}) => {
recorrencia.usuario_id = usuario_id;
recorrencia.id = id;
return knex("recorrencia").update(recorrencia).where({usuario_id, id})
const limparParcelas = async (recorrencia) => {
return await knex('movimentacao').del().where({ recorrencia_id: recorrencia.id })
}

export const delRecorrencia = ({usuario_id, id}) => {
return knex("recorrencia").del().where({usuario_id, id})
const calculaParcelas = ({ tipo_recorrencia_id, inicial, final }) => {
switch (tipo_recorrencia_id) {
case 1:
return 1 + differenceInMonths(final, inicial)
case 2:
return 1 + differenceInYears(final, inicial)
default:
return 1 + differenceInDays(final, inicial)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
rounded
size="large"
color="green-accent-2"
prepend-icon="mdi-currency-usd"
prepend-icon="mdi-cash"
append-icon="mdi-playlist-plus"
@click="router.push('/nova-movimentacao')"
>
Expand Down
13 changes: 13 additions & 0 deletions web-app-vue/src/components/recorrencia/detalhe-recorrencia.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:color="props.recorrencia?.cor || 'green-accent-2'"
class="ma-2"
size="x-large"
:prepend-icon="props.recorrencia?.id ? props.recorrencia?.tipo_movimentacao_id == 1 ? 'mdi-cash-plus' : 'mdi-cash-minus' : 'mdi-cash'"
:append-icon="props.recorrencia?.id ? 'mdi-playlist-edit' : 'mdi-playlist-plus'"
@click="edit = !edit"
>
Expand All @@ -15,12 +16,21 @@
<v-form v-model="valid" @submit.prevent.stop="doSave">
<v-container>
<v-color-picker v-model="rec.cor"></v-color-picker>
<v-row align="center">
<!-- movEdit.tipo_movimentacao_id-->
<v-radio-group v-model="rec.tipo_movimentacao_id" inline>
<v-radio :value="1" label="Entrada"></v-radio>
<v-radio :value="2" label="Saída"></v-radio>
</v-radio-group>
</v-row>
<v-text-field
:rules="[requiredRule]"
v-model="rec.descricao"
label="Descrição"
></v-text-field>
<categoria-autocomplete v-model="rec.categoria_id" />
<conta-autocomplete :rules="[requiredRule]" v-model="rec.conta_id" />
<v-select
v-model="rec.tipo_recorrencia_id"
:items="recorrenciaStore.store.tiposRecorrencia"
Expand Down Expand Up @@ -87,6 +97,7 @@ import ButtonDate from '@/shared/button-date.vue'
import CategoriaAutocomplete from '@/shared/categoria-autocomplete.vue'
import { useRecorrenciaStore } from '@/stores/recorrenciaStore'
import { useCategoriaStore } from '@/stores/categoriaStore'
import ContaAutocomplete from '@/shared/conta-autocomplete.vue'
const recorrenciaStore = useRecorrenciaStore()
const categoriaStore = useCategoriaStore()
Expand All @@ -102,7 +113,9 @@ const reset = () => ({
tipo_recorrencia_id: 1,
inicial: startOfMonth(new Date()),
final: endOfMonth(new Date()),
tipo_movimentacao_id: 2,
categoria_id: null,
conta_id: null,
valorParcela: 0,
descricao: '',
parcelas: 1,
Expand Down

0 comments on commit 906ae62

Please sign in to comment.