Compare commits

..

10 Commits

Author SHA1 Message Date
1100a0fc08 pc 2025-04-05 13:05:42 -05:00
b4a5db028e ahorros 2022-10-02 08:03:49 -05:00
153f2da1f7 manejo de usuarios 2022-04-19 20:43:49 -05:00
a55f45cafd token expire, remove console 2021-08-24 20:08:42 -05:00
3b2a06b043 hummm .. 2021-08-14 09:02:48 -05:00
e170fe7f94 cambios readme 2021-07-31 21:49:24 -05:00
74b37c0dfe graficas highcharts 2021-07-30 23:56:33 -05:00
2db1144834 resumen 2021-07-27 19:21:05 -05:00
f84c170832 graficas 2021-07-27 18:46:14 -05:00
600358d640 no found 2021-06-22 20:45:25 -05:00
47 changed files with 2779 additions and 247 deletions

1
.gitignore vendored
View File

@@ -35,6 +35,7 @@ build/Release
# Dependency directories
node_modules/
uploads/
jspm_packages/
# Typescript v1 declaration files

View File

@@ -10,7 +10,7 @@ export default {
type: Array,
default: () => [
'rgba(72,72,176,0.2)',
'rgba(72,72,176,0.0)',
'rgba(72,72,176,0.1)',
'rgba(119,52,169,0)'
],
validator: val => {
@@ -35,14 +35,17 @@ export default {
if (!chartData) return;
const ctx =
this.ctx || document.getElementById(this.chartId).getContext('2d');
const gradientStroke = ctx.createLinearGradient(0, 230, 0, 50);
const gradientStroke = ctx.createLinearGradient(0, 230, 20, 50);
this.gradientStops.forEach((stop, index) => {
gradientStroke.addColorStop(stop, this.gradientColors[index]);
});
chartData.datasets.forEach(set => {
if (!set.backgroundColor) {
console.log(ctx)
set.backgroundColor = gradientStroke;
}
});

View File

@@ -0,0 +1,59 @@
import { Pie, mixins } from 'vue-chartjs';
export default {
name: 'pie-chart',
extends: Pie,
mixins: [mixins.reactiveProp],
props: {
extraOptions: Object,
gradientColors: {
type: Array,
default: () => [
'rgba(72,72,176,0.2)',
'rgba(72,72,176,0.1)',
'rgba(119,52,169,0)'
],
validator: val => {
return val.length > 1;
}
},
gradientStops: {
type: Array,
default: () => [1, 0.4, 0],
validator: val => {
return val.length > 1;
}
}
},
data() {
return {
ctx: null
};
},
methods: {
updateGradients(chartData) {
if (!chartData) return;
const ctx =
this.ctx || document.getElementById(this.chartId).getContext('2d');
const colors=["0xFF0000","0xFFFF00"]
chartData.datasets.forEach(set => {
if (!set.backgroundColor) {
set.backgroundColor = "rgba(119,52,169,1)";
}
});
}
},
mounted() {
this.$watch(
'chartData',
(newVal, oldVal) => {
this.updateGradients(newVal);
if (!oldVal) {
this.renderChart(this.chartData, this.extraOptions);
}
},
{ immediate: true }
);
}
};

View File

@@ -342,7 +342,8 @@ export let barChartOptions = {
xPadding: 12,
mode: 'nearest',
intersect: 0,
position: 'nearest'
position: 'nearest',
},
scales: {
yAxes: [

View File

@@ -0,0 +1,191 @@
export var chartOptions = {
credits: {
enabled: false
},
chart: {
renderTo: "container",
defaultSeriesType: "column",
backgroundColor: "rgba(0,0,0,0)"
},
xAxis: {
categories: [],
crosshair: true
},
yAxis: {
title: {
text: ""
},
labels: {
style: {
color: "#d4d2d2",
font: "11px Trebuchet MS, Verdana, sans-serif"
}
}
},
legend: {
itemStyle: {
color: "#d4d2d2"
}
},
tooltip: {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat:
'<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.0f} pesos</b></td></tr>',
footerFormat: "</table>",
shared: true,
useHTML: true
},
responsive: {
rules: [
{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
layout: "horizontal",
align: "center",
verticalAlign: "bottom"
}
}
}
]
}
};
export var pieOptions={
chart: {
renderTo: "container",
defaultSeriesType: "pie",
//backgroundColor: "rgba(255,0,0,)"
},
xAxis: {
categories: [],
crosshair: true
},
credits: {
enabled: false
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
};
export var ingresosvscomprasOptions = {
chart: {
renderTo: "container",
defaultSeriesType: "bar",
backgroundColor: "rgba(0,0,0,0)"
},
title: {
text: "Gastos Vs Ingresos"
},
plotOptions: {
bar: {
grouping: false,
shadow: false,
borderWidth: 0.5
},
},
legend: {
shadow: true
},
credits: {
enabled: false
},
xAxis: {
categories: [""],
crosshair: false
},
yAxis: [
{
min: 0,
title: {
text: "Pesos"
}
}
],
series: [
{
name: "Ingresos",
color: "rgba(0,80,200,.5)",
data: [150],
pointPadding: 0.25,
pointPlacement: -0.2
},
{
name: "Gastos",
color: "rgba(165,0,217,1)",
data: [120],
pointPadding: 0.3,
pointPlacement: -0.2
}
]
};
export var ingresosvsegresosOptions = {
chart: {
renderTo: "container",
defaultSeriesType: "bar",
backgroundColor: "rgba(0,0,0,0)"
},
title: {
text: ""
},
plotOptions: {
bar: {
grouping: false,
shadow: false,
borderWidth: 0.5
},
},
legend: {
shadow: false
},
credits: {
enabled: false
},
xAxis: {
categories: [""],
crosshair: false
},
yAxis: [
{
min: 0,
title: {
text: "Pesos"
}
}
],
series: [
{
name: "Ingresos",
color: "rgba(0,80,200,.5)",
data: [],
pointPadding: 0.25,
pointPlacement: -0.2
},
{
name: "Egresos",
color: "rgba(165,0,217,1)",
data: [],
pointPadding: 0.3,
pointPlacement: -0.2
}
]
};

View File

@@ -0,0 +1,69 @@
<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>
<template slot="header">
<img src="img//card-info.png" alt="" />
</template>
<base-input
label="Nombre Ahorro"
v-model="newAhorro.nombreAhorro"
></base-input>
<base-input
label="Descripción Ahorro"
v-model="newAhorro.detalleAhorro"
></base-input>
<base-button
type="info"
class="mb-3 col-12"
size="lg"
@click="saveAhorro()"
>Guardar</base-button
>
</card>
</span>
</div>
<!-- </div> -->
</template>
<script>
export default {
name: "Fahorro",
props: ["newAhorro", "saveAhorro","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

@@ -70,13 +70,14 @@ export default {
props: ["categorias", "metodos_pago", "newCompra", "saveCompra","isUpdate","updateCompra"],
data() {
return {
isOpen: false
isOpen: this.openForm
};
},
methods: {
toggleDropDown() {
this.isOpen = !this.isOpen;
},
closeDropDown() {
this.isOpen = false;
},

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

@@ -59,7 +59,7 @@
<template
slot="title"
>
<div class="photo"><img src="img/mdchaparror.png" /></div>
<div class="photo"><img :src=this.$store.state.auth.userData.image.secure_url /></div>
<b class="caret d-none d-lg-block d-xl-block"></b>
<p class="d-lg-none">Log out</p>
</template>
@@ -125,13 +125,15 @@ export default {
this.showMenu = !this.showMenu;
},
salir(){
localStorage.clear('auth');
this.$notify({
type: "danger",
icon: "tim-icons icon-alert-circle-exc",
message: "Sesión cerrada"
});
$nuxt.$router.push('/login');
this.$store.dispatch("salir");
}
}
};

View File

@@ -1,7 +0,0 @@
# COMPONENTS
**This directory is not required, you can delete it if you don't want to use it.**
The components directory contains your Vue.js Components.
_Nuxt.js doesn't supercharge these components._

View File

@@ -31,6 +31,15 @@
path: '/presupuesto',
}"
>
</sidebar-item>
<sidebar-item
:link="{
name: 'Ahorros',
icon: 'tim-icons icon-money-coins',
path: '/ahorros',
}"
>
</sidebar-item>
<sidebar-item
@@ -58,6 +67,17 @@
}"
>
</sidebar-item>
<sidebar-item
:link="{
name: 'Usuarios',
icon: 'tim-icons icon-single-02',
path: '/users',
}"
>
</sidebar-item>
</template>
</side-bar>
<!--Share plugin (for demo purposes). You can remove it if don't plan on using it-->

View File

@@ -1,14 +1,12 @@
<template>
<div>
<h1 v-if="error.statusCode === 404">Página no encontrada</h1>
<h1 v-else> !!Ha ocurrido un error!!</h1>
<NuxtLink to="/"> <i class="fas fa-home fa-2x"></i></NuxtLink>
<h1>Página no encontrada</h1>
</div>
</template>
<script>
export default {
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>

View File

@@ -0,0 +1,11 @@
//If the user does not have a token, we send it to login
//si el usuario no tiene token lo enviamos a login
export default function({ store, redirect }) {
if (store.state.auth.userData.role !="ADMIN") {
return redirect("/compras");
}
}

View File

@@ -53,15 +53,16 @@ export default {
'@nuxtjs/pwa',
'@nuxtjs/axios',
'nuxt-highcharts',
],
// Axios module configuration (https://go.nuxtjs.dev/config-axios)
axios: {
//baseURL: "http://192.168.1.111:4000/api"
// baseURL:"http://localhost:4000/api"
baseURL:"https://finanzasm.herokuapp.com/api"
baseURL: "http://192.168.1.11:4000/api"
// baseURL:process.env.BASE_URL
// baseURL:"https://finanzasm.fly.dev/api"
},
/*

8
APP/package-lock.json generated
View File

@@ -8004,12 +8004,12 @@
}
},
"nuxt-highcharts": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nuxt-highcharts/-/nuxt-highcharts-1.0.5.tgz",
"integrity": "sha512-HSByt6Q7Ww3X0pRs4XLbtDBXwE55zBFK0KcPoUc58xF/n+sVNP9UMpTeNd2iJcd1dJqvq2vKB5PhySLpAq9bfg==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/nuxt-highcharts/-/nuxt-highcharts-1.0.7.tgz",
"integrity": "sha512-LJ3PrjnGwS0nAQ8vQYFncsRWQVL1D3QKadbSbruks+8U5uLk5deAcNF4+WNlUfCAXkVk+TKhI2J+MTZ+7ouPZw==",
"requires": {
"@highcharts/map-collection": "^1.1.3",
"highcharts": "^8.1.0"
"highcharts": "^8.2.2"
}
},
"oauth-sign": {

View File

@@ -13,7 +13,7 @@
"@nuxtjs/axios": "^5.12.2",
"@nuxtjs/pwa": "^3.2.2",
"bootstrap": "4.3.1",
"chart.js": "^2.7.1",
"chart.js": "^2.9.4",
"cookieparser": "^0.1.0",
"core-js": "^3.7.0",
"cors": "^2.8.5",
@@ -24,7 +24,7 @@
"fuse.js": "^3.2.0",
"js-cookie": "^2.2.1",
"nuxt": "^2.14.7",
"nuxt-highcharts": "^1.0.3",
"nuxt-highcharts": "^1.0.7",
"perfect-scrollbar": "^1.3.0",
"register-service-worker": "^1.5.2",
"tween.js": "^16.6.0",

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,6 +0,0 @@
# PAGES
This directory contains your Application Views and Routes.
The framework reads all the `*.vue` files inside this directory and creates the router of your application.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing).

348
APP/pages/ahorros.vue Normal file
View File

@@ -0,0 +1,348 @@
<template>
<div>
<card>
<div class="row">
<base-input class="col-6">
<select
class="form-control"
@change="onChange()"
v-model="selectedAhorroName"
>
<option v-for="ahorro in ahorros">
{{ ahorro.nombreAhorro }}
</option>
</select>
</base-input>
<base-button
type="danger"
icon
size="sm"
v-if="selectedAhorro.nombreAhorro !== ''"
class="btn-link"
@click="deleteAhorro()"
>
<i class="el-icon-delete-solid"></i>
</base-button>
<div class="pull-right pull-buttom col-4">
<div class="col-12">
<Fahorro
:newAhorro="newAhorro"
:saveAhorro="saveAhorro"
:isOpen="isOpen"
/>
</div>
</div>
</div>
</card>
<card v-if="selectedAhorro.nombreAhorro !== ''">
<table>
<tr>
<td>
<span class="badge bg-Light">{{
selectedAhorro.nombreAhorro
}}</span>
</td>
</tr>
<tr>
<td>
<span class="badge bg-Light">{{
selectedAhorro.detalleAhorro
}}</span>
</td>
</tr>
</table>
</card>
<card v-if="selectedAhorro.nombreAhorro !== ''">
<div class="row">
<div class="col-8">
<el-table
:data="selectedAhorro.datos"
border
empty-text="No hay items"
stripe
style="width: 100%"
height="300"
>
<el-TableColumn prop="detalle" label="Detalle" sortable>
</el-TableColumn>
<el-TableColumn
prop="valor"
label="Valor"
sortable
:formatter="cell"
>
</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 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>Aporte</option>
<option>Retiro</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>Aportes: </b> {{ formatMoneda(totalAportes) }}
</div>
<div class="col-4">
<b>Retiros:</b> <span>{{ formatMoneda(totalRetiros) }} </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>
<script>
import { Table, TableColumn } from "element-ui";
export default {
components: {
[Table.name]: Table,
[TableColumn.name]: TableColumn,
},
middleware: "authenticated",
data() {
return {
isOpen: false,
newAhorro: {
nombreAhorro: "",
detalleAhorro: "",
},
selectedAhorro: {
_id: "",
nombreAhorro: "",
detalleAhorro: "",
datos: [],
},
selectedAhorroName: "",
newItem: {
_id: "",
detalle: "",
valor: 0,
tipo: "Aporte",
},
ahorros: [],
totalAportes: 0,
totalRetiros: 0,
total: 0,
};
},
methods: {
cell(row, column, cellValue, index) {
return this.formatMoneda(cellValue);
},
saveAhorro() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
};
this.newAhorro.nombreAhorro = this.newAhorro.nombreAhorro.trim();
const toSend = this.newAhorro;
this.$axios
.post("/ahorro", toSend, axiosHeader)
.then((res) => {
this.$notify({
type: "success",
icon: "tim-icons icon-check-2",
message: "Ahorro Creado",
});
this.isOpen = false;
this.getAhorro();
})
.catch((e) => {
this.$notify({
type: "danger",
icon: "tim-icons icon-alert-circle-exc",
message: "El ahorro ya existe :(",
});
return;
});
},
addItem() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
};
const toSend = this.newItem;
this.$axios
.put("/Ahorro", toSend, axiosHeader)
.then((res) => {
this.getItems();
})
.catch((e) => console.log(e));
},
deleteItem(item_id) {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
params: {
idAhorro: this.selectedAhorro._id,
iditem: item_id,
},
};
this.$axios
.delete("/ahorroitem", axiosHeader)
.then((res) => {
this.getItems();
})
.catch((e) => console.log(e));
},
getItems() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
params: {
ahorro_id: this.selectedAhorro._id,
},
};
this.$axios
.get("/ahorro_items", axiosHeader)
.then((res) => {
this.selectedAhorro.datos = res.data.data;
this.sumItems();
})
.catch((e) => console.log(e));
},
sumItems() {
this.totalAportes = this.selectedAhorro.datos.reduce(
(acc, x) => (x.tipo === "Aporte" ? acc + Number(x.valor) : acc),
0
);
this.totalRetiros = this.selectedAhorro.datos.reduce(
(acc, x) => (x.tipo === "Retiro" ? acc + Number(x.valor) : acc),
0
);
this.total = this.totalAportes - this.totalRetiros;
},
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}`;
}
},
getAhorro() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
limite: this.$store.state.filtro.nahorro,
},
};
this.$axios
.get("/ahorro", axiosHeader)
.then((res) => {
this.ahorros = [];
if (res.data.data.length) {
this.ahorros = res.data.data;
this.selectedAhorro = this.ahorros[0];
this.selectedAhorroName = this.selectedAhorro.nombreAhorro;
this.newItem._id = this.selectedAhorro._id;
this.sumItems();
}
})
.catch((e) => console.log(e));
},
onChange() {
this.selectedAhorro = this.ahorros.find(
(x) => x.nombreAhorro === this.selectedAhorroName
);
this.newItem._id = this.selectedAhorro._id;
this.sumItems();
},
deleteAhorro() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
params: {
id: this.selectedAhorro._id,
},
};
this.$axios
.delete("/ahorro", axiosHeader)
.then((res) => {
this.selectedAhorro = {
_id: "",
nombreAhorro: "",
datos: [],
};
this.selectedAhorroName = "";
this.getAhorro();
})
.catch((e) => console.log(e));
},
},
mounted() {
this.getAhorro();
},
watch: {
data() {
this.sumItems();
},
},
};
</script>
<style>
</style>

View File

@@ -76,7 +76,10 @@
:updateCompra="updateCompra"
:isUpdate="isUpdate"
/>
</div>
</div>
</template>
@@ -98,7 +101,8 @@ export default {
detalle: "",
valor: 0,
metodopago: "",
categoria: "",
categoria: ""
},
compras: [],
search: "",
@@ -106,23 +110,20 @@ export default {
categorias: [],
isUpdate: false,
openForm: false ,
isOpen: false,
};
},
mounted() {
async mounted() {
// this.$store.dispatch("getCategorias");
//this.$store.dispatch("getMetodos");
await this.$store.dispatch("getCategorias");
await this.$store.dispatch("getMetodos");
this.newCompra.fecha = this.$store.state.fecha;
this.categorias = this.$store.state.categorias;
this.metodos_pago = this.$store.state.metodos_de_pago;
this.getCompras();
},
@@ -140,7 +141,6 @@ export default {
this.$axios
.get("/compras", axiosHeader)
.then((res) => {
console.log(res.data.data);
this.compras = res.data.data;
})
.catch((e) => console.log(e));
@@ -155,12 +155,11 @@ export default {
},
};
const toSend = this.newCompra;
console.log(axiosHeader.data);
this.$axios
.post("/compra", toSend, axiosHeader)
.then((res) => {
this.clearFormCompra();
console.log(res.data.status);
this.getCompras();
})
.catch((e) => console.log(e));
@@ -172,12 +171,10 @@ export default {
},
};
const toSend = this.newCompra;
console.log(axiosHeader.data);
this.$axios
.put("/compra", toSend, axiosHeader)
.then((res) => {
this.clearFormCompra();
console.log(res.data.status);
this.getCompras();
})
.catch((e) => console.log(e));
@@ -187,7 +184,8 @@ export default {
var reg_edit = this.compras.filter((ic) => ic._id===id)[0];
this.newCompra = JSON.parse(JSON.stringify(reg_edit));
this.openForm = true;
console.log(reg_edit)
},
deleteCompra(id) {
@@ -202,7 +200,6 @@ export default {
this.$axios
.delete("/compra", axiosHeader)
.then((res) => {
console.log(res.data);
this.getCompras();
this.clearFormCompra();
})
@@ -218,7 +215,6 @@ export default {
},
getIcon(row, column, cellValue, index) {
const found = this.$store.state.categorias.filter((ic) => ic.name === cellValue)[0];
//console.log(found);
return `<i class="${found.icon}"></i>${cellValue}`
},

View File

@@ -1,9 +1,18 @@
<template>
<div>
<card title='Filtro general'>
<card title="Filtro general">
<base-input label="Filtro de fechas" v-model="filtro.fechas"></base-input>
<base-input label="Número de presupuestos" type="number" v-model="filtro.npresupuesto"></base-input>
<base-button @click='guardarFiltro()' type="info">Guardar</base-button>
<base-input
label="Número de presupuestos"
type="number"
v-model="filtro.npresupuesto"
></base-input>
<base-input
label="Número de ahorros"
type="number"
v-model="filtro.nahorro"
></base-input>
<base-button @click="guardarFiltro()" type="info">Guardar</base-button>
</card>
<div class="row">
<card title="Categorias">
@@ -37,14 +46,12 @@
</div>
<div class="col-4">
<form>
<base-input
type="text"
placeholder="Nombre de categoria"
v-model="newCategoria.name"
/>
<base-input>
<select class="form-control" v-model="newCategoria.icon">
<option v-for="icono in iconos">
@@ -100,7 +107,10 @@
</div>
<div class="col-4">
<form>
<base-input placeholder="Nombre pago" v-model="newMetodo.name"></base-input>
<base-input
placeholder="Nombre pago"
v-model="newMetodo.name"
></base-input>
<base-input>
<select class="form-control" v-model="newMetodo.icon">
<option v-for="icono in iconos">
@@ -137,7 +147,7 @@ export default {
mounted() {
this.getCategorias();
this.getMetodos();
this.filtro=this.$store.state.filtro
this.filtro = JSON.parse(JSON.stringify(this.$store.state.filtro));
},
data() {
return {
@@ -184,14 +194,15 @@ export default {
categorias: [],
metodos: [],
filtro: {
fechas:this.$store.state.filtro.fechas,
npresupuesto:this.$store.state.filtro.npresupuesto
}
fechas: "",
npresupuesto: 0,
nahorro: 0
},
};
},
methods: {
guardarFiltro() {
this.$store.commit("actualizarFiltro",this.filtro)
this.$store.commit("actualizarFiltro", this.filtro);
},
enviarCategoria() {
const axiosHeader = {
@@ -204,7 +215,6 @@ export default {
this.$axios
.post("/categoria", toSend, axiosHeader)
.then((res) => {
console.log(res);
this.getCategorias();
})
.catch((e) => {
@@ -213,7 +223,6 @@ export default {
icon: "tim-icons icon-alert-circle-exc",
message: JSON.parse(e.request.response).error,
});
console.log(e.request.responseText);
});
},
@@ -226,7 +235,6 @@ export default {
this.$axios
.get("/categoria", axiosHeader)
.then((res) => {
console.log(res.data.data);
this.categorias = res.data.data;
this.$store.commit("setCategorias", this.categorias);
})
@@ -244,7 +252,6 @@ export default {
this.$axios
.delete("/categoria", axiosHeader)
.then((res) => {
console.log(res.data);
this.getCategorias();
})
.catch((e) => {
@@ -262,7 +269,6 @@ export default {
this.$axios
.post("/metodo", toSend, axiosHeader)
.then((res) => {
console.log(res);
this.getMetodos();
})
.catch((e) => {
@@ -271,7 +277,6 @@ export default {
icon: "tim-icons icon-alert-circle-exc",
message: JSON.parse(e.request.response).error,
});
console.log(e.request.responseText);
});
},
@@ -284,7 +289,6 @@ export default {
this.$axios
.get("/metodo", axiosHeader)
.then((res) => {
console.log(res.data.data);
this.metodos = res.data.data;
this.$store.commit("setMetodos", this.metodos);
})
@@ -302,7 +306,6 @@ export default {
this.$axios
.delete("/metodo", axiosHeader)
.then((res) => {
console.log(res.data);
this.getMetodos();
})
.catch((e) => {

View File

@@ -1,14 +1,371 @@
<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="pull-right pull-buttom col-4">
<div class="col-12">
<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 :formatter="cell">
</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>
<option>Intereses</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-3">
<b>Total Cuotas: </b> {{ formatMoneda(totalCuotas) }}
</div>
<div class="col-3">
<b>Total Abonos a Capital:</b> <span>{{ formatMoneda(totalAbonos) }} </span>
</div>
<div class="col-3">
<b>Total Intereses:</b> <span>{{ formatMoneda(totalIntereses) }} </span>
</div>
<div class="col-3">
<b
>Total:<span :class="[total < 0 ? 'text-danger' : 'text-success']">
{{ formatMoneda(total) }}</span
></b
>
</div>
</div>
</card>
</div>
</template>
<script>
export default {
middleware: "authenticated",
import { Table, TableColumn } from "element-ui";
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,
totalIntereses: 0,
total: 0,
};
},
methods: {
cell(row, column, cellValue, index) {
return this.formatMoneda(cellValue);
},
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) => {
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.totalIntereses = this.selectedCredito.datos.reduce(
(acc, x) => (x.tipo === "Intereses" ? acc + Number(x.valor) : acc),
0
);
this.total = this.totalCuotas + this.totalAbonos + this.totalIntereses;
},
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;
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() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
params: {
id: this.selectedCredito._id,
},
};
this.$axios
.delete("/Credito", axiosHeader)
.then((res) => {
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>
<style>
</style>

View File

@@ -115,7 +115,6 @@ export default {
this.$axios
.get("/ingreso", axiosHeader)
.then((res) => {
console.log(res.data.data);
this.ingresos = res.data.data;
})
.catch((e) => console.log(e));
@@ -130,12 +129,10 @@ export default {
},
};
const toSend = this.newIngreso;
console.log(axiosHeader.data);
this.$axios
.post("/ingreso", toSend, axiosHeader)
.then((res) => {
this.clearFormIngreso();
console.log(res.data.status);
this.getIngresos();
})
.catch((e) => console.log(e));
@@ -147,12 +144,10 @@ export default {
},
};
const toSend = this.newIngreso;
console.log(axiosHeader.data);
this.$axios
.put("/ingreso", toSend, axiosHeader)
.then((res) => {
this.clearFormIngreso();
console.log(res.data.status);
this.getIngresos();
})
.catch((e) => console.log(e));
@@ -176,7 +171,6 @@ export default {
this.$axios
.delete("/ingreso", axiosHeader)
.then((res) => {
console.log(res.data);
this.getIngresos();
this.clearFormIngreso();
})

View File

@@ -71,7 +71,6 @@ export default {
icon: "tim-icons icon-check-2",
message: "Success! Welcome " + res.data.userData.name
});
console.log(res.data)
const auth = {
token: res.data.token,
userData: res.data.userData

View File

@@ -25,7 +25,7 @@
<i class="el-icon-delete-solid"></i>
</base-button>
<div class="row pull-right pull-buttom">
<div class="pull-right pull-buttom col-4">
<div class="col-12">
<Fpresupuesto
:newPresupuesto="newPresupuesto"
@@ -53,7 +53,7 @@
<el-TableColumn prop="detalle" label="Detalle" sortable>
</el-TableColumn>
<el-TableColumn prop="valor" label="Valor" sortable>
<el-TableColumn prop="valor" label="Valor" sortable :formatter="cell">
</el-TableColumn>
<el-TableColumn prop="tipo" label="Tipo" sortable> </el-TableColumn>
@@ -84,6 +84,7 @@
<select class="form-control" v-model="newItem.tipo">
<option>Ingreso</option>
<option>Egreso</option>
<option>Otrao</option>
</select>
</base-input>
<base-button
@@ -119,9 +120,9 @@
<script>
import { Table, TableColumn } from "element-ui";
export default {
components: {
[Table.name]: Table,
[TableColumn.name]: TableColumn,
},
@@ -153,6 +154,9 @@ export default {
};
},
methods: {
cell(row, column, cellValue, index) {
return this.formatMoneda(cellValue);
},
savePresupuesto() {
const axiosHeader = {
headers: {
@@ -192,7 +196,6 @@ export default {
this.$axios
.put("/presupuesto", toSend, axiosHeader)
.then((res) => {
console.log(res.data.status);
this.getItems();
})
.catch((e) => console.log(e));
@@ -243,6 +246,7 @@ export default {
0
);
this.total = this.totalIngresos - this.totalEgresos;
},
formatMoneda(dato) {
var num = dato;
@@ -274,7 +278,7 @@ export default {
this.selectedPresupuesto = this.presupuestos[0];
this.selectedPresupuestoName = this.selectedPresupuesto.nombrePresupuesto;
this.newItem._id = this.selectedPresupuesto._id;
console.log(this.selectedPresupuesto);
this.sumItems();
}
})
@@ -288,7 +292,7 @@ export default {
this.sumItems();
},
deletePresupuesto() {
console.log(this.selectedPresupuesto._id);
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
@@ -300,7 +304,6 @@ export default {
this.$axios
.delete("/presupuesto", axiosHeader)
.then((res) => {
console.log(res.data);
this.selectedPresupuesto = {
_id: "",
@@ -316,6 +319,10 @@ export default {
mounted() {
this.getPresupuesto();
},
watch:{
data(){this.sumItems()}
}
};
</script>

View File

@@ -60,6 +60,7 @@
</template>
<script>
export default {
middleware: "notAuthenticated",
layout: "auth",
data() {
@@ -71,10 +72,19 @@ export default {
},
};
},
created() {
$nuxt.$router.push("/login")
},
methods: {
register() {
let formData = new FormData();
formData.append("user", JSON.stringify(this.user));
this.$axios
.post("/register", this.user)
.post("/register", formData,{
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => {
this.$notify({
type: "success",
@@ -87,10 +97,11 @@ export default {
this.user.email = "";
})
.catch((e) => {
this.$notify({
type: "danger",
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

@@ -1,14 +1,207 @@
<template>
<h1>Resumen</h1>
<div>
<h1>Resumen Mensual</h1>
<card>
<div class="row">
<Badge type="info" class="col-4 p-1 rounded-pill"
>Total Ingresos: <br /><b>{{ formatMoneda(ingresos) }}</b></Badge
>
<Badge type="primary" class="col-4 p-1 rounded-pill"
>Total Gastos: <br /><b>{{ formatMoneda(compras) }}</b></Badge
>
<Badge :type="[(ingresos - compras) < 0 ? 'danger' :'success']" class="col-4 p-1 rounded-pill"
>Saldo: <br /><b>{{ formatMoneda(ingresos - compras) }}</b></Badge
>
</div>
<div class="chart-area" style="height: 300px">
<highchart
style="height: 100%"
v-if="isMounted"
:options="ingresosVscompras"
/>
</div>
</card>
<card>
<div class="chart-area" style="height: 300px">
<highchart
style="height: 100%"
v-if="isMounted"
:options="comprasChart"
/>
</div>
</card>
<card>
<div class="chart-area">
<highchart
style="height: 100%"
v-if="isMounted"
:options="metodosChart"
/>
</div>
</card>
<card>
<card-tittle>Bolsillos</card-tittle>
</card>
</div>
</template>
<script>
import * as configPlot from "@/components/Charts/config_plots";
import config from "@/config";
export default {
name: "dashboard",
middleware: "authenticated",
data() {
return {
isMounted: false,
comprasChart: {
...configPlot.chartOptions,
title: {
text: "Gastos por categoría",
},
series: [],
},
ingresosVscompras: {
...configPlot.ingresosvscomprasOptions,
},
metodosChart: {
...configPlot.pieOptions,
title: {
text: "Métodos de pago",
},
series: [
{
data: [],
},
],
},
ingresos: 1000,
compras: 1000,
};
},
methods: {
formatMoneda(dato) {
var num = dato;
if (!isNaN(num)) {
num = num
.toString()
.split("")
.reverse()
.join("")
.replace(/(?=\d*\.?)(\d{3})/g, "$1.");
num = num.split("").reverse().join("").replace(/^[\.]/, "");
//return '$' +num;
return `$ ${num}`;
}
},
getCompras() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
filtro: this.$store.state.filtro.fechas,
},
};
this.$axios
.get("/resumen_compras", axiosHeader)
.then((res) => {
//console.log(res.data.data);
this.compras = res.data.data;
this.ingresosVscompras.series[1].data[0] = this.compras;
})
.catch((e) => console.log(e));
},
getIngresos() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
filtro: this.$store.state.filtro.fechas,
},
};
this.$axios
.get("/resumen_ingresos", axiosHeader)
.then((res) => {
// console.log(res.data.data);
this.ingresos = res.data.data;
this.ingresosVscompras.series[0].data[0] = this.ingresos;
if (this.compras / this.ingresos > 0.8) {
this.ingresosVscompras.chart.backgroundColor = "rgba(150,0,0,0.4)";
} else {
this.ingresosVscompras.chart.backgroundColor = "rgba(0,0,0,0)";
}
})
.catch((e) => console.log(e));
},
async getResumenCategorias() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
filtro: this.$store.state.filtro.fechas,
},
};
await this.$axios
.get("/resumen_categorias", axiosHeader)
.then((res) => {
let categorias = res.data.labels;
let valores = res.data.datos;
this.comprasChart.xAxis.categories = categorias;
this.comprasChart.series = [{ name: "", data: valores }];
})
.catch((e) => console.log(e));
},
async getResumenMetodos() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
filtro: this.$store.state.filtro.fechas,
},
};
await this.$axios
.get("/resumen_metodos", axiosHeader)
.then((res) => {
let metodos = res.data.labels;
let valores = res.data.datos;
//this.metodosChart.xAxis.categories =metodos;
var series = [];
for (var i = 0; i < metodos.length; i++) {
var serie = {
name: metodos[i],
y: valores[i],
};
series.push(serie);
}
//console.log(series);
this.metodosChart.series = [{ name: "", data: series }];
})
.catch((e) => console.log(e));
},
},
async mounted() {
await this.getCompras();
await this.getIngresos();
await this.getResumenCategorias();
await this.getResumenMetodos();
this.isMounted = true;
},
};
</script>
<style>
</style>

218
APP/pages/users.vue Normal file
View File

@@ -0,0 +1,218 @@
<template>
<div>
<card class="col-12">
<el-table
:data="Users"
border
empty-text="No hay Ingresos registrados"
stripe
style="width: 100%"
>
<el-TableColumn type="expand">
<template slot-scope="props">
<p>Nombre: {{ props.row.name }}</p>
<p>Correo: {{ props.row.email }}</p>
<p>Permisos: {{ props.row.role }}</p>
<div class="imagen"><img :src=props.row.image.secure_url width="200" height="200" /></div>
</template>
</el-TableColumn>
<el-TableColumn prop="name" label="Nombre" sortable></el-TableColumn>
<el-TableColumn prop="email" label="Correo" sortable></el-TableColumn>
<el-TableColumn prop="role" label="Permisos" sortable></el-TableColumn>
<el-TableColumn fixed="right">
<div slot-scope="{ row, $index }">
<el-tooltip content="Delete" effect="light">
<base-button
type="danger"
icon
size="sm"
class="btn-link"
@click="deleteUser(row._id)"
>
<i class="el-icon-delete-solid"></i>
</base-button>
</el-tooltip>
</div>
</el-TableColumn>
</el-table>
</card>
<card class="card-login card-white">
<template slot="header">
<h1 class="card-title">Nuevo usuario </h1>
</template>
<div>
<base-input
name="name"
v-model="user.name"
placeholder="Name"
addon-left-icon="tim-icons icon-badge"
required
>
</base-input>
<base-input
name="email"
v-model="user.email"
placeholder="Email"
addon-left-icon="tim-icons icon-email-85"
>
</base-input>
<base-input
name="password"
v-model="user.password"
type="password"
placeholder="Password"
addon-left-icon="tim-icons icon-lock-circle"
>
</base-input>
<base-input>
<select class="form-control" v-model="user.role">
<option>USER</option>
<option>ADMIN</option>
</select>
</base-input>
<input ref="upload"
type="file"
name="file-upload"
multiple=""
accept="image/jpeg, image/png"
@change="handleFileUpload( $event )">
</div>
<div slot="footer">
<base-button
native-type="submit"
type="info"
class="mb-3"
size="lg"
@click="register()"
block
>
Register
</base-button>
</div>
</card>
</div>
</div>
</template>
<script>
import { Table, TableColumn } from "element-ui";
import { Select, Option } from "element-ui";
export default {
middleware: ["authenticated","authenticatedAdmin"],
components: {
[Table.name]: Table,
[TableColumn.name]: TableColumn,
[Option.name]: Option,
[Select.name]: Select,
},
//layout: "auth",
data() {
return {
user: {
name: "",
email: "",
password: "",
role:"USER",
files: "",
},
file: "",
Users: [],
};
},
mounted() {
this.getUsers();
},
methods: {
handleFileUpload(event) {
this.user.files = event.target.files[0];
},
getUsers() {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
};
this.$axios
.get("/users", axiosHeader)
.then((res) => {
this.Users = res.data.data;
})
.catch((e) => console.log(e));
},
register() {
let formData = new FormData();
formData.append("File", this.user.files);
this.user.files = "";
formData.append("user", JSON.stringify(this.user));
this.$axios
.post("/register", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => {
this.$notify({
type: "success",
icon: "tim-icons icon-check-2",
message: "Success! Now you can login...",
});
this.user.name = "";
this.user.password = "";
this.user.email = "";
this.user.role="USER"
this.getUsers();
})
.catch((e) => {
this.$notify({
type: "danger",
icon: "tim-icons icon-alert-circle-exc",
message:
"No esta permitido la creaciøn de usuarios, o ya existe !!!",
});
});
},
deleteUser(id) {
const axiosHeader = {
headers: {
token: this.$store.state.auth.token,
},
params: {
id: id,
},
};
this.$axios
.delete("/user", axiosHeader)
.then((res) => {
this.getUsers();
})
.catch((e) => console.log(e));
},
},
};
</script>
<style>
</style>

View File

@@ -1,7 +1,7 @@
export const state = () => ({
auth: null,
notifications: [],
filtro: {fechas:fechaString().slice(0, 7),npresupuesto:5},
filtro: { fechas: fechaString().slice(0, 7), npresupuesto: 5,nahorro:20 },
fecha: fechaString(),
categorias: [],
metodos_de_pago: []
@@ -24,9 +24,7 @@ export const mutations = {
state.metodos_de_pago = metodos;
},
actualizarFiltro(state, filtro) {
state.filtro=filtro
state.filtro = filtro;
}
};
@@ -34,8 +32,8 @@ function fechaString() {
let data = new Date();
let year = data.getFullYear();
let month =
data.getMonth() + 1 < 9 ? "0" + (data.getMonth() + 1) : data.getMonth() + 1;
let day = data.getDate() < 9 ? "0" + data.getDate() : data.getDate();
data.getMonth() + 1 <= 9 ? "0" + (data.getMonth() + 1) : data.getMonth() + 1;
let day = data.getDate() <= 9 ? "0" + data.getDate() : data.getDate();
let dataF = `${year}-${month}-${day}`;
return dataF;
}
@@ -51,35 +49,46 @@ export const actions = {
//saving auth in state
this.commit("setAuth", auth);
},
getCategorias() {
async getCategorias() {
const axiosHeader = {
headers: {
token: this.state.auth.token
}
};
this.$axios
await this.$axios
.get("/categoria", axiosHeader)
.then(res => {
this.commit("setCategorias", res.data.data);
})
.catch(error => {
console.log(error);
localStorage.clear();
const auth = {};
this.commit("setAuth", auth);
});
},
getMetodos() {
async getMetodos() {
const axiosHeader = {
headers: {
token: this.state.auth.token
}
};
this.$axios
await this.$axios
.get("/metodo", axiosHeader)
.then(res => {
this.commit("setMetodos", res.data.data);
})
.catch(e => console.log(e));
},
.catch(e => {
//Redireccion token
localStorage.clear();
const auth = {};
this.commit("setAuth", auth);
});
},
salir(){
localStorage.clear();
console.log("saliendo")
}
};

View File

@@ -1 +0,0 @@
{"_type":"export","__export_format":4,"__export_date":"2021-04-24T16:55:10.126Z","__export_source":"insomnia.desktop.app:v2021.2.2","resources":[{"_id":"req_bacdb6fe62fc41d4a66f9954983df3e0","parentId":"fld_5a6d850875f14063941b6444e621d252","modified":1618790367094,"created":1618790000482,"url":"{{ _.host }}/compras","name":"Compras","description":"","method":"GET","body":{},"parameters":[],"headers":[{"name":"Content-Type","value":"application/json","description":"","id":"pair_02cecdd51a164372a1c2ad69c152b9c5"},{"name":"token","value":"{{ _.token }}","description":"","id":"pair_10170987714541bdb47b153d97f6dcf2"}],"authentication":{},"metaSortKey":-1618790000482,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"fld_5a6d850875f14063941b6444e621d252","parentId":"wrk_0a6e28fdd90541048b1ff22740cf2f76","modified":1618791644992,"created":1618786993777,"name":"API_FINANZAS","description":"","environment":{"host":"localhost:4000/api","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyRGF0YSI6eyJfaWQiOiI1Y2EwM2MzM2U4MzAzNjAwMTdmOGRkYjkiLCJuYW1lIjoiTWFydGluIENoYXBhcnJvIiwiZW1haWwiOiJtZGNoYXBhcnJvckB1bmFsLmVkdS5jbyIsImRhdGUiOiIyMDE5LTAzLTMxVDA0OjA0OjAzLjMxNVoiLCJfX3YiOjB9LCJpYXQiOjE2MTg3OTE2MDQsImV4cCI6MTYyMTM4MzYwNH0.Zib1CPwU-McovWyq1IsELxuXs1FDlFUNT3MqV_4l_LE"},"environmentPropertyOrder":{"&":["host","token"]},"metaSortKey":-1618786993777,"_type":"request_group"},{"_id":"wrk_0a6e28fdd90541048b1ff22740cf2f76","parentId":null,"modified":1618786939580,"created":1618786939580,"name":"Insomnia","description":"","scope":"collection","_type":"workspace"},{"_id":"req_9b054b25cd8a44fcb69fd3641c1d1964","parentId":"fld_5a6d850875f14063941b6444e621d252","modified":1618791602686,"created":1618788181720,"url":"{{ _.host }}/login","name":"Login","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n\t\"email\":\"mdchaparror@unal.edu.co\",\n\t\"password\":\"un260874\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","value":"application/json","description":"","id":"pair_e165853035d54b15ab880335e6c239b4"}],"authentication":{},"metaSortKey":-1618788181720,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"req_462c83a2830a45a88e220ad467729798","parentId":"fld_5a6d850875f14063941b6444e621d252","modified":1618791147728,"created":1618787053177,"url":"{{ _.host }}/register","name":"Register","description":"Registro de usuarios","method":"POST","body":{"mimeType":"application/json","text":"{\n\t\"name\":\"Prueba\",\n\t\"password\":\"un260874\",\n\t\"email\":\"mmunevar@gmail.com\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","value":"application/json","id":"pair_4fae4b5f40e34c3a9405688cf351928e"}],"authentication":{},"metaSortKey":-1618787053178,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global","_type":"request"},{"_id":"env_90e649a7f8f53834ad95ba7c68334fc9919b0028","parentId":"wrk_0a6e28fdd90541048b1ff22740cf2f76","modified":1618786939670,"created":1618786939670,"name":"Base Environment","data":{},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1618786939670,"_type":"environment"},{"_id":"jar_90e649a7f8f53834ad95ba7c68334fc9919b0028","parentId":"wrk_0a6e28fdd90541048b1ff22740cf2f76","modified":1618786939676,"created":1618786939676,"name":"Default Jar","cookies":[],"_type":"cookie_jar"},{"_id":"spc_54809161a8294aa3ac1b5699085bb91d","parentId":"wrk_0a6e28fdd90541048b1ff22740cf2f76","modified":1618786939584,"created":1618786939584,"fileName":"Insomnia","contents":"","contentType":"yaml","_type":"api_spec"}]}

View File

@@ -14,3 +14,6 @@ npx mongoku start
# Referencias
[Element UI](http://element.eleme.io)
[highcharts](https://www.highcharts.com/demo)

View File

@@ -23,15 +23,21 @@ app.use(express.urlencoded({
app.set('port',process.env.PORT || 4000);
app.use(cors());
app.use(express.static('public'))
//Rutas
app.use('/api',require('./routes/resumen'));
app.use('/api',require('./routes/users'));
app.use('/api',require('./routes/compras'))
app.use('/api',require('./routes/ingresos'))
app.use('/api',require('./routes/presupuesto'))
app.use('/api',require('./routes/ahorro'))
app.use('/api',require('./routes/creditos'))
app.use('/api',require('./routes/categorias'))
app.use('/api',require('./routes/metodos_pago'))
app.use("*",(req,res)=>{res.redirect("/")})
app.disable('x-powered-by');
module.exports = app;
app.listen(app.get('port') ,() => console.log("service startes, listening on the port: ",app.get('port')))
@@ -39,19 +45,7 @@ app.listen(app.get('port') ,() => console.log("service startes, listening on the
//Mongo conecction
var uri;
if(process.env.NODE_ENV=='development'){
uri=process.env.MONGOOSE_URI_LOCAL
}
else{
uri=process.env.MONGOOSE_URI_PRODUCCION
}
uri=process.env.MONGOOSE_URI
const options={
useNewUrlParser:true,
useCreateIndex:true,

View File

@@ -3,7 +3,7 @@ const jwt = require('jsonwebtoken')
let checkAuth = (req,res,next)=>{
let token = req.get('token');
jwt.verify(token,"api finanzas mdchaparror @4050#",(err,decoded)=>{
jwt.verify(token,process.env.TOKEN_SECRET,(err,decoded)=>{
if(err){
return res.status(401).json({

22
models/ahorros.js Executable file
View File

@@ -0,0 +1,22 @@
const mongoose = require('mongoose');
const {Schema} =mongoose;
const itemSchema = new Schema({
detalle:{type:String},
valor:{type:Number},
tipo:{type:String, required:true}
})
const AhorroSchema=new Schema({
date: {type: Date, default: Date.now},
nombreAhorro: {type:String,required:true},
detalleAhorro:{type:String,required:true},
datos:[itemSchema],
user:{type:String, required:true},
child:itemSchema
});
module.exports.Ahorro=mongoose.model('ahorro',AhorroSchema);
module.exports.itemAhorro=mongoose.model('itemAhorro',itemSchema);

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);

View File

@@ -5,7 +5,12 @@ const UserSchema=new Schema({
name: {type:String,required:true},
email: {type:String, required:true},
password:{type:String, required:true},
date: {type: Date, default: Date.now}
date: {type: Date, default: Date.now},
role: {type: String,default:"USER",enum:["USER","ADMIN"]},
image: {
secure_url: {type: String, default:"https://res.cloudinary.com/mdchaparror/image/upload/v1650399265/avatars/user.jpg"},
public_id: String
}
});
UserSchema.methods.encryptPassword = async (password)=>{
const salt=await bscryptjs.genSalt(10);
@@ -19,6 +24,4 @@ UserSchema.methods.matchPassword=async function (password){
const User = mongoose.model('Users',UserSchema);
module.exports = User

530
package-lock.json generated
View File

@@ -1420,6 +1420,12 @@
"defer-to-connect": "^1.0.1"
}
},
"@tootallnate/once": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
"optional": true
},
"@types/bson": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz",
@@ -1456,6 +1462,18 @@
"negotiator": "0.6.2"
}
},
"acorn": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
"optional": true
},
"acorn-walk": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"optional": true
},
"agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -1580,6 +1598,15 @@
"dev": true,
"optional": true
},
"ast-types": {
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
"integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
"optional": true,
"requires": {
"tslib": "^2.0.1"
}
},
"async-each": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
@@ -1855,6 +1882,14 @@
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"busboy": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz",
"integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==",
"requires": {
"dicer": "0.3.0"
}
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
@@ -2026,6 +2061,30 @@
"mimic-response": "^1.0.0"
}
},
"cloudinary": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.29.0.tgz",
"integrity": "sha512-twqQvC5R5/RHenDVCbGc3ebww/HB/lBaxgoyy2aW2O/5bTzK7VbGpYsTGyV5zoiodlK8Z9SO0my9Gv92y+3K+g==",
"requires": {
"cloudinary-core": "^2.10.2",
"core-js": "3.6.5",
"lodash": "^4.17.11",
"proxy-agent": "^5.0.0",
"q": "^1.5.1"
},
"dependencies": {
"core-js": {
"version": "3.6.5",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
"integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
}
}
},
"cloudinary-core": {
"version": "2.12.3",
"resolved": "https://registry.npmjs.org/cloudinary-core/-/cloudinary-core-2.12.3.tgz",
"integrity": "sha512-Ll4eDzcrIVn4zCttMh3Mdi+KNz07p5EEjBT2PQSRx8Eok1lKPt3uBBenOk/w88RKK3B8SFIWcEe/mN4BHQ0p8A=="
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@@ -2212,6 +2271,12 @@
"integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
"dev": true
},
"data-uri-to-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
"integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
"optional": true
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -2242,6 +2307,12 @@
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true
},
"deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"optional": true
},
"defer-to-connect": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
@@ -2302,6 +2373,18 @@
}
}
},
"degenerator": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz",
"integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==",
"optional": true,
"requires": {
"ast-types": "^0.13.2",
"escodegen": "^1.8.1",
"esprima": "^4.0.0",
"vm2": "^3.9.8"
}
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@@ -2327,6 +2410,14 @@
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
},
"dicer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz",
"integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==",
"requires": {
"streamsearch": "0.1.2"
}
},
"dot-prop": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@@ -2444,11 +2535,43 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"escodegen": {
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
"integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
"optional": true,
"requires": {
"esprima": "^4.0.1",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"optionator": "^0.8.1",
"source-map": "~0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"optional": true
}
}
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"optional": true
},
"estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"optional": true
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
},
"etag": {
"version": "1.8.1",
@@ -2530,6 +2653,14 @@
"vary": "~1.1.2"
}
},
"express-fileupload": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.3.1.tgz",
"integrity": "sha512-LD1yabD3exmWIFujKGDnT1rmxSomaqQSlUvzIsrA1ZgwCJ6ci7lg2YHFGM3Q6DfK+Yk0gAVU7GWLE7qDMwZLkw==",
"requires": {
"busboy": "^0.3.1"
}
},
"extend-shallow": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
@@ -2624,6 +2755,18 @@
}
}
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"optional": true
},
"file-uri-to-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
"integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==",
"optional": true
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -2706,6 +2849,16 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs-extra": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz",
"integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"fs-minipass": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
@@ -2732,6 +2885,42 @@
"dev": true,
"optional": true
},
"ftp": {
"version": "0.3.10",
"resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz",
"integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=",
"optional": true,
"requires": {
"readable-stream": "1.1.x",
"xregexp": "2.0.0"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"optional": true
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"optional": true
}
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -2812,6 +3001,63 @@
"pump": "^3.0.0"
}
},
"get-uri": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz",
"integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==",
"optional": true,
"requires": {
"@tootallnate/once": "1",
"data-uri-to-buffer": "3",
"debug": "4",
"file-uri-to-path": "2",
"fs-extra": "^8.1.0",
"ftp": "^0.3.10"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"optional": true,
"requires": {
"ms": "2.1.2"
}
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"optional": true,
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"optional": true,
"requires": {
"graceful-fs": "^4.1.6"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"optional": true
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"optional": true
}
}
},
"get-value": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@@ -2878,8 +3124,7 @@
"graceful-fs": {
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
"dev": true
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
},
"has": {
"version": "1.0.3",
@@ -3003,6 +3248,34 @@
"toidentifier": "1.0.0"
}
},
"http-proxy-agent": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
"integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
"optional": true,
"requires": {
"@tootallnate/once": "1",
"agent-base": "6",
"debug": "4"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"optional": true,
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"optional": true
}
}
},
"https-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
@@ -3073,6 +3346,12 @@
"integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==",
"dev": true
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
"optional": true
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@@ -3375,6 +3654,15 @@
"minimist": "^1.2.5"
}
},
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
}
},
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
@@ -3448,6 +3736,16 @@
"package-json": "^6.3.0"
}
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"optional": true,
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
@@ -3461,8 +3759,7 @@
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.debounce": {
"version": "4.0.8",
@@ -3912,6 +4209,12 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"netmask": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
"integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
"optional": true
},
"node-addon-api": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz",
@@ -4136,6 +4439,20 @@
"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
"integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA=="
},
"optionator": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"optional": true,
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"word-wrap": "~1.2.3"
}
},
"p-cancelable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
@@ -4166,6 +4483,51 @@
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"pac-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz",
"integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==",
"optional": true,
"requires": {
"@tootallnate/once": "1",
"agent-base": "6",
"debug": "4",
"get-uri": "3",
"http-proxy-agent": "^4.0.1",
"https-proxy-agent": "5",
"pac-resolver": "^5.0.0",
"raw-body": "^2.2.0",
"socks-proxy-agent": "5"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"optional": true,
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"optional": true
}
}
},
"pac-resolver": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz",
"integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==",
"optional": true,
"requires": {
"degenerator": "^3.0.1",
"ip": "^1.1.5",
"netmask": "^2.0.1"
}
},
"package-json": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
@@ -4275,6 +4637,12 @@
"dev": true,
"optional": true
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"optional": true
},
"prepend-http": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
@@ -4295,6 +4663,60 @@
"ipaddr.js": "1.9.1"
}
},
"proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz",
"integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==",
"optional": true,
"requires": {
"agent-base": "^6.0.0",
"debug": "4",
"http-proxy-agent": "^4.0.0",
"https-proxy-agent": "^5.0.0",
"lru-cache": "^5.1.1",
"pac-proxy-agent": "^5.0.0",
"proxy-from-env": "^1.0.0",
"socks-proxy-agent": "^5.0.0"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"optional": true,
"requires": {
"ms": "2.1.2"
}
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"optional": true,
"requires": {
"yallist": "^3.0.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"optional": true
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"optional": true
}
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"optional": true
},
"pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
@@ -4320,6 +4742,11 @@
"escape-goat": "^2.0.0"
}
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
@@ -4697,6 +5124,12 @@
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
"integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
},
"smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
"optional": true
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -4814,6 +5247,44 @@
}
}
},
"socks": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz",
"integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==",
"optional": true,
"requires": {
"ip": "^1.1.5",
"smart-buffer": "^4.2.0"
}
},
"socks-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz",
"integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==",
"optional": true,
"requires": {
"agent-base": "^6.0.2",
"debug": "4",
"socks": "^2.3.3"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"optional": true,
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"optional": true
}
}
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -4906,6 +5377,11 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"streamsearch": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
"string-width": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
@@ -5087,6 +5563,21 @@
"nopt": "~1.0.10"
}
},
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
"optional": true
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"optional": true,
"requires": {
"prelude-ls": "~1.1.2"
}
},
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
@@ -5182,6 +5673,11 @@
"crypto-random-string": "^2.0.0"
}
},
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -5306,6 +5802,16 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"vm2": {
"version": "3.9.9",
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.9.tgz",
"integrity": "sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw==",
"optional": true,
"requires": {
"acorn": "^8.7.0",
"acorn-walk": "^8.2.0"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -5368,6 +5874,12 @@
"string-width": "^4.0.0"
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"optional": true
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -5391,6 +5903,12 @@
"integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
"dev": true
},
"xregexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
"integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=",
"optional": true
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

View File

@@ -12,11 +12,14 @@
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.1",
"cloudinary": "^1.29.0",
"colors": "^1.4.0",
"cors": "^2.8.5",
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-fileupload": "^1.3.1",
"fs-extra": "^10.0.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.12.4",
"mongoose-unique-validator": "^2.0.3",

111
routes/ahorro.js Normal file
View File

@@ -0,0 +1,111 @@
const router = require("express").Router();
const ahorro = require("../models/ahorros").Ahorro;
const itemAhorro = require("../models/ahorros").itemAhorro;
const { checkAuth } = require("../middlewares/authentication");
router.get("/ahorro", checkAuth, async (req, res) => {
var ahorros;
let limite = req.get('limite');
ahorros = await ahorro.find({ user: req.userData._id }).sort({
date: "desc",
}).limit(parseInt(limite));
return res.send({
status: "ok",
data: ahorros,
});
});
router.post("/ahorro", checkAuth, async (req, res) => {
const { nombreAhorro,detalleAhorro } = req.body;
var ahorros = await ahorro.find({
user: req.userData._id,
nombreAhorro: nombreAhorro,
});
if (ahorros.length == 0) {
const Ahorro = new ahorro({
nombreAhorro: nombreAhorro,
detalleAhorro:detalleAhorro,
});
console.log(Ahorro);
Ahorro.user = req.userData._id;
await Ahorro.save();
return res.json({
status: "OK",
});
}
return res.status(500).json({
status: "FAIL",
});
});
router.delete("/ahorro", checkAuth, async (req, res) => {
try {
const userId = req.userData._id;
const id = req.query.id;
const resultado = await ahorro.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("/ahorro", checkAuth, async (req, res) => {
const { _id, detalle, valor, tipo } = req.body;
const ahorro_edit = await ahorro.findOne({
_id: _id,
user: req.userData._id,
});
const itemP = new itemAhorro({ detalle, valor, tipo });
ahorro_edit.datos.push(itemP);
await ahorro_edit.save();
res.json({
status: "OK",
});
});
router.get("/ahorro_items", checkAuth, async (req, res) => {
const _id = req.query.ahorro_id;
const ahorro_edit = await ahorro.findOne({
_id: _id,
user: req.userData._id,
});
return res.json({
status: "OK",
data: ahorro_edit.datos,
});
});
router.delete("/ahorroitem", checkAuth, async (req, res) => {
try {
const userId = req.userData._id;
const iditem = req.query.iditem;
const idAhorro = req.query.idAhorro;
var ahorro_edit = await ahorro.findOne({
user: userId,
_id: idAhorro,
});
ahorro_edit.datos.id(iditem).remove();
await ahorro_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

@@ -22,7 +22,7 @@ router.get("/categoria", checkAuth, async (req, res) => {
const {name, icon} = req.body;
const user= req.userData._id;
var categoria = await Categoria.findOne({ name: name });
var categoria = await Categoria.findOne({ name: name,user:user });
if (categoria) {
return res.status(500).json({ status: "fail", error: "Categoria existente" });

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;

20
routes/index.js Normal file
View File

@@ -0,0 +1,20 @@
const router = require("express").Router()
const fs = require("fs");
const pathRoutes = `${__dirname}`
const removeExtension = (fileName) =>{
return fileName.split(".").shift()
}
fs.readdirSync(pathRoutes).filter(file =>{
const nameFile = removeExtension(file);
const skip = ['index'].includes(nameFile)
if(!skip){
console.log(nameFile)
}
})
module.exports= router

View File

@@ -22,7 +22,7 @@ router.get("/metodo", checkAuth, async (req, res) => {
const {name, icon} = req.body;
const user= req.userData._id;
var metodo = await Metodo.findOne({ name: name });
var metodo = await Metodo.findOne({ name: name,user:user });
if (metodo) {
return res.status(500).json({ status: "fail", error: "Método de pago existente" });

100
routes/resumen.js Normal file
View File

@@ -0,0 +1,100 @@
const router=require('express').Router();
const ingresos = require('../models/ingresos');
const Compras = require('../models/compras');
const { checkAuth } = require("../middlewares/authentication");
router.get("/resumen_compras", checkAuth, async (req, res) => {
var compras_;
var totalCompras=0;
let miFiltro = req.get('filtro');
const filtros = {
fecha: { $regex: miFiltro, $options: "i" },
};
compras_ = await Compras.find({$and:[{ user: req.userData._id },filtros]}).sort({
fecha: "desc",
});
totalCompras = compras_.reduce((acx,x)=> acx=acx+x.valor,0);
return res.send(
{
status:"ok",
data:totalCompras
}
)
});
router.get("/resumen_ingresos", checkAuth, async (req, res) => {
var ingresos_;
var totalIngresos=0;
let miFiltro = req.get('filtro');
const filtros = {
fecha: { $regex: miFiltro, $options: "i" },
};
ingresos_ = await ingresos.find({$and:[{ user: req.userData._id },filtros]}).sort({
fecha: "desc",
});
totalIngresos = ingresos_.reduce((acx,x)=> acx=acx+x.valor,0);
return res.send(
{
status:"ok",
data:totalIngresos
}
)
});
router.get('/resumen_categorias',checkAuth,async (req,res)=>{
var compras_;
var labels =[];
var datos =[];
let miFiltro = req.get('filtro');
const filtros = {
fecha: { $regex: miFiltro, $options: "i" },
};
compras_ = await Compras.aggregate([
{$match: { $and: [{ user:req.userData._id}, filtros] }},
{$group:{_id:{categoria:"$categoria"},total:{$sum:"$valor"}}}
]).sort({total:"desc"});
compras_.forEach(element => {
//console.log(element.total)
labels.push(element._id.categoria)
datos.push(element.total)
});
res.json({"labels":labels,"datos":datos});
});
router.get('/resumen_metodos',checkAuth,async (req,res)=>{
var compras_;
var labels =[];
var datos =[];
let miFiltro = req.get('filtro');
const filtros = {
fecha: { $regex: miFiltro, $options: "i" },
};
compras_ = await Compras.aggregate([
{$match: { $and: [{ user:req.userData._id}, filtros] }},
{$group:{_id:{metodopago:"$metodopago"},total:{$sum:"$valor"}}}
]).sort({total:"desc"});
compras_.forEach(element => {
//console.log(element.total)
labels.push(element._id.metodopago)
datos.push(element.total)
});
res.json({"labels":labels,"datos":datos});
});
module.exports = router;

View File

@@ -2,12 +2,29 @@ const express = require("express");
const router = express.Router();
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const User = require("../models/user")
//import User from "../models/user.js";
const User = require("../models/user");
const {loadImage,deleteImageCloud,scaleImage} = require("../utils/cloudinary");
const { checkAuth } = require("../middlewares/authentication");
const {uploadFile} = require('../utils/uploadfiles')
const fs = require("fs-extra");
//AUTH
router.post("/register", async (req, res) => {
const { name, email, password } = req.body;
router.get("/users", checkAuth, async (req, res) => {
var Users;
Users = await User.find({});
return res.send({
status: "ok",
data: Users,
});
});
if (process.env.REGISTER == "true") {
router.post("/register", uploadFile,async (req, res) => {
const { name, email, password } = JSON.parse(req.body.user);
const passEncrypted = bcrypt.hashSync(password, 10);
const newUser = new User({
@@ -18,6 +35,7 @@ router.post("/register", async (req, res) => {
const emailUser = await User.findOne({ email: email });
if (emailUser) {
deleteImage(req)
return res
.status(500)
.json({ status: "fail", error: "email already exists" });
@@ -25,6 +43,17 @@ router.post("/register", async (req, res) => {
try {
newUser.password = await newUser.encryptPassword(password);
if (req.files.File) {
console.log(req.files.File.tempFilePath);
const result = await loadImage(req.files.File.tempFilePath);
newUser.image = {
public_id: result.public_id,
secure_url: result.secure_url,
};
deleteImage(req)
}
await newUser.save();
res.json({
@@ -32,24 +61,39 @@ router.post("/register", async (req, res) => {
msg: "Usuario creado",
});
} catch (error) {
deleteImage(req)
return res
.status(500)
.json({ status: "fail", error: `internal error:${error}` });
}
});
} else {
router.post("/register", (req, res) => {
deleteImage(req)
return res
.status(500)
.json({
status: "faill",
error: `No tiene permitido crear usuarios nuevos`,
});
});
}
router.post("/login", async (req, res) => {
const { email, password } = req.body;
var user = await User.findOne({ email: email });
if (!user) {
res.status(401).json({ status: "fail", error: "Invalid credentials email" });
res
.status(401)
.json({ status: "fail", error: "Invalid credentials email" });
return;
}
if (! await user.matchPassword(password)) {
return res.status(401).json({ status: "fail", error: "Invalid credentials pass" });
if (!(await user.matchPassword(password))) {
return res
.status(401)
.json({ status: "fail", error: "Invalid credentials pass" });
}
user.set("password", undefined, { strict: false });
const token = jwt.sign(
@@ -67,6 +111,27 @@ router.post("/login", async (req, res) => {
res.json(toSend);
});
router.delete("/user", checkAuth, async (req, res) => {
try {
const id = req.query.id;
const userDelete = await User.findOne({ _id: id })
const resultado = await User.deleteOne({ _id: id });
if(userDelete.image.public_id)
await deleteImageCloud(userDelete.image.public_id).catch(console.error("No existe imagen para borrar"));
return res.json({ status: "ok", data: resultado });
} catch (error) {
console.error(error);
return res.status(500).json({ status: "fail", error: error });
}
});
//CRUD USER
const deleteImage = async (req)=>{
if (req.files.File) {
await fs.unlink(req.files.File.tempFilePath);
}
}
module.exports = router;

29
utils/cloudinary.js Normal file
View File

@@ -0,0 +1,29 @@
var cloudinary = require('cloudinary').v2;
cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
secure: true
});
const loadImage = async (filepath) =>{
return await cloudinary.uploader.upload(filepath,{
folder:'avatars'
})
}
const scaleImage = async (filepath) =>{
return await cloudinary.image(filepath,{
width: 70, height: 53, crop: "scale"
})
}
const deleteImageCloud = async (publicId) => {
return await cloudinary.uploader.destroy(publicId)
}
module.exports.loadImage = loadImage
module.exports.scaleImage = scaleImage
module.exports.deleteImageCloud = deleteImageCloud

9
utils/uploadfiles.js Normal file
View File

@@ -0,0 +1,9 @@
const fileUpload = require('express-fileupload')
const uploadFile = fileUpload({
useTempFiles: true,
tempFileDir: './uploads',
parseNested: true
})
module.exports.uploadFile =uploadFile