Feature: Add WhatsApp notifications for collection-ready orders
- Implement WhatsApp Business API integration via Meta Cloud API - Add phoneNumber field to Order model for storing customer phone numbers - Update admin order detail page with phone number input for collection orders - Send WhatsApp notification when admin marks order as ready for collection - Add WhatsApp service module with phone number formatting and message sending - Create database migrations for collection-related fields - Add WhatsApp credentials to .env configuration Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
a105fdf660
commit
36cc6dddff
@@ -56,11 +56,34 @@ export async function POST(req: Request) {
|
||||
cleanupPendingOrders().catch((err) => console.error('Cleanup error:', err));
|
||||
|
||||
const body = await req.json();
|
||||
console.log('Checkout request received with items:', body.items?.length, 'customerId:', body.customerId);
|
||||
console.log('Checkout request received with items:', body.items?.length, 'customerId:', body.customerId, 'isCollection:', body.isCollection);
|
||||
const items: CheckoutCartItem[] = body.items ?? [];
|
||||
const guest: GuestInfo | undefined = body.guest;
|
||||
const shippingCountry: string = body.shippingCountry ?? 'GB';
|
||||
const shippingService: string | undefined = body.shippingService;
|
||||
const isCollection: boolean = body.isCollection ?? false;
|
||||
const customer = await getCurrentCustomer();
|
||||
const checkoutEmail = guest?.email ?? customer?.email;
|
||||
|
||||
// Delete any other recent PENDING orders for this email to avoid duplicates
|
||||
if (checkoutEmail) {
|
||||
try {
|
||||
const deletedCount = await prisma.order.deleteMany({
|
||||
where: {
|
||||
email: checkoutEmail,
|
||||
status: 'PENDING',
|
||||
createdAt: {
|
||||
gte: new Date(Date.now() - 2 * 60 * 60 * 1000), // Within last 2 hours
|
||||
},
|
||||
},
|
||||
});
|
||||
if (deletedCount.count > 0) {
|
||||
console.log(`Cleaned up ${deletedCount.count} duplicate pending order(s) for ${checkoutEmail}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error deleting duplicate pending orders:', err);
|
||||
}
|
||||
}
|
||||
|
||||
if (items.length === 0) {
|
||||
return NextResponse.json({ error: 'Your bag is empty.' }, { status: 400 });
|
||||
@@ -95,11 +118,15 @@ export async function POST(req: Request) {
|
||||
|
||||
const subtotal = pricedItems.reduce((sum, i) => sum + i.unitPrice * i.quantity, 0);
|
||||
|
||||
// Calculate shipping cost
|
||||
// Calculate shipping cost (skip for collection orders)
|
||||
let shippingCost = 0;
|
||||
let selectedShippingService = shippingService;
|
||||
|
||||
try {
|
||||
if (isCollection) {
|
||||
console.log('Collection order - no shipping cost');
|
||||
selectedShippingService = null;
|
||||
} else {
|
||||
try {
|
||||
// Calculate total weight from cart items
|
||||
let totalWeightGrams = 0;
|
||||
for (const item of items) {
|
||||
@@ -138,9 +165,9 @@ export async function POST(req: Request) {
|
||||
// Default shipping cost if calculation fails
|
||||
shippingCost = 500; // £5.00
|
||||
}
|
||||
}
|
||||
|
||||
const total = subtotal + shippingCost;
|
||||
const customer = await getCurrentCustomer();
|
||||
|
||||
// Save the order up front, before redirecting to Stripe — this is what makes
|
||||
// the design files (and the order itself) retrievable afterward, whether or
|
||||
@@ -156,6 +183,7 @@ export async function POST(req: Request) {
|
||||
email: guest?.email ?? customer?.email,
|
||||
guestName: guest?.name,
|
||||
guestPhone: guest?.phone,
|
||||
isCollectionPickup,
|
||||
items: {
|
||||
create: pricedItems.map((i) => ({
|
||||
productId: i.productId,
|
||||
|
||||
Reference in New Issue
Block a user