Merge pull request #50749 from khushi8112/replace-use-of-publish-realtime-before-print

refactor: company details popup
This commit is contained in:
Khushi Rawat
2025-11-30 22:12:07 +05:30
committed by GitHub
3 changed files with 269 additions and 255 deletions

View File

@@ -282,59 +282,6 @@ class SalesInvoice(SellingController):
self.indicator_color = "green"
self.indicator_title = _("Paid")
def before_print(self, settings=None):
from frappe.contacts.doctype.address.address import get_address_display_list
super().before_print(settings)
company_details = frappe.get_value(
"Company", self.company, ["company_logo", "website", "phone_no", "email"], as_dict=True
)
required_fields = [
company_details.get("company_logo"),
company_details.get("phone_no"),
company_details.get("email"),
]
if not all(required_fields) and not frappe.has_permission("Company", "write", throw=False):
frappe.msgprint(
_(
"Some required Company details are missing. You don't have permission to update them. Please contact your System Manager."
)
)
return
if not self.company_address and not frappe.has_permission("Sales Invoice", "write", throw=False):
frappe.msgprint(
_(
"Company Address is missing. You don't have permission to update it. Please contact your System Manager."
)
)
return
address_display_list = get_address_display_list("Company", self.company)
address_line = address_display_list[0].get("address_line1") if address_display_list else ""
required_fields.append(self.company_address)
required_fields.append(address_line)
if not all(required_fields):
frappe.publish_realtime(
"sales_invoice_before_print",
{
"company_logo": company_details.get("company_logo"),
"website": company_details.get("website"),
"phone_no": company_details.get("phone_no"),
"email": company_details.get("email"),
"address_line": address_line,
"company": self.company,
"company_address": self.company_address,
"name": self.name,
},
user=frappe.session.user,
)
def validate(self):
self.validate_auto_set_posting_time()
super().validate()
@@ -2948,59 +2895,6 @@ def get_loyalty_programs(customer):
return lp_details
@frappe.whitelist()
def save_company_master_details(name, company, details):
from frappe.utils import validate_email_address
if isinstance(details, str):
details = frappe.parse_json(details)
if details.get("email"):
validate_email_address(details.get("email"), throw=True)
company_fields = ["company_logo", "website", "phone_no", "email"]
company_fields_to_update = {field: details.get(field) for field in company_fields if details.get(field)}
if company_fields_to_update:
frappe.db.set_value("Company", company, company_fields_to_update)
company_address = details.get("company_address")
if details.get("address_line1"):
address_doc = frappe.get_doc(
{
"doctype": "Address",
"address_title": details.get("address_title"),
"address_type": details.get("address_type"),
"address_line1": details.get("address_line1"),
"address_line2": details.get("address_line2"),
"city": details.get("city"),
"state": details.get("state"),
"pincode": details.get("pincode"),
"country": details.get("country"),
"is_your_company_address": 1,
"links": [{"link_doctype": "Company", "link_name": company}],
}
)
address_doc.insert()
company_address = address_doc.name
if company_address:
company_address_display = frappe.db.get_value("Sales Invoice", name, "company_address_display")
if not company_address_display or details.get("address_line1"):
from frappe.query_builder import DocType
SalesInvoice = DocType("Sales Invoice")
(
frappe.qb.update(SalesInvoice)
.set(SalesInvoice.company_address, company_address)
.set(SalesInvoice.company_address_display, get_address_display(company_address))
.where(SalesInvoice.name == name)
).run()
return True
@frappe.whitelist()
def create_invoice_discounting(source_name, target_doc=None):
invoice = frappe.get_doc("Sales Invoice", source_name)

View File

