Added quantity to entering invoices BOD-182

This commit is contained in:
Patrick Fic
2020-06-25 16:29:12 -07:00
parent 288e5e4c02
commit ea77478b02
17 changed files with 315 additions and 186 deletions

View File

@@ -348,6 +348,27 @@
<folder_node> <folder_node>
<name>errors</name> <name>errors</name>
<children> <children>
<concept_node>
<name>blocking</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>canceling</name> <name>canceling</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -7150,6 +7171,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>invoices</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>local_tax</name> <name>local_tax</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -14605,6 +14647,27 @@
<folder_node> <folder_node>
<name>errors</name> <name>errors</name>
<children> <children>
<concept_node>
<name>backordering</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>creating</name> <name>creating</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -14972,6 +15035,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>parts_orders</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>print</name> <name>print</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -16,7 +16,6 @@ export default function FormsFieldChanged({ form }) {
return ( return (
<Form.Item shouldUpdate style={{ margin: 0, padding: 0 }}> <Form.Item shouldUpdate style={{ margin: 0, padding: 0 }}>
{() => { {() => {
console.log("Render", form.isFieldsTouched());
if (form.isFieldsTouched()) if (form.isFieldsTouched())
return ( return (
<div> <div>
@@ -29,7 +28,7 @@ export default function FormsFieldChanged({ form }) {
}} }}
/> />
<AlertComponent <AlertComponent
type="warning" type='warning'
message={ message={
<div> <div>
<span>{t("general.messages.unsavedchanges")}</span> <span>{t("general.messages.unsavedchanges")}</span>
@@ -38,8 +37,7 @@ export default function FormsFieldChanged({ form }) {
style={{ style={{
cursor: "pointer", cursor: "pointer",
textDecoration: "underline", textDecoration: "underline",
}} }}>
>
{t("general.actions.reset")} {t("general.actions.reset")}
</span> </span>
</div> </div>

View File

@@ -5,8 +5,8 @@ function FormItemCurrency(props, ref) {
<InputNumber <InputNumber
{...props} {...props}
style={{ width: "initial" }} style={{ width: "initial" }}
formatter={(value) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")} // formatter={(value) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")}
parser={(value) => value.replace(/\$\s?|(,*)/g, "")} // parser={(value) => value.replace(/\$\s?|(,*)/g, "")}
precision={2} precision={2}
/> />
); );

View File

@@ -33,7 +33,7 @@ export function InvoiceFormContainer({ bodyshop, form, invoiceEdit }) {
VendorAutoCompleteData && VendorAutoCompleteData.vendors VendorAutoCompleteData && VendorAutoCompleteData.vendors
} }
loadLines={loadLines} loadLines={loadLines}
lineData={lineData ? lineData.joblines : null} lineData={lineData ? lineData.joblines : []}
responsibilityCenters={bodyshop.md_responsibility_centers || null} responsibilityCenters={bodyshop.md_responsibility_centers || null}
/> />
</div> </div>

View File

@@ -1,10 +1,9 @@
import { DeleteFilled } from "@ant-design/icons"; import { DeleteFilled, WarningOutlined } from "@ant-design/icons";
import { Button, Form, Input, Select, Switch } from "antd"; import { Button, Form, Input, InputNumber, Select, Switch } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import CurrencyInput from "../form-items-formatted/currency-form-item.component"; import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import InvoiceLineSearchSelect from "../invoice-line-search-select/invoice-line-search-select.component"; import InvoiceLineSearchSelect from "../invoice-line-search-select/invoice-line-search-select.component";
import { WarningOutlined } from "@ant-design/icons";
export default function InvoiceEnterModalLinesComponent({ export default function InvoiceEnterModalLinesComponent({
lineData, lineData,
@@ -35,16 +34,17 @@ export default function InvoiceEnterModalLinesComponent({
]}> ]}>
<InvoiceLineSearchSelect <InvoiceLineSearchSelect
options={lineData} options={lineData}
onBlur={null}
onSelect={(value, opt) => { onSelect={(value, opt) => {
setFieldsValue({ setFieldsValue({
invoicelines: getFieldsValue([ invoicelines: getFieldsValue([
"invoicelines", "invoicelines",
]).invoicelines.map((item, idx) => { ]).invoicelines.map((item, idx) => {
if (idx === index) { if (idx === index) {
console.log("opt", opt);
return { return {
...item, ...item,
line_desc: opt.line_desc, line_desc: opt.line_desc,
quantity: opt.part_qty || 1,
actual_price: opt.cost, actual_price: opt.cost,
cost_center: opt.part_type cost_center: opt.part_type
? responsibilityCenters.defaults.costs[ ? responsibilityCenters.defaults.costs[
@@ -71,6 +71,18 @@ export default function InvoiceEnterModalLinesComponent({
]}> ]}>
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item
label={t("invoicelines.fields.quantity")}
key={`${index}quantity`}
name={[field.name, "quantity"]}
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<InputNumber precision={0} />
</Form.Item>
<Form.Item <Form.Item
label={t("invoicelines.fields.actual")} label={t("invoicelines.fields.actual")}
key={`${index}actual_price`} key={`${index}actual_price`}
@@ -118,15 +130,15 @@ export default function InvoiceEnterModalLinesComponent({
const line = getFieldsValue(["invoicelines"]) const line = getFieldsValue(["invoicelines"])
.invoicelines[index]; .invoicelines[index];
if (!!!line) return null; if (!!!line) return null;
const lineDiscount = +( const lineDiscount = (
1 - 1 -
Math.round( Math.round(
(line.actual_cost / line.actual_price) * 100 (line.actual_cost / line.actual_price) * 100
) / ) /
100 100
).toFixed(2); ).toPrecision(2);
if (lineDiscount === discount) return null; if (lineDiscount - discount === 0) return null;
return <WarningOutlined style={{ color: "red" }} />; return <WarningOutlined style={{ color: "red" }} />;
}} }}
</Form.Item> </Form.Item>

View File

@@ -30,10 +30,9 @@ const InvoiceLineSearchSelect = ({
width: 300, width: 300,
}} }}
onChange={setOption} onChange={setOption}
optionFilterProp="line_desc" optionFilterProp='line_desc'
onBlur={onBlur} onBlur={onBlur}
onSelect={onSelect} onSelect={onSelect}>
>
<Select.Option key={null} value={"noline"} cost={0} line_desc={""}> <Select.Option key={null} value={"noline"} cost={0} line_desc={""}>
{t("invoicelines.labels.other")} {t("invoicelines.labels.other")}
</Select.Option> </Select.Option>
@@ -45,14 +44,14 @@ const InvoiceLineSearchSelect = ({
cost={item.act_price ? item.act_price : 0} cost={item.act_price ? item.act_price : 0}
part_type={item.part_type} part_type={item.part_type}
line_desc={item.line_desc} line_desc={item.line_desc}
> part_qty={item.part_qty}>
<Row justify="center" align="middle"> <Row justify='center' align='middle'>
<Col span={12}>{item.line_desc}</Col> <Col span={12}>{item.line_desc}</Col>
<Col span={8}> <Col span={8}>
<Tag color="blue">{item.oem_partno}</Tag> <Tag color='blue'>{item.oem_partno}</Tag>
</Col> </Col>
<Col span={4}> <Col span={4}>
<Tag color="green"> <Tag color='green'>
<CurrencyFormatter>{item.act_price || 0}</CurrencyFormatter> <CurrencyFormatter>{item.act_price || 0}</CurrencyFormatter>
</Tag> </Tag>
</Col> </Col>

View File

@@ -94,8 +94,7 @@ export function InvoicesListTableComponent({
render: (text, record) => ( render: (text, record) => (
<div> <div>
<Link <Link
to={`/manage/invoices?invoiceid=${record.id}&vendorid=${record.vendorid}`} to={`/manage/invoices?invoiceid=${record.id}&vendorid=${record.vendorid}`}>
>
<Button>{t("invoices.actions.edit")}</Button> <Button>{t("invoices.actions.edit")}</Button>
</Link> </Link>
<Button <Button
@@ -120,8 +119,7 @@ export function InvoicesListTableComponent({
isReturn: true, isReturn: true,
}, },
}) })
} }>
>
{t("invoices.actions.return")} {t("invoices.actions.return")}
</Button> </Button>
</div> </div>
@@ -167,6 +165,14 @@ export function InvoicesListTableComponent({
<CurrencyFormatter>{record.actual_cost}</CurrencyFormatter> <CurrencyFormatter>{record.actual_cost}</CurrencyFormatter>
), ),
}, },
{
title: t("invoicelines.fields.quantity"),
dataIndex: "quantity",
key: "quantity",
sorter: (a, b) => a.quantity - b.quantity,
sortOrder:
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
},
{ {
title: t("invoicelines.fields.cost_center"), title: t("invoicelines.fields.cost_center"),
dataIndex: "cost_center", dataIndex: "cost_center",
@@ -237,11 +243,11 @@ export function InvoicesListTableComponent({
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
<Table <Table
size="small" size='small'
scroll={{ x: "50%", y: "40rem" }} scroll={{ x: "50%", y: "40rem" }}
pagination={{ position: "top", defaultPageSize: 25 }} pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns} columns={columns}
rowKey="id" rowKey='id'
dataSource={record.invoicelines} dataSource={record.invoicelines}
/> />
</div> </div>
@@ -249,82 +255,85 @@ export function InvoicesListTableComponent({
}; };
return ( return (
<Table <div>
loading={loading} <Typography.Title level={4}>
size="small" {t("invoices.labels.invoices")}
title={() => ( </Typography.Title>
<div className="imex-table-header"> <Table
<Button onClick={() => refetch()}> loading={loading}
<SyncOutlined /> size='small'
</Button> title={() => (
<Button <div className='imex-table-header'>
onClick={() => { <Button onClick={() => refetch()}>
setInvoiceEnterContext({ <SyncOutlined />
actions: { refetch: invoicesQuery.refetch }, </Button>
context: { <Button
job, onClick={() => {
}, setInvoiceEnterContext({
}); actions: { refetch: invoicesQuery.refetch },
}} context: {
> job,
{t("jobs.actions.postInvoices")} },
</Button> });
<Button }}>
onClick={() => { {t("jobs.actions.postInvoices")}
setReconciliationContext({ </Button>
actions: { refetch: invoicesQuery.refetch }, <Button
context: { onClick={() => {
job, setReconciliationContext({
invoices: actions: { refetch: invoicesQuery.refetch },
(invoicesQuery.data && invoicesQuery.data.invoices) || [], context: {
}, job,
}); invoices:
}} (invoicesQuery.data && invoicesQuery.data.invoices) || [],
> },
{t("jobs.actions.reconcile")} });
</Button>{" "} }}>
<div className="imex-table-header__search"> {t("jobs.actions.reconcile")}
<Input.Search </Button>{" "}
placeholder={t("general.labels.search")} <div className='imex-table-header__search'>
onChange={(e) => { <Input.Search
e.preventDefault(); placeholder={t("general.labels.search")}
}} onChange={(e) => {
/> e.preventDefault();
}}
/>
</div>
</div> </div>
</div> )}
)} scroll={{ x: "50%", y: "40rem" }}
scroll={{ x: "50%", y: "40rem" }} expandedRowRender={rowExpander}
expandedRowRender={rowExpander} pagination={{ position: "top", defaultPageSize: 25 }}
pagination={{ position: "top", defaultPageSize: 25 }} columns={columns}
columns={columns} rowKey='id'
rowKey="id" dataSource={invoices}
dataSource={invoices} onChange={handleTableChange}
onChange={handleTableChange} expandable={{
expandable={{ expandedRowKeys: [selectedInvoice],
expandedRowKeys: [selectedInvoice], onExpand: (expanded, record) => {
onExpand: (expanded, record) => { handleOnRowClick(expanded ? record : null);
handleOnRowClick(expanded ? record : null); },
}, }}
}} rowSelection={{
rowSelection={{ onSelect: (record) => {
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selectedInvoice],
type: "radio",
}}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record); handleOnRowClick(record);
}, // click row },
onDoubleClick: (event) => {}, // double click row selectedRowKeys: [selectedInvoice],
onContextMenu: (event) => {}, // right button click row type: "radio",
onMouseEnter: (event) => {}, // mouse enter row }}
onMouseLeave: (event) => {}, // mouse leave row onRow={(record, rowIndex) => {
}; return {
}} onClick: (event) => {
/> handleOnRowClick(record);
}, // click row
onDoubleClick: (event) => {}, // double click row
onContextMenu: (event) => {}, // right button click row
onMouseEnter: (event) => {}, // mouse enter row
onMouseLeave: (event) => {}, // mouse leave row
};
}}
/>
</div>
); );
} }
export default connect(null, mapDispatchToProps)(InvoicesListTableComponent); export default connect(null, mapDispatchToProps)(InvoicesListTableComponent);

View File

@@ -12,8 +12,6 @@ import AllocationsAssignmentContainer from "../allocations-assignment/allocation
import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container"; import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container"; import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container"; import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
import queryString from "query-string";
import { useHistory, useLocation } from "react-router-dom";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setJobLineEditContext: (context) => setJobLineEditContext: (context) =>
@@ -38,9 +36,6 @@ export function JobLinesComponent({
}); });
const { t } = useTranslation(); const { t } = useTranslation();
const search = queryString.parse(useLocation().search);
const history = useHistory();
const columns = [ const columns = [
{ {
title: "#", title: "#",
@@ -219,8 +214,7 @@ export function JobLinesComponent({
actions: { refetch: refetch }, actions: { refetch: refetch },
context: record, context: record,
}); });
}} }}>
>
{t("general.actions.edit")} {t("general.actions.edit")}
</Button> </Button>
<AllocationsAssignmentContainer <AllocationsAssignmentContainer
@@ -244,9 +238,9 @@ export function JobLinesComponent({
const markMenu = ( const markMenu = (
<Menu onClick={handleMark}> <Menu onClick={handleMark}>
<Menu.Item key="PAA">PAA</Menu.Item> <Menu.Item key='PAA'>PAA</Menu.Item>
<Menu.Item key="PAN">PAN</Menu.Item> <Menu.Item key='PAN'>PAN</Menu.Item>
<Menu.Item key="PAL">PAL</Menu.Item> <Menu.Item key='PAL'>PAL</Menu.Item>
</Menu> </Menu>
); );
@@ -255,16 +249,16 @@ export function JobLinesComponent({
<PartsOrderModalContainer /> <PartsOrderModalContainer />
<Table <Table
columns={columns} columns={columns}
rowKey="id" rowKey='id'
loading={loading} loading={loading}
size="small" size='small'
pagination={{ position: "top", defaultPageSize: 50 }} pagination={{ position: "top", defaultPageSize: 50 }}
dataSource={jobLines} dataSource={jobLines}
onChange={handleTableChange} onChange={handleTableChange}
scroll={{ x: true, y: "40rem" }} scroll={{ x: true, y: "40rem" }}
title={() => { title={() => {
return ( return (
<div className="imex-table-header"> <div className='imex-table-header'>
<Button onClick={() => refetch()}> <Button onClick={() => refetch()}>
<SyncOutlined /> <SyncOutlined />
</Button> </Button>
@@ -278,8 +272,7 @@ export function JobLinesComponent({
linesToOrder: selectedLines, linesToOrder: selectedLines,
}, },
}); });
}} }}>
>
{t("parts.actions.order")} {t("parts.actions.order")}
</Button> </Button>
<Dropdown overlay={markMenu} trigger={["click"]}> <Dropdown overlay={markMenu} trigger={["click"]}>
@@ -295,11 +288,10 @@ export function JobLinesComponent({
actions: { refetch: refetch }, actions: { refetch: refetch },
context: { jobid: jobId }, context: { jobid: jobId },
}); });
}} }}>
>
{t("joblines.actions.new")} {t("joblines.actions.new")}
</Button> </Button>
<div className="imex-table-header__search"> <div className='imex-table-header__search'>
<Input.Search <Input.Search
placeholder={t("general.labels.search")} placeholder={t("general.labels.search")}
onChange={(e) => { onChange={(e) => {
@@ -317,8 +309,7 @@ export function JobLinesComponent({
{record.parts_order_lines.map((item) => ( {record.parts_order_lines.map((item) => (
<div key={item.id}> <div key={item.id}>
<Link <Link
to={`/manage/jobs/${jobId}?tab=partssublet&partsorderid=${item.parts_order.id}`} to={`/manage/jobs/${jobId}?tab=partssublet&partsorderid=${item.parts_order.id}`}>
>
{item.parts_order.order_number || ""} {item.parts_order.order_number || ""}
</Link> </Link>
- -

View File

@@ -19,9 +19,10 @@ export default function JobInvoiceTotals({ loading, invoices, jobTotals }) {
i.invoicelines.forEach((il) => { i.invoicelines.forEach((il) => {
invoiceTotals = invoiceTotals.add( invoiceTotals = invoiceTotals.add(
Dinero({ Dinero({
amount: amount: Math.round(
((il.actual_price || 0) * i.is_credit_memo ? -1 : 1 || 0) * 100, (il.actual_cost || 0) * (i.is_credit_memo ? -1 : 1) * 100
}) ),
}).multiply(il.quantity)
); );
}) })
); );

View File

@@ -14,7 +14,7 @@ export const CalculateAllocationsTotals = (
const r = allCodes.reduce((acc, value) => { const r = allCodes.reduce((acc, value) => {
acc.push({ acc.push({
opcode: value, opcode: value,
cost_center: responsibilitycenters.defaults[value], cost_center: responsibilitycenters.defaults.costs[value],
total: joblines.reduce((acc2, val2) => { total: joblines.reduce((acc2, val2) => {
return val2.mod_lbr_ty === value ? acc2 + val2.mod_lb_hrs : acc2; return val2.mod_lbr_ty === value ? acc2 + val2.mod_lb_hrs : acc2;
}, 0), }, 0),

View File

@@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button } from "antd"; import { Button, notification } from "antd";
import { useMutation } from "@apollo/react-hooks"; import { useMutation } from "@apollo/react-hooks";
import { MUTATION_BACKORDER_PART_LINE } from "../../graphql/parts-orders.queries"; import { MUTATION_BACKORDER_PART_LINE } from "../../graphql/parts-orders.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
@@ -37,6 +37,14 @@ export function PartsOrderLineBackorderButton({
}, },
}); });
if (!!result.errors) {
notification["error"]({
message: t("parts_orders.errors.backordering", {
message: JSON.stringify(result.errors),
}),
});
}
setLoading(false); setLoading(false);
}; };

View File

@@ -1,5 +1,5 @@
import { SyncOutlined } from "@ant-design/icons"; import { SyncOutlined } from "@ant-design/icons";
import { Button, Input, Table } from "antd"; import { Button, Input, Table, Typography } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -147,11 +147,11 @@ export function PartsOrderListTableComponent({
return ( return (
<div> <div>
<Table <Table
size="small" size='small'
scroll={{ x: "50%", y: "40rem" }} scroll={{ x: "50%", y: "40rem" }}
pagination={{ position: "top", defaultPageSize: 25 }} pagination={{ position: "top", defaultPageSize: 25 }}
columns={columns} columns={columns}
rowKey="id" rowKey='id'
dataSource={record.parts_order_lines} dataSource={record.parts_order_lines}
/> />
</div> </div>
@@ -159,57 +159,62 @@ export function PartsOrderListTableComponent({
}; };
return ( return (
<Table <div>
loading={loading} <Typography.Title level={4}>
size="small" {t("parts_orders.labels.parts_orders")}
title={() => ( </Typography.Title>
<div className="imex-table-header"> <Table
<Button onClick={() => refetch()}> loading={loading}
<SyncOutlined /> size='small'
</Button> title={() => (
<div className='imex-table-header'>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<div className="imex-table-header__search"> <div className='imex-table-header__search'>
<Input.Search <Input.Search
placeholder={t("general.labels.search")} placeholder={t("general.labels.search")}
onChange={(e) => { onChange={(e) => {
e.preventDefault(); e.preventDefault();
}} }}
/> />
</div>
</div> </div>
</div> )}
)} scroll={{ x: "50%", y: "40rem" }}
scroll={{ x: "50%", y: "40rem" }} expandedRowRender={rowExpander}
expandedRowRender={rowExpander} pagination={{ position: "top", defaultPageSize: 25 }}
pagination={{ position: "top", defaultPageSize: 25 }} columns={columns}
columns={columns} rowKey='id'
rowKey="id" dataSource={parts_orders}
dataSource={parts_orders} onChange={handleTableChange}
onChange={handleTableChange} expandable={{
expandable={{ expandedRowKeys: [selectedpartsorder],
expandedRowKeys: [selectedpartsorder], onExpand: (expanded, record) => {
onExpand: (expanded, record) => { handleOnRowClick(expanded ? record : null);
handleOnRowClick(expanded ? record : null); },
}, }}
}} rowSelection={{
rowSelection={{ onSelect: (record) => {
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selectedpartsorder],
type: "radio",
}}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record); handleOnRowClick(record);
}, // click row },
onDoubleClick: (event) => {}, // double click row selectedRowKeys: [selectedpartsorder],
onContextMenu: (event) => {}, // right button click row type: "radio",
onMouseEnter: (event) => {}, // mouse enter row }}
onMouseLeave: (event) => {}, // mouse leave row onRow={(record, rowIndex) => {
}; return {
}} onClick: (event) => {
/> handleOnRowClick(record);
}, // click row
onDoubleClick: (event) => {}, // double click row
onContextMenu: (event) => {}, // right button click row
onMouseEnter: (event) => {}, // mouse enter row
onMouseLeave: (event) => {}, // mouse leave row
};
}}
/>
</div>
); );
} }
export default connect(null, mapDispatchToProps)(PartsOrderListTableComponent); export default connect(null, mapDispatchToProps)(PartsOrderListTableComponent);

View File

@@ -32,6 +32,7 @@ const sortByParentId = (arr) => {
sortedList.push(origItem); sortedList.push(origItem);
console.log("DATA CONSISTENCY ERROR: ", origItem.ro_number); console.log("DATA CONSISTENCY ERROR: ", origItem.ro_number);
} }
return 1;
}); });
} }

View File

@@ -1,20 +1,20 @@
import React from "react";
import { MinusCircleTwoTone } from "@ant-design/icons";
import { Dropdown, Menu } from "antd";
import { useTranslation } from "react-i18next";
import { useMutation } from "@apollo/react-hooks"; import { useMutation } from "@apollo/react-hooks";
import { INSERT_APPOINTMENT } from "../../graphql/appointments.queries"; import { Dropdown, Menu, notification } from "antd";
import moment from "moment"; import moment from "moment";
import React from "react";
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_APPOINTMENT } from "../../graphql/appointments.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language)) //setUserLanguage: language => dispatch(setUserLanguage(language))
}); });
export default connect(mapStateToProps, mapDispatchToProps)(ScheduleBlockDay);
export function ScheduleBlockDay({ date, children, refetch, bodyshop }) { export function ScheduleBlockDay({ date, children, refetch, bodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -41,15 +41,23 @@ export function ScheduleBlockDay({ date, children, refetch, bodyshop }) {
variables: { app: [blockAppt] }, variables: { app: [blockAppt] },
}); });
if (!!result.errors) {
notification["error"]({
message: t("appointments.errors.blocking", {
message: JSON.stringify(result.errors),
}),
});
}
if (!!refetch) refetch(); if (!!refetch) refetch();
} }
}; };
const menu = ( const menu = (
<Menu onClick={handleMenu}> <Menu onClick={handleMenu}>
<Menu.Item key="block">{t("appointments.actions.block")}</Menu.Item> <Menu.Item key='block'>{t("appointments.actions.block")}</Menu.Item>
<Menu.Item key="2">2nd menu item</Menu.Item> <Menu.Item key='2'>2nd menu item</Menu.Item>
<Menu.Item key="3">3rd menu item</Menu.Item> <Menu.Item key='3'>3rd menu item</Menu.Item>
</Menu> </Menu>
); );
@@ -59,3 +67,4 @@ export function ScheduleBlockDay({ date, children, refetch, bodyshop }) {
</Dropdown> </Dropdown>
); );
} }
export default connect(mapStateToProps, mapDispatchToProps)(ScheduleBlockDay);

