'use strict'; const fs = require('fs'); const moment = require('moment'); //业绩报表相关 async function getReceivedDetail(ctx) { try { const { models } = ctx.fs.dc; const { keywordTarget, keyword, limit, page, toExport } = ctx.query let where = {} if (keywordTarget == 'contract' && keyword) { where.contractNo = { $like: `%${keyword}%` } } let findOption = { where: where, order: [['id', 'ASC']] } if (!toExport) {//非导出时考虑分页 if (limit) { findOption.limit = Number(limit) } if (page && limit) { findOption.offset = Number(page) * Number(limit) } } let res = await models.ReceivableDetail.findAndCountAll(findOption); if (toExport) {//数据导出相关 await exportReceivedDetail(ctx, res.rows); } else { ctx.status = 200 ctx.body = { count: res.count, rows: res.rows }; } } catch (error) { ctx.fs.logger.error(`path:${ctx.path},error:${error}`) ctx.status = 400; ctx.body = { name: 'FindAllError', message: '获取失败' } } } async function exportReceivedDetail(ctx, dataList) { try { let header = [{ title: '年度', key: 'year', }, { title: '序号', key: 'serialNo', }, { title: '编号', key: 'number', }, { title: '部门', key: 'department', }, { title: '销售人员', key: 'sale', }, { title: '合同编号', key: 'contractNo', }, { title: '客户名称', key: 'customer', }, { title: '项目名称', key: 'item', }, { title: '合同金额', key: 'amount', }, { title: '变更后合同金额', key: 'changeAmount', }, { title: '回款年份', key: 'receivableYear', }, { title: '回款日期', key: 'receivableDate', }, { title: '回款金额', key: 'receivableAmount', }, { title: '开票-回款', key: 'invoicedBack', }, { title: '剩余合同金额', key: 'remainConAmount', }, { title: '收入确认时间', key: 'incomeConfirmdate', }, { title: '第三方付款单位', key: 'thirdPayment', }, { title: '备注', key: 'remark', }] const { utils: { simpleExcelDown } } = ctx.app.fs; let exportData = [] for (let { dataValues: item } of dataList) { exportData.push(item) } const fileName = `回款明细表_${moment().format('YYYYMMDDHHmmss')}` + '.xlsx' const filePath = await simpleExcelDown({ data: exportData, header, fileName: fileName, needIndexCell: false }) const fileData = fs.readFileSync(filePath); ctx.status = 200; ctx.set('Content-Type', 'application/x-xls'); ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName)); ctx.body = fileData; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function getAchievementDetail(ctx) { try { const { models } = ctx.fs.dc; const { keywordTarget, keyword, limit, page, toExport } = ctx.query let where = {} if (keywordTarget == 'saler' && keyword) { where.sale = { $like: `%${keyword}%` } } if (keywordTarget == 'line' && keyword) { where.serviceLine = { $like: `%${keyword}%` } } if (keywordTarget == 'dep' && keyword) { where.department = { $like: `%${keyword}%` } } let findOption = { where: where, order: [['id', 'ASC']] } if (!toExport) {//非导出时考虑分页 if (limit) { findOption.limit = Number(limit) } if (page && limit) { findOption.offset = Number(page) * Number(limit) } } let res = await models.PerformanceDetail.findAndCountAll(findOption); if (toExport) {//数据导出相关 await exportAchievementDetail(ctx, res.rows); } else { ctx.status = 200 ctx.body = { count: res.count, rows: res.rows }; } } catch (error) { ctx.fs.logger.error(`path:${ctx.path},error:${error}`) ctx.status = 400; ctx.body = { name: 'FindAllError', message: '获取失败' } } } async function exportAchievementDetail(ctx, dataList) { try { let header = [{ title: '收到合同日期', key: 'recConDate', }, { title: '月份', key: 'month', }, { title: '部门', key: 'department', }, { title: '销售人员', key: 'sale', }, { title: '客户名称', key: 'customer', }, { title: '项目名称', key: 'item', }, { title: '合同金额', key: 'amount', }, { title: '实际业绩', key: 'realPerformance', }, { title: '考核业绩', key: 'assessmentPerformance', }, { title: '价格是否特批', key: 'isApproval', }, { title: '特批折算比例', key: 'approvalProp', }, { title: '预支提成及委外费用', key: 'cost', }, { title: '业务线', key: 'serviceLine', }, { title: '客户类型', key: 'cusType', }, { title: '行业', key: 'industry', }, { title: '信息来源', key: 'source', }, { title: '项目类型', key: 'itemType', }, { title: '客户省份', key: 'cusProvince', }, { title: '客户属性', key: 'cusAttribute', }, { title: '复购次数', key: 'repurchaseCount', }, { title: '是否可复制的业务路径', key: 'reproducible', }, { title: '省外业务', key: 'outProvince', }, { title: '复购业务', key: 'repurchase', }, { title: '可复制的业务路径', key: 'isreproduce', }] const { utils: { simpleExcelDown } } = ctx.app.fs; let exportData = [] for (let { dataValues: item } of dataList) { item.isApproval = JSON.stringify(item.isApproval) === 'null' ? '-' : item.isApproval ? '是' : '否'; item.reproducible = JSON.stringify(item.reproducible) === 'null' ? '-' : item.reproducible ? '是' : '否'; exportData.push(item) } const fileName = `业绩明细表_${moment().format('YYYYMMDDHHmmss')}` + '.xlsx' const filePath = await simpleExcelDown({ data: exportData, header, fileName: fileName }) const fileData = fs.readFileSync(filePath); ctx.status = 200; ctx.set('Content-Type', 'application/x-xls'); ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName)); ctx.body = fileData; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } /** * 查询明细表已存在编号数据,回款、合同、开票通用 * @param {*} ctx ctx ctx.query:{tableModel表模型名} */ async function getReceivedNumbers(ctx) { let errorMsg = { name: 'FindError', message: '查询失败' }; try { const { tableModel } = ctx.query; const models = ctx.fs.dc.models; let modelName = tableModel || 'ReceivableDetail' let list = await models[modelName].findAll({//查编号 attributes: ['number'] }); ctx.status = 200 ctx.body = list; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = errorMsg; } } /** * 导入明细表数据,回款、合同、开票通用 * @param {*} ctx ctx ctx.query:{tableModel表模型名} */ async function importBackDetails(ctx) { let errorMsg = { message: '导入失败' }; const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const data = ctx.request.body; const { tableModel } = ctx.query; let modelName = tableModel || 'ReceivableDetail' let addArr = []; let dataList = await models[modelName].findAll({//查编号 attributes: ['number'] }); data.map(d => { let exist = dataList.find(m => m.dataValues.number == d.number); if (!exist) { addArr.push(d); } }) //只处理新增的 if (addArr.length) { await models[modelName].bulkCreate(addArr, { transaction }); } await transaction.commit(); ctx.status = 204; } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = errorMsg; } } async function importAchieveDetails(ctx) { let errorMsg = { message: '导入业绩明细失败' }; const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const data = ctx.request.body; //业绩明细 没有唯一标识,前端校验后,导啥存啥 if (data.length) { await models.PerformanceDetail.bulkCreate(data); } await transaction.commit(); ctx.status = 204; } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = errorMsg; } } /** * 查询合同明细表数据 * @param {*} ctx ctx ctx.query:{keywordTarget-关键字项、keyword-关键字内容、limit-页宽, page-页码} */ async function getContractDetail(ctx) { try { const { models } = ctx.fs.dc; const { keywordTarget, keyword, limit, page } = ctx.query; const where = {}; if (keywordTarget && keyword) { where[keywordTarget] = { $iLike: `%${keyword}%` }; } let contractDetail = await models.ContractDetail.findAndCountAll({ attributes: { exclude: ['iscopy', 'hiredate', 'regularDate'] }, where: where, offset: Number(page) * Number(limit), limit: Number(limit), order: [['id', 'ASC']] }); ctx.status = 200 ctx.body = contractDetail; } catch (error) { ctx.fs.logger.error(`path:${ctx.path},error:${error}`) ctx.status = 400; ctx.body = { name: 'FindError', message: '查询合同明细表数据失败' } } } /** * 查询开票明细表数据 * @param {*} ctx ctx ctx.query:{keywordTarget-关键字项、keyword-关键字内容、limit-页宽, page-页码} */ async function getInvoicingDetail(ctx) { try { const { models } = ctx.fs.dc; const { keywordTarget, keyword, limit, page } = ctx.query; const where = {}; if (keywordTarget && keyword) { where[keywordTarget] = { $iLike: `%${keyword}%` }; } let invoiceDetail = await models.InvoiceDetail.findAndCountAll({ where: where, offset: Number(page) * Number(limit), limit: Number(limit), order: [['id', 'ASC']] }); ctx.status = 200 ctx.body = invoiceDetail; } catch (error) { ctx.fs.logger.error(`path:${ctx.path},error:${error}`) ctx.status = 400; ctx.body = { name: 'FindError', message: '查询开票明细表数据失败' } } } /** * 导出合同明细表数据 */ async function exportContractDetail(ctx) { try { const { models } = ctx.fs.dc; let exportData = await models.ContractDetail.findAll({ attributes: { exclude: ['iscopy', 'hiredate', 'regularDate'] }, order: [['id', 'ASC']] }); const { utils: { simpleExcelDown, contractDetailsColumnKeys } } = ctx.app.fs; let header = []; Object.keys(contractDetailsColumnKeys).map(key => { header.push({ title: contractDetailsColumnKeys[key], key: key }); }) const fileName = `合同明细表_${moment().format('YYYYMMDDHHmmss')}` + '.xlsx' const filePath = await simpleExcelDown({ data: exportData, header, fileName: fileName, needIndexCell: false }) const fileData = fs.readFileSync(filePath); ctx.status = 200; ctx.set('Content-Type', 'application/x-xls'); ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName)); ctx.body = fileData; } catch (error) { ctx.fs.logger.error(`path:${ctx.path},error:${error}`) ctx.status = 400; ctx.body = { name: 'ExportAllError', message: '导出合同明细表数据失败' } } } /** * 导出开票明细表数据 */ async function exportInvoicingDetail(ctx) { try { const { models } = ctx.fs.dc; let exportData = await models.InvoiceDetail.findAll({ order: [['id', 'ASC']] }); const { utils: { simpleExcelDown, invoicingDetailsColumnKeys } } = ctx.app.fs; let header = []; Object.keys(invoicingDetailsColumnKeys).map(key => { header.push({ title: invoicingDetailsColumnKeys[key], key: key }); }) const fileName = `开票明细表_${moment().format('YYYYMMDDHHmmss')}` + '.xlsx' const filePath = await simpleExcelDown({ data: exportData, header, fileName: fileName, needIndexCell: false }) const fileData = fs.readFileSync(filePath); ctx.status = 200; ctx.set('Content-Type', 'application/x-xls'); ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName)); ctx.body = fileData; } catch (error) { ctx.fs.logger.error(`path:${ctx.path},error:${error}`) ctx.status = 400; ctx.body = { name: 'ExportAllError', message: '导出开票明细表数据失败' } } } module.exports = { getReceivedDetail,//回款 getAchievementDetail,//业绩 getReceivedNumbers,//查询回款、合同、开票明细表 已有的所有编号 importBackDetails,//导入回款、合同、开票明细 importAchieveDetails,//导入业绩明细 getContractDetail, getInvoicingDetail, exportContractDetail, exportInvoicingDetail }