major claude changes

This commit is contained in:
2026-01-28 21:55:14 -05:00
parent f9d0e4c0fd
commit f9b5364c53
81 changed files with 11155 additions and 10086 deletions

View File

@@ -229,7 +229,7 @@
<div class="font-bold text-sm">{{ card.name_on_card }}</div>
<div class="text-sm">{{ card.type_of_card }}</div>
<div class="text-sm">{{ card.card_number }}</div>
<p class="text-sm">Exp: <span v-if="card.expiration_month < 10">0</span>{{ card.expiration_month }} / {{ card.expiration_year }}</p>
<p class="text-sm">Exp: <span v-if="Number(card.expiration_month) < 10">0</span>{{ card.expiration_month }} / {{ card.expiration_year }}</p>
<p class="text-sm">CVV: {{ card.security_number }}</p>
</div>
<div class="flex justify-end gap-2 mt-2">
@@ -305,43 +305,21 @@
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, computed, onMounted, watch, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import { Customer, CreditCard, CreateCardRequest } from '../../types/models'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import { useVuelidate } from "@vuelidate/core";
import { notify } from "@kyvg/vue3-notification"
import { minLength, required, requiredIf } from "@vuelidate/validators";
// --- TYPE DEFINITIONS (MODIFIED) ---
interface SimpleResponse<T> { data: T; }
interface Customer {
id: number;
customer_last_name: string;
customer_first_name: string;
customer_town: string;
customer_state: number;
customer_zip: string;
customer_phone_number: string;
customer_home_type: number;
customer_apt: string;
customer_address: string;
account_number: string;
}
// This interface now reflects the full card data from the backend
interface UserCard {
id: number;
last_four_digits?: number;
type_of_card: string;
expiration_month: number;
expiration_year: number;
name_on_card: string;
card_number: string;
security_number: string;
}
interface Promo { id: number; name_of_promotion: string; money_off_delivery: number; }
interface Driver { id: number; employee_first_name: string; employee_last_name: string; }
interface PricingTier { gallons: number | string; price: number | string; }
@@ -370,363 +348,384 @@ interface CardFormData {
type_of_card: string;
}
export default defineComponent({
name: 'deliveryCreate',
components: { Header, SideBar, Footer },
data() {
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],
userCards: [] as UserCard[],
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: '',
customer_asked_for_fill: false,
expected_delivery_date: '',
dispatcher_notes_taken: '',
prime: false,
emergency: false,
same_day: false,
credit: false,
cash: false,
check: false,
other: false,
credit_card_id: 0,
promo_id: 0,
driver_employee_id: 0,
} as DeliveryFormData,
// Simplified formCard data
formCard: {
card_number: '',
expiration_month: '',
expiration_year: '',
security_number: '',
card_name: '',
type_of_card: '',
} as CardFormData,
const router = useRouter()
const route = useRoute()
}
// Reactive data
const user = ref(null as any)
const customer = ref({} as any)
const isLoading = ref(false) // For main form submission
const isCardSaving = ref(false) // For quick add card form
const quickGallonAmounts = ref([100, 125, 150, 175, 200, 220])
const userCards = ref<CreditCard[]>([])
const promos = ref([] as Promo[])
const truckDriversList = ref([] as Driver[])
const pricingTiers = ref([] as PricingTier[])
const isLoadingAuthorize = ref(true)
const authorizeCheck = ref({ profile_exists: false, has_payment_methods: false, missing_components: [] as string[], valid_for_charging: false })
const isConfirmationModalVisible = ref(false)
const formDelivery = ref({
gallons_ordered: '',
customer_asked_for_fill: false,
expected_delivery_date: '',
dispatcher_notes_taken: '',
prime: false,
emergency: false,
same_day: false,
credit: false,
cash: false,
check: false,
other: false,
credit_card_id: 0,
promo_id: 0,
driver_employee_id: 0,
} as DeliveryFormData)
// Simplified formCard data
const formCard = ref({
card_number: '',
expiration_month: '',
expiration_year: '',
security_number: '',
card_name: '',
type_of_card: '',
} as CardFormData)
// Computed
const preAuthAmount = computed((): number => {
if (!formDelivery.value.credit || formDelivery.value.customer_asked_for_fill) return 0;
const gallons = Number(formDelivery.value.gallons_ordered);
if (isNaN(gallons) || gallons <= 0 || pricingTiers.value.length === 0) return 0;
// Find the correct price tier. Assumes tiers are for total price, not price/gallon.
let priceForGallons = 0;
const sortedTiers = [...pricingTiers.value].sort((a, b) => Number(a.gallons) - Number(b.gallons));
// Find the highest tier that is less than or equal to the gallons ordered
let applicableTier = sortedTiers.filter(t => gallons >= Number(t.gallons)).pop();
if (applicableTier) {
const pricePerGallon = Number(applicableTier.price) / Number(applicableTier.gallons);
priceForGallons = gallons * pricePerGallon;
} else if (sortedTiers.length > 0) {
// Fallback to the lowest tier's price/gallon if no tier is met (e.g., ordering 50 gallons when lowest tier is 100)
const lowestTier = sortedTiers[0];
const pricePerGallon = Number(lowestTier.price) / Number(lowestTier.gallons);
priceForGallons = gallons * pricePerGallon;
}
return priceForGallons;
})
const customerStateName = computed((): string => {
const states: Record<number, string> = { 0: 'Massachusetts', 1: 'Rhode Island', 2: 'New Hampshire', 3: 'Maine', 4: 'Vermont', 5: 'Connecticut', 6: 'New York' };
return states[customer.value.customer_state] || 'Unknown state';
})
const customerHomeTypeName = computed((): string => {
const types: Record<number, string> = { 0: 'Residential', 1: 'apartment', 2: 'condo', 3: 'commercial', 4: 'business', 5: 'construction', 6: 'container' };
return types[customer.value.customer_home_type] || 'Unknown type';
})
const isAnyPaymentMethodSelected = computed((): boolean => {
return !!(formDelivery.value?.credit || formDelivery.value?.cash || formDelivery.value?.check || formDelivery.value?.other);
})
const selectedGallonsAmount = computed((): number => {
const value = formDelivery.value.gallons_ordered ?? '';
return Number(value);
})
// Validations
const validations = {
formDelivery: {
gallons_ordered: {
required: requiredIf(() => !formDelivery.value.customer_asked_for_fill),
minValue: (value: string) => {
if (formDelivery.value.customer_asked_for_fill) return true;
if (!value) return true;
const num = parseInt(value, 10);
return num >= 1;
}
},
expected_delivery_date: { required },
driver_employee_id: { required },
credit_card_id: {
creditCardRequired: (value: number) => {
if (formDelivery.value.credit) { return value !== 0; }
return true;
}
},
},
validations() {
return {
formDelivery: {
gallons_ordered: {
required: requiredIf(function(this: any) { return !this.formDelivery.customer_asked_for_fill; }),
minValue: function(this: any, value: string) {
if (this.formDelivery.customer_asked_for_fill) return true;
if (!value) return true;
const num = parseInt(value, 10);
return num >= 1;
}
},
expected_delivery_date: { required },
driver_employee_id: { required },
credit_card_id: {
creditCardRequired: function(this: any, value: number) {
if (this.formDelivery.credit) { return value !== 0; }
return true;
}
},
},
isAnyPaymentMethodSelected: { mustBeTrue: (value: boolean) => value === true, },
// Simplified validations for quick add card
formCard: {
card_name: { required, minLength: minLength(1) },
security_number: { required, minLength: minLength(1) },
type_of_card: { required },
card_number: { required, minLength: minLength(1) },
expiration_month: { required },
expiration_year: { required },
},
isAnyPaymentMethodSelected: { mustBeTrue: (value: boolean) => value === true, },
// Simplified validations for quick add card
formCard: {
card_name: { required, minLength: minLength(1) },
security_number: { required, minLength: minLength(1) },
type_of_card: { required },
card_number: { required, minLength: minLength(1) },
expiration_month: { required },
expiration_year: { required },
},
}
const v$ = useVuelidate(validations, { formDelivery, formCard, isAnyPaymentMethodSelected })
// Functions
const setGallons = (amount: number) => {
formDelivery.value.gallons_ordered = String(amount);
formDelivery.value.customer_asked_for_fill = false;
}
const selectCreditCard = (cardId: number) => {
formDelivery.value.credit_card_id = cardId;
}
const setDeliveryDate = (days: number) => {
const date = new Date();
date.setDate(date.getDate() + days);
formDelivery.value.expected_delivery_date = date.toISOString().split('T')[0];
}
const isDeliveryDateSelected = (days: number): boolean => {
const date = new Date();
date.setDate(date.getDate() + days);
return formDelivery.value.expected_delivery_date === date.toISOString().split('T')[0];
}
const isPricingTierSelected = (tierGallons: number | string): boolean => {
if (!formDelivery.value.gallons_ordered) return false;
const selectedGallons = Number(formDelivery.value.gallons_ordered);
if (isNaN(selectedGallons)) return false;
const tierNum = Number(tierGallons);
if (isNaN(tierNum)) return false;
return selectedGallons === tierNum;
}
const getPricingTiers = () => {
let path = import.meta.env.VITE_BASE_URL + "/info/price/oil/tiers";
axios({ method: "get", url: path, withCredentials: true, headers: authHeader() })
.then((response: SimpleResponse<{ [key: string]: string }>) => {
pricingTiers.value = Object.entries(response.data).map(([gallons, price]) => ({ gallons: parseInt(gallons, 10), price: price }));
})
.catch(() => notify({ title: "Pricing Error", text: "Could not retrieve today's pricing.", type: "error" }));
}
const getCustomer = (user_id: string | number | string[]) => {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({ method: "get", url: path, withCredentials: true })
.then((response: SimpleResponse<Customer>) => { customer.value = response.data; })
.catch(() => notify({ title: "Error", text: "Could not find customer", type: "error" }));
}
const getPaymentCards = (user_id: string | number | string[]) => {
// IMPORTANT: This endpoint points to the Flask API that returns the secure card list.
let path = `${import.meta.env.VITE_BASE_URL}/payment/cards/${user_id}`;
return axios.get(path, { withCredentials: true, headers: authHeader() })
.then((response: SimpleResponse<CreditCard[]>) => { userCards.value = response.data; })
.catch(() => { userCards.value = []; }); // Clear cards on error
}
const getPromos = () => {
let path = import.meta.env.VITE_BASE_URL + "/promo/all";
axios({ method: "get", url: path, withCredentials: true })
.then((response: SimpleResponse<Promo[]>) => {
promos.value = response.data;
})
.catch(() => { /* empty */ });
}
const getDriversList = () => {
let path = import.meta.env.VITE_BASE_URL + "/employee/drivers";
axios({ method: "get", url: path, withCredentials: true, headers: authHeader() })
.then((response: SimpleResponse<Driver[]>) => {
truckDriversList.value = response.data;
})
.catch(() => { /* empty */ });
}
const editCard = (card_id: number) => {
router.push({ name: "cardedit", params: { id: card_id } });
}
const removeCard = (card_id: number) => {
if (window.confirm("Are you sure you want to remove this card?")) {
// You will need a new backend endpoint for this: DELETE /payments/customers/{customer_id}/cards/{card_id}
let path = `${import.meta.env.VITE_BASE_URL}/payment/card/remove/${card_id}`; // Keep old path or update to new
axios.delete(path, { headers: authHeader() })
.then(() => {
notify({ title: "Card Removed", type: "success" });
getPaymentCards(customer.value.id);
})
.catch(() => {
notify({ title: "Error", text: "Could not remove card.", type: "error" });
});
}
}
const onDeliverySubmit = async () => {
const isFormValid = await v$.value.formDelivery.$validate();
if (!isFormValid) {
notify({ title: "Form Incomplete", text: "Please review the fields marked in red.", type: "warn" });
return;
}
if (formDelivery.value.cash || formDelivery.value.check) {
isConfirmationModalVisible.value = true;
} else {
proceedWithSubmission();
}
}
const proceedWithSubmission = async () => {
isConfirmationModalVisible.value = false;
isLoading.value = true;
// Step 1: Create the delivery order record
const createDeliveryPath = `${import.meta.env.VITE_BASE_URL}/delivery/create/${customer.value.id}`;
try {
const deliveryResponse = await axios.post(createDeliveryPath, formDelivery.value, { withCredentials: true, headers: authHeader() });
const deliveryData = deliveryResponse.data;
if (!deliveryData.ok || !deliveryData.delivery_id) {
throw new Error(deliveryData.error || "Failed to create delivery record.");
}
// Delivery created successfully - redirect to payment page
notify({
title: "Success!",
text: `Delivery #${deliveryData.delivery_id} created. ${
formDelivery.value.credit
? "Redirecting to payment page."
: ""
}`,
type: "success"
});
router.push({ name: "payOil", params: { id: deliveryData.delivery_id } });
} catch (error: any) {
const errorMessage = error.response?.data?.detail || "An error occurred during submission.";
notify({ title: "Submission Error", text: errorMessage, type: "error" });
} finally {
isLoading.value = false;
}
}
const checkAuthorizeAccount = async () => {
if (!customer.value.id) return;
isLoadingAuthorize.value = true;
try {
const path = `${import.meta.env.VITE_AUTHORIZE_URL}/user/check-authorize-account/${customer.value.id}`;
const response = await axios.get(path, { headers: authHeader() });
authorizeCheck.value = 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
authorizeCheck.value = {
profile_exists: false,
has_payment_methods: false,
missing_components: ['api_error'],
valid_for_charging: false
};
},
computed: {
// New computed property to estimate pre-auth amount
preAuthAmount(): number {
if (!this.formDelivery.credit || this.formDelivery.customer_asked_for_fill) return 0;
const gallons = Number(this.formDelivery.gallons_ordered);
if (isNaN(gallons) || gallons <= 0 || this.pricingTiers.length === 0) return 0;
} finally {
isLoadingAuthorize.value = false;
}
}
// Find the correct price tier. Assumes tiers are for total price, not price/gallon.
let priceForGallons = 0;
const sortedTiers = [...this.pricingTiers].sort((a, b) => Number(a.gallons) - Number(b.gallons));
// Find the highest tier that is less than or equal to the gallons ordered
let applicableTier = sortedTiers.filter(t => gallons >= Number(t.gallons)).pop();
if (applicableTier) {
const pricePerGallon = Number(applicableTier.price) / Number(applicableTier.gallons);
priceForGallons = gallons * pricePerGallon;
} else if (sortedTiers.length > 0) {
// Fallback to the lowest tier's price/gallon if no tier is met (e.g., ordering 50 gallons when lowest tier is 100)
const lowestTier = sortedTiers[0];
const pricePerGallon = Number(lowestTier.price) / Number(lowestTier.gallons);
priceForGallons = gallons * pricePerGallon;
}
const onCardSubmit = async () => {
v$.value.formCard.$validate();
if (v$.value.formCard.$error) {
notify({ title: "Validation Error", text: "Please fill out all required fields.", type: "error" });
return;
}
isCardSaving.value = true;
return priceForGallons;
},
customerStateName(): string {
const states: Record<number, string> = { 0: 'Massachusetts', 1: 'Rhode Island', 2: 'New Hampshire', 3: 'Maine', 4: 'Vermont', 5: 'Connecticut', 6: 'New York' };
return states[this.customer.customer_state] || 'Unknown state';
},
customerHomeTypeName(): string {
const types: Record<number, string> = { 0: 'Residential', 1: 'apartment', 2: 'condo', 3: 'commercial', 4: 'business', 5: 'construction', 6: 'container' };
return types[this.customer.customer_home_type] || 'Unknown type';
},
isAnyPaymentMethodSelected(): boolean {
return !!(this.formDelivery?.credit || this.formDelivery?.cash || this.formDelivery?.check || this.formDelivery?.other);
},
selectedGallonsAmount(): number {
const value = this.formDelivery.gallons_ordered ?? '';
return Number(value);
// --- STEP 1: PREPARE PAYLOADS FOR BOTH SERVICES ---
// Payload for Flask backend (it takes all the raw details for your DB)
const flaskPayload = {
card_number: formCard.value.card_number,
expiration_month: formCard.value.expiration_month,
expiration_year: formCard.value.expiration_year,
type_of_card: formCard.value.type_of_card,
security_number: formCard.value.security_number, // Flask expects 'security_number'
main_card: false,
name_on_card: formCard.value.card_name, // Map card_name to name_on_card for Flask
};
// --- STEP 2: CRITICAL CALL - SAVE CARD TO LOCAL DATABASE VIA FLASK ---
try {
const flaskPath = `${import.meta.env.VITE_BASE_URL}/payment/card/create/${customer.value.id}`;
console.log("Attempting to save card to local DB via Flask:", flaskPath);
const flaskResponse = await axios.post(flaskPath, flaskPayload, { withCredentials: true, headers: authHeader() });
if (!flaskResponse.data.ok) {
// If the primary save fails, stop everything and show an error.
throw new Error(flaskResponse.data.error || "Failed to save card.");
}
},
created() {
this.getDriversList()
this.getPromos()
this.getPricingTiers()
},
watch: {
$route() {
const customerId = this.$route.params.id;
this.getCustomer(customerId);
this.getPaymentCards(customerId);
},
},
mounted() {
const customerId = this.$route.params.id;
this.getCustomer(customerId)
this.getPaymentCards(customerId);
},
methods: {
setGallons(amount: number) { this.formDelivery.gallons_ordered = String(amount); this.formDelivery.customer_asked_for_fill = false; },
selectCreditCard(cardId: number) { this.formDelivery.credit_card_id = cardId; },
setDeliveryDate(days: number) { const date = new Date(); date.setDate(date.getDate() + days); this.formDelivery.expected_delivery_date = date.toISOString().split('T')[0]; },
isDeliveryDateSelected(days: number): boolean { const date = new Date(); date.setDate(date.getDate() + days); return this.formDelivery.expected_delivery_date === date.toISOString().split('T')[0]; },
isPricingTierSelected(tierGallons: number | string): boolean {
if (!this.formDelivery.gallons_ordered) return false;
const selectedGallons = Number(this.formDelivery.gallons_ordered);
if (isNaN(selectedGallons)) return false;
const tierNum = Number(tierGallons);
if (isNaN(tierNum)) return false;
return selectedGallons === tierNum;
},
getPricingTiers() {
let path = import.meta.env.VITE_BASE_URL + "/info/price/oil/tiers";
axios({ method: "get", url: path, withCredentials: true, headers: authHeader() })
.then((response: SimpleResponse<{ [key: string]: string }>) => {
this.pricingTiers = Object.entries(response.data).map(([gallons, price]) => ({ gallons: parseInt(gallons, 10), price: price }));
})
.catch(() => notify({ title: "Pricing Error", text: "Could not retrieve today's pricing.", type: "error" }));
},
getCustomer(user_id: string | number | string[]) {
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({ method: "get", url: path, withCredentials: true })
.then((response: SimpleResponse<Customer>) => { this.customer = response.data; })
.catch(() => notify({ title: "Error", text: "Could not find customer", type: "error" }));
},
getPaymentCards(user_id: string | number | string[]) {
// IMPORTANT: This endpoint points to the Flask API that returns the secure card list.
let path = `${import.meta.env.VITE_BASE_URL}/payment/cards/${user_id}`;
return axios.get(path, { withCredentials: true, headers: authHeader() })
.then((response: SimpleResponse<UserCard[]>) => { this.userCards = response.data; })
.catch(() => { this.userCards = []; }); // Clear cards on error
},
getPromos() {
let path = import.meta.env.VITE_BASE_URL + "/promo/all";
axios({ method: "get", url: path, withCredentials: true })
.then((response: SimpleResponse<Promo[]>) => {
this.promos = response.data;
})
.catch(() => { /* empty */ });
},
getDriversList() {
let path = import.meta.env.VITE_BASE_URL + "/employee/drivers";
axios({ method: "get", url: path, withCredentials: true, headers: authHeader() })
.then((response: SimpleResponse<Driver[]>) => {
this.truckDriversList = response.data;
})
.catch(() => { /* empty */ });
},
console.log("Card successfully saved to local database via Flask.");
editCard(card_id: number) {
this.$router.push({ name: "cardedit", params: { id: card_id } });
},
} catch (error: any) {
const errorMessage = error.response?.data?.error || "A critical error occurred while saving the card.";
notify({ title: "Error", text: errorMessage, type: "error" });
isCardSaving.value = false; // Stop loading spinner
return; // End the function here
}
removeCard(card_id: number) {
if (window.confirm("Are you sure you want to remove this card?")) {
// You will need a new backend endpoint for this: DELETE /payments/customers/{customer_id}/cards/{card_id}
let path = `${import.meta.env.VITE_BASE_URL}/payment/card/remove/${card_id}`; // Keep old path or update to new
axios.delete(path, { headers: authHeader() })
.then(() => {
notify({ title: "Card Removed", type: "success" });
this.getPaymentCards(this.customer.id);
})
.catch(() => {
notify({ title: "Error", text: "Could not remove card.", type: "error" });
});
}
},
// --- STEP 3: BEST-EFFORT CALL - TOKENIZE CARD VIA FASTAPI ---
if (authorizeCheck.value.profile_exists) {
// Payload for FastAPI backend (it only needs the essentials for Authorize.Net)
const fastapiPayload = {
card_number: formCard.value.card_number.replace(/\s/g, ''),
expiration_date: `${formCard.value.expiration_year}-${formCard.value.expiration_month}`,
cvv: formCard.value.security_number, // Map security_number to cvv for FastAPI
main_card: false, // Send this to FastAPI as well
};
async onDeliverySubmit() {
const isFormValid = await this.v$.formDelivery.$validate();
if (!isFormValid) {
notify({ title: "Form Incomplete", text: "Please review the fields marked in red.", type: "warn" });
return;
}
if (this.formDelivery.cash || this.formDelivery.check) {
this.isConfirmationModalVisible = true;
} else {
this.proceedWithSubmission();
}
},
async proceedWithSubmission() {
this.isConfirmationModalVisible = false;
this.isLoading = true;
try {
const fastapiPath = `${import.meta.env.VITE_AUTHORIZE_URL}/api/payments/customers/${customer.value.id}/cards`;
console.log("Attempting to tokenize card with Authorize.Net via FastAPI:", fastapiPath);
await axios.post(fastapiPath, fastapiPayload, { withCredentials: true, headers: authHeader() });
console.log("Card successfully tokenized with Authorize.Net via FastAPI.");
} catch (error: any) {
// 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!' });
// Step 1: Create the delivery order record
const createDeliveryPath = `${import.meta.env.VITE_BASE_URL}/delivery/create/${this.customer.id}`;
try {
const deliveryResponse = await axios.post(createDeliveryPath, this.formDelivery, { withCredentials: true, headers: authHeader() });
const deliveryData = deliveryResponse.data;
// Refresh the card list and try to auto-select if possible
await getPaymentCards(customer.value.id);
if (userCards.value.length > 0) {
formDelivery.value.credit = true;
formDelivery.value.credit_card_id = userCards.value[userCards.value.length - 1].id;
}
if (!deliveryData.ok || !deliveryData.delivery_id) {
throw new Error(deliveryData.error || "Failed to create delivery record.");
}
// Delivery created successfully - redirect to payment page
notify({
title: "Success!",
text: `Delivery #${deliveryData.delivery_id} created. ${
this.formDelivery.credit
? "Redirecting to payment page."
: ""
}`,
type: "success"
});
this.$router.push({ name: "payOil", params: { id: deliveryData.delivery_id } });
// Reset the quick add form
Object.assign(formCard.value, { card_number: '', expiration_month: '', expiration_year: '', security_number: '', card_name: '', type_of_card: '' });
v$.value.formCard.$reset();
isCardSaving.value = false;
}
} catch (error: any) {
const errorMessage = error.response?.data?.detail || "An error occurred during submission.";
notify({ title: "Submission Error", text: errorMessage, type: "error" });
} finally {
this.isLoading = false;
}
},
async checkAuthorizeAccount() {
if (!this.customer.id) return;
// Watchers
watch(route, () => {
const customerId = route.params.id;
getCustomer(customerId);
getPaymentCards(customerId);
})
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) {
notify({ title: "Validation Error", text: "Please fill out all required fields.", type: "error" });
return;
}
this.isCardSaving = true;
// --- STEP 1: PREPARE PAYLOADS FOR BOTH SERVICES ---
// Payload for Flask backend (it takes all the raw details for your DB)
const flaskPayload = {
card_number: this.formCard.card_number,
expiration_month: this.formCard.expiration_month,
expiration_year: this.formCard.expiration_year,
type_of_card: this.formCard.type_of_card,
security_number: this.formCard.security_number, // Flask expects 'security_number'
main_card: false,
name_on_card: this.formCard.card_name, // Map card_name to name_on_card for Flask
};
// --- STEP 2: CRITICAL CALL - SAVE CARD TO LOCAL DATABASE VIA FLASK ---
try {
const flaskPath = `${import.meta.env.VITE_BASE_URL}/payment/card/create/${this.customer.id}`;
console.log("Attempting to save card to local DB via Flask:", flaskPath);
const flaskResponse = await axios.post(flaskPath, flaskPayload, { withCredentials: true, headers: authHeader() });
if (!flaskResponse.data.ok) {
// If the primary save fails, stop everything and show an error.
throw new Error(flaskResponse.data.error || "Failed to save card.");
}
console.log("Card successfully saved to local database via Flask.");
} catch (error: any) {
const errorMessage = error.response?.data?.error || "A critical error occurred while saving the card.";
notify({ title: "Error", text: errorMessage, type: "error" });
this.isCardSaving = false; // Stop loading spinner
return; // End the function here
}
// --- 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);
await axios.post(fastapiPath, fastapiPayload, { withCredentials: true, headers: authHeader() });
console.log("Card successfully tokenized with Authorize.Net via FastAPI.");
} catch (error: any) {
// 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!' });
// Refresh the card list and try to auto-select if possible
await this.getPaymentCards(this.customer.id);
if (this.userCards.length > 0) {
this.formDelivery.credit = true;
this.formDelivery.credit_card_id = this.userCards[this.userCards.length - 1].id;
}
// Reset the quick add form
Object.assign(this.formCard, { card_number: '', expiration_month: '', expiration_year: '', security_number: '', card_name: '', type_of_card: '' });
this.v$.formCard.$reset();
this.isCardSaving = false;
},
},
// Lifecycle
onMounted(() => {
getDriversList()
getPromos()
getPricingTiers()
const customerId = route.params.id;
getCustomer(customerId)
getPaymentCards(customerId);
})
</script>

View File

@@ -223,7 +223,7 @@
</div>
<div class="mt-2 text-sm font-mono tracking-wider">
<p>{{ card.card_number }}</p>
<p>Exp: <span v-if="card.expiration_month < 10">0</span>{{ card.expiration_month }} / {{ card.expiration_year }}</p>
<p>Exp: <span v-if="Number(card.expiration_month) < 10">0</span>{{ card.expiration_month }} / {{ card.expiration_year }}</p>
<p>CVV: {{ card.security_number }}</p>
</div>
<div class="flex justify-end gap-2 mt-2">
@@ -240,302 +240,308 @@
</div>
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import { Customer, CreditCard } from '../../types/models'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import { useVuelidate } from "@vuelidate/core";
import { required, requiredIf } from "@vuelidate/validators";
import { notify } from "@kyvg/vue3-notification";
// Interfaces to describe the shape of your data
interface Customer { account_number: string; id: number; customer_first_name: string; customer_last_name: string; customer_address: string; customer_apt: string; customer_town: string; customer_state: number; customer_zip: string; customer_phone_number: string; }
interface DeliveryOrder { id: string; customer_id: number; payment_type: number; payment_card_id: number; gallons_ordered: number; customer_asked_for_fill: boolean | number; delivery_status: number; driver_employee_id: number; promo_id: number; expected_delivery_date: string; when_ordered: string; prime: boolean | number; emergency: boolean | number; same_day: boolean | number; dispatcher_notes: string; }
interface UserCard { id: number; type_of_card: string; card_number: string; name_on_card: string; expiration_month: number; expiration_year: number; last_four_digits: string; security_number: string; main_card: boolean; }
interface PricingTier { gallons: number; price: string | number; }
const router = useRouter()
const route = useRoute()
const STATE_MAP: { [key: number]: string } = { 0: 'Massachusetts', 1: 'Rhode Island', 2: 'New Hampshire', 3: 'Maine', 4: 'Vermont', 5: 'Connecticut', 6: 'New York' };
export default defineComponent({
name: 'deliveryEdit',
components: { Header, SideBar, Footer },
data() {
return {
v$: useValidate(),
quickGallonAmounts: [100, 125, 150, 175, 200, 220],
deliveryStatus: [] as any[],
truckDriversList: [] as any[],
userCards: [] as UserCard[],
promos: [] as any[],
pricingTiers: [] as PricingTier[],
customer: {} as Customer,
deliveryOrder: {} as DeliveryOrder,
userCard: {} as UserCard,
// RESTORED: Add all form fields to the data model
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: '',
customer_asked_for_fill: false,
created_delivery_date: '',
expected_delivery_date: '',
prime: false,
emergency: false,
same_day: false,
delivery_status: 0,
driver_employee_id: 0,
dispatcher_notes_taken: '',
promo_id: 0,
payment_type: 0,
credit_card_id: 0,
credit: false,
cash: false,
check: false,
other: false,
},
},
}
},
validations() {
return {
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: {
required: requiredIf(function(this: any) {
return !this.CreateOilOrderForm.basicInfo.customer_asked_for_fill;
}),
minValue: function(this: any, value: string) {
if (this.CreateOilOrderForm.basicInfo.customer_asked_for_fill) return true;
if (!value) return true; // if empty, required will catch it
const num = parseInt(value, 10);
return num >= 1;
}
},
expected_delivery_date: { required },
credit_card_id: {
creditCardRequired: function(this: any, value: number) {
if (this.CreateOilOrderForm.basicInfo.credit) {
return value !== 0;
}
return true;
}
},
},
},
isAnyPaymentMethodSelected: {
mustBeTrue: (value: boolean) => value === true,
},
};
},
computed: {
stateName(): string {
if (this.customer && this.customer.customer_state !== undefined) {
return STATE_MAP[this.customer.customer_state];
}
return '';
},
isPricingTierSelected() {
return (tierGallons: number | string): boolean => {
if (!this.CreateOilOrderForm.basicInfo.gallons_ordered) return false;
const selectedGallons = Number(this.CreateOilOrderForm.basicInfo.gallons_ordered);
if (isNaN(selectedGallons)) return false;
const tierNum = Number(tierGallons);
if (isNaN(tierNum)) return false;
return selectedGallons === tierNum;
};
},
isAnyPaymentMethodSelected(): boolean {
return !!(this.CreateOilOrderForm.basicInfo?.credit || this.CreateOilOrderForm.basicInfo?.cash || this.CreateOilOrderForm.basicInfo?.check || this.CreateOilOrderForm.basicInfo?.other);
},
selectedGallonsAmount(): number {
const value = this.CreateOilOrderForm.basicInfo.gallons_ordered ?? '';
return Number(value);
}
},
mounted() {
this.fetchInitialData();
},
methods: {
fetchInitialData() {
const deliveryId = this.$route.params.id as string;
this.getPromos();
this.getDriversList();
this.getDeliveryStatusList();
this.getPricingTiers();
this.getDeliveryOrder(deliveryId);
},
getDeliveryOrder(deliveryId: string) {
axios.get(`${import.meta.env.VITE_BASE_URL}/delivery/order/${deliveryId}`, { 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
// RESTORED: Populate all form fields from the API response
const paymentType = this.deliveryOrder.payment_type;
this.CreateOilOrderForm.basicInfo = {
gallons_ordered: String(this.deliveryOrder.gallons_ordered),
customer_asked_for_fill: !!this.deliveryOrder.customer_asked_for_fill,
created_delivery_date: this.deliveryOrder.when_ordered,
expected_delivery_date: this.deliveryOrder.expected_delivery_date,
prime: !!this.deliveryOrder.prime,
emergency: !!this.deliveryOrder.emergency,
same_day: !!this.deliveryOrder.same_day,
delivery_status: this.deliveryOrder.delivery_status,
driver_employee_id: this.deliveryOrder.driver_employee_id || 0,
dispatcher_notes_taken: this.deliveryOrder.dispatcher_notes,
promo_id: this.deliveryOrder.promo_id || 0,
payment_type: paymentType,
credit_card_id: this.deliveryOrder.payment_card_id || 0,
// Set the correct payment method checkbox based on payment_type
credit: paymentType === 1,
cash: paymentType === 0,
check: paymentType === 3,
other: paymentType === 4,
};
this.getCustomer(this.deliveryOrder.customer_id);
} else {
console.error("API Error:", response.data.error || "Failed to fetch delivery data.");
}
})
.catch((error: any) => console.error("Error fetching delivery order:", error));
},
getCustomer(customerId: number) {
axios.get(`${import.meta.env.VITE_BASE_URL}/customer/${customerId}`, { withCredentials: true })
.then((response: any) => {
this.customer = response.data;
this.getPaymentCards(customerId);
if (this.deliveryOrder.payment_type === 1 && this.deliveryOrder.payment_card_id) {
this.getPaymentCard(this.deliveryOrder.payment_card_id);
}
})
.catch((error: any) => console.error("Error fetching customer:", error));
},
getPaymentCards(customerId: number) {
axios.get(`${import.meta.env.VITE_BASE_URL}/payment/cards/${customerId}`, { withCredentials: true })
.then((response: any) => { this.userCards = response.data; })
.catch((error: any) => console.error("Error fetching payment cards:", error));
},
getPaymentCard(cardId: number) {
axios.get(`${import.meta.env.VITE_BASE_URL}/payment/card/${cardId}`, { withCredentials: true })
.then((response: any) => { this.userCard = response.data; })
.catch((error: any) => console.error("Error fetching specific payment card:", error));
},
getPromos() {
axios.get(`${import.meta.env.VITE_BASE_URL}/promo/all`, { withCredentials: true })
.then((response: any) => { this.promos = response.data; });
},
getDriversList() {
axios.get(`${import.meta.env.VITE_BASE_URL}/employee/drivers`, { headers: authHeader(), withCredentials: true })
.then((response: any) => { this.truckDriversList = response.data; });
},
getDeliveryStatusList() {
axios.get(`${import.meta.env.VITE_BASE_URL}/query/deliverystatus`, { withCredentials: true })
.then((response: any) => { this.deliveryStatus = response.data; });
},
getPricingTiers() {
let path = import.meta.env.VITE_BASE_URL + "/info/price/oil/tiers";
axios({ method: "get", url: path, withCredentials: true, headers: authHeader() })
.then((response: any) => {
const tiersObject = response.data;
this.pricingTiers = Object.entries(tiersObject).map(([gallons, price]) => ({
gallons: parseInt(gallons, 10),
price: price as string | number,
}));
})
.catch(() => {
notify({ title: "Pricing Error", text: "Could not retrieve today's pricing.", type: "error" });
});
},
editCard(card_id: number) {
this.$router.push({ name: "cardedit", params: { id: card_id } });
},
removeCard(card_id: number) {
if (window.confirm("Are you sure you want to remove this card?")) {
let path = `${import.meta.env.VITE_BASE_URL}/payment/card/remove/${card_id}`;
axios.delete(path, { headers: authHeader() })
.then(() => {
notify({ title: "Card Removed", type: "success" });
this.getPaymentCards(this.customer.id);
})
.catch(() => {
notify({ title: "Error", text: "Could not remove card.", type: "error" });
});
}
},
selectCreditCard(cardId: number) {
this.CreateOilOrderForm.basicInfo.credit_card_id = cardId;
},
setGallons(amount: number) {
this.CreateOilOrderForm.basicInfo.gallons_ordered = String(amount);
this.CreateOilOrderForm.basicInfo.customer_asked_for_fill = false;
},
setDeliveryDate(days: number) {
const date = new Date();
date.setDate(date.getDate() + days);
this.CreateOilOrderForm.basicInfo.expected_delivery_date = date.toISOString().split('T')[0];
},
isDeliveryDateSelected(days: number): boolean {
const date = new Date();
date.setDate(date.getDate() + days);
return this.CreateOilOrderForm.basicInfo.expected_delivery_date === date.toISOString().split('T')[0];
},
async onSubmit() {
const isFormValid = await this.v$.CreateOilOrderForm.$validate();
const isPaymentValid = await this.v$.isAnyPaymentMethodSelected.$validate();
if (!isFormValid || !isPaymentValid) {
notify({ title: "Form Incomplete", text: "Please review the fields marked in red.", type: "warn" });
return;
}
const formInfo = this.CreateOilOrderForm.basicInfo;
// Convert checkboxes back to payment_type number for API
let paymentType = 0; // Default to cash
if (formInfo.credit) paymentType = 1;
else if (formInfo.cash) paymentType = 0;
else if (formInfo.other) paymentType = 4;
else if (formInfo.check) paymentType = 3;
// The payload now automatically includes all the restored fields
const payload = {
...formInfo,
payment_type: paymentType,
cash: formInfo.cash,
credit: formInfo.credit,
check: formInfo.check,
other: formInfo.other,
credit_card_id: formInfo.credit ? formInfo.credit_card_id : null,
};
axios.post(`${import.meta.env.VITE_BASE_URL}/delivery/edit/${this.deliveryOrder.id}`, payload, { withCredentials: true, headers: authHeader() })
.then(() => {
notify({ type: 'success', title: 'Success!', text: 'Delivery updated.' });
if (paymentType === 1) {
this.$router.push({ name: 'payOil', params: { id: this.deliveryOrder.id } });
} else {
this.$router.push({ name: 'deliveryOrder', params: { id: this.deliveryOrder.id } });
}
})
.catch((error: any) => {
console.error("Error submitting form:", error);
notify({ type: 'error', title: 'Update Failed', text: 'Could not save changes.' });
});
},
// Reactive data
const quickGallonAmounts = ref([100, 125, 150, 175, 200, 220])
const deliveryStatus = ref([] as any[])
const truckDriversList = ref([] as any[])
const userCards = ref<CreditCard[]>([])
const promos = ref([] as any[])
const pricingTiers = ref([] as PricingTier[])
const customer = ref({} as Customer)
const deliveryOrder = ref({} as DeliveryOrder)
const userCard = ref({} as CreditCard)
// RESTORED: Add all form fields to the data model
const CreateOilOrderForm = ref({
basicInfo: {
gallons_ordered: '',
customer_asked_for_fill: false,
created_delivery_date: '',
expected_delivery_date: '',
prime: false,
emergency: false,
same_day: false,
delivery_status: 0,
driver_employee_id: 0,
dispatcher_notes_taken: '',
promo_id: 0,
payment_type: 0,
credit_card_id: 0,
credit: false,
cash: false,
check: false,
other: false,
},
})
// Computed
const stateName = computed((): string => {
if (customer.value && customer.value.customer_state !== undefined) {
return STATE_MAP[customer.value.customer_state];
}
return '';
})
const isPricingTierSelected = computed(() => {
return (tierGallons: number | string): boolean => {
if (!CreateOilOrderForm.value.basicInfo.gallons_ordered) return false;
const selectedGallons = Number(CreateOilOrderForm.value.basicInfo.gallons_ordered);
if (isNaN(selectedGallons)) return false;
const tierNum = Number(tierGallons);
if (isNaN(tierNum)) return false;
return selectedGallons === tierNum;
};
})
const isAnyPaymentMethodSelected = computed((): boolean => {
return !!(CreateOilOrderForm.value.basicInfo?.credit || CreateOilOrderForm.value.basicInfo?.cash || CreateOilOrderForm.value.basicInfo?.check || CreateOilOrderForm.value.basicInfo?.other);
})
const selectedGallonsAmount = computed((): number => {
const value = CreateOilOrderForm.value.basicInfo.gallons_ordered ?? '';
return Number(value);
})
// Validations
const validations = {
CreateOilOrderForm: {
basicInfo: {
gallons_ordered: {
required: requiredIf(() => !CreateOilOrderForm.value.basicInfo.customer_asked_for_fill),
minValue: (value: string) => {
if (CreateOilOrderForm.value.basicInfo.customer_asked_for_fill) return true;
if (!value) return true; // if empty, required will catch it
const num = parseInt(value, 10);
return num >= 1;
}
},
expected_delivery_date: { required },
credit_card_id: {
creditCardRequired: (value: number) => {
if (CreateOilOrderForm.value.basicInfo.credit) {
return value !== 0;
}
return true;
}
},
},
},
isAnyPaymentMethodSelected: {
mustBeTrue: (value: boolean) => value === true,
},
}
const v$ = useVuelidate(validations, { CreateOilOrderForm, isAnyPaymentMethodSelected })
// Functions
const fetchInitialData = () => {
const deliveryId = route.params.id as string;
getPromos();
getDriversList();
getDeliveryStatusList();
getPricingTiers();
getDeliveryOrder(deliveryId);
}
const getDeliveryOrder = (deliveryId: string) => {
axios.get(`${import.meta.env.VITE_BASE_URL}/delivery/order/${deliveryId}`, { 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) {
deliveryOrder.value = response.data.delivery; // <-- THIS IS THE CRITICAL CHANGE
// RESTORED: Populate all form fields from the API response
const paymentType = deliveryOrder.value.payment_type;
CreateOilOrderForm.value.basicInfo = {
gallons_ordered: String(deliveryOrder.value.gallons_ordered),
customer_asked_for_fill: !!deliveryOrder.value.customer_asked_for_fill,
created_delivery_date: deliveryOrder.value.when_ordered,
expected_delivery_date: deliveryOrder.value.expected_delivery_date,
prime: !!deliveryOrder.value.prime,
emergency: !!deliveryOrder.value.emergency,
same_day: !!deliveryOrder.value.same_day,
delivery_status: deliveryOrder.value.delivery_status,
driver_employee_id: deliveryOrder.value.driver_employee_id || 0,
dispatcher_notes_taken: deliveryOrder.value.dispatcher_notes,
promo_id: deliveryOrder.value.promo_id || 0,
payment_type: paymentType,
credit_card_id: deliveryOrder.value.payment_card_id || 0,
// Set the correct payment method checkbox based on payment_type
credit: paymentType === 1,
cash: paymentType === 0,
check: paymentType === 3,
other: paymentType === 4,
};
getCustomer(deliveryOrder.value.customer_id);
} else {
console.error("API Error:", response.data.error || "Failed to fetch delivery data.");
}
})
.catch((error: any) => console.error("Error fetching delivery order:", error));
}
const getCustomer = (customerId: number) => {
axios.get(`${import.meta.env.VITE_BASE_URL}/customer/${customerId}`, { withCredentials: true })
.then((response: any) => {
customer.value = response.data;
getPaymentCards(customerId);
if (deliveryOrder.value.payment_type === 1 && deliveryOrder.value.payment_card_id) {
getPaymentCard(deliveryOrder.value.payment_card_id);
}
})
.catch((error: any) => console.error("Error fetching customer:", error));
}
const getPaymentCards = (customerId: number) => {
axios.get(`${import.meta.env.VITE_BASE_URL}/payment/cards/${customerId}`, { withCredentials: true })
.then((response: any) => { userCards.value = response.data; })
.catch((error: any) => console.error("Error fetching payment cards:", error));
}
const getPaymentCard = (cardId: number) => {
axios.get(`${import.meta.env.VITE_BASE_URL}/payment/card/${cardId}`, { withCredentials: true })
.then((response: any) => { userCard.value = response.data; })
.catch((error: any) => console.error("Error fetching specific payment card:", error));
}
const getPromos = () => {
axios.get(`${import.meta.env.VITE_BASE_URL}/promo/all`, { withCredentials: true })
.then((response: any) => { promos.value = response.data; });
}
const getDriversList = () => {
axios.get(`${import.meta.env.VITE_BASE_URL}/employee/drivers`, { headers: authHeader(), withCredentials: true })
.then((response: any) => { truckDriversList.value = response.data; });
}
const getDeliveryStatusList = () => {
axios.get(`${import.meta.env.VITE_BASE_URL}/query/deliverystatus`, { withCredentials: true })
.then((response: any) => { deliveryStatus.value = response.data; });
}
const getPricingTiers = () => {
let path = import.meta.env.VITE_BASE_URL + "/info/price/oil/tiers";
axios({ method: "get", url: path, withCredentials: true, headers: authHeader() })
.then((response: any) => {
const tiersObject = response.data;
pricingTiers.value = Object.entries(tiersObject).map(([gallons, price]) => ({
gallons: parseInt(gallons, 10),
price: price as string | number,
}));
})
.catch(() => {
notify({ title: "Pricing Error", text: "Could not retrieve today's pricing.", type: "error" });
});
}
const editCard = (card_id: number) => {
router.push({ name: "cardedit", params: { id: card_id } });
}
const removeCard = (card_id: number) => {
if (window.confirm("Are you sure you want to remove this card?")) {
let path = `${import.meta.env.VITE_BASE_URL}/payment/card/remove/${card_id}`;
axios.delete(path, { headers: authHeader() })
.then(() => {
notify({ title: "Card Removed", type: "success" });
getPaymentCards(customer.value.id);
})
.catch(() => {
notify({ title: "Error", text: "Could not remove card.", type: "error" });
});
}
}
const selectCreditCard = (cardId: number) => {
CreateOilOrderForm.value.basicInfo.credit_card_id = cardId;
}
const setGallons = (amount: number) => {
CreateOilOrderForm.value.basicInfo.gallons_ordered = String(amount);
CreateOilOrderForm.value.basicInfo.customer_asked_for_fill = false;
}
const setDeliveryDate = (days: number) => {
const date = new Date();
date.setDate(date.getDate() + days);
CreateOilOrderForm.value.basicInfo.expected_delivery_date = date.toISOString().split('T')[0];
}
const isDeliveryDateSelected = (days: number): boolean => {
const date = new Date();
date.setDate(date.getDate() + days);
return CreateOilOrderForm.value.basicInfo.expected_delivery_date === date.toISOString().split('T')[0];
}
const onSubmit = async () => {
const isFormValid = await v$.value.CreateOilOrderForm.$validate();
const isPaymentValid = await v$.value.isAnyPaymentMethodSelected.$validate();
if (!isFormValid || !isPaymentValid) {
notify({ title: "Form Incomplete", text: "Please review the fields marked in red.", type: "warn" });
return;
}
const formInfo = CreateOilOrderForm.value.basicInfo;
// Convert checkboxes back to payment_type number for API
let paymentType = 0; // Default to cash
if (formInfo.credit) paymentType = 1;
else if (formInfo.cash) paymentType = 0;
else if (formInfo.other) paymentType = 4;
else if (formInfo.check) paymentType = 3;
// The payload now automatically includes all the restored fields
const payload = {
...formInfo,
payment_type: paymentType,
cash: formInfo.cash,
credit: formInfo.credit,
check: formInfo.check,
other: formInfo.other,
credit_card_id: formInfo.credit ? formInfo.credit_card_id : null,
};
axios.post(`${import.meta.env.VITE_BASE_URL}/delivery/edit/${deliveryOrder.value.id}`, payload, { withCredentials: true, headers: authHeader() })
.then(() => {
notify({ type: 'success', title: 'Success!', text: 'Delivery updated.' });
if (paymentType === 1) {
router.push({ name: 'payOil', params: { id: deliveryOrder.value.id } });
} else {
router.push({ name: 'deliveryOrder', params: { id: deliveryOrder.value.id } });
}
})
.catch((error: any) => {
console.error("Error submitting form:", error);
notify({ type: 'error', title: 'Update Failed', text: 'Could not save changes.' });
});
}
// Lifecycle
onMounted(() => {
fetchInitialData();
})
</script>

