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