add sales order generation functionality

This commit is contained in:
Casey 2025-12-19 16:58:38 -06:00
parent 796b835c08
commit 9c9050c558
13 changed files with 289 additions and 143 deletions

View File

@ -74,4 +74,52 @@ def get_addresses(fields=["*"], filters={}):
return build_success_response(addresses)
except Exception as e:
frappe.log_error(message=str(e), title="Get Addresses Failed")
return build_error_response(str(e), 500)
return build_error_response(str(e), 500)
def create_address(address_data):
"""Create a new address."""
address = frappe.get_doc({
"doctype": "Address",
**address_data
})
address.insert(ignore_permissions=True)
return address
def address_exists(address_line1, address_line2, city, state, pincode):
"""Check if an address with the given details already exists."""
filters = {
"address_line1": address_line1,
"address_line2": address_line2,
"city": city,
"state": state,
"pincode": pincode
}
return frappe.db.exists("Address", filters) is not None
def calculate_address_title(customer_name, address_data):
return f"{customer_name} - {address_data.get('address_line1', '')}, {address_data.get('city', '')} - {address_data.get('type', '')}"
def create_address_links(address_doc, client_doc, contact_docs):
print("#####DEBUG: Linking customer to address.")
print("#####DEBUG: Client Doc:", client_doc.as_dict(), "Address Doc:", address_doc.as_dict(), "Contact Docs:", [c.as_dict() for c in contact_docs])
address_doc.append("links", {
"link_doctype": client_doc.doctype,
"link_name": client_doc.name
})
setattr(address_doc, "custom_customer_to_bill" if client_doc.doctype == "Customer" else "lead_name", client_doc.name)
# Address -> Contact
print("#####DEBUG: Linking contacts to address.")
address_doc.custom_contact = next((c.name for c in contact_docs if c.is_primary_contact), contact_docs[0].name)
for contact_doc in contact_docs:
address_doc.append("custom_linked_contacts", {
"contact": contact_doc.name,
"email": contact_doc.email_id,
"phone": contact_doc.phone,
"role": contact_doc.role
})
address_doc.append("links", {
"link_doctype": "Contact",
"link_name": contact_doc.name
})
address_doc.save(ignore_permissions=True)

View File

@ -1,5 +1,8 @@
import frappe, json
from custom_ui.db_utils import build_error_response, process_query_conditions, build_datatable_dict, get_count_or_filters, build_success_response, map_lead_client
from custom_ui.db_utils import build_error_response, process_query_conditions, build_datatable_dict, get_count_or_filters, build_success_response, map_lead_client, build_address_title
from erpnext.crm.doctype.lead.lead import make_customer
from custom_ui.api.db.addresses import address_exists, create_address, create_address_links
from custom_ui.api.db.contacts import check_and_get_contact, create_contact, create_contact_links
# ===============================================================================
# CLIENT MANAGEMENT API METHODS
@ -94,15 +97,9 @@ def get_client(client_name):
print("DEBUG: get_client called with client_name:", client_name)
try:
clientData = {"addresses": [], "contacts": [], "jobs": [], "sales_invoices": [], "payment_entries": [], "sales_orders": [], "tasks": []}
client_exists = frappe.db.exists("Customer", client_name)
if client_exists:
customer = frappe.get_doc("Customer", client_name)
else:
print("DEBUG: Client not found as Customer. Checking Lead.")
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"lead_name": client_name})[0]
customer = frappe.get_doc("Lead", lead_name)
if not customer:
return build_error_response(f"Client '{client_name}' not found as Customer or Lead.", 404)
customer = check_and_get_client_doc(client_name)
if not customer:
return build_error_response(f"Client with name '{client_name}' does not exist.", 404)
print("DEBUG: Retrieved customer/lead document:", customer.as_dict())
clientData = {**clientData, **customer.as_dict()}
if customer.doctype == "Lead":
@ -117,7 +114,7 @@ def get_client(client_name):
"Dynamic Link",
filters={
"link_doctype": "Lead",
"link_name": lead_name,
"link_name": customer.name,
"parenttype": ["in", ["Address", "Contact"]],
},
fields=[
@ -218,67 +215,55 @@ def upsert_client(data):
"""Create or update a client (customer and address)."""
try:
data = json.loads(data)
print("#####DEBUG: Upsert client data received:", data)
if address_exists(
data.get("address_line1"),
data.get("address_line2"),
data.get("city"),
data.get("state"),
data.get("pincode")
):
return build_error_response("This address already exists. Please use a different address or search for the address to find the associated client.", 400)
# Handle customer creation/update
print("#####DEBUG: Upsert client data received:", data)
print("#####DEBUG: Checking for existing customer with name:", data.get("customer_name"))
customer = frappe.db.exists("Customer", {"customer_name": data.get("customer_name")})
if not customer:
print("#####DEBUG: No existing customer found. Checking for existing lead")
customer = frappe.db.exists("Lead", {"lead_name": data.get("customer_name")})
if not customer:
print("#####DEBUG: No existing lead found. Creating new lead.")
primary_contact = next((c for c in data.get("contacts", []) if c.get("is_primary")), None)
if not primary_contact:
return build_error_response("Primary contact information is required to create a new customer.", 400)
print("#####DEBUG: Primary contact found:", primary_contact)
client_doc = create_lead({
"lead_name": data.get("customer_name"),
"first_name": primary_contact.get("first_name"),
"last_name": primary_contact.get("last_name"),
"email_id": primary_contact.get("email"),
"phone": primary_contact.get("phone_number"),
"customer_type": data.get("customer_type"),
"company": data.get("company")
})
else:
print("#####DEBUG: Existing lead found:", customer)
client_doc = frappe.get_doc("Lead", customer)
else:
print("#####DEBUG: Existing customer found:", customer)
if not customer:
print("#####DEBUG: No existing lead found. Creating new lead.")
is_individual = data.get("customer_type") == "Individual"
primary_contact = next((c for c in data.get("contacts", []) if c.get("is_primary")), None)
if not primary_contact:
return build_error_response("Primary contact information is required to create a new customer.", 400)
print("#####DEBUG: Primary contact found:", primary_contact)
new_lead_data = {
"doctype": "Lead",
"lead_name": data.get("customer_name"),
"first_name": primary_contact.get("first_name"),
"last_name": primary_contact.get("last_name"),
"email_id": primary_contact.get("email"),
"phone": primary_contact.get("phone_number"),
"customer_type": data.get("customer_type"),
"company": data.get("company")
}
print("#####DEBUG: New lead data prepared:", new_lead_data)
new_client_doc = frappe.get_doc(new_lead_data).insert(ignore_permissions=True)
else:
new_client_doc = frappe.get_doc("Customer", data.get("customer_name"))
print(f"#####DEBUG: {new_client_doc.doctype}:", new_client_doc.as_dict())
client_doc = frappe.get_doc("Customer", customer)
print(f"#####DEBUG: {client_doc.doctype}:", client_doc.as_dict())
# Handle address creation
print("#####DEBUG: Checking for existing address for customer/lead:", data.get("customer_name"))
existing_address = frappe.db.exists(
"Address",
{
"address_line1": data.get("address_line1"),
"city": data.get("city"),
"state": data.get("state"),
})
print("Existing address check:", existing_address)
if existing_address:
return build_error_response("Address already exists for this customer.", 400)
address_doc = frappe.get_doc({
"doctype": "Address",
"address_title": data.get("address_title"),
address_doc = create_address({
"address_title": build_address_title(data.get("customer_name"), data),
"address_line1": data.get("address_line1"),
"address_line2": data.get("address_line2"),
"city": data.get("city"),
"state": data.get("state"),
"country": "United States",
"pincode": data.get("pincode")
}).insert(ignore_permissions=True)
print("Address:", address_doc.as_dict())
})
#Handle contact creation
contact_docs = []
@ -286,19 +271,22 @@ def upsert_client(data):
if isinstance(contact_data, str):
contact_data = json.loads(contact_data)
print("#####DEBUG: Processing contact data:", contact_data)
contact_exists = frappe.db.exists("Contact", {"email_id": contact_data.get("email"), "phone": contact_data.get("phone_number")})
print("Contact exists check:", contact_exists)
if not contact_exists:
contact_doc = frappe.get_doc({
"doctype": "Contact",
contact_doc = check_and_get_contact(
contact_data.get("first_name"),
contact_data.get("last_name"),
contact_data.get("email"),
contact_data.get("phone_number")
)
if not contact_doc:
print("#####DEBUG: No existing contact found. Creating new contact.")
contact_doc = create_contact({
"first_name": contact_data.get("first_name"),
"last_name": contact_data.get("last_name"),
# "email_id": contact_data.get("email"),
# "phone": contact_data.get("phone_number"),
"custom_customer": customer_doc.name,
"role": contact_data.get("contact_role", "Other"),
"custom_email": contact_data.get("email"),
"is_primary_contact":1 if data.get("is_primary", False) else 0,
"is_primary_contact":1 if contact_data.get("is_primary", False) else 0,
"email_ids": [{
"email_id": contact_data.get("email"),
"is_primary": 1
@ -308,85 +296,37 @@ def upsert_client(data):
"is_primary_mobile_no": 1,
"is_primary_phone": 1
}]
}).insert(ignore_permissions=True)
print("Created new contact:", contact_doc.as_dict())
else:
contact_doc = frappe.get_doc("Contact", {"email_id": contact_data.get("email"), "phone": contact_data.get("phone_number")})
print("Contact already exists:", contact_doc.as_dict())
})
contact_docs.append(contact_doc)
##### Create links
# Customer -> Address
if new_client_doc.doctype == "Customer":
print("#####DEBUG: Creating links between customer, address, and contacts.")
new_client_doc.append("custom_select_address", {
if client_doc.doctype == "Customer":
print("#####DEBUG: Linking address to customer.")
client_doc.append("custom_select_address", {
"address_name": address_doc.name,
"address_line_1": address_doc.address_line1,
"city": address_doc.city,
"state": address_doc.state,
"pincode": address_doc.pincode
})
# Customer -> Contact
print("#####DEBUG: Linking contacts to customer.")
for contact_doc in contact_docs:
print("Linking contact:", contact_doc.as_dict())
print("with role:", contact_doc.role)
print("customer to append to:", new_client_doc.as_dict())
new_client_doc.append("custom_add_contacts", {
client_doc.append("custom_add_contacts", {
"contact": contact_doc.name,
"email": contact_doc.custom_email,
"phone": contact_doc.phone,
"role": contact_doc.role
})
new_client_doc.append("links", {
"link_doctype": "Contact",
"link_name": contact_doc.name
}
)
new_client_doc.save(ignore_permissions=True)
client_doc.save(ignore_permissions=True)
# Address -> Customer/Lead
print("#####DEBUG: Linking address to customer.")
address_doc.append("links", {
"link_doctype": new_client_doc.doctype,
"link_name": new_client_doc.name
})
if new_client_doc.doctype == "Lead":
address_doc.lead_name = new_client_doc.lead_name
# Address -> Contact
print("#####DEBUG: Linking address to contacts.")
address_doc.custom_contact = next((c.name for c in contact_docs if c.is_primary_contact), contact_docs[0].name)
for contact_doc in contact_docs:
address_doc.append("custom_linked_contacts", {
"contact": contact_doc.name,
"email": contact_doc.email_id,
"phone": contact_doc.phone,
"role": contact_doc.role
})
address_doc.save(ignore_permissions=True)
create_address_links(address_doc, client_doc, contact_docs)
# Contact -> Customer/Lead & Address
print("#####DEBUG: Linking contacts to customer.")
for contact_doc in contact_docs:
contact_doc.address = address_doc.name
contact_doc.append("links", {
"link_doctype": new_client_doc.doctype,
"link_name": new_client_doc.name
})
contact_doc.append("links", {
"link_doctype": "Address",
"link_name": address_doc.name
})
contact_doc.custom_customer = new_client_doc.name
contact_doc.save(ignore_permissions=True)
create_contact_links(contact_docs, client_doc, address_doc)
frappe.local.message_log = []
return build_success_response({
"customer": new_client_doc.as_dict(),
"customer": client_doc.as_dict(),
"address": address_doc.as_dict(),
"contacts": [contact_doc.as_dict() for contact_doc in contact_docs]
})
@ -402,7 +342,48 @@ def get_client_names(search_term):
search_pattern = f"%{search_term}%"
client_names = frappe.db.get_all(
"Customer",
filters={"customer_name": ["like", search_pattern]},
pluck="name")
return build_success_response(client_names)
except Exception as e:
return build_error_response(str(e), 500)
def check_if_customer(client_name):
"""Check if the given client name corresponds to a Customer."""
return frappe.db.exists("Customer", client_name) is not None
def check_and_get_client_doc(client_name):
"""Check if a client exists as Customer or Lead and return the document."""
print("DEBUG: Checking for existing client with name:", client_name)
customer = None
if check_if_customer(client_name):
print("DEBUG: Client found as Customer.")
customer = frappe.get_doc("Customer", client_name)
else:
print("DEBUG: Client not found as Customer. Checking Lead.")
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"lead_name": client_name})
if lead_name:
print("DEBUG: Client found as Lead.")
customer = frappe.get_doc("Lead", lead_name[0])
return customer
def convert_lead_to_customer(lead_name):
lead = frappe.get_doc("Lead", lead_name)
customer = make_customer(lead)
customer.insert(ignore_permissions=True)
def create_lead(lead_data):
lead = frappe.get_doc({
"doctype": "Lead",
**lead_data
})
lead.insert(ignore_permissions=True)
return lead
def get_customer_or_lead(client_name):
if check_if_customer(client_name):
return frappe.get_doc("Customer", client_name)
else:
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"lead_name": client_name})[0]
return frappe.get_doc("Lead", lead_name)

View File

@ -0,0 +1,50 @@
import frappe
def existing_contact_name(first_name: str, last_name: str, email: str, phone: str) -> str:
"""Check if a contact exists based on provided details."""
filters = {
"first_name": first_name,
"last_name": last_name,
"email_id": email,
"phone": phone
}
existing_contacts = frappe.db.get_all("Contact", pluck="name", filters=filters)
return existing_contacts[0] if existing_contacts else None
def get_contact(contact_name: str):
"""Retrieve a contact document by name."""
contact = frappe.get_doc("Contact", contact_name)
print("Retrieved existing contact:", contact.as_dict())
return contact
def check_and_get_contact(first_name: str, last_name: str, email: str, phone: str):
"""Check if a contact exists and return the contact document if found."""
contact_name = existing_contact_name(first_name, last_name, email, phone)
if contact_name:
return get_contact(contact_name)
return None
def create_contact(contact_data: dict):
"""Create a new contact."""
contact = frappe.get_doc({
"doctype": "Contact",
**contact_data
})
contact.insert(ignore_permissions=True)
print("Created new contact:", contact.as_dict())
return contact
def create_contact_links(contact_docs, client_doc, address_doc):
print("#####DEBUG: Linking contacts to client and address.")
for contact_doc in contact_docs:
contact_doc.address = address_doc.name
contact_doc.append("links", {
"link_doctype": client_doc.doctype,
"link_name": client_doc.name
})
contact_doc.append("links", {
"link_doctype": "Address",
"link_name": address_doc.name
})
contact_doc.custom_customer = client_doc.name
contact_doc.save(ignore_permissions=True)

View File

@ -2,6 +2,7 @@ import frappe, json
from frappe.utils.pdf import get_pdf
from custom_ui.db_utils import process_query_conditions, build_datatable_dict, get_count_or_filters, build_success_response, build_error_response
from werkzeug.wrappers import Response
from custom_ui.api.db.clients import check_if_customer, convert_lead_to_customer
# ===============================================================================
# ESTIMATES & INVOICES API METHODS
@ -152,6 +153,8 @@ def send_estimate_email(estimate_name):
quotation.custom_current_status = "Submitted"
quotation.custom_sent = 1
quotation.save()
quotation.submit()
frappe.db.commit()
updated_quotation = frappe.get_doc("Quotation", estimate_name)
return build_success_response(updated_quotation.as_dict())
except Exception as e:
@ -166,20 +169,26 @@ def update_response(name, response):
if not frappe.db.exists("Quotation", name):
raise Exception("Estimate not found.")
estimate = frappe.get_doc("Quotation", name)
if estimate.docstatus != 1:
raise Exception("Estimate must be submitted to update response.")
accepted = True if response == "Accepted" else False
new_status = "Estimate Accepted" if accepted else "Lost"
estimate.custom_response = response
estimate.custom_current_status = new_status
estimate.custom_followup_needed = 1 if response == "Requested call" else 0
estimate.status = "Ordered" if accepted else "Closed"
estimate.flags.ignore_permissions = True
print("DEBUG: Updating estimate with response:", response, "and status:", new_status)
# estimate.save()
estimate.submit()
frappe.db.commit()
estimate.save()
if accepted:
template = "custom_ui/templates/estimates/accepted.html"
if check_if_customer(estimate.party_name):
print("DEBUG: Party is already a customer:", estimate.party_name)
else:
print("DEBUG: Converting lead to customer for party:", estimate.party_name)
convert_lead_to_customer(estimate.party_name)
elif response == "Requested call":
template = "custom_ui/templates/estimates/request-call.html"
else:
@ -211,6 +220,7 @@ def upsert_estimate(data):
# Update fields
estimate.custom_installation_address = data.get("address_name")
estimate.party_name = data.get("contact_name")
estimate.custom_requires_half_payment = data.get("requires_half_payment", 0)
# Clear existing items and add new ones
estimate.items = []

View File

@ -102,3 +102,4 @@ def upsert_invoice(data):
except Exception as e:
return build_error_response(str(e), 500)

View File

@ -159,6 +159,14 @@ def build_full_address(doc):
return f"{first}, {second}"
return first or second or ""
def build_address_title(customer_name, address_data):
title_parts = [customer_name]
if address_data.get("address_line1"):
title_parts.append(address_data["address_line1"])
if address_data.get("type"):
title_parts.append(address_data["type"])
return " - ".join(title_parts)
def map_lead_client(client_data):
mappings = {
"lead_name": "customer_name",
@ -170,7 +178,8 @@ def map_lead_client(client_data):
if lead_field in client_data:
print(f"DEBUG: Mapping field {lead_field} to {client_field} with value {client_data[lead_field]}")
client_data[client_field] = client_data[lead_field]
client_data["customer_group"] = "" # Leads don't have customer groups
client_data["customer_group"] = ""
print("####DEBUG: Mapped client data:", client_data)
return client_data
def map_lead_update(client_data):

View File

@ -22,9 +22,10 @@ def after_save(doc, method):
address_doc.custom_estimate_sent_status = "Completed"
address_doc.save()
def after_submit(doc, method):
print("DEBUG: on_submit hook triggered for Quotation:", doc.name)
def on_update_after_submit(doc, method):
print("DEBUG: on_update_after_submit hook triggered for Quotation:", doc.name)
if doc.custom_current_status == "Estimate Accepted":
doc.custom_current_status = "Won"
print("DEBUG: Creating Sales Order from accepted Estimate")
address_doc = frappe.get_doc("Address", doc.custom_installation_address)
address_doc.custom_estimate_sent_status = "Completed"
@ -33,7 +34,8 @@ def after_submit(doc, method):
new_sales_order = make_sales_order(doc.name)
new_sales_order.custom_requires_half_payment = doc.requires_half_payment
new_sales_order.insert()
new_sales_order.submit()
print("DEBUG: Sales Order created successfully:", new_sales_order.name)
except Exception as e:
print("ERROR creating Sales Order from Estimate:", str(e))
frappe.log_error(f"Error creating Sales Order from Estimate {doc.name}: {str(e)}", "Estimate on_submit Error")
frappe.log_error(f"Error creating Sales Order from Estimate {doc.name}: {str(e)}", "Estimate on_update_after_submit Error")

View File

@ -3,4 +3,42 @@ import frappe
def after_insert(doc, method):
print(doc.as_dict())
# Create Invoice and Project from Sales Order
def create_sales_invoice_from_sales_order(doc, method):
try:
print("DEBUG: after_submit hook triggered for Sales Order:", doc.name)
invoice_ammount = doc.grand_total / 2 if doc.requires_half_payment else doc.grand_total
items = []
for so_item in doc.items:
# proportionally reduce rate if half-payment
rate = so_item.rate / 2 if doc.requires_half_payment else so_item.rate
qty = so_item.qty # usually full qty, but depends on half-payment rules
items.append({
"item_code": so_item.item_code,
"qty": qty,
"rate": rate,
"income_account": so_item.income_account,
"cost_center": so_item.cost_center,
"so_detail": so_item.name # links item to Sales Order
})
invoice = frappe.get_doc({
"doctype": "Sales Invoice",
"customer": doc.customer,
"company": doc.company,
"posting_date": frappe.utils.nowdate(),
"due_date": frappe.utils.nowdate(), # or calculate from payment terms
"currency": doc.currency,
"update_stock": 0,
"items": items,
"sales_order": doc.name, # link invoice to Sales Order
"ignore_pricing_rule": 1,
"payment_schedule": doc.payment_schedule if not half_payment else [] # optional
})
invoice.insert()
invoice.submit()
frappe.db.commit()
return invoice
except Exception as e:
print("ERROR creating Sales Invoice from Sales Order:", str(e))
frappe.log_error(f"Error creating Sales Invoice from Sales Order {doc.name}: {str(e)}", "Sales Order after_submit Error")

View File

@ -169,7 +169,8 @@ doc_events = {
"Quotation": {
"after_insert": "custom_ui.events.estimate.after_insert",
"on_update": "custom_ui.events.estimate.after_save",
"after_submit": "custom_ui.events.estimate.after_submit"
"after_submit": "custom_ui.events.estimate.after_submit",
"on_update_after_submit": "custom_ui.events.estimate.on_update_after_submit"
},
"Sales Order": {
"after_insert": "custom_ui.events.sales_order.after_insert"

View File

@ -2,16 +2,6 @@
<div class="form-section">
<h3>Address Information</h3>
<div class="form-grid">
<div class="form-field full-width">
<label for="address-title"> Address Title <span class="required">*</span> </label>
<InputText
id="address-title"
v-model="localFormData.addressTitle"
:disabled="isSubmitting || isEditMode"
placeholder="e.g., Home, Office, Site A"
class="w-full"
/>
</div>
<div class="form-field full-width">
<label for="address-line1"> Address Line 1 <span class="required">*</span> </label>
<InputText

View File

@ -381,11 +381,12 @@ defineExpose({
.check-btn {
border: 1px solid var(--primary-color);
color: var(--primary-color);
background: var(--surface-card);
padding: 0.25rem 0.75rem;
min-width: 8rem;
color: white;
background: var(--primary-color);
padding: 0.25rem 0.5rem;
min-width: 5rem;
justify-content: center;
font-size: 0.8rem;
}
.check-btn:disabled {

View File

@ -212,6 +212,7 @@ import DataUtils from "../../utils";
import Api from "../../api";
import { useRouter } from "vue-router";
import { useNotificationStore } from "../../stores/notifications-primevue";
import { useCompanyStore } from "../../stores/company";
const props = defineProps({
clientData: {
@ -230,6 +231,7 @@ const props = defineProps({
const router = useRouter();
const notificationStore = useNotificationStore();
const companyStore = useCompanyStore();
const navigateTo = (path) => {
router.push(path);
@ -561,6 +563,7 @@ const handleSave = async () => {
const clientData = {
customerName: formData.value.customerName,
customerType: formData.value.customerType,
companyName: companyStore.currentCompany,
addressTitle: formData.value.addressTitle,
addressLine1: formData.value.addressLine1,
addressLine2: formData.value.addressLine2,

View File

@ -87,6 +87,13 @@
<div class="total-section">
<strong>Total Cost: ${{ totalCost.toFixed(2) }}</strong>
</div>
<div class="half-payment-section">
<v-checkbox
v-model="formData.requiresHalfPayment"
label="Requires Half Payment"
:disabled="!isEditable"
/>
</div>
<div v-if="isEditable" class="action-buttons">
<Button label="Clear Items" @click="clearItems" severity="secondary" />
<Button
@ -199,6 +206,7 @@
</li>
</ul>
<p><strong>Total:</strong> ${{ totalCost.toFixed(2) }}</p>
<p><strong>Requires Half Payment:</strong> {{ formData.requiresHalfPayment ? 'Yes' : 'No' }}</p>
<p class="warning-text"><strong> Warning:</strong> After sending this estimate, it will be locked and cannot be edited.</p>
<div class="confirmation-buttons">
<Button
@ -247,6 +255,7 @@ const formData = reactive({
addressName: "",
contact: "",
estimateName: null,
requiresHalfPayment: false,
});
const selectedAddress = ref(null);
@ -367,6 +376,7 @@ const saveDraft = async () => {
contactName: selectedContact.value.name,
items: selectedItems.value.map((i) => ({ itemCode: i.itemCode, qty: i.qty })),
estimateName: formData.estimateName,
requiresHalfPayment: formData.requiresHalfPayment,
company: company.currentCompany
};
estimate.value = await Api.createEstimate(data);
@ -517,6 +527,7 @@ watch(
};
});
}
formData.requiresHalfPayment = estimate.value.custom_requires_half_payment || false;
}
} catch (error) {
console.error("Error loading estimate:", error);
@ -570,6 +581,7 @@ onMounted(async () => {
};
});
}
formData.requiresHalfPayment = estimate.value.custom_requires_half_payment || false;
}
} catch (error) {
console.error("Error loading estimate:", error);