update creation
This commit is contained in:
parent
97241f14ea
commit
a96832c21b
4 changed files with 119 additions and 71 deletions
|
|
@ -189,7 +189,7 @@ def get_clients_table_data(filters={}, sortings=[], page=1, page_size=10):
|
||||||
customer_name = "N/A"
|
customer_name = "N/A"
|
||||||
elif not customer_name and customer_links:
|
elif not customer_name and customer_links:
|
||||||
print("DEBUG: No customer to bill. Customer links found:", customer_links)
|
print("DEBUG: No customer to bill. Customer links found:", customer_links)
|
||||||
customer_name = frappe.get_value("Lead", customer_links[0].link_name, "lead_name") if is_lead else customer_links[0].link_name
|
customer_name = frappe.get_value("Lead", customer_links[0].link_name, "custom_customer_name") if is_lead else customer_links[0].link_name
|
||||||
tableRow["id"] = address["name"]
|
tableRow["id"] = address["name"]
|
||||||
tableRow["customer_name"] = customer_name
|
tableRow["customer_name"] = customer_name
|
||||||
tableRow["address"] = (
|
tableRow["address"] = (
|
||||||
|
|
@ -213,10 +213,15 @@ def get_clients_table_data(filters={}, sortings=[], page=1, page_size=10):
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def upsert_client(data):
|
def upsert_client(data):
|
||||||
"""Create or update a client (customer and address)."""
|
"""Create a client (customer and address)."""
|
||||||
try:
|
try:
|
||||||
data = json.loads(data)
|
data = json.loads(data)
|
||||||
print("#####DEBUG: Upsert client data received:", data)
|
print("#####DEBUG: Create client data received:", data)
|
||||||
|
|
||||||
|
customer_name = data.get("customer_name")
|
||||||
|
contacts = data.get("contacts", [])
|
||||||
|
|
||||||
|
# Check for existing address
|
||||||
if address_exists(
|
if address_exists(
|
||||||
data.get("address_line1"),
|
data.get("address_line1"),
|
||||||
data.get("address_line2"),
|
data.get("address_line2"),
|
||||||
|
|
@ -227,37 +232,28 @@ def upsert_client(data):
|
||||||
return build_error_response("This address already exists. Please use a different address or search for the address to find the associated client.", 400)
|
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
|
# Handle customer creation/update
|
||||||
print("#####DEBUG: Checking for existing customer with name:", data.get("customer_name"))
|
client_doc = check_and_get_client_doc(customer_name)
|
||||||
customer = frappe.db.exists("Customer", {"customer_name": data.get("customer_name")})
|
if not client_doc:
|
||||||
if not customer:
|
print("#####DEBUG: Creating new lead.")
|
||||||
print("#####DEBUG: No existing customer found. Checking for existing lead")
|
customer_type = data.get("customer_type", "Individual")
|
||||||
customer = frappe.db.exists("Lead", {"lead_name": data.get("customer_name")})
|
primary_contact = find_primary_contact_or_throw(contacts)
|
||||||
if not customer:
|
lead_data = {
|
||||||
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"),
|
"first_name": primary_contact.get("first_name"),
|
||||||
"last_name": primary_contact.get("last_name"),
|
"last_name": primary_contact.get("last_name"),
|
||||||
"email_id": primary_contact.get("email"),
|
"email_id": primary_contact.get("email"),
|
||||||
"phone": primary_contact.get("phone_number"),
|
"phone": primary_contact.get("phone_number"),
|
||||||
"customer_type": data.get("customer_type"),
|
"company": data.get("company"),
|
||||||
"company": data.get("company")
|
"custom_customer_name": customer_name,
|
||||||
})
|
"customer_type": customer_type
|
||||||
else:
|
}
|
||||||
print("#####DEBUG: Existing lead found:", customer)
|
if customer_type == "Company":
|
||||||
client_doc = frappe.get_doc("Lead", customer)
|
lead_data["company_name"] = data.get("customer_name")
|
||||||
else:
|
client_doc = create_lead(lead_data)
|
||||||
print("#####DEBUG: Existing customer found:", customer)
|
|
||||||
client_doc = frappe.get_doc("Customer", customer)
|
|
||||||
print(f"#####DEBUG: {client_doc.doctype}:", client_doc.as_dict())
|
print(f"#####DEBUG: {client_doc.doctype}:", client_doc.as_dict())
|
||||||
|
|
||||||
# Handle address creation
|
# Handle address creation
|
||||||
address_doc = create_address({
|
address_doc = create_address({
|
||||||
"address_title": build_address_title(data.get("customer_name"), data),
|
"address_title": build_address_title(customer_name, data),
|
||||||
"address_line1": data.get("address_line1"),
|
"address_line1": data.get("address_line1"),
|
||||||
"address_line2": data.get("address_line2"),
|
"address_line2": data.get("address_line2"),
|
||||||
"city": data.get("city"),
|
"city": data.get("city"),
|
||||||
|
|
@ -268,7 +264,7 @@ def upsert_client(data):
|
||||||
|
|
||||||
#Handle contact creation
|
#Handle contact creation
|
||||||
contact_docs = []
|
contact_docs = []
|
||||||
for contact_data in data.get("contacts", []):
|
for contact_data in contacts:
|
||||||
if isinstance(contact_data, str):
|
if isinstance(contact_data, str):
|
||||||
contact_data = json.loads(contact_data)
|
contact_data = json.loads(contact_data)
|
||||||
print("#####DEBUG: Processing contact data:", contact_data)
|
print("#####DEBUG: Processing contact data:", contact_data)
|
||||||
|
|
@ -283,8 +279,6 @@ def upsert_client(data):
|
||||||
contact_doc = create_contact({
|
contact_doc = create_contact({
|
||||||
"first_name": contact_data.get("first_name"),
|
"first_name": contact_data.get("first_name"),
|
||||||
"last_name": contact_data.get("last_name"),
|
"last_name": contact_data.get("last_name"),
|
||||||
# "email_id": contact_data.get("email"),
|
|
||||||
# "phone": contact_data.get("phone_number"),
|
|
||||||
"role": contact_data.get("contact_role", "Other"),
|
"role": contact_data.get("contact_role", "Other"),
|
||||||
"custom_email": contact_data.get("email"),
|
"custom_email": contact_data.get("email"),
|
||||||
"is_primary_contact":1 if contact_data.get("is_primary", False) else 0,
|
"is_primary_contact":1 if contact_data.get("is_primary", False) else 0,
|
||||||
|
|
@ -362,7 +356,11 @@ def check_and_get_client_doc(client_name):
|
||||||
customer = frappe.get_doc("Customer", client_name)
|
customer = frappe.get_doc("Customer", client_name)
|
||||||
else:
|
else:
|
||||||
print("DEBUG: Client not found as Customer. Checking Lead.")
|
print("DEBUG: Client not found as Customer. Checking Lead.")
|
||||||
|
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"company_name": client_name})
|
||||||
|
if not lead_name:
|
||||||
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"lead_name": client_name})
|
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"lead_name": client_name})
|
||||||
|
if not lead_name:
|
||||||
|
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"custom_customer_name": client_name})
|
||||||
if lead_name:
|
if lead_name:
|
||||||
print("DEBUG: Client found as Lead.")
|
print("DEBUG: Client found as Lead.")
|
||||||
customer = frappe.get_doc("Lead", lead_name[0])
|
customer = frappe.get_doc("Lead", lead_name[0])
|
||||||
|
|
@ -388,3 +386,10 @@ def get_customer_or_lead(client_name):
|
||||||
else:
|
else:
|
||||||
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"lead_name": client_name})[0]
|
lead_name = frappe.db.get_all("Lead", pluck="name", filters={"lead_name": client_name})[0]
|
||||||
return frappe.get_doc("Lead", lead_name)
|
return frappe.get_doc("Lead", lead_name)
|
||||||
|
|
||||||
|
def find_primary_contact_or_throw(contacts):
|
||||||
|
for contact in contacts:
|
||||||
|
if contact.get("is_primary"):
|
||||||
|
print("#####DEBUG: Primary contact found:", contact)
|
||||||
|
return contact
|
||||||
|
raise ValueError("No primary contact found in contacts list.")
|
||||||
|
|
@ -169,7 +169,7 @@ def build_address_title(customer_name, address_data):
|
||||||
|
|
||||||
def map_lead_client(client_data):
|
def map_lead_client(client_data):
|
||||||
mappings = {
|
mappings = {
|
||||||
"lead_name": "customer_name",
|
"custom_customer_name": "customer_name",
|
||||||
"customer_type": "customer_type",
|
"customer_type": "customer_type",
|
||||||
"territory": "territory",
|
"territory": "territory",
|
||||||
"company_name": "company"
|
"company_name": "company"
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,16 @@
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-field full-width checkbox-row">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="isBilling"
|
||||||
|
v-model="localFormData.isBillingAddress"
|
||||||
|
:disabled="isSubmitting"
|
||||||
|
style="margin-top: 0"
|
||||||
|
/>
|
||||||
|
<label for="isBilling">Is Billing Address</label>
|
||||||
|
</div>
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label for="zipcode"> Zip Code <span class="required">*</span> </label>
|
<label for="zipcode"> Zip Code <span class="required">*</span> </label>
|
||||||
<InputText
|
<InputText
|
||||||
|
|
@ -59,7 +69,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed, onMounted } from "vue";
|
||||||
import InputText from "primevue/inputtext";
|
import InputText from "primevue/inputtext";
|
||||||
import Api from "../../api";
|
import Api from "../../api";
|
||||||
import { useNotificationStore } from "../../stores/notifications-primevue";
|
import { useNotificationStore } from "../../stores/notifications-primevue";
|
||||||
|
|
@ -88,6 +98,12 @@ const localFormData = computed({
|
||||||
set: (value) => emit("update:formData", value),
|
set: (value) => emit("update:formData", value),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (localFormData.value.isBillingAddress === undefined) {
|
||||||
|
localFormData.value.isBillingAddress = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const zipcodeLookupDisabled = ref(true);
|
const zipcodeLookupDisabled = ref(true);
|
||||||
|
|
||||||
const handleZipcodeInput = async (event) => {
|
const handleZipcodeInput = async (event) => {
|
||||||
|
|
@ -181,6 +197,17 @@ const handleZipcodeInput = async (event) => {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-field.checkbox-row {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field.checkbox-row label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.form-grid {
|
.form-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|
|
||||||
|
|
@ -3,40 +3,8 @@
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h3>Client Information</h3>
|
<h3>Client Information</h3>
|
||||||
<label class="toggle-container" v-if="!isEditMode">
|
|
||||||
<v-switch v-model="isNewClient" color="success" />
|
|
||||||
<span class="toggle-label">New Client</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-field">
|
|
||||||
<label for="customer-name"> Customer Name <span class="required">*</span> </label>
|
|
||||||
<div class="input-with-button">
|
|
||||||
<InputText
|
|
||||||
id="customer-name"
|
|
||||||
v-model="localFormData.customerName"
|
|
||||||
:disabled="isSubmitting || isEditMode"
|
|
||||||
placeholder="Enter customer name"
|
|
||||||
class="w-full"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
label="Check Client"
|
|
||||||
size="small"
|
|
||||||
icon="pi pi-user-check"
|
|
||||||
class="check-btn"
|
|
||||||
@click="checkCustomerExists"
|
|
||||||
:disabled="isSubmitting || !localFormData.customerName.trim()"
|
|
||||||
>Check</Button>
|
|
||||||
<Button
|
|
||||||
v-if="!isNewClient && !isEditMode"
|
|
||||||
@click="searchCustomers"
|
|
||||||
:disabled="isSubmitting || !localFormData.customerName.trim()"
|
|
||||||
size="small"
|
|
||||||
icon="pi pi-search"
|
|
||||||
class="search-btn"
|
|
||||||
></Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label for="customer-type"> Customer Type <span class="required">*</span> </label>
|
<label for="customer-type"> Customer Type <span class="required">*</span> </label>
|
||||||
<Select
|
<Select
|
||||||
|
|
@ -48,6 +16,34 @@
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-field">
|
||||||
|
<label for="customer-name"> Customer Name <span class="required">*</span> </label>
|
||||||
|
<div class="input-with-button">
|
||||||
|
<InputText
|
||||||
|
id="customer-name"
|
||||||
|
v-model="localFormData.customerName"
|
||||||
|
:disabled="isSubmitting || isEditMode || localFormData.customerType !== 'Company'"
|
||||||
|
placeholder="Enter customer name"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="Check Client"
|
||||||
|
size="small"
|
||||||
|
icon="pi pi-user-check"
|
||||||
|
class="check-btn"
|
||||||
|
@click="checkCustomerExists"
|
||||||
|
:disabled="isSubmitting"
|
||||||
|
>Check</Button>
|
||||||
|
<Button
|
||||||
|
v-if="!isNewClient && !isEditMode"
|
||||||
|
@click="searchCustomers"
|
||||||
|
:disabled="isSubmitting || !localFormData.customerName.trim()"
|
||||||
|
size="small"
|
||||||
|
icon="pi pi-search"
|
||||||
|
class="search-btn"
|
||||||
|
></Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -147,6 +143,23 @@ watch(isNewClient, (newValue) => {
|
||||||
emit("newClientToggle", newValue);
|
emit("newClientToggle", newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Watch for changes that affect customer name
|
||||||
|
watch(
|
||||||
|
() => localFormData.value,
|
||||||
|
(newData) => {
|
||||||
|
if (newData.customerType === "Individual" && newData.contacts && newData.contacts.length > 0) {
|
||||||
|
const primary = newData.contacts.find((c) => c.isPrimary) || newData.contacts[0];
|
||||||
|
const firstName = primary.firstName || "";
|
||||||
|
const lastName = primary.lastName || "";
|
||||||
|
const fullName = `${firstName} ${lastName}`.trim();
|
||||||
|
if (fullName !== newData.customerName) {
|
||||||
|
newData.customerName = fullName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
const searchCustomers = async () => {
|
const searchCustomers = async () => {
|
||||||
const searchTerm = localFormData.value.customerName.trim();
|
const searchTerm = localFormData.value.customerName.trim();
|
||||||
if (!searchTerm) return;
|
if (!searchTerm) return;
|
||||||
|
|
@ -172,8 +185,11 @@ const searchCustomers = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkCustomerExists = async () => {
|
const checkCustomerExists = async () => {
|
||||||
const searchTerm = localFormData.value.customerName.trim();
|
const searchTerm = (localFormData.value.customerName || "").trim();
|
||||||
if (!searchTerm) return;
|
if (!searchTerm) {
|
||||||
|
notificationStore.addWarning("Please ensure a customer name is entered before checking.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = await Api.getClient(searchTerm);
|
const client = await Api.getClient(searchTerm);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue