Merged in release/2022-06-10 (pull request #502)
release/2022-06-10 Approved-by: Patrick Fic
This commit is contained in:
@@ -2181,6 +2181,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>existinginventoryline</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>
|
<concept_node>
|
||||||
<name>exporting</name>
|
<name>exporting</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -17266,6 +17287,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>addtoro</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>
|
<concept_node>
|
||||||
<name>consumefrominventory</name>
|
<name>consumefrominventory</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ export default function BillDeleteButton({ bill }) {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const result = await deleteBill({
|
const result = await deleteBill({
|
||||||
variables: { billId: bill.id },
|
variables: { billId: bill.id },
|
||||||
update(cache) {
|
update(cache, { errors }) {
|
||||||
|
if (errors) return;
|
||||||
cache.modify({
|
cache.modify({
|
||||||
fields: {
|
fields: {
|
||||||
bills(existingBills, { readField }) {
|
bills(existingBills, { readField }) {
|
||||||
@@ -36,11 +37,22 @@ export default function BillDeleteButton({ bill }) {
|
|||||||
if (!!!result.errors) {
|
if (!!!result.errors) {
|
||||||
notification["success"]({ message: t("bills.successes.deleted") });
|
notification["success"]({ message: t("bills.successes.deleted") });
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
//Check if it's an fkey violation.
|
||||||
message: t("bills.errors.deleting", {
|
const error = JSON.stringify(result.errors);
|
||||||
error: JSON.stringify(result.errors),
|
|
||||||
}),
|
if (error.toLowerCase().includes("inventory_billid_fkey")) {
|
||||||
});
|
notification["error"]({
|
||||||
|
message: t("bills.errors.deleting", {
|
||||||
|
error: t("bills.errors.existinginventoryline"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: t("bills.errors.deleting", {
|
||||||
|
error: JSON.stringify(result.errors),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|||||||
@@ -485,22 +485,33 @@ export function BillEnterModalLinesComponent({
|
|||||||
|
|
||||||
dataIndex: "actions",
|
dataIndex: "actions",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Space wrap>
|
<Form.Item shouldUpdate noStyle>
|
||||||
<Button disabled={disabled} onClick={() => remove(record.name)}>
|
{() => (
|
||||||
<DeleteFilled />
|
<Space wrap>
|
||||||
</Button>
|
<Button
|
||||||
<Form.Item shouldUpdate noStyle>
|
disabled={
|
||||||
{() =>
|
disabled ||
|
||||||
Simple_Inventory.treatment === "on" && (
|
getFieldValue("billlines")[record.fieldKey]?.inventories
|
||||||
|
?.length > 0
|
||||||
|
}
|
||||||
|
onClick={() => remove(record.name)}
|
||||||
|
>
|
||||||
|
<DeleteFilled />
|
||||||
|
</Button>
|
||||||
|
{Simple_Inventory.treatment === "on" && (
|
||||||
<BilllineAddInventory
|
<BilllineAddInventory
|
||||||
disabled={!billEdit || form.isFieldsTouched()}
|
disabled={
|
||||||
|
!billEdit ||
|
||||||
|
form.isFieldsTouched() ||
|
||||||
|
form.getFieldValue("is_credit_memo")
|
||||||
|
}
|
||||||
billline={getFieldValue("billlines")[record.fieldKey]}
|
billline={getFieldValue("billlines")[record.fieldKey]}
|
||||||
jobid={getFieldValue("jobid")}
|
jobid={getFieldValue("jobid")}
|
||||||
/>
|
/>
|
||||||
)
|
)}
|
||||||
}
|
</Space>
|
||||||
</Form.Item>
|
)}
|
||||||
</Space>
|
</Form.Item>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import "./bill-inventory-table.styles.scss";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
billEnterModal: selectBillEnterModal,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
@@ -17,6 +19,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
export default connect(mapStateToProps, mapDispatchToProps)(BillInventoryTable);
|
export default connect(mapStateToProps, mapDispatchToProps)(BillInventoryTable);
|
||||||
|
|
||||||
export function BillInventoryTable({
|
export function BillInventoryTable({
|
||||||
|
billEnterModal,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
form,
|
form,
|
||||||
billEdit,
|
billEdit,
|
||||||
@@ -28,11 +31,18 @@ export function BillInventoryTable({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (inventoryData) {
|
if (inventoryData) {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
inventory: inventoryData.inventory,
|
inventory: billEnterModal.context.consumeinventoryid
|
||||||
|
? inventoryData.inventory.map((i) => {
|
||||||
|
if (i.id === billEnterModal.context.consumeinventoryid)
|
||||||
|
i.consumefrominventory = true;
|
||||||
|
return i;
|
||||||
|
})
|
||||||
|
: inventoryData.inventory,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [inventoryData, form]);
|
}, [inventoryData, form, billEnterModal.context.consumeinventoryid]);
|
||||||
|
|
||||||
|
console.log(form.getFieldsValue());
|
||||||
return (
|
return (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
shouldUpdate={(prev, cur) => prev.vendorid !== cur.vendorid}
|
shouldUpdate={(prev, cur) => prev.vendorid !== cur.vendorid}
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import {
|
import {
|
||||||
selectAuthLevel,
|
selectAuthLevel,
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
|
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
|
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
authLevel: selectAuthLevel,
|
authLevel: selectAuthLevel,
|
||||||
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
@@ -24,9 +27,15 @@ export default connect(
|
|||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(BillMarkExportedButton);
|
)(BillMarkExportedButton);
|
||||||
|
|
||||||
export function BillMarkExportedButton({ bodyshop, authLevel, bill }) {
|
export function BillMarkExportedButton({
|
||||||
|
currentUser,
|
||||||
|
bodyshop,
|
||||||
|
authLevel,
|
||||||
|
bill,
|
||||||
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
|
||||||
|
|
||||||
const [updateBill] = useMutation(gql`
|
const [updateBill] = useMutation(gql`
|
||||||
mutation UPDATE_BILL($billId: uuid!) {
|
mutation UPDATE_BILL($billId: uuid!) {
|
||||||
@@ -46,6 +55,20 @@ export function BillMarkExportedButton({ bodyshop, authLevel, bill }) {
|
|||||||
variables: { billId: bill.id },
|
variables: { billId: bill.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await insertExportLog({
|
||||||
|
variables: {
|
||||||
|
logs: [
|
||||||
|
{
|
||||||
|
bodyshopid: bodyshop.id,
|
||||||
|
billid: bill.id,
|
||||||
|
successful: true,
|
||||||
|
message: t("general.labels.markedexported"),
|
||||||
|
useremail: currentUser.email,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!result.errors) {
|
if (!result.errors) {
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
message: t("bills.successes.markexported"),
|
message: t("bills.successes.markexported"),
|
||||||
@@ -69,11 +92,7 @@ export function BillMarkExportedButton({ bodyshop, authLevel, bill }) {
|
|||||||
|
|
||||||
if (hasAccess)
|
if (hasAccess)
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button loading={loading} disabled={bill.exported} onClick={handleUpdate}>
|
||||||
loading={loading}
|
|
||||||
disabled={bill.exported}
|
|
||||||
onClick={handleUpdate}
|
|
||||||
>
|
|
||||||
{t("bills.labels.markexported")}
|
{t("bills.labels.markexported")}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -64,9 +64,9 @@ export function BilllineAddInventory({
|
|||||||
cost_center: billline.cost_center,
|
cost_center: billline.cost_center,
|
||||||
deductedfromlbr: billline.deductedfromlbr,
|
deductedfromlbr: billline.deductedfromlbr,
|
||||||
applicable_taxes: {
|
applicable_taxes: {
|
||||||
local: false, //billline.applicable_taxes.local,
|
local: billline.applicable_taxes.local,
|
||||||
state: false, //billline.applicable_taxes.state,
|
state: billline.applicable_taxes.state,
|
||||||
federal: false, // billline.applicable_taxes.federal,
|
federal: billline.applicable_taxes.federal,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -76,7 +76,9 @@ export function BilllineAddInventory({
|
|||||||
|
|
||||||
const insertResult = await insertInventoryLine({
|
const insertResult = await insertInventoryLine({
|
||||||
variables: {
|
variables: {
|
||||||
joblineId: billline.joblineid,
|
joblineId:
|
||||||
|
billline.joblineid === "noline" ? billline.id : billline.joblineid, //This will return null as there will be no jobline that has the id of the bill line.
|
||||||
|
//Unfortunately, we can't send null as the GQL syntax validation fails.
|
||||||
joblineStatus: bodyshop.md_order_statuses.default_returned,
|
joblineStatus: bodyshop.md_order_statuses.default_returned,
|
||||||
inv: {
|
inv: {
|
||||||
shopid: bodyshop.id,
|
shopid: bodyshop.id,
|
||||||
@@ -99,8 +101,9 @@ export function BilllineAddInventory({
|
|||||||
act_price: billline.actual_price,
|
act_price: billline.actual_price,
|
||||||
cost: billline.actual_cost,
|
cost: billline.actual_cost,
|
||||||
quantity: billline.quantity,
|
quantity: billline.quantity,
|
||||||
job_line_id: billline.joblineid,
|
job_line_id:
|
||||||
part_type: billline.jobline.part_type,
|
billline.joblineid === "noline" ? null : billline.joblineid,
|
||||||
|
part_type: billline.jobline && billline.jobline.part_type,
|
||||||
cm_received: true,
|
cm_received: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Button } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import moment from "moment";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
setBillEnterContext: (context) =>
|
||||||
|
dispatch(setModalContext({ context: context, modal: "billEnter" })),
|
||||||
|
});
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(InventoryBillRo);
|
||||||
|
export function InventoryBillRo({
|
||||||
|
bodyshop,
|
||||||
|
setBillEnterContext,
|
||||||
|
inventoryline,
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setBillEnterContext({
|
||||||
|
actions: {
|
||||||
|
//refetch: refetch
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
disableInvNumber: true,
|
||||||
|
//job: { id: job.id },
|
||||||
|
consumeinventoryid: inventoryline.id,
|
||||||
|
bill: {
|
||||||
|
vendorid: bodyshop.inhousevendorid,
|
||||||
|
invoice_number: "ih",
|
||||||
|
isinhouse: true,
|
||||||
|
date: moment(),
|
||||||
|
total: 0,
|
||||||
|
|
||||||
|
// billlines: selectedLines.map((p) => {
|
||||||
|
// return {
|
||||||
|
// joblineid: p.id,
|
||||||
|
// actual_price: p.act_price,
|
||||||
|
// actual_cost: 0, //p.act_price,
|
||||||
|
// line_desc: p.line_desc,
|
||||||
|
// line_remarks: p.line_remarks,
|
||||||
|
// part_type: p.part_type,
|
||||||
|
// quantity: p.quantity || 1,
|
||||||
|
// applicable_taxes: {
|
||||||
|
// local: false,
|
||||||
|
// state: false,
|
||||||
|
// federal: false,
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("inventory.actions.addtoro")}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,10 +4,11 @@ import queryString from "query-string";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
|
import InventoryBillRo from "../inventory-bill-ro/inventory-bill-ro.component";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -75,7 +76,14 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
|||||||
key: "consumedbyjob",
|
key: "consumedbyjob",
|
||||||
|
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (text, record) => record.bill?.job?.ro_number,
|
render: (text, record) =>
|
||||||
|
record.bill?.job?.ro_number ? (
|
||||||
|
<Link to={`/manage/jobs/${record.bill?.job?.id}`}>
|
||||||
|
{record.bill?.job?.ro_number}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<InventoryBillRo inventoryline={record} />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
});
|
});
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(JobPartsQueueCount);
|
export default connect(mapStateToProps, mapDispatchToProps)(JobPartsQueueCount);
|
||||||
|
|
||||||
export function JobPartsQueueCount({ bodyshop, parts }) {
|
export function JobPartsQueueCount({ bodyshop, parts, style }) {
|
||||||
const partsStatus = useMemo(() => {
|
const partsStatus = useMemo(() => {
|
||||||
if (!parts) return null;
|
if (!parts) return null;
|
||||||
return parts.reduce(
|
return parts.reduce(
|
||||||
@@ -36,7 +36,7 @@ export function JobPartsQueueCount({ bodyshop, parts }) {
|
|||||||
if (!parts) return null;
|
if (!parts) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row style={style}>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<Tooltip title="Total">
|
<Tooltip title="Total">
|
||||||
<Tag>{partsStatus.total}</Tag>
|
<Tag>{partsStatus.total}</Tag>
|
||||||
|
|||||||
@@ -6,12 +6,17 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import {
|
||||||
|
selectBodyshop,
|
||||||
|
selectCurrentUser,
|
||||||
|
} from "../../redux/user/user.selectors";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
|
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
insertAuditTrail: ({ jobid, operation }) =>
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
@@ -22,9 +27,15 @@ export default connect(
|
|||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(JobAdminMarkReexport);
|
)(JobAdminMarkReexport);
|
||||||
|
|
||||||
export function JobAdminMarkReexport({ insertAuditTrail, bodyshop, job }) {
|
export function JobAdminMarkReexport({
|
||||||
|
insertAuditTrail,
|
||||||
|
bodyshop,
|
||||||
|
currentUser,
|
||||||
|
job,
|
||||||
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
|
||||||
const [markJobForReexport] = useMutation(gql`
|
const [markJobForReexport] = useMutation(gql`
|
||||||
mutation MARK_JOB_FOR_REEXPORT($jobId: uuid!) {
|
mutation MARK_JOB_FOR_REEXPORT($jobId: uuid!) {
|
||||||
update_jobs_by_pk(
|
update_jobs_by_pk(
|
||||||
@@ -101,6 +112,20 @@ export function JobAdminMarkReexport({ insertAuditTrail, bodyshop, job }) {
|
|||||||
variables: { jobId: job.id, date_exported: moment() },
|
variables: { jobId: job.id, date_exported: moment() },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await insertExportLog({
|
||||||
|
variables: {
|
||||||
|
logs: [
|
||||||
|
{
|
||||||
|
bodyshopid: bodyshop.id,
|
||||||
|
jobid: job.id,
|
||||||
|
successful: true,
|
||||||
|
message: t("general.labels.markedexported"),
|
||||||
|
useremail: currentUser.email,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!result.errors) {
|
if (!result.errors) {
|
||||||
notification["success"]({ message: t("jobs.successes.save") });
|
notification["success"]({ message: t("jobs.successes.save") });
|
||||||
insertAuditTrail({
|
insertAuditTrail({
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ import React, { useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||||
import {
|
import {
|
||||||
selectAuthLevel,
|
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
authLevel: selectAuthLevel,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
@@ -23,6 +24,8 @@ export default connect(
|
|||||||
)(BillMarkSelectedExported);
|
)(BillMarkSelectedExported);
|
||||||
|
|
||||||
export function BillMarkSelectedExported({
|
export function BillMarkSelectedExported({
|
||||||
|
bodyshop,
|
||||||
|
currentUser,
|
||||||
billids,
|
billids,
|
||||||
disabled,
|
disabled,
|
||||||
loadingCallback,
|
loadingCallback,
|
||||||
@@ -31,7 +34,7 @@ export function BillMarkSelectedExported({
|
|||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
|
||||||
const [updateBill] = useMutation(gql`
|
const [updateBill] = useMutation(gql`
|
||||||
mutation UPDATE_BILL($billIds: [uuid!]!) {
|
mutation UPDATE_BILL($billIds: [uuid!]!) {
|
||||||
update_bills(where: { id: { _in: $billIds } }, _set: { exported: true }) {
|
update_bills(where: { id: { _in: $billIds } }, _set: { exported: true }) {
|
||||||
@@ -49,9 +52,21 @@ export function BillMarkSelectedExported({
|
|||||||
loadingCallback(true);
|
loadingCallback(true);
|
||||||
const result = await updateBill({
|
const result = await updateBill({
|
||||||
variables: { billIds: billids },
|
variables: { billIds: billids },
|
||||||
update(cache){
|
update(cache) {},
|
||||||
|
});
|
||||||
}
|
|
||||||
|
await insertExportLog({
|
||||||
|
variables: {
|
||||||
|
logs: billids.map((id) => {
|
||||||
|
return {
|
||||||
|
bodyshopid: bodyshop.id,
|
||||||
|
billid: id,
|
||||||
|
successful: true,
|
||||||
|
message: t("general.labels.markedexported"),
|
||||||
|
useremail: currentUser.email,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.errors) {
|
if (!result.errors) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Icon from "@ant-design/icons";
|
import Icon from "@ant-design/icons";
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Input, Popover } from "antd";
|
import { Button, Input, Popover, Tooltip } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { FaRegStickyNote } from "react-icons/fa";
|
import { FaRegStickyNote } from "react-icons/fa";
|
||||||
@@ -69,10 +69,11 @@ export default function ProductionListColumnComment({ record }) {
|
|||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
|
display: "inline-block",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon component={FaRegStickyNote} style={{ marginRight: ".2rem" }} />
|
<Icon component={FaRegStickyNote} style={{ marginRight: ".2rem" }} />
|
||||||
{record.comment || " "}
|
<Tooltip title={record.comment}>{record.comment || " "}</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,25 +5,26 @@ import moment from "moment";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
|
import { TimeFormatter } from "../../utils/DateFormatter";
|
||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
|
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
|
||||||
import JobAltTransportChange from "../job-at-change/job-at-change.component";
|
import JobAltTransportChange from "../job-at-change/job-at-change.component";
|
||||||
|
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
||||||
import ProductionListColumnAlert from "./production-list-columns.alert.component";
|
import ProductionListColumnAlert from "./production-list-columns.alert.component";
|
||||||
import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component";
|
import ProductionListColumnBodyPriority from "./production-list-columns.bodypriority.component";
|
||||||
|
import ProductionListColumnComment from "./production-list-columns.comment.component";
|
||||||
import ProductionListDate from "./production-list-columns.date.component";
|
import ProductionListDate from "./production-list-columns.date.component";
|
||||||
import ProductionListColumnDetailPriority from "./production-list-columns.detailpriority.component";
|
import ProductionListColumnDetailPriority from "./production-list-columns.detailpriority.component";
|
||||||
import ProductionListEmployeeAssignment from "./production-list-columns.empassignment.component";
|
import ProductionListEmployeeAssignment from "./production-list-columns.empassignment.component";
|
||||||
import ProductionListLastContacted from "./production-list-columns.lastcontacted.component";
|
import ProductionListLastContacted from "./production-list-columns.lastcontacted.component";
|
||||||
import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component";
|
import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component";
|
||||||
import ProductionListColumnNote from "./production-list-columns.productionnote.component";
|
|
||||||
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
|
||||||
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
|
||||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
|
||||||
import ProductionListColumnComment from "./production-list-columns.comment.component";
|
|
||||||
import ProductionListColumnPartsReceived from "./production-list-columns.partsreceived.component";
|
import ProductionListColumnPartsReceived from "./production-list-columns.partsreceived.component";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import ProductionListColumnNote from "./production-list-columns.productionnote.component";
|
||||||
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
|
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
||||||
|
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
||||||
|
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
||||||
|
|
||||||
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||||
return [
|
return [
|
||||||
@@ -105,6 +106,16 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
<ProductionListDate record={record} field="actual_in" time />
|
<ProductionListDate record={record} field="actual_in" time />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t("jobs.fields.actual_in") + " (HH:MM)",
|
||||||
|
dataIndex: "actual_in_time",
|
||||||
|
key: "actual_in_time",
|
||||||
|
ellipsis: true,
|
||||||
|
|
||||||
|
render: (text, record) => (
|
||||||
|
<TimeFormatter>{record.actual_in}</TimeFormatter>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: i18n.t("jobs.fields.scheduled_completion"),
|
title: i18n.t("jobs.fields.scheduled_completion"),
|
||||||
dataIndex: "scheduled_completion",
|
dataIndex: "scheduled_completion",
|
||||||
@@ -124,6 +135,16 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t("jobs.fields.scheduled_completion") + " (HH:MM)",
|
||||||
|
dataIndex: "scheduled_completion_time",
|
||||||
|
key: "scheduled_completion_time",
|
||||||
|
ellipsis: true,
|
||||||
|
|
||||||
|
render: (text, record) => (
|
||||||
|
<TimeFormatter>{record.scheduled_completion}</TimeFormatter>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: i18n.t("jobs.fields.date_last_contacted"),
|
title: i18n.t("jobs.fields.date_last_contacted"),
|
||||||
dataIndex: "date_last_contacted",
|
dataIndex: "date_last_contacted",
|
||||||
@@ -176,6 +197,16 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t("jobs.fields.scheduled_delivery") + " (HH:MM)",
|
||||||
|
dataIndex: "scheduled_delivery_time",
|
||||||
|
key: "scheduled_delivery_time",
|
||||||
|
ellipsis: true,
|
||||||
|
|
||||||
|
render: (text, record) => (
|
||||||
|
<TimeFormatter>{record.scheduled_delivery}</TimeFormatter>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: i18n.t("jobs.fields.ins_co_nm"),
|
title: i18n.t("jobs.fields.ins_co_nm"),
|
||||||
dataIndex: "ins_co_nm",
|
dataIndex: "ins_co_nm",
|
||||||
|
|||||||
@@ -50,50 +50,45 @@ export default function ProductionListDate({
|
|||||||
"production-completion-soon"));
|
"production-completion-soon"));
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<Dropdown
|
||||||
<Dropdown
|
//trigger={["click"]}
|
||||||
//trigger={["click"]}
|
visible={visible}
|
||||||
visible={visible}
|
style={{
|
||||||
style={{
|
height: "19px",
|
||||||
height: "19px",
|
}}
|
||||||
}}
|
overlay={
|
||||||
overlay={
|
<Card style={{ padding: "1rem" }} onClick={(e) => e.stopPropagation()}>
|
||||||
<Card
|
<FormDatePicker
|
||||||
style={{ padding: "1rem" }}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
value={(record[field] && moment(record[field])) || null}
|
||||||
<FormDatePicker
|
onChange={handleChange}
|
||||||
|
format="MM/DD/YYYY"
|
||||||
|
isDateOnly={!time}
|
||||||
|
/>
|
||||||
|
{time && (
|
||||||
|
<TimePicker
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
value={(record[field] && moment(record[field])) || null}
|
value={(record[field] && moment(record[field])) || null}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
format="MM/DD/YYYY"
|
minuteStep={15}
|
||||||
isDateOnly={!time}
|
format="hh:mm a"
|
||||||
/>
|
/>
|
||||||
{time && (
|
)}
|
||||||
<TimePicker
|
<Button onClick={() => setVisible(false)}>
|
||||||
onClick={(e) => e.stopPropagation()}
|
{t("general.actions.close")}
|
||||||
value={(record[field] && moment(record[field])) || null}
|
</Button>
|
||||||
onChange={handleChange}
|
</Card>
|
||||||
minuteStep={15}
|
}
|
||||||
format="hh:mm a"
|
>
|
||||||
/>
|
<div
|
||||||
)}
|
onClick={() => setVisible(true)}
|
||||||
<Button onClick={() => setVisible(false)}>
|
style={{
|
||||||
{t("general.actions.close")}
|
height: "19px",
|
||||||
</Button>
|
}}
|
||||||
</Card>
|
className={className}
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<div
|
<DateFormatter bordered={false}>{record[field]}</DateFormatter>
|
||||||
onClick={() => setVisible(true)}
|
</div>
|
||||||
style={{
|
</Dropdown>
|
||||||
height: "19px",
|
|
||||||
}}
|
|
||||||
className={className}
|
|
||||||
>
|
|
||||||
<DateFormatter bordered={false}>{record[field]}</DateFormatter>
|
|
||||||
</div>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ export function SignInComponent({
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="email"
|
name="email"
|
||||||
rules={[
|
rules={[
|
||||||
{ required: true, message: t("general.validation.required") },
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("general.validation.required", { label: "Email" }),
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
@@ -71,7 +74,10 @@ export function SignInComponent({
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="password"
|
name="password"
|
||||||
rules={[
|
rules={[
|
||||||
{ required: true, message: t("general.validation.required") },
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("general.validation.required", { label: "Password" }),
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
|
|||||||
xs: "100%",
|
xs: "100%",
|
||||||
sm: "100%",
|
sm: "100%",
|
||||||
md: "100%",
|
md: "100%",
|
||||||
lg: "70%",
|
lg: "100%",
|
||||||
xl: "70%",
|
xl: "90%",
|
||||||
xxl: "70%",
|
xxl: "85%",
|
||||||
};
|
};
|
||||||
const drawerPercentage = selectedBreakpoint
|
const drawerPercentage = selectedBreakpoint
|
||||||
? bpoints[selectedBreakpoint[0]]
|
? bpoints[selectedBreakpoint[0]]
|
||||||
|
|||||||
@@ -42,7 +42,10 @@ export const UPDATE_INVENTORY_LINES = gql`
|
|||||||
|
|
||||||
export const QUERY_OUTSTANDING_INVENTORY = gql`
|
export const QUERY_OUTSTANDING_INVENTORY = gql`
|
||||||
query QUERY_OUTSTANDING_INVENTORY {
|
query QUERY_OUTSTANDING_INVENTORY {
|
||||||
inventory(where: { consumedbybillid: { _is_null: true } }) {
|
inventory(
|
||||||
|
where: { consumedbybillid: { _is_null: true } }
|
||||||
|
order_by: { line_desc: asc }
|
||||||
|
) {
|
||||||
id
|
id
|
||||||
actual_cost
|
actual_cost
|
||||||
actual_price
|
actual_price
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export const QUERY_PARTS_QUEUE = gql`
|
|||||||
vehicleid
|
vehicleid
|
||||||
ownerid
|
ownerid
|
||||||
queued_for_parts
|
queued_for_parts
|
||||||
|
comment
|
||||||
joblines_status {
|
joblines_status {
|
||||||
count
|
count
|
||||||
part_type
|
part_type
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
PageHeader,
|
PageHeader,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Input,
|
Input,
|
||||||
|
Switch,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -42,7 +43,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
|||||||
const [closeJob] = useMutation(UPDATE_JOB);
|
const [closeJob] = useMutation(UPDATE_JOB);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async ({ removefromproduction, ...values }) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const result = await client.mutate({
|
const result = await client.mutate({
|
||||||
mutation: generateJobLinesUpdatesForInvoicing(values.joblines),
|
mutation: generateJobLinesUpdatesForInvoicing(values.joblines),
|
||||||
@@ -63,6 +64,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
|||||||
kmin: values.kmin,
|
kmin: values.kmin,
|
||||||
kmout: values.kmout,
|
kmout: values.kmout,
|
||||||
dms_allocation: values.dms_allocation,
|
dms_allocation: values.dms_allocation,
|
||||||
|
...(removefromproduction ? { inproduction: false } : {}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
|
refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
|
||||||
@@ -248,6 +250,15 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
|||||||
onlyFuture={!!bodyshop.cdk_dealerid}
|
onlyFuture={!!bodyshop.cdk_dealerid}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{!jobRO && (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.actions.removefromproduction")}
|
||||||
|
name="removefromproduction"
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.kmin")}
|
label={t("jobs.fields.kmin")}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import AlertComponent from "../../components/alert/alert.component";
|
|||||||
import JobPartsQueueCount from "../../components/job-parts-queue-count/job-parts-queue-count.component";
|
import JobPartsQueueCount from "../../components/job-parts-queue-count/job-parts-queue-count.component";
|
||||||
import JobRemoveFromPartsQueue from "../../components/job-remove-from-parst-queue/job-remove-from-parts-queue.component";
|
import JobRemoveFromPartsQueue from "../../components/job-remove-from-parst-queue/job-remove-from-parts-queue.component";
|
||||||
import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
|
||||||
|
import ProductionListColumnComment from "../../components/production-list-columns/production-list-columns.comment.component";
|
||||||
import { QUERY_PARTS_QUEUE } from "../../graphql/jobs.queries";
|
import { QUERY_PARTS_QUEUE } from "../../graphql/jobs.queries";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
import { onlyUnique } from "../../utils/arrayHelper";
|
||||||
@@ -228,9 +229,18 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
|||||||
dataIndex: "partsstatus",
|
dataIndex: "partsstatus",
|
||||||
key: "partsstatus",
|
key: "partsstatus",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<JobPartsQueueCount parts={record.joblines_status} />
|
<JobPartsQueueCount
|
||||||
|
style={{ minWidth: "10rem" }}
|
||||||
|
parts={record.joblines_status}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.comment"),
|
||||||
|
dataIndex: "comment",
|
||||||
|
key: "comment",
|
||||||
|
render: (text, record) => <ProductionListColumnComment record={record} />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.queued_for_parts"),
|
title: t("jobs.fields.queued_for_parts"),
|
||||||
dataIndex: "queued_for_parts",
|
dataIndex: "queued_for_parts",
|
||||||
@@ -247,7 +257,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
|||||||
value: false,
|
value: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
//onFilter: (value, record) => record.queued_for_parts === value,
|
onFilter: (value, record) => record.queued_for_parts === value,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<JobRemoveFromPartsQueue
|
<JobRemoveFromPartsQueue
|
||||||
checked={record.queued_for_parts}
|
checked={record.queued_for_parts}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ export const getJobMedia = (jobid) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const getBillMedia = ({ jobid, invoice_number }) => {
|
export const getBillMedia = ({ jobid, invoice_number }) => {
|
||||||
console.log("in the action");
|
|
||||||
return {
|
return {
|
||||||
type: MediaActionTypes.GET_MEDIA_FOR_BILL,
|
type: MediaActionTypes.GET_MEDIA_FOR_BILL,
|
||||||
payload: { jobid, invoice_number },
|
payload: { jobid, invoice_number },
|
||||||
|
|||||||
@@ -147,6 +147,7 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"creating": "Error adding bill. {{error}}",
|
"creating": "Error adding bill. {{error}}",
|
||||||
"deleting": "Error deleting bill. {{error}}",
|
"deleting": "Error deleting bill. {{error}}",
|
||||||
|
"existinginventoryline": "This bill cannot be deleted as it is tied to items in inventory.",
|
||||||
"exporting": "Error exporting payable(s). {{error}}",
|
"exporting": "Error exporting payable(s). {{error}}",
|
||||||
"exporting-partner": "Unable to connect to ImEX Partner. Please ensure it is running and logged in.",
|
"exporting-partner": "Unable to connect to ImEX Partner. Please ensure it is running and logged in.",
|
||||||
"invalidro": "Not a valid RO.",
|
"invalidro": "Not a valid RO.",
|
||||||
@@ -1075,6 +1076,7 @@
|
|||||||
"inventory": {
|
"inventory": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"addtoinventory": "Add to Inventory",
|
"addtoinventory": "Add to Inventory",
|
||||||
|
"addtoro": "Add to RO",
|
||||||
"consumefrominventory": "Consume from Inventory?"
|
"consumefrominventory": "Consume from Inventory?"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
|||||||
@@ -147,6 +147,7 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"creating": "",
|
"creating": "",
|
||||||
"deleting": "",
|
"deleting": "",
|
||||||
|
"existinginventoryline": "",
|
||||||
"exporting": "",
|
"exporting": "",
|
||||||
"exporting-partner": "",
|
"exporting-partner": "",
|
||||||
"invalidro": "",
|
"invalidro": "",
|
||||||
@@ -1075,6 +1076,7 @@
|
|||||||
"inventory": {
|
"inventory": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"addtoinventory": "",
|
"addtoinventory": "",
|
||||||
|
"addtoro": "",
|
||||||
"consumefrominventory": ""
|
"consumefrominventory": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
|||||||
@@ -147,6 +147,7 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"creating": "",
|
"creating": "",
|
||||||
"deleting": "",
|
"deleting": "",
|
||||||
|
"existinginventoryline": "",
|
||||||
"exporting": "",
|
"exporting": "",
|
||||||
"exporting-partner": "",
|
"exporting-partner": "",
|
||||||
"invalidro": "",
|
"invalidro": "",
|
||||||
@@ -1075,6 +1076,7 @@
|
|||||||
"inventory": {
|
"inventory": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"addtoinventory": "",
|
"addtoinventory": "",
|
||||||
|
"addtoro": "",
|
||||||
"consumefrominventory": ""
|
"consumefrominventory": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ export function DateTimeFormatter(props) {
|
|||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
export function TimeFormatter(props) {
|
||||||
|
return props.children
|
||||||
|
? moment(props.children).format(props.format ? props.format : "hh:mm a")
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
export function TimeAgoFormatter(props) {
|
export function TimeAgoFormatter(props) {
|
||||||
const m = moment(props.children);
|
const m = moment(props.children);
|
||||||
|
|||||||
@@ -781,33 +781,33 @@ function GenerateCostingData(job) {
|
|||||||
//Push adjustments to bottom line.
|
//Push adjustments to bottom line.
|
||||||
if (job.adjustment_bottom_line) {
|
if (job.adjustment_bottom_line) {
|
||||||
//Add to totals.
|
//Add to totals.
|
||||||
const Adjustment = Dinero({ amount: job.adjustment_bottom_line * -100 }); //Need to invert, since this is being assigned as a cost.
|
const Adjustment = Dinero({ amount: job.adjustment_bottom_line * 100 }); //Need to invert, since this is being assigned as a cost.
|
||||||
summaryData.totalLaborCost = summaryData.totalLaborCost.add(Adjustment);
|
summaryData.totalLaborSales = summaryData.totalLaborSales.add(Adjustment);
|
||||||
summaryData.totalCost = summaryData.totalCost.add(Adjustment);
|
summaryData.totalSales = summaryData.totalSales.add(Adjustment);
|
||||||
//Add to lines.
|
//Add to lines.
|
||||||
costCenterData.push({
|
costCenterData.push({
|
||||||
id: "Adj",
|
id: "Adj",
|
||||||
cost_center: "Adjustment",
|
cost_center: "Adjustment",
|
||||||
sale_labor: Dinero().toFormat(),
|
sale_labor: Adjustment.toFormat(),
|
||||||
sale_labor_dinero: Dinero(),
|
sale_labor_dinero: Adjustment,
|
||||||
sale_parts: Dinero().toFormat(),
|
sale_parts: Dinero().toFormat(),
|
||||||
sale_parts_dinero: Dinero(),
|
sale_parts_dinero: Dinero(),
|
||||||
sale_additional: Dinero(),
|
sale_additional: Dinero(),
|
||||||
sale_additional_dinero: Dinero(),
|
sale_additional_dinero: Dinero(),
|
||||||
sale_sublet: Dinero(),
|
sale_sublet: Dinero(),
|
||||||
sale_sublet_dinero: Dinero(),
|
sale_sublet_dinero: Dinero(),
|
||||||
sales: Dinero().toFormat(),
|
sales: Adjustment.toFormat(),
|
||||||
sales_dinero: Dinero(),
|
sales_dinero: Adjustment,
|
||||||
cost_parts: Dinero().toFormat(),
|
cost_parts: Dinero().toFormat(),
|
||||||
cost_parts_dinero: Dinero(),
|
cost_parts_dinero: Dinero(),
|
||||||
cost_labor: Adjustment.toFormat(),
|
cost_labor: Dinero().toFormat(), //Adjustment.toFormat(),
|
||||||
cost_labor_dinero: Adjustment,
|
cost_labor_dinero: Dinero(), // Adjustment,
|
||||||
cost_additional: Dinero(),
|
cost_additional: Dinero(),
|
||||||
cost_additional_dinero: Dinero(),
|
cost_additional_dinero: Dinero(),
|
||||||
cost_sublet: Dinero(),
|
cost_sublet: Dinero(),
|
||||||
cost_sublet_dinero: Dinero(),
|
cost_sublet_dinero: Dinero(),
|
||||||
costs: Adjustment.toFormat(),
|
costs: Dinero().toFormat(),
|
||||||
costs_dinero: Adjustment,
|
costs_dinero: Dinero(),
|
||||||
gpdollars_dinero: Dinero(),
|
gpdollars_dinero: Dinero(),
|
||||||
gpdollars: Dinero().toFormat(),
|
gpdollars: Dinero().toFormat(),
|
||||||
gppercent: formatGpPercent(0),
|
gppercent: formatGpPercent(0),
|
||||||
|
|||||||
Reference in New Issue
Block a user