Compare commits

..

11 Commits

Author SHA1 Message Date
Allan Carr
10fceb7ddf IO-2384 Extend to Vehicle Related ROs 2023-08-17 16:18:56 -07:00
Allan Carr
6c1a0cff8d IO-2384 Default Sort Order for Related Jobs 2023-08-17 16:05:33 -07:00
Allan Carr
ba683a2e8a Merged in release/2023-08-11 (pull request #931)
Release/2023 08 11
2023-08-11 20:36:11 +00:00
Allan Carr
5209c12b89 Merged in feature/IO-2325-Ticket-Create-By (pull request #928)
IO-2325 Shift Clock Created By
2023-08-11 15:36:06 +00:00
Allan Carr
bf7aa17f65 IO-2325 Shift Clock Created By 2023-08-11 08:35:57 -07:00
Allan Carr
cd6e0dcde3 Merged in feature/IO-2325-Ticket-Create-By (pull request #926)
IO-2325 Time Ticket Creation Date
2023-08-10 19:06:58 +00:00
Allan Carr
a2822f5592 Merged in feature/IO-2376-Inactive-Employee-Login (pull request #925)
IO-2376 Prevent Inactive Employee from logging in
2023-08-10 19:06:49 +00:00
Allan Carr
ca129fa4a0 IO-2325 Time Ticket Creation Date 2023-08-10 12:06:47 -07:00
Allan Carr
de92b2d47e Merged in feature/IO-2375-Job-Costing-by-CSR-Filter-Label (pull request #924)
IO-2375 Filter label for Job Costing by CSR correction
2023-08-09 22:26:09 +00:00
Allan Carr
5d7384aa8b IO-2375 Filter label for Job Costing by CSR correction 2023-08-09 15:25:58 -07:00
Patrick Fic
bf18e687da Schema updates for parts dispatch. 2023-08-04 12:36:08 -07:00
24 changed files with 149 additions and 17 deletions

View File

@@ -1,10 +1,9 @@
import { useTreatments } from "@splitsoftware/splitio-react";
import Icon, {
BankFilled,
BarChartOutlined,
CarFilled,
ClockCircleFilled,
CheckCircleOutlined,
ClockCircleFilled,
DashboardFilled,
DollarCircleFilled,
ExportOutlined,
@@ -26,6 +25,7 @@ import Icon, {
UnorderedListOutlined,
UserOutlined,
} from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react";
import { Layout, Menu } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -252,7 +252,11 @@ function Header({
onClick={() => {
setTimeTicketContext({
actions: {},
context: {},
context: {
created_by: currentUser.displayName
? currentUser.email.concat(" | ", currentUser.displayName)
: currentUser.email,
},
});
}}
>

View File

@@ -6,6 +6,7 @@ import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort, statusSort } from "../../utils/sorters";
import OwnerDetailUpdateJobsComponent from "../owner-detail-update-jobs/owner-detail-update-jobs.component";
const mapStateToProps = createStructuredSelector({
@@ -15,6 +16,15 @@ const mapStateToProps = createStructuredSelector({
function OwnerDetailJobsComponent({ bodyshop, owner }) {
const { t } = useTranslation();
const [selectedJobs, setSelectedJobs] = useState([]);
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: { text: "" },
});
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const columns = [
{
title: t("jobs.fields.ro_number"),
@@ -26,6 +36,9 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
{record.ro_number || t("general.labels.na")}
</Link>
),
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
},
{
title: t("jobs.fields.vehicle"),
@@ -46,11 +59,17 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
key: "clm_no",
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder:
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
},
{
title: t("jobs.fields.status"),
dataIndex: "status",
key: "status",
sorter: (a, b) => statusSort(a.status, b.status, bodyshop.md_ro_statuses.statuses),
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
},
{
@@ -60,6 +79,9 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
render: (text, record) => (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
),
sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
},
];
@@ -80,6 +102,7 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
scroll={{ x: true }}
rowKey="id"
dataSource={owner.jobs}
onChange={handleTableChange}
rowSelection={{
onSelect: (record, selected, selectedRows) => {
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);

View File

@@ -1,21 +1,25 @@
import { useMutation } from "@apollo/client";
import { Button, Card, Form, notification, Space } from "antd";
import axios from "axios";
import moment from "moment";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import TechClockInComponent from "./tech-job-clock-in-form.component";
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
import moment from "moment";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
import TechClockInComponent from "./tech-job-clock-in-form.component";
const mapStateToProps = createStructuredSelector({
technician: selectTechnician,
bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
setTimeTicketContext: (context) =>
@@ -25,6 +29,7 @@ export function TechClockInContainer({
setTimeTicketContext,
technician,
bodyshop,
currentUser,
}) {
console.log(
"🚀 ~ file: tech-job-clock-in-form.container.jsx:29 ~ technician:",
@@ -66,6 +71,12 @@ export function TechClockInContainer({
values.cost_center
);
}),
created_by: currentUser.email.concat(
" | ",
technician.employee_number
.concat(" ", technician.first_name, " ", technician.last_name)
.trim()
),
},
],
},
@@ -100,6 +111,17 @@ export function TechClockInContainer({
employeeid: technician.id,
flat_rate: emps.flat_rate,
},
created_by: currentUser.email.concat(
" | ",
technician.employee_number
.concat(
" ",
technician.first_name,
" ",
technician.last_name
)
.trim()
),
},
});
}}

View File

@@ -9,9 +9,10 @@ import { createStructuredSelector } from "reselect";
import {
selectAuthLevel,
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort, dateSort } from "../../utils/sorters";
import RbacWrapper, {
HasRbacAccess,
@@ -20,6 +21,7 @@ import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
authLevel: selectAuthLevel,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
@@ -29,6 +31,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketList);
export function TimeTicketList({
bodyshop,
authLevel,
currentUser,
disabled,
loading,
timetickets,
@@ -193,7 +196,15 @@ export function TimeTicketList({
}
},
},
{
title: t("timetickets.fields.created_by"),
dataIndex: "created_by",
key: "created_by",
sorter: (a, b) => alphaSort(a.created_by, b.created_by),
sortOrder:
state.sortedInfo.columnKey === "created_by" && state.sortedInfo.order,
render: (text, record) => record.created_by,
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
@@ -254,7 +265,12 @@ export function TimeTicketList({
(techConsole ? null : (
<TimeTicketEnterButton
actions={{ refetch }}
context={{ jobId: jobId }}
context={{
jobId: jobId,
created_by: currentUser.displayName
? currentUser.email.concat(" | ", currentUser.displayName)
: currentUser.email,
}}
disabled={disabled}
>
{t("timetickets.actions.enter")}

View File

@@ -1,5 +1,5 @@
import { useMutation, useQuery } from "@apollo/client";
import { Button, Form, Modal, notification, PageHeader, Space } from "antd";
import { Button, Form, Modal, PageHeader, Space, notification } from "antd";
import moment from "moment";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -77,6 +77,7 @@ export function TimeTicketModalContainer({
)[0].rate
: null,
bodyshopid: bodyshop.id,
created_by: timeTicketModal.context.created_by,
},
],
},

View File

@@ -65,6 +65,21 @@ export function TimeTicektShiftContainer({
clockon: theTime,
date: theTime,
memo: values.memo,
created_by: isTechConsole
? currentUser.email.concat(
" | ",
technician.employee_number
.concat(
" ",
technician.first_name,
" ",
technician.last_name
)
.trim()
)
: currentUser.displayName
? currentUser.email.concat(" | ", currentUser.displayName)
: currentUser.email,
},
],
},

View File

@@ -6,8 +6,9 @@ import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import VehicleDetailUpdateJobsComponent from "../vehicle-detail-update-jobs/vehicle-detail-update-jobs.component";
import { alphaSort, statusSort } from "../../utils/sorters";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import VehicleDetailUpdateJobsComponent from "../vehicle-detail-update-jobs/vehicle-detail-update-jobs.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -16,6 +17,14 @@ const mapStateToProps = createStructuredSelector({
export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
const { t } = useTranslation();
const [selectedJobs, setSelectedJobs] = useState([]);
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: { text: "" },
});
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const columns = [
{
@@ -28,6 +37,9 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
{record.ro_number || t("general.labels.na")}
</Link>
),
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
},
{
title: t("jobs.fields.owner"),
@@ -43,11 +55,17 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
key: "clm_no",
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder:
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
},
{
title: t("jobs.fields.status"),
dataIndex: "status",
key: "status",
sorter: (a, b) => statusSort(a.status, b.status, bodyshop.md_ro_statuses.statuses),
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
},
{
@@ -57,6 +75,9 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
render: (text, record) => (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
),
sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
},
];
@@ -76,6 +97,7 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
rowKey="id"
scroll={{ x: true }}
dataSource={vehicle.jobs}
onChange={handleTableChange}
rowSelection={{
onSelect: (record, selected, selectedRows) => {
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);

View File

@@ -57,6 +57,7 @@ export const GET_LINE_TICKET_BY_PK = gql`
actualhrs
ciecacode
cost_center
created_by
date
id
jobid

View File

@@ -69,7 +69,7 @@ export const QUERY_OWNER_BY_ID = gql`
preferred_contact
note
tax_number
jobs {
jobs(order_by: { date_open: desc }) {
id
ro_number
clm_no

View File

@@ -37,6 +37,7 @@ export const QUERY_TIME_TICKETS_IN_RANGE = gql`
clockon
cost_center
created_at
created_by
date
id
rate
@@ -80,6 +81,7 @@ export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
clockon
cost_center
created_at
created_by
date
id
rate
@@ -112,6 +114,7 @@ export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
clockon
cost_center
created_at
created_by
date
id
rate
@@ -151,6 +154,7 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
clockon
cost_center
created_at
created_by
date
id
rate
@@ -181,6 +185,7 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
clockon
cost_center
created_at
created_by
date
id
rate
@@ -210,6 +215,7 @@ export const INSERT_NEW_TIME_TICKET = gql`
insert_timetickets(objects: $timeTicketInput) {
returning {
id
created_by
clockon
clockoff
employeeid

View File

@@ -28,11 +28,10 @@ export const QUERY_VEHICLE_BY_ID = gql`
updated_at
trim_color
notes
jobs {
jobs(order_by: { date_open: desc }) {
id
ro_number
ownr_fn
ownr_ln
owner {
id

View File

@@ -2730,6 +2730,7 @@
"clockon": "Clocked In",
"committed": "",
"cost_center": "Cost Center",
"created_by": "Created By",
"date": "Ticket Date",
"efficiency": "Efficiency",
"employee": "Employee",

View File

@@ -2730,6 +2730,7 @@
"clockon": "",
"committed": "",
"cost_center": "",
"created_by": "",
"date": "",
"efficiency": "",
"employee": "",

View File

@@ -2730,6 +2730,7 @@
"clockon": "",
"committed": "",
"cost_center": "",
"created_by": "",
"date": "",
"efficiency": "",
"employee": "",

View File

@@ -1040,7 +1040,7 @@ export const TemplateList = (type, context) => {
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_open"),
field: i18n.t("jobs.fields.date_invoiced"),
},
group: "jobs",
},

View File

@@ -4649,6 +4649,7 @@
_eq: X-Hasura-User-Id
- active:
_eq: true
allow_aggregations: true
update_permissions:
- role: user
permission:
@@ -4726,6 +4727,7 @@
_eq: X-Hasura-User-Id
- active:
_eq: true
allow_aggregations: true
update_permissions:
- role: user
permission:
@@ -5554,6 +5556,7 @@
- committed_at
- cost_center
- created_at
- created_by
- date
- employeeid
- flat_rate
@@ -5578,6 +5581,7 @@
- committed_at
- cost_center
- created_at
- created_by
- date
- employeeid
- flat_rate
@@ -5611,6 +5615,7 @@
- committed_at
- cost_center
- created_at
- created_by
- date
- employeeid
- flat_rate

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "public"."parts_dispatch_employeeid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "parts_dispatch_employeeid" on
"public"."parts_dispatch" using btree ("employeeid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "public"."parts_dispatch_dispatchid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "parts_dispatch_dispatchid" on
"public"."parts_dispatch_lines" using btree ("partsdispatchid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "public"."parts_dispatch_line_accepted_at";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "parts_dispatch_line_accepted_at" on
"public"."parts_dispatch_lines" using btree ("accepted_at");

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."timetickets" add column "created_by" text
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."timetickets" add column "created_by" text
null;