diff --git a/assets/pasted-20260413-130727-e67a0305.png b/assets/pasted-20260413-130727-e67a0305.png new file mode 100644 index 0000000..c288ed6 Binary files /dev/null and b/assets/pasted-20260413-130727-e67a0305.png differ diff --git a/assets/pasted-20260413-131715-2c4e92ec.png b/assets/pasted-20260413-131715-2c4e92ec.png new file mode 100644 index 0000000..bb84091 Binary files /dev/null and b/assets/pasted-20260413-131715-2c4e92ec.png differ diff --git a/backend/src/db/api/payroll_runs.js b/backend/src/db/api/payroll_runs.js index 554b706..c06458c 100644 --- a/backend/src/db/api/payroll_runs.js +++ b/backend/src/db/api/payroll_runs.js @@ -240,9 +240,19 @@ module.exports = class Payroll_runsDBApi { - output.payroll_line_items_payroll_run = await payroll_runs.getPayroll_line_items_payroll_run({ - transaction - }); + output.payroll_line_items_payroll_run = await Promise.all( + (await payroll_runs.getPayroll_line_items_payroll_run({ + transaction + })).map(async (payrollLineItem) => { + const payrollLineItemOutput = payrollLineItem.get({ plain: true }); + + payrollLineItemOutput.employee = await payrollLineItem.getEmployee({ + transaction, + }); + + return payrollLineItemOutput; + }), + ); diff --git a/backend/src/routes/payroll_generator.js b/backend/src/routes/payroll_generator.js index 4adea9d..4503435 100644 --- a/backend/src/routes/payroll_generator.js +++ b/backend/src/routes/payroll_generator.js @@ -5,6 +5,11 @@ const db = require('../db/models'); const { wrapAsync } = require('../helpers'); const { Op } = require('sequelize'); +const getInclusiveDateRange = (startDate, endDate) => ({ + start: new Date(`${startDate}T00:00:00.000Z`), + end: new Date(`${endDate}T23:59:59.999Z`), +}); + router.post('/preview', passport.authenticate('jwt', { session: false }), wrapAsync(async (req, res) => { const { startDate, endDate } = req.body; @@ -12,11 +17,13 @@ router.post('/preview', passport.authenticate('jwt', { session: false }), wrapAs return res.status(400).send('startDate and endDate are required'); } + const { start, end } = getInclusiveDateRange(startDate, endDate); + // Find job logs in range that are not paid const jobLogs = await db.job_logs.findAll({ where: { work_date: { - [Op.between]: [new Date(startDate), new Date(endDate)] + [Op.between]: [start, end] }, status: { [Op.ne]: 'paid' @@ -85,11 +92,13 @@ router.post('/generate', passport.authenticate('jwt', { session: false }), wrapA return res.status(400).send('startDate and endDate are required'); } + const { start, end } = getInclusiveDateRange(startDate, endDate); + // Find job logs const jobLogs = await db.job_logs.findAll({ where: { work_date: { - [Op.between]: [new Date(startDate), new Date(endDate)] + [Op.between]: [start, end] }, status: { [Op.ne]: 'paid' diff --git a/frontend/public/assets/vm-shot-2026-04-13T13-17-17-604Z.jpg b/frontend/public/assets/vm-shot-2026-04-13T13-17-17-604Z.jpg new file mode 100644 index 0000000..dee1594 Binary files /dev/null and b/frontend/public/assets/vm-shot-2026-04-13T13-17-17-604Z.jpg differ diff --git a/frontend/src/components/Job_logs/configureJob_logsCols.tsx b/frontend/src/components/Job_logs/configureJob_logsCols.tsx index 3585223..2f75d3d 100644 --- a/frontend/src/components/Job_logs/configureJob_logsCols.tsx +++ b/frontend/src/components/Job_logs/configureJob_logsCols.tsx @@ -218,52 +218,7 @@ export const loadColumns = async ( }, - { - field: 'odometer_start', - headerName: 'OdometerStart', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'odometer_end', - headerName: 'OdometerEnd', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - type: 'number', - - }, - - { - field: 'job_address', - headerName: 'JobAddress', - flex: 1, - minWidth: 120, - filterable: false, - headerClassName: 'datagrid--header', - cellClassName: 'datagrid--cell', - - - editable: hasUpdatePermission, - - - }, + { field: 'status', diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts index dde7fa5..79f9bd7 100644 --- a/frontend/src/menuAside.ts +++ b/frontend/src/menuAside.ts @@ -84,28 +84,12 @@ const menuAside: MenuAsideItem[] = [ icon: 'mdiLinkVariant' in icon ? icon['mdiLinkVariant' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, permissions: 'UPDATE_USERS' }, - { - href: '/chemical_products/chemical_products-list', - label: 'Chemical products', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiFlask' in icon ? icon['mdiFlask' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'UPDATE_USERS' - }, { href: '/job_logs/job_logs-list', label: 'All Job Logs', icon: 'mdiClipboardTextClock' in icon ? icon['mdiClipboardTextClock' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, permissions: 'UPDATE_USERS' }, - { - href: '/job_chemical_usages/job_chemical_usages-list', - label: 'Job chemical usages', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiFlaskOutline' in icon ? icon['mdiFlaskOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'UPDATE_USERS' - }, { href: '/payroll_runs/payroll_runs-list', label: 'Payroll runs', diff --git a/frontend/src/pages/dashboard.tsx b/frontend/src/pages/dashboard.tsx index dc96fdb..e40be66 100644 --- a/frontend/src/pages/dashboard.tsx +++ b/frontend/src/pages/dashboard.tsx @@ -32,9 +32,7 @@ const Dashboard = () => { const [vehicles, setVehicles] = React.useState(loadingMessage); const [pay_types, setPay_types] = React.useState(loadingMessage); const [employee_pay_types, setEmployee_pay_types] = React.useState(loadingMessage); - const [chemical_products, setChemical_products] = React.useState(loadingMessage); const [job_logs, setJob_logs] = React.useState(loadingMessage); - const [job_chemical_usages, setJob_chemical_usages] = React.useState(loadingMessage); const [payroll_runs, setPayroll_runs] = React.useState(loadingMessage); const [payroll_line_items, setPayroll_line_items] = React.useState(loadingMessage); @@ -58,8 +56,8 @@ const Dashboard = () => { return; } - const entities = ['users','roles','permissions','customers','vehicles','pay_types','employee_pay_types','chemical_products','job_logs','job_chemical_usages','payroll_runs','payroll_line_items',]; - const fns = [setUsers,setRoles,setPermissions,setCustomers,setVehicles,setPay_types,setEmployee_pay_types,setChemical_products,setJob_logs,setJob_chemical_usages,setPayroll_runs,setPayroll_line_items,]; + const entities = ['users','roles','permissions','customers','vehicles','pay_types','employee_pay_types','job_logs','payroll_runs','payroll_line_items',]; + const fns = [setUsers,setRoles,setPermissions,setCustomers,setVehicles,setPay_types,setEmployee_pay_types,setJob_logs,setPayroll_runs,setPayroll_line_items,]; const requests = entities.map((entity, index) => { @@ -355,34 +353,6 @@ const Dashboard = () => { } - {hasPermission(currentUser, 'READ_CHEMICAL_PRODUCTS') && -
-
-
-
- Chemical products -
-
- {chemical_products} -
-
-
- -
-
-
- } - {hasPermission(currentUser, 'READ_JOB_LOGS') &&
{
} - {hasPermission(currentUser, 'READ_JOB_CHEMICAL_USAGES') && -
-
-
-
- Job chemical usages -
-
- {job_chemical_usages} -
-
-
- -
-
-
- } - {hasPermission(currentUser, 'READ_PAYROLL_RUNS') &&
{ - odometer_start: '', @@ -298,7 +297,6 @@ const EditJob_logs = () => { - odometer_end: '', @@ -320,7 +318,6 @@ const EditJob_logs = () => { - 'job_address': '', @@ -875,146 +872,6 @@ const EditJob_logs = () => { > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/pages/job_logs/job_logs-edit.tsx b/frontend/src/pages/job_logs/job_logs-edit.tsx index 44c7dd1..cc79b96 100644 --- a/frontend/src/pages/job_logs/job_logs-edit.tsx +++ b/frontend/src/pages/job_logs/job_logs-edit.tsx @@ -271,7 +271,6 @@ const EditJob_logsPage = () => { - odometer_start: '', @@ -299,7 +298,6 @@ const EditJob_logsPage = () => { - odometer_end: '', @@ -321,7 +319,6 @@ const EditJob_logsPage = () => { - 'job_address': '', @@ -867,146 +864,6 @@ const EditJob_logsPage = () => { > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/pages/job_logs/job_logs-list.tsx b/frontend/src/pages/job_logs/job_logs-list.tsx index 20086f4..4be8c15 100644 --- a/frontend/src/pages/job_logs/job_logs-list.tsx +++ b/frontend/src/pages/job_logs/job_logs-list.tsx @@ -34,8 +34,7 @@ const Job_logsTablesPage = () => { const dispatch = useAppDispatch(); - const [filters] = useState([{label: 'JobAddress', title: 'job_address'},{label: 'NotesToAdmin', title: 'notes_to_admin'}, - {label: 'OdometerStart', title: 'odometer_start', number: 'true'},{label: 'OdometerEnd', title: 'odometer_end', number: 'true'}, + const [filters] = useState([{label: 'NotesToAdmin', title: 'notes_to_admin'}, {label: 'HoursConducted', title: 'hours_conducted', number: 'true'},{label: 'ClientPaid', title: 'client_paid', number: 'true'}, {label: 'WorkDate', title: 'work_date', date: 'true'}, diff --git a/frontend/src/pages/job_logs/job_logs-new.tsx b/frontend/src/pages/job_logs/job_logs-new.tsx index a60713c..bc4842e 100644 --- a/frontend/src/pages/job_logs/job_logs-new.tsx +++ b/frontend/src/pages/job_logs/job_logs-new.tsx @@ -163,7 +163,6 @@ const initialValues = { - odometer_start: '', @@ -179,7 +178,6 @@ const initialValues = { - odometer_end: '', @@ -192,7 +190,6 @@ const initialValues = { - job_address: '', @@ -527,136 +524,6 @@ const Job_logsNew = () => { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/pages/job_logs/job_logs-table.tsx b/frontend/src/pages/job_logs/job_logs-table.tsx index ba4d511..7e6ee34 100644 --- a/frontend/src/pages/job_logs/job_logs-table.tsx +++ b/frontend/src/pages/job_logs/job_logs-table.tsx @@ -34,8 +34,7 @@ const Job_logsTablesPage = () => { const dispatch = useAppDispatch(); - const [filters] = useState([{label: 'JobAddress', title: 'job_address'},{label: 'NotesToAdmin', title: 'notes_to_admin'}, - {label: 'OdometerStart', title: 'odometer_start', number: 'true'},{label: 'OdometerEnd', title: 'odometer_end', number: 'true'}, + const [filters] = useState([{label: 'NotesToAdmin', title: 'notes_to_admin'}, {label: 'HoursConducted', title: 'hours_conducted', number: 'true'},{label: 'ClientPaid', title: 'client_paid', number: 'true'}, {label: 'WorkDate', title: 'work_date', date: 'true'}, diff --git a/frontend/src/pages/job_logs/job_logs-view.tsx b/frontend/src/pages/job_logs/job_logs-view.tsx index 4711028..7c7a945 100644 --- a/frontend/src/pages/job_logs/job_logs-view.tsx +++ b/frontend/src/pages/job_logs/job_logs-view.tsx @@ -421,127 +421,6 @@ const Job_logsView = () => {
- - - - - - - - - - - - - - - - - -
-

OdometerStart

-

{job_logs?.odometer_start || 'No data'}

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

OdometerEnd

-

{job_logs?.odometer_end || 'No data'}

-
- - - - - - - - - - - - - - - - - - - - - - -
-

JobAddress

-

{job_logs?.job_address}

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Status

{job_logs?.status ?? 'No data'}

@@ -600,65 +479,6 @@ const Job_logsView = () => { - <> -

Job_chemical_usages JobLog

- -
- - - - - - - - - - - - - - - - - - - - {job_logs.job_chemical_usages_job_log && Array.isArray(job_logs.job_chemical_usages_job_log) && - job_logs.job_chemical_usages_job_log.map((item: any) => ( - router.push(`/job_chemical_usages/job_chemical_usages-view/?id=${item.id}`)}> - - - - - - - - - - - - - - - ))} - -
QuantityUsedNotes
- { item.quantity_used } - - { item.notes } -
-
- {!job_logs?.job_chemical_usages_job_log?.length &&
No data
} -
- - - - - - { useEffect(() => { if (currentUser?.id) { - axios.get(`/employee_pay_types?employee=${currentUser.id}&active=true`) + axios + .get(`/employee_pay_types?employee=${currentUser.id}&active=true`) .then((res) => { if (res.data && res.data.rows) { - // Ensure we are extracting the inner pay_type relation from employee_pay_types - const payTypes = res.data.rows.map((row: any) => row.pay_type).filter(Boolean); + const payTypes = res.data.rows + .map((row: any) => row.pay_type) + .filter(Boolean); setAssignedPayTypes(payTypes); } }) @@ -40,7 +42,7 @@ const LogWorkPage = () => { }, [currentUser]); const initialValues = { - work_date: new Date().toISOString().slice(0, 16), + work_date: new Date().toISOString().slice(0, 10), employee: currentUser?.id || '', customer: '', hours_conducted: '', @@ -48,12 +50,8 @@ const LogWorkPage = () => { workersCompClass: '', pay_type: '', vehicle: '', - odometer_start: '', - odometer_end: '', - job_address: '', status: 'submitted', notes_to_admin: '', - chemical_usages: [], }; const handleSubmit = async (data: any) => { @@ -72,10 +70,10 @@ const LogWorkPage = () => { handleSubmit(values)}> - {({ values }) => ( + {() => (
- + @@ -87,7 +85,14 @@ const LogWorkPage = () => { - + @@ -101,68 +106,18 @@ const LogWorkPage = () => { - - - - - - - - - - + - -

Chemical Usage (Optional)

- - {({ push, remove }) => ( -
- {values.chemical_usages.map((usage, index) => ( -
- - - - - - -
- remove(index)} - /> -
-
- ))} - push({ chemical_product: '', quantity_used: '' })} - /> -
- )} -
- @@ -180,4 +135,4 @@ LogWorkPage.getLayout = function getLayout(page: ReactElement) { return {page}; }; -export default LogWorkPage; \ No newline at end of file +export default LogWorkPage; diff --git a/frontend/src/pages/payroll_runs/payroll_runs-view.tsx b/frontend/src/pages/payroll_runs/payroll_runs-view.tsx index aaccb9e..b71ed11 100644 --- a/frontend/src/pages/payroll_runs/payroll_runs-view.tsx +++ b/frontend/src/pages/payroll_runs/payroll_runs-view.tsx @@ -30,10 +30,20 @@ const Payroll_runsView = () => { const { id } = router.query; function removeLastCharacter(str) { - console.log(str,`str`) return str.slice(0, -1); } + function formatEmployeeName(employee) { + if (!employee) return 'No data'; + + const fullName = [employee.firstName, employee.lastName] + .filter(Boolean) + .join(' ') + .trim(); + + return fullName || employee.email || 'No data'; + } + useEffect(() => { dispatch(fetch({ id })); }, [dispatch, id]); @@ -292,72 +302,28 @@ const Payroll_runsView = () => { - - - - - - + - - - - - - - - - - - - - - - - {payroll_runs.payroll_line_items_payroll_run && Array.isArray(payroll_runs.payroll_line_items_payroll_run) && payroll_runs.payroll_line_items_payroll_run.map((item: any) => ( router.push(`/payroll_line_items/payroll_line_items-view/?id=${item.id}`)}> - - - - - - + - - - - - - - - - - - - - - - - ))}
Employee TotalHoursGrossPayTotalCommissionBaseTotalClientPaidSummary
+ {formatEmployeeName(item.employee)} + { item.total_hours } { item.gross_pay } { item.total_commission_base } - { item.total_client_paid } - - { item.summary } -