Merged in test-AIO (pull request #1387)

Rome Deployment & minor bug fixes for IO.
This commit is contained in:
Patrick Fic
2024-04-01 21:55:37 +00:00
20 changed files with 246 additions and 135 deletions

View File

@@ -132,7 +132,7 @@ jobs:
name: Install Dependencies
command: npm i
- run: npm run build:rome
- run: npm run build:production:rome
- aws-cli/setup:
aws_access_key_id: AWS_ACCESS_KEY_ID
@@ -144,6 +144,31 @@ jobs:
to: "s3://rome-online-production/"
arguments: "--exclude '*.map'"
promanager-app-build:
docker:
- image: cimg/node:18.18.2
working_directory: ~/repo/client
steps:
- checkout:
path: ~/repo
- run:
name: Install Dependencies
command: npm i
- run: npm run build:production:promanager
- aws-cli/setup:
aws_access_key_id: AWS_ACCESS_KEY_ID
aws_secret_access_key: AWS_SECRET_ACCESS_KEY
region: AWS_REGION
- aws-s3/sync:
from: build
to: "s3://promanager-production/"
arguments: "--exclude '*.map'"
test-rome-hasura-migrate:
docker:
- image: cimg/node:18.18.2
@@ -188,6 +213,31 @@ jobs:
to: "s3://rome-online-test/"
arguments: "--exclude '*.map'"
test-promanager-app-build:
docker:
- image: cimg/node:18.18.2
working_directory: ~/repo/client
steps:
- checkout:
path: ~/repo
- run:
name: Install Dependencies
command: npm i
- run: npm run build:test:promanager
- aws-cli/setup:
aws_access_key_id: AWS_ACCESS_KEY_ID
aws_secret_access_key: AWS_SECRET_ACCESS_KEY
region: AWS_REGION
- aws-s3/sync:
from: dist
to: "s3://promanager-testing/"
arguments: "--exclude '*.map'"
test-hasura-migrate:
docker:
- image: cimg/node:18.18.2
@@ -307,16 +357,16 @@ workflows:
- rome-api-deploy:
filters:
branches:
only: rome/master
only: master-AIO
- rome-app-build:
filters:
branches:
only: rome/master
only: master-AIO
- rome-hasura-migrate:
secret: ${HASURA_PROD_SECRET}
filters:
branches:
only: rome/master
only: master-AIO
- imex-test-app-build:
filters:
branches:
@@ -334,6 +384,14 @@ workflows:
filters:
branches:
only: test-AIO
- test-promanager-app-build:
filters:
branches:
only: test-AIO
- promanager-app-build:
filters:
branches:
only: master-AIO
- test-rome-hasura-migrate:
secret: ${HASURA_ROME_TEST_SECRET}
filters:

View File

@@ -1,4 +1,4 @@
<babeledit_project be_version="2.7.1" version="1.2">
<babeledit_project version="1.2" be_version="2.7.1">
<!--
BabelEdit project file
@@ -27170,6 +27170,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>employee_csr_writer</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>employee_prep</name>
<definition_loaded>false</definition_loaded>

View File

@@ -58,7 +58,7 @@ const Eula = ({ currentEula, currentUser, acceptEula }) => {
// Trim the values of the fields before submitting
const trimmedFormValues = Object.entries(otherFormValues).reduce((acc, [key, value]) => {
acc[key] = typeof value === "string" ? value.trim() : value;
acc[key] = typeof value === "string" ? value?.trim() : value;
return acc;
}, {});
@@ -140,7 +140,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => (
{
required: true,
validator: (_, value) =>
value.trim() !== "" ? Promise.resolve() : Promise.reject(new Error(t("eula.messages.first_name")))
value?.trim() !== "" ? Promise.resolve() : Promise.reject(new Error(t("eula.messages.first_name")))
}
]}
>
@@ -155,7 +155,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => (
{
required: true,
validator: (_, value) =>
value.trim() !== "" ? Promise.resolve() : Promise.reject(new Error(t("eula.messages.last_name")))
value?.trim() !== "" ? Promise.resolve() : Promise.reject(new Error(t("eula.messages.last_name")))
}
]}
>
@@ -172,7 +172,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => (
{
required: true,
validator: (_, value) =>
value.trim() !== "" ? Promise.resolve() : Promise.reject(new Error(t("eula.messages.business_name")))
value?.trim() !== "" ? Promise.resolve() : Promise.reject(new Error(t("eula.messages.business_name")))
}
]}
>

