Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exam solved #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
let dictionary = {};

const express = require("express");
const bodyParser = require("body-parser");
const morgan = require("morgan");
const mongoose = require("mongoose");
const config = require("./config");
const {responseHelpers} = require("./middleware");
const {responseHelpers, cacheMiddleware} = require("./middleware")(dictionary);
const routes = require("./routes");
const request = require("request");
require("./models");

const app = express();
Expand All @@ -18,19 +21,19 @@ app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(morgan("dev"));

// Add cache middleware
app.use(cacheMiddleware);

// Add response helpers
app.use(responseHelpers);

// Add cache middleware
// app.use(cacheMiddleware);

// Setup mongoose and load models
mongoose.Promise = global.Promise;
mongoose.connect(config.db, {useNewUrlParser: true});
// models(mongoose);

// Register the routes and mount them all at /api
app.use("/api", routes(app, express.Router()));
app.use("/api", routes(app, express.Router(), request, config));

// default route handler
app.use((req, res) => {
Expand Down
2 changes: 1 addition & 1 deletion config/test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
env: "test",
db: "mongodb://localhost:27017/courses_test",
port: process.env.PORT || 3000
port: 3000
};
176 changes: 118 additions & 58 deletions controllers/billing.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module.exports = (mongoose) => {
module.exports = (mongoose, request, config) => {
const Course = mongoose.model("Course");
const Evaluation = mongoose.model("Evaluation");
const Student = mongoose.model("Student");
const afipUrl = 'http://localhost:'+config.port+'/api/afip';

// para cada curso dame la evaluacion
// para cada evaluacion dame los aprobados
Expand All @@ -10,6 +11,70 @@ module.exports = (mongoose) => {
// agrupar por student y calcular precio final
// devolver precio, nombre, apellido y billing address

function getChargeables(){
return new Promise((resolve, reject) => {
let courses = {};
Course.find({status: "finished"})
.then((_courses) => {
courses = _courses.reduce((coursesDict, course) => {
// eslint-disable-next-line
coursesDict[course._id] = course.price;
return coursesDict;
}, {});
const promiseArray = _courses.map((course) => {
return Evaluation.findOne({courseId: course._id});
});
return Promise.all(promiseArray);
})
.then((evaluations) => {
return Promise.resolve(evaluations.map((evaluation) => {
const evaluationStudents = evaluation.notes
.filter((note) => {
return note.status === "passed";
})
.map((student) => {
return student.studentId;
});
return {
courseId: evaluation.courseId,
students: evaluationStudents
};
}));
})
.then((approvedStudentsToBill) => {
const studentsWithPrice = {};
approvedStudentsToBill.forEach((course) => {
course.students.forEach((student) => {
if (studentsWithPrice[student]) {
studentsWithPrice[student] += courses[course.courseId];
} else {
studentsWithPrice[student] = courses[course.courseId];
}
});
});
return Promise.resolve(studentsWithPrice);
})
.then((studentsWithPrice) => {
const studentsBillingInfo = Object.keys(studentsWithPrice).map((id) => {
return new Promise((resolve) => {
Student.findById(id).then((student) => {
return resolve({
firstName: student.firstName,
lastName: student.lastName,
address: student.billingAddress,
price: studentsWithPrice[id]
});
});
});
});
resolve(Promise.all(studentsBillingInfo));
})
.catch((err) => {
reject(err);
});
})
}

/**
* getChargeableStudents - get the students which passed the evaluation for a finished course
*
Expand All @@ -18,62 +83,7 @@ module.exports = (mongoose) => {
* @return {Array<StudentBillingInfo>} studentsBillingInfo
*/
function getChargeableStudents(req, res) {
let courses = {};
Course.find({status: "finished"})
.then((_courses) => {
courses = _courses.reduce((coursesDict, course) => {
// eslint-disable-next-line
coursesDict[course._id] = course.price;
return coursesDict;
}, {});
const promiseArray = _courses.map((course) => {
return Evaluation.findOne({courseId: course._id});
});
return Promise.all(promiseArray);
})
.then((evaluations) => {
return Promise.resolve(evaluations.map((evaluation) => {
const evaluationStudents = evaluation.notes
.filter((note) => {
return note.status === "passed";
})
.map((student) => {
return student.studentId;
});
return {
courseId: evaluation.courseId,
students: evaluationStudents
};
}));
})
.then((approvedStudentsToBill) => {
const studentsWithPrice = {};
approvedStudentsToBill.forEach((course) => {
course.students.forEach((student) => {
if (studentsWithPrice[student]) {
studentsWithPrice[student] += courses[course.courseId];
} else {
studentsWithPrice[student] = courses[course.courseId];
}
});
});
return Promise.resolve(studentsWithPrice);
})
.then((studentsWithPrice) => {
const studentsBillingInfo = Object.keys(studentsWithPrice).map((id) => {
return new Promise((resolve) => {
Student.findById(id).then((student) => {
return resolve({
firstName: student.firstName,
lastName: student.lastName,
address: student.billingAddress,
price: studentsWithPrice[id]
});
});
});
});
return Promise.all(studentsBillingInfo);
})
getChargeables()
.then((studentsBillingInfo) => {
res.response200({studentsBillingInfo}, `Found '${studentsBillingInfo.length}' Students.`);
})
Expand All @@ -82,7 +92,57 @@ module.exports = (mongoose) => {
});
}

function getInvoices(req, res) {
getChargeables()
.then(students => {
return students.map(item => {
return {
nomYAp: `${item.firstName} ${item.lastName}`,
dir: `${item.address.street1}, ${item.address.city}, ${item.address.state}, ${item.address.country}`,
importe: item.price / 100
}
})
})
.then(async (toInvoice) => {
let data = [];
let initLength = toInvoice.length;
while (data.length < initLength) {
let elem = toInvoice.shift();
await callAFIP(elem)
.then(info => {
data.push({
BillingNumber: info.data.id+"",
FirstAndLastName: elem.nomYAp,
Address: elem.dir ,
price: elem.importe+""
});
})
.catch(err => {
toInvoice.push(elem);
})
}
res.response200(data, `Found '${data.length}' Students to invoice.`);
})
.catch(err => {
res.response500(err, "Courses couldn't be found!");
})
}

function callAFIP(obj){
return new Promise((resolve, reject) => {
request.post(afipUrl, {json: obj}, (err, res, info) => {
if(err) {
reject(err);
} else if(info.status == "error")
reject(info.message);
else
resolve(info);
})
})
}

return {
getChargeableStudents
getChargeableStudents,
getInvoices
};
};
2 changes: 1 addition & 1 deletion controllers/courses.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = (mongoose) => {
var Course = mongoose.model("Course"),
filterFields = ["status"],
filterFields = ["status", "technologyId"],
sortFields = ["status"];

var buildFilterQuery = function(params) {
Expand Down
47 changes: 46 additions & 1 deletion controllers/evaluations.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const GenericController = require("./genericController");

module.exports = (mongoose) => {
const Evaluation = mongoose.model("Evaluation");
const Student = mongoose.model("Student");

const listOptions = {
filterBy: [],
sortBy: []
Expand All @@ -18,8 +21,50 @@ module.exports = (mongoose) => {
return controller.create(req, res, {normalize: getEvaluationDTO});
}

function failuresByStates(req, res) {
Evaluation.find({},{notes: 1})
.then(evaluations => {
let failed = {};
for(var i=0; i<evaluations.length; i++){
let notes = evaluations[i].notes;
for(var j=0; j<notes.length; j++){
if(notes[j].status === "failed"){
failed[notes[j].studentId] ?
failed[notes[j].studentId] = failed[notes[j].studentId] + 1 :
failed[notes[j].studentId] = 1;
}

}
}
return failed
})
.then(evalsFailed => {
let promises = []
Object.keys(evalsFailed).forEach(item => {
promises.push(Student.find({"_id": { $eq: item}}, {"billingAddress.state": 1}))
})
return Promise.all(promises)
})
.then(states => {
let _states_ = {}
for(var i=0; i<states.length; i++){
_states_[states[i][0].billingAddress.state] ?
_states_[states[i][0].billingAddress.state] = _states_[states[i][0].billingAddress.state] + 1 :
_states_[states[i][0].billingAddress.state] = 1;
}
return _states_
})
.then(evalsFailed => {
res.response200(evalsFailed, `Found ${Object.keys(evalsFailed).length} State.`);
})
.catch((err) => {
res.response500(err, "evaluations couldn't be found!");
});
}

return {
...controller,
create: createEvaluation
create: createEvaluation,
failuresByStates
};
};
61 changes: 61 additions & 0 deletions middleware/cacheMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const notStored = [
"/api/admin/billing/getChargeableStudents"
];

function isNotCacheable(url){
return notStored.find(item => {
return url.includes(item);
})
}

function findResponse(dictionary, url){
return dictionary[url];
}

let postCondition = (key, url) => {
return key == url
}

function getParentPath(url){
let parts = url.split("/");
return (parts.slice(0, parts.length -1)).join("/");
}

let putCondition = (key, url) => {
let parentUrl = getParentPath(url);
return key == url || key == parentUrl
}

function deleteFromDictionary(dictionary, method, url){
let condition;
if(method === 'POST')
condition = postCondition
else //method PUT
condition = putCondition
for(key in dictionary){
if(condition(key, url)){
delete dictionary[key];
}
}
}

module.exports = (dictionary) => {
return (req, res, next) => {
if(isNotCacheable(req.originalUrl)){
//console.log("Ruta no cacheable")
next()
} else if(req.method === "GET") {
let elem = findResponse(dictionary, req.originalUrl);
if(elem){
//console.log("Respuesta cacheada")
res.json(elem)
} else {
//console.log("Respuesta sin cachear")
next()
}
} else if(req.method === "POST" || req.method === "PUT") {
deleteFromDictionary(dictionary, req.method, req.originalUrl)
next()
}
}
};
11 changes: 9 additions & 2 deletions middleware/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
const responseHelpers = require("./responseHelpers");

module.exports = {responseHelpers};
module.exports = (dictionary) => {
const responseHelpers = require("./responseHelpers")(dictionary);
const cacheMiddleware = require("./cacheMiddleware")(dictionary);

return {
cacheMiddleware,
responseHelpers
}
};
Loading