added cancel button

This commit is contained in:
2025-10-20 12:01:16 -04:00
parent 78e959883d
commit e70ae887f3
10 changed files with 136 additions and 66 deletions

View File

@@ -377,6 +377,7 @@ export default defineComponent({
return {
v$: useValidate(),
user: null as any,
customer: {} as any,
isLoading: false, // For main form submission
isCardSaving: false, // For quick add card form
quickGallonAmounts: [100, 125, 150, 175, 200, 220],
@@ -384,6 +385,8 @@ export default defineComponent({
promos: [] as Promo[],
truckDriversList: [] as Driver[],
pricingTiers: [] as PricingTier[],
isLoadingAuthorize: true,
authorizeCheck: { profile_exists: false, has_payment_methods: false, missing_components: [] as string[], valid_for_charging: false },
isConfirmationModalVisible: false,
formDelivery: {
gallons_ordered: '',
@@ -410,7 +413,7 @@ export default defineComponent({
card_name: '',
type_of_card: '',
} as CardFormData,
customer: {} as Customer,
}
},
validations() {
@@ -622,7 +625,29 @@ export default defineComponent({
this.isLoading = false;
}
},
async checkAuthorizeAccount() {
if (!this.customer.id) return;
this.isLoadingAuthorize = true;
try {
const path = `${import.meta.env.VITE_AUTHORIZE_URL}/user/check-authorize-account/${this.customer.id}`;
const response = await axios.get(path, { headers: authHeader() });
this.authorizeCheck = response.data;
} catch (error) {
console.error("Failed to check authorize account:", error);
notify({ title: "Error", text: "Could not check payment account status.", type: "error" });
// Set default error state
this.authorizeCheck = {
profile_exists: false,
has_payment_methods: false,
missing_components: ['api_error'],
valid_for_charging: false
};
} finally {
this.isLoadingAuthorize = false;
}
},
async onCardSubmit() {
this.v$.formCard.$validate();
if (this.v$.formCard.$error) {
@@ -643,13 +668,7 @@ export default defineComponent({
name_on_card: this.formCard.card_name, // Map card_name to name_on_card for Flask
};
// Payload for FastAPI backend (it only needs the essentials for Authorize.Net)
const fastapiPayload = {
card_number: this.formCard.card_number.replace(/\s/g, ''),
expiration_date: `${this.formCard.expiration_year}-${this.formCard.expiration_month}`,
cvv: this.formCard.security_number, // Map security_number to cvv for FastAPI
main_card: false, // Send this to FastAPI as well
};
// --- STEP 2: CRITICAL CALL - SAVE CARD TO LOCAL DATABASE VIA FLASK ---
try {
@@ -671,6 +690,15 @@ export default defineComponent({
}
// --- STEP 3: BEST-EFFORT CALL - TOKENIZE CARD VIA FASTAPI ---
if (this.authorizeCheck.profile_exists) {
// Payload for FastAPI backend (it only needs the essentials for Authorize.Net)
const fastapiPayload = {
card_number: this.formCard.card_number.replace(/\s/g, ''),
expiration_date: `${this.formCard.expiration_year}-${this.formCard.expiration_month}`,
cvv: this.formCard.security_number, // Map security_number to cvv for FastAPI
main_card: false, // Send this to FastAPI as well
};
try {
const fastapiPath = `${import.meta.env.VITE_AUTHORIZE_URL}/api/payments/customers/${this.customer.id}/cards`;
console.log("Attempting to tokenize card with Authorize.Net via FastAPI:", fastapiPath);
@@ -680,7 +708,9 @@ export default defineComponent({
// If this fails, we just log it for the developers. We DON'T show an error to the user.
console.warn("NON-CRITICAL-ERROR: Tokenization with Authorize.Net failed, but the card was saved locally.", error.response?.data || error.message);
}
}else{
console.log("Skipping Authorize.Net tokenization as no profile exists for customer.");
}
// --- STEP 4: ALWAYS SHOW SUCCESS, REFRESH CARDS, STAY ON PAGE ---
// This code runs as long as the first (Flask) call was successful.
notify({ type: 'success', title: 'Card Saved!' });

View File

@@ -339,6 +339,13 @@
<router-link :to="{ name: 'Ticket', params: { id: deliveryOrder.id } }">
<button class="btn btn-success btn-sm">Print Ticket</button>
</router-link>
<button
class="btn btn-error btn-sm"
@click="cancelDelivery"
v-if="[0, 2, 3, 4, 5, 9].includes(deliveryOrder.delivery_status)"
>
Cancel
</button>
</div>
</div>
</div>
@@ -527,6 +534,36 @@ export default defineComponent({
}
})
},
cancelDelivery() {
let path = import.meta.env.VITE_BASE_URL + '/delivery/cancel/' + this.deliveryOrder.id;
axios({
method: 'post',
url: path,
headers: authHeader(),
}).then((response: any) => {
if (response.data.ok) {
notify({
title: "Success",
text: "Delivery cancelled",
type: "success",
});
// Refresh the delivery data
this.getOilOrder(this.deliveryOrder.id);
} else {
notify({
title: "Failure",
text: "Failed to cancel delivery",
type: "error",
});
}
}).catch(() => {
notify({
title: "Error",
text: "Error cancelling delivery",
type: "error",
});
});
},
userStatus() {
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
axios({

View File

@@ -35,8 +35,6 @@
<th>Status</th>
<th>Town / Address</th>
<th>Gallons</th>
<th>Options</th>
<th>Payment</th>
<th class="text-right">Actions</th>
</tr>
</thead>
@@ -79,13 +77,7 @@
<span v-if="oil.emergency" class="badge badge-error badge-xs">EMERGENCY</span>
</div>
</td>
<td>
<span v-if="oil.payment_type == 0">Cash</span>
<span v-else-if="oil.payment_type == 1">CC</span>
<span v-else-if="oil.payment_type == 2">Cash/CC</span>
<span v-else-if="oil.payment_type == 3">Check</span>
<span v-else-if="oil.payment_type == 4">Other</span>
</td>
<td class="text-right">
<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>
@@ -137,13 +129,7 @@
<span v-if="oil.customer_asked_for_fill" class="badge badge-info badge-xs">FILL</span>
<span v-else>{{ oil.gallons_ordered }}</span>
</p>
<p><strong class="font-semibold">Payment:</strong>
<span v-if="oil.payment_type == 0">Cash</span>
<span v-else-if="oil.payment_type == 1">CC</span>
<span v-else-if="oil.payment_type == 2">Cash/CC</span>
<span v-else-if="oil.payment_type == 3">Check</span>
<span v-else-if="oil.payment_type == 4">Other</span>
</p>
</div>
<div class="card-actions justify-end flex-wrap gap-2 mt-2">

View File

@@ -29,7 +29,7 @@
<th>Status</th>
<th>Town / Address</th>
<th>Gallons</th>
<th>Options</th>
<th class="text-right">Actions</th>
</tr>
</thead>