This commit is contained in:
2021-06-22 20:45:25 -05:00
parent 14f9937d93
commit 600358d640
9 changed files with 628 additions and 83 deletions

View File

@@ -0,0 +1,80 @@
<template>
<!-- <div class="fixed-plugin" v-click-outside="closeDropDown"> -->
<div class="dropdown show-dropdown" :class="{ show: isOpen }">
<a data-toggle="dropdown" class="settings-icon">
<i class="btn btn-info" @click="toggleDropDown">Nuevo </i>
</a>
<span class="dropdown-menu" :class="{ show: isOpen }">
<card class="col-12">
<template slot="header">
<img src="img//card-info.png" alt="" />
</template>
<base-input
label="Descripcion"
v-model="newCredito.nombreCredito"
></base-input>
<base-input
label="valor"
type="number"
v-model="newCredito.valor"
></base-input>
<base-input
label="Tasa Interés"
type="number"
v-model="newCredito.tasa_interes"
></base-input>
<base-button
type="info"
class="mb-3 col-12"
size="lg"
@click="saveCredito()"
>Guardar</base-button
>
</card>
</span>
</div>
<!-- </div> -->
</template>
<script>
export default {
name: "Fcredito",
props: ["newCredito", "saveCredito","isOpen"],
// data() {
// return {
// isOpen: false,
// };
// },
methods: {
toggleDropDown() {
this.isOpen = !this.isOpen;
},
closeDropDown() {
this.isOpen = false;
},
},
};
</script>
<style scoped lang="scss">
.settings-icon {
cursor: pointer;
}
.badge-vue {
background-color: #ffffff;
}
.color_fondo {
background-color: #ffffff;
}
</style>

View File

@@ -1,14 +1,12 @@
<template> <template>
<div> <div>
<h1 v-if="error.statusCode === 404">Página no encontrada</h1> <h1>Página no encontrada</h1>
<h1 v-else> !!Ha ocurrido un error!!</h1>
<NuxtLink to="/"> <i class="fas fa-home fa-2x"></i></NuxtLink>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: ['error'], props: ['error'],
layout: 'error' // you can set a custom layout for the error page //layout: 'error' // you can set a custom layout for the error page
} }
</script> </script>

View File

@@ -1,40 +0,0 @@
<template>
<auth-layout class="not-found-page">
<div class="centered">
<h1><i class="not-found-icon nc-icon nc-puzzle-10"></i>404</h1>
<p>The page you requested ccc could not be found.</p>
</div>
</auth-layout>
</template>
<script>
export default {
layout: 'error'
};
</script>
<style lang="scss">
.not-found-page {
.full-page > .content,
.centered {
min-height: calc(100vh - 160px);
}
.not-found-icon {
margin-right: 10px;
}
.centered {
h1,
i {
font-size: 50px;
}
p {
font-size: 20px;
}
display: flex;
padding-bottom: 150px;
flex-direction: column;
align-items: center;
justify-content: center;
color: white;
}
}
</style>

View File

