Refactored onsite meeting to bids all over the codebase.

This commit is contained in:
rocketdebris 2025-12-10 10:25:37 -05:00
parent 6e2535763f
commit 080d9ff1b4
6 changed files with 48 additions and 49 deletions

View File

@ -3,7 +3,7 @@ import json
from custom_ui.db_utils import build_error_response, build_success_response, process_filters, process_sorting from custom_ui.db_utils import build_error_response, build_success_response, process_filters, process_sorting
@frappe.whitelist() @frappe.whitelist()
def get_week_onsite_meetings(week_start, week_end): def get_week_bid_meetings(week_start, week_end):
"""Get On-Site Meetings scheduled within a specific week.""" """Get On-Site Meetings scheduled within a specific week."""
try: try:
meetings = frappe.db.get_all( meetings = frappe.db.get_all(
@ -24,13 +24,13 @@ def get_week_onsite_meetings(week_start, week_end):
return build_error_response(str(e), 500) return build_error_response(str(e), 500)
@frappe.whitelist() @frappe.whitelist()
def get_onsite_meetings(fields=["*"], filters={}): def get_bid_meetings(fields=["*"], filters={}):
"""Get paginated On-Site Meetings with filtering and sorting support.""" """Get paginated On-Site Meetings with filtering and sorting support."""
try: try:
print("DEBUG: Raw onsite meeting options received:", filters) print("DEBUG: Raw bid meeting options received:", filters)
processed_filters = process_filters(filters) processed_filters = process_filters(filters)
meetings = frappe.db.get_all( meetings = frappe.db.get_all(
"On-Site Meeting", "On-Site Meeting",
fields=fields, fields=fields,
@ -40,17 +40,17 @@ def get_onsite_meetings(fields=["*"], filters={}):
for meeting in meetings: for meeting in meetings:
address_doc = frappe.get_doc("Address", meeting["address"]) address_doc = frappe.get_doc("Address", meeting["address"])
meeting["address"] = address_doc.as_dict() meeting["address"] = address_doc.as_dict()
return build_success_response( return build_success_response(
meetings meetings
) )
except Exception as e: except Exception as e:
frappe.log_error(message=str(e), title="Get On-Site Meetings Failed") frappe.log_error(message=str(e), title="Get On-Site Meetings Failed")
return build_error_response(str(e), 500) return build_error_response(str(e), 500)
@frappe.whitelist() @frappe.whitelist()
def get_unscheduled_onsite_meetings(): def get_unscheduled_bid_meetings():
"""Get On-Site Meetings that are unscheduled.""" """Get On-Site Meetings that are unscheduled."""
try: try:
meetings = frappe.db.get_all( meetings = frappe.db.get_all(
@ -63,26 +63,26 @@ def get_unscheduled_onsite_meetings():
except Exception as e: except Exception as e:
frappe.log_error(message=str(e), title="Get Unscheduled On-Site Meetings Failed") frappe.log_error(message=str(e), title="Get Unscheduled On-Site Meetings Failed")
return build_error_response(str(e), 500) return build_error_response(str(e), 500)
@frappe.whitelist() @frappe.whitelist()
def create_onsite_meeting(address, notes=""): def create_bid_meeting(address, notes=""):
"""Create a new On-Site Meeting with Unscheduled status.""" """Create a new On-Site Meeting with Unscheduled status."""
try: try:
print(f"DEBUG: Creating meeting with address='{address}', notes='{notes}'") print(f"DEBUG: Creating meeting with address='{address}', notes='{notes}'")
# Validate address parameter # Validate address parameter
if not address or address == "None" or not address.strip(): if not address or address == "None" or not address.strip():
return build_error_response("Address is required and cannot be empty.", 400) return build_error_response("Address is required and cannot be empty.", 400)
# Get the address document name from the full address string # Get the address document name from the full address string
address_name = frappe.db.get_value("Address", filters={"full_address": address}, fieldname="name") address_name = frappe.db.get_value("Address", filters={"full_address": address}, fieldname="name")
print(f"DEBUG: Address lookup result: address_name='{address_name}'") print(f"DEBUG: Address lookup result: address_name='{address_name}'")
if not address_name: if not address_name:
return build_error_response(f"Address '{address}' not found in the system.", 404) return build_error_response(f"Address '{address}' not found in the system.", 404)
# Create the meeting with Unscheduled status # Create the meeting with Unscheduled status
meeting = frappe.get_doc({ meeting = frappe.get_doc({
"doctype": "On-Site Meeting", "doctype": "On-Site Meeting",
@ -93,19 +93,19 @@ def create_onsite_meeting(address, notes=""):
meeting.flags.ignore_permissions = True meeting.flags.ignore_permissions = True
meeting.insert(ignore_permissions=True) meeting.insert(ignore_permissions=True)
frappe.db.commit() frappe.db.commit()
# Clear any auto-generated messages from Frappe # Clear any auto-generated messages from Frappe
frappe.local.message_log = [] frappe.local.message_log = []
print(f"DEBUG: Meeting created successfully: {meeting.name}") print(f"DEBUG: Meeting created successfully: {meeting.name}")
return build_success_response(meeting.as_dict()) return build_success_response(meeting.as_dict())
except Exception as e: except Exception as e:
frappe.log_error(message=str(e), title="Create On-Site Meeting Failed") frappe.log_error(message=str(e), title="Create On-Site Meeting Failed")
return build_error_response(str(e), 500) return build_error_response(str(e), 500)
@frappe.whitelist() @frappe.whitelist()
def update_onsite_meeting(name, data): def update_bid_meeting(name, data):
"""Update an existing On-Site Meeting.""" """Update an existing On-Site Meeting."""
defualts = { defualts = {
"address": None, "address": None,
@ -141,4 +141,4 @@ def update_onsite_meeting(name, data):
return build_error_response(f"On-Site Meeting '{name}' does not exist.", 404) return build_error_response(f"On-Site Meeting '{name}' does not exist.", 404)
except Exception as e: except Exception as e:
return build_error_response(str(e), 500) return build_error_response(str(e), 500)

View File

@ -20,8 +20,8 @@ const FRAPPE_UPSERT_INVOICE_METHOD = "custom_ui.api.db.invoices.upsert_invoice";
const FRAPPE_GET_WARRANTY_CLAIMS_METHOD = "custom_ui.api.db.warranties.get_warranty_claims"; const FRAPPE_GET_WARRANTY_CLAIMS_METHOD = "custom_ui.api.db.warranties.get_warranty_claims";
// On-Site Meeting methods // On-Site Meeting methods
const FRAPPE_GET_WEEK_ONSITE_MEETINGS_METHOD = const FRAPPE_GET_WEEK_ONSITE_MEETINGS_METHOD =
"custom_ui.api.db.onsite_meetings.get_week_onsite_meetings"; "custom_ui.api.db.bid_meetings.get_week_bid_meetings";
const FRAPPE_GET_ONSITE_MEETINGS_METHOD = "custom_ui.api.db.onsite_meetings.get_onsite_meetings"; const FRAPPE_GET_ONSITE_MEETINGS_METHOD = "custom_ui.api.db.bid_meetings.get_bid_meetings";
// Address methods // Address methods
const FRAPPE_GET_ADDRESSES_METHOD = "custom_ui.api.db.addresses.get_addresses"; const FRAPPE_GET_ADDRESSES_METHOD = "custom_ui.api.db.addresses.get_addresses";
// Client methods // Client methods
@ -113,29 +113,29 @@ class Api {
// ON-SITE MEETING METHODS // ON-SITE MEETING METHODS
// ============================================================================ // ============================================================================
static async getUnscheduledOnSiteMeetings() { static async getUnscheduledBidMeetings() {
return await this.request( return await this.request(
"custom_ui.api.db.onsite_meetings.get_unscheduled_onsite_meetings", "custom_ui.api.db.bid_meetings.get_unscheduled_bid_meetings",
); );
} }
static async getScheduledOnSiteMeetings(fields = ["*"], filters = {}) { static async getScheduledBidMeetings(fields = ["*"], filters = {}) {
return await this.request(FRAPPE_GET_ONSITE_MEETINGS_METHOD, { fields, filters }); return await this.request(FRAPPE_GET_ONSITE_MEETINGS_METHOD, { fields, filters });
} }
static async getWeekOnSiteMeetings(weekStart, weekEnd) { static async getWeekBidMeetings(weekStart, weekEnd) {
return await this.request(FRAPPE_GET_WEEK_ONSITE_MEETINGS_METHOD, { weekStart, weekEnd }); return await this.request(FRAPPE_GET_WEEK_ONSITE_MEETINGS_METHOD, { weekStart, weekEnd });
} }
static async updateOnSiteMeeting(name, data) { static async updateBidMeeting(name, data) {
return await this.request("custom_ui.api.db.onsite_meetings.update_onsite_meeting", { return await this.request("custom_ui.api.db.bid_meetings.update_bid_meeting", {
name, name,
data, data,
}); });
} }
static async createOnSiteMeeting(address, notes = "") { static async createBidMeeting(address, notes = "") {
return await this.request("custom_ui.api.db.onsite_meetings.create_onsite_meeting", { return await this.request("custom_ui.api.db.bid_meetings.create_bid_meeting", {
address, address,
notes, notes,
}); });

View File

@ -54,9 +54,9 @@ const createButtons = ref([
}, },
}, },
{ {
label: "On-Site Meeting", label: "Bid",
command: () => { command: () => {
router.push("/schedule-onsite?new=true"); router.push("/schedule-bid?new=true");
}, },
}, },
{ {
@ -102,10 +102,9 @@ const categories = ref([
{ {
name: "Clients", name: "Clients",
icon: Community, icon: Community,
//url: "/clients"
buttons: clientButtons, buttons: clientButtons,
}, },
{ name: "Bids", icon: Neighbourhood, url: "/schedule-onsite" }, { name: "Bids", icon: Neighbourhood, url: "/schedule-bid" },
{ name: "Estimates", icon: Calculator, url: "/estimates" }, { name: "Estimates", icon: Calculator, url: "/estimates" },
{ name: "Jobs", icon: Hammer, url: "/jobs" }, { name: "Jobs", icon: Hammer, url: "/jobs" },
{ name: "Payments/Invoices", icon: ReceiveDollars, url: "/invoices" }, { name: "Payments/Invoices", icon: ReceiveDollars, url: "/invoices" },

View File

@ -6,7 +6,7 @@
@confirm="handleConfirm" @confirm="handleConfirm"
@cancel="handleCancel" @cancel="handleCancel"
> >
<template #title>Schedule New On-Site Meeting</template> <template #title>Schedule New Bid Meeting</template>
<div class="new-meeting-form"> <div class="new-meeting-form">
<div class="form-group"> <div class="form-group">
<label for="meeting-address">Address: <span class="required">*</span></label> <label for="meeting-address">Address: <span class="required">*</span></label>

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="schedule-onsite-container"> <div class="schedule-bid-container">
<!-- Header --> <!-- Header -->
<div class="header"> <div class="header">
<h2>On-Site Meeting Schedule</h2> <h2>Bid Schedule</h2>
<div class="header-controls"> <div class="header-controls">
<v-btn <v-btn
@click="previousWeek" @click="previousWeek"
@ -202,7 +202,7 @@
/> />
<!-- New Meeting Modal --> <!-- New Meeting Modal -->
<OnSiteMeetingModal <BidMeetingModal
v-model:visible="showNewMeetingModal" v-model:visible="showNewMeetingModal"
:initial-address="queryAddress" :initial-address="queryAddress"
@confirm="handleNewMeetingConfirm" @confirm="handleNewMeetingConfirm"
@ -214,7 +214,7 @@
<script setup> <script setup>
import { ref, computed, onMounted, watch } from "vue"; import { ref, computed, onMounted, watch } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import OnSiteMeetingModal from "../modals/OnSiteMeetingModal.vue"; import BidMeetingModal from "../modals/BidMeetingModal.vue";
import MeetingDetailsModal from "../modals/MeetingDetailsModal.vue"; import MeetingDetailsModal from "../modals/MeetingDetailsModal.vue";
import { useLoadingStore } from "../../stores/loading"; import { useLoadingStore } from "../../stores/loading";
import { useNotificationStore } from "../../stores/notifications-primevue"; import { useNotificationStore } from "../../stores/notifications-primevue";
@ -470,7 +470,7 @@ const handleNewMeetingConfirm = async (meetingData) => {
loadingStore.setLoading(true); loadingStore.setLoading(true);
// Create the meeting via API // Create the meeting via API
const result = await Api.createOnSiteMeeting(meetingData.address, meetingData.notes || ""); const result = await Api.createBidMeeting(meetingData.address, meetingData.notes || "");
showNewMeetingModal.value = false; showNewMeetingModal.value = false;
@ -502,7 +502,7 @@ const handleNewMeetingCancel = () => {
showNewMeetingModal.value = false; showNewMeetingModal.value = false;
// Clear query params after canceling // Clear query params after canceling
router.push({ router.push({
path: "/schedule-onsite", path: "/schedule-bid",
query: { query: {
date: formatDateForUrl(currentWeekStart.value), date: formatDateForUrl(currentWeekStart.value),
}, },
@ -665,7 +665,7 @@ const handleDrop = async (event, date, time) => {
status: "Scheduled", status: "Scheduled",
}; };
await Api.updateOnSiteMeeting(droppedMeeting.id, updateData); await Api.updateBidMeeting(droppedMeeting.id, updateData);
// If this was a reschedule, remove the old meeting from its original position // If this was a reschedule, remove the old meeting from its original position
if (droppedMeeting.isRescheduling && originalMeeting) { if (droppedMeeting.isRescheduling && originalMeeting) {
@ -755,7 +755,7 @@ const handleDropToUnscheduled = async (event) => {
try { try {
loadingStore.setLoading(true); loadingStore.setLoading(true);
await Api.updateOnSiteMeeting(droppedMeeting.id, { await Api.updateBidMeeting(droppedMeeting.id, {
status: "Unscheduled", status: "Unscheduled",
start_time: null, start_time: null,
end_time: null, end_time: null,
@ -801,7 +801,7 @@ const handleDropToUnscheduled = async (event) => {
const loadUnscheduledMeetings = async () => { const loadUnscheduledMeetings = async () => {
loadingStore.setLoading(true); loadingStore.setLoading(true);
try { try {
const result = await Api.getUnscheduledOnSiteMeetings(); const result = await Api.getUnscheduledBidMeetings();
// Ensure we always have an array // Ensure we always have an array
unscheduledMeetings.value = Array.isArray(result) ? result : []; unscheduledMeetings.value = Array.isArray(result) ? result : [];
console.log("Loaded unscheduled meetings:", unscheduledMeetings.value); console.log("Loaded unscheduled meetings:", unscheduledMeetings.value);
@ -850,7 +850,7 @@ const loadWeekMeetings = async () => {
// Try to get meetings from API // Try to get meetings from API
try { try {
const apiResult = await Api.getWeekOnSiteMeetings(weekStartStr, weekEndStr); const apiResult = await Api.getWeekBidMeetings(weekStartStr, weekEndStr);
if (Array.isArray(apiResult)) { if (Array.isArray(apiResult)) {
// Transform the API data to match what the calendar expects // Transform the API data to match what the calendar expects
meetings.value = apiResult meetings.value = apiResult
@ -989,7 +989,7 @@ watch(
</script> </script>
<style scoped> <style scoped>
.schedule-onsite-container { .schedule-bid-container {
padding: 20px; padding: 20px;
height: 100vh; height: 100vh;
display: flex; display: flex;

View File

@ -13,7 +13,7 @@ import Home from "./components/pages/Home.vue";
import TestDateForm from "./components/pages/TestDateForm.vue"; import TestDateForm from "./components/pages/TestDateForm.vue";
import Client from "./components/pages/Client.vue"; import Client from "./components/pages/Client.vue";
import ErrorHandlingDemo from "./components/pages/ErrorHandlingDemo.vue"; import ErrorHandlingDemo from "./components/pages/ErrorHandlingDemo.vue";
import ScheduleOnSite from "./components/pages/ScheduleOnSite.vue"; import ScheduleBid from "./components/pages/ScheduleBid.vue";
import Estimate from "./components/pages/Estimate.vue"; import Estimate from "./components/pages/Estimate.vue";
const routes = [ const routes = [
@ -24,7 +24,7 @@ const routes = [
{ path: "/calendar", component: Calendar }, { path: "/calendar", component: Calendar },
{ path: "/clients", component: Clients }, { path: "/clients", component: Clients },
{ path: "/client", component: Client }, { path: "/client", component: Client },
{ path: "/schedule-onsite", component: ScheduleOnSite }, { path: "/schedule-bid", component: ScheduleBid },
{ path: "/jobs", component: Jobs }, { path: "/jobs", component: Jobs },
{ path: "/invoices", component: Invoices }, { path: "/invoices", component: Invoices },
{ path: "/estimates", component: Estimates }, { path: "/estimates", component: Estimates },