diff --git a/DOCS/DOCS.md b/DOCS/DOCS.md index 6caac2c..b238e5e 100644 --- a/DOCS/DOCS.md +++ b/DOCS/DOCS.md @@ -1,6 +1,6 @@ # DOCS - ⚠️ dev docs is still under development... + ⚠️ dev docs is still in beta... ## core concept @@ -8,6 +8,15 @@ app has few main concepts: product, factor, customer, productOwner, car checkout the relationship between this entities [here](concept.png) -## how to works +## data transfer system + +component -> ipcRendered -> db(docs) +component <- ipcRendered <- db(docs) ... + + +## electron + +for now goje relying on old version of packages(like electron 11) +but it will upgrade to new versions soon... \ No newline at end of file diff --git a/src/App/App.jsx b/src/App/App.jsx index 8c8a2c4..3ec2e05 100755 --- a/src/App/App.jsx +++ b/src/App/App.jsx @@ -32,6 +32,8 @@ import SearchProductOwners from "./Pages/Reports/SearchProductOwners.jsx"; import { createMemoryHistory } from "history"; import { hot } from "react-hot-loader"; import PayTheCashPlease from "./Components/PayTheCashPlease.jsx"; +import SearchProductOwnerCars from "./Pages/Reports/SearchProductOwnerCars.jsx"; +import PrintSumProductOwnerSelectedCars from "./Pages/Reports/PrintSumProductOwnerSelectedCars.jsx"; const JDate = require("jalali-date"); const App = () => { @@ -55,7 +57,11 @@ const App = () => { isCashDate ? ( ) : ( - + // + // + ) ) : (
@@ -95,6 +101,14 @@ const App = () => { path="/printRemainingProducts" component={PrintRemainingProducts} /> + + diff --git a/src/App/Components/Report/CustomeDatePicker.jsx b/src/App/Components/Report/CustomeDatePicker.jsx new file mode 100644 index 0000000..3937e65 --- /dev/null +++ b/src/App/Components/Report/CustomeDatePicker.jsx @@ -0,0 +1,32 @@ +import React from "react"; +import { cleanTime, oneDay } from "../../utils"; +import { DatePicker } from "jalali-react-datepicker"; + +export default function CustomeDatePicker({ search, setSearch }) { + return ( +
+ از تاریخ: + { + setSearch({ + ...search, + fromm: cleanTime(value._d.getTime()), + }); + }} + /> + تا تاریخ: + { + setSearch({ + ...search, + till: cleanTime(value._d.getTime()) + oneDay, + }); + }} + /> +
+ ); +} diff --git a/src/App/Pages/Car/Car.jsx b/src/App/Pages/Car/Car.jsx index 324aa92..9cda9fa 100644 --- a/src/App/Pages/Car/Car.jsx +++ b/src/App/Pages/Car/Car.jsx @@ -21,7 +21,11 @@ function InfoSection({ car }) { صورتحساب -

{car.owner}

+

+ + {car.owner} + +

@@ -89,9 +93,12 @@ function SaleSection({ products, car }) { for (let i = 0; i < products.length; i++) { fullSum += salesInfos[i].FULL_SALE; } + // 0.01 for getting % (shortcut of Proportionality) sumSaleCommission = Math.floor(fullSum * (car.commission * 0.01)); } + // TODO: cleanCode(move all this stuff to a ipc) + // TODO: move all the logic to ipc useEffect(() => { if (salesInfos && salesInfos.length !== products.length) { getOneProductCalcs(products[salesInfos.length].customeId); @@ -275,6 +282,7 @@ function SaleSection({ products, car }) { 0 ? ( { + if (!goBack) { + const jdate = new JDate(); + const fileName = `صورتحساب های ${ownerName} - ${jdate.format( + "DD MMMM YYYY" + )}.pdf`; + const options = { + jsPDF: { format: "a5" }, + filename: fileName, + html2canvas: { scale: 1 }, + }; + html2pdf() + .set(options) + .from(document.body) + .save() + .then(() => { + setGoBack(true); + }); + } + }); + + return ( +
+ {goBack ? ( + + ) : ( +
+ + + + + + + + + + + + + {cars.map((car, index) => { + return ( + + + + + + + ); + })} + +
تاریخ ورودپلاککد ماشینصافی
{}{car.plaque}{car.customeId}{}
+
+
+
+

+ مجموع صافی ها + : + + + +

+
+
+ )} +
+ ); +} + +export default function PrintSumProductOwnerSelectedCars() { + const { clearNotifs } = useContext(NotifContext); + let { ownerName, selectedCars } = useParams(); + selectedCars = selectedCars.split(","); + const init = useRef(true); + + const [cars, setCars] = useState(); + + const sumProductOwnerSelectedCars = (carIds) => { + ipcRenderer.send("sumProductOwnerSelectedCars", carIds); + }; + + useEffect(() => { + if (init.current) { + clearNotifs(); + sumProductOwnerSelectedCars(selectedCars); + init.current = false; + } + + ipcRenderer.on("sumProductOwnerSelectedCars", (event, cars) => { + setCars(cars.reverse()); + }); + + // clean up + return () => { + ipcRenderer.removeAllListeners("sumProductOwnerSelectedCars"); + }; + }); + const currentDate = new Date(new JDate()._d).getTime(); + + return cars && cars.length >= 2 ? ( +
+
+
+ +
+

+ صورتحساب + + +

{ownerName}

+ +

+
+
+ تاریخ گزارش + : + + + +
+ +
+ +
+
+
+ ) : ( + + ); +} diff --git a/src/App/Pages/Reports/SearchProductOwnerCars.jsx b/src/App/Pages/Reports/SearchProductOwnerCars.jsx new file mode 100644 index 0000000..9b5a8f0 --- /dev/null +++ b/src/App/Pages/Reports/SearchProductOwnerCars.jsx @@ -0,0 +1,155 @@ +// import { List } from "@material-ui/core"; +import { Button, List } from "@material-ui/core"; +import React, { useEffect, useState } from "react"; +import { useRef } from "react"; +import { Link, useParams } from "react-router-dom"; +import Loading from "../../Components/Loading.jsx"; +const { ipcRenderer } = require("electron"); +import Nav from "../../Components/Nav.jsx"; +import PrintIcon from "@material-ui/icons/Print"; +import PrintDisabledIcon from "@material-ui/icons/PrintDisabled"; +import SearchResultItem from "../../Components/Report/SearchResultItem.jsx"; +import ShowDate from "../../Components/ShowDate.jsx"; +import DescriptionIcon from "@material-ui/icons/Description"; +import { productsToString } from "../../utils.js"; + +export default function SearchProductOwnerCars({ history }) { + const init = useRef(true); + let { id } = useParams(); + + const getOneProductOwner = (id) => { + ipcRenderer.send("getOneProductOwner", id); + }; + + const findProductOwnerCars = (id) => { + ipcRenderer.send("findProductOwnerCars", id); + }; + + // get cars, list cars + const [productOwner, setProductOwner] = useState(false); + const [cars, setCars] = useState(false); + const [checkeds, setCheckeds] = useState([]); + + useEffect(() => { + if (init.current) { + // get product owner + get her cars + getOneProductOwner(id); + init.current = false; + } + + ipcRenderer.on("getOneProductOwner", (event, productOwner) => { + init.current = false; + setProductOwner(productOwner); + findProductOwnerCars(productOwner.customeId); + }); + + ipcRenderer.on("findProductOwnerCars", (event, cars) => { + setCars(cars); + }); + + // clean up + return () => { + ipcRenderer.removeAllListeners("getOneProductOwner"); + ipcRenderer.removeAllListeners("findProductOwnerCars"); + }; + }); + + const toggleItems = (items, newItem) => { + if (!items && !newItem) return; + const index = items.indexOf(newItem); + if (index < 0) { + items = [...items, newItem]; + } else { + items.splice(index, 1); + } + setCheckeds(items); + }; + + let resultsList; + if (cars && cars.length > 0) { + resultsList = cars.map((car) => { + const icon = car.isPrinted ? ( + + ) : ( + + ); + const onChecked = car.isPrinted + ? (checked) => { + toggleItems(checkeds, checked); + } + : null; + return ( +
+ + + {car.plaque && " | " + car.plaque} + + } + customeId={car.customeId} + titleHint={ + + ({productsToString(car.products)}){icon} + + } + to={`/car/${car.customeId}`} + onChecked={onChecked} + /> +
+ ); + }); + } + + return productOwner && resultsList ? ( +
+
+ ) : ( + + ); +} diff --git a/src/App/Pages/Reports/SearchProductOwners.jsx b/src/App/Pages/Reports/SearchProductOwners.jsx index 5242cfe..5361680 100644 --- a/src/App/Pages/Reports/SearchProductOwners.jsx +++ b/src/App/Pages/Reports/SearchProductOwners.jsx @@ -49,7 +49,7 @@ export default function SearchProductOwners({ history }) { ); @@ -65,6 +65,16 @@ export default function SearchProductOwners({ history }) { }} /> {resultsList ? {resultsList} : <>} +
+
+
+
+
+
+
+
+
+
); } diff --git a/src/calculators/calcCar.js b/src/calculators/calcCar.js new file mode 100644 index 0000000..80827bf --- /dev/null +++ b/src/calculators/calcCar.js @@ -0,0 +1,21 @@ +const calculate = (car, productsSales, callback) => { + let fullSum, sumSaleCommission; + + fullSum = 0; + for (let i = 0; i < productsSales.length; i++) { + fullSum += productsSales[i].FULL_SALE; + } + // 0.01 for getting % (shortcut of Proportionality) + sumSaleCommission = Math.floor(fullSum * (car.commission * 0.01)); + + const ownerEarnings = + fullSum - (sumSaleCommission + car.portage + car.unload + car.cash); + + if (typeof callback === "function") { + callback(ownerEarnings); + } +}; + +module.exports = { + calculate, +}; diff --git a/src/db/productOwnerDocs.js b/src/db/productOwnerDocs.js index b97a191..c02ae54 100644 --- a/src/db/productOwnerDocs.js +++ b/src/db/productOwnerDocs.js @@ -1,6 +1,19 @@ const { db } = require("../db"); const autoFiller = require("../modules/autoFiller"); +// TODO: cleanCode -> seperate file for sorts functions +// TODO: cleanCode -> error handling function + +const sortCarArray = (cars) => { + if (!cars) return; + cars + .sort((a, b) => { + return a.arrivalDate - b.arrivalDate; + }) + .reverse(); + return cars; +}; + const getAll = (callback) => { db.find({ docType: "productOwner" }, (err, docs) => { if (err) throw err; @@ -10,13 +23,43 @@ const getAll = (callback) => { }); }; +const getOne = (id, callback) => { + if (!id) return; + db.find( + { + $and: [{ docType: "productOwner" }, { customeId: id }], + }, + function (err, docs) { + if (err) throw err; + if (typeof callback === "function") { + callback(docs[0]); + } + } + ); +}; + const isProductOwnerExists = (productOwner, callback) => { + db.find({ docType: "productOwner", name: productOwner.name }, (err, docs) => { + if (err) throw err; + if (typeof callback === "function") { + callback(docs); + } + }); +}; + +const search = (id, callback) => { + if (!id) return; db.find( - { docType: "productOwner", name: productOwner.name }, - (err, docs) => { + { + $and: [{ docType: "car" }, { ownerId: id }], + }, + function (err, docs) { if (err) throw err; if (typeof callback === "function") { - callback(docs); + if (docs) { + docs = sortCarArray(docs); + callback(docs); + } } } ); @@ -34,6 +77,8 @@ const insert = (productOwner, callback) => { module.exports = { getAll, + getOne, + search, insert, isProductOwnerExists, }; diff --git a/src/ipcMains/ipcCars.js b/src/ipcMains/ipcCars.js index c67fd02..edcab2f 100644 --- a/src/ipcMains/ipcCars.js +++ b/src/ipcMains/ipcCars.js @@ -52,15 +52,9 @@ ipcMain.on("includeCar", (event, car) => { }); ipcMain.on("editCar", (event, car) => { - // isCarProductsHaveDependency validateCar(car, (status, message) => { - // log car - // log a lot of things - // pass car and edit new car if (status === true) { createProductsBasedOnCar(car, car.customeId, (products) => { - // inserting/editing each product based on - // objects created by createProductsBasedOnCar for (let i = 0; i < products.length; i++) { (function (ind) { setTimeout(function () { @@ -84,7 +78,6 @@ ipcMain.on("editCar", (event, car) => { ); } else { productDocs.insert(products[ind], (newProduct) => { - // saving product customeId for later use cases on car object car.products[ind].customeId = newProduct.customeId; if (i === products.length - 1) { carDocs.update(car._id, car, () => { diff --git a/src/ipcMains/ipcProductOwner.js b/src/ipcMains/ipcProductOwner.js index c34622a..ecb8bb5 100644 --- a/src/ipcMains/ipcProductOwner.js +++ b/src/ipcMains/ipcProductOwner.js @@ -1,5 +1,8 @@ const { ipcMain } = require("electron"); const productOwnerDocs = require("../db/productOwnerDocs"); +const carDocs = require("../db/carDocs"); +const calcOneProduct = require("../calculators/calcOneProduct"); +const calcCar = require("../calculators/calcCar"); const { validateProductOwner } = require("../modules/validator"); ipcMain.on("getAllProductOwners", (event) => { @@ -8,6 +11,57 @@ ipcMain.on("getAllProductOwners", (event) => { }); }); +ipcMain.on("getOneProductOwner", (event, id) => { + productOwnerDocs.getOne(id, (docs) => { + event.reply("getOneProductOwner", docs); + }); +}); + +ipcMain.on("findProductOwnerCars", (event, id) => { + productOwnerDocs.search(id, (docs) => { + event.reply("findProductOwnerCars", docs); + }); +}); + +// TODO: clean code +ipcMain.on("sumProductOwnerSelectedCars", (event, carsId) => { + const cars = []; + let index = 0; + const getOneCar = (index) => { + const carId = carsId[index]; + carDocs.getOne(carId, (car) => { + let index2 = 0; + let productsSales = []; + const getOneProductCalcs = (index2) => { + const productId = car.products[index2].customeId; + calcOneProduct.calculate(productId, (results) => { + productsSales.push(results); + index2++; + if (index2 < car.products.length) { + getOneProductCalcs(index2); + } else if (index2 == car.products.length) { + calcCar.calculate(car, productsSales, (res) => { + cars.push({ + ownerEarnings: res, + arrivalDate: car.arrivalDate, + plaque: car.plaque, + customeId: car.customeId, + }); + }); + index++; + getOneCar(index); + if (carsId.length === cars.length) { + event.reply("sumProductOwnerSelectedCars", cars); + } + } + }); + }; + getOneProductCalcs(index2); + }); + }; + getOneCar(index); +}); + ipcMain.on("addNewProductOwner", (event, productOwner) => { validateProductOwner(productOwner, (status, message) => { if (status === true) {