664 lines
29 KiB
Vue
Executable File
664 lines
29 KiB
Vue
Executable File
<template>
|
|
<div class="flex">
|
|
|
|
<!-- Main container with responsive horizontal padding -->
|
|
<div class="w-full px-4 md:px-6 py-4">
|
|
<div class="text-sm breadcrumbs">
|
|
<ul>
|
|
<li><router-link :to="{ name: 'home' }">Home</router-link></li>
|
|
<li><router-link :to="{ name: 'customer' }">Customers</router-link></li>
|
|
<li v-if="customer && customer.id">
|
|
<router-link :to="{ name: 'customerProfile', params: { id: customer.id } }">
|
|
{{ customer.customer_first_name }} {{ customer.customer_last_name }}
|
|
</router-link>
|
|
</li>
|
|
<li>Finalize Ticket #{{ deliveryOrder.id }}</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Page Header -->
|
|
<div class="flex flex-wrap justify-between items-center gap-2 mt-4">
|
|
<h1 class="text-3xl font-bold">
|
|
Finalize Delivery #{{ deliveryOrder.id }}
|
|
</h1>
|
|
<router-link v-if="deliveryOrder.id" :to="{ name: 'deliveryEdit', params: { id: deliveryOrder.id } }">
|
|
<button class="btn btn-sm btn-secondary">Edit Order</button>
|
|
</router-link>
|
|
</div>
|
|
|
|
<!-- NEW LAYOUT: A single 2-column grid for the whole page -->
|
|
<div v-if="deliveryOrder" class="grid grid-cols-1 lg:grid-cols-2 gap-4 mt-4">
|
|
|
|
<!-- LEFT COLUMN: All Display Information -->
|
|
<div class="space-y-4">
|
|
|
|
<!-- Customer Info Card -->
|
|
<div class="bg-neutral rounded-lg p-5">
|
|
<div class="text-xl font-bold mb-2">Customer</div>
|
|
<div>
|
|
<div class="font-bold">{{ customer.customer_first_name }} {{ customer.customer_last_name }}</div>
|
|
<div>{{customer.customer_address}}</div>
|
|
<div v-if="customer.customer_apt && customer.customer_apt !== 'None'">{{ customer.customer_apt }}</div>
|
|
<div>
|
|
{{ customer.customer_town }},
|
|
<span v-if="customer.customer_state == 0">Massachusetts</span>
|
|
<span v-else-if="customer.customer_state == 1">Rhode Island</span>
|
|
<span v-else-if="customer.customer_state == 2">New Hampshire</span>
|
|
<span v-else-if="customer.customer_state == 3">Maine</span>
|
|
<span v-else-if="customer.customer_state == 4">Vermont</span>
|
|
<span v-else-if="customer.customer_state == 5">Maine</span>
|
|
<span v-else-if="customer.customer_state == 6">New York</span>
|
|
<span v-else>Unknown state</span>
|
|
{{ customer.customer_zip }}
|
|
</div>
|
|
<div class="mt-2 text-sm">
|
|
{{ customer.customer_phone_number }}
|
|
(<span v-if="customer.customer_home_type == 0">Residential</span>
|
|
<span v-else-if="customer.customer_home_type == 1">apartment</span>
|
|
<span v-else-if="customer.customer_home_type == 2">condo</span>
|
|
<span v-else-if="customer.customer_home_type == 3">commercial</span>
|
|
<span v-else-if="customer.customer_home_type == 4">business</span>
|
|
<span v-else-if="customer.customer_home_type == 5">construction</span>
|
|
<span v-else-if="customer.customer_home_type == 6">container</span>)
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delivery Details Card -->
|
|
<div class="bg-neutral rounded-lg p-5">
|
|
<h3 class="text-xl font-bold mb-4">Delivery Details</h3>
|
|
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
|
<div>
|
|
<div class="font-bold">Status</div>
|
|
<div class="opacity-80">
|
|
<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">Today</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 == 10">Finalized</span>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="font-bold">Scheduled Date</div>
|
|
<div class="opacity-80">{{ deliveryOrder.expected_delivery_date }}</div>
|
|
</div>
|
|
<div>
|
|
<div class="font-bold">When Ordered</div>
|
|
<div class="opacity-80">{{ deliveryOrder.when_ordered }}</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Transaction Summary -->
|
|
<div v-if="transaction && transaction.auth_net_transaction_id" class="bg-neutral rounded-lg p-5">
|
|
<h3 class="text-xl font-bold mb-4">Transaction Summary</h3>
|
|
<div class="space-y-3">
|
|
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
|
<div class="flex justify-between">
|
|
<span class="font-bold">Transaction ID:</span>
|
|
<span class="font-mono">{{ transaction.auth_net_transaction_id }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="font-bold">Pre-Auth Amount:</span>
|
|
<span>${{ transaction.preauthorize_amount || '0.00' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="font-bold">Charge Amount:</span>
|
|
<span>${{ transaction.charge_amount || '0.00' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="font-bold">Type:</span>
|
|
<span :class="getTypeColor(transaction.transaction_type)">{{ transaction.transaction_type === 0 ? 'Charge' : transaction.transaction_type === 1 ? 'Auth' : 'Capture' }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="font-bold">Date:</span>
|
|
<span>{{ transaction.created_at }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="font-bold">Status:</span>
|
|
<span :class="transaction.status === 0 ? 'text-success' : 'text-error'">
|
|
{{ transaction.status === 0 ? 'Approved' : 'Declined' }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Financial Summary Card -->
|
|
<div class="bg-neutral rounded-lg p-5">
|
|
<h3 class="text-xl font-bold mb-4">Financial Summary</h3>
|
|
<div class="space-y-3">
|
|
<!-- Pricing & Gallons -->
|
|
<div class="grid grid-cols-2 sm:grid-cols-3 gap-3 text-sm">
|
|
<div>
|
|
<div class="font-bold">Price / Gallon</div>
|
|
<div class="opacity-80">${{ Number(deliveryOrder.customer_price).toFixed(2) }}</div>
|
|
</div>
|
|
<div>
|
|
<div class="font-bold">Gallons Ordered</div>
|
|
<div class="opacity-80" v-if="deliveryOrder.customer_asked_for_fill == 1">FILL</div>
|
|
<div class="opacity-80" v-else>{{ deliveryOrder.gallons_ordered }}</div>
|
|
</div>
|
|
<div>
|
|
<div class="font-bold">Gallons Delivered</div>
|
|
<div class="opacity-80">{{ FinalizeOilOrderForm.gallons_delivered || deliveryOrder.gallons_delivered || 'N/A' }}</div>
|
|
</div>
|
|
</div>
|
|
<!-- Fees -->
|
|
<div class="text-sm space-y-1 border-t border-base-100 pt-3">
|
|
<div v-if="deliveryOrder.prime == 1" class="flex justify-between"><span>Prime Fee</span> <span>${{ Number(pricing.price_prime).toFixed(2) }}</span></div>
|
|
<div v-if="deliveryOrder.same_day === 1" class="flex justify-between"><span>Same Day Fee</span> <span>${{ Number(pricing.price_same_day).toFixed(2) }}</span></div>
|
|
</div>
|
|
<!-- Payment -->
|
|
<div class="border-t border-base-100 pt-3">
|
|
<div class="font-bold text-sm">Payment Method</div>
|
|
<div class="opacity-80 text-sm">
|
|
<span v-if="deliveryOrder.payment_type == 0">Cash</span>
|
|
<span v-else-if="deliveryOrder.payment_type == 1">CC - Tiger (Physical)</span>
|
|
<span v-else-if="deliveryOrder.payment_type == 11">CC - Authorize (API)</span>
|
|
<span v-else-if="deliveryOrder.payment_type == 2">Credit Card & Cash</span>
|
|
<span v-else-if="deliveryOrder.payment_type == 3">Check</span>
|
|
<span v-else-if="deliveryOrder.payment_type == 4">Other</span>
|
|
<span v-else>No Payment Type Added</span>
|
|
</div>
|
|
<div v-if="userCardfound && (deliveryOrder.payment_type == 1 || deliveryOrder.payment_type == 2 || deliveryOrder.payment_type == 11)" class="mt-2 p-3 rounded-lg border bg-accent/20 border-accent">
|
|
<!-- --- MODIFICATION --- Full display of card data -->
|
|
<div class="font-bold text-sm">{{ userCard.type_of_card }}</div>
|
|
<div class="text-sm font-mono tracking-wider space-y-1">
|
|
<p>Name: {{ userCard.name_on_card }}</p>
|
|
<p>Card: {{ userCard.card_number }}</p>
|
|
<p>CVV: {{ userCard.security_number }}</p>
|
|
<p>Exp: {{ userCard.expiration_month }} / {{ userCard.expiration_year }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Total Breakdown -->
|
|
<div class="border-t border-base-100 pt-3 space-y-2">
|
|
<!-- Show breakdown only when promo is active -->
|
|
<div v-if="promo_active">
|
|
<!-- Oil & Fees Total (before discount) -->
|
|
<div class="flex justify-between items-center text-sm">
|
|
<span>Oil & Fees Total</span>
|
|
<span>${{ total_amount.toFixed(2) }}</span>
|
|
</div>
|
|
<!-- Promo Discount -->
|
|
<div class="flex justify-between items-center text-sm text-success">
|
|
<span>{{ promo.name_of_promotion }}</span>
|
|
<span>-${{ discount.toFixed(2) }}</span>
|
|
</div>
|
|
</div>
|
|
<!-- Final Charge Amount (always show) -->
|
|
<div class="flex justify-between items-center">
|
|
<span class="text-lg font-bold">
|
|
Final Charge Amount
|
|
</span>
|
|
<span class="text-2xl font-bold text-success">
|
|
${{ finalChargeAmount.toFixed(2) }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- RIGHT COLUMN: Finalize Form -->
|
|
<div class="space-y-4">
|
|
<div class="bg-base-100 rounded-lg p-5">
|
|
<h2 class="text-2xl font-bold mb-4">Finalize Ticket</h2>
|
|
<form class="space-y-4" @submit.prevent="onSubmit">
|
|
|
|
<div>
|
|
<label class="label"><span class="label-text font-bold">Gallons Delivered</span></label>
|
|
<input v-model="FinalizeOilOrderForm.gallons_delivered" class="input input-bordered input-sm w-full max-w-xs" type="number" step="0.01" placeholder="# gallons" />
|
|
</div>
|
|
|
|
<div>
|
|
<label class="label"><span class="label-text font-bold">Fill Location</span></label>
|
|
<input v-model="FinalizeOilOrderForm.fill_location" class="input input-bordered input-sm w-full max-w-xs" type="text" placeholder="Fill location (e.g., 1-12)" />
|
|
</div>
|
|
|
|
<div>
|
|
<label class="label"><span class="label-text font-bold">Cash Received</span></label>
|
|
<input v-model="FinalizeOilOrderForm.cash_recieved" class="input input-bordered input-sm w-full max-w-xs" type="number" step="0.01" placeholder="Amount received" />
|
|
</div>
|
|
|
|
<div>
|
|
<label class="label"><span class="label-text font-bold">Check #</span></label>
|
|
<input v-model="FinalizeOilOrderForm.check_number" class="input input-bordered input-sm w-full max-w-xs" type="text" placeholder="Check Number" />
|
|
</div>
|
|
|
|
<div class="pt-2">
|
|
<!-- --- MODIFICATION --- Added loading state to button -->
|
|
<button type="submit" class="btn btn-secondary btn-sm" :disabled="isLoading">
|
|
<span v-if="isLoading" class="loading loading-spinner loading-xs"></span>
|
|
{{ isLoading ? 'Finalizing...' : 'Finalize Delivery' }}
|
|
</button>
|
|
</div>
|
|
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="text-center p-10">
|
|
Loading ticket details...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<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 SideBar from '../../../layouts/sidebar/sidebar.vue'
|
|
import Footer from '../../../layouts/footers/footer.vue'
|
|
import { notify } from "@kyvg/vue3-notification"
|
|
|
|
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;
|
|
}
|
|
interface PreAuthTransaction {
|
|
id: number;
|
|
transaction_type: number;
|
|
status: number;
|
|
auth_net_transaction_id: string;
|
|
preauthorize_amount: number;
|
|
}
|
|
|
|
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,
|
|
}
|
|
},
|
|
computed: {
|
|
finalChargeAmount(): number {
|
|
// If promo is active, use server-calculated totals (which include discounts)
|
|
if (this.promo_active && this.total_amount_after_discount > 0) {
|
|
return this.total_amount_after_discount;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
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;
|
|
this.FinalizeOilOrderForm.gallons_delivered = this.deliveryOrder.gallons_delivered || '';
|
|
|
|
|
|
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();
|
|
});
|
|
},
|
|
|
|
// 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 } });
|
|
}
|
|
|
|
} 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 } });
|
|
}
|
|
|
|
} 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 } });
|
|
|
|
} 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 } });
|
|
}
|
|
},
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style scoped></style>
|