%PDF- %PDF-
| Direktori : /home/opti/workflow/src/routes/ |
| Current File : /home/opti/workflow/src/routes/account.js |
var express = require('express');
var router = express.Router();
var formidable = require('formidable');
var fs = require('fs');
var path = require('path');
var Op = require('sequelize').Op;
var ejs = require('ejs');
var pdf = require('html-pdf');
// var moment = require('moment');
// const email = require('../config/mail');
var secured = require('../middleware/login');
var db = require('../models');
//import models
// const db = require('../models'); // new require for db object
//TODO::list all contacts, invoices etc...
//get method/route for sll organisation list/view,
router.get('/', secured, function(req, res, next) {
res.render('account/index', {script: 'index'});
});
//////invoices////
//get method/route for sll invoices,
router.get('/invoices', secured, async(req, res, next) =>{
const [ invoices ] = await Promise.all([
db.Invoice.findAll({ where: {orgId: req.user.orgId }, include: ['invoiceStatus', {model:db.Contact, as:'contactFrom', include:['person', 'group']}, {model:db.Contact, as:'contactTo', include:['person', 'group']}], order: [ ['createdAt', 'DESC'],['statusId', 'ASC']]}),
]);
db.PaymentMethod.findAll({})
.then(paymentMethods=>{
res.render('account/invoice/index', { invoices, paymentMethods});
})
});
//create invoice get Method
router.get('/invoices/create', secured, async(req, res, next) =>{
db.Currency.findAll({})
.then(currencies => {
res.render('account/invoice/addInvoice',{currencies});
})
});
//indit invoice get Method
router.get('/invoices/edit/:uuid', secured, async(req, res, next) =>{
db.Invoice.findOne({where:{uuid:req.params.uuid}, include:['invoiceStatus', 'invoiceItems']})
.then(invoice =>{
if(invoice.statusId >= 3){ // not draft, not approved
req.flash('info', 'Invoice cannot be edited' );
return res.redirect('/accounts/invoices/view/'+invoice.uuid);
}
db.Currency.findAll({})
.then(currencies => {
return res.render('account/invoice/addInvoice',{invoice});
})
})
});
//postMethod for creat invoice
router.post('/invoices/create', secured, function(req, res, next) {
// let orgId = 0;
// console.log(req.body)
var form = new formidable.IncomingForm();
form.parse(req, async(err, fields, files) =>{
console.log(fields)
var itemNames = JSON.parse(fields.allNames);
var itemDescriptions = JSON.parse(fields.allDescriptions);
var itemPrices = JSON.parse(fields.allPrices);
var itemQuantities = JSON.parse(fields.allQuantities);
var balanceDue = fields.totalAmount - (fields.amountPaid ? parseFloat(fields.amountPaid) : 0);
let invoice;
if(fields.invoiceUuid){
[invoice] = await Promise.all([
db.Invoice.findOne({where:{uuid:fields.invoiceUuid}, include:['invoiceItems']})
])
var partyToId = fields.partyToId ? JSON.parse(fields.partyToId) : null;
var partyFromId = fields.partyFromId ? JSON.parse(fields.partyFromId) : null;
invoice.update({invoiceCategoryId: parseInt(fields.typeCategoryId), invoiceTypeId: parseInt(fields.invoiceTypeId), partyToId:partyToId, partyFromId:partyFromId, roleTypeId:fields.roleTypeId,currencyId:parseInt(fields.currencyId), dueDate: new Date(fields.dueDate), invoiceDate: new Date(fields.invoiceDate), referenceNumber, number:lastNumber, orgId:req.user.orgId , invoiceMessage:fields.invoiceMessage, billingAccountId:fields.billingAccountId, description:fields.description, amount:fields.totalAmount, balanceDue})
.then(async (i)=>{
await invoice.invoiceItems.forEach( item =>{
item.destroy();
})
})
db.InvoiceHistory.create({
invoiceId:invoice.id, orgId: req.user.orgId, statusId:invoice.statusId, message:`${req.user.firstName} ${req.user.lastName} edited this invoice.`, madeBy:req.user.id
});
}
else{
var partyToId = fields.partyToId ? JSON.parse(fields.partyToId).id : null;
var partyFromId = fields.partyFromId ? JSON.parse(fields.partyFromId).id : null;
//from here down to ... just to generate reference number
const [lastInvoice ] = await Promise.all([
db.Invoice.findOne({attributes:['number'], where:{orgId:req.user.orgId}, order:[['createdAt', 'DESC']] })
])
console.log(lastInvoice);
var lastNumber = 0;
if(!lastInvoice)
lastNumber = 0;
else
lastNumber = lastInvoice.number
var lastNumberLength = 0;
lastNumber++;
var n = lastNumber;
if (n >= 1) ++lastNumberLength;
while (n / 10 >= 1) {
n/= 10;
++lastNumberLength;
}
if(lastNumberLength == 1)
lastNumber = "000"+lastNumber;
else if(lastNumberLength == 2)
lastNumber = "00"+lastNumber;
else if(lastNumberLength == 3)
lastNumber = "0"+lastNumber;
var day = new Date().getDay()+""; //convert it to string
if(day.length == 1) day = "0"+day;
var referenceNumber = 'INV-'+ day +"-" + lastNumber;
//yeah up till here
[invoice] = await Promise.all([
db.Invoice.create({ invoiceCategoryId: parseInt(fields.typeCategoryId), invoiceTypeId: parseInt(fields.invoiceTypeId), partyToId:partyToId, partyFromId:partyFromId, roleTypeId:fields.roleTypeId,currencyId:parseInt(fields.currencyId), dueDate: new Date(fields.dueDate), invoiceDate: new Date(fields.invoiceDate), referenceNumber, number:lastNumber, orgId:req.user.orgId , invoiceMessage:fields.invoiceMessage, billingAccountId:fields.billingAccountId, description:fields.description, amount:fields.totalAmount, balanceDue, statusId:1/*in-process*/})
])
db.InvoiceHistory.create({
invoiceId:invoice.id, orgId: req.user.orgId, statusId:invoice.statusId, message:`${req.user.firstName} ${req.user.lastName} created this invoice.`, madeBy:req.user.id
});
}
await itemNames.forEach((name, index)=>{
db.InvoiceItem.create({invoiceId: invoice.id, name:name, description:itemDescriptions[index], quantity:itemQuantities[index], price:itemPrices[index], /* tax */})
})
if(fields.invoiceUuid)
req.flash('success', `Invoice ${invoice.referenceNumber} successfully Updated!` );
else
req.flash('success', 'Invoice successfully Created!' );
res.redirect('/accounts/invoices/view/'+invoice.uuid);
});
});
//view invoice
router.get('/invoices/view/:uuid', secured, async(req, res, next) =>{
const [invoice, invoiceStatus ] = await Promise.all([
db.Invoice.findOne({ where:{ uuid:req.params.uuid}, include: ['invoiceStatus', 'invoiceType', {model:db.Contact, as:'contactFrom', include:['person', 'group']}, {model:db.Contact, as:'contactTo', include:['person', 'group']}, 'invoiceItems']}),
db.InvoiceStatus.findAll({})
])
if(!invoice){
req.flash('error', 'Invoice Not Found!' );
res.redirect('/accounts/invoices')
}
db.PaymentMethod.findAll({})
.then(paymentMethods=>{
db.Organization.findOne({where:{id:req.user.orgId}})
.then(organization=>{
res.render('account/invoice/viewInvoice', { invoice, invoiceStatus, paymentMethods, organization});
})
})
});
//view invoice history
router.post('/invoices/history', secured, async(req, res, next) =>{
// console.log(req.body.uuid)
db.Invoice.findOne({ where:{ uuid:req.body.uuid}})
.then(invoice=>{
if(!invoice){
return res.json({type: "error",message:"Invoice Not Found!"});
}
db.InvoiceHistory.findAll({where:{invoiceId:invoice.id}})
.then(invoiceHistories=>{
return res.json({type: "success", histories: invoiceHistories, invoice});
})
})
});
//send invoice
router.post('/invoices/send', secured, async(req, res, next) =>{
db.Invoice.findOne({ where:{ uuid:req.body.invoiceUuid}, include: ['invoiceStatus', 'invoiceType', {model:db.Contact, as:'contactFrom', include:['person', 'group']}, {model:db.Contact, as:'contactTo', include:['person', 'group']}, 'invoiceItems']})
.then(invoice=>{
if(!invoice){
if(req.xhr)
return res.json({type: "error",message:"Invoice Not Found!"}) ;
else {
req.flash('error', 'Invoice Not Found!' );
return res.redirect('/accounts/invoices')
}
}
//invoice already sent
if(invoice.statusId == 3){
if(req.xhr)
return res.json({type: "error",message:"Invoice has already been sent!"}) ;
else {
req.flash('info', 'Invoice has already been sent!' );
return res.redirect('/accounts/invoices/'+invoice.uuid)
}
}
//TODO:: SEND EMAIL.>>>>>>>>>>>
db.Organization.findOne({where:{id:req.user.orgId}})
.then(organization=>{
// sendMail('invoice', {invoice, organization});
})
//3 is sent
invoice.update({statusId: 3})
.then(i =>{
db.InvoiceHistory.create({invoiceId:invoice.id, orgId: req.user.orgId, statusId:invoice.statusId, message:`${req.user.firstName} ${req.user.lastName} sent this invoice.`, madeBy:req.user.id});
if(req.xhr)
return res.json({type: "success",message:"Invoice successfully sent!"}) ;
else {
req.flash('success', 'Invoice successfully sent!' );
return res.redirect('/accounts/invoices/view/'+invoice.uuid)
}
})
})
});
//send invoice
router.post('/invoices/make-payment', secured, async(req, res, next) =>{
console.log(req.body);
db.Invoice.findOne({ where:{ uuid:req.body.invoiceUuid}})
.then(invoice=>{
if(!invoice){
if(req.xhr)
return res.json({type: "error",message:"Invoice Not Found!"}) ;
else {
req.flash('error', 'Invoice Not Found!' );
return res.redirect('/accounts/invoices')
}
}
//TODO:: SEND EMAIL.>>>>>>>>>>>
var statusId;
var balanceDue;
if(invoice.balanceDue == parseFloat(req.body.amountPaid)){
statusId = 6;
balanceDue = 0;
}else{
statusId = 9;
balanceDue = invoice.balanceDue - parseFloat(req.body.amountPaid);
}
//6 is paid/full, 9 => partial payment
var body = req.body;
invoice.update({statusId, balanceDue})
.then( async(i) =>{
//from here down to ... just to generate reference number
const [lastPayment] = await Promise.all([
db.Payment.findOne({attributes:['number'], where:{orgId:req.user.orgId}, order:[['createdAt', 'DESC']] })
])
// console.log(lastPayment);
var lastNumber = 0;
if(!lastPayment)
lastNumber = 0;
else
lastNumber = lastPayment.number
var lastNumberLength = 0;
lastNumber++;
var n = lastNumber;
if (n >= 1) ++lastNumberLength;
while (n / 10 >= 1) {
n/= 10;
++lastNumberLength;
}
if(lastNumberLength == 1)
lastNumber = "000"+lastNumber;
else if(lastNumberLength == 2)
lastNumber = "00"+lastNumber;
else if(lastNumberLength == 3)
lastNumber = "0"+lastNumber;
var day = new Date().getDay()+""; //convert it to string
if(day.length == 1) day = "0"+day;
var referenceNumber = 'PAY-'+ day +"-" + lastNumber;
//yeah up till here
//invoicesCategoryId = paymentTypeId (purchase or sales)
db.Payment.create({orgId:req.user.orgId, invoiceId:invoice.id, paymentMethodId:body.paymentMethodId, partyToId: invoice.partyToId, partyFromId: invoice.partyFromId, amount: body.amountPaid, currencyId:invoice.currencyId, comment:body.comment, referenceNumber, paymentTypeId: invoice.invoiceCategoryId, number: lastNumber})
.then(payment => {
db.InvoiceHistory.create({invoiceId:invoice.id, orgId: req.user.orgId, statusId:invoice.statusId, message:`${req.user.firstName} ${req.user.lastName} recorded payment <a href="/accounts/payment/view/${payment.uuid}" >#${payment.referenceNumber}</a> - <span class="pink">${payment.amount}</span> for this invoice.`, madeBy:req.user.id});
db.PaymentHistory.create({paymentId:payment.id, orgId: req.user.orgId, statusId:1 /* 1 => received */, message:`${req.user.firstName} ${req.user.lastName} recorded payment - <span class="pink">${payment.amount}</span> for <a href="/accounts/invoices/view/${invoice.uuid}">#${invoice.referenceNumber}</a>.`, madeBy:req.user.id});
if(req.xhr)
return res.json({type: "success",message:"Payment recorded Successfully!", invoice}) ;
else {
req.flash('success', 'Payment recorded Successfully!' );
return res.redirect('/accounts/invoices/view/'+invoice.uuid)
}
})
})
})
});
//get for ekko-light make-payment
router.get('/invoices/pay/:invoiceUuid', secured, async(req, res, next) =>{
db.Invoice.findOne({ where:{ uuid:req.params.invoiceUuid}})
.then(invoice=>{
if(!invoice){
req.flash('error', 'Invoice Not Found!' );
return res.redirect('/accounts/invoices')
}
db.PaymentMethod.findAll({})
.then(paymentMethods=>{
return res.render('account/invoice/pay',{invoice, paymentMethods})
})
})
})
//download invoice
router.get('/invoices/download/:uuid', secured, async(req, res, next) =>{
const [invoice, invoiceStatus, organization ] = await Promise.all([
db.Invoice.findOne({ where:{ uuid:req.params.uuid}, include: ['invoiceStatus', 'invoiceType', {model:db.Contact, as:'contactFrom', include:['person', 'group']}, {model:db.Contact, as:'contactTo', include:['person', 'group']}, 'invoiceItems']}),
db.InvoiceStatus.findAll({}),
db.Organization.findOne({where:{id:req.user.orgId}})
])
if(!invoice){
req.flash('error', 'Invoice Not Found!' );
res.redirect('/accounts/invoices')
}
const file = path.join(__dirname, '..', 'views', 'pdf', 'invoice.ejs');
var html;
ejs.renderFile(file, {invoice, invoiceStatus, organization}, function(err, result) {
// render on success
if (result) {
html = result;
}
// render or error
else {
res.end('An error occurred');
console.log(err);
}
});
var options = { filename: invoice.referenceNumber+'.pdf', format: 'A4', orientation: 'portrait', directory: './phantomScripts/',type: "pdf" };
pdf.create(html, options).toFile(function(err, res) {
if (err) return console.log(err);
console.log(res);
});
});
// a ajax request from create new payment page
router.post('/invoices/balanceDue', secured, async(req, res, next) =>{
db.Invoice.findOne({ where:{ uuid:req.body.invoiceUuid}, attributes: ['balanceDue']})
.then(invoice=>{
if(!invoice){
return res.json({type: "error",message:"Invoice Not Found!"}) ;
}
return res.json({type: "success",balanceDue:invoice.balanceDue}) ;
})
})
//get all invoicetypes from ajax, it could be a get request but, post works fine
router.post('/invoices/getTypes', secured, function(req, res, next) {
let typeCategoryId = req.body.typeCategoryId
db.InvoiceType.findAll({ where: {typeCategoryId: typeCategoryId} })
.then( invoices=>{
res.json(invoices);
})
});
////////////////////////////////////
///contact//////////
//////////////////
//get method/route for sll invoices,
router.get('/contacts', secured, async(req, res, next) =>{
db.Contact.findAll({where:{orgId:req.user.orgId },include: ['person', 'group'], order: [ ['createdAt', 'DESC'],]})
.then(contacts =>{
console.log(contacts)
res.render('account/contact/index', { contacts});
})
})
//postMethod for creat contact
router.post('/contacts/create', secured, function(req, res, next) {
var form = new formidable.IncomingForm();
form.parse(req, async(err, fields, files) =>{
if(fields.contactType == '1'){ //individual
//TODO::Validate data
let passport = files.passport;
if (passport === null) {
req.flash('error', 'Please Fill All The Required Forms');
res.redirect(`/accounts/contacts`);
}
let passport_name;
if (passport && passport.name) {
passport_name = (saveFile(passport))//
}
await db.Person.create({ firstName: fields.firstname, lastName:fields.lastname, middleName: fields.middlename, salutation:fields.salutation, gender: parseInt(fields.gender), suffix:fields.suffix, birthDate: new Date(fields.birthdate), maritalStatus: parseInt(fields.maritalStatus), orgId: req.user.orgId , passport:passport_name, email:fields.email, phoneNo:fields.phoneNo})
// .save()
.then(person => {
// you can now access the currently saved person with the variable person... nice!
makeContactReference(req.user.orgId, person, 1);//1 for individual
})
.catch(error => {
console.log(error);
// Ooops, do some error-handling
})
}
else if(fields.contactType == '2'){ //group
let logo = files.logo;
if (logo === null) {
req.flash('error', 'Please Fill All The Required Forms');
res.redirect(`/accounts/contacts`);
}
let logo_name;
if (logo && logo.name) {
logo_name = (saveFile(logo))
}
await db.Group.build({ name: fields.name, nameLocal: fields.nameLocal, offSiteName:fields.offSiteName, address:fields.address, comment: fields.comment, logoUrl:logo_name , orgId:req.user.orgId, email:fields.email, phoneNo:fields.phoneNo})
.save()
.then(group => {
makeContactReference(req.user.orgId, group, 2);//2 for group
// you can now access the currently saved group with the variable group... nice!
})
.catch(error => {
// Ooops, do some error-handling
console.log(error);
})
}
req.flash('success', 'Contact successfully Added!' );
res.redirect('/accounts/contacts');
});
});
//postMethod for search of contact/auto complete
router.post('/contact/autocomplete', secured, async(req, res, next) => {
let contact_query = req.body.contact_query
// console.log(contact_query);
let contacts = [];
const [people, groups] = await Promise.all([
db.Person.findAll({ where: {orgId: req.user.orgId, [Op.or]: [{firstName: {[Op.like]: '%'+contact_query+'%'}}, {lastName: {[Op.like]: '%'+contact_query+'%'}}, {middleName: {[Op.like]: '%'+contact_query+'%'}}]}, include:db.Contact} ),
db.Group.findAll({ where: {orgId: req.user.orgId, [Op.or]: [{name: {[Op.like]: '%'+contact_query+'%'}}, {nameLocal: {[Op.like]: '%'+contact_query+'%'}}]} , include:db.Contact} )
]);
await people.forEach(person =>{
//{name: `Abdul Ola Lateef`, contactType: 1, id: 1} /*2ND 1 = person */
//id is contact.id
contacts.push({name:`${person.firstName} ${person.middleName} ${person.lastName}`, contactType: 1 , id: person.Contact.id});
})
await groups.forEach(group =>{
//{name: `Optisoft tech`, contactType: 2, id: 1} /*2ND 2 = group */
//id is contact.id
contacts.push({name:`${group.name}`, contactType: 2 , id: group.Contact.id});
})
res.json(contacts);
});
function makeContactReference(orgId, contact, contactType){
if(contactType == 1){//individual
db.Contact.create({orgId, personId:contact.id, contactType})
.catch(error=>console.log(error));
}
else{
db.Contact.create({orgId, groupId:contact.id, contactType})
.catch(error=>console.log(error));
}
}
/////////////////////////////////
//////////payments/////////////////
//get method/route for all payments,
router.get('/payments', secured, async(req, res, next) =>{
const [ payments ] = await Promise.all([
db.Payment.findAll({where: {orgId: req.user.orgId}, include: [ {model:db.Contact, as:'contactFrom', include:['person', 'group']}, {model:db.Contact, as:'contactTo', include:['person', 'group']}, 'paymentMethod', 'invoice'], order: [ ['createdAt', 'DESC'],]}),
]);
res.render('account/payment/index', { payments});
});
router.get('/payments/create', secured, async(req, res, next) =>{
const [ invoices, paymentMethods ] = await Promise.all([
db.Invoice.findAll({where: {orgId: req.user.orgId, [Op.or]: [{statusId: {[Op.eq]: 3 /* sent */}}, {statusId: {[Op.eq]: 4 /* received */}}, {statusId: {[Op.eq]: 9 /* partial */}}] }, include: [ {model:db.Contact, as:'contactFrom', include:['person', 'group']}, {model:db.Contact, as:'contactTo', include:['person', 'group']}]}),
db.PaymentMethod.findAll({ })
]);
// console.log(invoices)
res.render('account/payment/create', { invoices, paymentMethods});
});
//just some converter, doesnt work in helper
router.post('/getInvoiceContact', secured, async(req, res, next)=>{
// const invoice = req.body.uuid
console.log(req.body)
let partyFromId = req.body.partyFromId;
let partyToId = req.body.partyToId;
let partyId;
if(partyFromId ){
partyId = partyFromId
const [contact] = await Promise.all([
db.Contact.findOne({where:{id:partyId}, include:['person', 'group'] })
])
if(contact.contactType == 1){
contactObj = {name: contact.person.firstName +" "+ contact.person.lastName, id:contact.id}
}
else{
contactObj = {name: contact.group.name, id:contact.id}
}
// console.log(contactObj)
return res.json(contactObj);
}
else if(partyToId){
partyId = partyToId;
const [contact] = await Promise.all([
db.Contact.findOne({where:{id:partyId}, include:['person', 'group']})
])
if(contact.contactType == 1){
contactObj = {name: contact.person.firstName +" "+ contact.person.lastName, id:contact.id}
}
else{
contactObj = {name: contact.group.name, id:contact.id}
}
// console.log(contactObj)
return res.json(contactObj);
}
})
function saveFile(file){
const name = `${Math.floor(Date.now() / 1000)}_${Math.round(Math.random() * 10000)}.${file.name.split('.').pop()}`;
const dest = path.join(__dirname, '..', 'public', 'assets', 'images', 'contacts', name);
const data = fs.readFileSync(file.path);
fs.writeFileSync(dest, data);
fs.unlinkSync(file.path);
// uploadInfo.fileSize = fileUpload.size;
// uploadInfo.fileType = fileUpload.type;
return name;
}
function sendMail(templateName, data){
//create the path of email template folder
var templateDir = path.join(__dirname, "../", 'views', 'emails', templateName)
email
.send({
template: templateDir,
message: {
to: 'muilat.champ@gmail.com',
// attachments: [
// {
// filename: 'text1.txt',
// content: 'hello world!'
// }
// ]
},
locals: {
data: data
}
})
.then(res => {
console.log('res.originalMessage', res.originalMessage)
})
.catch(console.error);
}
module.exports = router;