巴林闲侠
2 years ago
10 changed files with 841 additions and 6 deletions
@ -0,0 +1,34 @@ |
|||||
|
/* eslint-disable*/ |
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = dc => { |
||||
|
const DataTypes = dc.ORM; |
||||
|
const sequelize = dc.orm; |
||||
|
const Holiday = sequelize.define("holiday", { |
||||
|
day: { |
||||
|
type: DataTypes.DATEONLY, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: true, |
||||
|
field: "day", |
||||
|
autoIncrement: false, |
||||
|
unique: "holiday_day_uindex" |
||||
|
}, |
||||
|
holiday: { |
||||
|
type: DataTypes.JSONB, |
||||
|
allowNull: true, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "holiday", |
||||
|
autoIncrement: false |
||||
|
} |
||||
|
}, { |
||||
|
tableName: "holiday", |
||||
|
comment: "", |
||||
|
indexes: [] |
||||
|
}); |
||||
|
dc.models.Holiday = Holiday; |
||||
|
return Holiday; |
||||
|
}; |
@ -0,0 +1,142 @@ |
|||||
|
/* eslint-disable*/ |
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = dc => { |
||||
|
const DataTypes = dc.ORM; |
||||
|
const sequelize = dc.orm; |
||||
|
const Overtime = sequelize.define("overtime", { |
||||
|
id: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: true, |
||||
|
field: "id", |
||||
|
autoIncrement: true, |
||||
|
unique: "overtime_id_uindex" |
||||
|
}, |
||||
|
pepUserId: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "pep_user_id", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
startTime: { |
||||
|
type: DataTypes.DATE, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "start_time", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
endTime: { |
||||
|
type: DataTypes.DATE, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "end_time", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
duration: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "duration", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
pepProcessStoryId: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "pep_process_story_id", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
wfProcessState: { |
||||
|
type: DataTypes.STRING, |
||||
|
allowNull: true, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "wf_process_state", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
takeRestWorkday: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
defaultValue: "0", |
||||
|
comment: "工作日调休", |
||||
|
primaryKey: false, |
||||
|
field: "take_rest_workday", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
takeRestDayoff: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
defaultValue: "0", |
||||
|
comment: "普假调休", |
||||
|
primaryKey: false, |
||||
|
field: "take_rest_dayoff", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
takeRestFestivals: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
defaultValue: "0", |
||||
|
comment: "节假日调休", |
||||
|
primaryKey: false, |
||||
|
field: "take_rest_festivals", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
payWorkday: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
defaultValue: "0", |
||||
|
comment: "工作日补偿", |
||||
|
primaryKey: false, |
||||
|
field: "pay_workday", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
payDayoff: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
defaultValue: "0", |
||||
|
comment: "普假补偿", |
||||
|
primaryKey: false, |
||||
|
field: "pay_dayoff", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
payFestivals: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
defaultValue: "0", |
||||
|
comment: "节假日补偿", |
||||
|
primaryKey: false, |
||||
|
field: "pay_festivals", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
compensate: { |
||||
|
type: DataTypes.STRING, |
||||
|
allowNull: true, |
||||
|
defaultValue: null, |
||||
|
comment: "补偿方式", |
||||
|
primaryKey: false, |
||||
|
field: "compensate", |
||||
|
autoIncrement: false |
||||
|
} |
||||
|
}, { |
||||
|
tableName: "overtime", |
||||
|
comment: "", |
||||
|
indexes: [] |
||||
|
}); |
||||
|
dc.models.Overtime = Overtime; |
||||
|
return Overtime; |
||||
|
}; |
@ -0,0 +1,88 @@ |
|||||
|
/* eslint-disable*/ |
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = dc => { |
||||
|
const DataTypes = dc.ORM; |
||||
|
const sequelize = dc.orm; |
||||
|
const Vacate = sequelize.define("vacate", { |
||||
|
id: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: true, |
||||
|
field: "id", |
||||
|
autoIncrement: true, |
||||
|
unique: "vacate_id_uindex" |
||||
|
}, |
||||
|
pepUserId: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "pep_user_id", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
startTime: { |
||||
|
type: DataTypes.DATE, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "start_time", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
endTime: { |
||||
|
type: DataTypes.DATE, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: null, |
||||
|
primaryKey: false, |
||||
|
field: "end_time", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
type: { |
||||
|
type: DataTypes.STRING, |
||||
|
allowNull: true, |
||||
|
defaultValue: null, |
||||
|
comment: "请假类别", |
||||
|
primaryKey: false, |
||||
|
field: "type", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
duration: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: true, |
||||
|
defaultValue: null, |
||||
|
comment: "时长 s", |
||||
|
primaryKey: false, |
||||
|
field: "duration", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
pepProcessStoryId: { |
||||
|
type: DataTypes.INTEGER, |
||||
|
allowNull: false, |
||||
|
defaultValue: null, |
||||
|
comment: "和 项企 workflow_process_history 关联", |
||||
|
primaryKey: false, |
||||
|
field: "pep_process_story_id", |
||||
|
autoIncrement: false |
||||
|
}, |
||||
|
wfProcessState: { |
||||
|
type: DataTypes.STRING, |
||||
|
allowNull: true, |
||||
|
defaultValue: null, |
||||
|
comment: "流程状态", |
||||
|
primaryKey: false, |
||||
|
field: "wf_process_state", |
||||
|
autoIncrement: false |
||||
|
} |
||||
|
}, { |
||||
|
tableName: "vacate", |
||||
|
comment: "", |
||||
|
indexes: [] |
||||
|
}); |
||||
|
dc.models.Vacate = Vacate; |
||||
|
return Vacate; |
||||
|
}; |
@ -0,0 +1,429 @@ |
|||||
|
const schedule = require('node-schedule'); |
||||
|
const moment = require('moment') |
||||
|
|
||||
|
module.exports = function (app, opts) { |
||||
|
const updateAttendance = app.fs.scheduleInit( |
||||
|
// 妥妥流水账 (*^▽^*)
|
||||
|
{ |
||||
|
interval: '34 21 4 * * *', |
||||
|
// interval: '*/3 * * * *',
|
||||
|
immediate: true, |
||||
|
// proRun: true,
|
||||
|
}, |
||||
|
async () => { |
||||
|
console.info('假勤数据更新 ', moment().format('YYYY-MM-DD HH:mm:ss')); |
||||
|
const { workFlow: { processState } } = opts |
||||
|
try { |
||||
|
const startTime = moment() |
||||
|
const { models } = app.fs.dc |
||||
|
const { judgeHoliday } = app.fs.utils |
||||
|
const { clickHouse } = app.fs |
||||
|
const { database: camWorkflow } = clickHouse.camWorkflow.opts.config |
||||
|
const { } = app.fs.utils |
||||
|
|
||||
|
let overtimeNeedData = { |
||||
|
begainTime: { |
||||
|
keyWord: ['加班开始时间'], |
||||
|
require: true, |
||||
|
}, |
||||
|
endTime: { |
||||
|
keyWord: ['加班结束时间'], |
||||
|
require: true, |
||||
|
}, |
||||
|
duration: { |
||||
|
keyWord: ['总时长(小时)'] |
||||
|
}, |
||||
|
compensate: { |
||||
|
keyWord: ['加班补偿'], |
||||
|
require: true, |
||||
|
}, |
||||
|
hrAffirmDuration: { |
||||
|
keyWord: ['人事核定加班小时', '核定加班小时'], |
||||
|
require: true, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
let vacateNeedData = { |
||||
|
begainTime: { |
||||
|
keyWord: ['请假开始时间', '请假起始时间'], |
||||
|
keys: ['leaveStartTime'], |
||||
|
require: true, |
||||
|
}, |
||||
|
endTime: { |
||||
|
keyWord: ['请假结束时间', '请假终止时间'], |
||||
|
keys: ['leaveEndTime'], |
||||
|
require: true, |
||||
|
}, |
||||
|
type: { |
||||
|
keyWord: ['请假类别', '请假类型'], |
||||
|
keys: ['leaveType'], |
||||
|
require: true, |
||||
|
}, |
||||
|
hrAffirmType: { |
||||
|
keyWord: ['核定请假类别'], |
||||
|
}, |
||||
|
duration: { |
||||
|
keyWord: ['请假时长(小时)', '请假小时'], |
||||
|
keys: ['leaveTime'] |
||||
|
}, |
||||
|
hrAffirmDuration: { |
||||
|
keyWord: ['核定请假小时'], |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
const schemaRecursionObj = ({ |
||||
|
jsonSchema, keyWord, targetKeys = [], schemaPath, require |
||||
|
}) => { |
||||
|
let schemaPath_ = JSON.parse(JSON.stringify(schemaPath)) |
||||
|
if (jsonSchema.properties) { |
||||
|
for (let prKey in jsonSchema.properties) { |
||||
|
if ( |
||||
|
keyWord.includes(jsonSchema.properties[prKey].title) |
||||
|
|| targetKeys.includes(prKey) |
||||
|
) { |
||||
|
schemaPath_.push({ |
||||
|
prKey, |
||||
|
...jsonSchema.properties[prKey] |
||||
|
}) |
||||
|
return schemaPath_ |
||||
|
} else if (jsonSchema.properties[prKey].properties) { |
||||
|
schemaPath_.push({ |
||||
|
prKey, |
||||
|
...jsonSchema.properties[prKey] |
||||
|
}) |
||||
|
schemaPath_ = schemaRecursionObj({ |
||||
|
jsonSchema: jsonSchema.properties[prKey], |
||||
|
keyWord, |
||||
|
targetKeys, |
||||
|
schemaPath: schemaPath_, |
||||
|
require, |
||||
|
}) |
||||
|
if (!schemaPath_.length && require) { |
||||
|
console.warn('数据字段查找错误:', jsonSchema.properties); |
||||
|
} |
||||
|
if (schemaPath_.length > schemaPath.length) { |
||||
|
return schemaPath_ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
return schemaPath_ |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const dataRecursionObj = (dataObj, index, needData, lastKeyObj, nd) => { |
||||
|
const keyObj = needData[nd].schemaPath[index] |
||||
|
if (dataObj.hasOwnProperty(keyObj.prKey)) { |
||||
|
if (lastKeyObj.prKey == keyObj.prKey) { |
||||
|
let gotValue = dataObj[keyObj.prKey] |
||||
|
if (keyObj.enum) { |
||||
|
let vIndex = keyObj.enum.findIndex(ke => ke == gotValue) |
||||
|
gotValue = keyObj.enumNames[vIndex] |
||||
|
} |
||||
|
return gotValue |
||||
|
} else { |
||||
|
return dataRecursionObj( |
||||
|
dataObj[keyObj.prKey], |
||||
|
index + 1, |
||||
|
needData, |
||||
|
lastKeyObj, |
||||
|
nd |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const getData = (applyDetail, needData) => { |
||||
|
for (let nd in needData) { |
||||
|
if (needData[nd].noProcess) { |
||||
|
continue |
||||
|
} |
||||
|
if (applyDetail.formSchema) { |
||||
|
const { jsonSchema } = JSON.parse(applyDetail.formSchema) |
||||
|
needData[nd].schemaPath = schemaRecursionObj({ |
||||
|
jsonSchema: jsonSchema || {}, |
||||
|
keyWord: needData[nd]['keyWord'], |
||||
|
targetKeys: needData[nd]['keys'], |
||||
|
schemaPath: [], |
||||
|
require: nd.require |
||||
|
}) |
||||
|
if ( |
||||
|
needData[nd].schemaPath |
||||
|
&& needData[nd].schemaPath.length |
||||
|
) { |
||||
|
const lastKeyObj = needData[nd] |
||||
|
.schemaPath[needData[nd].schemaPath.length - 1] |
||||
|
if (applyDetail.formData) { |
||||
|
const formData = JSON.parse(applyDetail.formData) |
||||
|
needData[nd].value = dataRecursionObj( |
||||
|
formData, 0, needData, lastKeyObj, nd |
||||
|
) |
||||
|
} else { |
||||
|
console.warn( |
||||
|
`表单数据缺失:`, |
||||
|
applyDetail |
||||
|
); |
||||
|
} |
||||
|
} else { |
||||
|
if (needData[nd].require) { |
||||
|
// 记录错误 关键数据没找到
|
||||
|
console.warn( |
||||
|
`数据字段查找错误:${nd.needData[nd]['keyWord'].join('、')}`, |
||||
|
jsonSchema |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
const attendanceRes = await clickHouse.pepEmis.query( |
||||
|
` |
||||
|
SELECT |
||||
|
story.id AS historyId, |
||||
|
story.apply_user AS pepUserId, |
||||
|
story.form_data AS formData, |
||||
|
story.submit_form_data AS submitFormData, |
||||
|
fform.form_schema AS formSchema, |
||||
|
fprocess.name AS processName, |
||||
|
procin.state_ AS state, |
||||
|
fform.id AS formId |
||||
|
` |
||||
|
+ |
||||
|
`,fversion.id AS versionId` + |
||||
|
`,fgroup.name AS groupName` + |
||||
|
` |
||||
|
FROM |
||||
|
workflow_process_history AS story |
||||
|
INNER JOIN workflow_process_version AS fversion |
||||
|
ON fversion.id = story.version_id |
||||
|
INNER JOIN workflow_process_form AS fform |
||||
|
ON fform.id = fversion.form_id |
||||
|
INNER JOIN workflow_process AS fprocess |
||||
|
ON fprocess.id = fform.process_id |
||||
|
INNER JOIN workflow_group AS fgroup |
||||
|
ON fgroup.id = fprocess.group_id |
||||
|
AND fgroup.name = '假勤管理' |
||||
|
INNER JOIN ${camWorkflow}.act_hi_procinst AS procin |
||||
|
ON procin.id_ = story.procinst_id |
||||
|
` |
||||
|
).toPromise() |
||||
|
|
||||
|
let insertCount = 0, updateCount = 0, invalidCount = 0, unCompletedCount = 0, unknowCount = 0 |
||||
|
for (let a of attendanceRes) { |
||||
|
console.log(`处理 ${a.pepUserId}·s ${a.processName}(form:${a.formId} story:${a.historyId}) `); |
||||
|
if (a.processName) { |
||||
|
if ('COMPLETED' == a.state) { |
||||
|
if (a.processName.indexOf('请假') > -1) { |
||||
|
let needData = JSON.parse(JSON.stringify(vacateNeedData)) |
||||
|
getData(a, needData) |
||||
|
const { begainTime, endTime, type, hrAffirmType, duration, hrAffirmDuration } = needData |
||||
|
if (begainTime.value && endTime.value && type.value) { |
||||
|
let durationSec = 0 |
||||
|
if (hrAffirmDuration.value) { |
||||
|
durationSec = parseFloat(hrAffirmDuration.value) * 3600 |
||||
|
} else if (duration.value) { |
||||
|
durationSec = parseFloat(duration.value) * 3600 |
||||
|
} else { |
||||
|
durationSec = moment(endTime.value).diff(moment(begainTime.value), 'second') |
||||
|
} |
||||
|
if (typeof durationSec != 'number' || isNaN(durationSec) || durationSec <= 0) { |
||||
|
console.warn('请假时长计算结果错误', hrAffirmDuration, duration); |
||||
|
invalidCount++ |
||||
|
} else { |
||||
|
|
||||
|
let typeStorage = '' |
||||
|
if (hrAffirmType.value) { |
||||
|
typeStorage = hrAffirmType.value |
||||
|
} else { |
||||
|
typeStorage = type.value |
||||
|
} |
||||
|
|
||||
|
const existRes = await models.Vacate.findOne({ |
||||
|
where: { |
||||
|
pepProcessStoryId: a.historyId |
||||
|
} |
||||
|
}) |
||||
|
let storageD = { |
||||
|
pepUserId: a.pepUserId, |
||||
|
pepProcessStoryId: a.historyId, |
||||
|
startTime: moment(begainTime.value).format('YYYY-MM-DD HH:mm:ss'), |
||||
|
endTime: moment(endTime.value).format('YYYY-MM-DD HH:mm:ss'), |
||||
|
duration: durationSec, |
||||
|
type: typeStorage, |
||||
|
wfProcessState: a.state, |
||||
|
} |
||||
|
if (existRes) { |
||||
|
await models.Vacate.update(storageD, { |
||||
|
where: { |
||||
|
id: existRes.id |
||||
|
} |
||||
|
}) |
||||
|
updateCount++ |
||||
|
} else { |
||||
|
await models.Vacate.create(storageD) |
||||
|
insertCount++ |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
console.warn('必填 value 缺失:', needData,); |
||||
|
console.warn('流程数据:', a); |
||||
|
invalidCount++ |
||||
|
} |
||||
|
} else if (a.processName.indexOf('加班') > -1) { |
||||
|
// 深拷贝所需查询数据
|
||||
|
let needData = JSON.parse(JSON.stringify(overtimeNeedData)) |
||||
|
// 获取表单里的数据并插入 needData
|
||||
|
getData(a, needData) |
||||
|
|
||||
|
const { begainTime, endTime, duration, compensate, hrAffirmDuration } = needData |
||||
|
|
||||
|
if (begainTime.value && endTime.value && hrAffirmDuration.value && compensate.value) { |
||||
|
let durationSec = parseFloat(hrAffirmDuration.value) * 3600 |
||||
|
|
||||
|
if (typeof durationSec != 'number' || isNaN(durationSec || durationSec <= 0)) { |
||||
|
console.warn('加班时长计算结果错误', duration); |
||||
|
invalidCount++ |
||||
|
} else { |
||||
|
// 开始时间
|
||||
|
let begainTime_ = moment(begainTime.value) |
||||
|
// 加上人事确定的时间的结束时间
|
||||
|
let endTimeWithHrAffirm = begainTime_.clone().add(durationSec, 'seconds') |
||||
|
// 定义需要统计的各类变量
|
||||
|
let takeRestWorkday = 0, |
||||
|
takeRestDayoff = 0, |
||||
|
takeRestFestivals = 0, |
||||
|
payWorkday = 0, |
||||
|
payDayoff = 0, |
||||
|
payFestivals = 0 |
||||
|
|
||||
|
// 判断 结束时间在加班当天的时间节点后 也就是说跨天加班了
|
||||
|
if (endTimeWithHrAffirm.isSameOrAfter(begainTime_)) { |
||||
|
let packageSuccess = true |
||||
|
// 考虑加了好多天的流程
|
||||
|
let curday = begainTime_.clone() |
||||
|
while (curday.isSameOrBefore(endTimeWithHrAffirm)) { |
||||
|
let duration_ = 0 |
||||
|
if (curday.isSame(endTimeWithHrAffirm, 'day')) { |
||||
|
// 是同一天
|
||||
|
duration_ = endTimeWithHrAffirm.diff(curday, 'seconds') |
||||
|
} else if (curday.isSame(begainTime_, 'day')) { |
||||
|
// 和开始日期是同一天
|
||||
|
// 同时也说明和结束日期不是同一天
|
||||
|
duration_ = begainTime_.clone() |
||||
|
.endOf('day') |
||||
|
.diff(begainTime_, 'seconds') + 1 |
||||
|
} else { |
||||
|
// 跨了好几天
|
||||
|
// 不但 curday 加 后一天也加
|
||||
|
duration_ = 24 * 3600 |
||||
|
} |
||||
|
const holidayRes = await judgeHoliday(curday.format('YYYY-MM-DD')) |
||||
|
if (holidayRes) { |
||||
|
if (compensate.value && compensate.value.indexOf('调休') >= 0) { |
||||
|
if (holidayRes.workday) { |
||||
|
takeRestWorkday += duration_ |
||||
|
} else if (holidayRes.dayoff) { |
||||
|
takeRestDayoff += duration_ |
||||
|
} else if (holidayRes.festivals) { |
||||
|
takeRestFestivals += duration_ |
||||
|
} else { |
||||
|
let a = 4 |
||||
|
} |
||||
|
} else if (compensate.value && compensate.value.indexOf('补偿') >= 0) { |
||||
|
if (holidayRes.workday) { |
||||
|
payWorkday += duration_ |
||||
|
} else if (holidayRes.dayoff) { |
||||
|
payDayoff += duration_ |
||||
|
} else if (holidayRes.festivals) { |
||||
|
payFestivals += duration_ |
||||
|
} |
||||
|
} else { |
||||
|
console.warn(`加班补偿字段未知:`, compensate.value); |
||||
|
invalidCount++ |
||||
|
packageSuccess = false |
||||
|
break |
||||
|
} |
||||
|
} else { |
||||
|
console.warn(`节假日信息获取失败`, curday.format('YYYY-MM-DD')); |
||||
|
invalidCount++ |
||||
|
packageSuccess = false |
||||
|
break |
||||
|
} |
||||
|
curday = curday.add(1, 'day').startOf('day') |
||||
|
} |
||||
|
if (packageSuccess) { |
||||
|
const existRes = await models.Overtime.findOne({ |
||||
|
where: { |
||||
|
pepProcessStoryId: a.historyId |
||||
|
} |
||||
|
}) |
||||
|
let storageD = { |
||||
|
pepUserId: a.pepUserId, |
||||
|
pepProcessStoryId: a.historyId, |
||||
|
startTime: moment(begainTime.value).format('YYYY-MM-DD HH:mm:ss'), |
||||
|
endTime: moment(endTime.value).format('YYYY-MM-DD HH:mm:ss'), |
||||
|
duration: durationSec, |
||||
|
wfProcessState: a.state, |
||||
|
takeRestWorkday, |
||||
|
takeRestDayoff, |
||||
|
takeRestFestivals, |
||||
|
payWorkday, |
||||
|
payDayoff, |
||||
|
payFestivals, |
||||
|
compensate: compensate.value |
||||
|
} |
||||
|
if (existRes) { |
||||
|
await models.Overtime.update(storageD, { |
||||
|
where: { |
||||
|
id: existRes.id |
||||
|
} |
||||
|
}) |
||||
|
updateCount++ |
||||
|
} else { |
||||
|
await models.Overtime.create(storageD) |
||||
|
insertCount++ |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
console.warn(`结束时间在开始时间之前(unbelievable)`, '开始' + begainTime.value, '结束' + endTime.value, '人事确认结束' + endTimeWithHrAffirm.format()); |
||||
|
invalidCount++ |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
console.warn('必填 value 缺失:', needData,); |
||||
|
console.warn('流程数据:', a); |
||||
|
invalidCount++ |
||||
|
} |
||||
|
} else { |
||||
|
console.warn('假勤分组内不明流程'); |
||||
|
unknowCount++ |
||||
|
} |
||||
|
} else { |
||||
|
unCompletedCount++ |
||||
|
} |
||||
|
} else { |
||||
|
invalidCount++ |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
console.info(` |
||||
|
假勤数据更新 用时 ${moment().diff(startTime, 'seconds')} s |
||||
|
`)
|
||||
|
console.info(` |
||||
|
共:${attendanceRes.length}; |
||||
|
新增:${insertCount}; |
||||
|
更新数据:${updateCount}; |
||||
|
非完成状态流程:${unCompletedCount}; |
||||
|
不明流程:${unknowCount}; |
||||
|
无效(warning):${invalidCount}; |
||||
|
`);
|
||||
|
} catch (error) { |
||||
|
app.fs.logger.error(`sechedule: updateAttendance, error: ${error}`); |
||||
|
} |
||||
|
}); |
||||
|
return { |
||||
|
updateAttendance, |
||||
|
} |
||||
|
} |
@ -0,0 +1,59 @@ |
|||||
|
'use strict'; |
||||
|
const moment = require('moment'); |
||||
|
const request = require('superagent'); |
||||
|
|
||||
|
module.exports = function (app, opts) { |
||||
|
const timorHoliday = app.fs.scheduleInit( |
||||
|
{ |
||||
|
interval: '54 42 4 */7 * * *', |
||||
|
// immediate: true,
|
||||
|
proRun: true, |
||||
|
}, |
||||
|
async () => { |
||||
|
const { timorApiUrl } = opts |
||||
|
const { models } = app.fs.dc |
||||
|
|
||||
|
const existCount = await models.Holiday.count() |
||||
|
|
||||
|
let begainDay = existCount ? moment() : moment('2022-01-01') |
||||
|
let endDay = moment().add(3, 'months').endOf('month') |
||||
|
let checkDay = begainDay.clone() |
||||
|
while (checkDay.isSameOrBefore(endDay)) { |
||||
|
try { |
||||
|
const checkDayStr = checkDay.format('YYYY-MM-DD') |
||||
|
let holidayRes = await request.get( |
||||
|
timorApiUrl + `holiday/info/${checkDayStr}`, |
||||
|
) |
||||
|
let holidayData = holidayRes.body || {} |
||||
|
if (holidayData.code == 0) { |
||||
|
const dbRes = await models.Holiday.findOne({ |
||||
|
where: { |
||||
|
day: checkDayStr |
||||
|
} |
||||
|
}) |
||||
|
if (dbRes) { |
||||
|
await models.Holiday.update({ holiady: holidayData }, { |
||||
|
where: { |
||||
|
day: checkDayStr |
||||
|
} |
||||
|
}) |
||||
|
} else { |
||||
|
await models.Holiday.create({ |
||||
|
day: checkDayStr, |
||||
|
holiady: holidayData |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
checkDay = checkDay.add(1, 'day') |
||||
|
} catch (error) { |
||||
|
console.error(error); |
||||
|
// TODO 发邮件
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
return { |
||||
|
timorHoliday |
||||
|
} |
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
'use strict'; |
||||
|
const moment = require('moment') |
||||
|
const request = require('superagent'); |
||||
|
|
||||
|
module.exports = function (app, opts) { |
||||
|
|
||||
|
async function judgeHoliday (dayStr) { |
||||
|
const { timorApiUrl } = opts |
||||
|
const { models } = app.fs.dc |
||||
|
let dayStr_ = dayStr || moment().format('YYYY-MM-DD') |
||||
|
let holidayData = null |
||||
|
const dbRes = await models.Holiday.findOne({ |
||||
|
where: { |
||||
|
day: dayStr_ |
||||
|
} |
||||
|
}) |
||||
|
if (dbRes) { |
||||
|
holidayData = dbRes.dataValues.holiday |
||||
|
} else { |
||||
|
let holidayRes = await request.get( |
||||
|
timorApiUrl + `holiday/info/${dayStr_}` |
||||
|
) |
||||
|
holidayData = holidayRes.body || {} |
||||
|
} |
||||
|
|
||||
|
if (holidayData && holidayData.code == 0) { |
||||
|
let returnD = { |
||||
|
workday: false, |
||||
|
dayoff: false, |
||||
|
festivals: false, |
||||
|
params: holidayData.type |
||||
|
} |
||||
|
let holidayType = holidayData.type.type |
||||
|
if ( |
||||
|
holidayType == 2 |
||||
|
&& holidayData.holiday |
||||
|
&& holidayData.holiday.wage == 3 |
||||
|
) { |
||||
|
// 正经节假日 3倍工资那种
|
||||
|
// festivals
|
||||
|
returnD.festivals = true |
||||
|
} else if ( |
||||
|
holidayType == 1 |
||||
|
|| ( |
||||
|
holidayType == 2 |
||||
|
&& holidayData.holiday |
||||
|
&& holidayData.holiday.wage < 3 |
||||
|
) |
||||
|
) { |
||||
|
// 普假 休息日非节假日
|
||||
|
returnD.dayoff = true |
||||
|
} else if (holidayType == 0 || holidayType == 3) { |
||||
|
// 工作日或补班
|
||||
|
returnD.workday = true |
||||
|
} |
||||
|
return returnD |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
judgeHoliday |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue