export default function usePlaceOrder({ activeCart, activeCartItems, orderInfo, fullAddress, subtotal, total, getCarts, onSuccess, }) { const { $dayjs, $id, $getdata, $insertapi, $patchapi, $deleteapi, $snackbar } = useNuxtApp(); const isPending = ref(false); const paidPaymentStatus = ref(); const invoice = ref(); const invoice_details = ref(); const payment_record = ref(); const showVietQRModal = ref(); /** * Create a record in `invoice` as `pending` */ async function createOrder() { try { isPending.value = true; const invoicePayload = { customer: activeCart.value.customer, customer_name: activeCart.value.customer__fullname, customer_phone: activeCart.value.customer__phone, customer_email: activeCart.value.customer__email, shipping_address: fullAddress.value, product_amount: activeCartItems.value.length, shipping_fee: orderInfo.value.shipping_fee, total_amount: subtotal.value, discount_amount: 0, final_amount: total.value, order_type: "pos", status: "pending", payment_status: 1, staff: 1, ordered_at: new Date(), paid_at: null, delivery_method: orderInfo.value.deliveryMethod.id, }; const invoiceRecord = await $insertapi("Invoice", { data: invoicePayload, notify: false, }); invoice.value = invoiceRecord; return invoiceRecord; } catch (error) { console.error(error); $snackbar("Tạo đơn hàng không thành công", "Error"); } finally { isPending.value = false; } } async function printReceipt() { return await $fetch("/api/print/receipt", { method: "POST", body: { invoice: invoice.value, invoice_details: invoice_details.value, payment_record: payment_record.value, }, }); } /** * Prints receipt, displays snackbar, resets cart, closes modal */ async function onOrderSuccess() { $snackbar("Khởi tạo đơn hàng thành công", "Success"); printReceipt(); resetCart(); onSuccess(); } /** * Mark sold IMEIs, create invoice details, delivery info, payment records, reset cart. * Runs when order payment is confirmed. * @param invoiceId id of created invoice */ async function finalizeOrder(invoiceId) { if (!invoiceId) { console.error("invoiceId is required"); return; } const imeisSold = await markImeisSold(); invoice_details.value = await createInvoiceDetails(invoiceId, imeisSold); await createPaymentRecord(invoiceId); if (orderInfo.value.deliveryMethod.code === "HOME_DELIVERY") { await createDeliveryInfo(invoiceId); } // update invoice.payment_status from PENDING to PAID await $patchapi("Invoice", { id: invoiceId, payment_status: paidPaymentStatus.value.id }); await onOrderSuccess(); } async function markImeisSold() { const imeisSoldPayload = activeCartItems.value.map((cartItem) => ({ imei: cartItem.imei__imei, variant: cartItem.imei__variant, sold_date: $dayjs().format("YYYY-MM-DD"), })); const imeisSold = await $insertapi("IMEI_Sold", { data: imeisSoldPayload, notify: false, }); return imeisSold; } async function createInvoiceDetails(invoiceId, imeisSold) { const invoiceDetailPayload = activeCartItems.value.map((cartItem) => { const imeiSold = imeisSold.find((imeiSold) => imeiSold.imei === cartItem.imei__imei); return { invoice: invoiceId, variant: cartItem.imei__variant, imei_sold: imeiSold.id, price: cartItem.imei__variant__price, }; }); const invoiceDetails = await $insertapi("Invoice_Detail", { data: invoiceDetailPayload, notify: false, values: "id,code,invoice,variant,variant__code,variant__product,variant__product__name,variant__color,variant__color__name,variant__ram__code,variant__ram__capacity,variant__internal_storage__code,variant__internal_storage__capacity,variant__price,variant__image__path,imei_sold,price,status,note,deleted,create_time,update_time", }); return invoiceDetails; } async function createDeliveryInfo(invoiceId) { const deliveryInfoPayload = { invoice: invoiceId, receiver_name: orderInfo.value.receiver_name, receiver_phone: orderInfo.value.receiver_phone, city: orderInfo.value.address.city, district: orderInfo.value.address.district, ward: orderInfo.value.address.ward, address: orderInfo.value.address.address_detail, shipping_fee: orderInfo.value.shipping_fee, carrier: orderInfo.value.deliveryMethod.id, tracking_code: $id(), status: "pending", staff: 1, }; const deliveryInfo = await $insertapi("Delivery_Info", { data: deliveryInfoPayload, notify: false, }); return deliveryInfo; } async function createPaymentRecord(invoiceId) { const paymentRecord = await $insertapi("Payment_Record", { data: { invoice: invoiceId, payment_method: orderInfo.value.paymentMethod.id, transfer_amount: orderInfo.value.paymentMethod.code === "CASH" ? undefined : total.value, cash_amount: orderInfo.value.paymentMethod.code === "CASH" ? total.value : undefined, }, notify: false, }); payment_record.value = paymentRecord; return paymentRecord; } async function resetCart() { await Promise.all([ $deleteapi( "Cart_Item", activeCartItems.value.map((c) => c.id), ), $patchapi("Cart", { id: activeCartItems.value[0].cart, customer: null, }), ]); getCarts(); } async function placeOrder() { await createOrder(); if (orderInfo.value.paymentMethod.code === "CASH") { finalizeOrder(invoice.value.id); } else if (orderInfo.value.paymentMethod.code === "VIETQR") { showVietQRModal.value = { component: "pos/VietQR", title: "Thanh toán qua VietQR", width: "700px", vbind: { invoiceId: invoice.value.id, finalizeOrder }, // verify thủ công? }; } else if (orderInfo.value.paymentMethod.code === "VNPAY") { try { const { paymentUrl } = await $fetch("/api/vnpay/create-payment", { method: "POST", body: { amount: invoice.value.total_amount, invoiceCode: invoice.value.code, }, }); window.open(paymentUrl, "vnpaypopup", "popup=true,width=900,height=700"); listenToVnpayEvents(); } catch (error) { console.error(error); } } } function vnpayListener(e) { console.log("main window received e.data from popup", e.data); const { type, message } = e.data; if (type === "vnpay-success") { finalizeOrder(invoice.value.id); } if (type === "vnpay-error") { $snackbar(`Thanh toán VNPAY thất bại: ${message}`, "Error"); } } function listenToVnpayEvents() { window.removeEventListener("message", vnpayListener); window.addEventListener("message", vnpayListener); } function testReturnPage() { listenToVnpayEvents(); const vnp_ResponseCode = "01"; window.open( `http://localhost:3000/vnpay-return?vnp_Amount=1000000&vnp_BankCode=NCB&vnp_BankTranNo=VNP15593296&vnp_CardType=ATM&vnp_OrderInfo=Thanh+to%C3%A1n+%C4%91%C6%A1n+h%C3%A0ng+HD000001&vnp_PayDate=20260622142046&vnp_ResponseCode=${vnp_ResponseCode}&vnp_TmnCode=SCG4UUS6&vnp_TransactionNo=15593296&vnp_TransactionStatus=00&vnp_TxnRef=HD000001-2026-06-22T07:20:14.735Z&vnp_SecureHash=9726fe2db0da9741fc14fc42ced098cabf204f21ab12f633e8ac1cb7c9567a3b7a379d790f29a1a8b60fa8edb24acb0faca83feca0f7757865b0bf853b55ea01`, "return", "popup=true,width=800,height=600", ); } onMounted(async () => { paidPaymentStatus.value = await $getdata("Payment_Status", { filter: { code: "PAID" }, first: true, }); }); return { isPending, placeOrder, testReturnPage, showVietQRModal }; }