@@ -1,14 +1,363 @@
<template> <template>
<h1>Creditos</h1> <div>
<card>
<div class="row">
<base-input class="col-6">
<select
class="form-control"
@change="onChange()"
v-model="selectedCreditoName"
>
<option v-for="Credito in Creditos">
{{ Credito.nombreCredito }}
</option>
</select>
</base-input>
<base-button
type="danger"
icon
size="sm"
v-if="selectedCredito.nombreCredito !== ''"
class="btn-link"
@click="deleteCredito()"
>
<i class="el-icon-delete-solid"></i>
</base-button>
<div class="row pull-right pull-buttom">
<div class="col-6">
<Fcredito
:newCredito="newCredito"
:saveCredito="saveCredito"
:isOpen="isOpen"
/>
</div>
</div>
</div>
</card>
<card v-if="selectedCredito.nombreCredito !== ''">
<table>
<tr>
<td><b>Credito:</b></td>
<td>
<span class="badge bg-Light">{{
selectedCredito.nombreCredito
}}</span>
</td>
</tr>
<tr>
<td><b>Valor Inicial:</b></td>
<td>
<span class="badge bg-Light">{{ formatMoneda(selectedCredito.valor) }}</span>
</td>
</tr>
<tr>
<td><b>Tasa Interés:</b></td>
<td>
<span class="badge bg-Light">{{ selectedCredito.tasa_interes }} %</span>
</td>
</tr>
</table>
</card>
<card title="Credito" v-if="selectedCredito.nombreCredito !== ''">
<div class="row">
<div class="col-8">
<el-table
:data="selectedCredito.datos"
border
empty-text="No hay items"
stripe
style="width: 100%"
height="300"
>
<el-TableColumn prop="fecha" label="Fecha" sortable>
</el-TableColumn>
<el-TableColumn prop="detalle" label="Detalle" sortable>
</el-TableColumn>
<el-TableColumn prop="valor" label="Valor" sortable>
</el-TableColumn>
<el-TableColumn prop="tipo" label="Tipo" sortable> </el-TableColumn>
<el-TableColumn>
<div slot-scope="{ row, $index }">
<el-tooltip content="Delete" effect="light">
<base-button
type="danger"
icon
size="sm"
class="btn-link"
@click="deleteItem(row._id)"
>
<i class="el-icon-delete-solid"></i>
</base-button>
</el-tooltip>
</div>
</el-TableColumn>
</el-table>
</div>
<div class="col-4">
<base-input
label="Fecha"
v-model="newItem.fecha"
type="Date"
required
></base-input>
<base-input v-model="newItem.detalle" label="Descripción">
</base-input>
<base-input v-model="newItem.valor" type="Number"> </base-input>
<base-input>
<select class="form-control" v-model="newItem.tipo">
<option>Cuota</option>
<option>Abono Capital</option>
</select>
</base-input>
<base-button
type="info"
class="mb-3 col-12"
size="lg"
@click="addItem()"
>Guardar</base-button
>
</div>
</div>
</card>
<card>
<div class="row">
<div class="col-4">
<b>Total Cuotas: </b> {{ formatMoneda(totalCuotas) }}
</div>
<div class="col-4">
<b>Total Abonos a Capital:</b> <span>{{ formatMoneda(totalAbonos) }} </span>
</div>
<div class="col-4">
<b
>Total:<span :class="[total < 0 ? 'text-danger' : 'text-success']">
{{ formatMoneda(total) }}</span
></b
>
</div>
</div>
</card>
</div>
</template> </template>
<script> <script>
export default { import { Table, TableColumn } from "element-ui";
middleware: "authenticated",
export default {
components: {
[Table.name]: Table,
[TableColumn.name]: TableColumn,
},
middleware: "authenticated",
data() {
return {
isOpen: false,
newCredito: {
nombreCredito: "",
valor: 0,
tasa_interes: 0.0,
},
selectedCredito: {
_id: "",
nombreCredito: "",
valor: 0,
tasa_interes: 0.0,
datos: [],
},
selectedCreditoName: "",
newItem: {
_id: "",
fecha:"",
detalle: "",
valor: 0,
tipo: "Cuota",
},
Creditos: [],
totalCuotas: 0,
totalAbonos: 0,
total: 0,
};
},
methods: {
saveCredito() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
};
this.newCredito.nombreCredito = this.newCredito.nombreCredito.trim();
const toSend = this.newCredito;
this.$axios
.post("/Credito", toSend, axiosHeader)
.then((res) => {
this.$notify({
type: "success",
icon: "tim-icons icon-check-2",
message: "Credito Creado",
});
this.isOpen = false;
this.getCredito();
})
.catch((e) => {
this.$notify({
type: "danger",
icon: "tim-icons icon-alert-circle-exc",
message: "El Credito ya existe :(",
});
return;
});
},
addItem() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
};
const toSend = this.newItem;
this.$axios
.put("/Credito", toSend, axiosHeader)
.then((res) => {
console.log(res.data.status);
this.getItems();
})
.catch((e) => console.log(e));
},
deleteItem(item_id) {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
params: {
idCredito: this.selectedCredito._id,
iditem: item_id,
},
};
this.$axios
.delete("/Creditoitem", axiosHeader)
.then((res) => {
this.getItems();
})
.catch((e) => console.log(e));
},
getItems() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
params: {
credito_id: this.selectedCredito._id,
},
};
this.$axios
.get("/Credito_items", axiosHeader)
.then((res) => {
this.selectedCredito.datos = res.data.data;
this.sumItems();
})
.catch((e) => console.log(e));
},
sumItems() {
this.totalCuotas = this.selectedCredito.datos.reduce(
(acc, x) => (x.tipo === "Cuota" ? acc + Number(x.valor) : acc),
0
);
this.totalAbonos = this.selectedCredito.datos.reduce(
(acc, x) => (x.tipo === "Abono Capital" ? acc + Number(x.valor) : acc),
0
);
this.total = this.totalCuotas + this.totalAbonos;
},
formatMoneda(dato) {
var num = dato;
if (!isNaN(num)) {
num = Math.abs(num)
.toString()
.split("")
.reverse()
.join("")
.replace(/(?=\d*\.?)(\d{3})/g, "$1.");
num = num.split("").reverse().join("").replace(/^[\.]/, "");
return `$ ${num}`;
} }
},
getCredito() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
limite: this.$store.state.filtro.nCredito,
},
};
this.$axios
.get("/Credito", axiosHeader)
.then((res) => {
this.Creditos = [];
if (res.data.data.length) {
this.Creditos = res.data.data;
this.selectedCredito = this.Creditos[0];
this.selectedCreditoName = this.selectedCredito.nombreCredito;
this.newItem._id = this.selectedCredito._id;
console.log(this.selectedCredito);
this.sumItems();
}
})
.catch((e) => console.log(e));
},
onChange() {
this.selectedCredito = this.Creditos.find(
(x) => x.nombreCredito === this.selectedCreditoName
);
this.newItem._id = this.selectedCredito._id;
this.sumItems();
},
deleteCredito() {
console.log(this.selectedCredito._id);
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
params: {
id: this.selectedCredito._id,
},
};
this.$axios
.delete("/Credito", axiosHeader)
.then((res) => {
console.log(res.data);
this.selectedCredito = {
_id: "",
nombreCredito: "",
datos: [],
};
this.selectedCreditoName = "";
this.getCredito();
})
.catch((e) => console.log(e));
},
},
mounted() {
this.getCredito();
this.newItem.fecha = this.$store.state.fecha;
},
};
</script> </script>
<style> <style>
</style> </style>