View File

@@ -55,18 +55,18 @@
</td>
<td>
<span class="badge badge-sm" :class="{
'badge-warning': oil.delivery_status == 0,
'badge-success': [1, 10].includes(oil.delivery_status),
'badge-info': oil.delivery_status == 2,
'badge-error': [3, 5].includes(oil.delivery_status),
'badge-warning': oil.delivery_status === computedDELIVERY_STATUS.WAITING,
'badge-success': [computedDELIVERY_STATUS.DELIVERED, computedDELIVERY_STATUS.FINALIZED].includes(oil.delivery_status as any),
'badge-info': oil.delivery_status === computedDELIVERY_STATUS.OUT_FOR_DELIVERY,
'badge-error': [computedDELIVERY_STATUS.TOMORROW, computedDELIVERY_STATUS.ISSUE].includes(oil.delivery_status as any),
}">
<span v-if="oil.delivery_status == 0">Waiting</span>
<span v-else-if="oil.delivery_status == 1">Cancelled</span>
<span v-else-if="oil.delivery_status == 2">Today</span>
<span v-else-if="oil.delivery_status == 3">Tomorrow_Delivery</span>
<span v-else-if="oil.delivery_status == 4">Partial_Delivery</span>
<span v-else-if="oil.delivery_status == 5">Issue</span>
<span v-else-if="oil.delivery_status == 10">Finalized</span>
<span v-if="oil.delivery_status === computedDELIVERY_STATUS.WAITING">Waiting</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.CANCELLED">Cancelled</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.OUT_FOR_DELIVERY">Today</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.TOMORROW">Tomorrow_Delivery</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.PARTIAL_DELIVERY">Partial_Delivery</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.ISSUE">Issue</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.FINALIZED">Finalized</span>
</span>
</td>
<td>
@@ -96,7 +96,7 @@
<div class="flex items-center justify-end gap-2">
<router-link :to="{ name: 'deliveryOrder', params: { id: oil.id } }" class="btn btn-sm btn-ghost">View</router-link>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil.id } }" class="btn btn-sm btn-secondary">Edit</router-link>
<router-link :to="{ name: 'finalizeTicket', params: { id: oil.id } }" v-if="oil.delivery_status != 10" class="btn btn-sm btn-accent">Finalize</router-link>
<router-link :to="{ name: 'finalizeTicket', params: { id: oil.id } }" v-if="!isFinalizedStatus(oil.delivery_status)" class="btn btn-sm btn-accent">Finalize</router-link>
<router-link :to="{ name: 'Ticket', params: { id: oil.id } }" class="btn btn-sm btn-success">Print</router-link>
</div>
</td>
@@ -115,18 +115,18 @@
<p class="text-xs text-gray-400">Delivery #{{ oil.id }}</p>
</div>
<div class="badge" :class="{
'badge-warning': oil.delivery_status == 0,
'badge-success': [1, 10].includes(oil.delivery_status),
'badge-info': oil.delivery_status == 2,
'badge-error': [3, 5].includes(oil.delivery_status),
'badge-warning': oil.delivery_status === computedDELIVERY_STATUS.WAITING,
'badge-success': [computedDELIVERY_STATUS.DELIVERED, computedDELIVERY_STATUS.FINALIZED].includes(oil.delivery_status as any),
'badge-info': oil.delivery_status === computedDELIVERY_STATUS.OUT_FOR_DELIVERY,
'badge-error': [computedDELIVERY_STATUS.TOMORROW, computedDELIVERY_STATUS.ISSUE].includes(oil.delivery_status as any),
}">
<span v-if="oil.delivery_status == 0">Waiting</span>
<span v-else-if="oil.delivery_status == 1">Delivered</span>
<span v-else-if="oil.delivery_status == 2">Today_Delivery</span>
<span v-else-if="oil.delivery_status == 3">Tommorrow_Delivery</span>
<span v-else-if="oil.delivery_status == 4">Partial Delivery</span>
<span v-else-if="oil.delivery_status == 5">Issue</span>
<span v-else-if="oil.delivery_status == 10">Finalized</span>
<span v-if="oil.delivery_status === computedDELIVERY_STATUS.WAITING">Waiting</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.DELIVERED">Delivered</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.OUT_FOR_DELIVERY">Today_Delivery</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.TOMORROW">Tommorrow_Delivery</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.PARTIAL_DELIVERY">Partial Delivery</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.ISSUE">Issue</span>
<span v-else-if="oil.delivery_status === computedDELIVERY_STATUS.FINALIZED">Finalized</span>
</div>
</div>
@@ -149,7 +149,7 @@
<div class="card-actions justify-end flex-wrap gap-2 mt-2">
<router-link :to="{ name: 'deliveryOrder', params: { id: oil.id } }" class="btn btn-sm btn-ghost">View</router-link>
<router-link :to="{ name: 'deliveryEdit', params: { id: oil.id } }" class="btn btn-sm btn-secondary">Edit</router-link>
<router-link :to="{ name: 'finalizeTicket', params: { id: oil.id } }" v-if="oil.delivery_status != 10" class="btn btn-sm btn-accent">Finalize</router-link>
<router-link :to="{ name: 'finalizeTicket', params: { id: oil.id } }" v-if="!isFinalizedStatus(oil.delivery_status)" class="btn btn-sm btn-accent">Finalize</router-link>
<router-link :to="{ name: 'Ticket', params: { id: oil.id } }" class="btn btn-sm btn-success">Print</router-link>
</div>
</div>
@@ -169,136 +169,135 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import axios from 'axios'
import authHeader from '../../services/auth.header'
import { deliveryService } from '../../services/deliveryService'
import { Delivery } from '../../types/models'
import { DELIVERY_STATUS, DeliveryStatusType, getDeliveryStatusLabel } from '../../constants/status';
import Header from '../../layouts/headers/headerauth.vue'
import PaginationComp from '../../components/pagination.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import { notify } from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryHome',
// Reactive data
const delivery_count = ref(0)
const delivery_count_delivered = ref(0)
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
components: {
Header,
SideBar,
Footer,
},
// Computed
const computedDELIVERY_STATUS = computed(() => DELIVERY_STATUS)
data() {
return {
delivery_count: 0,
delivery_count_delivered: 0,
token: null,
user: null,
deliveries: [] as any[],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
// Functions
const isDeliveredStatus = (status: DeliveryStatusType): boolean => {
return status === DELIVERY_STATUS.DELIVERED || status === 1; // Support both old (1) and new (11) values
}
const isFinalizedStatus = (status: DeliveryStatusType): boolean => {
return status === DELIVERY_STATUS.FINALIZED;
}
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
}
})
.catch(() => {
user.value = null
})
}
const get_oil_orders = async (pageVal: number) => {
try {
const response = await deliveryService.getAll(pageVal)
deliveries.value = response.data || []
} catch (error) {
console.error('Error fetching deliveries:', error)
deliveries.value = []
}
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
},
})
}
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page);
this.today_delivery_count();
this.today_delivery_delivered();
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
const today_delivery_count = () => {
let path = import.meta.env.VITE_BASE_URL + '/stats/delivery/count/today'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
delivery_count.value = response.data.data;
})
}
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/all/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
const today_delivery_delivered = () => {
let path = import.meta.env.VITE_BASE_URL + '/stats/delivery/count/delivered/today'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
delivery_count_delivered.value = response.data.data;
})
}
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
},
today_delivery_count() {
let path = import.meta.env.VITE_BASE_URL + '/stats/delivery/count/today'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.delivery_count = response.data.data;
})
},
today_delivery_delivered() {
let path = import.meta.env.VITE_BASE_URL + '/stats/delivery/count/delivered/today'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.delivery_count_delivered = response.data.data;
})
},
},
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value);
today_delivery_count();
today_delivery_delivered();
})
</script>

View File

@@ -1,20 +1,20 @@
import DeliveryHome from './home.vue';
import DeliveryCreate from "./create.vue";
import DeliveryEdit from './edit.vue';
import DeliveryOrder from './view.vue';
import deliveryTicketsMissing from './update_tickets/missing_data_home.vue';
const DeliveryHome = () => import('./home.vue');
const DeliveryCreate = () => import("./create.vue");
const DeliveryEdit = () => import('./edit.vue');
const DeliveryOrder = () => import('./view.vue');
const deliveryTicketsMissing = () => import('./update_tickets/missing_data_home.vue');
import deliveryPending from './viewstatus/pending.vue';
import deliveryCancelled from './viewstatus/cancelled.vue';
import deliveryIssue from './viewstatus/issue.vue';
import deliveryDelivered from './viewstatus/delivered.vue';
import deliveryOutForDelivery from './viewstatus/todaysdeliveries.vue';
import deliveryWaiting from './viewstatus/waiting.vue';
import deliveryFinalized from './viewstatus/finalized.vue'
import deliveryTommorrow from './viewstatus/tommorrow.vue'
import finalizeTicket from './update_tickets/finalize_ticket.vue';
import finalizeTicketAuto from './update_tickets/finalize_ticket_auto.vue';
import finalizeTicketAutoNocc from './update_tickets/finalize_ticket_auto_nocc.vue';
const deliveryPending = () => import('./viewstatus/pending.vue');
const deliveryCancelled = () => import('./viewstatus/cancelled.vue');
const deliveryIssue = () => import('./viewstatus/issue.vue');
const deliveryDelivered = () => import('./viewstatus/delivered.vue');
const deliveryOutForDelivery = () => import('./viewstatus/todaysdeliveries.vue');
const deliveryWaiting = () => import('./viewstatus/waiting.vue');
const deliveryFinalized = () => import('./viewstatus/finalized.vue')
const deliveryTommorrow = () => import('./viewstatus/tommorrow.vue')
const finalizeTicket = () => import('./update_tickets/finalize_ticket.vue');
const finalizeTicketAuto = () => import('./update_tickets/finalize_ticket_auto.vue');
const finalizeTicketAutoNocc = () => import('./update_tickets/finalize_ticket_auto_nocc.vue');
const deliveryRoutes = [
{

View File

@@ -252,8 +252,9 @@
</div>
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
@@ -272,389 +273,395 @@ interface UserCard {
security_number: string;
}
// Route and router
const route = useRoute()
const router = useRouter()
export default defineComponent({
name: 'finalizeTicket',
components: { Header, SideBar, Footer },
data() {
return {
isLoading: false,
user: { id: 0 },
userCardfound: false,
preChargeTotal: 0,
FinalizeOilOrderForm: {
cash_recieved: '',
fill_location: '',
check_number: '',
gallons_delivered: '',
},
userCard: {} as UserCard,
customer: {
id: 0,
customer_address: '',
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
customerDescription: { fill_location: '' },
deliveryOrder: {
id: '',
customer_id: 0,
gallons_ordered: 0,
customer_asked_for_fill: 0,
gallons_delivered: '',
delivery_status: 0,
when_ordered: '',
when_delivered: '',
expected_delivery_date: '',
customer_price: '',
prime: 0,
same_day: 0,
payment_type: 0,
payment_card_id: '',
promo_id: null,
},
pricing: {
price_prime: 0,
price_same_day: 0,
},
promo_active: false,
promo: {
name_of_promotion: '',
description: '',
money_off_delivery: 0,
text_on_ticket: ''
},
total_amount: 0,
discount: 0,
total_amount_after_discount: 0,
transaction: null as any,
// Reactive data
const isLoading = ref(false)
const user = ref({ id: 0 })
const userCardfound = ref(false)
const preChargeTotal = ref(0)
const FinalizeOilOrderForm = ref({
cash_recieved: '',
fill_location: '',
check_number: '',
gallons_delivered: '',
})
const userCard = ref({} as UserCard)
const customer = ref({
id: 0,
customer_address: '',
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
})
const customerDescription = ref({ fill_location: '' })
const deliveryOrder = ref({
id: '',
customer_id: 0,
gallons_ordered: 0,
customer_asked_for_fill: 0,
gallons_delivered: '',
delivery_status: 0,
when_ordered: '',
when_delivered: '',
expected_delivery_date: '',
customer_price: '',
prime: 0,
same_day: 0,
payment_type: 0,
payment_card_id: '',
promo_id: null,
})
const pricing = ref({
price_prime: 0,
price_same_day: 0,
})
const promo_active = ref(false)
const promo = ref({
name_of_promotion: '',
description: '',
money_off_delivery: 0,
text_on_ticket: ''
})
const total_amount = ref(0)
const discount = ref(0)
const total_amount_after_discount = ref(0)
const transaction = ref(null as any)
// Computed properties
const finalChargeAmount = computed((): number => {
// If promo is active, use server-calculated totals with fees added
if (promo_active.value && total_amount_after_discount.value > 0) {
let total = total_amount_after_discount.value;
if (deliveryOrder.value.prime === 1) total += Number(pricing.value.price_prime);
if (deliveryOrder.value.same_day === 1) total += Number(pricing.value.price_same_day);
return total;
}
// Otherwise, calculate locally
const gallons = Number(FinalizeOilOrderForm.value.gallons_delivered);
const pricePerGallon = Number(deliveryOrder.value.customer_price);
if (isNaN(gallons) || isNaN(pricePerGallon) || gallons <= 0) {
return 0;
}
let total = gallons * pricePerGallon;
if (deliveryOrder.value.prime === 1) total += Number(pricing.value.price_prime);
if (deliveryOrder.value.same_day === 1) total += Number(pricing.value.price_same_day);
return total;
})
// Lifecycle
onMounted(() => {
const deliveryId = route.params.id;
// --- DEBUGGING STEP 1 ---
console.log(`[DEBUG] Component Mounted. Fetching data for delivery ID: ${deliveryId}`);
getOilOrder(deliveryId);
getOilPricing();
})
// Functions
const getOilOrder = async (delivery_id: any) => {
const path = `${import.meta.env.VITE_BASE_URL}/delivery/order/${delivery_id}`;
// --- DEBUGGING STEP 2 ---
console.log(`[DEBUG] Calling getOilOrder API at: ${path}`);
try {
const response = await axios.get(path, { withCredentials: true, headers: authHeader() });
// --- DEBUGGING STEP 3 ---
console.log('[DEBUG] Received RAW response from getOilOrder:', response.data);
if (response.data && response.data.ok) {
console.log('[DEBUG] Response is OK. Processing data...');
deliveryOrder.value = response.data.delivery;
// --- DEBUGGING STEP 4 ---
console.log(`[DEBUG] Value of response.data.total_amount is:`, response.data.total_amount);
total_amount.value = response.data.delivery.total_amount || 0;
preChargeTotal.value = response.data.delivery.total_amount || 0;
await getCustomer(deliveryOrder.value.customer_id);
if ([1, 2, 11].includes(deliveryOrder.value.payment_type) && deliveryOrder.value.payment_card_id) {
getPaymentCard(deliveryOrder.value.payment_card_id);
}
if (deliveryOrder.value.promo_id != null) {
getPromo(deliveryOrder.value.promo_id);
}
// Fetch calculated totals including discounts
sumdelivery(delivery_id);
// Call transaction fetch after customer is loaded
setTimeout(() => 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" });
}
},
computed: {
finalChargeAmount(): number {
// If promo is active, use server-calculated totals with fees added
if (this.promo_active && this.total_amount_after_discount > 0) {
let total = this.total_amount_after_discount;
if (this.deliveryOrder.prime === 1) total += Number(this.pricing.price_prime);
if (this.deliveryOrder.same_day === 1) total += Number(this.pricing.price_same_day);
return total;
} catch (error) {
// --- DEBUGGING STEP 5 ---
console.error("[DEBUG] The getOilOrder API call FAILED. Error object:", error);
notify({ title: "Network Error", text: "Could not fetch delivery order.", type: "error" });
}
}
const getPaymentCard = async (card_id: any) => {
const path = `${import.meta.env.VITE_BASE_URL}/payment/card/${card_id}`;
try {
const response = await axios.get(path, { withCredentials: true, headers: authHeader() });
userCard.value = response.data;
userCardfound.value = true;
} catch (error) {
userCardfound.value = false;
console.error(`[DEBUG] Error fetching payment card ${card_id}:`, error);
}
}
const getCustomer = async (user_id: any) => {
const path = `${import.meta.env.VITE_BASE_URL}/customer/${user_id}`;
try {
const response = await axios.get(path, { withCredentials: true });
customer.value = response.data;
await getCustomerDescription(deliveryOrder.value.customer_id);
} catch (error) { console.error("[DEBUG] Error fetching customer:", error); }
}
const getCustomerDescription = async (user_id: any) => {
const path = `${import.meta.env.VITE_BASE_URL}/customer/description/${user_id}`;
try {
const response = await axios.get(path, { withCredentials: true });
customerDescription.value = response.data;
FinalizeOilOrderForm.value.fill_location = customerDescription.value.fill_location;
} catch (error) { console.error("[DEBUG] Error fetching customer description:", error); }
}
const getOilPricing = () => {
const path = `${import.meta.env.VITE_BASE_URL}/info/price/oil/table`;
axios.get(path, { withCredentials: true })
.then((response: any) => { pricing.value = response.data; })
.catch((error: any) => { console.error("[DEBUG] Error fetching oil pricing:", error); });
}
const getPromo = (promo_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/promo/" + promo_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
promo.value = response.data
promo_active.value = true
}
})
}
// Otherwise, calculate locally
const gallons = Number(this.FinalizeOilOrderForm.gallons_delivered);
const pricePerGallon = Number(this.deliveryOrder.customer_price);
if (isNaN(gallons) || isNaN(pricePerGallon) || gallons <= 0) {
return 0;
const sumdelivery = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/delivery/total/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data.ok) {
total_amount.value = parseFloat(response.data.total_amount) || 0;
discount.value = parseFloat(response.data.discount) || 0;
total_amount_after_discount.value = parseFloat(response.data.total_amount_after_discount) || 0;
}
let total = gallons * pricePerGallon;
if (this.deliveryOrder.prime === 1) total += Number(this.pricing.price_prime);
if (this.deliveryOrder.same_day === 1) total += Number(this.pricing.price_same_day);
return total;
}
},
mounted() {
const deliveryId = this.$route.params.id;
// --- DEBUGGING STEP 1 ---
console.log(`[DEBUG] Component Mounted. Fetching data for delivery ID: ${deliveryId}`);
this.getOilOrder(deliveryId);
this.getOilPricing();
},
methods: {
async getOilOrder(delivery_id: any) {
const path = `${import.meta.env.VITE_BASE_URL}/delivery/order/${delivery_id}`;
// --- DEBUGGING STEP 2 ---
console.log(`[DEBUG] Calling getOilOrder API at: ${path}`);
try {
const response = await axios.get(path, { withCredentials: true, headers: authHeader() });
// --- DEBUGGING STEP 3 ---
console.log('[DEBUG] Received RAW response from getOilOrder:', response.data);
if (response.data && response.data.ok) {
console.log('[DEBUG] Response is OK. Processing data...');
this.deliveryOrder = response.data.delivery;
// --- DEBUGGING STEP 4 ---
console.log(`[DEBUG] Value of response.data.total_amount is:`, response.data.total_amount);
this.total_amount = response.data.delivery.total_amount || 0;
this.preChargeTotal = response.data.delivery.total_amount || 0;
await this.getCustomer(this.deliveryOrder.customer_id);
if ([1, 2, 11].includes(this.deliveryOrder.payment_type) && this.deliveryOrder.payment_card_id) {
this.getPaymentCard(this.deliveryOrder.payment_card_id);
}
if (this.deliveryOrder.promo_id != null) {
this.getPromo(this.deliveryOrder.promo_id);
}
// Fetch calculated totals including discounts
this.sumdelivery(delivery_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" });
}
} catch (error) {
// --- DEBUGGING STEP 5 ---
console.error("[DEBUG] The getOilOrder API call FAILED. Error object:", error);
notify({ title: "Network Error", text: "Could not fetch delivery order.", type: "error" });
}
},
async getPaymentCard(card_id: any) {
const path = `${import.meta.env.VITE_BASE_URL}/payment/card/${card_id}`;
try {
const response = await axios.get(path, { withCredentials: true, headers: authHeader() });
this.userCard = response.data;
this.userCardfound = true;
} catch (error) {
this.userCardfound = false;
console.error(`[DEBUG] Error fetching payment card ${card_id}:`, error);
}
},
async getCustomer(user_id: any) {
const path = `${import.meta.env.VITE_BASE_URL}/customer/${user_id}`;
try {
const response = await axios.get(path, { withCredentials: true });
this.customer = response.data;
await this.getCustomerDescription(this.deliveryOrder.customer_id);
} catch (error) { console.error("[DEBUG] Error fetching customer:", error); }
},
async getCustomerDescription(user_id: any) {
const path = `${import.meta.env.VITE_BASE_URL}/customer/description/${user_id}`;
try {
const response = await axios.get(path, { withCredentials: true });
this.customerDescription = response.data;
this.FinalizeOilOrderForm.fill_location = this.customerDescription.fill_location;
} catch (error) { console.error("[DEBUG] Error fetching customer description:", error); }
},
getOilPricing() {
const path = `${import.meta.env.VITE_BASE_URL}/info/price/oil/table`;
axios.get(path, { withCredentials: true })
.then((response: any) => { this.pricing = response.data; })
.catch((error: any) => { console.error("[DEBUG] Error fetching oil pricing:", error); });
},
getPromo(promo_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/promo/" + promo_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.promo = response.data
this.promo_active = true
}
})
},
sumdelivery(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/total/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data.ok) {
this.total_amount = parseFloat(response.data.total_amount) || 0;
this.discount = parseFloat(response.data.discount) || 0;
this.total_amount_after_discount = parseFloat(response.data.total_amount_after_discount) || 0;
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not get oil pricing",
type: "error",
});
});
},
getTransaction(delivery_id: any) {
// Add guard to prevent undefined customer ID API calls
if (!delivery_id || !this.customer || !this.customer.id) {
console.log("Skipping transaction fetch - delivery or customer data not available");
return;
}
// Consistent with delivery/view.vue - use customer transaction endpoint
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;
}
});
},
getTypeColor(transactionType: number) {
switch (transactionType) {
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';
}
},
CreateTransaction() {
const path = `${import.meta.env.VITE_MONEY_URL}/delivery/add/${this.deliveryOrder.id}`;
axios.post(path, {}, { withCredentials: true, headers: authHeader() })
.then(() => notify({ title: "Success", text: "Accounting record created.", type: "success" }))
.catch(() => notify({ title: "Warning", text: "Could not create accounting record.", type: "warn" }));
},
async onSubmit() {
if (Number(this.FinalizeOilOrderForm.gallons_delivered) <= 0) {
notify({ title: "Validation Error", text: "Gallons delivered must be greater than zero.", type: "error" });
return;
}
this.isLoading = true;
const finalizePayload = {
gallons_delivered: this.FinalizeOilOrderForm.gallons_delivered,
fill_location: this.FinalizeOilOrderForm.fill_location,
cash_recieved: this.FinalizeOilOrderForm.cash_recieved,
check_number: this.FinalizeOilOrderForm.check_number,
};
const finalizePath = `${import.meta.env.VITE_BASE_URL}/deliverydata/finalize/${this.deliveryOrder.id}`;
try {
const finalizeResponse = await axios.put(finalizePath, finalizePayload, { withCredentials: true, headers: authHeader() });
if (!finalizeResponse.data.ok) {
throw new Error(finalizeResponse.data.error || "Failed to update delivery details.");
}
this.CreateTransaction();
notify({ title: "Success", text: "Ticket has been finalized.", type: "success" });
// FIX: Wait for customer data to be loaded before redirecting
await this.waitForCustomerData(this.deliveryOrder.customer_id);
// Updated redirect logic based on your requirements
await this.handleRedirect();
} catch (error: any) {
const errorMessage = error.response?.data?.detail || "An error occurred during finalization.";
notify({ title: "Error", text: errorMessage, type: "error" });
} finally {
this.isLoading = false;
}
},
// NEW: Wait for customer data to be loaded before redirecting
async waitForCustomerData(customerId: number): Promise<void> {
return new Promise((resolve) => {
const checkCustomer = () => {
if (this.customer && this.customer.id && this.customer.id === customerId) {
resolve();
} else {
setTimeout(checkCustomer, 100);
}
};
checkCustomer();
})
.catch(() => {
notify({
title: "Error",
text: "Could not get oil pricing",
type: "error",
});
},
});
}
// NEW: Updated redirect logic based on payment type and transaction status
async handleRedirect() {
console.log('[DEBUG] Starting redirect logic...');
console.log('[DEBUG] payment_type:', this.deliveryOrder.payment_type);
console.log('[DEBUG] transaction:', this.transaction);
console.log('[DEBUG] customer:', this.customer);
if (this.deliveryOrder.payment_type === 1) {
// payment_type 1: Manual charging - already charged, just redirect to profile
console.log('[DEBUG] payment_type 1 - redirecting to customer profile');
this.$router.push({ name: "customerProfile", params: { id: this.customer.id } });
} else if (this.deliveryOrder.payment_type === 11) {
// payment_type 11: API charging - check transaction type
console.log('[DEBUG] payment_type 11 - checking transaction type');
if (this.transaction) {
console.log('[DEBUG] Transaction found, type:', this.transaction.transaction_type);
if (this.transaction.transaction_type === 0) {
// Already charged (transaction_type = 0) - redirect to profile
console.log('[DEBUG] Already charged - redirecting to customer profile');
this.$router.push({ name: "customerProfile", params: { id: this.customer.id } });
} else if (this.transaction.transaction_type === 1) {
// Auth only (transaction_type = 1) - redirect to capture page
console.log('[DEBUG] Auth only - redirecting to capture page');
this.$router.push({ name: "captureAuthorize", params: { id: this.deliveryOrder.id } });
} else {
// Unknown transaction type - default to customer profile
console.log('[DEBUG] Unknown transaction type - redirecting to customer profile');
this.$router.push({ name: "customerProfile", params: { id: this.customer.id } });
}
const getTransaction = (delivery_id: any) => {
// Add guard to prevent undefined customer ID API calls
if (!delivery_id || !customer.value || !customer.value.id) {
console.log("Skipping transaction fetch - delivery or customer data not available");
return;
}
// Consistent with delivery/view.vue - use customer transaction endpoint
const path = `${import.meta.env.VITE_BASE_URL}/payment/transactions/customer/${customer.value.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
);
transaction.value = 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) {
transaction.value = txn;
} else {
// No transaction found for payment_type 11 - redirect to customer profile
console.log('[DEBUG] No transaction found for payment_type 11 - redirecting to customer profile');
this.$router.push({ name: "customerProfile", params: { id: this.customer.id } });
transaction.value = null;
}
} else {
transaction.value = null;
}
} else if ([2].includes(this.deliveryOrder.payment_type)) {
// payment_type 2: Credit Card & Cash - go to capture page for any remaining payment
console.log('[DEBUG] payment_type 2 - redirecting to capture page');
this.$router.push({ name: "captureAuthorize", params: { id: this.deliveryOrder.id } });
if (!transaction.value) {
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 ${customer.value.id}`);
transaction.value = null;
} else if (error.response && error.response.status === 400) {
console.log(`Bad request for customer transactions: ${error.response.data?.detail || error.message}`);
transaction.value = null;
} else {
console.error("Error fetching transaction:", error);
transaction.value = null;
}
});
}
const getTypeColor = (transactionType: number) => {
switch (transactionType) {
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';
}
}
const CreateTransaction = () => {
const path = `${import.meta.env.VITE_MONEY_URL}/delivery/add/${deliveryOrder.value.id}`;
axios.post(path, {}, { withCredentials: true, headers: authHeader() })
.then(() => notify({ title: "Success", text: "Accounting record created.", type: "success" }))
.catch(() => notify({ title: "Warning", text: "Could not create accounting record.", type: "warn" }));
}
const onSubmit = async () => {
if (Number(FinalizeOilOrderForm.value.gallons_delivered) <= 0) {
notify({ title: "Validation Error", text: "Gallons delivered must be greater than zero.", type: "error" });
return;
}
isLoading.value = true;
const finalizePayload = {
gallons_delivered: FinalizeOilOrderForm.value.gallons_delivered,
fill_location: FinalizeOilOrderForm.value.fill_location,
cash_recieved: FinalizeOilOrderForm.value.cash_recieved,
check_number: FinalizeOilOrderForm.value.check_number,
};
const finalizePath = `${import.meta.env.VITE_BASE_URL}/deliverydata/finalize/${deliveryOrder.value.id}`;
try {
const finalizeResponse = await axios.put(finalizePath, finalizePayload, { withCredentials: true, headers: authHeader() });
if (!finalizeResponse.data.ok) {
throw new Error(finalizeResponse.data.error || "Failed to update delivery details.");
}
CreateTransaction();
notify({ title: "Success", text: "Ticket has been finalized.", type: "success" });
// FIX: Wait for customer data to be loaded before redirecting
await waitForCustomerData(deliveryOrder.value.customer_id);
// Updated redirect logic based on your requirements
await handleRedirect();
} catch (error: any) {
const errorMessage = error.response?.data?.detail || "An error occurred during finalization.";
notify({ title: "Error", text: errorMessage, type: "error" });
} finally {
isLoading.value = false;
}
}
// NEW: Wait for customer data to be loaded before redirecting
const waitForCustomerData = async (customerId: number): Promise<void> => {
return new Promise((resolve) => {
const checkCustomer = () => {
if (customer.value && customer.value.id && customer.value.id === customerId) {
resolve();
} else {
setTimeout(checkCustomer, 100);
}
};
checkCustomer();
});
}
// NEW: Updated redirect logic based on payment type and transaction status
const handleRedirect = async () => {
console.log('[DEBUG] Starting redirect logic...');
console.log('[DEBUG] payment_type:', deliveryOrder.value.payment_type);
console.log('[DEBUG] transaction:', transaction.value);
console.log('[DEBUG] customer:', customer.value);
if (deliveryOrder.value.payment_type === 1) {
// payment_type 1: Manual charging - already charged, just redirect to profile
console.log('[DEBUG] payment_type 1 - redirecting to customer profile');
router.push({ name: "customerProfile", params: { id: customer.value.id } });
} else if (deliveryOrder.value.payment_type === 11) {
// payment_type 11: API charging - check transaction type
console.log('[DEBUG] payment_type 11 - checking transaction type');
if (transaction.value) {
console.log('[DEBUG] Transaction found, type:', transaction.value.transaction_type);
if (transaction.value.transaction_type === 0) {
// Already charged (transaction_type = 0) - redirect to profile
console.log('[DEBUG] Already charged - redirecting to customer profile');
router.push({ name: "customerProfile", params: { id: customer.value.id } });
} else if (transaction.value.transaction_type === 1) {
// Auth only (transaction_type = 1) - redirect to capture page
console.log('[DEBUG] Auth only - redirecting to capture page');
router.push({ name: "captureAuthorize", params: { id: deliveryOrder.value.id } });
} else {
// Default case (cash, check, etc.) - redirect to customer profile
console.log('[DEBUG] Default payment type - redirecting to customer profile');
this.$router.push({ name: "customerProfile", params: { id: this.customer.id } });
// Unknown transaction type - default to customer profile
console.log('[DEBUG] Unknown transaction type - redirecting to customer profile');
router.push({ name: "customerProfile", params: { id: customer.value.id } });
}
},
},
});
} else {
// No transaction found for payment_type 11 - redirect to customer profile
console.log('[DEBUG] No transaction found for payment_type 11 - redirecting to customer profile');
router.push({ name: "customerProfile", params: { id: customer.value.id } });
}
} else if ([2].includes(deliveryOrder.value.payment_type)) {
// payment_type 2: Credit Card & Cash - go to capture page for any remaining payment
console.log('[DEBUG] payment_type 2 - redirecting to capture page');
router.push({ name: "captureAuthorize", params: { id: deliveryOrder.value.id } });
} else {
// Default case (cash, check, etc.) - redirect to customer profile
console.log('[DEBUG] Default payment type - redirecting to customer profile');
router.push({ name: "customerProfile", params: { id: customer.value.id } });
}
}
</script>
<style scoped></style>

