From b9b1f74a3691e5c6e378ae7ce741399a02acd713 Mon Sep 17 00:00:00 2001 From: Alaguraj0361 Date: Tue, 19 May 2026 17:49:11 +0530 Subject: [PATCH] add /create-order endpoint with CORS support and test script --- package-lock.json | 27 ++++++++++++++++ package.json | 1 + server.js | 79 +++++++++++++++++++++++++++++++++++++++++++++++ test-order.js | 22 +++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 test-order.js diff --git a/package-lock.json b/package-lock.json index 7bbe1f8..236c78b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "cors": "^2.8.6", "crypto": "^1.0.1", "dotenv": "^17.4.2", "express": "^5.2.1", @@ -211,6 +212,23 @@ "node": ">=6.6.0" } }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/crypto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", @@ -684,6 +702,15 @@ "node": ">=6.0.0" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", diff --git a/package.json b/package.json index ca16b08..52aac85 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "license": "ISC", "description": "", "dependencies": { + "cors": "^2.8.6", "crypto": "^1.0.1", "dotenv": "^17.4.2", "express": "^5.2.1", diff --git a/server.js b/server.js index 434d1c9..6f3b358 100644 --- a/server.js +++ b/server.js @@ -1,10 +1,12 @@ require('dotenv').config({ override: true }); const express = require('express'); +const cors = require('cors'); const crypto = require('crypto'); const { generateInvoicePDF } = require('./pdfGenerator'); const { sendEmailWithAttachment } = require('./mailer'); const app = express(); +app.use(cors()); // Allow frontend Shopify store to call this server const PORT = process.env.PORT || 3000; // Middleware to capture raw body for Shopify webhook HMAC verification @@ -80,3 +82,80 @@ app.post('/webhooks/orders/create', verifyShopifyWebhook, async (req, res) => { app.listen(PORT, () => { console.log(`Shopify Invoice Email Plugin running on port ${PORT}`); }); + +// Endpoint to create order from custom checkout frontend +app.post('/create-order', async (req, res) => { + try { + const { customerData, cartItems } = req.body; + + const line_items = cartItems.map(item => ({ + variant_id: item.variant_id || item.id, + quantity: item.quantity, + price: (item.price / 100).toFixed(2) + })); + + const orderPayload = { + order: { + line_items: line_items, + customer: { + first_name: customerData.first_name, + last_name: customerData.last_name, + email: customerData.email, + phone: customerData.phone + }, + billing_address: { + first_name: customerData.first_name, + last_name: customerData.last_name, + address1: customerData.address1, + address2: customerData.address2, + city: customerData.city, + province: customerData.province, + zip: customerData.zip, + country: "India", + phone: customerData.phone + }, + shipping_address: { + first_name: customerData.first_name, + last_name: customerData.last_name, + address1: customerData.address1, + address2: customerData.address2, + city: customerData.city, + province: customerData.province, + zip: customerData.zip, + country: "India", + phone: customerData.phone + }, + email: customerData.email, + tags: "custom_checkout", + financial_status: "pending", // Payment to be done on WhatsApp + shipping_lines: [ + { + title: customerData.courier || "Standard Courier", + price: "0.00" // Update this if shipping has logic + } + ] + } + }; + + const shopifyResponse = await fetch(`https://${process.env.SHOPIFY_STORE_DOMAIN}/admin/api/2024-01/orders.json`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Shopify-Access-Token': process.env.SHOPIFY_ADMIN_API_TOKEN + }, + body: JSON.stringify(orderPayload) + }); + + const data = await shopifyResponse.json(); + + if (!shopifyResponse.ok) { + console.error("Shopify Order Creation Failed:", JSON.stringify(data, null, 2)); + return res.status(400).json({ error: 'Failed to create order', details: data }); + } + + res.status(200).json({ success: true, order: data.order }); + } catch (error) { + console.error("Error creating order:", error); + res.status(500).json({ error: 'Internal Server Error' }); + } +}); diff --git a/test-order.js b/test-order.js new file mode 100644 index 0000000..1884609 --- /dev/null +++ b/test-order.js @@ -0,0 +1,22 @@ +const data = { + customerData: { + first_name: 'Test', + last_name: 'User', + email: 'test@example.com', + address1: '123 Test St', + city: 'Test City', + province: 'Tamil Nadu', + zip: '12345', + phone: '1234567890' + }, + cartItems: [{ variant_id: 123456, quantity: 1 }] +}; + +fetch('http://localhost:3000/create-order', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data) +}) +.then(r => r.json()) +.then(console.log) +.catch(console.error);