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

This commit is contained in:
Nabin Hait
2026-05-29 12:26:55 +05:30
parent 01e7224210
commit 2cf51a0367
2 changed files with 191 additions and 178 deletions

View File

@@ -0,0 +1,185 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please 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 erpnext.accounts.party import get_party_account_currency, get_party_details
from erpnext.stock.doctype.material_request.material_request import set_missing_values
@frappe.whitelist()
def make_supplier_quotation_from_rfq(
source_name: str, target_doc: str | Document | None = None, for_supplier: str | None = None
):
def postprocess(source, target_doc):
if for_supplier:
target_doc.supplier = for_supplier
args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True)
target_doc.currency = args.currency or get_party_account_currency(
"Supplier", for_supplier, source.company
)
target_doc.buying_price_list = args.buying_price_list or frappe.db.get_single_value(
"Buying Settings", "buying_price_list"
)
set_missing_values(source, target_doc)
doclist = get_mapped_doc(
"Request for Quotation",
source_name,
{
"Request for Quotation": {
"doctype": "Supplier Quotation",
"validation": {"docstatus": ["=", 1]},
"field_map": {"opportunity": "opportunity"},
},
"Request for Quotation Item": {
"doctype": "Supplier Quotation Item",
"field_map": {
"name": "request_for_quotation_item",
"parent": "request_for_quotation",
"project_name": "project",
},
},
},
target_doc,
postprocess,
)
return doclist
# This method is used to make supplier quotation from supplier's portal.
@frappe.whitelist()
def create_supplier_quotation(doc: str | Document | dict):
if isinstance(doc, str):
doc = json.loads(doc)
if frappe.session.user not in frappe.get_all(
"Portal User", {"parent": doc.get("supplier")}, pluck="user"
):
frappe.throw(_("Not Permitted"), frappe.PermissionError)
try:
sq_doc = frappe.get_doc(
{
"doctype": "Supplier Quotation",
"supplier": doc.get("supplier"),
"terms": doc.get("terms"),
"company": doc.get("company"),
"currency": doc.get("currency")
or get_party_account_currency("Supplier", doc.get("supplier"), doc.get("company")),
"buying_price_list": doc.get("buying_price_list")
or frappe.db.get_single_value("Buying Settings", "buying_price_list"),
}
)
add_items(sq_doc, doc.get("supplier"), doc.get("items"))
sq_doc.flags.ignore_permissions = True
sq_doc.run_method("set_missing_values")
sq_doc.save()
frappe.msgprint(_("Supplier Quotation {0} Created").format(sq_doc.name))
return sq_doc.name
except Exception:
return None
def add_items(sq_doc, supplier, items):
for data in items:
if isinstance(data, dict):
data = frappe._dict(data)
create_rfq_items(sq_doc, supplier, data)
def create_rfq_items(sq_doc, supplier, data):
args = {}
for field in [
"item_code",
"item_name",
"description",
"qty",
"rate",
"conversion_factor",
"warehouse",
"material_request",
"material_request_item",
"stock_qty",
"uom",
]:
args[field] = data.get(field)
args.update(
{
"request_for_quotation_item": data.name,
"request_for_quotation": data.parent,
"supplier_part_no": frappe.db.get_value(
"Item Supplier", {"parent": data.item_code, "supplier": supplier}, "supplier_part_no"
),
}
)
sq_doc.append("items", args)
@frappe.whitelist()
def get_item_from_material_requests_based_on_supplier(
source_name: str, target_doc: str | Document | None = None
):
Item = frappe.qb.DocType("Item")
Item_Supp = frappe.qb.DocType("Item Supplier")
MR = frappe.qb.DocType("Material Request")
MR_Item = frappe.qb.DocType("Material Request Item")
query = (
frappe.qb.from_(MR_Item)
.join(MR)
.on(MR_Item.parent == MR.name)
.join(Item)
.on(MR_Item.item_code == Item.name)
.join(Item_Supp)
.on(Item.name == Item_Supp.parent)
.select(MR.name, MR_Item.item_code)
.where(Item_Supp.supplier == source_name)
.where(MR.status != "Stopped")
.where(MR.material_request_type == "Purchase")
.where(MR.docstatus == 1)
.where(MR.per_ordered < 99.99)
)
mr_items_list = query.run(as_dict=True)
material_requests = {}
for d in mr_items_list:
material_requests.setdefault(d.name, []).append(d.item_code)
for mr, items in material_requests.items():
target_doc = get_mapped_doc(
"Material Request",
mr,
{
"Material Request": {
"doctype": "Request for Quotation",
"validation": {
"docstatus": ["=", 1],
"material_request_type": ["=", "Purchase"],
},
},
"Material Request Item": {
"doctype": "Request for Quotation Item",
"condition": lambda row: row.item_code in items,
"field_map": [
["name", "material_request_item"],
["parent", "material_request"],
["uom", "uom"],
],
},
},
target_doc,
)
return target_doc

View File