View File

@@ -33,7 +33,7 @@ function FeatureWrapper({ bodyshop, featureName, noauth, children, ...restProps
}
export function HasFeatureAccess({ featureName, bodyshop }) {
return bodyshop?.features.allAccess || dayjs(bodyshop?.features[featureName]).isAfter(dayjs());
return bodyshop?.features?.allAccess || dayjs(bodyshop?.features[featureName]).isAfter(dayjs());
}
export default connect(mapStateToProps, null)(FeatureWrapper);

View File

@@ -431,7 +431,12 @@ export function JobLinesComponent({
</Space>
</Tag>
)}
<JobLineDispatchButton selectedLines={selectedLines} setSelectedLines={setSelectedLines} job={job} />
<JobLineDispatchButton
selectedLines={selectedLines}
setSelectedLines={setSelectedLines}
job={job}
disabled={technician}
/>
{Enhanced_Payroll.treatment === "on" && (
<JobLineBulkAssignComponent selectedLines={selectedLines} setSelectedLines={setSelectedLines} job={job} />
)}

View File

@@ -7,6 +7,7 @@ import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import DataLabel from "../data-label/data-label.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -153,7 +154,15 @@ export function JobEmployeeAssignments({
/>
)}
</DataLabel>
<DataLabel label={t("jobs.fields.employee_csr")}>
<DataLabel
label={t(
InstanceRenderManager({
imex: "jobs.fields.employee_csr",
rome: "jobs.fields.employee_csr_writer",
promanager: "USE_ROME"
})
)}
>
{csr ? (
<div>
<span>{`${csr.first_name || ""} ${csr.last_name || ""}`}</span>

View File

@@ -224,7 +224,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
<span style={{ fontWeight: "bold" }}>
{t("job_lifecycle.content.current_status_accumulated_time")} (
{lifecycleData.lifecycle[0].value}):
</span>{" "}
</span>
{lifecycleData.durations.totalCurrentStatusDuration.humanReadable}
</li>
)}
@@ -250,6 +250,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
}}
columns={columns}
dataSource={lifecycleData.lifecycle}
rowKey="start"
/>
</Card>
</Space>

View File

