/** * Created by Zhong on 2017/8/11. */ const mongoose = require('mongoose'); const gljMapModel = mongoose.model('std_glj_lib_map'); const gljModel = mongoose.model('std_glj_lib_gljList'); const gljModelBackup = mongoose.model('std_glj_lib_gljList_backup'); const gljClassModel = mongoose.model('std_glj_lib_gljClass'); const gljClassModelBackup = mongoose.model('std_glj_lib_gljClass_backup'); const projectGLJModel = mongoose.model('glj_list'); const projectModel = mongoose.model('projects'); const userModel = mongoose.model('users'); const gljClassTemplateModel = mongoose.model('std_glj_lib_gljClassTemplate'); const compilationModel = mongoose.model('compilation'); const scMathUtil = require('../../../public/scMathUtil').getUtil(); const rationMapModel = mongoose.model('std_ration_lib_map'); const rationModel = mongoose.model('std_ration_lib_ration_items'); const complementaryRationModel = mongoose.model('complementary_ration_items'); import { OprDao } from "./gljMapModel"; import moment from "moment"; import counter from "../../../public/counter/counter"; import async from "async"; let _ = require("lodash"); class GljDao extends OprDao { // 处理单价,将多单价的第一个价格字段,设置成定额价 async setBasePrice(libID) { const gljs = await gljModel.find({ repositoryId: libID }).lean(); const bulks = []; gljs.forEach(glj => { const basePrice = glj.priceProperty && glj.priceProperty.price1 !== undefined && glj.priceProperty.price1 !== null ? glj.priceProperty.price1 : 0; bulks.push({ updateOne: { filter: { ID: glj.ID }, update: { $set: { basePrice, priceProperty: {} } } } }) }); const chunks = _.chunk(bulks, 1000); for (const chunk of chunks) { if (chunk.length) { await gljModel.bulkWrite(chunk); } } } // 处理消耗量,将多消耗量的第一个消耗量字段,设置成消耗量 async setConsumeAmt(sourceLibID, targetLibID) { const sourceGljs = await gljModelBackup.find({ repositoryId: sourceLibID }).lean(); const targetGljs = await gljModel.find({ repositoryId: targetLibID }).lean(); const sourceMap = {}; const sourceIDMap = {}; sourceGljs.forEach(glj => { sourceMap[glj.code] = glj; sourceIDMap[glj.ID] = glj.code; }); const targetMap = {}; targetGljs.forEach(glj => { targetMap[glj.code] = glj; }); const bulks = []; targetGljs.forEach(glj => { const source = sourceMap[glj.code]; if (source && source.component && source.component.length) { const component = []; source.component.forEach(c => { const cCode = sourceIDMap[c.ID]; if (!cCode) { return; } const target = targetMap[cCode]; if (!target) { return; } const newID = target.ID; const consumeAmt = c.consumeAmtProperty ? c.consumeAmtProperty.consumeAmt1 : undefined; component.push({ ID: newID, consumeAmt }); }) bulks.push({ updateOne: { filter: { ID: glj.ID }, update: { $set: { component } } } }) } }); if (bulks.length) { const chunks = _.chunk(bulks, 1000); for (const chunk of chunks) { if (chunk.length) { await gljModel.bulkWrite(chunk); } } } } async copyLib(sourceLibID, targetLibID) { const task = [ this.copyClassData(sourceLibID, targetLibID), this.copyGLJData(sourceLibID, targetLibID) ]; await Promise.all(task); } async copyClassData(sourceLibID, targetLibID) { const sourceClassData = await gljClassModel.find({ repositoryId: sourceLibID }, '-_id').lean(); const insertData = sourceClassData.map(item => ({ ...item, repositoryId: targetLibID })); if (insertData.length) { await gljClassModel.insertMany(insertData); } } async copyGLJData(sourceLibID, targetLibID) { const sourceGLJData = await gljModel.find({ repositoryId: sourceLibID }, '-_id').lean(); const IDMapping = {}; const countData = await counter.counterDAO.getIDAfterCount(counter.moduleName.GLJ, sourceGLJData.length); const countIdx = countData.sequence_value - (sourceGLJData.length - 1); sourceGLJData.forEach((glj, index) => { IDMapping[glj.ID] = countIdx + index; }); const insertData = sourceGLJData.map(glj => { const newComponent = (glj.component || []).map(c => ({ ID: IDMapping[c.ID], consumeAmt: c.consumeAmt })); /* // 设备改材料 const gljType = glj.gljType === 5 ? 201 : glj.gljType; */ return { ...glj, repositoryId: targetLibID, ID: IDMapping[glj.ID], component: newComponent }; }); if (insertData.length) { await gljModel.insertMany(insertData); } } async getReference(repositoryId, gljId) { const gljLib = await gljMapModel.findOne({ ID: repositoryId }); const rationLibIds = gljLib.rationLibs.map(lib => lib.ID); const rationLibs = await rationMapModel.find({ ID: { $in: rationLibIds } }, '-_id ID dispName'); const rationLibNameMapping = {}; rationLibs.forEach(item => { rationLibNameMapping[item.ID] = item.dispName; }); const stdRations = await rationModel.find({ rationRepId: { $in: rationLibIds }, 'rationGljList.gljId': gljId }, '-_id code rationRepId'); const rst = {}; const unknownLib = '未知定额库'; const complementaryLib = '补充定额库'; stdRations.forEach(ration => { const libName = rationLibNameMapping[ration.rationRepId] || unknownLib; if (!rst[libName]) { rst[libName] = []; } rst[libName].push(ration); }); const complementaryRations = await complementaryRationModel.find({ 'rationGljList.gljId': gljId }, '-_id code'); if (complementaryRations.length) { rst[complementaryLib] = []; } complementaryRations.forEach(ration => rst[complementaryLib].push({ code: ration.code })); return rst; } async getUsedInfo(repositoryId, gljId) { let userMap = {}; let userIDList = []; let projectList = await projectGLJModel.find({ "glj_id": gljId }, '-_id project_id').lean(); if (projectList.length > 0) { let projectUserList = await projectModel.find({ 'ID': { $in: _.map(projectList, "project_id") } }, '-_id ID userID').lean(); for (let p of projectUserList) { if (!userMap[p.userID]) { userMap[p.userID] = true; userIDList.push(p.userID); } } let userList = await userModel.find({ '_id': { $in: userIDList } }, '_id username mobile').lean(); for (let u of userList) { userMap[u._id.toString()] = u; } for (let p of projectUserList) { p.username = userMap[p.userID].username; p.mobile = userMap[p.userID].mobile; } return projectUserList } return []; } async getGljTreeSync(gljLibId) { return await gljClassModel.find({ repositoryId: gljLibId }); } getGljTypes(gljLibId, callback) { gljClassModel.find({ "repositoryId": gljLibId, "$or": [{ "isDeleted": null }, { "isDeleted": false }, { deleted: false }] }, '-_id', { lean: true }, function (err, data) { if (err) callback("获取工料机类型错误!", false) else { callback(0, data); } }) } _exist(data, attr) { return data && data[attr] !== 'undefined' && data[attr]; } sortToNumber(datas) { for (let i = 0, len = datas.length; i < len; i++) { let data = datas[i]._doc; if (this._exist(data, 'basePrice')) { data['basePrice'] = parseFloat(data['basePrice']); } if (this._exist(data, 'component')) { for (let j = 0, jLen = data['component'].length; j < jLen; j++) { let comGljObj = data['component'][j]._doc; if (this._exist(comGljObj, 'consumeAmt')) { comGljObj['consumeAmt'] = parseFloat(comGljObj['consumeAmt']); } } } } } async getGljItemsSync(gljLibId) { return await gljModel.find({ repositoryId: gljLibId }, '-_id', { lean: true }); } async getGljItemsByRep(repositoryId, callback = null) { /* let me = this; if (callback === null) { return gljModel.find({"repositoryId": repositoryId}); } else { gljModel.find({"repositoryId": repositoryId},function(err,data){ if(err) callback(true, "") else { me.sortToNumber(data); callback(false,data); } }) }*/ let me = this; let rst = []; //批量获取异步 let functions = []; let count = await gljModel.find({ repositoryId: repositoryId, $or: [{ deleted: null }, { deleted: false }] }).count(); let findCount = Math.ceil(count / 500); for (let i = 0, len = findCount; i < len; i++) { functions.push((function (flag) { return function (cb) { gljModel.find({ repositoryId: repositoryId, deleted: null }, '-_id', { lean: true }, cb).skip(flag).sort({ ID: 1 }).limit(500); } })(i * 500)); } async.parallel(functions, function (err, results) { if (err) { callback(err, null); } else { for (let stdGljs of results) { rst = rst.concat(stdGljs); } me.sortToNumber(rst); callback(0, rst); } }); } getGljItemByType(repositoryId, type, callback) { let me = this; gljModel.find({ "repositoryId": repositoryId, "gljType": type }, function (err, data) { if (err) callback(true, ""); else { me.sortToNumber(data); callback(false, data); } }) }; getGljItem(repositoryId, code, callback) { let me = this; gljModel.find({ "repositoryId": repositoryId, "code": code }, function (err, data) { if (err) callback(true, "") else { me.sortToNumber(data); callback(false, data); } }) }; getGljItems(gljIds, callback) { let me = this; gljModel.find({ "ID": { "$in": gljIds } }, function (err, data) { if (err) callback(true, "") else { me.sortToNumber(data); callback(false, data); } }) }; getGljItemsByCode(repositoryId, codes, callback) { let me = this; gljModel.find({ "repositoryId": repositoryId, "code": { "$in": codes } }, function (err, data) { if (err) callback(true, ""); else { me.sortToNumber(data); callback(false, data); } }) }; updateComponent(libId, oprtor, updateArr, callback) { let parallelFucs = []; for (let i = 0; i < updateArr.length; i++) { parallelFucs.push((function (obj) { return function (cb) { if (typeof obj.component === 'undefined') { obj.component = []; } gljModel.update({ repositoryId: libId, ID: obj.ID }, obj, function (err, result) { if (err) { cb(err); } else { cb(null, obj); } }) } })(updateArr[i])); } parallelFucs.push((function () { return function (cb) { GljDao.updateOprArr({ ID: libId }, oprtor, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) { if (err) { cb(err); } else { cb(null); } }) } })()); async.parallel(parallelFucs, function (err, result) { if (err) { callback(err, '更新组成物错误!', null); } else { callback(null, '成功!', result); } }); } mixUpdateGljItems(repId, lastOpr, updateItems, addItems, rIds, callback) { if (updateItems.length == 0 && rIds.length == 0) { GljDao.addGljItems(repId, lastOpr, addItems, callback); } else if (rIds.length > 0 && updateItems.length > 0) { async.parallel([ function (cb) { GljDao.removeGljItems(repId, lastOpr, rIds, cb); }, function (cb) { GljDao.updateGljItems(repId, lastOpr, updateItems, cb); } ], function (err) { if (err) { callback(true, "Fail to update and delete", false) } else { callback(false, "Save successfully", false); } }) } else if (rIds.length > 0 && updateItems.length === 0) { GljDao.removeGljItems(repId, lastOpr, rIds, callback); } else if (updateItems.length > 0 || addItems.length > 0) { GljDao.updateGljItems(repId, lastOpr, updateItems, function (err, results) { if (err) { callback(true, "Fail to update", false); } else { if (addItems && addItems.length > 0) { GljDao.addGljItems(repId, lastOpr, addItems, callback); } else { callback(false, "Save successfully", results); } } }); } } /*mixUpdateGljItems (repId, lastOpr, updateItems, addItems, rIds, callback) { if (updateItems.length == 0 && rIds.length == 0) { GljDao.addGljItems(repId, lastOpr, addItems, callback); } else if (rIds.length > 0) { GljDao.removeGljItems(repId, lastOpr, rIds, function(err, message, docs) { }); }else{ GljDao.updateGljItems(repId, lastOpr, updateItems, function(err, results){ if (err) { callback(true, "Fail to update", false); } else { if (addItems && addItems.length > 0) { GljDao.addGljItems(repId, lastOpr, addItems, callback); } else { callback(false, "Save successfully", results); } } }); } };*/ static removeGljItems(repId, lastOpr, rIds, callback) { if (rIds && rIds.length > 0) { gljModel.collection.remove({ ID: { $in: rIds } }, null, function (err, docs) { if (err) { callback(true, "Fail to remove", false); } else { GljDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) { if (err) { callback(true, "Fail to update operator", false); } else { callback(false, "Remove successfully", docs); } }); } }) } else { callback(false, "No records were deleted!", null); } } static addGljItems(repId, lastOpr, items, callback) { if (items && items.length > 0) { const codes = []; items.forEach(item => codes.push(item.code)); gljModel.find({ repositoryId: repId, code: { $in: codes } }, '-_id code', { lean: true }, (err, codeData) => { if (err) { callback(true, '判断编码唯一性失败', false); return; } const insertData = []; const failCode = []; items.forEach(item => { const matchData = codeData.find(codeItem => codeItem.code === item.code); if (!matchData) { insertData.push(item); } else { failCode.push(item.code); } }); if (!insertData.length) { callback(false, 'empty data', { insertData, failCode }); return; } counter.counterDAO.getIDAfterCount(counter.moduleName.GLJ, items.length, (counterErr, counterData) => { if (counterErr) { callback(true, '获取人材机ID失败', false); return; } const maxId = counterData.sequence_value; for (let i = 0; i < insertData.length; i++) { insertData[i].ID = (maxId - (insertData.length - 1) + i); insertData[i].repositoryId = repId; } const task = []; insertData.forEach(item => { task.push({ insertOne: { document: item } }); }); gljModel.bulkWrite(task, (insertErr, rst) => { if (insertErr) { callback(true, '新增数据失败', false); return; } GljDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) { if (err) { callback(true, "Fail to update Operator", false); } else { callback(false, "Add successfully", { insertData, failCode }); } }); }); }); }); } else { callback(true, "No source", false); } } static updateGljItems(repId, lastOpr, items, callback) { var functions = []; for (var i = 0; i < items.length; i++) { functions.push((function (doc) { return function (cb) { var filter = {}; if (doc.ID) { filter.ID = doc.ID; } else { filter.repositoryId = repId; filter.code = doc.code; } gljModel.update(filter, doc, cb); }; })(items[i])); } functions.push((function () { return function (cb) { GljDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) { if (err) { cb(err); } else { cb(null); } }) } })()); async.parallel(functions, function (err, results) { callback(err, results); }); } getRationGljIds(rationLibs, callback) { } updateNodes(updateData, lastOpr, callback) { let functions = []; for (let i = 0, len = updateData.length; i < len; i++) { functions.push((function (doc) { return function (cb) { if (doc.updateType === 'update' && !doc.updateData.deleted) { gljClassModel.update({ repositoryId: doc.updateData.repositoryId, ID: doc.updateData.ID }, doc.updateData, function (err) { if (err) { cb(err); } else { cb(null); } }); } else if (doc.updateType === 'update' && doc.updateData.deleted) { gljClassModel.remove({ repositoryId: doc.updateData.repositoryId, ID: doc.updateData.ID }, function (err) { if (err) { cb(err); } else { gljModel.remove({ repositoryId: doc.updateData.repositoryId, gljClass: doc.updateData.ID }, function (err) { if (err) { cb(err); } else { cb(null); } }); } }); } else if (doc.updateType === 'new') { gljClassModel.create(doc.updateData, function (err) { if (err) { cb(err); } else { cb(null); } }); } }; })(updateData[i])); } if (updateData.length > 0) { functions.push((function () { return function (cb) { GljDao.updateOprArr({ ID: updateData[0].updateData.rationRepId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) { if (err) { cb(err); } else { cb(null); } }) } })()); } async.parallel(functions, function (err, results) { if (!err) { err = 0; } callback(err, results); }); } /* updateNodes (repId, lastOpr, nodes, callback) { var functions = []; for (var i=0; i < nodes.length; i++) { functions.push((function(doc) { return function(cb) { gljClassModel.update({ID: doc.ID}, doc, cb); }; })(nodes[i])); } functions.push((function () { return function (cb) { GljDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) { if(err){ cb(err); } else{ cb(null); } }) } })()); async.parallel(functions, function(err, results) { callback(err, results); }); }*/ removeNodes(repId, lastOpr, nodeIds, preNodeId, preNodeNextId, callback) { var functions = []; if (preNodeId != -1) { functions.push((function (nodeId, nextId) { return function (cb) { gljClassModel.update({ ID: nodeId }, { "NextSiblingID": nextId }, cb); }; })(preNodeId, preNodeNextId)); } for (var i = 0; i < nodeIds.length; i++) { functions.push((function (nodeId) { return function (cb) { gljClassModel.update({ ID: nodeId }, { "isDeleted": true }, cb); }; })(nodeIds[i])); } functions.push((function () { return function (cb) { GljDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) { if (err) { cb(err); } else { cb(null); } }) } })()); async.parallel(functions, function (err, results) { callback(err, results); }); } createNewNode(repId, lastOpr, lastNodeId, nodeData, callback) { return counter.counterDAO.getIDAfterCount(counter.moduleName.GLJ, 1, function (err, result) { nodeData.repositoryId = repId; nodeData.ID = result.sequence_value; var node = new gljModel(nodeData); async.parallel([ function (cb) { node.save(function (err, result) { if (err) { cb("章节树ID错误!", false); } else { if (lastNodeId > 0) { gljClassModel.update({ ID: lastNodeId }, { "NextSiblingID": nodeData.ID }, function (err, rst) { if (err) { cb("章节树ID错误!", false); } else { cb(false, result); } }); } else cb(false, result); } }); }, function (cb) { GljDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) { if (err) { cb(err); } else { cb(null); } }) } ], function (err, result) { if (err) { callback(true, "章节树错误!", false); } else { callback(false, '', result[0]); } }) }); } getGljItemsOccupied(repId, occupation, callback) { gljModel.find({ repositoryId: repId }, occupation, function (err, result) { if (err) callback(true, 'fail', null); else callback(false, 'sc', result); }); } async getGljItemsByRepId(repositoryId, returnFields = '') { return gljModel.find({ "repositoryId": repositoryId }, returnFields); } async batchUpdateGljPrice(gljLibId, sheetData) { let gljLib = await gljMapModel.findOne({ ID: gljLibId }); if (!gljLib) { throw '不存在此人材机库'; } let compilation = await compilationModel.findOne({ _id: mongoose.Types.ObjectId(gljLib.compilationId) }); if (!compilation) { throw '不存在此费用定额'; } let priceProperties = compilation.priceProperties ? compilation.priceProperties : []; //根据第一行数据,获取列下标与字段名映射 let colMapping = {}; for (let col = 0; col < sheetData[0].length; col++) { let cData = sheetData[0][col]; if (cData === '编码') { colMapping['code'] = col; } else { if (priceProperties.length === 0) { if (cData === '定额价') { colMapping['basePrice'] = col; break; } } else { for (let priceProp of priceProperties) { if (priceProp.price.dataName === cData) { colMapping[priceProp.price.dataCode] = col; break; } } } } } let colMappingKeys = Object.keys(colMapping); if (colMappingKeys.length < 2) { throw 'excel数据不正确' } let updateBulk = []; //避免重复 let updateCodes = []; //库中存在的人材机 let dateA = Date.now(); let existGljs = await gljModel.find({ repositoryId: gljLibId }, '-_id code ID'); let existMapping = {}; for (let glj of existGljs) { existMapping[glj.code] = glj; } for (let row = 0; row < sheetData.length; row++) { if (row === 0) { continue; } let gljCode = sheetData[row][colMapping.code], existGlj = existMapping[gljCode]; //更新多单价、不覆盖priceProperty字段,覆盖priceProperty下的子字段'priceProperty.x' if (gljCode && gljCode !== '' && !updateCodes.includes(gljCode) && existGlj) { if (priceProperties.length > 0) { for (let priceProp of priceProperties) { let dataCode = priceProp.price.dataCode; let priceCellData = sheetData[row][colMapping[dataCode]]; //Excel中没有这个单价则跳过 if (!colMapping[dataCode]) { continue; } let updateSet = {}; updateSet['priceProperty.' + dataCode] = priceCellData && !isNaN(priceCellData) ? scMathUtil.roundTo(parseFloat(priceCellData), -2) : 0; updateBulk.push({ updateOne: { filter: { ID: existGlj.ID }, update: { $set: updateSet } } }); } updateCodes.push(gljCode); } else { if (colMapping.basePrice) { let priceCellData = sheetData[row][colMapping.basePrice]; let basePrice = priceCellData && !isNaN(priceCellData) ? scMathUtil.roundTo(priceCellData, -2) : 0; updateCodes.push(gljCode); updateBulk.push({ updateOne: { filter: { ID: existGlj.ID }, update: { $set: { basePrice: basePrice } } } }); } } } } if (updateBulk.length > 0) { while (updateBulk.length > 0) { let sliceBulk = updateBulk.splice(0, 1000); await gljModel.bulkWrite(sliceBulk); } } } async importComponents(gljLibId, sheetData) { const gljLib = await gljMapModel.findOne({ ID: gljLibId }); if (!gljLib) { throw '不存在此人材机库'; } const compilation = await compilationModel.findOne({ _id: mongoose.Types.ObjectId(gljLib.compilationId) }); if (!compilation) { throw '不存在此费用定额'; } // 将所有人材机进行编码映射 const allGLJs = await gljModel.find({ repositoryId: gljLibId }, { ID: true, code: true }).lean(); const codeMapping = {}; allGLJs.forEach(glj => codeMapping[glj.code] = glj); // excel表格列号与字段的映射 const colMapping = { // 材料编码 code: 0, // 组成物编码 componentCode: 1, // 组成物消耗量 consumeAmt: 2 }; // 跳过列头 for (let row = 1; row < sheetData.length; row++) { const rowData = sheetData[row]; const code = rowData[colMapping.code]; const componentCode = rowData[colMapping.componentCode]; const consumeAmt = +rowData[colMapping.consumeAmt]; const glj = codeMapping[code]; const component = codeMapping[componentCode]; if (!glj || !component) { continue; } if (!glj.component) { glj.component = []; } glj.component.push({ ID: component.ID, consumeAmt: consumeAmt }); } // 更新数据 const tasks = []; allGLJs.filter(glj => glj.component && glj.component.length).forEach(glj => { tasks.push({ updateOne: { filter: { ID: glj.ID }, update: { $set: { component: glj.component } } } }); }); if (tasks.length) { await gljModel.bulkWrite(tasks); } } } export default GljDao;