diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/classes/item.js | 6 | ||||
-rw-r--r-- | src/components/editors/invoice-headers-editor.js | 40 | ||||
-rw-r--r-- | src/components/pickers/item-picker.js | 25 | ||||
-rw-r--r-- | src/components/pickers/scss/item-picker.scss | 4 | ||||
-rw-r--r-- | src/components/tables/invoice-item-table.js | 2 | ||||
-rw-r--r-- | src/components/tables/invoice-summary.js | 7 | ||||
-rw-r--r-- | src/components/tables/item-table.js | 2 | ||||
-rw-r--r-- | src/components/tables/scss/summary.scss | 25 | ||||
-rw-r--r-- | src/components/tables/scss/table.scss | 2 | ||||
-rw-r--r-- | src/views/invoice/new.js | 17 | ||||
-rw-r--r-- | src/views/invoice/scss/invoice.scss | 22 |
11 files changed, 136 insertions, 16 deletions
diff --git a/src/classes/item.js b/src/classes/item.js index e9e692b..65e8fed 100644 --- a/src/classes/item.js +++ b/src/classes/item.js @@ -24,7 +24,7 @@ export const currency = value => c(value, { decimal: '.', seperator: ',', precision: 2, - symbol: '₹', + symbol: '₹ ', }); export class Item { @@ -74,8 +74,8 @@ export const editItem = (item, ok, fail) => { .catch(err => fail()); } -export const getDiscountValue = (item) => item.DiscountPercentage > 0 - ? currency(item.UnitPrice).multiply(item.Quantity).divide(100) : currency(0.00) +export const getDiscountValue = (item) => + currency(item.UnitPrice).multiply(item.Quantity).divide(100).multiply(item.DiscountPercentage) export const getGSTValue = (item) => item.GSTPercentage > 0 ? currency(item.UnitPrice).multiply(item.Quantity).subtract(getDiscountValue).divide(100).multiply(item.GSTPercentage) : currency(0.00) diff --git a/src/components/editors/invoice-headers-editor.js b/src/components/editors/invoice-headers-editor.js new file mode 100644 index 0000000..f71b319 --- /dev/null +++ b/src/components/editors/invoice-headers-editor.js @@ -0,0 +1,40 @@ +/* OpenBills-web - Web based libre billing software + * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@vidhukant.xyz> + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +import './scss/item-editor.scss'; + +import { useState, useEffect } from 'react'; + +const InvoiceHeadersEditor = ({roundOff, setRoundOff}) => { + + return ( + <> + <h1>Invoice Options:</h1> + <form onSubmit={(e) => e.preventDefault()}> + <label> + <input + type="checkbox" + onChange={() => setRoundOff(prev => !prev)} + checked={roundOff}/> + Round off the Total + </label> + </form> + </> + ) +} + +export default InvoiceHeadersEditor; diff --git a/src/components/pickers/item-picker.js b/src/components/pickers/item-picker.js index c486660..3029fb5 100644 --- a/src/components/pickers/item-picker.js +++ b/src/components/pickers/item-picker.js @@ -44,15 +44,18 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { } const handleInput = e => { - const { name, value, type } = e.target; - const val = type === "number" ? parseFloat(value) : value + const { name, value } = e.target; setItem(prevItem => ({ ...prevItem, - [name]: type === "number" ? (isNaN(val) ? prevItem[name] : val) : val + [name]: `${value}` })); } const validate = () => { + if (!isNumeric(item.Quantity) || !isNumeric(item.DiscountPercentage) + || !isNumeric(item.GSTPercentage) || !isNumeric(item.UnitPrice)) { + return false; + } if (item.Id === null) { return false; } @@ -68,7 +71,8 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { if (item.MaxQuantity > 0 && item.Quantity > item.MaxQuantity) { return false; } - if (item.DiscountPercentage > 100 || item.GSTPercentage > 100) { + if (item.DiscountPercentage > 100 || item.DiscountPercentage < 0 + || item.GSTPercentage > 100 || item.GSTPercentage < 0) { return false; } return true; @@ -83,6 +87,8 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { } } + const isNumeric = (i) => !isNaN(i) && !isNaN(parseFloat(i)); + // input elements are sorted on the basis of // how likely they are going to be edited return ( @@ -106,10 +112,10 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { Quantity: <input type="number" + className={((!isNumeric(item.Quantity) || (item.MaxQuantity > 0 && item.Quantity > item.MaxQuantity) || (item.Quantity < item.MinQuantity))) ? "warning" : ""} step="0.01" value={item.Quantity} name="Quantity" - min={item.MinQuantity > 0 ? item.MinQuantity : 1} max={item.MaxQuantity > 0 ? item.MaxQuantity : null} onChange={handleInput} /> </label> @@ -117,6 +123,7 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { Price: <input type="number" + className={(!isNumeric(item.UnitPrice) || item.UnitPrice < 0) ? "warning" : ""} step="0.01" value={item.UnitPrice} name="UnitPrice" @@ -126,7 +133,10 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { Discount %: <input type="number" - step="0.01" + className={(!isNumeric(item.DiscountPercentage) || item.DiscountPercentage < 0 || item.DiscountPercentage > 100) ? "warning" : ""} + max="100" + min="0" + step="0.1" value={item.DiscountPercentage} name="DiscountPercentage" onChange={handleInput} /> @@ -152,6 +162,9 @@ const ItemPicker = ({invoiceItems, addInvoiceItem}) => { <input type="number" step="0.01" + className={(!isNumeric(item.GSTPercentage) || item.GSTPercentage < 0 || item.GSTPercentage > 100) ? "warning" : ""} + max="100" + min="0" value={item.GSTPercentage} name="GSTPercentage" onChange={handleInput} /> diff --git a/src/components/pickers/scss/item-picker.scss b/src/components/pickers/scss/item-picker.scss index b3e797a..63ddbcf 100644 --- a/src/components/pickers/scss/item-picker.scss +++ b/src/components/pickers/scss/item-picker.scss @@ -92,4 +92,8 @@ color: $fgColorAlt; background-color: $warningColor; } + + input.warning { + border-color: $warningColor; + } } diff --git a/src/components/tables/invoice-item-table.js b/src/components/tables/invoice-item-table.js index d008ebc..865b326 100644 --- a/src/components/tables/invoice-item-table.js +++ b/src/components/tables/invoice-item-table.js @@ -38,7 +38,7 @@ const ItemTable = ({items, setItems, isInterstate, sum}) => { */ return ( <> - <table> + <table className={"item-table"}> <thead> <tr> <th>S. No</th> diff --git a/src/components/tables/invoice-summary.js b/src/components/tables/invoice-summary.js index 7018d50..a5c594f 100644 --- a/src/components/tables/invoice-summary.js +++ b/src/components/tables/invoice-summary.js @@ -15,16 +15,17 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import './scss/summary.scss'; import { currency } from '../../classes/item'; -const InvoiceSummary = ({sum}) => { +const InvoiceSummary = ({sum, roundOff}) => { const totalRoundedOff = currency(sum.Amount !== undefined ? Math.round(sum.Amount.value) : 0.00); - const roundedOffDiff = sum.Amount !== undefined ? sum.Amount.subtract(totalRoundedOff) : currency(0.00); + const roundedOffDiff = sum.Amount !== undefined && roundOff ? sum.Amount.subtract(totalRoundedOff) : currency(0.00); return ( <> <h1>Summary:</h1> - <table> + <table className={"summary-table"}> <tbody> {sum.UnitPrice !== undefined && <tr> diff --git a/src/components/tables/item-table.js b/src/components/tables/item-table.js index 5a405a5..2fb7210 100644 --- a/src/components/tables/item-table.js +++ b/src/components/tables/item-table.js @@ -39,7 +39,7 @@ const ItemTable = (props) => { } return ( - <table> + <table className={"item-table"}> <thead> <tr> <th>S. No</th> diff --git a/src/components/tables/scss/summary.scss b/src/components/tables/scss/summary.scss new file mode 100644 index 0000000..d5714f9 --- /dev/null +++ b/src/components/tables/scss/summary.scss @@ -0,0 +1,25 @@ +/* OpenBills-web - Web based libre billing software + * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@vidhukant.xyz> + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +@import "colors"; + +table.summary-table { + min-width: 25rem; + tr:hover { + background-color: rgba($thColor, 0.4); + } +} diff --git a/src/components/tables/scss/table.scss b/src/components/tables/scss/table.scss index 0bb5a48..d201a49 100644 --- a/src/components/tables/scss/table.scss +++ b/src/components/tables/scss/table.scss @@ -17,7 +17,7 @@ @import "colors"; -table { +table.item-table { width: 90%; margin: auto; diff --git a/src/views/invoice/new.js b/src/views/invoice/new.js index be180cf..cacf8d3 100644 --- a/src/views/invoice/new.js +++ b/src/views/invoice/new.js @@ -15,10 +15,13 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import "./scss/invoice.scss"; + import ClientPicker from '../../components/pickers/client-picker'; import ItemPicker from '../../components/pickers/item-picker'; import ItemTable from '../../components/tables/invoice-item-table'; import InvoiceSummary from '../../components/tables/invoice-summary'; +import HeadersEditor from '../../components/editors/invoice-headers-editor'; import { InvoiceClient } from '../../classes/client'; import { calcSum, currency } from '../../classes/item'; @@ -29,6 +32,7 @@ const NewInvoicePage = () => { const [client, setClient] = useState(new InvoiceClient()); const [shippingAddressId, setShippingAddressId] = useState(-1); const [items, setItems] = useState([]); + const [roundOffTotal, setRoundOffTotal] = useState(true); //TODO: load from config //const [isInterstate, setIsInterstate] = useState(false); const isInterstate = false; // temporary const [sum, setSum] = useState({ @@ -58,7 +62,18 @@ const NewInvoicePage = () => { setItems={setItems} isInterstate={isInterstate} sum={sum} /> - <InvoiceSummary sum={sum} /> + <div className={"two-col"}> + <div> + <HeadersEditor + roundOff={roundOffTotal} + setRoundOff={setRoundOffTotal} /> + </div> + <div> + <InvoiceSummary + sum={sum} + roundOff={roundOffTotal} /> + </div> + </div> </> ); } diff --git a/src/views/invoice/scss/invoice.scss b/src/views/invoice/scss/invoice.scss new file mode 100644 index 0000000..32607b1 --- /dev/null +++ b/src/views/invoice/scss/invoice.scss @@ -0,0 +1,22 @@ +/* OpenBills-web - Web based libre billing software + * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@vidhukant.xyz> + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +.two-col { + width: 100%; + display: flex; + justify-content: space-between; +} |