Feature #5701
closedPrepare the purchase module , vendor_invoices, product_batches schema preparation
Subtasks
Related issues
Updated by Teja Sriram Sangani about 2 months ago
- Status changed from New to Resolved
- % Done changed from 0 to 90
const mongoose = require("mongoose");
const Counter = require("../../models/MVP@2/counter-model");
// Action History (shared)
const actionHistorySchema = new mongoose.Schema({
action: {
type: String,
enum: ["create", "update", "delete", "comment", "status_change", "revert"],
required: true,
},
performedBy: { type: String, ref: "NurseryUser" },
timestamp: { type: Date, default: Date.now },
note: { type: String, trim: true },
changes: { type: mongoose.Schema.Types.Mixed },
});
// Invoice Sub-Item (Product Purchase)
const PurchaseItemSchema = new mongoose.Schema({
productId: {
type: mongoose.Schema.Types.ObjectId,
ref: "NurseryProduct",
required: true,
},
vendorId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Vendor",
required: true,
},
quantity: { type: Number, required: true },
purchase_cost: { type: Number, required: true }, // cost per unit
totalCost: { type: Number }, // auto-calculated quantity * purchaseCost
tax: { type: Number, default: 0 }, // tax amount for this item
stockBatchId: {
type: mongoose.Schema.Types.ObjectId,
ref: "StockBatch",
},
});
// Installment (optional)
const PaymentInstallmentSchema = new mongoose.Schema({
amount: { type: Number, required: true },
status: {
type: String,
enum: ["pending", "paid", "failed"],
default: "pending",
},
paymentMode: {
type: String,
enum: ["cash", "card", "bank_transfer", "upi", "online", "zelle"],
required: true,
},
doneAt: { type: Date },
dueDate: { type: Date },
});
// Final Invoice Schema
const VendorInvoiceSchema = new mongoose.Schema({
vendorId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Vendor",
required: true,
},
invoiceId: { type: String }, // auto-generated like PI_0001
createdBy: { type: String, ref: "NurseryUser" },
updatedBy: { type: String, ref: "NurseryUser" },
items: [PurchaseItemSchema],
totalAmount: { type: Number, required: true },
remainingBalance: { type: Number, default: function () { return this.totalAmount; } },
payments: [PaymentInstallmentSchema],
status: {
type: String,
enum: [
"awaiting_payment",
"partial",
"paid",
"failed",
"overdue",
"canceled",
],
default: "awaiting_payment",
},
actionHistory: [actionHistorySchema],
dueDate: { type: Date },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now },
});
// Auto-calc + Auto Invoice ID
VendorInvoiceSchema.pre("save", async function (next) {
this.updatedAt = Date.now();
// Calculate remaining amount
const paid = this.payments
.filter((p) => p.status === "paid")
.reduce((sum, p) => sum + p.amount, 0);
this.remainingBalance = this.totalAmount - paid;
// New invoice? Generate Invoice ID
if (this.isNew) {
const counter = await Counter.findOneAndUpdate(
{ _id: "vendorInvoiceId" },
{ $inc: { seq: 1 } },
{ new: true, upsert: true }
);
this.invoiceId = `VI_${String(counter.seq).padStart(4, "0")}`;
}
next();
});
module.exports = mongoose.model("VendorInvoice", VendorInvoiceSchema);
vednor invoice schema
const mongoose = require("mongoose");
const stockBatchSchema = new mongoose.Schema({
productId: {
type: mongoose.Schema.Types.ObjectId,
ref: "NurseryProduct",
required: true,
},
vendorId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Vendor",
required: true,
},
invoiceId: {
type: mongoose.Schema.Types.ObjectId,
ref: "VendorInvoice",
},
purchase_cost: { type: Number, required: true },
qtyReceived: { type: Number, required: true },
qtyRemaining: { type: Number, required: true },
receivedAt: { type: Date, default: Date.now },
createdBy: { type: String, ref: "NurseryUser" },
BatchStatus: { type: Boolean, default: true },
});
module.exports = mongoose.model("StockBatch", stockBatchSchema);
stockBatch schema
Updated by Yalavarthi Thriveni about 1 month ago
- Status changed from Resolved to Closed