View File

@@ -28,6 +28,7 @@
"viewjob": "View Job" "viewjob": "View Job"
}, },
"errors": { "errors": {
"blocking": "Error creating block {{message}}.",
"canceling": "Error canceling appointment. {{message}}", "canceling": "Error canceling appointment. {{message}}",
"saving": "Error scheduling appointment. {{message}}" "saving": "Error scheduling appointment. {{message}}"
}, },
@@ -477,6 +478,7 @@
"entered_total": "Total of Entered Lines", "entered_total": "Total of Entered Lines",
"federal_tax": "Federal Tax", "federal_tax": "Federal Tax",
"invoice_total": "Invoice Total Amount", "invoice_total": "Invoice Total Amount",
"invoices": "Invoices",
"local_tax": "Local Tax", "local_tax": "Local Tax",
"new": "New Invoice", "new": "New Invoice",
"noneselected": "No invoice selected.", "noneselected": "No invoice selected.",
@@ -906,6 +908,7 @@
"receive": "Receive" "receive": "Receive"
}, },
"errors": { "errors": {
"backordering": "Error backordering part {{message}}.",
"creating": "Error encountered when creating parts order. " "creating": "Error encountered when creating parts order. "
}, },
"fields": { "fields": {
@@ -927,6 +930,7 @@
"inthisorder": "Parts in this Order", "inthisorder": "Parts in this Order",
"newpartsorder": "New Parts Order", "newpartsorder": "New Parts Order",
"orderhistory": "Order History", "orderhistory": "Order History",
"parts_orders": "Parts Orders",
"print": "Show Printed Form", "print": "Show Printed Form",
"returnpartsorder": "Return Parts Order" "returnpartsorder": "Return Parts Order"
}, },