@@ -7,6 +7,7 @@ from collections import defaultdict
import frappe
from frappe import _, bold, qb, throw
from frappe.contacts.doctype.address.address import get_address_display
from frappe.model.workflow import get_workflow_name, is_transition_condition_satisfied
from frappe.query_builder import Criterion, DocType
from frappe.query_builder.custom import ConstantColumn
@@ -4167,3 +4168,130 @@ def update_gl_dict_with_regional_fields(doc, gl_dict):
def update_gl_dict_with_app_based_fields(doc, gl_dict):
for method in frappe.get_hooks("update_gl_dict_with_app_based_fields", default=[]):
frappe.get_attr(method)(doc, gl_dict)
@frappe.whitelist()
def get_missing_company_details(doctype, docname):
from frappe.contacts.doctype.address.address import get_address_display_list
company = frappe.db.get_value(doctype, docname, "company")
if doctype == "Purchase Order":
company_address = frappe.db.get_value(doctype, docname, "billing_address")
else:
company_address = frappe.db.get_value(doctype, docname, "company_address")
company_details = frappe.get_value(
"Company", company, ["company_logo", "website", "phone_no", "email"], as_dict=True
)
required_fields = [
company_details.get("company_logo"),
company_details.get("phone_no"),
company_details.get("email"),
]
if not all(required_fields) and not frappe.has_permission("Company", "write", throw=False):
frappe.msgprint(
_(
"Some required Company details are missing. You don't have permission to update them. Please contact your System Manager."
)
)
return
if not company_address and not frappe.has_permission(doctype, "write", throw=False):
frappe.msgprint(
_(
"Company Address is missing. You don't have permission to update it. Please contact your System Manager."
)
)
return
address_display_list = get_address_display_list("Company", company)
address_line = address_display_list[0].get("address_line1") if address_display_list else ""
required_fields.append(company_address)
required_fields.append(address_line)
if all(required_fields):
return False
return {
"company_logo": company_details.get("company_logo"),
"website": company_details.get("website"),
"phone_no": company_details.get("phone_no"),
"email": company_details.get("email"),
"address_line": address_line,
"company": company,
"company_address": company_address,
"name": docname,
}
@frappe.whitelist()
def update_company_master_and_address(current_doctype, name, company, details):
from frappe.utils import validate_email_address
if isinstance(details, str):
details = frappe.parse_json(details)
if details.get("email"):
validate_email_address(details.get("email"), throw=True)
company_fields = ["company_logo", "website", "phone_no", "email"]
company_fields_to_update = {field: details.get(field) for field in company_fields if details.get(field)}
if company_fields_to_update:
frappe.db.set_value("Company", company, company_fields_to_update)
company_address = details.get("company_address")
if details.get("address_line1"):
address_doc = frappe.get_doc(
{
"doctype": "Address",
"address_title": details.get("address_title"),
"address_type": details.get("address_type"),
"address_line1": details.get("address_line1"),
"address_line2": details.get("address_line2"),
"city": details.get("city"),
"state": details.get("state"),
"pincode": details.get("pincode"),
"country": details.get("country"),
"is_your_company_address": 1,
"links": [{"link_doctype": "Company", "link_name": company}],
}
)
address_doc.insert()
company_address = address_doc.name
update_doc_company_address(current_doctype, name, company_address, details)
def update_doc_company_address(current_doctype, docname, company_address, details):
if not company_address:
return
address_field_map = {
"Purchase Order": ("billing_address", "billing_address_display"),
"Sales Invoice": ("company_address", "company_address_display"),
"Delivery Note": ("company_address", "company_address_display"),
"POS Invoice": ("company_address", "company_address_display"),
}
address_field, display_field = address_field_map.get(
current_doctype, ("company_address", "company_address_display")
)
current_display = frappe.db.get_value(current_doctype, docname, display_field)
if current_display and not details.get("address_line1"):
return
from frappe.query_builder import DocType
DocType = DocType(current_doctype)
(
frappe.qb.update(DocType)
.set(getattr(DocType, address_field), company_address)
.set(getattr(DocType, display_field), get_address_display(company_address))
.where(DocType.name == docname)
).run()

View File

