diff --git a/src/assets/images/googlereview.png b/src/assets/images/googlereview.png new file mode 100644 index 0000000..0d5aaff Binary files /dev/null and b/src/assets/images/googlereview.png differ diff --git a/src/layouts/footers/footer.vue b/src/layouts/footers/footer.vue index bd83d85..5a6973f 100755 --- a/src/layouts/footers/footer.vue +++ b/src/layouts/footers/footer.vue @@ -15,9 +15,10 @@
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