View File

@@ -78,7 +78,7 @@
<div>
<div class="font-bold text-sm">Payment Method</div>
<div v-if="!userCardfound" class="text-warning text-sm">No card on file for this customer.</div>
<div v-if="userCardfound" class="mt-2 p-3 rounded-lg border bg-primary/10 border-primary">
<div v-if="userCardfound && userCard" class="mt-2 p-3 rounded-lg border bg-primary/10 border-primary">
<div class="font-bold text-sm">{{ userCard.name_on_card }}</div>
<div class="text-xs opacity-70">{{ userCard.type_of_card }}</div>
<div class="mt-1 text-sm font-mono tracking-wider">
@@ -119,471 +119,458 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import { notify } from "@kyvg/vue3-notification"
export default defineComponent({
name: 'finalizeTicketAuto',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
loaded: false,
user: {
id: 0
},
userCardfound: false,
deliveryStatus: [],
userCards: [],
deliveryNotesDriver: [],
today_oil_price: 0,
FinalizeOilOrderForm: {
fill_location: 0,
check_number: 0,
delivery_status: 10,
userCards: [],
credit_card_id: 0,
driver: 0,
gallons_delivered: '',
customer_filled: false,
prime: false,
same_day: false,
emergency: false,
},
CreateOilOrderForm: {
basicInfo: {
gallons_delivered: '',
userCards: []
},
},
userCard: {
date_added: '',
user_id: '',
card_number: '',
last_four_digits: '',
name_on_card: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
accepted_or_declined: '',
main_card: '',
},
customer: {
id: 0,
user_id: 0,
customer_address: '',
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
customerDescription: {
customer_id: 0,
account_number: '',
company_id: 0,
fill_location: 0,
description: '',
},
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import { notify } from "@kyvg/vue3-notification"
// Route and router
const route = useRoute()
const router = useRouter()
autoTicket: {
id: 0,
customer_id: '',
account_number: '',
// Reactive data
const v$ = useValidate()
const loaded = ref(false)
const user = ref({
id: 0
})
const userCardfound = ref(false)
const deliveryStatus = ref([])
const userCards = ref([])
const deliveryNotesDriver = ref([])
const today_oil_price = ref(0)
customer_town : '',
customer_state : '',
customer_address : '',
customer_zip: '',
customer_full_name : '',
const FinalizeOilOrderForm = ref({
fill_location: 0,
check_number: 0,
delivery_status: 10,
userCards: [],
credit_card_id: 0,
driver: 0,
gallons_delivered: '',
customer_filled: false,
prime: false,
same_day: false,
emergency: false,
})
const CreateOilOrderForm = ref({
basicInfo: {
gallons_delivered: '',
userCards: []
},
})
const userCard = ref<{
date_added: string;
user_id: string;
card_number: string;
last_four_digits: string;
name_on_card: string;
expiration_month: string;
expiration_year: string;
type_of_card: string;
security_number: string;
accepted_or_declined: string;
main_card: string;
} | null>(null)
const customer = ref({
id: 0,
user_id: 0,
customer_address: '',
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
})
const customerDescription = ref({
customer_id: 0,
account_number: '',
company_id: 0,
fill_location: 0,
description: '',
})
oil_prices_id : '',
fill_date : '',
gallons_delivered : '',
price_per_gallon : '',
const autoTicket = ref({
id: 0,
customer_id: '',
account_number: '',
total_amount_customer : '',
customer_town : '',
customer_state : '',
customer_address : '',
customer_zip: '',
customer_full_name : '',
payment_type : '',
payment_card_id : '',
payment_status : '',
open_ticket_id: 0
oil_prices_id : '',
fill_date : '',
gallons_delivered : '',
price_per_gallon : '',
},
total_amount_customer : '',
autoDelivery: {
id: 0,
customer_id: 0,
account_number: '',
customer_town: '',
customer_state: 0,
customer_address: '',
customer_zip: '',
customer_full_name: '',
last_fill: '',
days_since_last_fill: 0,
last_updated: '',
estimated_gallons_left: 0,
estimated_gallons_left_prev_day: 0,
tank_height: '',
tank_size: '',
house_factor: 0,
auto_status: 0,
open_ticket_id: null,
},
}
},
created() {
this.userStatus()
},
watch: {
$route() {
this.today_price_oil();
this.getAutoTicket(this.$route.params.id);
},
},
mounted() {
this.today_price_oil();
this.getAutoTicket(this.$route.params.id);
payment_type : '',
payment_card_id : '',
payment_status : '',
open_ticket_id: 0
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.user.id = response.data.user_id;
}
})
},
getPaymentCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data.userCard.card_number === ''){
this.userCard === null;
this.userCardfound = false;
}
else{
this.userCard = response.data;
this.userCardfound = true;
}
this.FinalizeOilOrderForm.userCards = response.data.id
})
.catch(() => {
});
},
getPaymentCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/cards/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCards = response.data;
if (this.userCards && this.userCards.length > 0) {
this.userCardfound = true;
this.userCard = this.userCards.find((card: any) => card.main_card) || this.userCards[0];
}
})
.catch(() => {
});
},
getCustomer(user_id: any) {
if (!user_id || user_id === 'undefined') return;
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;
if (this.customer.id > 0) {
this.getPaymentCards(this.customer.user_id || this.customer.id);
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
this.customer = { id: 0, user_id: 0, customer_address: '', customer_first_name: '', customer_last_name: '', customer_town: '', customer_state: 0, customer_zip: '', customer_apt: '', customer_home_type: 0, customer_phone_number: '' };
});
},
getCustomerDescription(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/description/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customerDescription = response.data;
this.loaded = true
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getAutoTicket(delivery_id: any) {
let path = import.meta.env.VITE_AUTO_URL + "/delivery/autoticket/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.autoTicket = response.data;
this.getCustomer(this.autoTicket.customer_id)
})
this.getAutoDelivery(this.autoTicket.id)
this.getCustomerDescription(this.autoTicket.customer_id)
})
.catch(() => {
notify({
title: "Error",
text: "Could not get automatic",
type: "error",
});
});
},
getAutoDelivery(delivery_id: any) {
let path = import.meta.env.VITE_AUTO_URL + "/delivery/finddelivery/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
const autoDelivery = ref({
id: 0,
customer_id: 0,
account_number: '',
customer_town: '',
customer_state: 0,
customer_address: '',
customer_zip: '',
customer_full_name: '',
last_fill: '',
days_since_last_fill: 0,
last_updated: '',
estimated_gallons_left: 0,
estimated_gallons_left_prev_day: 0,
tank_height: '',
tank_size: '',
house_factor: 0,
auto_status: 0,
open_ticket_id: null,
})
this.autoDelivery = response.data;
this.getCustomer(this.autoDelivery.customer_id)
this.getCustomerDescription(this.autoDelivery.customer_id)
})
.catch(() => {
notify({
title: "Error",
text: "Could not get automatic",
type: "error",
});
});
},
today_price_oil() {
let path = import.meta.env.VITE_BASE_URL + '/info/price/oil'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.today_oil_price = response.data.price_for_customer;
})
},
UpdateAuto(payload: {
gallons: string,
delivery_id: string,
}) {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/delivery"
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
text: 'Update',
type: 'postive',
title: 'top'
})
this.$router.push({ name: "auto" });
}
else {
notify({
text: 'Auto Failure',
type: 'negative',
title: 'Update'
})
}
})
},
// Watchers
watch(() => route.params, () => {
today_price_oil()
getAutoTicket(route.params.id)
}, { immediate: false })
ConfirmAuto(payload: {
gallons_delivered: string,
}) {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/auto/create/" + this.autoDelivery.id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
// Lifecycle
onMounted(() => {
userStatus()
today_price_oil()
getAutoTicket(route.params.id)
})
notify({
title: "Success",
text: "Auto Delivered",
type: "success",
});
this.CreateTransaction(response.data['0']['auto_ticket_id'])
this.updateTransactionDelivery(this.autoDelivery.id, response.data['0']['auto_ticket_id'])
this.$router.push({ name: "payAutoCapture", params: { id: response.data['0']['auto_ticket_id'] } });
}
if (response.data.error) {
notify({
title: "Error",
text: "Could not finalize auto",
type: "error",
});
this.$router.push("auto");
}
})
},
closeTicket(ticketId: number) {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/auto/close_ticket/" + ticketId;
axios({
method: "put",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then(() => {
// Ticket closed successfully
})
},
UpdateDeliveredAuto(payload: {
gallons_delivered: string,
}) {
console.log(this.autoDelivery)
let path = import.meta.env.VITE_AUTO_URL + "/confirm/auto/update/" + this.autoDelivery.id;
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
notify({
title: "Success",
text: "Auto Updated",
type: "success",
});
// Removed redirect from here, will handle in onSubmit
}
})
},
updateTransactionDelivery(current_delivery_id: any, new_delivery_id: any) {
const path = `${import.meta.env.VITE_AUTHORIZE_URL}/api/auto/transaction/delivery/${current_delivery_id}/update/${new_delivery_id}`;
axios.put(path, {}, { withCredentials: true, headers: authHeader() })
.then(() => console.log("Transaction auto_id updated"))
.catch(() => console.error("Error updating transaction auto_id"));
},
CreateTransaction(auto_ticket_id: string,) {
let path = import.meta.env.VITE_MONEY_URL + "/delivery/add/auto/" + auto_ticket_id;
axios({
method: "post",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.status == 201) {
notify({
message: 'Confirmed Transaction',
type: 'positive',
position: 'top'
})
}
else {
notify({
message: 'Form Error',
type: 'negative',
position: 'top'
})
}
})
},
onSubmit() {
let payload = {
gallons_delivered: this.FinalizeOilOrderForm.gallons_delivered,
};
this.UpdateDeliveredAuto(payload);
if (this.autoTicket.payment_status == '1') {
// Pre-authorized: redirect to capture page
this.$router.push({ name: "payAutoCapture", params: { id: this.autoTicket.id } });
} else {
// Fully charged: close ticket
if (this.autoDelivery.open_ticket_id) {
this.closeTicket(this.autoDelivery.open_ticket_id);
}
this.$router.push({ name: "auto" });
}
},
},
// Functions
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
</script>
<style scoped></style>
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
user.value.id = response.data.user_id;
}
})
}
const getPaymentCard = (card_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data.userCard.card_number === ''){
userCard.value = null;
userCardfound.value = false;
}
else{
userCard.value = response.data;
userCardfound.value = true;
}
FinalizeOilOrderForm.value.userCards = response.data.id
})
.catch(() => {
});
}
const getPaymentCards = (user_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/payment/cards/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
userCards.value = response.data;
if (userCards.value && userCards.value.length > 0) {
userCardfound.value = true;
userCard.value = userCards.value.find((card: any) => card.main_card) || userCards.value[0];
}
})
.catch(() => {
});
}
const getCustomer = (user_id: any) => {
if (!user_id || user_id === 'undefined') return;
let path = import.meta.env.VITE_BASE_URL + "/customer/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
customer.value = response.data;
if (customer.value.id > 0) {
getPaymentCards(customer.value.user_id || customer.value.id);
}
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
customer.value = { id: 0, user_id: 0, customer_address: '', customer_first_name: '', customer_last_name: '', customer_town: '', customer_state: 0, customer_zip: '', customer_apt: '', customer_home_type: 0, customer_phone_number: '' };
});
}
const getCustomerDescription = (user_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/customer/description/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
customerDescription.value = response.data;
loaded.value = true
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
}
const getAutoTicket = (delivery_id: any) => {
let path = import.meta.env.VITE_AUTO_URL + "/delivery/autoticket/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
autoTicket.value = response.data;
getCustomer(autoTicket.value.customer_id)
getAutoDelivery(autoTicket.value.id)
getCustomerDescription(autoTicket.value.customer_id)
})
.catch(() => {
notify({
title: "Error",
text: "Could not get automatic",
type: "error",
});
});
}
const getAutoDelivery = (delivery_id: any) => {
let path = import.meta.env.VITE_AUTO_URL + "/delivery/finddelivery/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
autoDelivery.value = response.data;
getCustomer(autoDelivery.value.customer_id)
getCustomerDescription(autoDelivery.value.customer_id)
})
.catch(() => {
notify({
title: "Error",
text: "Could not get automatic",
type: "error",
});
});
}
const today_price_oil = () => {
let path = import.meta.env.VITE_BASE_URL + '/info/price/oil'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
today_oil_price.value = response.data.price_for_customer;
})
}
const UpdateAuto = (payload: {
gallons: string,
delivery_id: string,
}) => {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/delivery"
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
text: 'Update',
type: 'postive',
title: 'top'
})
router.push({ name: "auto" });
}
else {
notify({
text: 'Auto Failure',
type: 'negative',
title: 'Update'
})
}
})
}
const ConfirmAuto = (payload: {
gallons_delivered: string,
}) => {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/auto/create/" + autoDelivery.value.id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
notify({
title: "Success",
text: "Auto Delivered",
type: "success",
});
CreateTransaction(response.data['0']['auto_ticket_id'])
updateTransactionDelivery(autoDelivery.value.id, response.data['0']['auto_ticket_id'])
router.push({ name: "payAutoCapture", params: { id: response.data['0']['auto_ticket_id'] } });
}
if (response.data.error) {
notify({
title: "Error",
text: "Could not finalize auto",
type: "error",
});
router.push("auto");
}
})
}
const closeTicket = (ticketId: number) => {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/auto/close_ticket/" + ticketId;
axios({
method: "put",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then(() => {
// Ticket closed successfully
})
}
const UpdateDeliveredAuto = (payload: {
gallons_delivered: string,
}) => {
console.log(autoDelivery.value)
let path = import.meta.env.VITE_AUTO_URL + "/confirm/auto/update/" + autoDelivery.value.id;
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
notify({
title: "Success",
text: "Auto Updated",
type: "success",
});
// Removed redirect from here, will handle in onSubmit
}
})
}
const updateTransactionDelivery = (current_delivery_id: any, new_delivery_id: any) => {
const path = `${import.meta.env.VITE_AUTHORIZE_URL}/api/auto/transaction/delivery/${current_delivery_id}/update/${new_delivery_id}`;
axios.put(path, {}, { withCredentials: true, headers: authHeader() })
.then(() => console.log("Transaction auto_id updated"))
.catch(() => console.error("Error updating transaction auto_id"));
}
const CreateTransaction = (auto_ticket_id: string) => {
let path = import.meta.env.VITE_MONEY_URL + "/delivery/add/auto/" + auto_ticket_id;
axios({
method: "post",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.status == 201) {
notify({
message: 'Confirmed Transaction',
type: 'positive',
position: 'top'
})
}
else {
notify({
message: 'Form Error',
type: 'negative',
position: 'top'
})
}
})
}
const onSubmit = () => {
let payload = {
gallons_delivered: FinalizeOilOrderForm.value.gallons_delivered,
};
UpdateDeliveredAuto(payload);
if (autoTicket.value.payment_status == '1') {
// Pre-authorized: redirect to capture page
router.push({ name: "payAutoCapture", params: { id: autoTicket.value.id } });
} else {
// Fully charged: close ticket
if (autoDelivery.value.open_ticket_id) {
closeTicket(autoDelivery.value.open_ticket_id);
}
router.push({ name: "auto" });
}
</script>
<style scoped></style>

View File

@@ -78,7 +78,7 @@
<div>
<div class="font-bold text-sm">Payment Method</div>
<div v-if="!userCardfound" class="text-warning text-sm">No card on file for this customer.</div>
<div v-if="userCardfound" class="mt-2 p-3 rounded-lg border bg-primary/10 border-primary">
<div v-if="userCardfound && userCard" class="mt-2 p-3 rounded-lg border bg-primary/10 border-primary">
<div class="font-bold text-sm">{{ userCard.name_on_card }}</div>
<div class="text-xs opacity-70">{{ userCard.type_of_card }}</div>
<div class="mt-1 text-sm font-mono tracking-wider">
@@ -121,8 +121,9 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
@@ -131,408 +132,397 @@ import Footer from '../../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import { notify } from "@kyvg/vue3-notification"
// Route and router
const route = useRoute()
const router = useRouter()
export default defineComponent({
name: 'finalizeTicketAuto',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
v$: useValidate(),
loaded: false,
user: {
id: 0
},
userCardfound: false,
deliveryStatus: [],
userCards: [],
deliveryNotesDriver: [],
today_oil_price: 0,
FinalizeOilOrderForm: {
fill_location: 0,
check_number: 0,
delivery_status: 10,
userCards: [],
credit_card_id: 0,
driver: 0,
gallons_delivered: '',
customer_filled: false,
prime: false,
same_day: false,
emergency: false,
},
CreateOilOrderForm: {
basicInfo: {
gallons_delivered: '',
userCards: []
},
},
userCard: {
date_added: '',
user_id: '',
card_number: '',
last_four_digits: '',
name_on_card: '',
expiration_month: '',
expiration_year: '',
type_of_card: '',
security_number: '',
accepted_or_declined: '',
main_card: '',
},
customer: {
id: 0,
user_id: 0,
customer_address: '',
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
customerDescription: {
customer_id: 0,
account_number: '',
company_id: 0,
fill_location: 0,
description: '',
},
autoTicket: {
id: 0,
customer_id: '',
account_number: '',
customer_town: '',
customer_state: '',
customer_address: '',
customer_zip: '',
customer_full_name: '',
oil_prices_id: '',
fill_date: '',
gallons_delivered: '',
price_per_gallon: '',
total_amount_customer: '',
payment_type: '',
payment_card_id: '',
payment_status: '',
open_ticket_id: 0
},
autoDelivery: {
id: 0,
customer_id: 0,
account_number: '',
customer_town: '',
customer_state: 0,
customer_address: '',
customer_zip: '',
customer_full_name: '',
last_fill: '',
days_since_last_fill: 0,
last_updated: '',
estimated_gallons_left: 0,
estimated_gallons_left_prev_day: 0,
tank_height: '',
tank_size: '',
house_factor: 0,
auto_status: 0,
open_ticket_id: null,
},
}
},
created() {
this.userStatus()
},
watch: {
$route() {
this.today_price_oil();
this.getAutoTicket(this.$route.params.id);
},
},
mounted() {
this.today_price_oil();
this.getAutoDelivery(this.$route.params.id);
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
this.user.id = response.data.user_id;
}
})
},
getPaymentCard(card_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data.userCard.card_number === '') {
this.userCard === null;
this.userCardfound = false;
}
else {
this.userCard = response.data;
this.userCardfound = true;
}
this.FinalizeOilOrderForm.userCards = response.data.id
})
.catch(() => {
});
},
getPaymentCards(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/payment/cards/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.userCards = response.data;
if (this.userCards && this.userCards.length > 0) {
this.userCardfound = true;
this.userCard = this.userCards.find((card: any) => card.main_card) || this.userCards[0];
}
})
.catch(() => {
});
},
getCustomer(userid: any) {
let path = import.meta.env.VITE_BASE_URL + '/customer/' + userid;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.customer = response.data
})
},
getCreditCards(userid: any) {
let path = import.meta.env.VITE_BASE_URL + '/payment/cards/' + userid;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.userCards = response.data;
if (this.userCards && this.userCards.length > 0) {
this.userCardfound = true;
this.userCard = this.userCards.find((card: any) => card.main_card) || this.userCards[0];
}
})
},
getCustomerDescription(user_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/customer/description/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.customerDescription = response.data;
this.loaded = true
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getAutoTicket(delivery_id: any) {
let path = import.meta.env.VITE_AUTO_URL + "/delivery/autoticket/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.autoTicket = response.data;
this.getCustomer(this.autoTicket.customer_id)
this.getAutoDelivery(this.autoTicket.id)
this.getCustomerDescription(this.autoTicket.customer_id)
})
.catch(() => {
notify({
title: "Error",
text: "Could not get automatic",
type: "error",
});
});
},
getAutoDelivery(delivery_id: any) {
let path = import.meta.env.VITE_AUTO_URL + "/delivery/delivery/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data && response.data.customer_id) {
this.autoDelivery = response.data;
this.getCustomer(this.autoDelivery.customer_id)
this.getCreditCards(this.autoDelivery.customer_id)
} else {
console.error("API Error:", response.data.error || "Failed to fetch auto delivery data.");
}
})
.catch((error: any) => {
console.error("API Error in getAutoDelivery:", error);
notify({
title: "Error",
text: "Could not get automatic delivery",
type: "error",
});
});
},
today_price_oil() {
let path = import.meta.env.VITE_BASE_URL + '/info/price/oil'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
this.today_oil_price = response.data.price_for_customer;
})
},
UpdateAuto(payload: {
gallons: string,
delivery_id: string,
}) {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/delivery"
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
text: 'Update',
type: 'postive',
title: 'top'
})
this.$router.push({ name: "auto" });
}
else {
notify({
text: 'Auto Failure',
type: 'negative',
title: 'Update'
})
}
})
},
CreateTransaction(auto_ticket_id: string,) {
let path = import.meta.env.VITE_MONEY_URL + "/delivery/add/auto/" + auto_ticket_id;
axios({
method: "post",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.status == 201) {
notify({
message: 'Confirmed Transaction',
type: 'positive',
position: 'top'
})
}
else {
notify({
message: 'Form Error',
type: 'negative',
position: 'top'
})
}
})
},
ConfirmAuto(payload: {
gallons_delivered: string,
}) {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/auto/create/nopreauth/" + this.autoDelivery.id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
notify({
title: "Success",
text: "Auto Delivered",
type: "success",
});
this.CreateTransaction(response.data['0']['auto_ticket_id'])
}
if (response.data.error) {
notify({
title: "Error",
text: "Could not finalize auto",
type: "error",
});
this.$router.push("auto");
}
})
},
onSubmit() {
let payload = {
gallons_delivered: this.FinalizeOilOrderForm.gallons_delivered,
};
this.ConfirmAuto(payload)
this.$router.push({ name: "auto" });
},
// Reactive data
const v$ = useValidate()
const loaded = ref(false)
const user = ref({
id: 0
})
const userCardfound = ref(false)
const deliveryStatus = ref([])
const userCards = ref([])
const deliveryNotesDriver = ref([])
const today_oil_price = ref(0)
const FinalizeOilOrderForm = ref({
fill_location: 0,
check_number: 0,
delivery_status: 10,
userCards: [],
credit_card_id: 0,
driver: 0,
gallons_delivered: '',
customer_filled: false,
prime: false,
same_day: false,
emergency: false,
})
const CreateOilOrderForm = ref({
basicInfo: {
gallons_delivered: '',
userCards: []
},
})
const userCard = ref<{
date_added: string;
user_id: string;
card_number: string;
last_four_digits: string;
name_on_card: string;
expiration_month: string;
expiration_year: string;
type_of_card: string;
security_number: string;
accepted_or_declined: string;
main_card: string;
} | null>(null)
const customer = ref({
id: 0,
user_id: 0,
customer_address: '',
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
})
const customerDescription = ref({
customer_id: 0,
account_number: '',
company_id: 0,
fill_location: 0,
description: '',
})
const autoTicket = ref({
id: 0,
customer_id: '',
account_number: '',
customer_town: '',
customer_state: '',
customer_address: '',
customer_zip: '',
customer_full_name: '',
oil_prices_id: '',
fill_date: '',
gallons_delivered: '',
price_per_gallon: '',
total_amount_customer: '',
payment_type: '',
payment_card_id: '',
payment_status: '',
open_ticket_id: 0
})
const autoDelivery = ref({
id: 0,
customer_id: 0,
account_number: '',
customer_town: '',
customer_state: 0,
customer_address: '',
customer_zip: '',
customer_full_name: '',
last_fill: '',
days_since_last_fill: 0,
last_updated: '',
estimated_gallons_left: 0,
estimated_gallons_left_prev_day: 0,
tank_height: '',
tank_size: '',
house_factor: 0,
auto_status: 0,
open_ticket_id: null,
})
// Watchers
watch(() => route.params, () => {
today_price_oil()
getAutoTicket(route.params.id)
}, { immediate: false })
// Lifecycle
onMounted(() => {
userStatus()
today_price_oil()
getAutoDelivery(route.params.id)
})
// Functions
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
user.value.id = response.data.user_id;
}
})
}
const getPaymentCard = (card_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data.userCard.card_number === '') {
userCard.value = null;
userCardfound.value = false;
}
else {
userCard.value = response.data;
userCardfound.value = true;
}
FinalizeOilOrderForm.value.userCards = response.data.id
})
.catch(() => {
});
}
const getPaymentCards = (user_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/payment/cards/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
userCards.value = response.data;
if (userCards.value && userCards.value.length > 0) {
userCardfound.value = true;
userCard.value = userCards.value.find((card: any) => card.main_card) || userCards.value[0];
}
})
.catch(() => {
});
}
const getCustomer = (userid: any) => {
let path = import.meta.env.VITE_BASE_URL + '/customer/' + userid;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
customer.value = response.data
})
}
const getCreditCards = (userid: any) => {
let path = import.meta.env.VITE_BASE_URL + '/payment/cards/' + userid;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
userCards.value = response.data;
if (userCards.value && userCards.value.length > 0) {
userCardfound.value = true;
userCard.value = userCards.value.find((card: any) => card.main_card) || userCards.value[0];
}
})
}
const getCustomerDescription = (user_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/customer/description/" + user_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
customerDescription.value = response.data;
loaded.value = true
})
.catch(() => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
}
const getAutoTicket = (delivery_id: any) => {
let path = import.meta.env.VITE_AUTO_URL + "/delivery/autoticket/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
autoTicket.value = response.data;
getCustomer(autoTicket.value.customer_id)
getAutoDelivery(autoTicket.value.id)
getCustomerDescription(autoTicket.value.customer_id)
})
.catch(() => {
notify({
title: "Error",
text: "Could not get automatic",
type: "error",
});
});
}
const getAutoDelivery = (delivery_id: any) => {
let path = import.meta.env.VITE_AUTO_URL + "/delivery/delivery/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data && response.data.customer_id) {
autoDelivery.value = response.data;
getCustomer(autoDelivery.value.customer_id)
getCreditCards(autoDelivery.value.customer_id)
} else {
console.error("API Error:", response.data.error || "Failed to fetch auto delivery data.");
}
})
.catch((error: any) => {
console.error("API Error in getAutoDelivery:", error);
notify({
title: "Error",
text: "Could not get automatic delivery",
type: "error",
});
});
}
const today_price_oil = () => {
let path = import.meta.env.VITE_BASE_URL + '/info/price/oil'
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
today_oil_price.value = response.data.price_for_customer;
})
}
const UpdateAuto = (payload: {
gallons: string,
delivery_id: string,
}) => {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/delivery"
axios({
method: "put",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
text: 'Update',
type: 'postive',
title: 'top'
})
router.push({ name: "auto" });
}
else {
notify({
text: 'Auto Failure',
type: 'negative',
title: 'Update'
})
}
})
}
const CreateTransaction = (auto_ticket_id: string) => {
let path = import.meta.env.VITE_MONEY_URL + "/delivery/add/auto/" + auto_ticket_id;
axios({
method: "post",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.status == 201) {
notify({
message: 'Confirmed Transaction',
type: 'positive',
position: 'top'
})
}
else {
notify({
message: 'Form Error',
type: 'negative',
position: 'top'
})
}
})
}
const ConfirmAuto = (payload: {
gallons_delivered: string,
}) => {
let path = import.meta.env.VITE_AUTO_URL + "/confirm/auto/create/nopreauth/" + autoDelivery.value.id;
axios({
method: "post",
url: path,
data: payload,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
notify({
title: "Success",
text: "Auto Delivered",
type: "success",
});
CreateTransaction(response.data['0']['auto_ticket_id'])
}
if (response.data.error) {
notify({
title: "Error",
text: "Could not finalize auto",
type: "error",
});
router.push("auto");
}
})
}
const onSubmit = () => {
let payload = {
gallons_delivered: FinalizeOilOrderForm.value.gallons_delivered,
};
ConfirmAuto(payload)
router.push({ name: "auto" });
}
</script>
<style scoped></style>

