diff --git a/package-lock.json b/package-lock.json
index 5b8710a..a74cef6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "invoice",
+ "name": "invoice_and_zakat_tracking_system",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "name": "invoice",
+ "name": "invoice_and_zakat_tracking_system",
"version": "0.1.0",
"dependencies": {
"@emotion/react": "^11.8.2",
@@ -16,6 +16,7 @@
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
+ "axios": "^1.5.1",
"buffer": "^6.0.3",
"firebase": "^9.6.8",
"react": "^17.0.2",
@@ -5601,6 +5602,29 @@
"node": ">=4"
}
},
+ "node_modules/axios": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz",
+ "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
+ "dependencies": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/axios/node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@@ -7467,9 +7491,9 @@
}
},
"node_modules/domelementtype": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
- "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
@@ -8829,9 +8853,9 @@
"integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg=="
},
"node_modules/follow-redirects": {
- "version": "1.14.9",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
- "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
+ "version": "1.15.3",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
+ "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
"funding": [
{
"type": "individual",
@@ -14575,6 +14599,11 @@
"node": ">= 0.10"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
"node_modules/psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -21912,6 +21941,28 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz",
"integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw=="
},
+ "axios": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz",
+ "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
+ "requires": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ },
+ "dependencies": {
+ "form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ }
+ }
+ },
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@@ -23317,9 +23368,9 @@
}
},
"domelementtype": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
- "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
},
"domexception": {
"version": "2.0.1",
@@ -24335,9 +24386,9 @@
"integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg=="
},
"follow-redirects": {
- "version": "1.14.9",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
- "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
+ "version": "1.15.3",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
+ "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q=="
},
"fork-ts-checker-webpack-plugin": {
"version": "6.5.0",
@@ -28374,6 +28425,11 @@
}
}
},
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
diff --git a/package.json b/package.json
index 813899d..f7cfddd 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
+ "axios": "^1.5.1",
"buffer": "^6.0.3",
"firebase": "^9.6.8",
"react": "^17.0.2",
@@ -52,4 +53,3 @@
]
}
}
-
diff --git a/src/components/CalculateZakat.jsx b/src/components/CalculateZakat.jsx
new file mode 100644
index 0000000..2d821a9
--- /dev/null
+++ b/src/components/CalculateZakat.jsx
@@ -0,0 +1,121 @@
+import React, { useState } from 'react'
+import Popup from './Popup'
+import { Box, Typography } from '@mui/material'
+import { getYearRange } from '../utils/helpers'
+import { formatMoney } from '../reducer'
+import PaidOutlinedIcon from '@mui/icons-material/PaidOutlined'
+import CurrencyExchangeOutlinedIcon from '@mui/icons-material/CurrencyExchangeOutlined'
+import { useEffect } from 'react'
+import { getCurrentNisaabRate } from '../firebase/zakatyears'
+
+function CalculateZakat({ zakatYear, netAssets }) {
+ const [openPopup, setOpen] = useState(false)
+ const [currentNisaab, setCurrentNisaab] = useState(zakatYear?.nisab || 0)
+ const [expenses, setExpenses] = useState(0)
+ const [amountDue, setAmountDue] = useState((1 / 40) * netAssets)
+
+ useEffect(() => {
+ getCurrentNisaabRate().then(setCurrentNisaab)
+ }, [])
+ useEffect(() => {
+ const assets = netAssets - expenses
+ if (assets >= currentNisaab) {
+ setAmountDue((1 / 40) * assets)
+ } else {
+ setAmountDue(0)
+ }
+ }, [expenses, currentNisaab, netAssets])
+
+ const handleSubmit = async (e) => {
+ e.preventDefault()
+ }
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default CalculateZakat
diff --git a/src/components/ProtectedRoute.jsx b/src/components/ProtectedRoute.jsx
index 9e120ea..6ab989a 100644
--- a/src/components/ProtectedRoute.jsx
+++ b/src/components/ProtectedRoute.jsx
@@ -12,8 +12,9 @@ function ProtectedRoute({ children, restrictedTo = [], redirect = '/' }) {
const [loggedUser, setLoggedUser] = useState(auth.currentUser)
useEffect(() => {
+ let isCanceled = false
const unsubscribe = userChanged((user) => {
- if (user) {
+ if (user && !isCanceled) {
setLoggedUser(user)
if (!user)
getOne('users', loggedUser.id)
@@ -22,7 +23,10 @@ function ProtectedRoute({ children, restrictedTo = [], redirect = '/' }) {
}
})
- return () => unsubscribe()
+ return () => {
+ isCanceled = true
+ unsubscribe()
+ }
}, [loggedUser, user, dispatch])
if (!loggedUser) {
diff --git a/src/css/Reports.css b/src/css/Reports.css
index d9b41fc..ec3ea07 100644
--- a/src/css/Reports.css
+++ b/src/css/Reports.css
@@ -21,7 +21,7 @@
}
section.left > div {
- margin: 1rem 0;
+ /* margin: 1rem 0; */
display: flex;
flex-direction: column;
gap: 15px;
@@ -74,6 +74,7 @@ section.left .filter_container .input {
}
.reports.container.dashboard {
flex-direction: row;
+ gap: 1.5rem;
}
.reports > section.right .chart {
padding: 10px;
diff --git a/src/devdata/data.js b/src/devdata/data.js
index 1665b51..854a340 100644
--- a/src/devdata/data.js
+++ b/src/devdata/data.js
@@ -29,7 +29,7 @@ export const products = temp.map((name) => {
export const zakatYears = [
{
id: uid(6),
- openingBalance: Math.random() * 1_500_000,
+ openingBalance: 1_500_000 - Math.random() * 700_000,
closingBalance: null,
nisab: 700_000 + Math.random() * 100_000,
beginDate: new Date(Date.now() - oneMonth),
@@ -42,7 +42,7 @@ export const zakatYears = [
},
{
id: uid(6),
- openingBalance: Math.random() * 1_500_000,
+ openingBalance: 1_500_000 - Math.random() * 700_000,
nisab: 700_000 + Math.random() * 100_000,
beginDate: new Date(Date.now() - 13 * oneMonth),
endDate: new Date(Date.now() - oneMonth),
@@ -56,53 +56,55 @@ export const zakatYears = [
]
// Dummy RInvoices
-const data = []
-for (let i = 0; i < 15; i++) {
- let invoiceTotal = 0
- data.push({
- id: uid(6),
- billerStreetAddress: 'Street Address' + (i + 1),
- billerCity: 'City' + (i + 1),
- billerZipCode: 'Zip Code' + (i + 1),
- billerCountry: 'Country' + (i + 1),
- clientName: 'Name' + (i + 1),
- clientPhone: Math.floor(Math.random() * 100_000_000_000),
- clientEmail: 'email' + (i + 1) + '@example.com',
- clientAddress: 'strret address' + (i + 1),
- clientCity: 'client City' + (i + 1),
- clientZipCode: 'zip code' + (i + 1),
- clientCountry: 'client country ' + (i + 1),
- invoiceDateUnix: '',
- invoiceDate: new Date(
- 2022,
- Math.round(Math.random() * 12),
- Math.round(Math.random() * 25)
- ),
- paymentTerms: 'some terms',
- paymentDueDate: new Date(),
- paymentDueDateUnix: new Date(Date.now() + (i + 1) * 86400),
- productDescription: '',
- invoicePending: !!(i % 2),
- invoiceDraft: '',
- invoicePaid: !(i % 2),
- invoiceItemList: Array(i + 1)
- .fill()
- .map((_, i) => {
- const engine = products[Math.floor(Math.random() * products.length)]
- invoiceTotal += engine.basePrice * (i + 1)
- return {
- itemName: engine.name,
- engineNo: Math.floor(Math.random() * 10000000),
- qty: i + 1,
- price: engine.basePrice,
- cost: engine.costPrice,
- total: engine.basePrice * (i + 1),
- }
- }),
- invoiceTotal,
- userID: i % users.length,
+const data = Array(15)
+ .fill(null)
+ .map((_, i) => {
+ let invoiceTotal = 0
+ return {
+ id: uid(6),
+ billerStreetAddress: 'Street Address' + (i + 1),
+ billerCity: 'City' + (i + 1),
+ billerZipCode: 'Zip Code' + (i + 1),
+ billerCountry: 'Country' + (i + 1),
+ clientName: 'Name' + (i + 1),
+ clientPhone: Math.floor(Math.random() * 100_000_000_000),
+ clientEmail: 'email' + (i + 1) + '@example.com',
+ clientAddress: 'strret address' + (i + 1),
+ clientCity: 'client City' + (i + 1),
+ clientZipCode: 'zip code' + (i + 1),
+ clientCountry: 'client country ' + (i + 1),
+ invoiceDateUnix: '',
+ invoiceDate: new Date(
+ i < 8 ? 2022 : 2023,
+ Math.round(Math.random() * 12),
+ Math.round(Math.random() * 25)
+ ),
+ paymentTerms: 'some terms',
+ paymentDueDate: new Date(),
+ paymentDueDateUnix: new Date(Date.now() + (i + 1) * 86400),
+ productDescription: '',
+ invoicePending: !!(i % 2),
+ invoiceDraft: '',
+ invoicePaid: !(i % 2),
+ invoiceItemList: Array(i + 1)
+ .fill()
+ .map((_, i) => {
+ const engine = products[Math.floor(Math.random() * products.length)]
+ invoiceTotal += engine.basePrice * (i + 1)
+ return {
+ itemName: engine.name,
+ engineNo: Math.floor(Math.random() * 10000000),
+ qty: i + 1,
+ price: engine.basePrice,
+ cost: engine.costPrice,
+ total: engine.basePrice * (i + 1),
+ }
+ }),
+ invoiceTotal,
+ userID: i % users.length,
+ zakatYearID: zakatYears[i < 8 ? 1 : 0].id,
+ }
})
-}
// Dummy chart data
export const userSalesData = [
diff --git a/src/devdata/temp.json b/src/devdata/temp.json
deleted file mode 100644
index 1074432..0000000
--- a/src/devdata/temp.json
+++ /dev/null
@@ -1,564 +0,0 @@
-[
- {
- "revenueService": {
- "revenueServiceId": "079c5c0c-40e7-4694-b5d2-a26580517623",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": null,
- "amount": 1000.0,
- "categoryName": "Application Form Fee",
- "categoryDescription": "Form Fee",
- "categoryStatus": null,
- "accountNo": "010",
- "accountCode": "010",
- "duration": "{\"years\":1,\"months\":1,\"days\":1}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-07T17:34:41.662+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2023-05-21T01:55:46.526+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": null,
- "parentName": null,
- "serviceAbbreviation": "AF",
- "requireInvoiceNo": false,
- "applicationId": null,
- "signatureId": "3e7ed51d-76ab-4839-a090-fd1305061587",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": [
- {
- "revenueService": {
- "revenueServiceId": "d08e1fcc-1af0-4404-a26e-3e83e6410d99",
- "revenueServiceCode": "4430731",
- "parentServiceId": "079c5c0c-40e7-4694-b5d2-a26580517623",
- "invoiceStructureId": "2549725e-a4c8-43e7-890e-1fafe13ed784",
- "amount": 0.0,
- "categoryName": "Test Fee",
- "categoryDescription": "Test Fee",
- "categoryStatus": null,
- "accountNo": "090000",
- "accountCode": "0909999",
- "duration": "{\"years\":0,\"months\":0,\"days\":90}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-05-09T20:39:23.092+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-05-27T19:01:19.993+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Numbering Renewal for Fixed & Mobile",
- "parentName": "Application Form Fee",
- "serviceAbbreviation": "TF",
- "requireInvoiceNo": true,
- "applicationId": null,
- "signatureId": "7d7c6c84-4f43-46bf-bde9-503f4ca8ad88",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- }
- ]
- },
- {
- "revenueService": {
- "revenueServiceId": "77065666-c075-4a65-a8fd-97bd80e21ebc",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": "af99b9e0-c525-4420-90c5-91a4da92311e",
- "amount": 2000.0,
- "categoryName": "Short Code",
- "categoryDescription": "Short Code",
- "categoryStatus": null,
- "accountNo": "-",
- "accountCode": "-",
- "duration": "{\"years\":1,\"months\":0,\"days\":0}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-07-13T13:06:17.879+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-07-25T08:30:29.436+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Numbering Short Code",
- "parentName": null,
- "serviceAbbreviation": "SC",
- "requireInvoiceNo": false,
- "applicationId": "spectrum",
- "signatureId": "e82356cf-decf-45d3-a73f-cd7c0e471051",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "367703a7-2db8-4e35-b600-211e629af69e",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": "9ae23c9b-dc93-40ac-9f41-68438c61d5f0",
- "amount": 0.0,
- "categoryName": "Type Approval",
- "categoryDescription": "Type Approval",
- "categoryStatus": null,
- "accountNo": "009",
- "accountCode": "009",
- "duration": "{\"years\":1,\"months\":1,\"days\":1}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-07T17:33:27.258+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2023-02-01T22:36:12.667+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Type Approval",
- "parentName": null,
- "serviceAbbreviation": "TY",
- "requireInvoiceNo": true,
- "applicationId": "d8a36768-47a3-40e5-a95a-8af51a4e4bcc",
- "signatureId": "7d7c6c84-4f43-46bf-bde9-503f4ca8ad88",
- "autoApproval": true,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "7e4c538b-e94e-4fa2-b4e7-971e283ae308",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": "79c0c1c0-b7e3-4a64-87fd-935758639c27",
- "amount": 1999.0,
- "categoryName": "Another Service",
- "categoryDescription": "Just Another Service",
- "categoryStatus": null,
- "accountNo": "03040",
- "accountCode": "03040",
- "duration": "{\"years\":0,\"months\":0,\"days\":0}",
- "allowPartPayment": true,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-05-31T09:08:38.767+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2023-05-23T08:13:30.110+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Meck Test Structure",
- "parentName": null,
- "serviceAbbreviation": "AS",
- "requireInvoiceNo": false,
- "applicationId": null,
- "signatureId": "e82356cf-decf-45d3-a73f-cd7c0e471051",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "a65ce2f8-d9db-434f-a7f9-af8590fe9608",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": null,
- "amount": 0.0,
- "categoryName": "Numbering Plan Fee",
- "categoryDescription": "Numbering Plan",
- "categoryStatus": null,
- "accountNo": "090",
- "accountCode": "090",
- "duration": "{\"years\":null,\"months\":12,\"days\":0}",
- "allowPartPayment": true,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-07T17:35:43.316+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-05-25T13:18:27.489+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": null,
- "parentName": null,
- "serviceAbbreviation": "NP",
- "requireInvoiceNo": true,
- "applicationId": null,
- "signatureId": "7d7c6c84-4f43-46bf-bde9-503f4ca8ad88",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": [
- {
- "revenueService": {
- "revenueServiceId": "93a3aec6-42f8-43c0-8832-de61bbce2209",
- "revenueServiceCode": "4430731",
- "parentServiceId": "a65ce2f8-d9db-434f-a7f9-af8590fe9608",
- "invoiceStructureId": "8f93b60a-104e-4d17-a6bc-9c9fe7d4961b",
- "amount": 0.0,
- "categoryName": "Numbering Plan New - Fixed&Mobile",
- "categoryDescription": "Numbering Plan New - Fixed&Mobile",
- "categoryStatus": null,
- "accountNo": "8910",
- "accountCode": "891",
- "duration": "{\"years\":0,\"months\":0,\"days\":0}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-10T14:07:53.267+0000",
- "createdBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-04-20T11:59:44.713+0000",
- "modifiedBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Numbering New Invoice for Fixed & Mobile",
- "parentName": "Numbering Plan Fee",
- "serviceAbbreviation": "NP",
- "requireInvoiceNo": true,
- "applicationId": null,
- "signatureId": "79f3402d-df5f-4843-bba9-c90b8b6c9ac2",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "b17ad0da-11ed-4823-b73b-ef27fc749e90",
- "revenueServiceCode": "4430731",
- "parentServiceId": "a65ce2f8-d9db-434f-a7f9-af8590fe9608",
- "invoiceStructureId": "2549725e-a4c8-43e7-890e-1fafe13ed784",
- "amount": 0.0,
- "categoryName": "Numbering Plan Renewal - Fixed&Mobile",
- "categoryDescription": "Numbering Renewal - Fixed&Mobile",
- "categoryStatus": null,
- "accountNo": "8902",
- "accountCode": "8902",
- "duration": "{\"years\":0,\"months\":0,\"days\":0}",
- "allowPartPayment": true,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-10T14:10:06.066+0000",
- "createdBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2023-01-27T15:06:23.833+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Numbering Renewal for Fixed & Mobile",
- "parentName": "Numbering Plan Fee",
- "serviceAbbreviation": "NP",
- "requireInvoiceNo": true,
- "applicationId": null,
- "signatureId": "79f3402d-df5f-4843-bba9-c90b8b6c9ac2",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- }
- ]
- },
- {
- "revenueService": {
- "revenueServiceId": "361b4cfc-1ef3-42a0-b057-a45392f3a78e",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": "313023d4-f469-472b-8ab3-21109b2cd4f0",
- "amount": 0.0,
- "categoryName": "License Fees",
- "categoryDescription": "License Fees",
- "categoryStatus": null,
- "accountNo": "048302",
- "accountCode": "05939",
- "duration": "{\"years\":0,\"months\":0,\"days\":0}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-05-31T14:09:02.264+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-05-31T14:10:26.262+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "License Structure",
- "parentName": null,
- "serviceAbbreviation": "LF",
- "requireInvoiceNo": true,
- "applicationId": "licensing",
- "signatureId": "2af2e945-50f9-47a9-91e6-9afb578e38f2",
- "autoApproval": true,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "a2992ee9-6e82-4191-b792-d45116a690c2",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": null,
- "amount": 0.0,
- "categoryName": "Spectrum Fee",
- "categoryDescription": "Spectrum Fee",
- "categoryStatus": null,
- "accountNo": "890087",
- "accountCode": "890008",
- "duration": "{\"years\":0,\"months\":0,\"days\":0}",
- "allowPartPayment": true,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-10T14:36:01.133+0000",
- "createdBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": null,
- "modifiedBy": null,
- "invoiceStructureName": null,
- "parentName": null,
- "serviceAbbreviation": "SP",
- "requireInvoiceNo": true,
- "applicationId": null,
- "signatureId": null,
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": [
- {
- "revenueService": {
- "revenueServiceId": "007fe7c7-e666-4989-9b42-4d5da8f941e0",
- "revenueServiceCode": "4430731",
- "parentServiceId": "a2992ee9-6e82-4191-b792-d45116a690c2",
- "invoiceStructureId": "3fc5ce78-217d-41e9-9477-4e1234d68e52",
- "amount": 0.0,
- "categoryName": "Microwave & 7080 eBand Spectrum",
- "categoryDescription": "Microwave & 7080 eBand Spectrum",
- "categoryStatus": null,
- "accountNo": "89007",
- "accountCode": "890002",
- "duration": "{\"years\":0,\"months\":0,\"days\":60}",
- "allowPartPayment": true,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-10T14:39:44.912+0000",
- "createdBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-08-01T14:06:57.157+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Spectrum - Microwave & 7080 eBand",
- "parentName": "Spectrum Fee",
- "serviceAbbreviation": "SP",
- "requireInvoiceNo": true,
- "applicationId": "spectrum",
- "signatureId": "7d7c6c84-4f43-46bf-bde9-503f4ca8ad88",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "005e46f9-59fe-4797-8c38-8e398b71ca71",
- "revenueServiceCode": "4430731",
- "parentServiceId": "a2992ee9-6e82-4191-b792-d45116a690c2",
- "invoiceStructureId": "f2ac4c7e-359c-426a-988a-880101a48911",
- "amount": 0.0,
- "categoryName": "Space Service Frequency",
- "categoryDescription": "Space Service Frequency",
- "categoryStatus": null,
- "accountNo": "89007",
- "accountCode": "89008",
- "duration": "{\"years\":0,\"months\":0,\"days\":0}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-10T14:37:22.480+0000",
- "createdBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-07-18T14:33:21.906+0000",
- "modifiedBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Spectrum - ESIM Space",
- "parentName": "Spectrum Fee",
- "serviceAbbreviation": "SP",
- "requireInvoiceNo": true,
- "applicationId": null,
- "signatureId": "e2fa06cf-0e8f-4156-9e06-1d05e6227a11",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "7b6b09be-6d62-4ad7-83dc-de1cff3cf28b",
- "revenueServiceCode": "4430731",
- "parentServiceId": "a2992ee9-6e82-4191-b792-d45116a690c2",
- "invoiceStructureId": "011a6512-1c3e-488f-bd29-55c81463d53d",
- "amount": 0.0,
- "categoryName": "WLL Spectrum",
- "categoryDescription": "WLL Spectrum",
- "categoryStatus": null,
- "accountNo": "4430731",
- "accountCode": "4430731",
- "duration": "{\"years\":0,\"months\":0,\"days\":60}",
- "allowPartPayment": true,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-07-18T14:36:38.280+0000",
- "createdBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-08-01T14:07:57.755+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "WLL Spectrum",
- "parentName": "Spectrum Fee",
- "serviceAbbreviation": "SP",
- "requireInvoiceNo": true,
- "applicationId": "spectrum",
- "signatureId": "e2fa06cf-0e8f-4156-9e06-1d05e6227a11",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "e1e9e90f-7051-493f-aef9-86fbebb366cc",
- "revenueServiceCode": "4430731",
- "parentServiceId": "a2992ee9-6e82-4191-b792-d45116a690c2",
- "invoiceStructureId": "c9c6d934-7119-4c2e-b1e5-778f98e7c467",
- "amount": 0.0,
- "categoryName": "SPECIAL INVOICE FOR SPECTRUM TRADING, AUCTION, ETC",
- "categoryDescription": "SPECIAL INVOICE FOR SPECTRUM TRADING, AUCTION",
- "categoryStatus": null,
- "accountNo": "4430731",
- "accountCode": "4430731",
- "duration": "{\"years\":0,\"months\":0,\"days\":60}",
- "allowPartPayment": true,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-08-16T09:31:22.028+0000",
- "createdBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-08-16T09:35:56.902+0000",
- "modifiedBy": "{\"appUserId\":\"fff022c9-5490-41e7-9cd4-9e22a247405b\",\"username\":\"finance_kiames\",\"name\":\"James Akinniranye\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": "Special Spectrum Invoice Structure",
- "parentName": "Spectrum Fee",
- "serviceAbbreviation": "SP",
- "requireInvoiceNo": true,
- "applicationId": null,
- "signatureId": "79f3402d-df5f-4843-bba9-c90b8b6c9ac2",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- }
- ]
- },
- {
- "revenueService": {
- "revenueServiceId": "efe3f77d-8e48-44f4-acde-17ac25d55278",
- "revenueServiceCode": "e",
- "parentServiceId": null,
- "invoiceStructureId": "eab88166-481d-49c8-86c4-300a4400ce81",
- "amount": 0.0,
- "categoryName": "te",
- "categoryDescription": "te",
- "categoryStatus": null,
- "accountNo": "etecec",
- "accountCode": "et",
- "duration": "{\"years\":0,\"months\":0,\"days\":100}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-11T05:34:44.584+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": null,
- "modifiedBy": null,
- "invoiceStructureName": "te",
- "parentName": null,
- "serviceAbbreviation": "te",
- "requireInvoiceNo": false,
- "applicationId": null,
- "signatureId": null,
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": [
- {
- "revenueService": {
- "revenueServiceId": "0ecfc03e-61d1-4464-8c09-1daf862b1403",
- "revenueServiceCode": "432",
- "parentServiceId": "efe3f77d-8e48-44f4-acde-17ac25d55278",
- "invoiceStructureId": null,
- "amount": 0.0,
- "categoryName": "remote",
- "categoryDescription": "desc",
- "categoryStatus": null,
- "accountNo": "444",
- "accountCode": "000",
- "duration": "{\"years\":1,\"months\":0,\"days\":0}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-04-11T13:18:41.044+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": "2022-04-11T13:19:25.709+0000",
- "modifiedBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "invoiceStructureName": null,
- "parentName": "te",
- "serviceAbbreviation": "REM",
- "requireInvoiceNo": false,
- "applicationId": "1721f893-b6de-4989-9bd7-9387c884f6c6",
- "signatureId": "3e7ed51d-76ab-4839-a090-fd1305061587",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- }
- ]
- },
- {
- "revenueService": {
- "revenueServiceId": "cfa262db-aca7-4b32-ba9c-5b0b62e16dfa",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": null,
- "amount": 0.0,
- "categoryName": "Revalidation Fee",
- "categoryDescription": "Payment For Revalidation",
- "categoryStatus": null,
- "accountNo": "509960",
- "accountCode": "594095",
- "duration": "{\"years\":0,\"months\":0,\"days\":0}",
- "allowPartPayment": true,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2022-06-14T12:07:17.992+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": null,
- "modifiedBy": null,
- "invoiceStructureName": null,
- "parentName": null,
- "serviceAbbreviation": "RF",
- "requireInvoiceNo": false,
- "applicationId": "licensing",
- "signatureId": "",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- },
- {
- "revenueService": {
- "revenueServiceId": "da4c4010-afab-4016-917f-8f0696ef3fe8",
- "revenueServiceCode": "4430731",
- "parentServiceId": null,
- "invoiceStructureId": null,
- "amount": 10000.0,
- "categoryName": "Tender Fee",
- "categoryDescription": "Tender Fee",
- "categoryStatus": null,
- "accountNo": "010",
- "accountCode": "010",
- "duration": "{\"years\":1,\"months\":1,\"days\":1}",
- "allowPartPayment": false,
- "actionAdditionalDetails": null,
- "deleted": false,
- "dateCreated": "2023-07-07T02:34:41.662+0000",
- "createdBy": "{\"appUserId\":\"cf7cdab4-77c7-4223-917d-cbc6cb20b569\",\"username\":\"finance-admin\",\"name\":\"Finance Admin\",\"organizationId\":\"70b3fbd7-9281-4f7f-9ba2-5c439ae993ce\",\"organizationName\":\"Finance Department\"}",
- "dateModified": null,
- "modifiedBy": null,
- "invoiceStructureName": null,
- "parentName": null,
- "serviceAbbreviation": "TF",
- "requireInvoiceNo": false,
- "applicationId": null,
- "signatureId": "1d4eea8a-a472-49b0-a81e",
- "autoApproval": false,
- "manualInvoice": true
- },
- "children": []
- }
-]
diff --git a/src/firebase/crud.js b/src/firebase/crud.js
index 0ae7b72..0afd528 100644
--- a/src/firebase/crud.js
+++ b/src/firebase/crud.js
@@ -12,13 +12,13 @@ import { uid } from 'uid'
import { db, devEnv } from './_config'
/**
- * This file Defgines the crud operations for collections
+ * This file Defines the crud operations for collections
*/
/**
* Retrieve all documents from a collection
* @param {"invoices" | "users" | "products" | "zakatyears"} colname
- * @returns
+ * @returns {Promise}
*/
export const getAll = async (colname) => {
if (devEnv) {
diff --git a/src/firebase/factory.js b/src/firebase/factory.js
index f842720..57d5eea 100644
--- a/src/firebase/factory.js
+++ b/src/firebase/factory.js
@@ -1,3 +1,6 @@
+import Invoices from '../devdata/data'
+import { cleanDate } from '../utils/dateFunctions'
+
/**
* gets the monthname of a date
* @param {Date} dt
@@ -45,22 +48,19 @@ const groupBy = (data, key) => {
/**
* unwind Invoices by there itemList
- * @param {[Object]} invoices List of invoices
+ * @param {(typeof Invoices)} invoices List of invoices
* @returns {[Object]} list of unwind invoice
*/
export const transformInvoices = (invoices) => {
const transformed = []
+
invoices.forEach((inv) => {
inv.invoiceItemList.forEach((item, i) => {
transformed.push({
id: inv.id + i,
userID: inv.userID,
- date: inv.invoiceDate?.hasOwnProperty('seconds')
- ? new Date(
- inv.invoiceDate?.seconds * 1000 +
- inv.invoiceDate?.nanoseconds / 1000000
- )
- : new Date(inv.invoiceDate),
+ zakatYearID: inv.zakatYearID,
+ date: cleanDate(inv.invoiceDate),
...item,
})
})
diff --git a/src/firebase/products.js b/src/firebase/products.js
index bb77879..cefe908 100644
--- a/src/firebase/products.js
+++ b/src/firebase/products.js
@@ -8,6 +8,7 @@ import {
} from 'firebase/firestore/lite'
import { products } from '../devdata/data'
import { db, devEnv } from './_config'
+import { getAll } from './crud'
/**
* This file defines specific functions related to products collection
@@ -54,3 +55,16 @@ export const updateProductQuantities = async (items) => {
})
await Promise.all(updates)
}
+
+/**
+ * Returns the Current Assets Value in Stock
+ * @returns {Promise}
+ */
+export const getCurrentAssetsValue = async () => {
+ const products = await getAll('products')
+
+ return products.reduce(
+ (subtotal, p) => subtotal + p.costPrice * p.quantity,
+ 0
+ )
+}
diff --git a/src/firebase/zakatyears.js b/src/firebase/zakatyears.js
index 40eb2bf..7ebb6cf 100644
--- a/src/firebase/zakatyears.js
+++ b/src/firebase/zakatyears.js
@@ -1,10 +1,14 @@
import { collection, getDocs, query, where } from 'firebase/firestore/lite'
-import { db, devEnv } from './_config'
+import { db, devEnv, goldApiDotIoApiKey } from './_config'
import { getAll } from './crud'
+import { ZakatYear, Invoice } from '../models'
+import { getCurrentAssetsValue } from './products'
+import axios from 'axios'
+import { convertNairaToUsd, convertUsdToNaira } from '../utils/helpers'
/**
* Get The Active Zakata Year
- * @returns
+ * @returns {ZakatYear}
*/
export const getActiveYear = async () => {
if (devEnv) {
@@ -22,3 +26,95 @@ export const getActiveYear = async () => {
)
return years.length ? years[0] : null
}
+
+/**
+ * Retrieve All invoices in particular zaka
+ * @param {string} id zakat year id
+ * @returns {Promise}
+ */
+export const getZakatYearsInvoices = async (id) => {
+ let invoices = []
+
+ if (devEnv) {
+ invoices = (await getAll('invoices')).filter(
+ (inv) => inv.zakatYearID === id
+ )
+ } else {
+ const q = query(collection(db, 'invoices'), where('zakatYearID', '==', id))
+ const docsSnapshot = await getDocs(q)
+ docsSnapshot.forEach((doc) =>
+ invoices.push({
+ ...doc.data(),
+ id: doc.id,
+ })
+ )
+ }
+
+ return invoices
+}
+
+/**
+ * Gets the Total Sales falling within the specified Year
+ * @param {string} id
+ * @returns {Promise} Total Sales within the Year
+ */
+export const getZakatYearsSales = async (id) => {
+ const invoices = await getZakatYearsInvoices(id)
+ const sale = invoices.reduce(
+ (subtotal, inv) => subtotal + inv.invoiceTotal,
+ 0
+ )
+ return sale
+}
+
+/**
+ * Give an Estimate of amount Due for a given Zakat Year
+ * @param {ZakatYear} year The Year to calculate for
+ * @returns {Promise} Estimated Amount
+ */
+export const getEstimatedAmountDue = async (year) => {
+ let sales = await getZakatYearsSales(year.id)
+
+ // Estimated 25% of Sales lost due to miscalleneous
+ sales *= 0.75
+
+ // Remove Opening Balance of The Year
+ sales -= year.openingBalance
+
+ // Add The Current Value of assets in stock
+ sales += await getCurrentAssetsValue()
+
+ // Calculate Legal (1/40)
+ const due = Math.ceil(sales * (1 / 40))
+
+ return due
+}
+
+/**
+ * Returns The Current Nisaab in Naira
+ * @returns {Promise}
+ */
+export const getCurrentNisaabRate = async () => {
+ if (devEnv) {
+ const rand = Math.random() * 100_000
+ const det = Math.random()
+ return 4_000_000 + rand * (det < 0.5 ? -1 : 1)
+ }
+ const response = await axios({
+ url: 'https://www.goldapi.io/api/XAU/USD',
+ method: 'get',
+
+ headers: {
+ 'x-access-token': goldApiDotIoApiKey,
+ 'Content-Type': 'application/json',
+ },
+ })
+ // Get Price In Ounce
+ const oneOunceUsdPrice = response.data.price
+
+ // Nisaab of Gold is 2.73295 ounces
+ const nisaabInUsd = 2.73295 * oneOunceUsdPrice
+ const nisaabInNaira = await convertUsdToNaira(nisaabInUsd)
+
+ return nisaabInNaira
+}
diff --git a/src/index.css b/src/index.css
index 5bb74f1..e2b3a2d 100644
--- a/src/index.css
+++ b/src/index.css
@@ -79,11 +79,15 @@ button,
flex-direction: column;
}
+.jc-space-between {
+ justify-content: space-between;
+}
+
.container {
width: 100%;
padding: 0;
padding-bottom: 1rem;
- max-width: 1200px;
+ max-width: 1000px;
max-height: 100vh;
overflow-y: scroll;
margin: 0 auto;
diff --git a/src/models/index.js b/src/models/index.js
index 531537c..f8b879e 100644
--- a/src/models/index.js
+++ b/src/models/index.js
@@ -22,3 +22,73 @@ export const Invoice = {
userID: null,
zakatYearID: null,
}
+
+/**
+ * Zakat year default model
+ */
+export const ZakatYear = {
+ id: '',
+ /**
+ * Net Asset Value as the begining of The Year
+ * must be >= nisaab
+ */
+ openingBalance: 0,
+ /**
+ * The Nisaab as at the begining of the Year
+ */
+ nisab: 0,
+ /**
+ * Start Date of the Year range
+ */
+ beginDate: new Date(),
+ /**
+ * End Date of the Year range
+ */
+ endDate: new Date(),
+ /**
+ * Date The Due amount is paid (if applicable)
+ */
+ datePaid: new Date(),
+ /**
+ * Net Assets Value as at the End of the Year Range
+ */
+ closingBalance: 0,
+ /**
+ * Amount Due for The Year (to be calculated at the end of the Year)
+ */
+ amountDue: 0,
+ /**
+ * Marker for the Years time
+ * (active for current inactive otherwise)
+ */
+ status: 'inactive',
+ /**
+ * Marker for Payment
+ * one of ('paid', 'not-paid', 'not-applicable')
+ */
+ paymentStatus: 'not-paid',
+ dateCreated: new Date(),
+}
+
+/**
+ *
+ */
+export const Product = {
+ /**
+ * Name of The Product
+ * it has be unique
+ */
+ name: '',
+ /**
+ * Cost of The Product to the Business owner
+ */
+ costPrice: 0,
+ /**
+ * Quantity of the Product in stock
+ */
+ quantity: 0,
+ /**
+ * Borderline selling price of the product
+ */
+ basePrice: 0,
+}
diff --git a/src/pages/Zakat.jsx b/src/pages/Zakat.jsx
index d8714fe..3f58c00 100644
--- a/src/pages/Zakat.jsx
+++ b/src/pages/Zakat.jsx
@@ -15,7 +15,14 @@ import { useStateValue } from '../StateProvider'
import { cleanDate, dayDifference, toDdMmmYy } from '../utils/dateFunctions'
import useTable from '../hooks/useTable'
import { getAll } from '../firebase/crud'
-import { toNDigits } from '../utils/helpers'
+import { getYearRange, toNDigits } from '../utils/helpers'
+import {
+ getEstimatedAmountDue,
+ getZakatYearsSales,
+} from '../firebase/zakatyears'
+import { ZakatYear } from '../models'
+import { getCurrentAssetsValue } from '../firebase/products'
+import CalculateZakat from '../components/CalculateZakat'
const headCells = [
{ id: 'year', label: 'Year' },
@@ -29,30 +36,31 @@ function Zakat() {
const [loading, setLoading] = useState(false)
const [zakatyears, setZakatyears] = useState([])
const [filter, setFilter] = useState({ fn: (items) => items })
+ const [currentYear, setCurrentYear] = useState(ZakatYear)
+ const [yearSales, setYearSales] = useState(0)
+ const [yearDueEst, setYearDueEst] = useState(0)
+ const [assetInStock, setAssetsInStock] = useState(0)
+ const { activeYear } = useStateValue()[0]
- const { activeYear: currentYear } = useStateValue()[0]
const { TableContainer, TblHead, TblPagination, recordsAfterPagination } =
useTable(zakatyears, headCells, filter)
useEffect(() => {
let isCanceled = false
getAll('zakatyears').then((years) => !isCanceled && setZakatyears(years))
+ getCurrentAssetsValue().then(
+ (value) => !isCanceled && setAssetsInStock(value)
+ )
+ setCurrentYear(activeYear)
return () => {
isCanceled = true
}
- }, [])
+ }, [activeYear])
- const getYear = (year) => {
- const start = cleanDate(year.beginDate)
- const stop = cleanDate(year.endDate)
- return `${toNDigits(
- start.getMonth() + 1,
- 2
- )}/${start.getFullYear()} - ${toNDigits(
- stop.getMonth() + 1,
- 2
- )}/${stop.getFullYear()}`
- }
+ useEffect(() => {
+ getZakatYearsSales(currentYear?.id).then(setYearSales)
+ getEstimatedAmountDue(currentYear).then(setYearDueEst)
+ }, [currentYear])
return (
@@ -61,37 +69,35 @@ function Zakat() {
{/* Top Level Info */}
Zakat Year
-
+
- {currentYear.status}
+ {currentYear?.status}
- {currentYear.paymentStatus}
+ {currentYear?.paymentStatus}
-
+
- {toDdMmmYy(currentYear.beginDate)}
- {toDdMmmYy(currentYear.endDate)}
@@ -103,7 +109,7 @@ function Zakat() {
Opening Balance
- {formatMoney(currentYear.openingBalance)}
+ {formatMoney(currentYear?.openingBalance)}
@@ -111,15 +117,23 @@ function Zakat() {
Opening Nisaab
- {formatMoney(currentYear.nisab)}
+ {formatMoney(currentYear?.nisab)}
+
+
+
+
+ Year Sales
+
+
+ {formatMoney(yearSales)}
- Current Balance
+ Assets In Stock
- {formatMoney(currentYear.openingBalance)}
+ {formatMoney(assetInStock)}
@@ -127,7 +141,7 @@ function Zakat() {
Due in (Days)
- {dayDifference(new Date(), currentYear.endDate)}
+ {dayDifference(new Date(), currentYear?.endDate)}
@@ -135,13 +149,17 @@ function Zakat() {
Amount Due (Est.)
- {currentYear.openingBalance >= currentYear.nisab
- ? formatMoney(currentYear.averageMonthly)
+ {yearSales >= currentYear?.nisab
+ ? formatMoney(yearDueEst)
: 'N/A'}
-
+
+ {/*
*/}
{recordsAfterPagination().map((y, i) => (
- {getYear(y)}
+ {getYearRange(y)}
{formatMoney(y.openingBalance)}
{formatMoney(y.closingBalance)}
{formatMoney(y.nisab)}
diff --git a/src/utils/helpers.js b/src/utils/helpers.js
index 13fc74c..5445084 100644
--- a/src/utils/helpers.js
+++ b/src/utils/helpers.js
@@ -1,4 +1,8 @@
// import { cleanDate } from "./dateFunctions"
+import { XEApiID, XEApiKey, devEnv } from '../firebase/_config'
+import { ZakatYear } from '../models'
+import { cleanDate } from './dateFunctions'
+import axios from 'axios'
/**
* @author MAHADI
@@ -13,3 +17,46 @@
export const toNDigits = (value, digits) => {
return String(value).padStart(digits, '0')
}
+
+/**
+ * Gets The Year Range of a Zakat Year in the form
+ * mm/yyyy - mm/yyyy
+ * @param {ZakatYear} year
+ * @returns {string} Year Range
+ */
+export const getYearRange = (year) => {
+ if (!year) return ''
+ const start = cleanDate(year.beginDate)
+ const stop = cleanDate(year.endDate)
+ return `${toNDigits(
+ start.getMonth() + 1,
+ 2
+ )}/${start.getFullYear()} - ${toNDigits(
+ stop.getMonth() + 1,
+ 2
+ )}/${stop.getFullYear()}`
+}
+
+/**
+ * Converts Usd To Naira Using the XE api
+ * @param {number} usd the amount of usd
+ * @returns {Promise} equivalent of usd in naira
+ */
+export const convertUsdToNaira = async (usd) => {
+ if (devEnv) {
+ return usd * 875
+ }
+ const url = `https://xecdapi.xe.com/v1/convert_from.csv/?from=USD&to=NGN&amount=${usd}`
+ const response = await axios({
+ url,
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ auth: {
+ username: XEApiID,
+ password: XEApiKey,
+ },
+ })
+ return Number(response.data.split(',').slice(-1)[0])
+}