Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 81 additions & 9 deletions src/controllers/bmdashboard/bmInventoryTypeController.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ const filepath = path.join(rootPath, filename);
const { readFile } = fs;
const { writeFile } = fs;

function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolType, EquipType) {
function bmInventoryTypeController(
InvType,
MatType,
ConsType,
ReusType,
ToolType,
EquipType,
invTypeHistory,
) {
async function fetchMaterialTypes(req, res) {
try {
MatType.find()
Expand Down Expand Up @@ -362,32 +370,95 @@ function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolTyp
const updateNameAndUnit = async (req, res) => {
try {
const { invtypeId } = req.params;
const { name, unit } = req.body;
const {
name,
unit,
requestor: { requestorId },
} = req.body;

// 1. Fetch existing document
const invType = await MatType.findById(invtypeId);
if (!invType) {
return res.status(404).send('invType Material not found check Id');
}

// 2. Name uniqueness check
if (name && name !== invType.name) {
const existingInvType = await MatType.findOne({
name,
_id: { $ne: invtypeId },
});

if (existingInvType) {
return res.status(404).send('Material name already exists');
}
}

const historyDocs = [];
const updateData = {};

if (name) {
// 3. Track name change
if (name && name !== invType.name) {
historyDocs.push({
invtypeId,
field: 'name',
oldValue: invType.name,
newValue: name,
editedBy: requestorId,
});
updateData.name = name;
}

if (unit) {
// 4. Track unit change
if (unit && unit !== invType.unit) {
historyDocs.push({
invtypeId,
field: 'unit',
oldValue: invType.unit,
newValue: unit,
editedBy: requestorId,
});
updateData.unit = unit;
}

const updatedInvType = await InvType.findByIdAndUpdate(invtypeId, updateData, {
// 5. Save history (if any)
if (historyDocs.length > 0) {
await invTypeHistory.insertMany(historyDocs);
}

// 6. Update main document
const updatedInvType = await MatType.findByIdAndUpdate(invtypeId, updateData, {
new: true,
runValidators: true,
});

if (!updatedInvType) {
return res.status(404).json({ error: 'invType Material not found check Id' });
}

res.status(200).json(updatedInvType);
} catch (error) {
console.error(error);
res.status(500).send(error);
}
};

const fetchInvTypeHistory = async (req, res) => {
try {
const { invtypeId } = req.params;

if (!invtypeId || !invtypeId.match(/^[0-9a-fA-F]{24}$/)) {
return res.status(400).json({ message: 'Invalid inventory type id' });
}

const history = await invTypeHistory
.find({ invtypeId })
.populate('editedBy', '_id firstName lastName email')
.sort({ editedAt: -1 })
.lean();

res.status(200).json(history);
} catch (error) {
console.error('Fetch history error:', error);
res.status(500).json({ message: 'Failed to fetch inventory history' });
}
};
return {
fetchMaterialTypes,
fetchConsumableTypes,
Expand All @@ -402,6 +473,7 @@ function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolTyp
addToolType,
fetchInvUnitsFromJson,
fetchInventoryByType,
fetchInvTypeHistory,
};
}

Expand Down
124 changes: 88 additions & 36 deletions src/models/bmdashboard/buildingInventoryType.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,70 +23,121 @@ const invTypeBase = mongoose.model('invTypeBase', invTypeBaseSchema, 'buildingIn

// ex: sand, stone, brick, lumber

const materialType = invTypeBase.discriminator('material_type', new mongoose.Schema({
category: { type: String, enum: ['Material'] },
unit: { type: String, required: true }, // unit of measurement
}));
const materialType = invTypeBase.discriminator(
'material_type',
new mongoose.Schema({
category: { type: String, enum: ['Material'] },
unit: { type: String, required: true }, // unit of measurement
}),
);

//---------------------------
// CONSUMABLE TYPE
//---------------------------

// ex: screws, nails, staples

const consumableType = invTypeBase.discriminator('consumable_type', new mongoose.Schema({
category: { type: String, enum: ['Consumable'] },
unit: { type: String, required: true },
size: { type: String, required: false },
}));
const consumableType = invTypeBase.discriminator(
'consumable_type',
new mongoose.Schema({
category: { type: String, enum: ['Consumable'] },
unit: { type: String, required: true },
size: { type: String, required: false },
}),
);

//---------------------------
// REUSABLE TYPE
//---------------------------

// ex: gloves, brushes, hammers, screwdrivers

const reusableType = invTypeBase.discriminator('reusable_type', new mongoose.Schema({
category: { type: String, enum: ['Reusable'] },
}));
const reusableType = invTypeBase.discriminator(
'reusable_type',
new mongoose.Schema({
category: { type: String, enum: ['Reusable'] },
}),
);

//---------------------------
// TOOL TYPE
//---------------------------

// ex: shovels, wheelbarrows, power drills, jackhammers

const toolType = invTypeBase.discriminator('tool_type', new mongoose.Schema({
category: { type: String, enum: ['Tool'] },
invoice: String,
purchaseRental: String,
fromDate: Date,
toDate:Date,
condition: String,
phoneNumber: String,
quantity: Number,
currency: String,
unitPrice: Number,
shippingFee: Number,
taxes: Number,
totalPriceWithShipping: Number,
images: String,
link: String,

// isPowered: { type: Boolean, required: true },
// powerSource: { type: String, required: () => this.isPowered }, // required if isPowered = true (syntax?)
}));
const toolType = invTypeBase.discriminator(
'tool_type',
new mongoose.Schema({
category: { type: String, enum: ['Tool'] },
invoice: String,
purchaseRental: String,
fromDate: Date,
toDate: Date,
condition: String,
phoneNumber: String,
quantity: Number,
currency: String,
unitPrice: Number,
shippingFee: Number,
taxes: Number,
totalPriceWithShipping: Number,
images: String,
link: String,

// isPowered: { type: Boolean, required: true },
// powerSource: { type: String, required: () => this.isPowered }, // required if isPowered = true (syntax?)
}),
);

//---------------------------
// EQUIPMENT TYPE
//---------------------------

// ex: tractors, excavators

const equipmentType = invTypeBase.discriminator('equipment_type', new mongoose.Schema({
category: { type: String, enum: ['Equipment'] },
fuelType: { type: String, enum: ['Diesel', 'Biodiesel', 'Gasoline', 'Natural Gas', 'Ethanol'], required: true },
}));
const equipmentType = invTypeBase.discriminator(
'equipment_type',
new mongoose.Schema({
category: { type: String, enum: ['Equipment'] },
fuelType: {
type: String,
enum: ['Diesel', 'Biodiesel', 'Gasoline', 'Natural Gas', 'Ethanol'],
required: true,
},
}),
);
/* =========================
INVENTORY TYPE HISTORY
========================= */

const invTypeHistorySchema = new Schema({
invtypeId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'invTypeBase',
required: true,
},
field: {
type: String,
required: true,
},
oldValue: {
type: Schema.Types.Mixed,
},
newValue: {
type: Schema.Types.Mixed,
},
editedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'userProfile',
required: true,
},
editedAt: {
type: Date,
default: Date.now,
},
});

const invTypeHistory = mongoose.model('invTypeHistory', invTypeHistorySchema);

module.exports = {
invTypeBase,
Expand All @@ -95,4 +146,5 @@ module.exports = {
reusableType,
toolType,
equipmentType,
invTypeHistory,
};
12 changes: 11 additions & 1 deletion src/routes/bmdashboard/bmInventoryTypeRouter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
const express = require('express');

const routes = function (baseInvType, matType, consType, reusType, toolType, equipType) {
const routes = function (
baseInvType,
matType,
consType,
reusType,
toolType,
equipType,
invTypeHistory,
) {
const inventoryTypeRouter = express.Router();
const controller = require('../../controllers/bmdashboard/bmInventoryTypeController')(
baseInvType,
Expand All @@ -9,6 +17,7 @@ const routes = function (baseInvType, matType, consType, reusType, toolType, equ
reusType,
toolType,
equipType,
invTypeHistory,
);

// Route for fetching all material types
Expand Down Expand Up @@ -40,6 +49,7 @@ const routes = function (baseInvType, matType, consType, reusType, toolType, equ
.put(controller.updateNameAndUnit);

inventoryTypeRouter.route('/inventoryUnits').get(controller.fetchInvUnitsFromJson);
inventoryTypeRouter.route('/invtypes/:invtypeId/history').get(controller.fetchInvTypeHistory);

return inventoryTypeRouter;
};
Expand Down
2 changes: 2 additions & 0 deletions src/startup/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const {
reusableType,
toolType,
equipmentType,
invTypeHistory,
} = require('../models/bmdashboard/buildingInventoryType');
const {
buildingConsumable,
Expand Down Expand Up @@ -211,6 +212,7 @@ const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRout
reusableType,
toolType,
equipmentType,
invTypeHistory,
);

const toolAvailabilityRoutes = require('../routes/bmdashboard/bmToolAvailabilityRoutes');
Expand Down
Loading