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 ? (
+
+
+
+
+ بارهای
+
+
+ {productOwner.name}
+
+
+
{`${resultsList.length} صافی موجود است.`}
+ {resultsList ?
{resultsList}
: <>>}
+ {checkeds && checkeds.length > 1 ? (
+
+
+
+ جمع
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ ) : (
+
+ );
+}
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) {