From 6654c84aebd0c841c42230703b916a68ba5b9b8b Mon Sep 17 00:00:00 2001 From: Visoth Date: Tue, 23 Jul 2024 08:25:55 +0700 Subject: [PATCH] Working on Supplier and Warehouse --- Controller/Inventory_Movement.js | 142 ++++++++++++++++++++++++++++++ Controller/Items.js | 13 +++ Controller/Warehouse.js | 58 ++++++++++++ Model/Inventory_Movement_Model.js | 140 +++++++++++++++++++++++++++++ Model/SupplierItemModel.js | 31 +++++++ Model/WarehouseModel.js | 61 +++++++++++++ app.js | 5 +- routes/inventory_movement.js | 27 ++++++ routes/warehouse.js | 27 ++++++ 9 files changed, 503 insertions(+), 1 deletion(-) create mode 100644 Controller/Inventory_Movement.js create mode 100644 Controller/Warehouse.js create mode 100644 Model/Inventory_Movement_Model.js create mode 100644 Model/SupplierItemModel.js create mode 100644 Model/WarehouseModel.js create mode 100644 routes/inventory_movement.js create mode 100644 routes/warehouse.js diff --git a/Controller/Inventory_Movement.js b/Controller/Inventory_Movement.js new file mode 100644 index 0000000..d411daf --- /dev/null +++ b/Controller/Inventory_Movement.js @@ -0,0 +1,142 @@ +const asyncHandler = require("../Middleware/async"); +const sequelize = require('sequelize') +const db = require("../Config/db"); +const ErrorResponse = require("../utils/errorResponse"); +const { getInventoryMovementTable } = require("../Model/Inventory_Movement_Model"); +const ItemModel = require("../Model/ItemModel"); + + +exports.getAllStock = asyncHandler(async (req, res, next) => { + try { + const userDBCode = req.user.DB_CODE; + if (!userDBCode) { + return next(new ErrorResponse("Store Code not found or disabled", 400)); + } + + const InventoryModel = getInventoryMovementTable(`${userDBCode}TDINVMOV`); + let allInventory = await InventoryModel.findAll({ + raw: true + }); + + // Map over all inventory items and fetch associated item details + const inventoryWithDetails = await Promise.all(allInventory.map(async (inv) => { + const item = await ItemModel.findOne({ + where: { + ITEM_CODE: inv.ITEM_CODE, + DB_CODE: userDBCode + }, + attributes: ['ITEM_BCODE', 'ITEM_DESC', 'ITEM_COST1', 'ITEM_PRICE1', 'CAT_CODE'], // specify only the necessary fields to fetch + raw: true + }); + + // Merge item details with inventory data + return { + ...inv, + ITEM_NAME: item ? item.ITEM_DESC : null, + ITEM_IMAGE: item ? item.ITEM_IMG : null, + ITEM_COST1: item ? item.ITEM_COST1 : null, + ITEM_PRICE1: item ? item.ITEM_PRICE1 : null, + }; + })); + + return res.status(200).json({ + success: true, + data: inventoryWithDetails + }); + } catch (err) { + console.log("ERROR GET ALL STORE", err); + return next(new ErrorResponse("Failed to retrieve stock", 400)); // More specific error message + } +}); + + +exports.createStock = asyncHandler(async (req, res, next) => { + const t = await db.transaction() + try { + const userDBCode = req.user.DB_CODE + if (!userDBCode) { + return next(new ErrorResponse("Store Code not found or disabled", 400)); + } + + const InventoryModel = getInventoryMovementTable(`${userDBCode}TDINVMOV`) + const maxSequenceQty = await db.query(`SELECT MAX(SEQUENCE)+1 AS MAX FROM ${userDBCode}TDINVMOV`, + { + transaction: t, + type: sequelize.QueryTypes.SELECT + }).catch((err) => { + throw `Cannot query max sequence ${err}`; + }) + + // check whether ITEM_CODE exists in the database + const itemCode = await ItemModel.findOne({ + where: { + ITEM_CODE: req.body.ITEM_CODE, + DB_CODE: userDBCode + } + }) + + if (!itemCode) { + return next(new ErrorResponse("Item Code not found", 400)); + } + + + const { MOV_PRD, MOV_REF, MOV_LINE, LOCATION, ITEM_CODE, MOV_DATE, STATUS, IR_STAT, BATCH_NO, BATCH_LINE, LINE_REF, QUANTITY, COST, TOTAL } = req.body + const newInventory = await InventoryModel.create({ + SEQUENCE: maxSequenceQty[0]?.MAX || 1, + ID_ALLOC: req.user.USER_ID, + REC_TYPE: "T", + MOV_UNITS: "1", + MOV_TYPE: "OB", + UPDTE_PHYS: "", + UPDTE_ORDR: "", + ALLOC_REF: req.user.DB_CODE + generateTimestampBasedAllocRef(), + ACCNT_CODE: "", + ASSET_CODE: req.body.ASSET_CODE || "", + ANAL_M0: req.body.ANAL_M0 || "", + ANAL_M1: req.body.ANAL_M1 || "", + ANAL_M2: req.body.ANAL_M2 || "", + ANAL_M3: req.body.ANAL_M3 || "", + ANAL_M4: req.body.ANAL_M4 || "", + ANAL_M5: req.body.ANAL_M5 || "", + ANAL_M6: req.body.ANAL_M6 || "", + ANAL_M7: req.body.ANAL_M7 || "", + ANAL_M8: req.body.ANAL_M8 || "", + ANAL_M9: req.body.ANAL_M9 || "", + ORIG_LINE_NO: req.body.ORIG_LINE_NO || "", + PO_VALUE: req.body.PO_VALUE || 0, + ID_ENTERED: req.user.USER_NAME, + ID_ALLOC: req.user.USER_NAME, + + MOV_PRD, MOV_REF, MOV_LINE, LOCATION, ITEM_CODE, MOV_DATE, STATUS, IR_STAT, BATCH_NO, BATCH_LINE, LINE_REF, QUANTITY, COST, TOTAL, + + }) + // const allInventory = await InventoryModel.findAll() + return res.status(200).json({ + success: true, + data: newInventory + }) + } catch (err) { + console.log("ERROR GET ALL STORE", err) + await t.rollback() + return next(new ErrorResponse(err, 400)); + } +}) + +function generateTimestampBasedAllocRef() { + const now = new Date(); + const year = now.getFullYear(); + const month = (now.getMonth() + 1).toString().padStart(2, '0'); // Month is zero-indexed, add 1 and pad it to ensure two digits + const day = now.getDate().toString().padStart(2, '0'); + const hours = now.getHours().toString().padStart(2, '0'); + const minutes = now.getMinutes().toString().padStart(2, '0'); + const seconds = now.getSeconds().toString().padStart(2, '0'); + const milliseconds = now.getMilliseconds().toString().padStart(3, '0'); + + const allocRef = `-${year}${month}${day}${hours}${minutes}`; + console.log("ALLOC REF", allocRef) + return allocRef; +} + + + + diff --git a/Controller/Items.js b/Controller/Items.js index 72a7ea6..4787c4e 100644 --- a/Controller/Items.js +++ b/Controller/Items.js @@ -3,6 +3,7 @@ const sequelize = require('sequelize') const DBInfo = require("../Model/Database"); const ItemModel = require("../Model/ItemModel"); const CategoryModel = require("../Model/CategoryModel"); +const SupplierItemModel = require("../Model/SupplierItemModel"); const ErrorResponse = require("../utils/ErrorResponse"); const SuccessResponse = require("../utils/SuccessResponse"); const fs = require('fs') @@ -79,6 +80,7 @@ exports.createItemByStore = asyncHandler(async (req, res, next) => { const unitStock = items['UNIT_STOCK'] ?? '1'; const unitSale = items['UNIT_SALE'] ?? '1'; const catCode = items['CATE_CODE']; // CAT_CODE -> CAT_DETAIL_ID + const supplierCode = items['SUPP_CODE']; const itemCost1 = items['ITEM_COST1']; const itemPrice1 = items['ITEM_PRICE1']; @@ -131,6 +133,17 @@ exports.createItemByStore = asyncHandler(async (req, res, next) => { USER_UPDT: req.user.USER_NAME, DATE_UPDT: date, }) + + // add to TDITEMSP table + + await SupplierItemModel.create({ + ITEM_CODE: itemCode, + DB_CODE: req.user.DB_CODE, + SUPP_CODE: supplierCode, + SUPP_COST: itemCost1, + SUPP_UNIT: "1" + }) + let folderPath = process.env.ITEM_IMAGE_LOCATION + "/" + req.user.DB_CODE + "/" if (!fs.existsSync(folderPath)) fs.mkdirSync(folderPath, { recursive: true, diff --git a/Controller/Warehouse.js b/Controller/Warehouse.js new file mode 100644 index 0000000..aab215a --- /dev/null +++ b/Controller/Warehouse.js @@ -0,0 +1,58 @@ +const asyncHandler = require("../Middleware/async"); +const sequelize = require('sequelize') +const db = require('../Config/db') +const WarehouseModel = require('../Model/WarehouseModel') +const ErrorResponse = require('../utils/ErrorResponse') +const fs = require('fs'); +const SuccessResponse = require('../utils/SuccessResponse'); +const dateFormat = require('dateformat') + +exports.getAllWarehouse = asyncHandler(async (req, res, next) => { + try { + const warehouse = await WarehouseModel.findAll({ + where: + { + DB_CODE: req.user.DB_CODE, + WAR_STAT: 'A' + } + + }) + if (!warehouse) { + return next(new ErrorResponse("Warehouse not found", 404)) + } + res.status(200).json(new SuccessResponse(200, warehouse)) + + } catch (e) { + return next(new ErrorResponse(e, 500)) + + } +}) + +exports.createWarehouse = asyncHandler(async (req, res, next) => { + try { + var date = dateFormat(new Date(), "yyyy-mm-dd HH:mm:ss") + await db.transaction(async (t) => { + const warehouse = await WarehouseModel.create({ + DB_CODE: req.user.DB_CODE, + WAR_CODE: req.body.WAR_CODE, + WAR_NAME: req.body.WAR_NAME, + WAR_DESC: req.body.WAR_DESC ?? "", + WAR_ADD1: req.body.WAR_ADDRESS ?? "", + WAR_ADD2: req.body.WAR_ADD2 ?? "", + WAR_ADD3: req.body.WAR_ADD3 ?? "", + WAR_TEL1: req.body.WAR_TEL1 ?? "", + WAR_TEL2: req.body.WAR_TEL2 ?? "", + WAR_FAX: req.body.WAR_FAX ?? "", + WAR_COM1: req.body.WAR_COM1 ?? "", + WAR_COM2: req.body.WAR_COM2 ?? "", + WAR_CREA: date, + USER_CODE: req.user.USER_CODE, + WAR_STAT: 'A' + }, { transaction: t }) + res.status(200).json(new SuccessResponse(200, warehouse)) + }) + } catch (e) { + console.log("ERROR CREATING WAREHOUSE ", e) + return next(new ErrorResponse(`Something when wrong ${e}`, 500)); + } +}) \ No newline at end of file diff --git a/Model/Inventory_Movement_Model.js b/Model/Inventory_Movement_Model.js new file mode 100644 index 0000000..287d788 --- /dev/null +++ b/Model/Inventory_Movement_Model.js @@ -0,0 +1,140 @@ +const db = require("../Config/db"); +const sequelize = require("sequelize"); + +const modelCache = {}; + +function getInventoryMovementTable(tableName) { + console.log("MODEL CACHE ", modelCache); + if (!modelCache[tableName]) { + const model = db.define( + tableName, + { + SEQUENCE: { + type: sequelize.INTEGER + }, + REC_TYPE: { + type: sequelize.STRING + }, + MOV_PRD: { + type: sequelize.INTEGER + }, + MOV_REF: { + primaryKey: true, + type: sequelize.STRING + }, + MOV_LINE: { + primaryKey: true, + type: sequelize.STRING + }, + LOCATION: { + type: sequelize.STRING + }, + ITEM_CODE: { + type: sequelize.STRING + }, + MOV_DATE: { + type: sequelize.STRING + }, + STATUS: { + type: sequelize.STRING + }, + IR_STAT: { + type: sequelize.STRING + }, + BATCH_NO: { + type: sequelize.INTEGER + }, + BATCH_LINE: { + type: sequelize.STRING + }, + LINE_REF: { + type: sequelize.STRING + }, + QUANTITY: { + type: sequelize.FLOAT + }, + COST: { + type: sequelize.FLOAT + }, + TOTAL: { + type: sequelize.FLOAT + }, + MOV_UNITS: { + type: sequelize.STRING + }, + MOV_TYPE: { + type: sequelize.STRING + }, + UPDTE_PHYS: { + type: sequelize.STRING + }, + UPDTE_ORDR: { + type: sequelize.STRING + }, + ALLOC_REF: { + type: sequelize.STRING + }, + ACCNT_CODE: { + type: sequelize.STRING + }, + ASSET_CODE: { + type: sequelize.STRING + }, + ANAL_M0: { + type: sequelize.STRING + }, + ANAL_M1: { + type: sequelize.STRING + }, + ANAL_M2: { + type: sequelize.STRING + }, + ANAL_M3: { + type: sequelize.STRING + }, + ANAL_M4: { + type: sequelize.STRING + }, + ANAL_M5: { + type: sequelize.STRING + }, + ANAL_M6: { + type: sequelize.STRING + }, + ANAL_M7: { + type: sequelize.STRING + }, + ANAL_M8: { + type: sequelize.STRING + }, + ANAL_M9: { + type: sequelize.STRING + }, + ORIG_LINE_NO: { + type: sequelize.STRING + }, + PO_VALUE: { + type: sequelize.FLOAT + }, + ID_ENTERED: { + type: sequelize.STRING + }, + ID_ALLOC: { + type: sequelize.STRING + } + }, + { + timestamps: false, + freezeTableName: true + } + ); + + model.removeAttribute('id'); + + modelCache[tableName] = model; + } + return modelCache[tableName]; + +} + +module.exports = { getInventoryMovementTable }; diff --git a/Model/SupplierItemModel.js b/Model/SupplierItemModel.js new file mode 100644 index 0000000..b5f6e32 --- /dev/null +++ b/Model/SupplierItemModel.js @@ -0,0 +1,31 @@ +const sequelize = require("sequelize") +const db = require("../Config/db"); + +const SupplierItem = db.define( + 'TDITEMSP', + { + ITEM_CODE: { + type: sequelize.STRING, + }, + DB_CODE: { + type: sequelize.STRING + }, + SUPP_CODE: { + type: sequelize.STRING + }, + SUPP_COST: { + type: sequelize.NUMERIC + }, + SUPP_UNIT: { + type: sequelize.STRING + } + + }, + { + timestamps: false, + freezeTableName: true, + } +) + +SupplierItem.removeAttribute('id') +module.exports = SupplierItem; \ No newline at end of file diff --git a/Model/WarehouseModel.js b/Model/WarehouseModel.js new file mode 100644 index 0000000..b959161 --- /dev/null +++ b/Model/WarehouseModel.js @@ -0,0 +1,61 @@ +const sequelize = require('sequelize') +const db = require('../Config/db') + +const WarehouseModel = db.define( + 'TDWAREH', + { + DB_CODE: { + type: sequelize.STRING, + }, + WAR_CODE: { + type: sequelize.STRING, + }, + WAR_NAME: { + type: sequelize.STRING, + }, + WAR_DESC: { + type: sequelize.STRING, + }, + WAR_ADD1: { + type: sequelize.STRING, + }, + WAR_ADD2: { + type: sequelize.STRING, + }, + WAR_ADD3: { + type: sequelize.STRING, + }, + WAR_TEL1: { + type: sequelize.STRING, + }, + WAR_TEL2: { + type: sequelize.STRING, + }, + WAR_FAX: { + type: sequelize.STRING, + }, + WAR_COM1: { + type: sequelize.STRING, + }, + WAR_COM2: { + type: sequelize.STRING, + }, + WAR_STAT: { + type: sequelize.STRING, + }, + USER_CODE: { + type: sequelize.STRING, + }, + WAR_CREA: { + type: sequelize.STRING, + }, + }, + { + timestamps: false, + freezeTableName: true, + } +) + + +WarehouseModel.removeAttribute('id') +module.exports = WarehouseModel; \ No newline at end of file diff --git a/app.js b/app.js index 94bc090..6494ca5 100644 --- a/app.js +++ b/app.js @@ -6,7 +6,6 @@ var logger = require('morgan'); var dotenv = require("dotenv") var app = express(); -// const bodyParser = require('body-parser'); dotenv.config({ @@ -25,6 +24,8 @@ var storeRouter = require('./routes/store') var categoryRouter = require('./routes/category') var subscriptionRouter = require('./routes/subscription') var supplierRouter = require('./routes/supplier') +var inventoryRouter = require('./routes/inventory_movement') +var wareouseRouter = require('./routes/warehouse') //CORS @@ -60,6 +61,8 @@ app.use("/api/v1/store", storeRouter) app.use("/api/v1/subscriptions", subscriptionRouter) app.use("/api/v1/category", categoryRouter) app.use("/api/v1/supplier", supplierRouter) +app.use("/api/v1/inventory", inventoryRouter) +app.use('/api/v1/warehouse', wareouseRouter) diff --git a/routes/inventory_movement.js b/routes/inventory_movement.js new file mode 100644 index 0000000..b3dfb11 --- /dev/null +++ b/routes/inventory_movement.js @@ -0,0 +1,27 @@ +const express = require('express') +const route = express.Router() +const controller = require("../Controller/Inventory_Movement") +const { protect, protectAtlogin } = require("../Middleware/auth") + +// const multer = require('multer') +// const moment = require('moment') + +// var storage = multer.diskStorage({ +// destination: function (req, file, cb) { +// if (file.fieldname == "store_image") cb(null, "upload/store/tmp_post"); +// }, +// filename: function (req, file, cb) { +// cb( +// null, +// moment(Date.now()).format("YYYY-MM-DD_HH-mm-ss_") + file.originalname +// ); +// }, +// }); + +// var upload = multer({ storage: storage }); + +route.route("/add_stock").post(protect, controller.createStock) +route.route("/get_all_stock").get(protect, controller.getAllStock) +// route.route("/register").post(upload.single("store_image"), protectAtlogin, controller.registerStore) + +module.exports = route; \ No newline at end of file diff --git a/routes/warehouse.js b/routes/warehouse.js new file mode 100644 index 0000000..a864780 --- /dev/null +++ b/routes/warehouse.js @@ -0,0 +1,27 @@ +const express = require("express"); +const route = express.Router(); +const controller = require("../Controller/Warehouse"); +const { protect } = require("../Middleware/auth") + +// const multer = require("multer"); +// const moment = require("moment"); +// var storage = multer.diskStorage({ +// destination: function (req, file, cb) { +// if (file.fieldname == "supplier_image") cb(null, "uploads/supplier/tmp_post"); +// }, + +// filename: function (req, file, cb) { +// cb( +// null, +// moment(Date.now()).format("YYYY-MM-DD_HH-mm-ss_") + file.originalname +// ); +// }, +// }); + +// var upload = multer({ storage: storage }); + + +route.route('/').get(protect, controller.getAllWarehouse) +route.route('/').post(protect, controller.createWarehouse) + +module.exports = route; \ No newline at end of file