const mongoose = require("mongoose"), Schema = mongoose.Schema, { UserTypes, InvCreateOption, InvoiceStatus, CostingItemType, Units } = require("../helpers/constants"), Currencies = require("../helpers/currencies"), env = require("../helpers/env"); const clientSchema = new Schema({ billTo: { type: Schema.Types.ObjectId, ref: UserTypes.CLIENT, required: true }, code: { type: String, required: false }, logo: { type: String, required: false, get: (logo) => logo ? `${env.INV_IMG_VIR_DIR}/${logo}` : undefined }, split: { type: String, required: true }, subTotal: { type: String, required: true }, paymentTerm: { type: Number, required: false }, discount: { type: String, required: false }, taxRate: { type: String, required: false }, amountPaid: { type: String, required: false }, amountDue: { type: String, required: false }, note: { type: String, required: false } }, { _id: false, toJSON: { getters: true }, toObject: { getters: true }, versionKey: false }); const jobSchema = new Schema({ job: { type: Schema.Types.Number, ref: "Job" }, name: { type: String, required: false }, totalAmount: { type: String, required: true }, costings: { billableArea: { type: Number, min: 0, required: false }, billableAmount: { type: Number, min: 0, require: false }, currency: { type: String, enum: Object.keys(Currencies), require: false }, items: [ { item: { type: Schema.Types.ObjectId, ref: 'costing_items', require: false }, name: { type: String, require: false }, price: { type: Number, min: 0, require: false }, quantity: { type: Number, min: 0, require: false }, type: { type: Number, enum: Object.values(CostingItemType), require: false }, unit: { type: Number, enum: Object.values(Units), require: false }, }, ], }, }, { _id: false, toJSON: { getters: true }, toObject: { getters: true }, versionKey: false }); const schema = new Schema({ code: { type: String, required: true }, companyName: { type: String, required: false }, address: { type: String, required: false }, logo: { type: String, required: false, get: (logo) => logo ? `${env.INV_IMG_VIR_DIR}/${logo}` : undefined }, currency: { type: String, required: true }, poNumber: { type: String, required: false }, dueDate: { type: Date, required: true }, openDate: { type: Date, required: true }, paidAt: { type: Date, required: false }, note: { type: String, required: false }, paymentTerm: { type: Number, required: false }, createOp: { type: String, enum: Object.values(InvCreateOption), message: "{VALUE} for invoice 'createOp' is not supported", default: InvCreateOption.Option1, }, status: { type: String, enum: Object.values(InvoiceStatus), message: "{VALUE} for invoice 'status' is not supported", default: InvoiceStatus.Draft, }, jobs: [jobSchema, { id: false }], clients: [clientSchema, { id: false }], // Applicator userId. This is for performance optimization when querying byPuid: { type: Schema.Types.ObjectId, ref: UserTypes.APP, required: true, index: true }, createdBy: { type: Schema.Types.ObjectId, ref: 'User', required: false }, updatedBy: { type: Schema.Types.ObjectId, ref: 'User', required: false } }, { timestamps: true, toJSON: { getters: true, id: false }, toObject: { getters: true, id: false } }); schema.index({ status: 1, openDate: 1 }); module.exports = mongoose.model("Invoice", schema);