diff options
-rw-r--r-- | src/classes/item.js | 17 | ||||
-rw-r--r-- | src/components/pickers/item-picker.js | 10 | ||||
-rw-r--r-- | src/components/tables/invoice-item-table.js | 116 | ||||
-rw-r--r-- | src/components/tables/scss/table.scss | 8 | ||||
-rw-r--r-- | src/views/invoice/new.js | 13 |
5 files changed, 113 insertions, 51 deletions
diff --git a/src/classes/item.js b/src/classes/item.js index 0486262..639a63f 100644 --- a/src/classes/item.js +++ b/src/classes/item.js @@ -64,3 +64,20 @@ export const editItem = (item, ok, fail) => { .then(res => ok()) .catch(err => fail()) } + +export const getDiscountValue = (item) => item.DiscountPercentage > 0 + ? ((item.UnitPrice * item.Quantity)/100) * item.DiscountPercentage : 0.00; + +export const getGSTValue = (item) => item.GSTPercentage > 0 + ? (((item.UnitPrice * item.Quantity) - getDiscountValue(item))/100) * item.GSTPercentage : 0.00; + +export const getAmount = (item) => + (item.UnitPrice * item.Quantity) - getDiscountValue(item) + getGSTValue(item) + +export const calcSum = (items) => items.reduce((prev, current, id, arr) => ({ + GST: prev.GST + getGSTValue(current), + Discount: prev.Discount + getDiscountValue(current), + UnitPrice: prev.UnitPrice + current.UnitPrice, + Amount: prev.Amount + getAmount(current), + Quantity: prev.Quantity + current.Quantity +}), {GST: 0, Discount: 0, UnitPrice: 0, Amount: 0, Quantity: 0}); diff --git a/src/components/pickers/item-picker.js b/src/components/pickers/item-picker.js index 339319f..d756427 100644 --- a/src/components/pickers/item-picker.js +++ b/src/components/pickers/item-picker.js @@ -37,10 +37,10 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { } const handleInput = e => { - const { name, value } = e.target; + const { name, value, type } = e.target; setItem(prevItem => ({ ...prevItem, - [name]: value + [name]: type === "number" ? parseFloat(value) : value })); } @@ -65,7 +65,7 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { <option key="placeholder" value={""} disabled>Select an Item</option> {items.map(i => <option key={i.Id} value={i.Id} disabled={invoiceItems.some(j => j.Id === i.Id)}> - {i.Name}{i.Brand.Id === null ? "" : " - " + i.Brand.Name} + {i.Name}{i.Brand.Id === undefined ? "" : " - " + i.Brand.Name} </option> )} </select> @@ -76,8 +76,8 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { type="number" value={item.Quantity} name="Quantity" - min={item.MinQuantity} - max={item.MaxQuantity} + min={item.MinQuantity > 0 ? item.MinQuantity : 1} + max={item.MaxQuantity > 0 ? item.MaxQuantity : null} onChange={handleInput} /> </label> <label className={"narrow"}> diff --git a/src/components/tables/invoice-item-table.js b/src/components/tables/invoice-item-table.js index 6b0a1a5..12ee52e 100644 --- a/src/components/tables/invoice-item-table.js +++ b/src/components/tables/invoice-item-table.js @@ -16,11 +16,11 @@ */ import './scss/table.scss'; -import { deleteItem } from './../../classes/item'; +import { deleteItem, getDiscountValue, getGSTValue, getAmount } from './../../classes/item'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faPencil, faTrashCan } from '@fortawesome/free-solid-svg-icons' -const ItemTable = ({items, setItems}) => { +const ItemTable = ({items, setItems, isInterstate, sum}) => { const handleEdit = (i) => { alert("coming soon; please delete and add item again"); } @@ -29,15 +29,7 @@ const ItemTable = ({items, setItems}) => { setItems(items.filter(i => i.Id !== item.Id)); } - /* TODO: all the math should be done here - * i.e CGST, IGST, total price (i.e price x quantity) - * discount/gst value (i.e number instead of percentage) - * - * the total cost and the like may be handled by - * parent component since they are needed - * by other things (probably) - * - * all the values will be calculated on runtime. + /* all the values will be calculated on runtime. * the database will only store the unit price * and gst/discount *percentages* and everything else * will be calculated on runtime. i.e the @@ -45,40 +37,80 @@ const ItemTable = ({items, setItems}) => { * those same values shown to the user while creating the invoice */ return ( - <table> - <thead> - <tr> - <th>S. No</th> - <th>Name</th> - <th>Description</th> - <th>Brand Name</th> - <th>UOM</th> - <th>HSN</th> - <th>Unit Price</th> - <th>GST %</th> - {/* TODO: CGST, IGST, etc */} - <th></th> - </tr> - </thead> - <tbody> - {items && items.map((i, id=id+1) => ( - <tr key={id}> - <td>{id+1}</td> - <td className={i.Name === "" ? "empty" : ""}>{i.Name}</td> - <td className={i.Description === "" ? "empty" : ""}>{i.Description}</td> - <td className={i.Brand.Name === "" ? "empty" : ""}>{i.Brand.Name}</td> - <td className={i.UnitOfMeasure === "" ? "empty" : ""}>{i.UnitOfMeasure}</td> - <td className={i.HSN === "" ? "empty" : ""}>{i.HSN}</td> - <td className={i.UnitPrice === 0.0 ? "empty" : ""}>{i.UnitPrice}</td> - <td className={i.GSTPercentage === 0.0 ? "empty" : ""}>{i.GSTPercentage}</td> + <> + <table> + <thead> + <tr> + <th>S. No</th> + <th>Name</th> + <th>Description</th> + <th>Brand Name</th> + <th>Quantity</th> + <th>UOM</th> + <th>Unit Price</th> + <th>Discount (%)</th> + {isInterstate + ? <th>IGST (%)</th> + : <> + <th>SGST (%)</th> + <th>CGST (%)</th> + </> + } + <th>HSN</th> + <th>Amount</th> + <th></th> + </tr> + </thead> + <tbody> + {items && items.map((i, id) => ( + <tr key={id}> + <td>{id+1}</td> + <td className={i.Name === "" ? "empty" : ""}>{i.Name}</td> + <td className={i.Description === "" ? "empty" : ""}>{i.Description}</td> + <td className={i.Brand.Name === "" ? "empty" : ""}>{i.Brand.Name}</td> + <td>{i.Quantity}</td> + <td className={i.UnitOfMeasure === "" ? "empty" : ""}>{i.UnitOfMeasure}</td> + <td className={i.UnitPrice > 0 ? "" : "empty"}>{i.UnitPrice}</td> + <td className={i.DiscountPercentage > 0 ? "" : "empty"}>{getDiscountValue(i)} ({i.DiscountPercentage}%)</td> + {isInterstate + ? <td className={i.GSTPercentage > 0 ? "" : "empty"}>{getGSTValue(i)} ({i.GSTPercentage}%)</td> + : <> + <td className={i.GSTPercentage > 0 ? "" : "empty"}>{getGSTValue(i) / 2} ({i.GSTPercentage / 2}%)</td> + <td className={i.GSTPercentage > 0 ? "" : "empty"}>{getGSTValue(i) / 2} ({i.GSTPercentage / 2}%)</td> + </> + } + <td className={i.HSN === "" ? "empty" : ""}>{i.HSN}</td> + <td>{getAmount(i)}</td> + <td className={"buttons"}> + <FontAwesomeIcon icon={faPencil} onClick={() => handleEdit(i)}/> + <FontAwesomeIcon icon={faTrashCan} onClick={() => handleDelete(i)}/> + </td> + </tr> + ))} + <tr className={"total"}> + <td>Total</td> + <td className={"empty"}></td> + <td className={"empty"}></td> + <td className={"empty"}></td> + <td className={sum.Quantity > 0 ? "" : "empty"}>{sum.Quantity}</td> + <td className={"empty"}></td> + <td className={sum.UnitPrice > 0 ? "" : "empty"}>{sum.UnitPrice}</td> + <td className={sum.Discount > 0 ? "" : "empty"}>{sum.Discount}</td> + {isInterstate + ? <td className={sum.GST > 0 ? "" : "empty"}>{sum.GST}</td> + : <> + <td className={sum.GST > 0 ? "" : "empty"}>{sum.GST / 2}</td> + <td className={sum.GST > 0 ? "" : "empty"}>{sum.GST / 2}</td> + </> + } + <td className={"empty"}></td> + <td className={sum.Amount > 0 ? "" : "empty"}>{sum.Amount}</td> <td className={"buttons"}> - <FontAwesomeIcon icon={faPencil} onClick={() => handleEdit(i)}/> - <FontAwesomeIcon icon={faTrashCan} onClick={() => handleDelete(i)}/> </td> </tr> - ))} - </tbody> - </table> + </tbody> + </table> + </> ); } diff --git a/src/components/tables/scss/table.scss b/src/components/tables/scss/table.scss index 13e247a..0bb5a48 100644 --- a/src/components/tables/scss/table.scss +++ b/src/components/tables/scss/table.scss @@ -53,3 +53,11 @@ table { white-space: pre-line; } } + +table .total { + font-size: 1.2em; + color: $primaryAccentColor; + td:not(.empty) { + border-color: $secondaryAccentColor; + } +} diff --git a/src/views/invoice/new.js b/src/views/invoice/new.js index 70bc545..1d162ad 100644 --- a/src/views/invoice/new.js +++ b/src/views/invoice/new.js @@ -20,6 +20,7 @@ import ItemPicker from '../../components/pickers/item-picker'; import ItemTable from '../../components/tables/invoice-item-table'; import { InvoiceClient } from '../../classes/client'; +import { calcSum } from '../../classes/item'; import { useState, useEffect } from 'react'; @@ -27,10 +28,12 @@ const NewInvoicePage = () => { const [client, setClient] = useState(new InvoiceClient()); const [shippingAddressId, setShippingAddressId] = useState(-1); const [items, setItems] = useState([]); + const [isInterstate, setIsInterstate] = useState(false); + const [sum, setSum] = useState({}); - useEffect(() => { - setShippingAddressId(-1); - }, [client]); + useEffect(() => setShippingAddressId(-1), [client]); + + useEffect(() => setSum(calcSum(items)), [items]); return ( <> @@ -44,7 +47,9 @@ const NewInvoicePage = () => { addInvoiceItem={(item) => setItems(prev => [...prev, item])} /> <ItemTable items={items} - setItems={setItems} /> + setItems={setItems} + isInterstate={isInterstate} + sum={sum} /> </> ); } |