View File

@@ -28,6 +28,7 @@
"viewjob": "Ver trabajo" "viewjob": "Ver trabajo"
}, },
"errors": { "errors": {
"blocking": "",
"canceling": "Error al cancelar la cita. {{message}}", "canceling": "Error al cancelar la cita. {{message}}",
"saving": "Error al programar la cita. {{message}}" "saving": "Error al programar la cita. {{message}}"
}, },
@@ -477,6 +478,7 @@
"entered_total": "", "entered_total": "",
"federal_tax": "", "federal_tax": "",
"invoice_total": "", "invoice_total": "",
"invoices": "",
"local_tax": "", "local_tax": "",
"new": "", "new": "",
"noneselected": "", "noneselected": "",
@@ -906,6 +908,7 @@
"receive": "" "receive": ""
}, },
"errors": { "errors": {
"backordering": "",
"creating": "Se encontró un error al crear el pedido de piezas." "creating": "Se encontró un error al crear el pedido de piezas."
}, },
"fields": { "fields": {
@@ -927,6 +930,7 @@
"inthisorder": "Partes en este pedido", "inthisorder": "Partes en este pedido",
"newpartsorder": "", "newpartsorder": "",
"orderhistory": "Historial de pedidos", "orderhistory": "Historial de pedidos",
"parts_orders": "",
"print": "Mostrar formulario impreso", "print": "Mostrar formulario impreso",
"returnpartsorder": "" "returnpartsorder": ""
}, },

