diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index ec11ee357..0223ded6c 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -1750,6 +1750,32 @@ invoicelines + + actions + + + newline + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + fields @@ -1863,6 +1889,27 @@ labels + + entered + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + other false @@ -1884,6 +1931,27 @@ + + unreconciled + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + diff --git a/client/src/components/form-items-formatted/currency-form-item.component.jsx b/client/src/components/form-items-formatted/currency-form-item.component.jsx index 85c82e8e0..0c24be519 100644 --- a/client/src/components/form-items-formatted/currency-form-item.component.jsx +++ b/client/src/components/form-items-formatted/currency-form-item.component.jsx @@ -4,10 +4,9 @@ function FormItemCurrency(props, ref) { return ( `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")} - parser={value => value.replace(/\$\s?|(,*)/g, "")} + //formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",")} + // parser={value => value.replace(/\$\s?|(,*)/g, "")} precision={2} - /> ); } diff --git a/client/src/components/invoice-enter-modal/invoice-enter-modal.component.jsx b/client/src/components/invoice-enter-modal/invoice-enter-modal.component.jsx index 2719e8b66..b28bc0e34 100644 --- a/client/src/components/invoice-enter-modal/invoice-enter-modal.component.jsx +++ b/client/src/components/invoice-enter-modal/invoice-enter-modal.component.jsx @@ -1,8 +1,18 @@ -import { Button, DatePicker, Form, Input, Modal, Select, Switch } from "antd"; +import { + Button, + DatePicker, + Form, + Input, + Modal, + Select, + Switch, + Tag +} from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; import CurrencyInput from "../form-items-formatted/currency-form-item.component"; import InvoiceEnterModalLinesComponent from "./invoice-enter-modal.lines.component"; + export default function InvoiceEnterModalComponent({ visible, invoice, @@ -15,15 +25,12 @@ export default function InvoiceEnterModalComponent({ handleVendorSelect, vendorAutoCompleteOptions, lineData, - linesState, - vendor + vendor, + job }) { const { t } = useTranslation(); const [form] = Form.useForm(); const { resetFields } = form; - //Default Values to be set in form. - // {getFieldDecorator("retail", { initialValue: jobLine.act_price })( - // initialValue: jobLine.act_price * (discount ? 1 - discount : 1) return (
@@ -53,7 +60,11 @@ export default function InvoiceEnterModalComponent({ > + @@ -105,8 +120,11 @@ export default function InvoiceEnterModalComponent({ @@ -114,8 +132,11 @@ export default function InvoiceEnterModalComponent({ @@ -130,8 +151,11 @@ export default function InvoiceEnterModalComponent({ @@ -142,6 +166,7 @@ export default function InvoiceEnterModalComponent({ discount={vendor && vendor.discount} form={form} /> + diff --git a/client/src/components/invoice-enter-modal/invoice-enter-modal.container.jsx b/client/src/components/invoice-enter-modal/invoice-enter-modal.container.jsx index da75903e0..0aad70dbf 100644 --- a/client/src/components/invoice-enter-modal/invoice-enter-modal.container.jsx +++ b/client/src/components/invoice-enter-modal/invoice-enter-modal.container.jsx @@ -69,7 +69,7 @@ function InvoiceEnterModalContainer({ const handleFinish = values => { console.log("values", values); alert("Closing this modal."); - // toggleModalVisible(); + // toggleModalVisible(); // if (!jobLineEditModal.context.id) { // insertJobLine({ // variables: { @@ -141,6 +141,7 @@ function InvoiceEnterModalContainer({ )[0] : null } + job={invoiceEnterModal.context.job || null} /> ); } diff --git a/client/src/components/invoice-enter-modal/invoice-enter-modal.lines.component.jsx b/client/src/components/invoice-enter-modal/invoice-enter-modal.lines.component.jsx index a0f347a02..d6efded68 100644 --- a/client/src/components/invoice-enter-modal/invoice-enter-modal.lines.component.jsx +++ b/client/src/components/invoice-enter-modal/invoice-enter-modal.lines.component.jsx @@ -1,7 +1,8 @@ import { DeleteFilled } from "@ant-design/icons"; -import { Button, Form, Input, Select } from "antd"; -import React from "react"; +import { Button, Col, Form, Input, Row, Select, Tag } from "antd"; +import React, { useState } from "react"; import { useTranslation } from "react-i18next"; +import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyInput from "../form-items-formatted/currency-form-item.component"; export default function InvoiceEnterModalLinesComponent({ @@ -11,128 +12,211 @@ export default function InvoiceEnterModalLinesComponent({ }) { const { t } = useTranslation(); const { setFieldsValue, getFieldsValue } = form; - return ( - - {(fields, { add, remove }) => { - return ( -
- {fields.map((field, index) => ( - -
- - - - {console.log( - 'getFieldsValue("invoicelines").invoicelines[index]', - getFieldsValue("invoicelines").invoicelines[index] - )} - {getFieldsValue("invoicelines").invoicelines[index] && - getFieldsValue("invoicelines").invoicelines[index] - .line_desc && - !getFieldsValue("invoicelines").invoicelines[index].joblineid - ? "Other" - : null} - - { - setFieldsValue({ - invoicelines: getFieldsValue( - "invoicelines" - ).invoicelines.map((item, idx) => { - if (idx === index) { - return { - ...item, - actual_cost: - parseFloat(e.target.value.substring(1)) * 1 - - discount - }; - } - return item; + const [amounts, setAmounts] = useState({ invoiceTotal: 0, enteredAmount: 0 }); + + return ( +
+ + {(fields, { add, remove }) => { + return ( +
+ {fields.map((field, index) => ( + +
+ + + + {getFieldsValue("invoicelines").invoicelines[index] && + getFieldsValue("invoicelines").invoicelines[index] + .joblinename && + !getFieldsValue("invoicelines").invoicelines[index] + .joblineid ? ( + + + + ) : null} + + + { + setFieldsValue({ + invoicelines: getFieldsValue( + "invoicelines" + ).invoicelines.map((item, idx) => { + if (idx === index) { + return { + ...item, + actual_cost: + parseFloat(e.target.value) * (1 - discount) + }; + } + return item; + }) + }); + }} + /> + + + + setAmounts({ + invoiceTotal: getFieldsValue().total, + enteredTotal: getFieldsValue("invoicelines") + .invoicelines + ? getFieldsValue( + "invoicelines" + ).invoicelines.reduce( + (acc, value) => + acc + + (value && value.actual_cost + ? value.actual_cost + : 0), + 0 + ) + : 0 }) - }); + } + /> + + + + + + { + remove(field.name); }} /> - - - - - - - - - { - remove(field.name); - }} - /> -
+
+ + ))} + + - ))} - - - -
- ); - }} - +
+ ); + }} + + + + {t("invoicelines.labels.entered")} + {amounts.enteredTotal} + + + + + {t("invoicelines.labels.unreconciled")}: + + {amounts.invoiceTotal - amounts.enteredTotal} + + + + +
); } diff --git a/client/src/redux/store.js b/client/src/redux/store.js index 7a5034e60..0dfd35ffa 100644 --- a/client/src/redux/store.js +++ b/client/src/redux/store.js @@ -1,4 +1,4 @@ -import { createStore, applyMiddleware } from "redux"; +import { createStore, applyMiddleware, compose } from "redux"; import { persistStore } from "redux-persist"; import { createLogger } from "redux-logger"; import createSagaMiddleware from "redux-saga"; @@ -11,7 +11,19 @@ if (process.env.NODE_ENV === "development") { middlewares.push(createLogger({ collapsed: true, diff: true })); } -export const store = createStore(rootReducer, applyMiddleware(...middlewares)); +const composeEnhancers = + typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ + // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize... + }) + : compose; + +const enhancer = composeEnhancers( + applyMiddleware(...middlewares) + // other store enhancers if any +); + +export const store = createStore(rootReducer, enhancer); sagaMiddleWare.run(rootSaga); export const persistor = persistStore(store); diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index a9c7de65b..83f2fc451 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -145,6 +145,9 @@ } }, "invoicelines": { + "actions": { + "newline": "New Line" + }, "fields": { "actual": "Actual", "actual_cost": "Actual Cost", @@ -153,7 +156,9 @@ "retail": "Retail" }, "labels": { - "other": "Other Item" + "entered": "Entered", + "other": "--Not On Estimate--", + "unreconciled": "Unreconciled" } }, "invoices": { diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index d42394bc8..8ea76012e 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -145,6 +145,9 @@ } }, "invoicelines": { + "actions": { + "newline": "" + }, "fields": { "actual": "", "actual_cost": "", @@ -153,7 +156,9 @@ "retail": "" }, "labels": { - "other": "" + "entered": "", + "other": "", + "unreconciled": "" } }, "invoices": { diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index b8307049a..04de6e07e 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -145,6 +145,9 @@ } }, "invoicelines": { + "actions": { + "newline": "" + }, "fields": { "actual": "", "actual_cost": "", @@ -153,7 +156,9 @@ "retail": "" }, "labels": { - "other": "" + "entered": "", + "other": "", + "unreconciled": "" } }, "invoices": {