All checks were successful
farmcontrol/farmcontrol-api/pipeline/head This commit looks good
This commit introduces several utility functions in `utils.js` to improve ObjectId handling, including `isByte`, `isTwelveByteBuffer`, and `objectIdToString`. The `expandObjectIds` function is updated to better handle various ObjectId formats, including BSON ObjectIds and serialized 12-byte buffers. Additionally, comprehensive tests are added in `utils.expandObjectIds.test.js` to verify the correct behavior of these enhancements, ensuring robust handling of ObjectId conversions and expansions.
175 lines
5.1 KiB
JavaScript
175 lines
5.1 KiB
JavaScript
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);
|