@@ -2,23 +2,24 @@
# For license information, please see license.txt
import json
import frappe
from frappe import _
from frappe.core.doctype.communication.email import make
from frappe.desk.form.load import get_attachments
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.query_builder import Order
from frappe.utils import get_url
from frappe.utils.print_format import download_pdf
from frappe.utils.user import get_user_fullname
from erpnext.accounts.party import get_party_account_currency, get_party_details
from erpnext.buying.utils import validate_for_items
from erpnext.controllers.buying_controller import BuyingController
from erpnext.stock.doctype.material_request.material_request import set_missing_values
from .mapper import (
create_supplier_quotation,
get_item_from_material_requests_based_on_supplier,
make_supplier_quotation_from_rfq,
)
STANDARD_USERS = ("Guest", "Administrator")
@@ -438,120 +439,6 @@ def get_list_context(context=None):
return list_context
@frappe.whitelist()
def make_supplier_quotation_from_rfq(
source_name: str, target_doc: str | Document | None = None, for_supplier: str | None = None
):
def postprocess(source, target_doc):
if for_supplier:
target_doc.supplier = for_supplier
args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True)
target_doc.currency = args.currency or get_party_account_currency(
"Supplier", for_supplier, source.company
)
target_doc.buying_price_list = args.buying_price_list or frappe.db.get_single_value(
"Buying Settings", "buying_price_list"
)
set_missing_values(source, target_doc)
doclist = get_mapped_doc(
"Request for Quotation",
source_name,
{
"Request for Quotation": {
"doctype": "Supplier Quotation",
"validation": {"docstatus": ["=", 1]},
"field_map": {"opportunity": "opportunity"},
},
"Request for Quotation Item": {
"doctype": "Supplier Quotation Item",
"field_map": {
"name": "request_for_quotation_item",
"parent": "request_for_quotation",
"project_name": "project",
},
},
},
target_doc,
postprocess,
)
return doclist
# This method is used to make supplier quotation from supplier's portal.
@frappe.whitelist()
def create_supplier_quotation(doc: str | Document | dict):
if isinstance(doc, str):
doc = json.loads(doc)
if frappe.session.user not in frappe.get_all(
"Portal User", {"parent": doc.get("supplier")}, pluck="user"
):
frappe.throw(_("Not Permitted"), frappe.PermissionError)
try:
sq_doc = frappe.get_doc(
{
"doctype": "Supplier Quotation",
"supplier": doc.get("supplier"),
"terms": doc.get("terms"),
"company": doc.get("company"),
"currency": doc.get("currency")
or get_party_account_currency("Supplier", doc.get("supplier"), doc.get("company")),
"buying_price_list": doc.get("buying_price_list")
or frappe.db.get_single_value("Buying Settings", "buying_price_list"),
}
)
add_items(sq_doc, doc.get("supplier"), doc.get("items"))
sq_doc.flags.ignore_permissions = True
sq_doc.run_method("set_missing_values")
sq_doc.save()
frappe.msgprint(_("Supplier Quotation {0} Created").format(sq_doc.name))
return sq_doc.name
except Exception:
return None
def add_items(sq_doc, supplier, items):
for data in items:
if isinstance(data, dict):
data = frappe._dict(data)
create_rfq_items(sq_doc, supplier, data)
def create_rfq_items(sq_doc, supplier, data):
args = {}
for field in [
"item_code",
"item_name",
"description",
"qty",
"rate",
"conversion_factor",
"warehouse",
"material_request",
"material_request_item",
"stock_qty",
"uom",
]:
args[field] = data.get(field)
args.update(
{
"request_for_quotation_item": data.name,
"request_for_quotation": data.parent,
"supplier_part_no": frappe.db.get_value(
"Item Supplier", {"parent": data.item_code, "supplier": supplier}, "supplier_part_no"
),
}
)
sq_doc.append("items", args)
@frappe.whitelist()
def get_pdf(
name: str,
@@ -575,65 +462,6 @@ def get_pdf(
)
@frappe.whitelist()
def get_item_from_material_requests_based_on_supplier(
source_name: str, target_doc: str | Document | None = None
):
Item = frappe.qb.DocType("Item")
Item_Supp = frappe.qb.DocType("Item Supplier")
MR = frappe.qb.DocType("Material Request")
MR_Item = frappe.qb.DocType("Material Request Item")
query = (
frappe.qb.from_(MR_Item)
.join(MR)
.on(MR_Item.parent == MR.name)
.join(Item)
.on(MR_Item.item_code == Item.name)
.join(Item_Supp)
.on(Item.name == Item_Supp.parent)
.select(MR.name, MR_Item.item_code)
.where(Item_Supp.supplier == source_name)
.where(MR.status != "Stopped")
.where(MR.material_request_type == "Purchase")
.where(MR.docstatus == 1)
.where(MR.per_ordered < 99.99)
)
mr_items_list = query.run(as_dict=True)
material_requests = {}
for d in mr_items_list:
material_requests.setdefault(d.name, []).append(d.item_code)
for mr, items in material_requests.items():
target_doc = get_mapped_doc(
"Material Request",
mr,
{
"Material Request": {
"doctype": "Request for Quotation",
"validation": {
"docstatus": ["=", 1],
"material_request_type": ["=", "Purchase"],
},
},
"Material Request Item": {
"doctype": "Request for Quotation Item",
"condition": lambda row: row.item_code in items,
"field_map": [
["name", "material_request_item"],
["parent", "material_request"],
["uom", "uom"],
],
},
},
target_doc,
)
return target_doc
@frappe.whitelist()
def get_supplier_tag():
filters = {"document_type": "Supplier"}