View File

@@ -28,6 +28,7 @@
"viewjob": "Voir le travail" "viewjob": "Voir le travail"
}, },
"errors": { "errors": {
"blocking": "",
"canceling": "Erreur lors de l'annulation du rendez-vous. {{message}}", "canceling": "Erreur lors de l'annulation du rendez-vous. {{message}}",
"saving": "Erreur lors de la planification du rendez-vous. {{message}}" "saving": "Erreur lors de la planification du rendez-vous. {{message}}"
}, },
@@ -477,6 +478,7 @@
"entered_total": "", "entered_total": "",
"federal_tax": "", "federal_tax": "",
"invoice_total": "", "invoice_total": "",
"invoices": "",
"local_tax": "", "local_tax": "",
"new": "", "new": "",
"noneselected": "", "noneselected": "",
@@ -906,6 +908,7 @@
"receive": "" "receive": ""
}, },
"errors": { "errors": {
"backordering": "",
"creating": "Erreur rencontrée lors de la création de la commande de pièces." "creating": "Erreur rencontrée lors de la création de la commande de pièces."
}, },
"fields": { "fields": {
@@ -927,6 +930,7 @@
"inthisorder": "Pièces dans cette commande", "inthisorder": "Pièces dans cette commande",
"newpartsorder": "", "newpartsorder": "",
"orderhistory": "Historique des commandes", "orderhistory": "Historique des commandes",
"parts_orders": "",
"print": "Afficher le formulaire imprimé", "print": "Afficher le formulaire imprimé",
"returnpartsorder": "" "returnpartsorder": ""
}, },