diff --git a/controllers/order.controller.js b/controllers/order.controller.js index 1f4b71c7fece064b909909461c5ab7cce6c9f615..865c6ecf254317155d3ddae91ae3cb531bbe8690 100644 --- a/controllers/order.controller.js +++ b/controllers/order.controller.js @@ -2390,6 +2390,7 @@ module.exports.generateShippingLabel = async (req, res) => { }); } + // Check if order belongs to the store (for store admin) const user = req.user; if (user.role === "store_admin" && order.store_id !== user.storeId) { @@ -2483,6 +2484,22 @@ module.exports.generateShippingLabel = async (req, res) => { amount: `$${parseFloat(order.total_amount).toFixed(2)}`, labelNotes: "", }, + // Order Items (map from order.orderItems) + orderItems: order.orderItems ? order.orderItems.map(item => ({ + name: item.product_name || "Product", + variant: item.variant_name && item.variant_name !== "DUMMY" ? item.variant_name : "", + quantity: item.quantity || 1, + totalPrice: parseFloat(item.total_price) || 0.00 + })) : [], + + // Order Totals + orderTotals: { + subTotal: parseFloat(order.subtotal_amount) || 0.00, + tax: parseFloat(order.tax_amount) || 0.00, + shipping: parseFloat(order.shipping_cost) || 0.00, + discount: parseFloat(order.discount_amount) || 0.00, + total: parseFloat(order.total_amount) || (parseFloat(order.subtotal_amount) + parseFloat(order.tax_amount) + parseFloat(order.shipping_cost) - parseFloat(order.discount_amount)) || 0.00 + }, }; // Generate unique timestamp for filenames @@ -3142,6 +3159,44 @@ const generateLabelHTML = async (labelData) => { Package Details: ${labelData.packageDetails || "Standard Package"} + + ${labelData.orderItems && labelData.orderItems.length > 0 ? ` +
+
ORDER ITEMS:
+ ${labelData.orderItems.map(item => ` +
+ ${item.name}${item.variant ? ` - ${item.variant}` : ''} + ${item.quantity}x + $${item.totalPrice.toFixed(2)} +
+ `).join('')} + + ${labelData.orderTotals ? ` +
+
+ Sub Total: + $${labelData.orderTotals.subTotal ? labelData.orderTotals.subTotal.toFixed(2) : '0.00'} +
+
+ Tax: + $${parseFloat(labelData.orderTotals.tax || 0).toFixed(2)} +
+
+ Shipping: + $${parseFloat(labelData.orderTotals.shipping || 0).toFixed(2)} +
+
+ Discount: + -$${parseFloat(labelData.orderTotals.discount || 0).toFixed(2)} +
+
+ TOTAL: + $${labelData.orderTotals.total ? labelData.orderTotals.total.toFixed(2) : '0.00'} +
+
+ ` : ''} +
+ ` : ''} @@ -4695,19 +4750,20 @@ module.exports.createOrderForSuperAdmin = async (req, res) => { }) ); + console.log("cartItemsForCalculationnnnnnn",cartItemsForCalculation) // Calculate cart summary using the same function as ecommerce - const cartSummary = await calculateCartSummary( - cartItemsForCalculation, - null, // No cart object for super admin - { + const cartSummary = await calculateCartSummary({ + cartItems: cartItemsForCalculation, + cart: null, // No cart object for super admin + options: { deliveryMethod: deliveryMethod, discountAmount: 0, // Can be added later if needed discountPercentage: 0, }, - customerState, - parseFloat(shipping) || 15, - storeId - ); + customerState: customerState, + storeId: storeId, + tipAmount: parseFloat(tip) || 0, + }); // Use cart summary for order totals const subtotalAmount = cartSummary.subtotal; diff --git a/controllers/product.controller.js b/controllers/product.controller.js index a6c6ec3286a3175a7789ce9e29d30d5ff0bce20a..5a31b286e13f1cf0cdfeefb3449ad450bb027a70 100644 --- a/controllers/product.controller.js +++ b/controllers/product.controller.js @@ -3038,7 +3038,7 @@ module.exports.getAllProducts = async (req, res) => { const storeIdFromToken = req.user?.storeId || req.user?.storeID || req.user?.store_id; - console.log("storeIdFromTokennnnn",storeIdFromToken) + // console.log("storeIdFromTokennnnn",storeIdFromToken) // Handle masterProducts parameter if (masterProducts === "true" || masterProducts === true) { @@ -3274,7 +3274,7 @@ module.exports.getAllProducts = async (req, res) => { distinct: true, // Important for many-to-many relationships }); - console.log("productsssssss",products) + // console.log("productsssssss",products) // Add price and stock information to each product, and include variants for multi-variant products const productsWithPrices = products.map((product) => { const productData = product.toJSON(); diff --git a/controllers/store.controller.js b/controllers/store.controller.js index 4a07af44b6cef34202068e6fe5a256dbd15da0aa..7ff5dad040a1e58031ec39775766d213945638a3 100644 --- a/controllers/store.controller.js +++ b/controllers/store.controller.js @@ -14,6 +14,7 @@ const { createSingleUserService, updateUserService, updateSingleUserService, + updateSingleUserWithHooksService, } = require("../services/user.services"); const ERROR_RESPONSE = require("../utils/handleError"); const { getPagination } = require("../utils/pagination"); @@ -350,7 +351,7 @@ module.exports.updateStoreSection = async (req, res) => { console.log("Updating existing store admin:", existingStoreAdmin.ID); // Update the existing user with new email and password - await updateSingleUserService( + await updateSingleUserWithHooksService( { email: sectionData.storeAdminLoginEmail, password: sectionData.temporaryPassword, @@ -1654,8 +1655,14 @@ module.exports.getStoreCategoryCounts = async (req, res) => { COUNT(DISTINCT p.ID) AS productCount FROM categories c LEFT JOIN product_category pc ON pc.category_id = c.ID - LEFT JOIN products p ON p.ID = pc.product_id AND p.status = 'active' - LEFT JOIN product_store ps ON ps.productId = p.ID AND ps.storeId = ? AND ps.isActive = true + INNER JOIN products p + ON p.ID = pc.product_id + AND p.status = 'active' + AND p.isDeleted = 0 + INNER JOIN product_store ps + ON ps.productId = p.ID + AND ps.storeId = ? + AND ps.isActive = true WHERE c.isDeleted = false GROUP BY c.ID, c.categoryName ORDER BY c.categoryName ASC; @@ -1669,11 +1676,10 @@ module.exports.getStoreCategoryCounts = async (req, res) => { SELECT COUNT(DISTINCT p.ID) AS total FROM products p INNER JOIN product_store ps ON ps.productId = p.ID AND ps.storeId = ? AND ps.isActive = true - WHERE p.status = 'active'; + WHERE p.status = 'active' AND p.isDeleted = 0; `, { replacements: [storeId], type: sequelize.QueryTypes.SELECT } ); - return res.status(200).json({ status: true, message: "Category counts fetched successfully", @@ -2202,7 +2208,7 @@ module.exports.superAdminUpdateStoreSection = async (req, res) => { console.log("Updating existing store admin:", existingStoreAdmin.ID); // Update the existing user with new email and password - await updateSingleUserService( + await updateSingleUserWithHooksService( { email: sectionData.storeAdminLoginEmail, password: sectionData.temporaryPassword, diff --git a/services/user.services.js b/services/user.services.js index 9bec0ca473772cd44b8cbcf46afb2f0ab42ed3a6..6055d529673a78513fb7e9aa950c486ce9228ab3 100644 --- a/services/user.services.js +++ b/services/user.services.js @@ -100,3 +100,19 @@ module.exports.updateSingleUserService = async (payload, query) => { throw new Error("Error while updating the user"); } }; + +// New service for password updates that need bcrypt hooks +module.exports.updateSingleUserWithHooksService = async (payload, query) => { + try { + const user = await USER_MODEL.findOne(query); + if (!user) { + throw new Error("User not found"); + } + + const updatedUser = await user.update(payload); + return updatedUser; + } catch (error) { + console.error("Update Error:", error); + throw new Error("Error while updating the user"); + } +}; \ No newline at end of file diff --git a/utils/cartCalculations.js b/utils/cartCalculations.js index 324b7af727867198f0c2568dee0f8f3dc28b5079..a7c60c13a320a0bc04501e5428c9f33b9874b584 100644 --- a/utils/cartCalculations.js +++ b/utils/cartCalculations.js @@ -823,11 +823,11 @@ const calculateCartSummary = async ({ customerState, calculationStoreId, }); - console.log("processedCartItems", processedCartItems); + // console.log("processedCartItems", processedCartItems); // Calculate basic cart totals const cartCalculations = calculateCartTotals(processedCartItems); - console.log("cartCalculations", cartCalculations); + // console.log("cartCalculations", cartCalculations); // Apply additional options (discounts, shipping, etc.) const { @@ -836,14 +836,14 @@ const calculateCartSummary = async ({ deliveryMethod = "standard", appliedDiscounts = null, } = options; - console.log("options", options); + // console.log("options", options); // Calculate discount let finalDiscount = parseFloat(discountAmount) || 0; if (discountPercentage > 0) { finalDiscount += (cartCalculations.subtotal * discountPercentage) / 100; } - console.log("finalDiscount", finalDiscount); + // console.log("finalDiscount", finalDiscount); // // Get pickup address from store let pickup = null; @@ -925,7 +925,7 @@ const calculateCartSummary = async ({ surchargeDetails, } = chargesInfo; - console.log("chargesInfo", chargesInfo); + // console.log("chargesInfo", chargesInfo); // Calculate all active contributions for all charge types try { @@ -1000,7 +1000,7 @@ const calculateCartSummary = async ({ shippingContribution, tipDistribution, }); - console.log("profitDetails", profitDetails); + // console.log("profitDetails", profitDetails); } catch (error) { console.error("Error calculating profits:", error); // Set default profit values if calculation fails @@ -1038,7 +1038,7 @@ const calculateCartSummary = async ({ ? profitBreakdown.contributions.shipping.customer : 0; - console.log("appliedShippCharges", appliedShippCharges); + // console.log("appliedShippCharges", appliedShippCharges); //Order calculations const finalTotal = @@ -1049,7 +1049,7 @@ const calculateCartSummary = async ({ tipAmount + // Tip amount (surcharges || 0); // surcharges - console.log("finalTotal", finalTotal); + // console.log("finalTotal", finalTotal); return { cartId: cart?.ID, diff --git a/utils/generateTrackingNumber.js b/utils/generateTrackingNumber.js index 44c07ad9eab768b02a7944812d77e158f9ef0999..e646bc8744913b0e9f4d959b73d082ac583255e6 100644 --- a/utils/generateTrackingNumber.js +++ b/utils/generateTrackingNumber.js @@ -1,20 +1,19 @@ /** - * Generate unique tracking number based on order number - * @param {string} orderNumber - The order number + * Generate unique tracking number + * Format: TRK-YYYYMM-XXX (e.g., TRK-202501-001, TRK-202501-002) + * @param {string} orderNumber - The order number (optional) * @returns {string} Unique tracking number */ -const generateTrackingNumber = (orderNumber) => { - // Remove any non-alphanumeric characters from order number - const cleanOrderNumber = orderNumber.replace(/[^a-zA-Z0-9]/g, ''); - - // Get current timestamp for uniqueness - const timestamp = Date.now().toString().slice(-6); +const generateTrackingNumber = (orderNumber = null) => { + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, "0"); - // Generate random 3-digit number - const random = Math.floor(Math.random() * 900) + 100; + // Generate a simple sequential number based on current timestamp + const timestamp = Date.now().toString().slice(-3); // Last 3 digits of timestamp - // Combine: TRK + clean order number + timestamp + random - const trackingNumber = `TRK${cleanOrderNumber}${timestamp}${random}`; + // Format: TRK-YYYYMM-XXX + const trackingNumber = `TRK-${year}${month}-${timestamp}`; return trackingNumber; }; @@ -25,12 +24,16 @@ const generateTrackingNumber = (orderNumber) => { * @param {string} prefix - Optional prefix (default: "TRK") * @returns {string} Unique tracking number */ -const generateTrackingNumberWithPrefix = (orderNumber, prefix = "TRK") => { - const cleanOrderNumber = orderNumber.replace(/[^a-zA-Z0-9]/g, ''); - const timestamp = Date.now().toString().slice(-6); - const random = Math.floor(Math.random() * 900) + 100; +const generateTrackingNumberWithPrefix = (orderNumber = null, prefix = "TRK") => { + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, "0"); + + // Generate a simple sequential number based on current timestamp + const timestamp = Date.now().toString().slice(-3); // Last 3 digits of timestamp - return `${prefix}${cleanOrderNumber}${timestamp}${random}`; + // Format: PREFIX-YYYYMM-XXX + return `${prefix}-${year}${month}-${timestamp}`; }; module.exports = { diff --git a/utils/generateUniqueNumber.js b/utils/generateUniqueNumber.js index 9541b9899a7a78da76a54adcae5c1f09576a4ad3..b593e6b3df4e4ee47d1066d0ee22453a0967d3af 100644 --- a/utils/generateUniqueNumber.js +++ b/utils/generateUniqueNumber.js @@ -148,7 +148,7 @@ module.exports.getNextPONumber = async () => { /** * Generate a unique order number - * Format: ORD-YYYYMMDD-XXX (e.g., ORD-20250908-001, ORD-20250908-002) + * Format: ORD-YYYYMMDDXX (e.g., ORD-2025090901, ORD-2025090902) * Uses UNIQUE_NUMBER_MODEL to prevent race conditions */ module.exports.generateOrderNumber = async () => { @@ -158,16 +158,16 @@ module.exports.generateOrderNumber = async () => { const month = String(today.getMonth() + 1).padStart(2, "0"); const day = String(today.getDate()).padStart(2, "0"); - // Create a unique key for today's order sequence + // Create a unique key for this day's order sequence const sequenceKey = `orderNumber_${year}${month}${day}`; - // Get or create the sequence record for today + // Get or create the sequence record for this day let record = await UNIQUE_NUMBER_MODEL.findOne({ where: { type: sequenceKey } }); if (!record) { - // First order for today, start from 1 + // First order for this day, start from 1 record = await UNIQUE_NUMBER_MODEL.create({ type: sequenceKey, number: 1 @@ -181,10 +181,10 @@ module.exports.generateOrderNumber = async () => { // Get the current sequence number const sequence = record.number; - // Format sequence as 3-digit number (001, 002, 003, etc.) - const sequenceNumber = String(sequence).padStart(3, "0"); + // Format sequence as 2-digit number (01, 02, 03, etc.) + const sequenceNumber = String(sequence).padStart(2, "0"); - const orderNumber = `ORD-${year}${month}${day}-${sequenceNumber}`; + const orderNumber = `ORD-${year}${month}${day}${sequenceNumber}`; console.log(`Generated order number: ${orderNumber}`); return orderNumber; diff --git a/utils/pdfKitShippingLabel.js b/utils/pdfKitShippingLabel.js index 664a1b25b70070f7fc572799c439601ca84f3ff8..1d8c4e36bad40cd8b0b36fadd793ac53e683c5ad 100644 --- a/utils/pdfKitShippingLabel.js +++ b/utils/pdfKitShippingLabel.js @@ -123,35 +123,33 @@ const generateShippingLabelPDF = async (fulfillmentData) => { // Order details section const orderDetailsY = 110; - doc.fontSize(5) + doc.fontSize(6) .font('Helvetica-Bold') .text('ORDER DETAILS', 6, orderDetailsY); - // Sample order items (you can modify this to use actual order data) - const orderItems = [ - { name: 'iPhone 15 Pro Max 256GB', qty: '1x', price: '$1,199.00' }, - { name: 'AirPods Pro 2nd Gen', qty: '1x', price: '$249.00' }, - { name: 'Screen Protector', qty: '2x', price: '$19.98' } - ]; + // Use actual order items from fulfillmentData + const orderItems = fulfillmentData.orderItems || []; + const orderTotals = fulfillmentData.orderTotals || {}; - let itemY = orderDetailsY + 6; + let itemY = orderDetailsY + 7; orderItems.forEach(item => { - // Item name - doc.fontSize(3) + // Item name with variant if available + const itemName = item.variant ? `${item.name} - ${item.variant}` : item.name; + doc.fontSize(4) .font('Helvetica-Bold') - .text(item.name, 6, itemY, { width: 70 }); + .text(itemName, 6, itemY, { width: 70 }); // Quantity in the middle - doc.fontSize(3) + doc.fontSize(4) .font('Helvetica') - .text(item.qty, 78, itemY, { width: 15, align: 'center' }); + .text(`${item.quantity}x`, 78, itemY, { width: 15, align: 'center' }); // Price on the right - doc.fontSize(3) + doc.fontSize(4) .font('Helvetica') - .text(item.price, 95, itemY, { width: 55, align: 'right' }); + .text(`$${item.totalPrice.toFixed(2)}`, 95, itemY, { width: 55, align: 'right' }); - itemY += 5; + itemY += 6; }); // Dotted line separator @@ -161,34 +159,42 @@ const generateShippingLabelPDF = async (fulfillmentData) => { .stroke('#000000'); // Order totals - const totalsY = itemY + 6; + const totalsY = itemY + 7; - doc.fontSize(3) + doc.fontSize(4) .font('Helvetica-Bold') .text('Sub Total', 6, totalsY, { width: 70 }) - .text('$1,467.98', 78, totalsY, { width: 70, align: 'right' }); + .text(`$${orderTotals.subTotal ? orderTotals.subTotal.toFixed(2) : '0.00'}`, 78, totalsY, { width: 70, align: 'right' }); - doc.fontSize(3) + // Always show tax line + doc.fontSize(4) .font('Helvetica-Bold') - .text('Tax (8.5%)', 6, totalsY + 6, { width: 70 }) - .text('$124.78', 78, totalsY + 6, { width: 70, align: 'right' }); + .text('Tax', 6, totalsY + 7, { width: 70 }) + .text(`$${parseFloat(orderTotals.tax || 0).toFixed(2)}`, 78, totalsY + 7, { width: 70, align: 'right' }); - doc.fontSize(3) + // Always show shipping line + doc.fontSize(4) + .font('Helvetica-Bold') + .text('Shipping', 6, totalsY + 14, { width: 70 }) + .text(`$${parseFloat(orderTotals.shipping || 0).toFixed(2)}`, 78, totalsY + 14, { width: 70, align: 'right' }); + + // Always show discount line + doc.fontSize(4) .font('Helvetica-Bold') - .text('Shipping', 6, totalsY + 12, { width: 70 }) - .text('$9.99', 78, totalsY + 12, { width: 70, align: 'right' }); + .text('Discount', 6, totalsY + 21, { width: 70 }) + .text(`-$${parseFloat(orderTotals.discount || 0).toFixed(2)}`, 78, totalsY + 21, { width: 70, align: 'right' }); // Dotted line separator - doc.moveTo(6, totalsY + 18) - .lineTo(152, totalsY + 18) + doc.moveTo(6, totalsY + 28) + .lineTo(152, totalsY + 28) .dash(2, { space: 2 }) .stroke('#000000'); // Grand total - doc.fontSize(4) + doc.fontSize(5) .font('Helvetica-Bold') - .text('TOTAL', 6, totalsY + 24, { width: 70 }) - .text('$1,602.75', 78, totalsY + 24, { width: 70, align: 'right' }); + .text('TOTAL', 6, totalsY + 35, { width: 70 }) + .text(`$${orderTotals.total ? orderTotals.total.toFixed(2) : '0.00'}`, 78, totalsY + 35, { width: 70, align: 'right' }); // Generate and embed barcode try { diff --git a/utils/shippingLabelTemplate.js b/utils/shippingLabelTemplate.js index 1e6a3ef01abd949783045c793c4d553f21b12c9c..f83128c1650051d3103772d1a298f22d21bdb281 100644 --- a/utils/shippingLabelTemplate.js +++ b/utils/shippingLabelTemplate.js @@ -308,22 +308,22 @@ const generateShippingLabelHTML = async (fulfillmentData, barcodeUrl = null) =>
Sub Total
$${orderTotals.subTotal ? orderTotals.subTotal.toFixed(2) : '0.00'}
- ${orderTotals.tax && orderTotals.tax > 0 ? `
Tax${orderTotals.taxRate ? ` (${orderTotals.taxRate}%)` : ''}
-
$${orderTotals.tax.toFixed(2)}
+
$${parseFloat(orderTotals.tax || 0).toFixed(2)}
- ` : ''} - ${orderTotals.shipping && orderTotals.shipping > 0 ? `
Shipping
-
$${orderTotals.shipping.toFixed(2)}
+
$${parseFloat(orderTotals.shipping || 0).toFixed(2)}
+
+
+
Discount
+
-$${parseFloat(orderTotals.discount || 0).toFixed(2)}
- ` : ''}
TOTAL
-
$${orderTotals.grandTotal ? orderTotals.grandTotal.toFixed(2) : '0.00'}
+
$${orderTotals.total ? orderTotals.total.toFixed(2) : '0.00'}