View File

@@ -71,72 +71,54 @@
<Footer/>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref([])
export default defineComponent({
name: 'deliveryTicketsMissing',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [
],
}
},
created() {
this.userStatus()
},
mounted() {
this.get_oil_orders()
},
methods: {
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders() {
let path = import.meta.env.VITE_BASE_URL + '/deliverystatus/pending';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
},
// Lifecycle
onMounted(() => {
userStatus()
get_oil_orders()
})
// Functions
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
}
})
.catch(() => {
user.value = null
})
}
const get_oil_orders = () => {
let path = import.meta.env.VITE_BASE_URL + '/deliverystatus/pending';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
deliveries.value = response.data
})
}
</script>
<style scoped>

View File

@@ -67,20 +67,20 @@
<div class="font-bold text-sm">Current Status</div>
<div class="badge badge-lg"
:class="{
'badge-success': [1, 10].includes(deliveryOrder.delivery_status),
'badge-info': deliveryOrder.delivery_status == 2,
'badge-error': deliveryOrder.delivery_status == 5,
'badge-warning': ![1, 10, 2, 5].includes(deliveryOrder.delivery_status)
'badge-success': [DELIVERY_STATUS.DELIVERED, DELIVERY_STATUS.FINALIZED].includes(deliveryOrder.delivery_status as any),
'badge-info': deliveryOrder.delivery_status == DELIVERY_STATUS.OUT_FOR_DELIVERY,
'badge-error': deliveryOrder.delivery_status == DELIVERY_STATUS.ISSUE,
'badge-warning': ![DELIVERY_STATUS.DELIVERED, DELIVERY_STATUS.FINALIZED, DELIVERY_STATUS.OUT_FOR_DELIVERY, DELIVERY_STATUS.ISSUE].includes(deliveryOrder.delivery_status as any)
}">
<span v-if="deliveryOrder.delivery_status == 0">Waiting</span>
<span v-else-if="deliveryOrder.delivery_status == 1">Delivered</span>
<span v-else-if="deliveryOrder.delivery_status == 2">Out_for_Delivery</span>
<span v-else-if="deliveryOrder.delivery_status == 3">Tomorrow</span>
<span v-else-if="deliveryOrder.delivery_status == 4">Partial Delivery</span>
<span v-else-if="deliveryOrder.delivery_status == 5">Misdelivery</span>
<span v-else-if="deliveryOrder.delivery_status == 6">Unknown</span>
<span v-else-if="deliveryOrder.delivery_status == 9">Pending</span>
<span v-else-if="deliveryOrder.delivery_status == 10">Finalized</span>
<span v-if="deliveryOrder.delivery_status == DELIVERY_STATUS.WAITING">Waiting</span>
<span v-else-if="deliveryOrder.delivery_status == DELIVERY_STATUS.DELIVERED">Delivered</span>
<span v-else-if="deliveryOrder.delivery_status == DELIVERY_STATUS.OUT_FOR_DELIVERY">Out_for_Delivery</span>
<span v-else-if="deliveryOrder.delivery_status == DELIVERY_STATUS.TOMORROW">Tomorrow</span>
<span v-else-if="deliveryOrder.delivery_status == DELIVERY_STATUS.PARTIAL_DELIVERY">Partial Delivery</span>
<span v-else-if="deliveryOrder.delivery_status == DELIVERY_STATUS.ISSUE">Misdelivery</span>
<span v-else-if="deliveryOrder.delivery_status == DELIVERY_STATUS.UNKNOWN">Unknown</span>
<span v-else-if="deliveryOrder.delivery_status == DELIVERY_STATUS.PENDING_PAYMENT">Pending</span>
<span v-else-if="deliveryOrder.delivery_status == DELIVERY_STATUS.FINALIZED">Finalized</span>
</div>
</div>
<div>
@@ -354,488 +354,480 @@
</div>
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { useRoute } from 'vue-router'
import axios from 'axios'
import authHeader from '../../services/auth.header'
interface UserCard {
id: number;
last_four: string;
type_of_card: string;
expiration_month: number;
expiration_year: number;
name_on_card: string;
card_number: string;
security_number: string;
main_card?: boolean;
}
import { DELIVERY_STATUS, PAYMENT_STATUS, TRANSACTION_STATUS } from '../../constants/status'
import { CreditCard } from '../../types/models'
import Header from '../../layouts/headers/headerauth.vue'
import SideBar from '../../layouts/sidebar/sidebar.vue'
import Footer from '../../layouts/footers/footer.vue'
import useValidate from "@vuelidate/core";
import { notify } from "@kyvg/vue3-notification"
import moment from 'moment';
import dayjs from 'dayjs';
export default defineComponent({
name: 'deliveryOrder',
const route = useRoute()
components: {
Header,
SideBar,
Footer,
},
// Reactive data
const v$ = useValidate()
const user = ref({
user_id: 0
})
const priceprime = ref(0)
const pricesameday = ref(0)
const priceemergency = ref(0)
const total_amount = ref(0)
const discount = ref(0)
const total_amount_after_discount = ref(0)
const deliveryNotesDriver = ref([])
const userCardfound = ref(false)
const userCard = ref({} as CreditCard)
const customer = ref({
account_number: '',
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_address: '',
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
})
data() {
return {
v$: useValidate(),
user: {
user_id: 0
},
priceprime: 0,
pricesameday: 0,
priceemergency: 0,
total_amount: 0,
discount: 0,
total_amount_after_discount: 0,
deliveryNotesDriver: [],
userCardfound: false,
userCard: {} as UserCard,
customer: {
account_number: '',
id: 0,
user_id: 0,
customer_first_name: '',
customer_last_name: '',
customer_town: '',
customer_state: 0,
customer_address: '',
customer_zip: '',
customer_apt: '',
customer_home_type: 0,
customer_phone_number: '',
},
const deliveryMoney = ref({
time_added: '',
total_amount_oil: '',
total_amount_emergency: '',
total_amount_same_day: '',
total_amount_prime: '',
total_amount_fee: '',
total_discount_amount: '',
total_discount_total: '',
total_amount: '',
})
const promo = ref({
id: 0,
name_of_promotion: '',
description: '',
money_off_delivery: '',
text_on_ticket: ''
})
const pricing = ref({
price_from_supplier: 0,
price_for_customer: 0,
price_for_employee: 0,
price_same_day: 0,
price_prime: 0,
price_emergency: 0,
date: "",
})
const deliveryOrder = ref({
id: '',
customer_id: 0,
customer_name: '',
customer_address: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
gallons_ordered: 0,
customer_asked_for_fill: 0,
gallons_delivered: '',
customer_filled: 0,
delivery_status: 0,
when_ordered: '',
when_delivered: '',
expected_delivery_date: '',
automatic: 0,
oil_id: 0,
supplier_price: '',
customer_price: '',
customer_temperature: '',
dispatcher_notes: '',
prime: 0,
same_day: 0,
emergency: 0,
payment_type: 0,
payment_card_id: '',
driver_employee_id: 0,
driver_first_name: '',
driver_last_name: '',
promo_id: 0,
})
const transaction = ref(null as any)
deliveryMoney: {
time_added: '',
total_amount_oil: '',
total_amount_emergency: '',
total_amount_same_day: '',
total_amount_prime: '',
total_amount_fee: '',
total_discount_amount: '',
total_discount_total: '',
total_amount: '',
},
promo: {
id: 0,
name_of_promotion: '',
description: '',
money_off_delivery: '',
text_on_ticket: ''
},
pricing: {
price_from_supplier: 0,
price_for_customer: 0,
price_for_employee: 0,
price_same_day: 0,
price_prime: 0,
price_emergency: 0,
date: "",
},
deliveryOrder: {
id: '',
customer_id: 0,
customer_name: '',
customer_address: '',
customer_town: '',
customer_state: 0,
customer_zip: '',
gallons_ordered: 0,
customer_asked_for_fill: 0,
gallons_delivered: '',
customer_filled: 0,
delivery_status: 0,
when_ordered: '',
when_delivered: '',
expected_delivery_date: '',
automatic: 0,
oil_id: 0,
supplier_price: '',
customer_price: '',
customer_temperature: '',
dispatcher_notes: '',
prime: 0,
same_day: 0,
emergency: 0,
payment_type: 0,
payment_card_id: '',
driver_employee_id: 0,
driver_first_name: '',
driver_last_name: '',
promo_id: 0,
},
transaction: null as any,
}
},
// Computed
const computedDELIVERY_STATUS = computed(() => DELIVERY_STATUS)
const computedPAYMENT_STATUS = computed(() => PAYMENT_STATUS)
const computedTRANSACTION_STATUS = computed(() => TRANSACTION_STATUS)
created() {
this.userStatus()
},
watch: {
$route() {
this.getOilOrder(this.$route.params.id);
this.getOilOrderMoney(this.$route.params.id);
this.sumdelivery(this.$route.params.id);
},
},
mounted() {
this.getOilOrder(this.$route.params.id);
this.getOilOrderMoney(this.$route.params.id);
this.sumdelivery(this.$route.params.id);
this.getOilPricing();
},
// Watchers
watch(route, () => {
getOilOrder(route.params.id);
getOilOrderMoney(route.params.id);
sumdelivery(route.params.id);
})
methods: {
format_date(value: string) {
if (value) {
return moment(String(value)).format('LLLL')
}
},
getTypeColor(transactionType: number) {
switch (transactionType) {
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';
}
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.$router.push({ name: "customerProfile", params: { id: this.customer.user_id } });
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
},
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",
});
// Lifecycle
onMounted(() => {
userStatus()
getOilOrder(route.params.id);
getOilOrderMoney(route.params.id);
sumdelivery(route.params.id);
getOilPricing();
})
// Functions
const format_date = (value: string) => {
if (value) {
return dayjs(String(value)).format('LLLL')
}
}
const getTypeColor = (transactionType: number) => {
switch (transactionType) {
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';
}
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
},
getOilPricing() {
let path = import.meta.env.VITE_BASE_URL + "/info/price/oil/table";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
this.pricing = response.data;
})
.catch((_error: any) => {
notify({
title: "Error",
text: "Could not get oil pricing",
type: "error",
});
});
},
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;
})
.catch((_error: any) => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
},
getPaymentCard(card_id: any) {
if (card_id) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
// Check if we have valid card data
if (response.data && response.data.card_number && response.data.card_number !== '') {
this.userCard = response.data;
this.userCardfound = true;
} else {
this.userCard = {} as UserCard;
this.userCardfound = false;
}
})
.catch((error: any) => {
console.error("Error fetching payment card:", error);
this.userCard = {} as UserCard;
this.userCardfound = false;
});
} else {
this.userCardfound = false;
}
},
// Note: router.push would need to be imported and used
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
}
const cancelDelivery = () => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/cancel/' + deliveryOrder.value.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
getOilOrder(deliveryOrder.value.id);
} else {
notify({
title: "Failure",
text: "Failed to cancel delivery",
type: "error",
});
}
}).catch(() => {
notify({
title: "Error",
text: "Error cancelling delivery",
type: "error",
});
});
}
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
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(),
})
})
}
const getOilPricing = () => {
let path = import.meta.env.VITE_BASE_URL + "/info/price/oil/table";
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
pricing.value = response.data;
})
.catch((_error: any) => {
notify({
title: "Error",
text: "Could not get oil pricing",
type: "error",
});
});
}
const 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) => {
customer.value = response.data;
})
.catch((_error: any) => {
notify({
title: "Error",
text: "Could not find customer",
type: "error",
});
});
}
const getPaymentCard = (card_id: any) => {
if (card_id) {
let path = import.meta.env.VITE_BASE_URL + "/payment/card/" + card_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.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);
}
if (this.deliveryOrder.promo_id != null) {
this.getPromo(this.deliveryOrder.promo_id);
}
// Only fetch transactions for Authorize.net payments
if (this.deliveryOrder.payment_type == 11) {
this.getTransaction(delivery_id);
}
// Check if we have valid card data
if (response.data && response.data.card_number && response.data.card_number !== '') {
userCard.value = response.data;
userCardfound.value = true;
} else {
console.error("API Error:", response.data.error || "Failed to fetch delivery data.");
notify({ title: "Error", text: "Could not load delivery details.", type: "error" });
userCard.value = {} as CreditCard;
userCardfound.value = false;
}
})
.catch((error: any) => {
console.error("Error fetching delivery order:", error);
console.error("Error fetching payment card:", error);
userCard.value = {} as CreditCard;
userCardfound.value = false;
});
},
getOilOrderMoney(delivery_id: any) {
let path = import.meta.env.VITE_MONEY_URL + "/delivery/order/money/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.deliveryMoney = response.data
}
})
},
sumdelivery(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/delivery/total/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data && response.data.ok) {
this.priceprime = response.data.priceprime || 0;
this.pricesameday = response.data.pricesameday || 0;
this.priceemergency = response.data.priceemergency || 0;
this.total_amount = parseFloat(response.data.total_amount) || 0;
this.discount = parseFloat(response.data.discount) || 0;
this.total_amount_after_discount = parseFloat(response.data.total_amount_after_discount) || 0;
} else {
// Fallback calculation if API doesn't return expected data
this.calculateFallbackTotal();
}
})
.catch((error: any) => {
console.error("Error fetching delivery totals:", error);
// Fallback calculation on error
this.calculateFallbackTotal();
notify({
title: "Warning",
text: "Could not get delivery totals, using estimated calculation",
type: "warn",
});
});
},
} else {
userCardfound.value = false;
}
}
calculateFallbackTotal() {
// Fallback calculation using available data
if (this.deliveryOrder.gallons_ordered && this.pricing.price_for_customer) {
const gallons = Number(this.deliveryOrder.gallons_ordered);
const pricePerGallon = Number(this.pricing.price_for_customer);
let total = gallons * pricePerGallon;
const 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) {
deliveryOrder.value = response.data.delivery; // <-- THIS IS THE CRITICAL CHANGE
if (this.deliveryOrder.prime == 1) {
total += Number(this.pricing.price_prime) || 0;
}
if (this.deliveryOrder.same_day == 1) {
total += Number(this.pricing.price_same_day) || 0;
}
if (this.deliveryOrder.emergency == 1) {
total += Number(this.pricing.price_emergency) || 0;
}
// Now that deliveryOrder is the correct object, the rest of the logic will work.
getCustomer(deliveryOrder.value.customer_id);
this.total_amount = total;
this.total_amount_after_discount = total; // No discount info available
this.discount = 0;
if ([1, 2, 3].includes(deliveryOrder.value.payment_type)) {
getPaymentCard(deliveryOrder.value.payment_card_id);
}
},
getPromo(promo_id: any) {
let path = import.meta.env.VITE_BASE_URL + "/promo/" + promo_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
this.promo = response.data;
}
})
.catch((error: any) => {
console.error('Error fetching promo:', error);
})
},
calculateDeliveryTotal() {
if (!this.deliveryOrder.gallons_delivered || !this.pricing.price_for_customer) {
return '0.00';
if (deliveryOrder.value.promo_id != null) {
getPromo(deliveryOrder.value.promo_id);
}
const gallons = Number(this.deliveryOrder.gallons_delivered);
const pricePerGallon = Number(this.pricing.price_for_customer);
let total = gallons * pricePerGallon;
if (this.deliveryOrder.prime == 1) {
total += Number(this.pricing.price_prime) || 0;
}
if (this.deliveryOrder.same_day == 1) {
total += Number(this.pricing.price_same_day) || 0;
}
if (this.deliveryOrder.emergency == 1) {
total += Number(this.pricing.price_emergency) || 0;
// Only fetch transactions for Authorize.net payments
if (deliveryOrder.value.payment_type == 11) {
getTransaction(delivery_id);
}
return total.toFixed(2);
},
calculateEstimatedTotal() {
if (!this.deliveryOrder.gallons_ordered || !this.pricing.price_for_customer) {
return 0;
}
} 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: any) => {
console.error("Error fetching delivery order:", error);
});
}
const gallons = Number(this.deliveryOrder.gallons_ordered);
const pricePerGallon = Number(this.pricing.price_for_customer);
let total = gallons * pricePerGallon;
if (this.deliveryOrder.prime == 1) {
total += Number(this.pricing.price_prime) || 0;
}
if (this.deliveryOrder.same_day == 1) {
total += Number(this.pricing.price_same_day) || 0;
}
if (this.deliveryOrder.emergency == 1) {
total += Number(this.pricing.price_emergency) || 0;
const getOilOrderMoney = (delivery_id: any) => {
let path = import.meta.env.VITE_MONEY_URL + "/delivery/order/money/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
deliveryMoney.value = response.data
}
})
}
return total;
},
getTransaction(delivery_id: any) {
// Simple endpoint to get transaction directly by delivery_id
const path = `${import.meta.env.VITE_BASE_URL}/payment/transaction/delivery/${delivery_id}`;
axios.get(path, {
withCredentials: true,
headers: authHeader()
}).then((response: any) => {
if (response.data.ok) {
this.transaction = response.data.transaction;
console.log("Transaction loaded:", this.transaction);
} else {
console.log("No transaction found for delivery:", delivery_id);
this.transaction = null;
}
}).catch((error: any) => {
console.error("Error fetching transaction:", error);
this.transaction = null;
const sumdelivery = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/delivery/total/" + delivery_id;
axios({
method: "get",
url: path,
withCredentials: true,
})
.then((response: any) => {
if (response.data && response.data.ok) {
priceprime.value = response.data.priceprime || 0;
pricesameday.value = response.data.pricesameday || 0;
priceemergency.value = response.data.priceemergency || 0;
total_amount.value = parseFloat(response.data.total_amount) || 0;
discount.value = parseFloat(response.data.discount) || 0;
total_amount_after_discount.value = parseFloat(response.data.total_amount_after_discount) || 0;
} else {
// Fallback calculation if API doesn't return expected data
calculateFallbackTotal();
}
})
.catch((error: any) => {
console.error("Error fetching delivery totals:", error);
// Fallback calculation on error
calculateFallbackTotal();
notify({
title: "Warning",
text: "Could not get delivery totals, using estimated calculation",
type: "warn",
});
},
},
})
});
}
const calculateFallbackTotal = () => {
// Fallback calculation using available data
if (deliveryOrder.value.gallons_ordered && pricing.value.price_for_customer) {
const gallons = Number(deliveryOrder.value.gallons_ordered);
const pricePerGallon = Number(pricing.value.price_for_customer);
let total = gallons * pricePerGallon;
if (deliveryOrder.value.prime == 1) {
total += Number(pricing.value.price_prime) || 0;
}
if (deliveryOrder.value.same_day == 1) {
total += Number(pricing.value.price_same_day) || 0;
}
if (deliveryOrder.value.emergency == 1) {
total += Number(pricing.value.price_emergency) || 0;
}
total_amount.value = total;
total_amount_after_discount.value = total; // No discount info available
discount.value = 0;
}
}
const getPromo = (promo_id: any) => {
let path = import.meta.env.VITE_BASE_URL + "/promo/" + promo_id;
axios({
method: "get",
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data) {
promo.value = response.data;
}
})
.catch((error: any) => {
console.error('Error fetching promo:', error);
})
}
const calculateDeliveryTotal = () => {
if (!deliveryOrder.value.gallons_delivered || !pricing.value.price_for_customer) {
return '0.00';
}
const gallons = Number(deliveryOrder.value.gallons_delivered);
const pricePerGallon = Number(pricing.value.price_for_customer);
let total = gallons * pricePerGallon;
if (deliveryOrder.value.prime == 1) {
total += Number(pricing.value.price_prime) || 0;
}
if (deliveryOrder.value.same_day == 1) {
total += Number(pricing.value.price_same_day) || 0;
}
if (deliveryOrder.value.emergency == 1) {
total += Number(pricing.value.price_emergency) || 0;
}
return total.toFixed(2);
}
const calculateEstimatedTotal = () => {
if (!deliveryOrder.value.gallons_ordered || !pricing.value.price_for_customer) {
return 0;
}
const gallons = Number(deliveryOrder.value.gallons_ordered);
const pricePerGallon = Number(pricing.value.price_for_customer);
let total = gallons * pricePerGallon;
if (deliveryOrder.value.prime == 1) {
total += Number(pricing.value.price_prime) || 0;
}
if (deliveryOrder.value.same_day == 1) {
total += Number(pricing.value.price_same_day) || 0;
}
if (deliveryOrder.value.emergency == 1) {
total += Number(pricing.value.price_emergency) || 0;
}
return total;
}
const getTransaction = (delivery_id: any) => {
// Simple endpoint to get transaction directly by delivery_id
const path = `${import.meta.env.VITE_BASE_URL}/payment/transaction/delivery/${delivery_id}`;
axios.get(path, {
withCredentials: true,
headers: authHeader()
}).then((response: any) => {
if (response.data.ok) {
transaction.value = response.data.transaction;
console.log("Transaction loaded:", transaction.value);
} else {
console.log("No transaction found for delivery:", delivery_id);
transaction.value = null;
}
}).catch((error: any) => {
console.error("Error fetching transaction:", error);
transaction.value = null;
});
}
</script>
<style scoped></style>

