shippinh rates
This commit is contained in:
parent
ccf11a4b64
commit
57c5b6f864
6 changed files with 289 additions and 99 deletions
|
|
@ -560,7 +560,7 @@ module.exports = (pool, query, authMiddleware) => {
|
||||||
|
|
||||||
// Get cart items
|
// Get cart items
|
||||||
const cartItemsResult = await query(
|
const cartItemsResult = await query(
|
||||||
`SELECT ci.*, p.price, p.name, p.description, p.weight_grams,
|
`SELECT ci.*, p.price, p.name, p.description, p.weight_grams, p.length_cm, p.width_cm, p.height_cm,
|
||||||
(
|
(
|
||||||
SELECT json_build_object(
|
SELECT json_build_object(
|
||||||
'path', pi.image_path,
|
'path', pi.image_path,
|
||||||
|
|
@ -588,15 +588,55 @@ module.exports = (pool, query, authMiddleware) => {
|
||||||
return sum + (parseFloat(item.price) * item.quantity);
|
return sum + (parseFloat(item.price) * item.quantity);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// Determine shipping cost
|
// Determine shipping cost and create shipment if needed
|
||||||
let shippingCost = 0;
|
let shippingCost = 0;
|
||||||
|
let shipmentData = null;
|
||||||
|
|
||||||
if (config.shipping.enabled) {
|
if (config.shipping.enabled) {
|
||||||
// If a specific shipping method was selected
|
// If a specific shipping method was selected
|
||||||
if (shippingMethod && shippingMethod.id) {
|
if (shippingMethod && shippingMethod.id) {
|
||||||
shippingCost = parseFloat(shippingMethod.rate) || 0;
|
// Parse shipping address to object if it's a string
|
||||||
|
const parsedAddress = typeof shippingAddress === 'string'
|
||||||
|
? shippingService.parseAddressString(shippingAddress)
|
||||||
|
: shippingAddress;
|
||||||
|
|
||||||
|
// Calculate total weight
|
||||||
|
const totalWeight = shippingService.calculateTotalWeight(cartItemsResult.rows);
|
||||||
|
|
||||||
|
// Create an actual shipment on EasyPost if a real rate was selected (not flat/free)
|
||||||
|
if (config.shipping.easypostEnabled &&
|
||||||
|
!shippingMethod.id.includes('flat-rate') &&
|
||||||
|
!shippingMethod.id.includes('free-shipping')) {
|
||||||
|
try {
|
||||||
|
// Create parcel details
|
||||||
|
const parcelDetails = {
|
||||||
|
weight: totalWeight,
|
||||||
|
order_total: subtotal
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create shipment with the selected rate
|
||||||
|
shipmentData = await shippingService.createShipment(
|
||||||
|
null, // Use default origin
|
||||||
|
parsedAddress,
|
||||||
|
parcelDetails,
|
||||||
|
shippingMethod.id
|
||||||
|
);
|
||||||
|
|
||||||
|
// Use the actual rate from the created shipment
|
||||||
|
shippingCost = shipmentData.selected_rate.rate;
|
||||||
|
|
||||||
|
console.log('Shipment created successfully:', shipmentData.shipment_id);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating shipment:', error);
|
||||||
|
// Fallback to the rate provided
|
||||||
|
shippingCost = parseFloat(shippingMethod.rate) || 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Use the rate provided for flat rate or free shipping
|
||||||
|
shippingCost = parseFloat(shippingMethod.rate) || 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Default to flat rate
|
// Default to flat rate if no method selected
|
||||||
const shippingRates = await shippingService.getFlatRateShipping(subtotal);
|
const shippingRates = await shippingService.getFlatRateShipping(subtotal);
|
||||||
shippingCost = shippingRates[0].rate;
|
shippingCost = shippingRates[0].rate;
|
||||||
}
|
}
|
||||||
|
|
@ -628,12 +668,13 @@ module.exports = (pool, query, authMiddleware) => {
|
||||||
|
|
||||||
// If a shipping method was selected, save it with the order
|
// If a shipping method was selected, save it with the order
|
||||||
if (shippingMethod && shippingMethod.id) {
|
if (shippingMethod && shippingMethod.id) {
|
||||||
const shippingInfo = {
|
const shippingInfo = shipmentData || {
|
||||||
method_id: shippingMethod.id,
|
method_id: shippingMethod.id,
|
||||||
carrier: shippingMethod.carrier,
|
carrier: shippingMethod.carrier,
|
||||||
service: shippingMethod.service,
|
service: shippingMethod.service,
|
||||||
rate: shippingMethod.rate,
|
rate: shippingMethod.rate,
|
||||||
estimated_days: shippingMethod.delivery_days
|
estimated_days: shippingMethod.delivery_days,
|
||||||
|
tracking_code: null
|
||||||
};
|
};
|
||||||
|
|
||||||
await client.query(
|
await client.query(
|
||||||
|
|
@ -652,7 +693,8 @@ module.exports = (pool, query, authMiddleware) => {
|
||||||
cartItems: cartItemsResult.rows,
|
cartItems: cartItemsResult.rows,
|
||||||
subtotal,
|
subtotal,
|
||||||
shippingCost,
|
shippingCost,
|
||||||
total
|
total,
|
||||||
|
shipmentData
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note: We don't clear the cart here now - we'll do that after successful payment
|
// Note: We don't clear the cart here now - we'll do that after successful payment
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ module.exports = (pool, query, authMiddleware) => {
|
||||||
// Create checkout session
|
// Create checkout session
|
||||||
router.post('/create-checkout-session', async (req, res, next) => {
|
router.post('/create-checkout-session', async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const { cartItems, shippingAddress, userId, orderId } = req.body;
|
const { cartItems, shippingAddress, userId, orderId, shippingDetails } = req.body;
|
||||||
|
|
||||||
if (!cartItems || cartItems.length === 0) {
|
if (!cartItems || cartItems.length === 0) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
|
|
@ -123,6 +123,12 @@ module.exports = (pool, query, authMiddleware) => {
|
||||||
shipping_address: JSON.stringify(shippingAddress),
|
shipping_address: JSON.stringify(shippingAddress),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add tracking information to metadata if available
|
||||||
|
if (shippingDetails && shippingDetails.tracking_code) {
|
||||||
|
metadata.tracking_code = shippingDetails.tracking_code;
|
||||||
|
metadata.shipping_carrier = shippingDetails.shipping_method || 'Standard Shipping';
|
||||||
|
}
|
||||||
|
|
||||||
// Create Stripe checkout session
|
// Create Stripe checkout session
|
||||||
const session = await stripeClient.checkout.sessions.create({
|
const session = await stripeClient.checkout.sessions.create({
|
||||||
payment_method_types: ['card'],
|
payment_method_types: ['card'],
|
||||||
|
|
@ -131,22 +137,21 @@ module.exports = (pool, query, authMiddleware) => {
|
||||||
success_url: `${config.site.protocol}://${config.site.domain}/checkout/success?session_id={CHECKOUT_SESSION_ID}`,
|
success_url: `${config.site.protocol}://${config.site.domain}/checkout/success?session_id={CHECKOUT_SESSION_ID}`,
|
||||||
cancel_url: `${config.site.protocol}://${config.site.domain}/checkout/cancel`,
|
cancel_url: `${config.site.protocol}://${config.site.domain}/checkout/cancel`,
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
shipping_address_collection: {
|
|
||||||
allowed_countries: ['US', 'CA'],
|
|
||||||
},
|
|
||||||
shipping_options: [
|
shipping_options: [
|
||||||
{
|
{
|
||||||
shipping_rate_data: {
|
shipping_rate_data: {
|
||||||
type: 'fixed_amount',
|
type: 'fixed_amount',
|
||||||
fixed_amount: {
|
fixed_amount: {
|
||||||
amount: 0,
|
amount: shippingDetails && shippingDetails.shipping_cost ?
|
||||||
|
Math.round(parseFloat(shippingDetails.shipping_cost) * 100) : 0,
|
||||||
currency: 'usd',
|
currency: 'usd',
|
||||||
},
|
},
|
||||||
display_name: 'Free shipping',
|
display_name: shippingDetails && shippingDetails.shipping_method ?
|
||||||
|
shippingDetails.shipping_method : 'Standard Shipping',
|
||||||
delivery_estimate: {
|
delivery_estimate: {
|
||||||
minimum: {
|
minimum: {
|
||||||
unit: 'business_day',
|
unit: 'business_day',
|
||||||
value: 5,
|
value: 2,
|
||||||
},
|
},
|
||||||
maximum: {
|
maximum: {
|
||||||
unit: 'business_day',
|
unit: 'business_day',
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,134 @@ const shippingService = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an actual shipment in EasyPost based on selected rate
|
||||||
|
* @param {Object} addressFrom - Shipping origin address
|
||||||
|
* @param {Object} addressTo - Customer shipping address
|
||||||
|
* @param {Object} parcelDetails - Package dimensions and weight
|
||||||
|
* @param {string} selectedRateId - The ID of the selected rate
|
||||||
|
* @returns {Promise<Object>} Created shipment details
|
||||||
|
*/
|
||||||
|
async createShipment(addressFrom, addressTo, parcelDetails, selectedRateId) {
|
||||||
|
// If EasyPost is not enabled, return a simulated shipment
|
||||||
|
if (!config.shipping.easypostEnabled || !config.shipping.easypostApiKey) {
|
||||||
|
console.log("EasyPost not configured for shipment creation");
|
||||||
|
return this.createSimulatedShipment(selectedRateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Format addresses for EasyPost
|
||||||
|
const fromAddress = this.formatAddress(addressFrom || config.shipping.originAddress);
|
||||||
|
const toAddress = this.formatAddress(addressTo);
|
||||||
|
|
||||||
|
// Format parcel for EasyPost
|
||||||
|
const parcel = this.formatParcel(parcelDetails);
|
||||||
|
|
||||||
|
// Step 1: Create a shipment
|
||||||
|
const shipmentResponse = await axios.post(
|
||||||
|
'https://api.easypost.com/v2/shipments',
|
||||||
|
{
|
||||||
|
shipment: {
|
||||||
|
from_address: fromAddress,
|
||||||
|
to_address: toAddress,
|
||||||
|
parcel: parcel,
|
||||||
|
options: {
|
||||||
|
label_format: 'PDF',
|
||||||
|
label_size: '4x6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
auth: {
|
||||||
|
username: config.shipping.easypostApiKey,
|
||||||
|
password: ''
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const shipment = shipmentResponse.data;
|
||||||
|
console.log("Shipment created successfully:", shipment.id);
|
||||||
|
|
||||||
|
// Step 2: Buy the selected rate
|
||||||
|
const buyResponse = await axios.post(
|
||||||
|
`https://api.easypost.com/v2/shipments/${shipment.id}/buy`,
|
||||||
|
{
|
||||||
|
rate: {
|
||||||
|
id: selectedRateId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
auth: {
|
||||||
|
username: config.shipping.easypostApiKey,
|
||||||
|
password: ''
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const purchasedShipment = buyResponse.data;
|
||||||
|
console.log("Rate purchased successfully:", purchasedShipment.id);
|
||||||
|
|
||||||
|
// Return the important details
|
||||||
|
return {
|
||||||
|
shipment_id: purchasedShipment.id,
|
||||||
|
tracking_code: purchasedShipment.tracking_code,
|
||||||
|
label_url: purchasedShipment.postage_label.label_url,
|
||||||
|
selected_rate: {
|
||||||
|
id: purchasedShipment.selected_rate.id,
|
||||||
|
carrier: purchasedShipment.selected_rate.carrier,
|
||||||
|
service: purchasedShipment.selected_rate.service,
|
||||||
|
rate: parseFloat(purchasedShipment.selected_rate.rate),
|
||||||
|
delivery_days: purchasedShipment.selected_rate.delivery_days || 'Unknown',
|
||||||
|
delivery_date: purchasedShipment.selected_rate.delivery_date || null
|
||||||
|
},
|
||||||
|
carrier: purchasedShipment.selected_rate.carrier,
|
||||||
|
service: purchasedShipment.selected_rate.service,
|
||||||
|
created_at: purchasedShipment.created_at,
|
||||||
|
status: purchasedShipment.status
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('EasyPost API error during shipment creation:', error.response?.data || error.message);
|
||||||
|
|
||||||
|
// Return a fallback simulated shipment
|
||||||
|
return this.createSimulatedShipment(selectedRateId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a simulated shipment when EasyPost is not available
|
||||||
|
* @param {string} selectedRateId - The ID of the selected rate
|
||||||
|
* @returns {Object} Simulated shipment details
|
||||||
|
*/
|
||||||
|
createSimulatedShipment(selectedRateId) {
|
||||||
|
// Generate a random tracking number
|
||||||
|
const trackingNumber = `SIMSHIP${Math.floor(Math.random() * 1000000000)}`;
|
||||||
|
|
||||||
|
// Return a simulated shipment
|
||||||
|
return {
|
||||||
|
shipment_id: `sim_${Date.now()}`,
|
||||||
|
tracking_code: trackingNumber,
|
||||||
|
label_url: null,
|
||||||
|
selected_rate: {
|
||||||
|
id: selectedRateId,
|
||||||
|
carrier: selectedRateId.includes('flat') ? 'Standard' : 'Simulated',
|
||||||
|
service: selectedRateId.includes('flat') ? 'Flat Rate Shipping' : 'Standard Service',
|
||||||
|
rate: selectedRateId.includes('free') ? 0 : config.shipping.flatRate,
|
||||||
|
delivery_days: '5-7',
|
||||||
|
delivery_date: null
|
||||||
|
},
|
||||||
|
carrier: selectedRateId.includes('flat') ? 'Standard' : 'Simulated',
|
||||||
|
service: selectedRateId.includes('flat') ? 'Flat Rate Shipping' : 'Standard Service',
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
status: 'simulated'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format address for EasyPost API
|
* Format address for EasyPost API
|
||||||
* @param {Object} address - Address details
|
* @param {Object} address - Address details
|
||||||
|
|
@ -142,19 +270,19 @@ const shippingService = {
|
||||||
delivery_time: rate.est_delivery_time || null
|
delivery_time: rate.est_delivery_time || null
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Check if free shipping applies
|
// // Check if free shipping applies
|
||||||
if (orderTotal >= config.shipping.freeThreshold) {
|
// if (orderTotal >= config.shipping.freeThreshold) {
|
||||||
formattedRates.push({
|
// formattedRates.push({
|
||||||
id: 'free-shipping',
|
// id: 'free-shipping',
|
||||||
carrier: 'FREE',
|
// carrier: 'FREE',
|
||||||
service: 'Standard Shipping',
|
// service: 'Standard Shipping',
|
||||||
rate: 0,
|
// rate: 0,
|
||||||
currency: 'USD',
|
// currency: 'USD',
|
||||||
delivery_days: '5-7',
|
// delivery_days: '5-7',
|
||||||
delivery_date: null,
|
// delivery_date: null,
|
||||||
delivery_time: null
|
// delivery_time: null
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return formattedRates;
|
return formattedRates;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,42 @@
|
||||||
Rocks/
|
ROCKS/
|
||||||
|
├── backend/
|
||||||
|
│ ├── src/
|
||||||
|
│ │ ├── services/
|
||||||
|
│ │ │ ├── shippingService.js
|
||||||
|
│ │ ├── routes/
|
||||||
|
│ │ │ ├── shipping.js
|
||||||
|
│ │ │ ├── settingsAdmin.js
|
||||||
|
│ │ │ ├── cart.js
|
||||||
|
│ │ │ ├── userOrders.js
|
||||||
|
│ │ │ ├── orderAdmin.js
|
||||||
|
│ │ │ ├── stripePayment.js
|
||||||
|
│ │ │ ├── auth.js
|
||||||
|
│ │ │ ├── userAdmin.js
|
||||||
|
│ │ │ ├── products.js
|
||||||
|
│ │ │ ├── categoryAdmin.js
|
||||||
|
│ │ │ ├── productAdminImages.js
|
||||||
|
│ │ │ ├── images.js
|
||||||
|
│ │ │ └── productAdmin.js
|
||||||
|
│ │ ├── models/
|
||||||
|
│ │ │ └── SystemSettings.js
|
||||||
|
│ │ ├── middleware/
|
||||||
|
│ │ │ ├── upload.js
|
||||||
|
│ │ │ ├── auth.js
|
||||||
|
│ │ │ └── adminAuth.js
|
||||||
|
│ │ └── db/
|
||||||
|
│ │ └── index.js
|
||||||
|
│ ├── index.js
|
||||||
|
│ ├── config.js
|
||||||
|
│ ├── node_modules/
|
||||||
|
│ ├── public/
|
||||||
|
│ │ └── uploads/
|
||||||
|
│ │ └── products/
|
||||||
|
│ ├── package.json
|
||||||
|
│ ├── package-lock.json
|
||||||
|
│ ├── .env
|
||||||
|
│ ├── Dockerfile
|
||||||
|
│ ├── README.md
|
||||||
|
│ └── .gitignore
|
||||||
├── frontend/
|
├── frontend/
|
||||||
│ ├── node_modules/
|
│ ├── node_modules/
|
||||||
│ ├── src/
|
│ ├── src/
|
||||||
|
|
@ -11,8 +49,8 @@ Rocks/
|
||||||
│ │ │ │ ├── DashboardPage.jsx
|
│ │ │ │ ├── DashboardPage.jsx
|
||||||
│ │ │ │ ├── CategoriesPage.jsx
|
│ │ │ │ ├── CategoriesPage.jsx
|
||||||
│ │ │ │ └── ProductsPage.jsx
|
│ │ │ │ └── ProductsPage.jsx
|
||||||
│ │ │ ├── PaymentSuccessPage.jsx
|
|
||||||
│ │ │ ├── CheckoutPage.jsx
|
│ │ │ ├── CheckoutPage.jsx
|
||||||
|
│ │ │ ├── PaymentSuccessPage.jsx
|
||||||
│ │ │ ├── UserOrdersPage.jsx
|
│ │ │ ├── UserOrdersPage.jsx
|
||||||
│ │ │ ├── PaymentCancelPage.jsx
|
│ │ │ ├── PaymentCancelPage.jsx
|
||||||
│ │ │ ├── ProductDetailPage.jsx
|
│ │ │ ├── ProductDetailPage.jsx
|
||||||
|
|
@ -23,6 +61,15 @@ Rocks/
|
||||||
│ │ │ ├── RegisterPage.jsx
|
│ │ │ ├── RegisterPage.jsx
|
||||||
│ │ │ ├── NotFoundPage.jsx
|
│ │ │ ├── NotFoundPage.jsx
|
||||||
│ │ │ └── LoginPage.jsx
|
│ │ │ └── LoginPage.jsx
|
||||||
|
│ │ ├── services/
|
||||||
|
│ │ │ ├── adminService.js
|
||||||
|
│ │ │ ├── authService.js
|
||||||
|
│ │ │ ├── settingsAdminService.js
|
||||||
|
│ │ │ ├── cartService.js
|
||||||
|
│ │ │ ├── categoryAdminService.js
|
||||||
|
│ │ │ ├── imageService.js
|
||||||
|
│ │ │ ├── productService.js
|
||||||
|
│ │ │ └── api.js
|
||||||
│ │ ├── components/
|
│ │ ├── components/
|
||||||
│ │ │ ├── OrderStatusDialog.jsx
|
│ │ │ ├── OrderStatusDialog.jsx
|
||||||
│ │ │ ├── StripePaymentForm.jsx
|
│ │ │ ├── StripePaymentForm.jsx
|
||||||
|
|
@ -40,15 +87,6 @@ Rocks/
|
||||||
│ │ │ ├── reduxHooks.js
|
│ │ │ ├── reduxHooks.js
|
||||||
│ │ │ ├── settingsAdminHooks.js
|
│ │ │ ├── settingsAdminHooks.js
|
||||||
│ │ │ └── categoryAdminHooks.js
|
│ │ │ └── categoryAdminHooks.js
|
||||||
│ │ ├── services/
|
|
||||||
│ │ │ ├── adminService.js
|
|
||||||
│ │ │ ├── authService.js
|
|
||||||
│ │ │ ├── settingsAdminService.js
|
|
||||||
│ │ │ ├── cartService.js
|
|
||||||
│ │ │ ├── categoryAdminService.js
|
|
||||||
│ │ │ ├── imageService.js
|
|
||||||
│ │ │ ├── productService.js
|
|
||||||
│ │ │ └── api.js
|
|
||||||
│ │ ├── utils/
|
│ │ ├── utils/
|
||||||
│ │ │ └── imageUtils.js
|
│ │ │ └── imageUtils.js
|
||||||
│ │ ├── layouts/
|
│ │ ├── layouts/
|
||||||
|
|
@ -71,65 +109,31 @@ Rocks/
|
||||||
│ │ ├── App.jsx
|
│ │ ├── App.jsx
|
||||||
│ │ ├── config.js
|
│ │ ├── config.js
|
||||||
│ │ └── main.jsx
|
│ │ └── main.jsx
|
||||||
│ └── public/
|
|
||||||
│ ├── favicon.svg
|
|
||||||
│ ├── package-lock.json
|
|
||||||
│ ├── package.json
|
|
||||||
│ ├── vite.config.js
|
|
||||||
│ ├── Dockerfile
|
|
||||||
│ ├── nginx.conf
|
|
||||||
│ ├── index.html
|
|
||||||
│ ├── README.md
|
|
||||||
│ ├── .env
|
|
||||||
│ └── setup-frontend.sh
|
|
||||||
├── backend/
|
|
||||||
│ ├── src/
|
|
||||||
│ │ ├── routes/
|
|
||||||
│ │ │ ├── userOrders.js
|
|
||||||
│ │ │ ├── orderAdmin.js
|
|
||||||
│ │ │ ├── stripePayment.js
|
|
||||||
│ │ │ ├── cart.js
|
|
||||||
│ │ │ ├── auth.js
|
|
||||||
│ │ │ ├── userAdmin.js
|
|
||||||
│ │ │ ├── settingsAdmin.js
|
|
||||||
│ │ │ ├── products.js
|
|
||||||
│ │ │ ├── categoryAdmin.js
|
|
||||||
│ │ │ ├── productAdminImages.js
|
|
||||||
│ │ │ ├── images.js
|
|
||||||
│ │ │ └── productAdmin.js
|
|
||||||
│ │ ├── models/
|
|
||||||
│ │ │ └── SystemSettings.js
|
|
||||||
│ │ ├── middleware/
|
|
||||||
│ │ │ ├── upload.js
|
|
||||||
│ │ │ ├── auth.js
|
|
||||||
│ │ │ └── adminAuth.js
|
|
||||||
│ │ ├── db/
|
|
||||||
│ │ │ └── index.js
|
|
||||||
│ │ ├── index.js
|
|
||||||
│ │ └── config.js
|
|
||||||
│ ├── public/
|
│ ├── public/
|
||||||
│ │ └── uploads/
|
│ │ ├── favicon.svg
|
||||||
│ │ └── products/
|
│ │ └── index.html
|
||||||
│ ├── node_modules/
|
│ ├── package-lock.json
|
||||||
│ ├── .env
|
|
||||||
│ ├── package.json
|
│ ├── package.json
|
||||||
|
│ ├── vite.config.js
|
||||||
│ ├── Dockerfile
|
│ ├── Dockerfile
|
||||||
|
│ ├── nginx.conf
|
||||||
│ ├── README.md
|
│ ├── README.md
|
||||||
│ └── .gitignore
|
│ ├── .env
|
||||||
|
│ └── setup-frontend.sh
|
||||||
├── db/
|
├── db/
|
||||||
│ ├── init/
|
│ └── init/
|
||||||
│ │ ├── 01-schema.sql
|
│ ├── 12-shipping-orders.sql
|
||||||
│ │ ├── 02-seed.sql
|
│ ├── 09-system-settings.sql
|
||||||
│ │ ├── 03-api-key.sql
|
│ ├── 11-notifications.sql
|
||||||
│ │ ├── 04-product-images.sql
|
│ ├── 10-payment.sql
|
||||||
│ │ ├── 05-admin-role.sql
|
│ ├── 08-create-email.sql
|
||||||
│ │ ├── 06-product-categories.sql
|
│ ├── 07-user-keys.sql
|
||||||
│ │ ├── 07-user-keys.sql
|
│ ├── 06-product-categories.sql
|
||||||
│ │ ├── 08-create-email.sql
|
│ ├── 05-admin-role.sql
|
||||||
│ │ ├── 09-system-settings.sql
|
│ ├── 02-seed.sql
|
||||||
│ │ ├── 10-payment.sql
|
│ ├── 04-product-images.sql
|
||||||
│ │ └── 11-notifications.sql
|
│ ├── 03-api-key.sql
|
||||||
│ └── .gitignore
|
│ └── 01-schema.sql
|
||||||
├── test/
|
├── test/
|
||||||
├── fileStructure.txt
|
├── fileStructure.txt
|
||||||
├── docker-compose.yml
|
├── docker-compose.yml
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,14 @@ export const StripeProvider = ({ children }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a checkout session
|
// Create a checkout session
|
||||||
const createCheckoutSession = async (cartItems, orderId, shippingAddress, userId) => {
|
const createCheckoutSession = async (cartItems, orderId, shippingAddress, userId, shippingDetails = null) => {
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.post('/payment/create-checkout-session', {
|
const response = await apiClient.post('/payment/create-checkout-session', {
|
||||||
cartItems,
|
cartItems,
|
||||||
orderId,
|
orderId,
|
||||||
shippingAddress,
|
shippingAddress,
|
||||||
userId
|
userId,
|
||||||
|
shippingDetails
|
||||||
});
|
});
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,19 @@ const CheckoutPage = () => {
|
||||||
// Store the order ID for later use
|
// Store the order ID for later use
|
||||||
setOrderId(orderResponse.orderId);
|
setOrderId(orderResponse.orderId);
|
||||||
|
|
||||||
|
// Use the shipping data from the response if available
|
||||||
|
const shippingDetails = orderResponse.shipmentData ? {
|
||||||
|
shipping_cost: orderResponse.shippingCost,
|
||||||
|
shipping_method: `${orderResponse.shipmentData.carrier} - ${orderResponse.shipmentData.service}`,
|
||||||
|
tracking_code: orderResponse.shipmentData.tracking_code,
|
||||||
|
label_url: orderResponse.shipmentData.label_url
|
||||||
|
} : {
|
||||||
|
shipping_cost: orderResponse.shippingCost,
|
||||||
|
shipping_method: selectedShippingMethod ?
|
||||||
|
`${selectedShippingMethod.carrier} - ${selectedShippingMethod.service}` :
|
||||||
|
'Standard Shipping'
|
||||||
|
};
|
||||||
|
|
||||||
// Proceed to payment step
|
// Proceed to payment step
|
||||||
setActiveStep(3);
|
setActiveStep(3);
|
||||||
|
|
||||||
|
|
@ -229,10 +242,7 @@ const CheckoutPage = () => {
|
||||||
orderResponse.orderId,
|
orderResponse.orderId,
|
||||||
shippingAddress,
|
shippingAddress,
|
||||||
user,
|
user,
|
||||||
{
|
shippingDetails
|
||||||
shipping_cost: orderResponse.shippingCost || shippingCost,
|
|
||||||
shipping_method: selectedShippingMethod ? selectedShippingMethod.carrier + ' - ' + selectedShippingMethod.service : 'Standard Shipping'
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Redirect to Stripe Checkout
|
// Redirect to Stripe Checkout
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue