import mongoose from 'mongoose'; import { generateId } from '../../utils.js'; import { editObject, newObject, deleteObject } from '../../database.js'; const { Schema } = mongoose; const listingSchema = new Schema( { _reference: { type: String, default: () => generateId()() }, product: { type: Schema.Types.ObjectId, ref: 'product', required: false }, vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true }, stockLocation: { type: Schema.Types.ObjectId, ref: 'stockLocation', required: true }, marketplace: { type: Schema.Types.ObjectId, ref: 'marketplace', required: true }, title: { type: String, required: false }, state: { type: { type: String, enum: ['draft', 'active', 'inactive', 'deleted', 'suspended', 'syncing'], default: 'draft', }, message: { type: String, required: false }, }, url: { type: String, required: false }, description: { type: String, required: false }, externalReference: { type: String, required: false }, price: { type: Number, required: false }, currency: { type: String, required: false }, lastSyncedAt: { type: Date, required: false }, stockQuantity: { type: Number, required: false, default: 0 }, condition: { type: String, enum: [ 'new', 'likeNew', 'newOther', 'newWithDefects', 'manufacturerRefurbished', 'certifiedRefurbished', 'excellentRefurbished', 'veryGoodRefurbished', 'goodRefurbished', 'sellerRefurbished', 'usedExcellent', 'usedVeryGood', 'usedGood', 'usedAcceptable', 'forPartsOrNotWorking', 'preOwnedExcellent', 'preOwnedFair', ], default: 'new', required: false, }, courierServices: [{ type: Schema.Types.ObjectId, ref: 'courierService', required: true }], }, { timestamps: true } ); listingSchema.index({ title: 'text', url: 'text' }); listingSchema.index({ marketplace: 1, externalReference: 1 }, { unique: true, sparse: true }); listingSchema.virtual('id').get(function () { return this._id; }); listingSchema.set('toJSON', { virtuals: true, transform(doc, ret) { if (!ret.state && ret.status) { ret.state = { type: ret.status, message: null }; } if (ret.status) delete ret.status; return ret; }, }); const refId = (value) => value?._id ?? value; listingSchema.statics.recalculate = async function (listing, user) { const listingId = refId(listing); if (!listingId) { return; } const listingVarientModel = mongoose.model('listingVarient'); const productSkuModel = mongoose.model('productSku'); const listingProductId = refId(listing.product); const findVarients = () => listingVarientModel.find({ listing: listingId }).sort({ createdAt: 1 }).lean(); let varients = await findVarients(); if (listingProductId) { const productSkus = await productSkuModel .find({ product: listingProductId }) .sort({ createdAt: 1 }) .lean(); const varientsBySkuId = new Map(); const unmatchedVarients = []; for (const varient of varients) { const skuId = refId(varient.productSku); if (skuId && !varientsBySkuId.has(String(skuId))) { varientsBySkuId.set(String(skuId), varient); } else { unmatchedVarients.push(varient); } } for (const sku of productSkus) { const skuId = sku._id; const varientUpdateData = { product: listingProductId, productSku: skuId, }; const existingVarient = varientsBySkuId.get(String(skuId)) || unmatchedVarients.shift(); if (existingVarient) { varientsBySkuId.delete(String(skuId)); const existingProductId = refId(existingVarient.product); const existingSkuId = refId(existingVarient.productSku); if ( String(existingProductId) === String(listingProductId) && String(existingSkuId) === String(skuId) ) { continue; } const varientResult = await editObject({ model: listingVarientModel, id: existingVarient._id, updateData: varientUpdateData, user, recalculate: false, }); if (varientResult.error) { throw varientResult; } } else { const varientResult = await newObject({ model: listingVarientModel, newData: { ...varientUpdateData, listing: listingId, state: { type: listing.state?.type || 'draft' }, }, user, recalculate: false, }); if (varientResult.error) { throw varientResult; } } } for (const extra of [...varientsBySkuId.values(), ...unmatchedVarients]) { const deleteResult = await deleteObject({ model: listingVarientModel, id: extra._id, user, }); if (deleteResult.error) { throw deleteResult; } } varients = await findVarients(); } for (const varient of varients) { await listingVarientModel.recalculate(varient, user); } }; export const listingModel = mongoose.model('listing', listingSchema);