refactor(purchase_invoice): move mapping functions to mapper.py

This commit is contained in:
Nabin Hait
2026-05-29 13:04:08 +05:30
parent 7b456c6405
commit f9d67ebb1e
2 changed files with 132 additions and 121 deletions

View File

@@ -0,0 +1,129 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import json
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.utils import flt
from erpnext.controllers.accounts_controller import merge_taxes
@frappe.whitelist()
def make_debit_note(source_name: str, target_doc: str | Document | None = None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Purchase Invoice", source_name, target_doc)
@frappe.whitelist()
def make_stock_entry(source_name: str, target_doc: str | Document | None = None):
doc = get_mapped_doc(
"Purchase Invoice",
source_name,
{
"Purchase Invoice": {"doctype": "Stock Entry", "validation": {"docstatus": ["=", 1]}},
"Purchase Invoice Item": {
"doctype": "Stock Entry Detail",
"field_map": {"stock_qty": "transfer_qty", "batch_no": "batch_no"},
},
},
target_doc,
)
return doc
@frappe.whitelist()
def make_inter_company_sales_invoice(source_name: str, target_doc: Document | None = None):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
return make_inter_company_transaction("Purchase Invoice", source_name, target_doc)
@frappe.whitelist()
def make_purchase_receipt(
source_name: str, target_doc: str | Document | None = None, args: str | dict | None = None
):
if args is None:
args = {}
if isinstance(args, str):
args = json.loads(args)
def post_parent_process(source_parent, target_parent):
remove_items_with_zero_qty(target_parent)
set_missing_values(source_parent, target_parent)
def remove_items_with_zero_qty(target_parent):
target_parent.items = [row for row in target_parent.get("items") if row.get("qty") != 0]
def set_missing_values(source_parent, target_parent):
target_parent.run_method("set_missing_values")
if args and args.get("merge_taxes"):
merge_taxes(source_parent, target_parent)
target_parent.run_method("calculate_taxes_and_totals")
def update_item(obj, target, source_parent):
from erpnext.controllers.sales_and_purchase_return import get_returned_qty_map_for_row
returned_qty_map = (
get_returned_qty_map_for_row(
source_parent.name, source_parent.supplier, obj.name, "Purchase Invoice"
)
or {}
)
target.qty = flt(obj.qty) - flt(obj.received_qty) - flt(returned_qty_map.get("qty"))
target.received_qty = flt(obj.qty) - flt(obj.received_qty)
target.stock_qty = (flt(obj.qty) - flt(obj.received_qty) - flt(returned_qty_map.get("qty"))) * flt(
obj.conversion_factor
)
target.amount = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate)
target.base_amount = (
(flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate) * flt(source_parent.conversion_rate)
)
def select_item(d):
filtered_items = args.get("filtered_children", [])
child_filter = d.name in filtered_items if filtered_items else True
return child_filter
doc = get_mapped_doc(
"Purchase Invoice",
source_name,
{
"Purchase Invoice": {
"doctype": "Purchase Receipt",
"validation": {
"docstatus": ["=", 1],
},
},
"Purchase Invoice Item": {
"doctype": "Purchase Receipt Item",
"field_map": {
"name": "purchase_invoice_item",
"parent": "purchase_invoice",
"bom": "bom",
"purchase_order": "purchase_order",
"po_detail": "purchase_order_item",
"material_request": "material_request",
"material_request_item": "material_request_item",
"wip_composite_asset": "wip_composite_asset",
},
"postprocess": update_item,
"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty) and select_item(doc),
},
"Purchase Taxes and Charges": {
"doctype": "Purchase Taxes and Charges",
"reset_value": not (args and args.get("merge_taxes")),
"ignore": args.get("merge_taxes") if args else 0,
},
},
target_doc,
post_parent_process,
)
return doc

View File