View File

@@ -87,10 +87,11 @@ export default {
this.user.email = ""; this.user.email = "";
}) })
.catch((e) => { .catch((e) => {
this.$notify({ this.$notify({
type: "danger", type: "danger",
icon: "tim-icons icon-alert-circle-exc", icon: "tim-icons icon-alert-circle-exc",
message: "User already exists :(", message: "No esta permitido la creaciøn de usuarios, o ya existe !!!",
}); });
}); });
}, },

View File

@@ -28,8 +28,10 @@ app.use('/api',require('./routes/users'));
app.use('/api',require('./routes/compras')) app.use('/api',require('./routes/compras'))
app.use('/api',require('./routes/ingresos')) app.use('/api',require('./routes/ingresos'))
app.use('/api',require('./routes/presupuesto')) app.use('/api',require('./routes/presupuesto'))
app.use('/api',require('./routes/creditos'))
app.use('/api',require('./routes/categorias')) app.use('/api',require('./routes/categorias'))
app.use('/api',require('./routes/metodos_pago')) app.use('/api',require('./routes/metodos_pago'))
app.use("*",(req,res)=>{res.redirect("/")})
app.disable('x-powered-by'); app.disable('x-powered-by');
module.exports = app; module.exports = app;

23
models/credito.js Executable file
View File

@@ -0,0 +1,23 @@
const mongoose = require('mongoose');
const {Schema} =mongoose;
const itemSchema = new Schema({
fecha:{type: String, required:true},
detalle:{type:String},
valor:{type:Number},
tipo:{type:String, required:true}
})
const CreditoSchema=new Schema({
date: {type: Date, default: Date.now},
nombreCredito: {type:String,required:true},
datos:[itemSchema],
valor: {type:Number, default:0},
tasa_interes:{type:Number, default:0},
user:{type:String, required:true},
child:itemSchema
});
module.exports.Credito=mongoose.model('creditos',CreditoSchema);
module.exports.itemCredito=mongoose.model('itemCredito',itemSchema);

114
routes/creditos.js Normal file
View File