View File

@@ -121,104 +121,93 @@
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import { deliveryService } from '../../../services/deliveryService'
import { Delivery } from '../../../types/models'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryCancelled',
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
components: {
Header,
SideBar,
Footer,
},
// Functions
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
data() {
return {
token: null,
user: null,
deliveries: [] as any[],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/issue/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/cancelled/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
user.value = response.data.user;
}
})
},
},
.catch(() => {
user.value = null
})
}
const get_oil_orders = async (pageVal: number) => {
try {
const response = await deliveryService.getIssues(pageVal)
deliveries.value = response.data || []
} catch (error) {
console.error('Error fetching issue deliveries:', error)
deliveries.value = []
}
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/cancelled/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
}
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value)
})
</script>

View File

@@ -121,105 +121,93 @@
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import { deliveryService } from '../../../services/deliveryService'
import { Delivery } from '../../../types/models'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryDelivered',
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
components: {
Header,
SideBar,
Footer,
},
// Functions
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
data() {
return {
token: null,
user: null,
deliveries: [] as any[],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delivered/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
user.value = response.data.user;
}
})
},
},
.catch(() => {
user.value = null
})
}
const get_oil_orders = async (pageVal: number) => {
try {
const response = await deliveryService.getDelivered(pageVal)
deliveries.value = response.data || []
} catch (error) {
console.error('Error fetching delivered deliveries:', error)
deliveries.value = []
}
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
}
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value)
})
</script>

