From e70ae887f31b5e5d827a940af96e21c290633458 Mon Sep 17 00:00:00 2001 From: Edwin Eames Date: Mon, 20 Oct 2025 12:01:16 -0400 Subject: [PATCH] added cancel button --- src/assets/images/googlereview.png | Bin 0 -> 5856 bytes src/layouts/footers/footer.vue | 21 ++++++-- src/pages/customer/profile/profile.vue | 30 +++++++++-- .../profile/profile/AutomaticDeliveries.vue | 15 +++--- .../profile/profile/DeliveriesTable.vue | 1 + .../customer/profile/profile/HistoryTabs.vue | 30 ++--------- src/pages/delivery/create.vue | 48 ++++++++++++++---- src/pages/delivery/view.vue | 37 ++++++++++++++ .../delivery/viewstatus/todaysdeliveries.vue | 18 +------ src/pages/delivery/viewstatus/tommorrow.vue | 2 +- 10 files changed, 136 insertions(+), 66 deletions(-) create mode 100644 src/assets/images/googlereview.png diff --git a/src/assets/images/googlereview.png b/src/assets/images/googlereview.png new file mode 100644 index 0000000000000000000000000000000000000000..0d5aaff866bf76f65e6a40594aca23382f048d36 GIT binary patch literal 5856 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 q0{{U3|LiyTfdBvi21!IgR09Ck`Spring Rebuilders - (508) 799-9342 @@ -36,7 +37,17 @@ export default defineComponent({ }, mounted() { }, - methods: {}, + methods: { + async copyReviewLink() { + try { + await navigator.clipboard.writeText('https://g.page/r/CZHnPQ85LsMUEBM/review') + alert('Link copied to clipboard!') + } catch (err) { + console.error('Failed to copy text: ', err) + alert('Failed to copy link. Please try again.') + } + }, + }, }) - \ No newline at end of file + diff --git a/src/pages/customer/profile/profile.vue b/src/pages/customer/profile/profile.vue index e24a082..3be6fcd 100755 --- a/src/pages/customer/profile/profile.vue +++ b/src/pages/customer/profile/profile.vue @@ -137,7 +137,28 @@ @edit-card="editCard" @remove-card="removeCard" /> - + + +
+

Automatic Delivery Actions

+
+ + + + + + + + + + + + +
+
+ @@ -305,6 +326,8 @@ interface AutomaticDelivery { customer_full_name: string; gallons_delivered: number | string; fill_date: string; + auto_status: number | string; + open_ticket_id: number | string; } interface CreditCard { @@ -600,13 +623,14 @@ export default defineComponent({ }) }, getCustomerAutoDelivery(userid: any) { - let path = import.meta.env.VITE_AUTO_URL + '/delivery/all/profile/profile/' + userid ; + let path = import.meta.env.VITE_AUTO_URL + '/delivery/auto/customer/' + userid ; axios({ method: 'get', url: path, headers: authHeader(), }).then((response: any) => { - this.autodeliveries = response.data + // Handle the case where response.data might be null (no auto delivery found) + this.autodeliveries = response.data ? [response.data] : [] }) }, getCustomerDelivery(userid: any, delivery_page: any) { diff --git a/src/pages/customer/profile/profile/AutomaticDeliveries.vue b/src/pages/customer/profile/profile/AutomaticDeliveries.vue index b3b5e4d..bd53aa0 100644 --- a/src/pages/customer/profile/profile/AutomaticDeliveries.vue +++ b/src/pages/customer/profile/profile/AutomaticDeliveries.vue @@ -16,15 +16,16 @@ - - {{ auto.id }} - {{ auto.customer_full_name }} - {{ auto.gallons_delivered }} - {{ auto.fill_date }} + + {{ autoticket.id }} + {{ autoticket.customer_full_name }} + {{ autoticket.gallons_delivered }} + {{ autoticket.fill_date }} - + + @@ -40,6 +41,8 @@ interface AutomaticDelivery { id: number; customer_full_name: string; gallons_delivered: number | string; + auto_status: number | string; + open_ticket_id: number | string; fill_date: string; } diff --git a/src/pages/customer/profile/profile/DeliveriesTable.vue b/src/pages/customer/profile/profile/DeliveriesTable.vue index 7c07ff3..813472c 100644 --- a/src/pages/customer/profile/profile/DeliveriesTable.vue +++ b/src/pages/customer/profile/profile/DeliveriesTable.vue @@ -34,6 +34,7 @@ View Edit Print + Finalize diff --git a/src/pages/customer/profile/profile/HistoryTabs.vue b/src/pages/customer/profile/profile/HistoryTabs.vue index c6c22a0..abbbd56 100644 --- a/src/pages/customer/profile/profile/HistoryTabs.vue +++ b/src/pages/customer/profile/profile/HistoryTabs.vue @@ -26,32 +26,7 @@ Automatic Deliveries
-
- - - - - - - - - - - - - - - - - - - -
IDNameGallonsDateView
{{ auto.id }}{{ auto.customer_full_name }}{{ auto.gallons_delivered }}{{ auto.fill_date }} - - - -
-
+
@@ -61,6 +36,7 @@ import { ref } from 'vue'; import DeliveriesTable from './DeliveriesTable.vue'; import ServiceCallsTable from './ServiceCallsTable.vue'; import TransactionsTable from './TransactionsTable.vue'; +import AutomaticDeliveries from './AutomaticDeliveries.vue'; // 1. Define the interfaces for the data this component receives and passes down. // These should match the interfaces in the child components. @@ -78,6 +54,8 @@ interface AutomaticDelivery { id: number; customer_full_name: string; gallons_delivered: number | string; + auto_status: number | string; + open_ticket_id: number | string; fill_date: string; } diff --git a/src/pages/delivery/create.vue b/src/pages/delivery/create.vue index c16d17c..099ab55 100755 --- a/src/pages/delivery/create.vue +++ b/src/pages/delivery/create.vue @@ -377,6 +377,7 @@ export default defineComponent({ return { v$: useValidate(), user: null as any, + customer: {} as any, isLoading: false, // For main form submission isCardSaving: false, // For quick add card form quickGallonAmounts: [100, 125, 150, 175, 200, 220], @@ -384,6 +385,8 @@ export default defineComponent({ promos: [] as Promo[], truckDriversList: [] as Driver[], pricingTiers: [] as PricingTier[], + isLoadingAuthorize: true, + authorizeCheck: { profile_exists: false, has_payment_methods: false, missing_components: [] as string[], valid_for_charging: false }, isConfirmationModalVisible: false, formDelivery: { gallons_ordered: '', @@ -410,7 +413,7 @@ export default defineComponent({ card_name: '', type_of_card: '', } as CardFormData, - customer: {} as Customer, + } }, validations() { @@ -622,7 +625,29 @@ export default defineComponent({ this.isLoading = false; } }, + async checkAuthorizeAccount() { + if (!this.customer.id) return; + this.isLoadingAuthorize = true; + + try { + const path = `${import.meta.env.VITE_AUTHORIZE_URL}/user/check-authorize-account/${this.customer.id}`; + const response = await axios.get(path, { headers: authHeader() }); + this.authorizeCheck = response.data; + } catch (error) { + console.error("Failed to check authorize account:", error); + notify({ title: "Error", text: "Could not check payment account status.", type: "error" }); + // Set default error state + this.authorizeCheck = { + profile_exists: false, + has_payment_methods: false, + missing_components: ['api_error'], + valid_for_charging: false + }; + } finally { + this.isLoadingAuthorize = false; + } + }, async onCardSubmit() { this.v$.formCard.$validate(); if (this.v$.formCard.$error) { @@ -643,13 +668,7 @@ export default defineComponent({ name_on_card: this.formCard.card_name, // Map card_name to name_on_card for Flask }; - // Payload for FastAPI backend (it only needs the essentials for Authorize.Net) - const fastapiPayload = { - card_number: this.formCard.card_number.replace(/\s/g, ''), - expiration_date: `${this.formCard.expiration_year}-${this.formCard.expiration_month}`, - cvv: this.formCard.security_number, // Map security_number to cvv for FastAPI - main_card: false, // Send this to FastAPI as well - }; + // --- STEP 2: CRITICAL CALL - SAVE CARD TO LOCAL DATABASE VIA FLASK --- try { @@ -671,6 +690,15 @@ export default defineComponent({ } // --- STEP 3: BEST-EFFORT CALL - TOKENIZE CARD VIA FASTAPI --- + if (this.authorizeCheck.profile_exists) { + // Payload for FastAPI backend (it only needs the essentials for Authorize.Net) + const fastapiPayload = { + card_number: this.formCard.card_number.replace(/\s/g, ''), + expiration_date: `${this.formCard.expiration_year}-${this.formCard.expiration_month}`, + cvv: this.formCard.security_number, // Map security_number to cvv for FastAPI + main_card: false, // Send this to FastAPI as well + }; + try { const fastapiPath = `${import.meta.env.VITE_AUTHORIZE_URL}/api/payments/customers/${this.customer.id}/cards`; console.log("Attempting to tokenize card with Authorize.Net via FastAPI:", fastapiPath); @@ -680,7 +708,9 @@ export default defineComponent({ // If this fails, we just log it for the developers. We DON'T show an error to the user. console.warn("NON-CRITICAL-ERROR: Tokenization with Authorize.Net failed, but the card was saved locally.", error.response?.data || error.message); } - + }else{ + console.log("Skipping Authorize.Net tokenization as no profile exists for customer."); + } // --- STEP 4: ALWAYS SHOW SUCCESS, REFRESH CARDS, STAY ON PAGE --- // This code runs as long as the first (Flask) call was successful. notify({ type: 'success', title: 'Card Saved!' }); diff --git a/src/pages/delivery/view.vue b/src/pages/delivery/view.vue index 585ac46..0ce2044 100755 --- a/src/pages/delivery/view.vue +++ b/src/pages/delivery/view.vue @@ -339,6 +339,13 @@ + @@ -527,6 +534,36 @@ export default defineComponent({ } }) }, + cancelDelivery() { + let path = import.meta.env.VITE_BASE_URL + '/delivery/cancel/' + this.deliveryOrder.id; + axios({ + method: 'post', + url: path, + headers: authHeader(), + }).then((response: any) => { + if (response.data.ok) { + notify({ + title: "Success", + text: "Delivery cancelled", + type: "success", + }); + // Refresh the delivery data + this.getOilOrder(this.deliveryOrder.id); + } else { + notify({ + title: "Failure", + text: "Failed to cancel delivery", + type: "error", + }); + } + }).catch(() => { + notify({ + title: "Error", + text: "Error cancelling delivery", + type: "error", + }); + }); + }, userStatus() { let path = import.meta.env.VITE_BASE_URL + '/auth/whoami'; axios({ diff --git a/src/pages/delivery/viewstatus/todaysdeliveries.vue b/src/pages/delivery/viewstatus/todaysdeliveries.vue index 5cdf483..a39aa6d 100755 --- a/src/pages/delivery/viewstatus/todaysdeliveries.vue +++ b/src/pages/delivery/viewstatus/todaysdeliveries.vue @@ -35,8 +35,6 @@ Status Town / Address Gallons - Options - Payment Actions @@ -79,13 +77,7 @@ EMERGENCY - - Cash - CC - Cash/CC - Check - Other - +
View @@ -137,13 +129,7 @@ FILL {{ oil.gallons_ordered }}

-

Payment: - Cash - CC - Cash/CC - Check - Other -

+
diff --git a/src/pages/delivery/viewstatus/tommorrow.vue b/src/pages/delivery/viewstatus/tommorrow.vue index 9611d42..ab719ad 100644 --- a/src/pages/delivery/viewstatus/tommorrow.vue +++ b/src/pages/delivery/viewstatus/tommorrow.vue @@ -29,7 +29,7 @@ Status Town / Address Gallons - Options + Actions