@@ -0,0 +1,114 @@
const router = require("express").Router();
const Credito = require("../models/credito").Credito;
const itemCredito = require("../models/credito").itemCredito;
const { checkAuth } = require("../middlewares/authentication");
router.get("/credito", checkAuth, async (req, res) => {
var creditos;
let limite = req.get('limite');
creditos = await Credito.find({ user: req.userData._id }).sort({
date: "desc",
}).limit(parseInt(limite));
return res.send({
status: "ok",
data: creditos,
});
});
router.post("/credito", checkAuth, async (req, res) => {
const { nombreCredito,valor,tasa_interes } = req.body;
var creditos = await Credito.find({
user: req.userData._id,
nombreCredito: nombreCredito,
});
if (creditos.length == 0) {
const credito = new Credito({
nombreCredito: nombreCredito,
valor:valor,
tasa_interes:tasa_interes
});
credito.user = req.userData._id;
await credito.save();
return res.json({
status: "OK",
});
}
return res.status(500).json({
status: "FAIL",
});
});
router.delete("/credito", checkAuth, async (req, res) => {
try {
const userId = req.userData._id;
const id = req.query.id;
const resultado = await Credito.deleteOne({ user: userId, _id: id });
return res.json({ status: "ok", data: resultado });
} catch (error) {
console.log(error);
return res.status(500).json({ status: "fail", error: error });
}
});
router.put("/credito", checkAuth, async (req, res) => {
const { _id, fecha, detalle, valor, tipo } = req.body;
const credito_edit = await Credito.findOne({
_id: _id,
user: req.userData._id,
});
const itemP = new itemCredito({ fecha,detalle, valor, tipo });
credito_edit.datos.push(itemP);
await credito_edit.save();
res.json({
status: "OK",
});
});
router.get("/credito_items", checkAuth, async (req, res) => {
const _id = req.query.credito_id;
const credito_edit = await Credito.findOne({
_id: _id,
user: req.userData._id,
});
return res.json({
status: "OK",
data: credito_edit.datos,
});
});
router.delete("/creditoitem", checkAuth, async (req, res) => {
try {
const userId = req.userData._id;
const iditem = req.query.iditem;
const credito_id = req.query.idCredito;
var credito_edit = await Credito.findOne({
user: userId,
_id: credito_id,
});
console.log(credito_edit)
console.log("---------------")
credito_edit.datos.id(iditem).remove();
await credito_edit.save();
return res.json({ status: "ok" });
} catch (error) {
console.log(error);
return res.status(500).json({ status: "fail", error: error });
}
});
module.exports = router;

View File

@@ -2,10 +2,12 @@ const express = require("express");
const router = express.Router(); const router = express.Router();
const jwt = require("jsonwebtoken"); const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt"); const bcrypt = require("bcrypt");
const User = require("../models/user") const User = require("../models/user");
//import User from "../models/user.js"; //import User from "../models/user.js";
//AUTH //AUTH
if (process.env.REGISTER == "true") {
router.post("/register", async (req, res) => { router.post("/register", async (req, res) => {
const { name, email, password } = req.body; const { name, email, password } = req.body;
const passEncrypted = bcrypt.hashSync(password, 10); const passEncrypted = bcrypt.hashSync(password, 10);
@@ -37,19 +39,35 @@ router.post("/register", async (req, res) => {
.json({ status: "fail", error: `internal error:${error}` }); .json({ status: "fail", error: `internal error:${error}` });
} }
}); });
}
else{
router.post("/register", (req, res) => {
return res
.status(500)
.json({ status: "faill", error: `No tiene permitido crear usuarios nuevos` });
})
}
router.post("/login", async (req, res) => { router.post("/login", async (req, res) => {
const { email, password } = req.body; const { email, password } = req.body;
var user = await User.findOne({ email: email }); var user = await User.findOne({ email: email });
if (!user) { if (!user) {
res.status(401).json({ status: "fail", error: "Invalid credentials email" }); res
.status(401)
.json({ status: "fail", error: "Invalid credentials email" });
return; return;
} }
if (! await user.matchPassword(password)) { if (!(await user.matchPassword(password))) {
return res.status(401).json({ status: "fail", error: "Invalid credentials pass" }); return res
.status(401)
.json({ status: "fail", error: "Invalid credentials pass" });
} }
user.set("password", undefined, { strict: false }); user.set("password", undefined, { strict: false });
const token = jwt.sign( const token = jwt.sign(