@@ -1,155 +1,147 @@
let beforePrintHandled = false;
const doctype_list = ["Sales Invoice", "Delivery Note", "Purchase Order", "POS Invoice"];
const allowed_print_formats = [
"Sales Invoice Standard",
"Sales Invoice with Item Image",
"Delivery Note Standard",
"Delivery Note with Item Image",
"Purchase Order Standard",
"Purchase Order with Item Image",
"POS Invoice Standard",
"POS Invoice with Item Image",
];
const allowed_letterheads = ["Company Letterhead", "Company Letterhead - Grey"];
frappe.realtime.on("sales_invoice_before_print", (data) => {
let print_format = $('input[data-fieldname="print_format"]').val();
let letterhead = $('input[data-fieldname="letterhead"]').val();
let allowed_print_formats = ["Sales Invoice Standard", "Sales Invoice with Item Image"];
let allowed_letterheads = ["Company Letterhead", "Company Letterhead - Grey"];
if (!allowed_print_formats.includes(print_format) && !allowed_letterheads.includes(letterhead)) {
return;
}
handle_route_event();
function handle_route_event() {
const route = frappe.get_route();
const current_doctype = route[1];
const current_docname = route[2];
if (!beforePrintHandled && route[0] === "print" && route[1] === "Sales Invoice") {
beforePrintHandled = true;
if (!doctype_list.includes(current_doctype)) return;
let companyDetailsDialog = new frappe.ui.Dialog({
title: "Enter Company Details",
fields: [
{
label: "Company Logo",
fieldname: "company_logo",
fieldtype: "Attach Image",
reqd: data.company_logo ? 0 : 1,
hidden: data.company_logo ? 1 : 0,
setTimeout(() => {
if (should_fetch_company_details()) {
fetch_company_details(current_doctype, current_docname);
}
}, 500);
}
function should_fetch_company_details() {
const print_format = $('input[data-fieldname="print_format"]').val();
const letterhead = $('input[data-fieldname="letterhead"]').val();
return allowed_print_formats.includes(print_format) || allowed_letterheads.includes(letterhead);
}
function fetch_company_details(current_doctype, current_docname) {
frappe.call({
method: "erpnext.controllers.accounts_controller.get_missing_company_details",
args: { doctype: current_doctype, docname: current_docname },
callback: function (r) {
if (r && r.message) {
open_company_details_dialog(r.message, current_doctype);
}
},
});
}
function open_company_details_dialog(data, current_doctype) {
const dialog = new frappe.ui.Dialog({
title: __("Enter Company Details"),
fields: build_dialog_fields(data),
primary_action_label: __("Save"),
primary_action(values) {
save_company_details(dialog, data, values, current_doctype);
},
});
dialog.show();
}
function build_dialog_fields(data) {
return [
make_field(__("Company Logo"), "company_logo", "Attach Image", data.company_logo),
make_field(__("Website"), "website", "Data", data.website),
make_field(__("Phone No"), "phone_no", "Data", data.phone_no),
{
label: __("Email"),
fieldname: "email",
fieldtype: "Data",
options: "Email",
reqd: data.email ? 0 : 1,
hidden: data.email ? 1 : 0,
},
{ fieldtype: "Section Break" },
make_field(__("Address Title"), "address_title", "Data", data.address_line),
{
label: __("Address Type"),
fieldname: "address_type",
fieldtype: "Select",
options: ["Billing", "Shipping"],
default: "Billing",
reqd: data.address_line ? 0 : 1,
hidden: data.address_line ? 1 : 0,
},
make_field(__("Address Line 1"), "address_line1", "Data", data.address_line),
make_field(__("Address Line 2"), "address_line2", "Data", data.address_line, false),
make_field(__("City"), "city", "Data", data.address_line),
make_field(__("State"), "state", "Data", data.address_line, false),
{
label: __("Country"),
fieldname: "country",
fieldtype: "Link",
options: "Country",
reqd: data.address_line ? 0 : 1,
hidden: data.address_line ? 1 : 0,
},
make_field(__("Postal Code"), "pincode", "Data", data.address_line, false),
{
label: __("Select Company Address"),
fieldname: "company_address",
fieldtype: "Link",
options: "Address",
get_query: () => ({
query: "frappe.contacts.doctype.address.address.address_query",
filters: {
link_doctype: "Company",
link_name: data.company,
},
{
label: "Website",
fieldname: "website",
fieldtype: "Data",
hidden: data.website ? 1 : 0,
},
{
label: "Phone No",
fieldname: "phone_no",
fieldtype: "Data",
reqd: data.phone_no ? 0 : 1,
hidden: data.phone_no ? 1 : 0,
},
{
label: "Email",
fieldname: "email",
fieldtype: "Data",
options: "Email",
reqd: data.email ? 0 : 1,
hidden: data.email ? 1 : 0,
},
{
fieldname: "section_break_1",
fieldtype: "Section Break",
},
{
label: "Address Title",
fieldname: "address_title",
fieldtype: "Data",
reqd: data.address_line ? 0 : 1,
hidden: data.address_line ? 1 : 0,
},
{
label: "Address Type",
fieldname: "address_type",
fieldtype: "Select",
options: ["Billing", "Shipping"],
default: "Billing",
reqd: data.address_line ? 0 : 1,
hidden: data.address_line ? 1 : 0,
},
{
label: "Address Line 1",
fieldname: "address_line1",
fieldtype: "Data",
reqd: data.address_line ? 0 : 1,
hidden: data.address_line ? 1 : 0,
},
{
label: "Address Line 2",
fieldname: "address_line2",
fieldtype: "Data",
hidden: data.address_line ? 1 : 0,
},
{
label: "City",
fieldname: "city",
fieldtype: "Data",
reqd: data.address_line ? 0 : 1,
hidden: data.address_line ? 1 : 0,
},
{
label: "State",
fieldname: "state",
fieldtype: "Data",
hidden: data.address_line ? 1 : 0,
},
{
label: "Country",
fieldname: "country",
fieldtype: "Link",
options: "Country",
reqd: data.address_line ? 0 : 1,
hidden: data.address_line ? 1 : 0,
},
{
label: "Postal Code",
fieldname: "pincode",
fieldtype: "Data",
hidden: data.address_line ? 1 : 0,
},
{
label: "Select Company Address",
fieldname: "company_address",
fieldtype: "Link",
options: "Address",
get_query: function () {
return {
query: "frappe.contacts.doctype.address.address.address_query",
filters: {
link_doctype: "Company",
link_name: data.company,
},
};
},
reqd: data.address_line && !data.company_address ? 1 : 0,
hidden: data.address_line && !data.company_address ? 0 : 1,
},
],
primary_action_label: "Save",
primary_action(values) {
frappe.call({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.save_company_master_details",
args: {
name: data.name,
company: data.company,
details: values,
},
callback: function () {
companyDetailsDialog.hide();
frappe.msgprint(__("Updating details."));
setTimeout(() => {
window.location.reload();
}, 1000);
},
});
},
});
companyDetailsDialog.show();
}
});
frappe.router.on("change", () => {
const route = frappe.get_route();
if (route[0] !== "print" || route[1] !== "Sales Invoice") {
beforePrintHandled = false;
}
});
}),
reqd: data.address_line && !data.company_address ? 1 : 0,
hidden: data.address_line && !data.company_address ? 0 : 1,
},
];
}
function make_field(label, fieldname, fieldtype, existing_value, required_if_empty = true) {
return {
label,
fieldname,
fieldtype,
reqd: existing_value ? 0 : required_if_empty ? 1 : 0,
hidden: existing_value ? 1 : 0,
};
}
function save_company_details(dialog, data, values, current_doctype) {
frappe.call({
method: "erpnext.controllers.accounts_controller.update_company_master_and_address",
args: {
name: data.name,
company: data.company,
details: values,
current_doctype: current_doctype,
},
callback() {
dialog.hide();
frappe.msgprint(__("Updating details."));
setTimeout(() => {
location.reload();
}, 1000);
},
});
}