@@ -29,7 +29,8 @@ export function JobLineDispatchButton({
bodyshop,
jobRO,
job,
currentUser
currentUser,
disabled
}) {
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
@@ -137,7 +138,7 @@ export function JobLineDispatchButton({
return (
<Popover open={visible} content={popMenu}>
<Button disabled={selectedLines.length === 0 || jobRO} loading={loading} onClick={() => setVisible(true)}>
<Button disabled={selectedLines.length === 0 || jobRO || disabled} loading={loading} onClick={() => setVisible(true)}>
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
</Button>
</Popover>

View File

@@ -10,6 +10,7 @@ import { insertAuditTrail } from "../../redux/application/application.actions";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -147,7 +148,13 @@ export function JobsConvertButton({ bodyshop, job, refetch, jobRO, insertAuditTr
{bodyshop.enforce_conversion_csr && (
<Form.Item
name={"employee_csr"}
label={t("jobs.fields.employee_csr")}
label={t(
InstanceRenderManager({
imex: "jobs.fields.employee_csr",
rome: "jobs.fields.employee_csr_writer",
promanager: "USE_ROME"
})
)}
rules={[
{
required: bodyshop.enforce_conversion_csr

View File

@@ -118,8 +118,8 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
{job?.cccontracts?.length > 0 && (
<DataLabel label={t("jobs.labels.contracts")}>
{job.cccontracts.map((c, index) => (
<Space wrap>
<Link key={c.id} to={`/manage/courtesycars/contracts/${c.id}`}>
<Space key={c.id} wrap>
<Link to={`/manage/courtesycars/contracts/${c.id}`}>
{`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model}`}
{index !== job.cccontracts.length - 1 ? "," : null}
</Link>

View File

@@ -306,7 +306,7 @@ export function PartsQueueListComponent({ bodyshop }) {
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
// handleOnRowClick(record);
}
};
}}

View File

@@ -26,6 +26,7 @@ import ProductionListColumnStatus from "./production-list-columns.status.compone
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
import { store } from "../../redux/store";
import { setModalContext } from "../../redux/modals/modals.actions";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatments }) => {
const { Enhanced_Payroll } = treatments;
@@ -120,15 +121,13 @@ const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatme
sortOrder: state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
render: (text, record) =>
technician ? (
<>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
} ${record.v_color || ""} ${record.plate_no || ""}`}</>
) : (
<Link to={`/manage/vehicles/${record.vehicleid}`}>{`${
record.v_model_yr || ""
} ${record.v_make_desc || ""} ${record.v_model_desc || ""} ${
<>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""} ${
record.v_color || ""
} ${record.plate_no || ""}`}</Link>
} ${record.plate_no || ""}`}</>
) : (
<Link to={`/manage/vehicles/${record.vehicleid}`}>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
} ${record.v_color || ""} ${record.plate_no || ""}`}</Link>
)
},
{
@@ -442,7 +441,13 @@ const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatme
)
},
{
title: i18n.t("jobs.fields.employee_csr"),
title: i18n.t(
InstanceRenderManager({
imex: "jobs.fields.employee_csr",
rome: "jobs.fields.employee_csr_writer",
promanager: "USE_ROME"
})
),
dataIndex: "employee_csr",
key: "employee_csr",
sortOrder: state.sortedInfo.columnKey === "employee_csr" && state.sortedInfo.order,

View File

@@ -4019,30 +4019,38 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
rome: <ShopInfoResponsibilitycentersTaxesComponent form={form} />
})}
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.itemexemptcode")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_responsibility_centers", "taxes", "itemexemptcode"]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.invoiceexemptcode")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_responsibility_centers", "taxes", "invoiceexemptcode"]}
>
<Input />
</Form.Item>
{InstanceRenderManager({
rome: (
<>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.itemexemptcode")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_responsibility_centers", "taxes", "itemexemptcode"]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.responsibilitycenters.invoiceexemptcode")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_responsibility_centers", "taxes", "invoiceexemptcode"]}
>
<Input />
</Form.Item>
</>
),
promanager: "USE_ROME"
})}
{/*<LayoutFormRow id="local_tax">*/}
{/* <Form.Item*/}
{/* label={t("bodyshop.fields.responsibilitycenters.local_tax")}*/}

View File

@@ -93,18 +93,18 @@ export function TechSider({ technician, techLogout, bodyshop, setTimeTicketTaskC
disabled: !!!technician,
label: <Link to={`/tech/shiftclock`}>{t("menus.tech.shiftclockin")}</Link>
},
{
key: "5",
icon: <ScheduleOutlined />,
disabled: !!!technician,
label: <Link to={`/tech/list`}>{t("menus.tech.productionlist")}</Link>
},
{
key: "dispatchedparts",
disabled: !!!technician,
icon: <CarOutlined />,
label: <Link to={`/tech/dispatchedparts`}>{t("menus.tech.dispatchedparts")}</Link>
},
{
key: "5",
icon: <ScheduleOutlined />,
disabled: !!!technician,
label: <Link to={`/tech/list`}>{t("menus.tech.productionlist")}</Link>
},
{
key: "6",
icon: <Icon component={BsKanban} />,

View File

@@ -207,74 +207,75 @@ 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: "Pay",
// dataIndex: "pay",
// key: "pay",
// render: (text, record) =>
// Dinero({ amount: Math.round(record.rate * 100) })
// .multiply(record.flat_rate ? record.productivehrs : record.actualhrs)
// .toFormat("$0.00"),
// },
{
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<Space wrap>
{techConsole && (
]),
{
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: "Pay",
// dataIndex: "pay",
// key: "pay",
// render: (text, record) =>
// Dinero({ amount: Math.round(record.rate * 100) })
// .multiply(record.flat_rate ? record.productivehrs : record.actualhrs)
// .toFormat("$0.00"),
// },
{
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<Space wrap>
{techConsole && (
<TimeTicketEnterButton
actions={{ refetch }}
context={{ id: record.id, timeticket: record }}
disabled={!record.job || disabled}
>
<EditFilled />
</TimeTicketEnterButton>
)}
{!techConsole && (
<RbacWrapper
action="timetickets:edit"
noauth={() => {
return <div />;
}}
>
<TimeTicketEnterButton
actions={{ refetch }}
context={{ id: record.id, timeticket: record }}
disabled={!record.job || disabled}
context={{
id: record.id,
timeticket: record
}}
disabled={
HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:editcommitted"
}) &&
HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:shiftedit"
})
? disabled
: !record.jobid
}
>
<EditFilled />
</TimeTicketEnterButton>
)}
{!techConsole && (
<RbacWrapper
action="timetickets:edit"
noauth={() => {
return <div />;
}}
>
<TimeTicketEnterButton
actions={{ refetch }}
context={{
id: record.id,
timeticket: record
}}
disabled={
HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:editcommitted"
}) &&
HasRbacAccess({
bodyshop,
authLevel: authLevel,
action: "timetickets:shiftedit"
})
? disabled
: !record.jobid
}
>
<EditFilled />
</TimeTicketEnterButton>
</RbacWrapper>
)}
</Space>
)
}
])
</RbacWrapper>
)}
</Space>
)
}
];
const handleTableChange = (pagination, filters, sorter) => {

View File

@@ -60,8 +60,8 @@ export function TimeTicketModalComponent({
{item.cost_center === "timetickets.labels.shift"
? t(item.cost_center)
: bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || Enhanced_Payroll.treatment === "on"
? t(`joblines.fields.lbr_types.${item.cost_center.toUpperCase()}`)
: item.cost_center}
? t(`joblines.fields.lbr_types.${item.cost_center.toUpperCase()}`)
: item.cost_center}
</Select.Option>
))}
</Select>
@@ -215,14 +215,6 @@ export function TimeTicketModalComponent({
>
<InputNumber precision={1} />
</Form.Item>
{
// <TimeTicketCalculatorComponent
// jobid={form.getFieldValue("jobid")}
// setProductiveHours={(productivehrs) =>
// form.setFieldsValue({productivehrs})
// }
// />
}
</>
)}
</Form.Item>

View File

@@ -33,7 +33,7 @@ export function TimeTickeTaskModalContainer({
toggleModalVisible
}) {
const [form] = Form.useForm();
const { context, visible, actions } = timeTicketTasksModal;
const { context, open, actions } = timeTicketTasksModal;
const [completedTasks, setCompletedTasks] = useState([]);
const [unassignedHours, setUnassignedHours] = useState(0);
const { t } = useTranslation();
@@ -59,13 +59,13 @@ export function TimeTickeTaskModalContainer({
[client]
);
useEffect(() => {
if (visible) {
if (open) {
form.setFieldsValue({ ...context, task: null, timetickets: null });
if (context.jobid) {
getCompletedTasks(context.jobid);
}
}
}, [context.jobid, visible, getCompletedTasks, form, context]);
}, [context.jobid, open, getCompletedTasks, form, context]);
async function handleValueChange(changedValues, allValues) {
if (changedValues.jobid) {
@@ -118,7 +118,7 @@ export function TimeTickeTaskModalContainer({
return (
<Modal
destroyOnClose
open={visible}
open={open}
onCancel={() => {
toggleModalVisible();
form.resetFields();

View File

@@ -1640,6 +1640,7 @@
"driveable": "Driveable",
"employee_body": "Body",
"employee_csr": "Customer Service Rep.",
"employee_csr_writer": "Writer",
"employee_prep": "Prep",
"employee_refinish": "Refinish",
"est_addr1": "Estimator Address",

View File

@@ -1640,6 +1640,7 @@
"driveable": "",
"employee_body": "",
"employee_csr": "Representante de servicio al cliente.",
"employee_csr_writer": "",
"employee_prep": "",
"employee_refinish": "",
"est_addr1": "Dirección del tasador",

View File

@@ -1640,6 +1640,7 @@
"driveable": "",
"employee_body": "",
"employee_csr": "représentant du service à la clientèle",
"employee_csr_writer": "",
"employee_prep": "",
"employee_refinish": "",
"est_addr1": "Adresse de l'évaluateur",