巴林闲侠
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