diff --git a/utility_billing/utility_billing/doctype/meter_reading/meter_reading.js b/utility_billing/utility_billing/doctype/meter_reading/meter_reading.js index fc2e7e3..8aa386e 100644 --- a/utility_billing/utility_billing/doctype/meter_reading/meter_reading.js +++ b/utility_billing/utility_billing/doctype/meter_reading/meter_reading.js @@ -105,9 +105,10 @@ frappe.ui.form.on("Meter Reading Item", { method: "utility_billing.utility_billing.doctype.meter_reading.meter_reading.get_previous_invoice_reading", args: { item_code: row.item_code, + customer: frm.doc.customer, }, callback: function (r) { - row.previous_reading = r.message[1] || 0; + row.previous_reading = r.message || 0; frm.refresh_field("items"); }, }); diff --git a/utility_billing/utility_billing/doctype/meter_reading/meter_reading.py b/utility_billing/utility_billing/doctype/meter_reading/meter_reading.py index c34ea97..93e90e0 100644 --- a/utility_billing/utility_billing/doctype/meter_reading/meter_reading.py +++ b/utility_billing/utility_billing/doctype/meter_reading/meter_reading.py @@ -44,6 +44,9 @@ def create_sales_order(meter_reading): "selling_price_list": meter_reading.price_list, } ) + utility_property = frappe.get_value("Customer", meter_reading.customer, "utility_property") + if utility_property: + sales_order.utility_property = utility_property for rate in meter_reading.rates: rate_dict = rate.as_dict() @@ -52,8 +55,7 @@ def create_sales_order(meter_reading): for i in meter_reading.items: - _, prev_reading = get_previous_invoice_reading(i.item_code) - prev_consumption = get_previous_consumption(i.item_code) + prev_reading = get_previous_invoice_reading(i.item_code, meter_reading.customer) sales_order.append( "meter_readings", { @@ -74,34 +76,20 @@ def create_sales_order(meter_reading): return sales_order - @frappe.whitelist() -def get_previous_consumption(item_code): - """Fetch the sum of previous readings for the specified meter number sharing the same parent.""" - parent, _ = get_previous_invoice_reading(item_code) - meter_reading = DocType("Sales Invoice Meter Reading") - previous_consumption = ( - frappe.qb.from_(meter_reading) - .where(meter_reading.parent == parent) - .select(Sum(meter_reading.current_reading - meter_reading.previous_reading)) - ).run() - return previous_consumption[0][0] if previous_consumption else 0 - - -@frappe.whitelist() -def get_previous_invoice_reading(item_code): - """Fetch the previous reading and its parent for the specified meter number.""" - previous_reading = frappe.get_all( - "Sales Invoice Meter Reading", - filters={"item_code": item_code}, - fields=["current_reading", "creation", "parent"], - order_by="creation desc", - limit_page_length=1, - ) - if previous_reading: - return previous_reading[0].parent, previous_reading[0].current_reading - else: - return "None", 0 +def get_previous_invoice_reading(item_code, customer): + """Fetch the last submitted invoice's current reading for the specified item and customer.""" + + latest_invoice = frappe.get_value("Sales Invoice", filters={"customer": customer, "docstatus": 1}, + fieldname="name", order_by="creation desc") + + if not latest_invoice: + return 0 + + previous_reading = frappe.get_value("Sales Invoice Meter Reading", filters={"parent": latest_invoice, "item_code": item_code}, + fieldname="current_reading", order_by="creation desc") + + return previous_reading or 0 @frappe.whitelist() diff --git a/utility_billing/utility_billing/doctype/utility_category/utility_category.json b/utility_billing/utility_billing/doctype/utility_category/utility_category.json index 5c1330a..5bdfcdc 100644 --- a/utility_billing/utility_billing/doctype/utility_category/utility_category.json +++ b/utility_billing/utility_billing/doctype/utility_category/utility_category.json @@ -6,7 +6,12 @@ "doctype": "DocType", "engine": "InnoDB", "field_order": [ - "title" + "title", + "lft", + "rgt", + "is_group", + "old_parent", + "parent_utility_category" ], "fields": [ { @@ -14,15 +19,51 @@ "fieldtype": "Data", "label": "Title", "unique": 1 + }, + { + "fieldname": "lft", + "fieldtype": "Int", + "hidden": 1, + "label": "Left", + "no_copy": 1, + "read_only": 1 + }, + { + "fieldname": "rgt", + "fieldtype": "Int", + "hidden": 1, + "label": "Right", + "no_copy": 1, + "read_only": 1 + }, + { + "fieldname": "is_group", + "fieldtype": "Check", + "label": "Is Group" + }, + { + "fieldname": "old_parent", + "fieldtype": "Link", + "label": "Old Parent", + "options": "Utility Category" + }, + { + "fieldname": "parent_utility_category", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Parent Utility Category", + "options": "Utility Category" } ], "index_web_pages_for_search": 1, + "is_tree": 1, "links": [], - "modified": "2024-11-06 16:06:42.742911", + "modified": "2024-11-06 16:40:59.588124", "modified_by": "Administrator", "module": "Utility Billing", "name": "Utility Category", "naming_rule": "By fieldname", + "nsm_parent_field": "parent_utility_category", "owner": "Administrator", "permissions": [ { diff --git a/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.js b/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.js index d8e8002..b5f5164 100644 --- a/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.js +++ b/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.js @@ -65,6 +65,26 @@ frappe.ui.form.on("Utility Service Request", { } }, + property: function (frm) { + if (frm.doc.property) { + frappe.call({ + method: "frappe.client.get_value", + args: { + doctype: "Utility Property", + fieldname: "territory", + filters: { + name: frm.doc.property, + }, + }, + callback: function (r) { + if (r.message && r.message.territory) { + frm.set_value("territory", r.message.territory); + } + }, + }); + } + }, + tc_name: function (frm) { if (!frm.doc.tc_name) { frm.set_value("terms", ""); diff --git a/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.json b/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.json index 0c8d2d8..2b83897 100644 --- a/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.json +++ b/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.json @@ -15,6 +15,7 @@ "date", "customer_group", "territory", + "property", "column_break_wxld", "company", "tax_id", @@ -36,10 +37,9 @@ "connection_size", "pipes_typedistance", "column_break_bfhu", - "east_cordinates", "water_network", "column_break_omtp", - "south_cordinates", + "location", "address_and_contacts_tab", "section_break_ywar", "address_html", @@ -229,16 +229,6 @@ "fieldtype": "Data", "label": "Water Network" }, - { - "fieldname": "east_cordinates", - "fieldtype": "Data", - "label": "East Cordinates" - }, - { - "fieldname": "south_cordinates", - "fieldtype": "Data", - "label": "South Cordinates" - }, { "fieldname": "pipes_typedistance", "fieldtype": "Data", @@ -418,12 +408,24 @@ "fieldname": "date_posted", "fieldtype": "Date", "label": "Posted by Date" + }, + { + "fieldname": "property", + "fieldtype": "Link", + "label": "Property", + "options": "Utility Property" + }, + { + "fieldname": "location", + "fieldtype": "Link", + "label": "Location", + "options": "Location" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2024-10-24 13:50:18.316001", + "modified": "2024-11-06 16:42:41.258215", "modified_by": "Administrator", "module": "Utility Billing", "name": "Utility Service Request", diff --git a/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.py b/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.py index b64ffba..dfa7939 100644 --- a/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.py +++ b/utility_billing/utility_billing/doctype/utility_service_request/utility_service_request.py @@ -35,6 +35,7 @@ def create_customer(doc): customer_doc.nrc_or_passport_no = doc.nrcpassport_no customer_doc.company = doc.company customer_doc.insert() + customer_doc.utility_property = doc.property frappe.db.set_value( "Utility Service Request", doc.name, "customer", customer_doc.name @@ -82,6 +83,7 @@ def create_sales_order(doc, customer_doc): sales_order_doc = frappe.new_doc("Sales Order") sales_order_doc.customer = customer_doc.name sales_order_doc.utility_service_request = doc.name + sales_order_doc.utility_property = doc.property sales_order_doc.transaction_date = frappe.utils.nowdate() sales_order_doc.delivery_date = add_months(sales_order_doc.transaction_date, 1) @@ -113,13 +115,12 @@ def create_site_survey(docname): issue_doc.subject = f"Site Survey for {docname} ({doc.customer_name})" issue_doc.description = ( f"Site survey created for Utility Service Request: {docname}, Customer name: {doc.customer_name}.\n" - f"{request_type_description}" + f"{' ' + request_type_description if request_type_description else ''}", ) issue_doc.utility_service_request = docname issue_doc.issue_type = doc.request_type issue_doc.insert() - doc.save() return {"issue": issue_doc.name} diff --git a/utility_billing/utility_billing/overrides/server/sales_invoice.py b/utility_billing/utility_billing/overrides/server/sales_invoice.py index 00dbe47..92cb528 100644 --- a/utility_billing/utility_billing/overrides/server/sales_invoice.py +++ b/utility_billing/utility_billing/overrides/server/sales_invoice.py @@ -2,40 +2,36 @@ import frappe from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals from erpnext.controllers.accounts_controller import AccountsController -from frappe.model.mapper import get_mapped_doc def before_validate(doc: Document, method: str) -> None: """Intercepts submit event for document""" - AccountsController.append_taxes_from_item_tax_template(doc) - calculate_taxes_and_totals(doc) - unique_sales_orders = {item.sales_order for item in doc.items if item.sales_order} - for sales_order in unique_sales_orders: - map_sales_order_meter_readings_to_invoice(sales_order, doc, True) + if not doc.taxes: + AccountsController.append_taxes_from_item_tax_template(doc) + calculate_taxes_and_totals(doc) + unique_sales_orders = { + item.sales_order + for item in frappe.get_all( + "Sales Invoice Item", + filters={"parent": doc.name, "sales_order": ["is", "set"]}, + fields=["sales_order"] + ) + } + for sales_order in unique_sales_orders: + map_sales_order_meter_readings_to_invoice(sales_order, doc) -def map_sales_order_meter_readings_to_invoice(source_name, target_doc, ignore_permissions): - """Map Sales Order to Sales Invoice, including meter readings.""" - return get_mapped_doc( - "Sales Order", - source_name, - { - "Sales Order": { - "doctype": "Sales Invoice", - "field_map": { - "party_account_currency": "party_account_currency", - "payment_terms_template": "payment_terms_template", - }, - "field_no_map": ["payment_terms_template"], - "validation": {"docstatus": ["=", 1]}, - }, - "Sales Order Meter Reading": { - "doctype": "Sales Invoice Meter Reading", - "add_if_empty": True, - } - }, - target_doc, - ignore_permissions=ignore_permissions, - ) +def map_sales_order_meter_readings_to_invoice(sales_order_name, target_doc): + """Map all fields from Sales Order Meter Reading to Sales Invoice Meter Reading.""" + sales_order = frappe.get_doc("Sales Order", sales_order_name) + meter_readings = sales_order.get("meter_readings") + target_doc.set("meter_readings", []) + if sales_order.utility_property: target_doc.utility_property = sales_order.utility_property + + for reading in meter_readings: + new_reading_data = reading.as_dict() + new_reading_data.pop("name", None) + new_reading = target_doc.append("meter_readings", new_reading_data) + new_reading.parent = target_doc.name