%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/opti/workflow/src/routes/
Upload File :
Create Path :
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;

Zerion Mini Shell 1.0