@@ -2,12 +2,9 @@
# License: GNU General Public License v3. See license.txt
import json
import frappe
from frappe import _, qb, throw
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.query_builder.functions import Sum
from frappe.utils import cint, cstr, flt, formatdate, get_link_to_form, getdate, nowdate
@@ -37,12 +34,14 @@ from erpnext.accounts.utils import get_account_currency, get_fiscal_year, update
from erpnext.assets.doctype.asset.asset import is_cwip_accounting_enabled
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.buying.utils import check_on_hold_or_closed_status
from erpnext.controllers.accounts_controller import merge_taxes, validate_account_head
from erpnext.controllers.accounts_controller import validate_account_head
from erpnext.controllers.buying_controller import BuyingController
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
update_billed_amount_based_on_po,
)
from .mapper import make_debit_note, make_inter_company_sales_invoice, make_purchase_receipt, make_stock_entry
class WarehouseMissingError(frappe.ValidationError):
pass
@@ -1140,31 +1139,6 @@ def make_regional_gl_entries(gl_entries, doc):
return gl_entries
@frappe.whitelist()
def make_debit_note(source_name: str, target_doc: str | Document | None = None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Purchase Invoice", source_name, target_doc)
@frappe.whitelist()
def make_stock_entry(source_name: str, target_doc: str | Document | None = None):
doc = get_mapped_doc(
"Purchase Invoice",
source_name,
{
"Purchase Invoice": {"doctype": "Stock Entry", "validation": {"docstatus": ["=", 1]}},
"Purchase Invoice Item": {
"doctype": "Stock Entry Detail",
"field_map": {"stock_qty": "transfer_qty", "batch_no": "batch_no"},
},
},
target_doc,
)
return doc
@frappe.whitelist()
def change_release_date(name: str, release_date: str | None = None):
if frappe.db.exists("Purchase Invoice", name):
@@ -1184,95 +1158,3 @@ def block_invoice(name: str, release_date: str, hold_comment: str | None = None)
if frappe.db.exists("Purchase Invoice", name):
pi = frappe.get_lazy_doc("Purchase Invoice", name)
pi.block_invoice(hold_comment, release_date)
@frappe.whitelist()
def make_inter_company_sales_invoice(source_name: str, target_doc: Document | None = None):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
return make_inter_company_transaction("Purchase Invoice", source_name, target_doc)
@frappe.whitelist()
def make_purchase_receipt(
source_name: str, target_doc: str | Document | None = None, args: str | dict | None = None
):
if args is None:
args = {}
if isinstance(args, str):
args = json.loads(args)
def post_parent_process(source_parent, target_parent):
remove_items_with_zero_qty(target_parent)
set_missing_values(source_parent, target_parent)
def remove_items_with_zero_qty(target_parent):
target_parent.items = [row for row in target_parent.get("items") if row.get("qty") != 0]
def set_missing_values(source_parent, target_parent):
target_parent.run_method("set_missing_values")
if args and args.get("merge_taxes"):
merge_taxes(source_parent, target_parent)
target_parent.run_method("calculate_taxes_and_totals")
def update_item(obj, target, source_parent):
from erpnext.controllers.sales_and_purchase_return import get_returned_qty_map_for_row
returned_qty_map = (
get_returned_qty_map_for_row(
source_parent.name, source_parent.supplier, obj.name, "Purchase Invoice"
)
or {}
)
target.qty = flt(obj.qty) - flt(obj.received_qty) - flt(returned_qty_map.get("qty"))
target.received_qty = flt(obj.qty) - flt(obj.received_qty)
target.stock_qty = (flt(obj.qty) - flt(obj.received_qty) - flt(returned_qty_map.get("qty"))) * flt(
obj.conversion_factor
)
target.amount = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate)
target.base_amount = (
(flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate) * flt(source_parent.conversion_rate)
)
def select_item(d):
filtered_items = args.get("filtered_children", [])
child_filter = d.name in filtered_items if filtered_items else True
return child_filter
doc = get_mapped_doc(
"Purchase Invoice",
source_name,
{
"Purchase Invoice": {
"doctype": "Purchase Receipt",
"validation": {
"docstatus": ["=", 1],
},
},
"Purchase Invoice Item": {
"doctype": "Purchase Receipt Item",
"field_map": {
"name": "purchase_invoice_item",
"parent": "purchase_invoice",
"bom": "bom",
"purchase_order": "purchase_order",
"po_detail": "purchase_order_item",
"material_request": "material_request",
"material_request_item": "material_request_item",
"wip_composite_asset": "wip_composite_asset",
},
"postprocess": update_item,
"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty) and select_item(doc),
},
"Purchase Taxes and Charges": {
"doctype": "Purchase Taxes and Charges",
"reset_value": not (args and args.get("merge_taxes")),
"ignore": args.get("merge_taxes") if args else 0,
},
},
target_doc,
post_parent_process,
)
return doc