From 46c7faf67d023eaef7898c6d839be1fde6707dc3 Mon Sep 17 00:00:00 2001 From: Nandinbold Norovsambuu Date: Fri, 30 Dec 2022 11:34:06 +0800 Subject: [PATCH] feat(timeclock): refactor and add cron --- .../plugin-timeclock-api/cronjobs/timelock.ts | 129 --------- packages/plugin-timeclock-api/package.json | 3 +- packages/plugin-timeclock-api/src/configs.ts | 9 +- .../src/cronjobs/timelock.ts | 29 ++ .../src/graphql/resolvers/mutations.ts | 30 +- .../src/graphql/resolvers/utils.ts | 9 + .../src/graphql/schema.ts | 7 + .../plugin-timeclock-api/src/messageBroker.ts | 11 + .../src/models/definitions/timeclock.ts | 25 ++ packages/plugin-timeclock-api/src/utils.ts | 256 ++++++++++++++++++ .../components/timeclock/TimeclockList.tsx | 24 +- .../src/components/timeclock/TimeclockRow.tsx | 17 +- .../src/containers/timeclock/TimeFormList.tsx | 6 +- .../containers/timeclock/TimeclockList.tsx | 21 +- .../src/graphql/mutations.ts | 18 +- .../src/graphql/queries.ts | 5 + packages/plugin-timeclock-ui/src/types.ts | 7 + 17 files changed, 446 insertions(+), 160 deletions(-) delete mode 100644 packages/plugin-timeclock-api/cronjobs/timelock.ts create mode 100644 packages/plugin-timeclock-api/src/cronjobs/timelock.ts create mode 100644 packages/plugin-timeclock-api/src/utils.ts diff --git a/packages/plugin-timeclock-api/cronjobs/timelock.ts b/packages/plugin-timeclock-api/cronjobs/timelock.ts deleted file mode 100644 index 81ad45caf0a..00000000000 --- a/packages/plugin-timeclock-api/cronjobs/timelock.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { Sequelize, DataTypes, Op } from 'sequelize'; -import { generateModels, models } from '../src/connectionResolver'; - -/** - * Connects to mysql server and extracts - */ - -export interface ITimeClock { - userId?: string; - employeeId?: string; - shiftStart: Date; - shiftEnd?: Date; - shiftActive?: boolean; - branchName?: number; - latitude?: number; -} - -export const connectToMysql = async (req, res) => { - const sequelize = new Sequelize('testt', 'nandi', 'password', { - host: 'localhost', - dialect: 'mysql', - define: { freezeTableName: true } - }); - - sequelize - .authenticate() - .then(() => { - console.log('Connection has been established successfully.'); - }) - .catch(error => { - console.error('Unable to connect to the database: ', error); - }); - - const Timeclock = sequelize.define( - '`dbo.attLog`', - { - ID: { - type: DataTypes.STRING - }, - authDateTime: { - type: DataTypes.DATE - }, - authDate: { - type: DataTypes.DATEONLY - }, - authTime: { - type: DataTypes.TIME - }, - direction: { - type: DataTypes.STRING - }, - deviceName: { - type: DataTypes.STRING - }, - deviceSerialNo: { - type: DataTypes.STRING - }, - employeeName: { - type: DataTypes.STRING - }, - cardNo: { - type: DataTypes.STRING - } - }, - { timestamps: false } - ); - - const data = extractAllData(Timeclock); - // console.log('111111', data); - - // for (const timeRow of data) { - - // } - - // extractNewData(Timeclock); - res.json('success'); -}; - -const extractAllData = (db: any) => { - let data; - const timeclockData: ITimeClock[] = []; - - db.findAll({ - raw: true, - order: [ - ['ID', 'ASC'], - ['authDateTime', 'ASC'] - ], - limit: 10 - }) - .then(response => { - data = JSON.parse(JSON.stringify(response)); - for (const row of data) { - // console.log('heheh', row); - // const empId = row._ID; - // const branch = row.deviceName; - // const empName = row.employeeName; - // const getEarliestTime = row.authDateTime; - // const getLatestTime = row.authDateTime; - // console.log('hjehhehehhe', empId, branch, empName); - // const time = models?.Timeclocks.createTimeClock({ - // shiftStart: getEarliestTime, - // shiftEnd: getLatestTime, - // shiftActive: false - // }); - } - }) - .catch(error => { - console.error('Failed to retrieve data : ', error); - }); - - return data; -}; - -const extractNewData = (db: any) => { - // find all time clock of today - const time = new Date('2022-12-22'); - - const arr = db - .findAll({ - raw: true, - authDateTime: { - where: { [Op.gte]: time } - } - }) - .then(res => { - // console.log('22222222222222', res); - }); -}; diff --git a/packages/plugin-timeclock-api/package.json b/packages/plugin-timeclock-api/package.json index 4624fee6515..4d28f35f119 100644 --- a/packages/plugin-timeclock-api/package.json +++ b/packages/plugin-timeclock-api/package.json @@ -8,6 +8,7 @@ "start": "cd .erxes/dist/plugin-timeclock-api/.erxes && node src" }, "dependencies": { - "mysql2": "^2.3.3" + "mysql2": "^2.3.3", + "dayjs": "1.8.15" } } diff --git a/packages/plugin-timeclock-api/src/configs.ts b/packages/plugin-timeclock-api/src/configs.ts index 12acaec4e26..8551b9836af 100644 --- a/packages/plugin-timeclock-api/src/configs.ts +++ b/packages/plugin-timeclock-api/src/configs.ts @@ -4,8 +4,7 @@ import resolvers from './graphql/resolvers'; import { initBroker } from './messageBroker'; import { getSubdomain } from '@erxes/api-utils/src/core'; import { generateModels } from './connectionResolver'; -import { connectToMysql } from '../cronjobs/timelock'; -import * as cors from 'cors'; +import cronjobs from './cronjobs/timelock'; export let mainDb; export let debug; @@ -23,6 +22,10 @@ export default { }; }, + meta: { + cronjobs + }, + apolloServerContext: async (context, req) => { const subdomain = getSubdomain(req); const models = await generateModels(subdomain); @@ -37,8 +40,6 @@ export default { mainDb = options.db; const app = options.app; - app.get('/mysql', connectToMysql); - initBroker(options.messageBrokerClient); graphqlPubsub = options.pubsubClient; diff --git a/packages/plugin-timeclock-api/src/cronjobs/timelock.ts b/packages/plugin-timeclock-api/src/cronjobs/timelock.ts new file mode 100644 index 00000000000..96694e18080 --- /dev/null +++ b/packages/plugin-timeclock-api/src/cronjobs/timelock.ts @@ -0,0 +1,29 @@ +import * as dayjs from 'dayjs'; +import { getEnv } from '@erxes/api-utils/src'; +import { connectAndQueryFromMySql } from '../utils'; + +const connectAndImportFromMysql = async (subdomain: string) => { + const MYSQL_TABLE = getEnv({ name: 'MYSQL_TABLE' }); + + // get time data from yesterday till now + const format = 'YYYY-MM-DD HH:mm:ss'; + const NOW = dayjs(Date.now()); + const YESTERDAY = NOW.add(-1, 'day'); + + const query = + 'SELECT * FROM `' + + MYSQL_TABLE + + '` WHERE authDateTime >= "' + + YESTERDAY.format(format) + + '" AND authDateTime <= "' + + NOW.format(format) + + '" ORDER by ID, authDateTime'; + + return await connectAndQueryFromMySql(subdomain, query); +}; + +export default { + handleDailyJob: async ({ subdomain }) => { + await connectAndImportFromMysql(subdomain); + } +}; diff --git a/packages/plugin-timeclock-api/src/graphql/resolvers/mutations.ts b/packages/plugin-timeclock-api/src/graphql/resolvers/mutations.ts index 4e26324ba8a..7841c093b4c 100644 --- a/packages/plugin-timeclock-api/src/graphql/resolvers/mutations.ts +++ b/packages/plugin-timeclock-api/src/graphql/resolvers/mutations.ts @@ -7,7 +7,7 @@ import { ITimeClock, IAbsenceType } from '../../models/definitions/timeclock'; -import { findBranches } from './utils'; +import { connectAndImportFromMysql, findBranches } from './utils'; interface ITimeClockEdit extends ITimeClock { _id: string; @@ -40,7 +40,7 @@ const timeclockMutations = { */ async timeclockStart( _root, - { userId, longitude, latitude }, + { userId, longitude, latitude, deviceType }, { models, user, subdomain }: IContext ) { // convert long, lat into radians @@ -48,7 +48,7 @@ const timeclockMutations = { const latRad = (latitude * Math.PI) / 180; let insideCoordinate = false; - + let getBranchName; const EARTH_RADIUS = 6378.14; const branches = await findBranches(subdomain, user._id); @@ -76,6 +76,7 @@ const timeclockMutations = { // if user's coordinate is within the radius if (dist * 1000 <= branch.radius) { insideCoordinate = true; + getBranchName = branch.title; } } @@ -85,7 +86,9 @@ const timeclockMutations = { timeclock = await models.Timeclocks.createTimeClock({ shiftStart: new Date(), shiftActive: true, - userId: userId ? `${userId}` : user._id + userId: userId ? `${userId}` : user._id, + branchName: getBranchName, + deviceType: `${deviceType}` }); } else { throw new Error('User not in the coordinate'); @@ -96,7 +99,7 @@ const timeclockMutations = { async timeclockStop( _root, - { _id, userId, longitude, latitude, ...doc }: ITimeClockEdit, + { _id, userId, longitude, latitude, deviceType, ...doc }: ITimeClockEdit, { models, subdomain, user }: IContext ) { const timeclock = await models.Timeclocks.findOne({ @@ -144,9 +147,14 @@ const timeclockMutations = { let updated; if (insideCoordinate) { + const getShiftStartDeviceType = ( + await models.Timeclocks.getTimeClock(_id) + ).deviceType; + updated = await models.Timeclocks.updateTimeClock(_id, { shiftEnd: new Date(), shiftActive: false, + deviceType: getShiftStartDeviceType + ' + ' + deviceType, ...doc }); } else { @@ -384,13 +392,6 @@ const timeclockMutations = { { _id, name, startDate, endDate, doc }, { models }: IContext ) { - // const updated = models.Absences.updateAbsence(_id, { - // holidayName: name, - // startTime: startDate, - // endTime: endDate, - // status: 'Holiday', - // ...doc - // }); return models.Absences.updateAbsence(_id, { holidayName: name, startTime: startDate, @@ -402,6 +403,11 @@ const timeclockMutations = { holidayRemove(_root, { _id }, { models }: IContext) { return models.Absences.removeAbsence(_id); + }, + + async extractAllDataFromMySQL(_root, {}, { subdomain }: IContext) { + const ret = await connectAndImportFromMysql(subdomain); + return ret; } }; diff --git a/packages/plugin-timeclock-api/src/graphql/resolvers/utils.ts b/packages/plugin-timeclock-api/src/graphql/resolvers/utils.ts index 6ab2a2b5aeb..8aa8ccb2bac 100644 --- a/packages/plugin-timeclock-api/src/graphql/resolvers/utils.ts +++ b/packages/plugin-timeclock-api/src/graphql/resolvers/utils.ts @@ -1,6 +1,8 @@ import { IModels } from '../../connectionResolver'; import { sendCoreMessage } from '../../messageBroker'; +import { connectAndQueryFromMySql } from '../../utils'; import { IUserReport } from '../../models/definitions/timeclock'; +import { getEnv } from '@erxes/api-utils/src'; export const findDepartment = async (subdomain: string, target) => { const department = await sendCoreMessage({ @@ -216,3 +218,10 @@ export const returnReportByUserIds = async ( groupTotalMinsScheduled ]; }; + +export const connectAndImportFromMysql = async (subdomain: string) => { + const MYSQL_TABLE = getEnv({ name: 'MYSQL_TABLE' }); + const query = 'select * from `' + MYSQL_TABLE + '` order by ID, authDateTime'; + + return await connectAndQueryFromMySql(subdomain, query); +}; diff --git a/packages/plugin-timeclock-api/src/graphql/schema.ts b/packages/plugin-timeclock-api/src/graphql/schema.ts index 7c75b057360..7aa63172fbf 100644 --- a/packages/plugin-timeclock-api/src/graphql/schema.ts +++ b/packages/plugin-timeclock-api/src/graphql/schema.ts @@ -16,6 +16,11 @@ export const types = ` shiftStart: Date shiftEnd: Date shiftActive: Boolean + employeeUserName: String + branchName: String + deviceName: String + employeeId: Int + deviceType: String } type Absence { @@ -123,6 +128,7 @@ const params = ` _id: String longitude: Float latitude: Float + deviceType: String `; const absence_params = ` @@ -166,4 +172,5 @@ export const mutations = ` holidayRemove(_id: String): JSON scheduleRemove(_id: String): JSON scheduleShiftRemove(_id: String): JSON + extractAllDataFromMySQL: [Timeclock] `; diff --git a/packages/plugin-timeclock-api/src/messageBroker.ts b/packages/plugin-timeclock-api/src/messageBroker.ts index 4a9b3ed4d3a..1055480b1d2 100644 --- a/packages/plugin-timeclock-api/src/messageBroker.ts +++ b/packages/plugin-timeclock-api/src/messageBroker.ts @@ -16,6 +16,17 @@ export const sendCoreMessage = async (args: ISendMessageArgs): Promise => { }); }; +export const sendFormsMessage = async ( + args: ISendMessageArgs +): Promise => { + return sendMessage({ + client, + serviceDiscovery, + serviceName: 'forms', + ...args + }); +}; + export default function() { return client; } diff --git a/packages/plugin-timeclock-api/src/models/definitions/timeclock.ts b/packages/plugin-timeclock-api/src/models/definitions/timeclock.ts index bff67c9dd68..ba84361f940 100644 --- a/packages/plugin-timeclock-api/src/models/definitions/timeclock.ts +++ b/packages/plugin-timeclock-api/src/models/definitions/timeclock.ts @@ -3,9 +3,14 @@ import { field } from './utils'; export interface ITimeClock { userId?: string; + employeeId?: number; + employeeUserName?: string; shiftStart: Date; shiftEnd?: Date; shiftActive?: boolean; + branchName?: string; + deviceName?: string; + deviceType?: string; longitude?: number; latitude?: number; } @@ -90,6 +95,26 @@ export const timeSchema = new Schema({ type: Boolean, label: 'Is shift started and active', default: false + }), + branchName: field({ + type: String, + label: 'Name of branch where user clocked in / out' + }), + deviceName: field({ + type: String, + label: 'Device name, which user used to clock in / out ' + }), + employeeUserName: field({ + type: String, + label: 'Employee user name, as saved on companys terminal' + }), + employeeId: field({ + type: Number, + label: 'Employee id, custom field' + }), + deviceType: field({ + type: String, + label: 'Which device used for clock in/out' }) }); diff --git a/packages/plugin-timeclock-api/src/utils.ts b/packages/plugin-timeclock-api/src/utils.ts new file mode 100644 index 00000000000..bc2ca2ee6f8 --- /dev/null +++ b/packages/plugin-timeclock-api/src/utils.ts @@ -0,0 +1,256 @@ +import { generateModels, IModels } from './connectionResolver'; +import { sendCoreMessage, sendFormsMessage } from './messageBroker'; +import { ITimeClock, IUserReport } from './models/definitions/timeclock'; +import * as mysql from 'mysql2'; +import * as dayjs from 'dayjs'; +import { getEnv } from '@erxes/api-utils/src'; +import { IUserDocument } from '@erxes/api-utils/src/types'; + +const findUserByEmployeeId = async (subdomain: string, empId: number) => { + const field = await sendFormsMessage({ + subdomain, + action: 'fields.findOne', + data: { + query: { + code: 'employeeId' + } + }, + isRPC: true + }); + + let user: IUserDocument; + + if (field) { + user = await sendCoreMessage({ + subdomain, + action: 'users.findOne', + data: { + customFieldsData: { $elemMatch: { field: field._id, value: empId } } + }, + isRPC: true + }); + + return user; + } else { + return null; + } +}; + +const connectAndQueryFromMySql = async (subdomain: string, query: string) => { + const MYSQL_HOST = getEnv({ name: 'MYSQL_HOST ' }); + const MYSQL_DB = getEnv({ name: 'MYSQL_DB' }); + const MYSQL_USERNAME = getEnv({ name: 'MYSQL_USERNAME' }); + const MYSQL_PASSWORD = getEnv({ name: 'MYSQL_PASSWORD' }); + + // create the connection to mySQL database + const connection = mysql.createConnection({ + host: MYSQL_HOST, + user: MYSQL_USERNAME, + password: MYSQL_PASSWORD, + database: MYSQL_DB + }); + + connection.connect(err => { + if (err) { + console.error('error connecting: ' + err.stack); + return; + } + }); + + let returnData; + connection.query(query, async (error, results) => { + if (error) { + throw new Error(`error: ${error}`); + } + + returnData = await importDataAndCreateTimeclock(subdomain, results); + }); + + return returnData; +}; + +const importDataAndCreateTimeclock = async ( + subdomain: string, + queryData: any +) => { + const returnData: ITimeClock[] = []; + const models: IModels = await generateModels(subdomain); + let currentEmpId = -9999999999; + let currentEmpData: any; + + for (const queryRow of queryData) { + const empId = queryRow.ID; + if (empId === currentEmpId) { + continue; + } else { + currentEmpId = empId; + + // if given employee id is number, extract all employee timeclock data + const empIdNumber = parseInt(empId, 10); + if (empIdNumber) { + currentEmpData = queryData.filter(row => row.ID === currentEmpId); + + returnData.push( + ...(await createUserTimeclock( + subdomain, + models, + empIdNumber, + queryRow.employeeName, + currentEmpData + )) + ); + } + } + } + + await models.Timeclocks.insertMany(returnData); + + return models.Timeclocks.find(); +}; + +const createUserTimeclock = async ( + subdomain: string, + models: IModels, + empId: number, + empName: string, + empData: any +) => { + const returnUserData: ITimeClock[] = []; + const user = await findUserByEmployeeId(subdomain, empId); + + // find if there's any unfinished shift from previous timeclock data + const unfinishedShifts = await models?.Timeclocks.find({ + shiftActive: true, + $or: [{ userId: user && user._id }, { employeeId: empId }] + }); + + for (const unfinishedShift of unfinishedShifts) { + const getShiftStart = dayjs(unfinishedShift.shiftStart); + + // find the potential shift end, which must be 30 mins later and within 16 hrs from shift start + const getShiftIdx = empData.findIndex( + row => + dayjs(row.authDateTime) > getShiftStart.add(30, 'minute') && + dayjs(row.authDateTime) < getShiftStart.add(16, 'hour') + ); + + if (getShiftIdx !== -1) { + const potentialShiftEnd = empData[getShiftIdx].authDateTime; + + // get reverse array + const reverseEmpData = empData.slice().reverse(); + + // find the latest time for shift end + const findLatestShiftEndIdx = reverseEmpData.findIndex( + row => + dayjs(row.authDateTime) < dayjs(potentialShiftEnd).add(30, 'minute') + ); + + const latestShiftIdx = empData.length - 1 - findLatestShiftEndIdx; + + await models.Timeclocks.updateTimeClock(unfinishedShift._id, { + userId: user?._id, + shiftStart: unfinishedShift.shiftStart, + shiftEnd: new Date(empData[latestShiftIdx].authDateTime), + shiftActive: false + }); + + // remove those shift(s) from emp Data + empData.splice(getShiftIdx, latestShiftIdx - getShiftIdx + 1); + } + } + + // filter emp data, get First In, Last Out time + for (let i = 0; i < empData.length; i++) { + const currShiftStart = empData[i].authDateTime; + // consider shift end as 10 mins after shift start + const getShiftEndIdx = empData.findIndex( + row => + dayjs(row.authDateTime) > dayjs(currShiftStart).add(10, 'minute') && + dayjs(row.authDateTime) < dayjs(currShiftStart).add(16, 'hour') + ); + + // if no shift end is found, shift is stilll active + if (getShiftEndIdx === -1) { + const newTimeclock = { + shiftStart: new Date(currShiftStart), + userId: user?._id, + deviceName: empData[i].deviceName, + employeeUserName: empName || undefined, + employeeId: empId, + shiftActive: true, + deviceType: 'faceTerminal' + }; + + if (!(await checkTimeClockAlreadyExists(newTimeclock, models))) { + returnUserData.push(newTimeclock); + } + continue; + } + + let currShiftEnd = empData[getShiftEndIdx].authDateTime; + + // get reverse array + const reverseEmpData = empData.slice().reverse(); + + // find the latest time for shift end + const findLatestShiftEndIdx = reverseEmpData.findIndex( + row => dayjs(row.authDateTime) < dayjs(currShiftEnd).add(30, 'minute') + ); + + i = empData.length - 1 - findLatestShiftEndIdx; + currShiftEnd = empData[i].authDateTime; + + const newTimeclockData = { + shiftStart: new Date(currShiftStart), + shiftEnd: new Date(currShiftEnd), + userId: user?._id, + deviceName: empData[getShiftEndIdx].deviceName || undefined, + employeeUserName: empName || undefined, + employeeId: empId, + shiftActive: false, + deviceType: 'faceTerminal' + }; + + if (!(await checkTimeClockAlreadyExists(newTimeclockData, models))) { + returnUserData.push(newTimeclockData); + } + } + + return returnUserData; +}; + +const checkTimeClockAlreadyExists = async ( + userData: ITimeClock, + models: IModels +) => { + let alreadyExists = false; + + // check if time log already exists in mongodb + const existingTimeclocks = await models.Timeclocks.find({ + $or: [ + { + userId: userData.userId + }, + { + employeeUserName: userData.employeeUserName + }, + { employeeId: userData.employeeId } + ] + }); + + // find duplicates and not include them in new timeclock data + const findExistingTimeclock = existingTimeclocks.find( + existingShift => + existingShift.shiftStart.getTime() === userData.shiftStart?.getTime() || + existingShift.shiftEnd?.getTime() === userData.shiftEnd?.getTime() + ); + + if (findExistingTimeclock) { + alreadyExists = true; + } + + return alreadyExists; +}; + +export { connectAndQueryFromMySql }; diff --git a/packages/plugin-timeclock-ui/src/components/timeclock/TimeclockList.tsx b/packages/plugin-timeclock-ui/src/components/timeclock/TimeclockList.tsx index f6dafab8870..5b870fe98f7 100755 --- a/packages/plugin-timeclock-ui/src/components/timeclock/TimeclockList.tsx +++ b/packages/plugin-timeclock-ui/src/components/timeclock/TimeclockList.tsx @@ -17,9 +17,15 @@ type Props = { startClockTime?: (userId: string) => void; loading: boolean; getActionBar: (actionBar: any) => void; + extractAllMySqlData: () => void; }; -function List({ timeclocks, startClockTime, getActionBar }: Props) { +function List({ + timeclocks, + startClockTime, + getActionBar, + extractAllMySqlData +}: Props) { const trigger = ( ); + const compareUserName = (a, b) => { + if (a.employeeUserName < b.employeeUserName) { + return -1; + } + if (a.employeeUserName > b.employeeUserName) { + return 1; + } + return 0; + }; + const content = ( @@ -67,11 +84,14 @@ function List({ timeclocks, startClockTime, getActionBar }: Props) { + + + - {timeclocks.map(timeclock => { + {timeclocks.sort(compareUserName).map(timeclock => { return ; })} diff --git a/packages/plugin-timeclock-ui/src/components/timeclock/TimeclockRow.tsx b/packages/plugin-timeclock-ui/src/components/timeclock/TimeclockRow.tsx index a169e10d06f..cb21befcb36 100644 --- a/packages/plugin-timeclock-ui/src/components/timeclock/TimeclockRow.tsx +++ b/packages/plugin-timeclock-ui/src/components/timeclock/TimeclockRow.tsx @@ -51,12 +51,27 @@ class Row extends React.Component { ? '-' : new Date(timeclock.shiftEnd).toLocaleTimeString(); + const overNightShift = + timeclock.shiftEnd && + new Date(timeclock.shiftEnd).toLocaleDateString() !== + new Date(timeclock.shiftStart).toLocaleDateString(); + return ( - + + + + ); diff --git a/packages/plugin-timeclock-ui/src/containers/timeclock/TimeFormList.tsx b/packages/plugin-timeclock-ui/src/containers/timeclock/TimeFormList.tsx index 76c42486527..dad6a6f12b7 100644 --- a/packages/plugin-timeclock-ui/src/containers/timeclock/TimeFormList.tsx +++ b/packages/plugin-timeclock-ui/src/containers/timeclock/TimeFormList.tsx @@ -41,7 +41,8 @@ const ListContainer = (props: FinalProps) => { variables: { userId: `${userId}`, longitude: long, - latitude: lat + latitude: lat, + deviceType: 'XOS' } }) .then(() => { @@ -56,7 +57,8 @@ const ListContainer = (props: FinalProps) => { _id: timeId, userId: `${userId}`, longitude: long, - latitude: lat + latitude: lat, + deviceType: 'XOS' } }) .then(() => { diff --git a/packages/plugin-timeclock-ui/src/containers/timeclock/TimeclockList.tsx b/packages/plugin-timeclock-ui/src/containers/timeclock/TimeclockList.tsx index 0f7b97be277..b8b872a0178 100755 --- a/packages/plugin-timeclock-ui/src/containers/timeclock/TimeclockList.tsx +++ b/packages/plugin-timeclock-ui/src/containers/timeclock/TimeclockList.tsx @@ -7,7 +7,7 @@ import { TimeClockMutationResponse, TimeClockQueryResponse } from '../../types'; import { queries } from '../../graphql'; import React from 'react'; import Spinner from '@erxes/ui/src/components/Spinner'; - +import { mutations } from '../../graphql'; type Props = { queryParams: any; history: any; @@ -27,16 +27,23 @@ type FinalProps = { TimeClockMutationResponse; const ListContainer = (props: FinalProps) => { - const { listTimeclocksQuery } = props; + const { listTimeclocksQuery, extractAllMySqlDataMutation } = props; if (listTimeclocksQuery.loading) { return ; } + const extractAllMySqlData = () => { + extractAllMySqlDataMutation().then(() => { + listTimeclocksQuery.refetch(); + }); + }; + const updatedProps = { ...props, timeclocks: listTimeclocksQuery.timeclocks || [], - loading: listTimeclocksQuery.loading + loading: listTimeclocksQuery.loading, + extractAllMySqlData }; return ; @@ -62,6 +69,12 @@ export default withProps( }, fetchPolicy: 'network-only' }) - }) + }), + graphql( + gql(mutations.extractAllDataFromMySQL), + { + name: 'extractAllMySqlDataMutation' + } + ) )(ListContainer) ); diff --git a/packages/plugin-timeclock-ui/src/graphql/mutations.ts b/packages/plugin-timeclock-ui/src/graphql/mutations.ts index dfa95831ad0..a261c8b86ae 100644 --- a/packages/plugin-timeclock-ui/src/graphql/mutations.ts +++ b/packages/plugin-timeclock-ui/src/graphql/mutations.ts @@ -5,16 +5,16 @@ const clockRemove = ` `; const clockStart = ` - mutation timeclockStart($userId: String, $longitude: Float, $latitude: Float){ - timeclockStart(userId: $userId, longitude: $longitude, latitude: $latitude){ + mutation timeclockStart($userId: String, $longitude: Float, $latitude: Float, $deviceType: String){ + timeclockStart(userId: $userId, longitude: $longitude, latitude: $latitude, deviceType: $deviceType){ _id } } `; const clockStop = ` - mutation timeclockStop( $userId: String, $_id: String, $longitude: Float, $latitude: Float){ - timeclockStop(userId: $userId, _id: $_id, longitude: $longitude, latitude: $latitude){ + mutation timeclockStop( $userId: String, $_id: String, $longitude: Float, $latitude: Float,$deviceType: String){ + timeclockStop(userId: $userId, _id: $_id, longitude: $longitude, latitude: $latitude, deviceType : $deviceType){ _id } } @@ -131,6 +131,13 @@ const scheduleShiftRemove = ` scheduleShiftRemove(_id: $_id) }`; +const extractAllDataFromMySQL = ` +mutation extractAllDataFromMySQL{ + extractAllDataFromMySQL{ + _id + } +}`; + export default { sendScheduleRequest, submitShift, @@ -151,5 +158,6 @@ export default { holidayEdit, holidayRemove, scheduleRemove, - scheduleShiftRemove + scheduleShiftRemove, + extractAllDataFromMySQL }; diff --git a/packages/plugin-timeclock-ui/src/graphql/queries.ts b/packages/plugin-timeclock-ui/src/graphql/queries.ts index 2a882357f4b..c1ccbf8d24c 100644 --- a/packages/plugin-timeclock-ui/src/graphql/queries.ts +++ b/packages/plugin-timeclock-ui/src/graphql/queries.ts @@ -30,6 +30,11 @@ const list = ` user { ${userFields} } + employeeUserName + branchName + employeeId + deviceName + deviceType } } `; diff --git a/packages/plugin-timeclock-ui/src/types.ts b/packages/plugin-timeclock-ui/src/types.ts index 66262a08451..eb7759014dd 100644 --- a/packages/plugin-timeclock-ui/src/types.ts +++ b/packages/plugin-timeclock-ui/src/types.ts @@ -8,6 +8,11 @@ export interface ITimeclock { shiftActive: boolean; user: IUser; shiftEnd: Date; + employeeUserName: string; + employeeId: number; + deviceName: string; + deviceType: string; + branchName: string; } export interface IAbsence { _id: string; @@ -129,6 +134,7 @@ export type MutationVariables = { userId: string; longitude: number; latitude: number; + deviceType?: string; }; export type AbsenceMutationVariables = { _id?: string; @@ -149,6 +155,7 @@ export type ScheduleMutationVariables = { export type TimeClockMutationResponse = { startTimeMutation: (params: { variables: MutationVariables }) => Promise; stopTimeMutation: (params: { variables: MutationVariables }) => Promise; + extractAllMySqlDataMutation: () => Promise; }; export type AbsenceMutationResponse = {
{__('Shift date')} {__('Shift started')} {__('Shift ended')}{__('Overnight')}{__('Branch / Device name')}{__('Device type')} {__('Status')}
{timeclock.user ? : '-'} + {timeclock.user && timeclock.user.details + ? timeclock.user.details.fullName || + `${timeclock.user.details.firstName} ${timeclock.user.details.lastName}` + : timeclock.employeeUserName || timeclock.employeeId} + {shiftDate} {shiftStartTime} {shiftEndTime}{overNightShift ? 'O' : ''} + {timeclock.branchName ? timeclock.branchName : timeclock.deviceName} + {timeclock.deviceType && timeclock.deviceType} {this.shiftBtnTrigger(timeclock.shiftActive)}