From 827debd1cc9b651f07f2dcbe7d9a25068ada2f91 Mon Sep 17 00:00:00 2001 From: Edwin Eames Date: Tue, 16 Sep 2025 13:52:16 -0400 Subject: [PATCH] small frontend changed --- .../profile/profile/TransactionsTable.vue | 7 +- .../update_tickets/finalize_ticket.vue | 111 +++++++----- src/pages/delivery/view.vue | 168 +++++++++++------- src/pages/pay/oil/capture_authorize.vue | 13 +- 4 files changed, 183 insertions(+), 116 deletions(-) diff --git a/src/pages/customer/profile/profile/TransactionsTable.vue b/src/pages/customer/profile/profile/TransactionsTable.vue index 71509d2..3b72d99 100644 --- a/src/pages/customer/profile/profile/TransactionsTable.vue +++ b/src/pages/customer/profile/profile/TransactionsTable.vue @@ -137,9 +137,10 @@ const getSourceText = (transaction: Transaction) => { const formatDate = (dateStr: string) => dateStr.split('T')[0]; // YYYY-MM-DD const getTypeColor = (transactionType: number) => { switch (transactionType) { - case 1: return 'text-blue-600'; - case 0: return 'text-orange-600'; - case 2: return 'text-green-600'; + case 1: return 'text-blue-600'; // Auth + case 0: return 'text-orange-600'; // Charge + case 2: return 'text-purple-600'; // Capture + case 3: return 'text-green-600'; // Delivery/Other default: return 'text-gray-600'; } } diff --git a/src/pages/delivery/update_tickets/finalize_ticket.vue b/src/pages/delivery/update_tickets/finalize_ticket.vue index 764cc1f..78449b6 100755 --- a/src/pages/delivery/update_tickets/finalize_ticket.vue +++ b/src/pages/delivery/update_tickets/finalize_ticket.vue @@ -334,7 +334,6 @@ export default defineComponent({ console.log(`[DEBUG] Component Mounted. Fetching data for delivery ID: ${deliveryId}`); this.getOilOrder(deliveryId); this.getOilPricing(); - this.getTransaction(deliveryId); }, methods: { async getOilOrder(delivery_id: any) { @@ -364,6 +363,9 @@ export default defineComponent({ if ([1, 2].includes(this.deliveryOrder.payment_type) && this.deliveryOrder.payment_card_id) { this.getPaymentCard(this.deliveryOrder.payment_card_id); } + + // Call transaction fetch after customer is loaded + setTimeout(() => this.getTransaction(delivery_id), 500); } else { console.error('[DEBUG] getOilOrder response was not OK or data is missing.'); notify({ title: "Data Error", text: "Could not retrieve complete delivery details.", type: "error" }); @@ -410,27 +412,63 @@ export default defineComponent({ .catch((error: any) => { console.error("[DEBUG] Error fetching oil pricing:", error); }); }, getTransaction(delivery_id: any) { - const path = `${import.meta.env.VITE_AUTHORIZE_URL}/api/transaction/delivery/${delivery_id}`; - axios.get(path, { withCredentials: true, headers: authHeader() }) - .then((response: any) => { - this.transaction = response.data; - }) - .catch((error: any) => { - // Handle 404 gracefully - delivery doesn't have transaction data in authorize system - if (error.response && error.response.status === 404) { - console.log(`No transaction found for delivery ${delivery_id} in authorize system`); - this.transaction = null; - } else { - console.error("Error fetching transaction:", error); - this.transaction = null; - } - }); + // Consistent with delivery/view.vue - use customer transaction endpoint + if (this.customer && this.customer.id) { + const path = `${import.meta.env.VITE_BASE_URL}/payment/transactions/customer/${this.customer.id}/1`; + axios.get(path, { withCredentials: true, headers: authHeader() }) + .then((response: any) => { + console.log("Transaction API response:", response.data); + // Handle both single transaction object and array responses + if (response.data && Array.isArray(response.data) && response.data.length > 0) { + // Find the transaction for this specific delivery + const deliveryTransaction = response.data.find((txn: any) => + txn.delivery_id === parseInt(delivery_id) || + txn.transaction_id === delivery_id || + txn.delivery_number === delivery_id + ); + this.transaction = deliveryTransaction || null; + } else if (response.data && !Array.isArray(response.data)) { + // If single transaction, check if it's for this delivery + const txn = response.data; + if (txn.delivery_id === parseInt(delivery_id) || + txn.transaction_id === delivery_id || + txn.delivery_number === delivery_id) { + this.transaction = txn; + } else { + this.transaction = null; + } + } else { + this.transaction = null; + } + + if (!this.transaction) { + console.log(`No transaction found for delivery ${delivery_id} among customer transactions`); + } + }) + .catch((error: any) => { + // Handle various error responses gracefully + if (error.response && error.response.status === 404) { + console.log(`No transactions found for customer ${this.customer.id}`); + this.transaction = null; + } else if (error.response && error.response.status === 400) { + console.log(`Bad request for customer transactions: ${error.response.data?.detail || error.message}`); + this.transaction = null; + } else { + console.error("Error fetching transaction:", error); + this.transaction = null; + } + }); + } else { + console.log("Customer data not available, cannot fetch transactions"); + this.transaction = null; + } }, getTypeColor(transactionType: number) { switch (transactionType) { - case 1: return 'text-blue-600'; - case 0: return 'text-orange-600'; - case 2: return 'text-green-600'; + case 1: return 'text-blue-600'; // Auth + case 0: return 'text-orange-600'; // Charge + case 2: return 'text-purple-600'; // Capture + case 3: return 'text-green-600'; // Delivery/Other default: return 'text-gray-600'; } }, @@ -458,36 +496,15 @@ export default defineComponent({ if (!finalizeResponse.data.ok) { throw new Error(finalizeResponse.data.error || "Failed to update delivery details."); } - if ([1, 2].includes(this.deliveryOrder.payment_type)) { - const transactionUrl = `${import.meta.env.VITE_AUTHORIZE_URL}/api/transaction/delivery/${this.deliveryOrder.id}`; - try { - const transactionResponse = await axios.get(transactionUrl, { withCredentials: true, headers: authHeader() }); - const preAuthTx = transactionResponse.data as PreAuthTransaction; - if (preAuthTx && preAuthTx.transaction_type === 1 && preAuthTx.status === 0) { - const capturePayload = { - auth_net_transaction_id: preAuthTx.auth_net_transaction_id, - charge_amount: this.finalChargeAmount.toFixed(2), - }; - const capturePath = `${import.meta.env.VITE_AUTHORIZE_URL}/api/capture/`; - await axios.post(capturePath, capturePayload, { withCredentials: true, headers: authHeader() }); - notify({ title: "Payment Captured", text: `Successfully charged $${capturePayload.charge_amount}.`, type: "success" }); - } else { - notify({ title: "Warning", text: "No valid pre-authorization found to capture. Please charge manually.", type: "warn" }); - } - } catch (error: any) { - if (error.response?.status === 404 && error.response?.data?.detail?.includes("No pre-authorization transaction found")) { - notify({ title: "Redirecting", text: "No pre-authorization found. Redirecting to customer profile to update payment method.", type: "info" }); - this.$router.push({ name: "customerProfile", params: { id: this.customer.id } }); - return; - } else { - notify({ title: "Error", text: "Failed to check transaction status.", type: "error" }); - throw error; - } - } - } this.CreateTransaction(); notify({ title: "Success", text: "Ticket has been finalized.", type: "success" }); - this.$router.push({ name: "deliveryOrder", params: { id: this.deliveryOrder.id } }); + + // Redirect based on payment type - redirect to capture for credit card payments + if ([1, 2].includes(this.deliveryOrder.payment_type)) { + this.$router.push({ name: "captureAuthorize", params: { id: this.deliveryOrder.id } }); + } else { + this.$router.push({ name: "deliveryOrder", params: { id: this.deliveryOrder.id } }); + } } catch (error: any) { const errorMessage = error.response?.data?.detail || "An error occurred during finalization."; notify({ title: "Error", text: errorMessage, type: "error" }); diff --git a/src/pages/delivery/view.vue b/src/pages/delivery/view.vue index 36d0972..c5379c5 100755 --- a/src/pages/delivery/view.vue +++ b/src/pages/delivery/view.vue @@ -145,7 +145,7 @@ -
+
@@ -448,7 +448,6 @@ export default defineComponent({ this.getOilOrderMoney(this.$route.params.id); this.sumdelivery(this.$route.params.id); this.getOilPricing(); - this.getTransaction(this.$route.params.id); }, methods: { @@ -459,9 +458,10 @@ export default defineComponent({ }, getTypeColor(transactionType: number) { switch (transactionType) { - case 1: return 'text-blue-600'; - case 0: return 'text-orange-600'; - case 2: return 'text-green-600'; + case 1: return 'text-blue-600'; // Auth + case 0: return 'text-orange-600'; // Charge + case 2: return 'text-green-600'; // Capture + case 3: return 'text-purple-600'; // Delivery/Other default: return 'text-gray-600'; } }, @@ -522,22 +522,26 @@ export default defineComponent({ }); }, getCustomer(user_id: any) { - let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id; - axios({ - method: "get", - url: path, - withCredentials: true, - }) - .then((response: any) => { - this.customer = response.data; + return new Promise((resolve, reject) => { + let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id; + axios({ + method: "get", + url: path, + withCredentials: true, }) - .catch(() => { + .then((response: any) => { + this.customer = response.data; + resolve(response.data); + }) + .catch((error: any) => { notify({ title: "Error", text: "Could not find customer", type: "error", }); + reject(error); }); + }); }, getPaymentCard(card_id: any) { @@ -568,40 +572,45 @@ export default defineComponent({ } }, -getOilOrder(delivery_id: any) { - if (!delivery_id) { // Add a guard to prevent calls with an undefined ID - console.error("getOilOrder called with no ID."); - return; - } - let path = import.meta.env.VITE_BASE_URL + "/delivery/" + delivery_id; - axios({ - method: "get", - url: path, - withCredentials: true, - headers: authHeader(), - }) - .then((response: any) => { - // FIX: Check for the 'ok' flag and access the nested 'delivery' object - if (response.data && response.data.ok) { - this.deliveryOrder = response.data.delivery; // <-- THIS IS THE CRITICAL CHANGE - - // Now that this.deliveryOrder is the correct object, the rest of the logic will work. - this.getCustomer(this.deliveryOrder.customer_id); - - if ([1, 2, 3].includes(this.deliveryOrder.payment_type)) { - this.getPaymentCard(this.deliveryOrder.payment_card_id); + async getOilOrder(delivery_id: any) { + if (!delivery_id) { // Add a guard to prevent calls with an undefined ID + console.error("getOilOrder called with no ID."); + return; } - if (this.deliveryOrder.promo_id != null) { - this.getPromo(this.deliveryOrder.promo_id); + let path = import.meta.env.VITE_BASE_URL + "/delivery/" + delivery_id; + try { + const response = await axios({ + method: "get", + url: path, + withCredentials: true, + headers: authHeader(), + }); + + // FIX: Check for the 'ok' flag and access the nested 'delivery' object + if (response.data && response.data.ok) { + this.deliveryOrder = response.data.delivery; // <-- THIS IS THE CRITICAL CHANGE + + // Now that this.deliveryOrder is the correct object, the rest of the logic will work. + await this.getCustomer(this.deliveryOrder.customer_id); + + if ([1, 2, 3].includes(this.deliveryOrder.payment_type)) { + this.getPaymentCard(this.deliveryOrder.payment_card_id); + } + if (this.deliveryOrder.promo_id != null) { + this.getPromo(this.deliveryOrder.promo_id); + } + + // Now that customer is loaded, we can fetch transactions directly + this.getTransaction(delivery_id); + + } else { + console.error("API Error:", response.data.error || "Failed to fetch delivery data."); + notify({ title: "Error", text: "Could not load delivery details.", type: "error" }); + } + } catch (error) { + console.error("Error fetching delivery order:", error); } - } else { - console.error("API Error:", response.data.error || "Failed to fetch delivery data."); - notify({ title: "Error", text: "Could not load delivery details.", type: "error" }); - } - }) - .catch( console.log("") - ); -}, + }, getOilOrderMoney(delivery_id: any) { let path = import.meta.env.VITE_MONEY_URL + "/delivery/order/money/" + delivery_id; axios({ @@ -709,22 +718,57 @@ getOilOrder(delivery_id: any) { }, getTransaction(delivery_id: any) { - const path = `${import.meta.env.VITE_AUTHORIZE_URL}/api/transaction/delivery/${delivery_id}`; - axios.get(path, { withCredentials: true, headers: authHeader() }) - .then((response: any) => { - console.log("Transaction API response:", response.data); // Debug log to see actual response structure - this.transaction = response.data; - }) - .catch((error: any) => { - // Handle 404 gracefully - delivery doesn't have transaction data in authorize system - if (error.response && error.response.status === 404) { - console.log(`No transaction found for delivery ${delivery_id} in authorize system`); - this.transaction = null; - } else { - console.error("Error fetching transaction:", error); - this.transaction = null; - } - }); + // Fix: Use customer transaction endpoint to get transactions for this delivery's customer + // The API seems to work with customer-centric endpoints + if (this.customer && this.customer.id) { + const path = `${import.meta.env.VITE_BASE_URL}/payment/transactions/customer/${this.customer.id}/1`; + axios.get(path, { withCredentials: true, headers: authHeader() }) + .then((response: any) => { + console.log("Transaction API response:", response.data); // Debug log to see actual response structure + // Handle both single transaction object and array responses + if (response.data && Array.isArray(response.data) && response.data.length > 0) { + // Find the transaction for this specific delivery + const deliveryTransaction = response.data.find((txn: any) => + txn.delivery_id === parseInt(delivery_id) || + txn.transaction_id === delivery_id || + txn.delivery_number === delivery_id + ); + this.transaction = deliveryTransaction || null; + } else if (response.data && !Array.isArray(response.data)) { + // If single transaction, check if it's for this delivery + const txn = response.data; + if (txn.delivery_id === parseInt(delivery_id) || + txn.transaction_id === delivery_id || + txn.delivery_number === delivery_id) { + this.transaction = txn; + } else { + this.transaction = null; + } + } else { + this.transaction = null; + } + + if (!this.transaction) { + console.log(`No transaction found for delivery ${delivery_id} among customer transactions`); + } + }) + .catch((error: any) => { + // Handle various error responses gracefully + if (error.response && error.response.status === 404) { + console.log(`No transactions found for customer ${this.customer.id}`); + this.transaction = null; + } else if (error.response && error.response.status === 400) { + console.log(`Bad request for customer transactions: ${error.response.data?.detail || error.message}`); + this.transaction = null; + } else { + console.error("Error fetching transaction:", error); + this.transaction = null; + } + }); + } else { + console.log("Customer data not available, cannot fetch transactions"); + this.transaction = null; + } }, }, }) diff --git a/src/pages/pay/oil/capture_authorize.vue b/src/pages/pay/oil/capture_authorize.vue index a162060..6352e55 100644 --- a/src/pages/pay/oil/capture_authorize.vue +++ b/src/pages/pay/oil/capture_authorize.vue @@ -159,7 +159,7 @@

Gallons Delivered

-
{{ gallonsDelivered || '0.00' }}
+
{{ gallonsDelivered || '0.00' }}
gallons
@@ -392,9 +392,14 @@ export default defineComponent({ } }) .catch((error: any) => { - notify({ title: "Error", text: "No pre-authorized transaction found", type: "error" }); - console.error("Error fetching transaction:", error); - this.$router.push({ name: 'finalizeTicket', params: { id: this.$route.params.id } }); + if (error.response && error.response.status === 404) { + notify({ title: "Info", text: "No pre-authorization found. Redirecting to customer profile to update payment method.", type: "info" }); + console.log("No transaction found for delivery - redirecting to customer profile"); + this.$router.push({ name: 'customerProfile', params: { id: this.customer.id } }); + } else { + notify({ title: "Error", text: "No pre-authorized transaction found", type: "error" }); + this.$router.push({ name: 'finalizeTicket', params: { id: this.$route.params.id } }); + } }); },