View File

@@ -121,109 +121,95 @@
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryFinalized',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [] as any[],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import { deliveryService } from '../../../services/deliveryService'
import { Delivery } from '../../../types/models'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/finalized/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
// Functions
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
},
},
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
</script>
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
}
})
.catch(() => {
user.value = null
})
}
const get_oil_orders = async (pageVal: number) => {
try {
const response = await deliveryService.getFinalized(pageVal)
deliveries.value = response.data || []
} catch (error) {
console.error('Error fetching finalized deliveries:', error)
deliveries.value = []
}
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
}
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value)
})
</script>
<style scoped>

View File

@@ -122,104 +122,93 @@
<Footer />
</template>
<script lang="ts">
import {defineComponent} from 'vue'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import { Delivery } from '../../../types/models'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import {notify} from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryIssue',
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
components: {
Header,
SideBar,
Footer,
},
// Functions
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
data() {
return {
token: null,
user: null,
deliveries: [] as any[],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/issue/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
user.value = response.data.user;
}
})
},
},
.catch(() => {
user.value = null
})
}
const get_oil_orders = (pageVal: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/issue/' + pageVal;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
deliveries.value = response.data
})
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
}
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value)
})
</script>

View File

@@ -157,108 +157,94 @@
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import { notify } from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryPending',
components: {
Header,
SideBar,
Footer,
},
data() {
return {
token: null,
user: null,
deliveries: [] as any[],
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
}
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
},
methods: {
getPage: function (page: any) {
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import { deliveryService } from '../../../services/deliveryService'
import { Delivery } from '../../../types/models'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import { notify } from "@kyvg/vue3-notification";
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/pending/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
},
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
},
// Functions
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
}
})
.catch(() => {
user.value = null
})
}
const get_oil_orders = async (pageVal: number) => {
try {
const response = await deliveryService.getPending(pageVal)
deliveries.value = response.data || []
} catch (error) {
console.error('Error fetching pending deliveries:', error)
deliveries.value = []
}
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
}
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value)
})
</script>
<style scoped></style>

View File

@@ -164,174 +164,116 @@
</div>
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import { deliveryService } from '../../../services/deliveryService'
import { Delivery } from '../../../types/models'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import { notify } from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryOutForDelivery',
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const totals = ref<{ town: string; gallons: number }[]>([])
const grand_total = ref(0)
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
components: {
Header,
SideBar,
Footer,
},
// Functions
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
data() {
return {
token: null,
user: null,
deliveries: [] as any[],
totals: [] as any[],
grand_total: 0,
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
}
})
.catch(() => {
user.value = null
})
}
const mod = (date: any) => new Date(date).getTime()
const get_oil_orders = async (pageVal: number) => {
try {
const response = await deliveryService.getOutForDelivery(pageVal)
deliveries.value = response.data || []
// Sort deliveries by Delivery # (id) in descending order
deliveries.value.sort((a, b) => b.id - a.id);
} catch (error) {
console.error('Error fetching out for delivery:', error)
deliveries.value = []
}
}
const get_totals = () => {
let path = import.meta.env.VITE_BASE_URL + '/deliverystatus/today-totals';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
totals.value = response.data.totals || []
grand_total.value = response.data.grand_total || 0
}).catch((error: any) => {
console.error('Error fetching totals:', error);
totals.value = []
grand_total.value = 0
})
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
this.get_totals()
},
methods: {
getPage: function (page: any) {
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
})
}
mod: (date: any) => new Date (date).getTime(),
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/outfordelivery/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
// Sort deliveries by Delivery # (id) in descending order
this.deliveries.sort((a, b) => b.id - a.id);
})
},
get_totals() {
let path = import.meta.env.VITE_BASE_URL + '/deliverystatus/today-totals';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.totals = response.data.totals || []
this.grand_total = response.data.grand_total || 0
}).catch((error: any) => {
console.error('Error fetching totals:', error);
this.totals = []
this.grand_total = 0
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
},
// printtTicketAll() {
// let path = import.meta.env.VITE_PRINT_URL + '/command/printticket/print_today';
// axios({
// method: 'get',
// url: path,
// headers: authHeader(),
// }).then((response: any) => {
// if (response.data.ok) {
// notify({
// title: "Success",
// text: "Sent to Printer",
// type: "success",
// });
// this.getPage(this.page)
// } else {
// notify({
// title: "Failure",
// text: "error printing",
// type: "success",
// });
// }
// })
// },
// printTicket(delivery_id: number) {
// let path = import.meta.env.VITE_PRINT_URL + '/command/printticket/' + delivery_id;
// axios({
// method: 'options',
// url: path,
// headers: authHeader(),
// }).then((response: any) => {
// if (response.data.ok) {
// notify({
// title: "Success",
// text: "Sent to Printer",
// type: "success",
// });
// this.getPage(this.page)
// } else {
// notify({
// title: "Failure",
// text: "error printing",
// type: "success",
// });
// }
// })
// },
},
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value)
get_totals()
})
</script>

View File

@@ -157,173 +157,164 @@
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import { Delivery } from '../../../types/models'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import { notify } from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryOutForDelivery',
interface TownTotal {
town: string;
gallons: number;
}
components: {
Header,
SideBar,
Footer,
},
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const totals = ref<TownTotal[]>([])
const grand_total = ref(0)
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
data() {
return {
token: null,
user: null,
deliveries: [] as any[],
totals: [] as any[],
grand_total: 0,
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
// Functions
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
}
})
.catch(() => {
user.value = null
})
}
const get_oil_orders = (pageVal: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/tommorrow/' + pageVal;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
deliveries.value = response.data
})
}
const get_totals = () => {
let path = import.meta.env.VITE_BASE_URL + '/deliverystatus/tomorrow-totals';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
totals.value = response.data.totals || []
grand_total.value = response.data.grand_total || 0
}).catch((error: any) => {
console.error('Error fetching totals:', error);
totals.value = []
grand_total.value = 0
})
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
},
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
this.get_totals()
},
methods: {
getPage: function (page: any) {
this.deliveries = [];
this.get_oil_orders(page)
},
})
}
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/tommorrow/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
get_totals() {
let path = import.meta.env.VITE_BASE_URL + '/deliverystatus/tomorrow-totals';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.totals = response.data.totals || []
this.grand_total = response.data.grand_total || 0
}).catch((error: any) => {
console.error('Error fetching totals:', error);
this.totals = []
this.grand_total = 0
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
},
printtTicketAll() {
let path = import.meta.env.VITE_PRINT_URL + '/command/printticket/print_tommorrow';
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "Sent to Printer",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error printing",
type: "success",
});
}
})
},
printTicket(delivery_id: number) {
let path = import.meta.env.VITE_PRINT_URL + '/command/printticket/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "Sent to Printer",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error printing",
type: "success",
});
}
})
},
},
const printtTicketAll = () => {
let path = import.meta.env.VITE_PRINT_URL + '/command/printticket/print_tommorrow';
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "Sent to Printer",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error printing",
type: "success",
});
}
})
}
const printTicket = (delivery_id: number) => {
let path = import.meta.env.VITE_PRINT_URL + '/command/printticket/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "Sent to Printer",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error printing",
type: "success",
});
}
})
}
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value)
get_totals()
})
</script>

View File

@@ -137,127 +137,112 @@
<Footer />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import axios from 'axios'
import authHeader from '../../../services/auth.header'
import { deliveryService } from '../../../services/deliveryService'
import { Delivery } from '../../../types/models'
import Header from '../../../layouts/headers/headerauth.vue'
import PaginationComp from '../../../components/pagination.vue'
import SideBar from '../../../layouts/sidebar/sidebar.vue'
import Footer from '../../../layouts/footers/footer.vue'
import { notify } from "@kyvg/vue3-notification";
export default defineComponent({
name: 'deliveryWaiting',
// Reactive data
const token = ref(null)
const user = ref(null)
const deliveries = ref<Delivery[]>([])
const totals = ref<{ town: string; gallons: number }[]>([])
const grand_total = ref(0)
const page = ref(1)
const perPage = ref(50)
const recordsLength = ref(0)
const options = ref({
edgeNavigation: false,
format: false,
template: PaginationComp
})
components: {
Header,
SideBar,
Footer,
},
// Functions
const getPage = (pageVal: any) => {
deliveries.value = [];
get_oil_orders(pageVal)
}
data() {
return {
token: null,
user: null,
deliveries: [] as any[],
totals: [] as any[],
grand_total: 0,
page: 1,
perPage: 50,
recordsLength: 0,
options: {
edgeNavigation: false,
format: false,
template: PaginationComp
const userStatus = () => {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
user.value = response.data.user;
}
})
.catch(() => {
user.value = null
})
}
const get_oil_orders = async (pageVal: number) => {
try {
const response = await deliveryService.getWaiting(pageVal)
deliveries.value = response.data || []
} catch (error) {
console.error('Error fetching waiting deliveries:', error)
deliveries.value = []
}
}
const get_totals = () => {
let path = import.meta.env.VITE_BASE_URL + '/deliverystatus/waiting-totals';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
totals.value = response.data.totals || []
grand_total.value = response.data.grand_total || 0
}).catch((error: any) => {
console.error('Error fetching totals:', error);
totals.value = []
grand_total.value = 0
})
}
const deleteCall = (delivery_id: any) => {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
getPage(page.value)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
},
})
}
created() {
this.userStatus()
},
mounted() {
this.getPage(this.page)
this.get_totals()
},
methods: {
getPage: function (page: any) {
// we simulate an api call that fetch the records from a backend
this.deliveries = [];
this.get_oil_orders(page)
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({
method: 'get',
url: path,
withCredentials: true,
headers: authHeader(),
})
.then((response: any) => {
if (response.data.ok) {
this.user = response.data.user;
}
})
.catch(() => {
this.user = null
})
},
get_oil_orders(page: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/waiting/' + page;
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.deliveries = response.data
})
},
get_totals() {
let path = import.meta.env.VITE_BASE_URL + '/deliverystatus/waiting-totals';
axios({
method: 'get',
url: path,
headers: authHeader(),
}).then((response: any) => {
this.totals = response.data.totals || []
this.grand_total = response.data.grand_total || 0
}).catch((error: any) => {
console.error('Error fetching totals:', error);
this.totals = []
this.grand_total = 0
})
},
deleteCall(delivery_id: any) {
let path = import.meta.env.VITE_BASE_URL + '/delivery/delete/' + delivery_id;
axios({
method: 'delete',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "deleted delivery",
type: "success",
});
this.getPage(this.page)
} else {
notify({
title: "Failure",
text: "error deleting delivery",
type: "success",
});
}
})
},
},
// Lifecycle
onMounted(() => {
userStatus()
getPage(page.value)
get_totals()
})
</script>