Merge branch 'version-12-hotfix' into version-12

This commit is contained in:
Sahil Khan 2019-08-07 16:21:14 +05:30
commit 9335cdd536
25 changed files with 1405 additions and 2555 deletions

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides from erpnext.hooks import regional_overrides
from frappe.utils import getdate from frappe.utils import getdate
__version__ = '12.0.4' __version__ = '12.0.5'
def get_default_company(user=None): def get_default_company(user=None):
'''Get default company for user''' '''Get default company for user'''

View File

@ -6,16 +6,10 @@ from frappe import _
def get_data(): def get_data():
return { return {
'fieldname': 'bank', 'fieldname': 'bank',
'non_standard_fieldnames': {
'Paymnet Order': 'company_bank'
},
'transactions': [ 'transactions': [
{ {
'label': _('Bank Deatils'), 'label': _('Bank Deatils'),
'items': ['Bank Account', 'Bank Guarantee'] 'items': ['Bank Account', 'Bank Guarantee']
},
{
'items': ['Payment Order']
} }
] ]
} }

View File

@ -648,13 +648,18 @@ def get_orders_to_be_billed(posting_date, party_type, party,
orders = [] orders = []
if voucher_type: if voucher_type:
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total" if party_account_currency == company_currency:
grand_total_field = "base_grand_total"
rounded_total_field = "base_rounded_total"
else:
grand_total_field = "grand_total"
rounded_total_field = "rounded_total"
orders = frappe.db.sql(""" orders = frappe.db.sql("""
select select
name as voucher_no, name as voucher_no,
{ref_field} as invoice_amount, if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) as invoice_amount,
({ref_field} - advance_paid) as outstanding_amount, (if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) - advance_paid) as outstanding_amount,
transaction_date as posting_date transaction_date as posting_date
from from
`tab{voucher_type}` `tab{voucher_type}`
@ -663,13 +668,14 @@ def get_orders_to_be_billed(posting_date, party_type, party,
and docstatus = 1 and docstatus = 1
and company = %s and company = %s
and ifnull(status, "") != "Closed" and ifnull(status, "") != "Closed"
and {ref_field} > advance_paid and if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) > advance_paid
and abs(100 - per_billed) > 0.01 and abs(100 - per_billed) > 0.01
{condition} {condition}
order by order by
transaction_date, name transaction_date, name
""".format(**{ """.format(**{
"ref_field": ref_field, "rounded_total_field": rounded_total_field,
"grand_total_field": grand_total_field,
"voucher_type": voucher_type, "voucher_type": voucher_type,
"party_type": scrub(party_type), "party_type": scrub(party_type),
"condition": condition "condition": condition

View File

@ -382,7 +382,7 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
`tab{child_doc}`.amount `tab{child_doc}`.amount
FROM `tab{child_doc}`, `tab{parent_doc}` FROM `tab{child_doc}`, `tab{parent_doc}`
WHERE WHERE
`tab{child_doc}`.parent = `tab{parent_doc}`.name and {date_field} `tab{child_doc}`.parent = `tab{parent_doc}`.name and `tab{parent_doc}`.{date_field}
between %s and %s and `tab{parent_doc}`.docstatus = 1 between %s and %s and `tab{parent_doc}`.docstatus = 1
{condition} group by `tab{child_doc}`.name {condition} group by `tab{child_doc}`.name
""".format(parent_doc = doctype, """.format(parent_doc = doctype,

View File

@ -93,6 +93,7 @@ def check_if_in_list(gle, gl_map, dimensions=None):
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False): def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
if not from_repost: if not from_repost:
validate_account_for_perpetual_inventory(gl_map) validate_account_for_perpetual_inventory(gl_map)
validate_cwip_accounts(gl_map)
round_off_debit_credit(gl_map) round_off_debit_credit(gl_map)
@ -123,6 +124,16 @@ def validate_account_for_perpetual_inventory(gl_map):
frappe.throw(_("Account: {0} can only be updated via Stock Transactions") frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(entry.account), StockAccountInvalidTransaction) .format(entry.account), StockAccountInvalidTransaction)
def validate_cwip_accounts(gl_map):
if not cint(frappe.db.get_value("Asset Settings", None, "disable_cwip_accounting")) \
and gl_map[0].voucher_type == "Journal Entry":
cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
where account_type = 'Capital Work in Progress' and is_group=0""")]
for entry in gl_map:
if entry.account in cwip_accounts:
frappe.throw(_("Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
def round_off_debit_credit(gl_map): def round_off_debit_credit(gl_map):
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency")) currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))

View File

@ -30,7 +30,9 @@ def update_last_purchase_rate(doc, is_submit):
# for it to be considered for latest purchase rate # for it to be considered for latest purchase rate
if flt(d.conversion_factor): if flt(d.conversion_factor):
last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor) last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor)
else: # Check if item code is present
# Conversion factor should not be mandatory for non itemized items
elif d.item_code:
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx)) frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
# update last purchsae rate # update last purchsae rate
@ -84,13 +86,13 @@ def get_linked_material_requests(items):
items = json.loads(items) items = json.loads(items)
mr_list = [] mr_list = []
for item in items: for item in items:
material_request = frappe.db.sql("""SELECT distinct mr.name AS mr_name, material_request = frappe.db.sql("""SELECT distinct mr.name AS mr_name,
(mr_item.qty - mr_item.ordered_qty) AS qty, (mr_item.qty - mr_item.ordered_qty) AS qty,
mr_item.item_code AS item_code, mr_item.item_code AS item_code,
mr_item.name AS mr_item mr_item.name AS mr_item
FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
WHERE mr.name = mr_item.parent WHERE mr.name = mr_item.parent
AND mr_item.item_code = %(item)s AND mr_item.item_code = %(item)s
AND mr.material_request_type = 'Purchase' AND mr.material_request_type = 'Purchase'
AND mr.per_ordered < 99.99 AND mr.per_ordered < 99.99
AND mr.docstatus = 1 AND mr.docstatus = 1
@ -98,6 +100,6 @@ def get_linked_material_requests(items):
ORDER BY mr_item.item_code ASC""",{"item": item}, as_dict=1) ORDER BY mr_item.item_code ASC""",{"item": item}, as_dict=1)
if material_request: if material_request:
mr_list.append(material_request) mr_list.append(material_request)
return mr_list return mr_list

View File

@ -94,6 +94,13 @@ def get_data():
"name": "BOM Update Tool", "name": "BOM Update Tool",
"description": _("Replace BOM and update latest price in all BOMs"), "description": _("Replace BOM and update latest price in all BOMs"),
}, },
{
"type": "page",
"label": _("BOM Comparison Tool"),
"name": "bom-comparison-tool",
"description": _("Compare BOMs for changes in Raw Materials and Operations"),
"data_doctype": "BOM"
},
] ]
}, },
{ {

View File

@ -1192,6 +1192,10 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
.format(child_item.idx, child_item.item_code)) .format(child_item.idx, child_item.item_code))
else: else:
child_item.rate = flt(d.get("rate")) child_item.rate = flt(d.get("rate"))
if child_item.price_list_rate:
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0, \
child_item.precision("discount_percentage"))
child_item.flags.ignore_validate_update_after_submit = True child_item.flags.ignore_validate_update_after_submit = True
if new_child_flag: if new_child_flag:
child_item.idx = len(parent.items) + 1 child_item.idx = len(parent.items) + 1

View File

@ -395,7 +395,9 @@ class BuyingController(StockController):
def set_qty_as_per_stock_uom(self): def set_qty_as_per_stock_uom(self):
for d in self.get("items"): for d in self.get("items"):
if d.meta.get_field("stock_qty"): if d.meta.get_field("stock_qty"):
if not d.conversion_factor: # Check if item code is present
# Conversion factor should not be mandatory for non itemized items
if not d.conversion_factor and d.item_code:
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx)) frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
d.stock_qty = flt(d.qty) * flt(d.conversion_factor) d.stock_qty = flt(d.qty) * flt(d.conversion_factor)

View File

@ -82,7 +82,7 @@ class calculate_taxes_and_totals(object):
item.net_rate = item.rate item.net_rate = item.rate
if not item.qty and self.doc.is_return: if not item.qty and self.doc.get("is_return"):
item.amount = flt(-1 * item.rate, item.precision("amount")) item.amount = flt(-1 * item.rate, item.precision("amount"))
else: else:
item.amount = flt(item.rate * item.qty, item.precision("amount")) item.amount = flt(item.rate * item.qty, item.precision("amount"))

View File

@ -77,7 +77,7 @@ def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_len
if or_filters: if or_filters:
for r in frappe.get_list(doctype, fields=fields,filters=filters, or_filters=or_filters, for r in frappe.get_list(doctype, fields=fields,filters=filters, or_filters=or_filters,
limit_start=limit_start, limit_page_length=limit_page_length, limit_start=limit_start, limit_page_length=limit_page_length,
ignore_permissions=ignore_permissions, order_by=order_by): ignore_permissions=ignore_permissions, order_by=order_by):
data.append(r) data.append(r)
@ -130,38 +130,56 @@ def get_customers_suppliers(doctype, user):
suppliers = [] suppliers = []
meta = frappe.get_meta(doctype) meta = frappe.get_meta(doctype)
customer_field_name = get_customer_field_name(doctype)
has_customer_field = meta.has_field(customer_field_name)
has_supplier_field = meta.has_field('supplier')
if has_common(["Supplier", "Customer"], frappe.get_roles(user)): if has_common(["Supplier", "Customer"], frappe.get_roles(user)):
contacts = frappe.db.sql(""" contacts = frappe.db.sql("""
select select
`tabContact`.email_id, `tabContact`.email_id,
`tabDynamic Link`.link_doctype, `tabDynamic Link`.link_doctype,
`tabDynamic Link`.link_name `tabDynamic Link`.link_name
from from
`tabContact`, `tabDynamic Link` `tabContact`, `tabDynamic Link`
where where
`tabContact`.name=`tabDynamic Link`.parent and `tabContact`.email_id =%s `tabContact`.name=`tabDynamic Link`.parent and `tabContact`.email_id =%s
""", user, as_dict=1) """, user, as_dict=1)
customers = [c.link_name for c in contacts if c.link_doctype == 'Customer'] \ customers = [c.link_name for c in contacts if c.link_doctype == 'Customer']
if meta.get_field("customer") else None suppliers = [c.link_name for c in contacts if c.link_doctype == 'Supplier']
suppliers = [c.link_name for c in contacts if c.link_doctype == 'Supplier'] \
if meta.get_field("supplier") else None
elif frappe.has_permission(doctype, 'read', user=user): elif frappe.has_permission(doctype, 'read', user=user):
customers = [customer.name for customer in frappe.get_list("Customer")] \ customer_list = frappe.get_list("Customer")
if meta.get_field("customer") else None customers = suppliers = [customer.name for customer in customer_list]
suppliers = [supplier.name for supplier in frappe.get_list("Customer")] \
if meta.get_field("supplier") else None
return customers, suppliers return customers if has_customer_field else None, \
suppliers if has_supplier_field else None
def has_website_permission(doc, ptype, user, verbose=False): def has_website_permission(doc, ptype, user, verbose=False):
doctype = doc.doctype doctype = doc.doctype
customers, suppliers = get_customers_suppliers(doctype, user) customers, suppliers = get_customers_suppliers(doctype, user)
if customers: if customers:
return frappe.get_all(doctype, filters=[(doctype, "customer", "in", customers), return frappe.db.exists(doctype, filters=get_customer_filter(doc, customers))
(doctype, "name", "=", doc.name)]) and True or False
elif suppliers: elif suppliers:
fieldname = 'suppliers' if doctype == 'Request for Quotation' else 'supplier' fieldname = 'suppliers' if doctype == 'Request for Quotation' else 'supplier'
return frappe.get_all(doctype, filters=[(doctype, fieldname, "in", suppliers), return frappe.db.exists(doctype, filters={
(doctype, "name", "=", doc.name)]) and True or False 'name': doc.name,
fieldname: ["in", suppliers]
})
else: else:
return False return False
def get_customer_filter(doc, customers):
doctype = doc.doctype
filters = frappe._dict()
filters.name = doc.name
filters[get_customer_field_name(doctype)] = ['in', customers]
if doctype == 'Quotation':
filters.party_type = 'Customer'
return filters
def get_customer_field_name(doctype):
if doctype == 'Quotation':
return 'party_name'
else:
return 'customer'

View File

@ -64,13 +64,20 @@ class EmployeeAdvance(Document):
def update_claimed_amount(self): def update_claimed_amount(self):
claimed_amount = frappe.db.sql(""" claimed_amount = frappe.db.sql("""
select sum(ifnull(allocated_amount, 0)) SELECT sum(ifnull(allocated_amount, 0))
from `tabExpense Claim Advance` FROM `tabExpense Claim Advance` eca, `tabExpense Claim` ec
where employee_advance = %s and docstatus=1 and allocated_amount > 0 WHERE
eca.employee_advance = %s
AND ec.approval_status="Approved"
AND ec.name = eca.parent
AND ec.docstatus=1
AND eca.allocated_amount > 0
""", self.name)[0][0] or 0 """, self.name)[0][0] or 0
if claimed_amount: frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount))
frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount)) self.reload()
self.set_status()
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
@frappe.whitelist() @frappe.whitelist()
def get_due_advance_amount(employee, posting_date): def get_due_advance_amount(employee, posting_date):

View File

@ -183,7 +183,7 @@ frappe.ui.form.on("Expense Claim", {
refresh: function(frm) { refresh: function(frm) {
frm.trigger("toggle_fields"); frm.trigger("toggle_fields");
if(frm.doc.docstatus == 1) { if(frm.doc.docstatus === 1 && frm.doc.approval_status !== "Rejected") {
frm.add_custom_button(__('Accounting Ledger'), function() { frm.add_custom_button(__('Accounting Ledger'), function() {
frappe.route_options = { frappe.route_options = {
voucher_no: frm.doc.name, voucher_no: frm.doc.name,
@ -194,7 +194,7 @@ frappe.ui.form.on("Expense Claim", {
}, __("View")); }, __("View"));
} }
if (frm.doc.docstatus===1 if (frm.doc.docstatus===1 && !cint(frm.doc.is_paid) && cint(frm.doc.grand_total) > 0
&& (cint(frm.doc.total_amount_reimbursed) < cint(frm.doc.total_sanctioned_amount)) && (cint(frm.doc.total_amount_reimbursed) < cint(frm.doc.total_sanctioned_amount))
&& frappe.model.can_create("Payment Entry")) { && frappe.model.can_create("Payment Entry")) {
frm.add_custom_button(__('Payment'), frm.add_custom_button(__('Payment'),

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@ from erpnext.setup.utils import get_exchange_rate
from frappe.website.website_generator import WebsiteGenerator from frappe.website.website_generator import WebsiteGenerator
from erpnext.stock.get_item_details import get_conversion_factor from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.stock.get_item_details import get_price_list_rate from erpnext.stock.get_item_details import get_price_list_rate
from frappe.core.doctype.version.version import get_diff
import functools import functools
@ -763,3 +764,52 @@ def add_additional_cost(stock_entry, work_order):
'description': name[0], 'description': name[0],
'amount': items.get(name[0]) 'amount': items.get(name[0])
}) })
@frappe.whitelist()
def get_bom_diff(bom1, bom2):
from frappe.model import table_fields
doc1 = frappe.get_doc('BOM', bom1)
doc2 = frappe.get_doc('BOM', bom2)
out = get_diff(doc1, doc2)
out.row_changed = []
out.added = []
out.removed = []
meta = doc1.meta
identifiers = {
'operations': 'operation',
'items': 'item_code',
'scrap_items': 'item_code',
'exploded_items': 'item_code'
}
for df in meta.fields:
old_value, new_value = doc1.get(df.fieldname), doc2.get(df.fieldname)
if df.fieldtype in table_fields:
identifier = identifiers[df.fieldname]
# make maps
old_row_by_identifier, new_row_by_identifier = {}, {}
for d in old_value:
old_row_by_identifier[d.get(identifier)] = d
for d in new_value:
new_row_by_identifier[d.get(identifier)] = d
# check rows for additions, changes
for i, d in enumerate(new_value):
if d.get(identifier) in old_row_by_identifier:
diff = get_diff(old_row_by_identifier[d.get(identifier)], d, for_child=True)
if diff and diff.changed:
out.row_changed.append((df.fieldname, i, d.get(identifier), diff.changed))
else:
out.added.append([df.fieldname, d.as_dict()])
# check for deletions
for d in old_value:
if not d.get(identifier) in new_row_by_identifier:
out.removed.append([df.fieldname, d.as_dict()])
return out

View File

@ -320,7 +320,8 @@ class ProductionPlan(Document):
'qty': data.get("stock_qty") * item.get("qty"), 'qty': data.get("stock_qty") * item.get("qty"),
'production_plan': self.name, 'production_plan': self.name,
'company': self.company, 'company': self.company,
'fg_warehouse': item.get("fg_warehouse") 'fg_warehouse': item.get("fg_warehouse"),
'update_consumed_material_cost_in_project': 0
}) })
work_order = self.create_work_order(data) work_order = self.create_work_order(data)
@ -430,7 +431,7 @@ def download_raw_materials(production_plan):
continue continue
item_list.append(['', '', '', '', bin_dict.get('warehouse'), item_list.append(['', '', '', '', bin_dict.get('warehouse'),
bin_dict.get('projected_qty'), bin_dict.get('actual_qty')]) bin_dict.get('projected_qty', 0), bin_dict.get('actual_qty', 0)])
build_csv_response(item_list, doc.name) build_csv_response(item_list, doc.name)
@ -507,8 +508,8 @@ def get_material_request_items(row, sales_order,
required_qty = 0 required_qty = 0
if ignore_existing_ordered_qty or bin_dict.get("projected_qty", 0) < 0: if ignore_existing_ordered_qty or bin_dict.get("projected_qty", 0) < 0:
required_qty = total_qty required_qty = total_qty
elif total_qty > bin_dict.get("projected_qty"): elif total_qty > bin_dict.get("projected_qty", 0):
required_qty = total_qty - bin_dict.get("projected_qty") required_qty = total_qty - bin_dict.get("projected_qty", 0)
if required_qty > 0 and required_qty < row['min_order_qty']: if required_qty > 0 and required_qty < row['min_order_qty']:
required_qty = row['min_order_qty'] required_qty = row['min_order_qty']
item_group_defaults = get_item_group_defaults(row.item_code, company) item_group_defaults = get_item_group_defaults(row.item_code, company)

View File

@ -1,484 +1,504 @@
{ {
"allow_import": 1, "allow_import": 1,
"autoname": "naming_series:", "autoname": "naming_series:",
"creation": "2013-01-10 16:34:16", "creation": "2013-01-10 16:34:16",
"doctype": "DocType", "doctype": "DocType",
"document_type": "Setup", "document_type": "Setup",
"field_order": [ "engine": "InnoDB",
"item", "field_order": [
"naming_series", "item",
"status", "naming_series",
"production_item", "status",
"item_name", "production_item",
"image", "item_name",
"bom_no", "image",
"allow_alternative_item", "bom_no",
"use_multi_level_bom", "column_break1",
"skip_transfer", "company",
"column_break1", "qty",
"company", "material_transferred_for_manufacturing",
"qty", "produced_qty",
"material_transferred_for_manufacturing", "sales_order",
"produced_qty", "project",
"sales_order", "settings_section",
"project", "allow_alternative_item",
"from_wip_warehouse", "use_multi_level_bom",
"warehouses", "column_break_18",
"wip_warehouse", "skip_transfer",
"fg_warehouse", "from_wip_warehouse",
"column_break_12", "update_consumed_material_cost_in_project",
"scrap_warehouse", "warehouses",
"required_items_section", "wip_warehouse",
"required_items", "fg_warehouse",
"time", "column_break_12",
"planned_start_date", "scrap_warehouse",
"actual_start_date", "required_items_section",
"column_break_13", "required_items",
"planned_end_date", "time",
"actual_end_date", "planned_start_date",
"expected_delivery_date", "actual_start_date",
"operations_section", "column_break_13",
"transfer_material_against", "planned_end_date",
"operations", "actual_end_date",
"section_break_22", "expected_delivery_date",
"planned_operating_cost", "operations_section",
"actual_operating_cost", "transfer_material_against",
"additional_operating_cost", "operations",
"column_break_24", "section_break_22",
"total_operating_cost", "planned_operating_cost",
"more_info", "actual_operating_cost",
"description", "additional_operating_cost",
"stock_uom", "column_break_24",
"column_break2", "total_operating_cost",
"material_request", "more_info",
"material_request_item", "description",
"sales_order_item", "stock_uom",
"production_plan", "column_break2",
"production_plan_item", "material_request",
"product_bundle_item", "material_request_item",
"amended_from" "sales_order_item",
], "production_plan",
"fields": [ "production_plan_item",
{ "product_bundle_item",
"fieldname": "item", "amended_from"
"fieldtype": "Section Break", ],
"options": "fa fa-gift" "fields": [
}, {
{ "fieldname": "item",
"fieldname": "naming_series", "fieldtype": "Section Break",
"fieldtype": "Select", "options": "fa fa-gift"
"label": "Series", },
"options": "MFG-WO-.YYYY.-", {
"print_hide": 1, "fieldname": "naming_series",
"reqd": 1, "fieldtype": "Select",
"set_only_once": 1 "label": "Series",
}, "options": "MFG-WO-.YYYY.-",
{ "print_hide": 1,
"default": "Draft", "reqd": 1,
"depends_on": "eval:!doc.__islocal", "set_only_once": 1
"fieldname": "status", },
"fieldtype": "Select", {
"label": "Status", "default": "Draft",
"no_copy": 1, "depends_on": "eval:!doc.__islocal",
"oldfieldname": "status", "fieldname": "status",
"oldfieldtype": "Select", "fieldtype": "Select",
"options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled", "label": "Status",
"read_only": 1, "no_copy": 1,
"reqd": 1, "oldfieldname": "status",
"search_index": 1 "oldfieldtype": "Select",
}, "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled",
{ "read_only": 1,
"fieldname": "production_item", "reqd": 1,
"fieldtype": "Link", "search_index": 1
"in_global_search": 1, },
"in_list_view": 1, {
"in_standard_filter": 1, "fieldname": "production_item",
"label": "Item To Manufacture", "fieldtype": "Link",
"oldfieldname": "production_item", "in_global_search": 1,
"oldfieldtype": "Link", "in_list_view": 1,
"options": "Item", "in_standard_filter": 1,
"reqd": 1 "label": "Item To Manufacture",
}, "oldfieldname": "production_item",
{ "oldfieldtype": "Link",
"depends_on": "eval:doc.production_item", "options": "Item",
"fieldname": "item_name", "reqd": 1
"fieldtype": "Data", },
"label": "Item Name", {
"read_only": 1 "depends_on": "eval:doc.production_item",
}, "fieldname": "item_name",
{ "fieldtype": "Data",
"fetch_from": "production_item.image", "label": "Item Name",
"fieldname": "image", "read_only": 1
"fieldtype": "Attach Image", },
"hidden": 1, {
"label": "Image", "fetch_from": "production_item.image",
"options": "image", "fieldname": "image",
"print_hide": 1, "fieldtype": "Attach Image",
"read_only": 1 "hidden": 1,
}, "label": "Image",
{ "options": "image",
"fieldname": "bom_no", "print_hide": 1,
"fieldtype": "Link", "read_only": 1
"label": "BOM No", },
"oldfieldname": "bom_no", {
"oldfieldtype": "Link", "fieldname": "bom_no",
"options": "BOM", "fieldtype": "Link",
"reqd": 1 "label": "BOM No",
}, "oldfieldname": "bom_no",
{ "oldfieldtype": "Link",
"default": "0", "options": "BOM",
"fieldname": "allow_alternative_item", "reqd": 1
"fieldtype": "Check", },
"label": "Allow Alternative Item" {
}, "default": "0",
{ "fieldname": "allow_alternative_item",
"default": "1", "fieldtype": "Check",
"description": "Plan material for sub-assemblies", "label": "Allow Alternative Item"
"fieldname": "use_multi_level_bom", },
"fieldtype": "Check", {
"label": "Use Multi-Level BOM", "default": "1",
"print_hide": 1 "description": "Plan material for sub-assemblies",
}, "fieldname": "use_multi_level_bom",
{ "fieldtype": "Check",
"default": "0", "label": "Use Multi-Level BOM",
"description": "Check if material transfer entry is not required", "print_hide": 1
"fieldname": "skip_transfer", },
"fieldtype": "Check", {
"label": "Skip Material Transfer to WIP Warehouse" "default": "0",
}, "description": "Check if material transfer entry is not required",
{ "fieldname": "skip_transfer",
"fieldname": "column_break1", "fieldtype": "Check",
"fieldtype": "Column Break", "label": "Skip Material Transfer to WIP Warehouse"
"oldfieldtype": "Column Break", },
"width": "50%" {
}, "fieldname": "column_break1",
{ "fieldtype": "Column Break",
"fieldname": "company", "oldfieldtype": "Column Break",
"fieldtype": "Link", "width": "50%"
"label": "Company", },
"oldfieldname": "company", {
"oldfieldtype": "Link", "fieldname": "company",
"options": "Company", "fieldtype": "Link",
"remember_last_selected_value": 1, "label": "Company",
"reqd": 1 "oldfieldname": "company",
}, "oldfieldtype": "Link",
{ "options": "Company",
"fieldname": "qty", "remember_last_selected_value": 1,
"fieldtype": "Float", "reqd": 1
"label": "Qty To Manufacture", },
"oldfieldname": "qty", {
"oldfieldtype": "Currency", "fieldname": "qty",
"reqd": 1 "fieldtype": "Float",
}, "label": "Qty To Manufacture",
{ "oldfieldname": "qty",
"default": "0", "oldfieldtype": "Currency",
"depends_on": "eval:doc.docstatus==1 && doc.skip_transfer==0", "reqd": 1
"fieldname": "material_transferred_for_manufacturing", },
"fieldtype": "Float", {
"label": "Material Transferred for Manufacturing", "default": "0",
"no_copy": 1, "depends_on": "eval:doc.docstatus==1 && doc.skip_transfer==0",
"read_only": 1 "fieldname": "material_transferred_for_manufacturing",
}, "fieldtype": "Float",
{ "label": "Material Transferred for Manufacturing",
"default": "0", "no_copy": 1,
"depends_on": "eval:doc.docstatus==1", "read_only": 1
"fieldname": "produced_qty", },
"fieldtype": "Float", {
"label": "Manufactured Qty", "default": "0",
"no_copy": 1, "depends_on": "eval:doc.docstatus==1",
"oldfieldname": "produced_qty", "fieldname": "produced_qty",
"oldfieldtype": "Currency", "fieldtype": "Float",
"read_only": 1 "label": "Manufactured Qty",
}, "no_copy": 1,
{ "oldfieldname": "produced_qty",
"allow_on_submit": 1, "oldfieldtype": "Currency",
"fieldname": "sales_order", "read_only": 1
"fieldtype": "Link", },
"in_global_search": 1, {
"label": "Sales Order", "allow_on_submit": 1,
"options": "Sales Order" "fieldname": "sales_order",
}, "fieldtype": "Link",
{ "in_global_search": 1,
"fieldname": "project", "label": "Sales Order",
"fieldtype": "Link", "options": "Sales Order"
"label": "Project", },
"oldfieldname": "project", {
"oldfieldtype": "Link", "fieldname": "project",
"options": "Project" "fieldtype": "Link",
}, "label": "Project",
{ "oldfieldname": "project",
"default": "0", "oldfieldtype": "Link",
"depends_on": "skip_transfer", "options": "Project"
"fieldname": "from_wip_warehouse", },
"fieldtype": "Check", {
"label": "Backflush Raw Materials From Work-in-Progress Warehouse" "default": "0",
}, "depends_on": "skip_transfer",
{ "fieldname": "from_wip_warehouse",
"fieldname": "warehouses", "fieldtype": "Check",
"fieldtype": "Section Break", "label": "Backflush Raw Materials From Work-in-Progress Warehouse"
"label": "Warehouses", },
"options": "fa fa-building" {
}, "fieldname": "warehouses",
{ "fieldtype": "Section Break",
"fieldname": "wip_warehouse", "label": "Warehouses",
"fieldtype": "Link", "options": "fa fa-building"
"label": "Work-in-Progress Warehouse", },
"options": "Warehouse" {
}, "fieldname": "wip_warehouse",
{ "fieldtype": "Link",
"fieldname": "fg_warehouse", "label": "Work-in-Progress Warehouse",
"fieldtype": "Link", "options": "Warehouse"
"label": "Target Warehouse", },
"options": "Warehouse" {
}, "fieldname": "fg_warehouse",
{ "fieldtype": "Link",
"fieldname": "column_break_12", "label": "Target Warehouse",
"fieldtype": "Column Break" "options": "Warehouse"
}, },
{ {
"fieldname": "scrap_warehouse", "fieldname": "column_break_12",
"fieldtype": "Link", "fieldtype": "Column Break"
"label": "Scrap Warehouse", },
"options": "Warehouse" {
}, "fieldname": "scrap_warehouse",
{ "fieldtype": "Link",
"fieldname": "required_items_section", "label": "Scrap Warehouse",
"fieldtype": "Section Break", "options": "Warehouse"
"label": "Required Items" },
}, {
{ "fieldname": "required_items_section",
"fieldname": "required_items", "fieldtype": "Section Break",
"fieldtype": "Table", "label": "Required Items"
"label": "Required Items", },
"no_copy": 1, {
"options": "Work Order Item", "fieldname": "required_items",
"print_hide": 1 "fieldtype": "Table",
}, "label": "Required Items",
{ "no_copy": 1,
"fieldname": "time", "options": "Work Order Item",
"fieldtype": "Section Break", "print_hide": 1
"label": "Time", },
"options": "fa fa-time" {
}, "fieldname": "time",
{ "fieldtype": "Section Break",
"allow_on_submit": 1, "label": "Time",
"default": "now", "options": "fa fa-time"
"fieldname": "planned_start_date", },
"fieldtype": "Datetime", {
"label": "Planned Start Date", "allow_on_submit": 1,
"reqd": 1 "default": "now",
}, "fieldname": "planned_start_date",
{ "fieldtype": "Datetime",
"fieldname": "actual_start_date", "label": "Planned Start Date",
"fieldtype": "Datetime", "reqd": 1
"label": "Actual Start Date", },
"read_only": 1 {
}, "fieldname": "actual_start_date",
{ "fieldtype": "Datetime",
"fieldname": "column_break_13", "label": "Actual Start Date",
"fieldtype": "Column Break" "read_only": 1
}, },
{ {
"fieldname": "planned_end_date", "fieldname": "column_break_13",
"fieldtype": "Datetime", "fieldtype": "Column Break"
"label": "Planned End Date", },
"no_copy": 1, {
"read_only": 1 "fieldname": "planned_end_date",
}, "fieldtype": "Datetime",
{ "label": "Planned End Date",
"fieldname": "actual_end_date", "no_copy": 1,
"fieldtype": "Datetime", "read_only": 1
"label": "Actual End Date", },
"read_only": 1 {
}, "fieldname": "actual_end_date",
{ "fieldtype": "Datetime",
"allow_on_submit": 1, "label": "Actual End Date",
"fieldname": "expected_delivery_date", "read_only": 1
"fieldtype": "Date", },
"label": "Expected Delivery Date" {
}, "allow_on_submit": 1,
{ "fieldname": "expected_delivery_date",
"fieldname": "operations_section", "fieldtype": "Date",
"fieldtype": "Section Break", "label": "Expected Delivery Date"
"label": "Operations", },
"options": "fa fa-wrench" {
}, "fieldname": "operations_section",
{ "fieldtype": "Section Break",
"default": "Work Order", "label": "Operations",
"depends_on": "operations", "options": "fa fa-wrench"
"fieldname": "transfer_material_against", },
"fieldtype": "Select", {
"label": "Transfer Material Against", "default": "Work Order",
"options": "\nWork Order\nJob Card" "depends_on": "operations",
}, "fieldname": "transfer_material_against",
{ "fieldtype": "Select",
"fieldname": "operations", "label": "Transfer Material Against",
"fieldtype": "Table", "options": "\nWork Order\nJob Card"
"label": "Operations", },
"options": "Work Order Operation", {
"read_only": 1 "fieldname": "operations",
}, "fieldtype": "Table",
{ "label": "Operations",
"depends_on": "operations", "options": "Work Order Operation",
"fieldname": "section_break_22", "read_only": 1
"fieldtype": "Section Break", },
"label": "Operation Cost" {
}, "depends_on": "operations",
{ "fieldname": "section_break_22",
"fieldname": "planned_operating_cost", "fieldtype": "Section Break",
"fieldtype": "Currency", "label": "Operation Cost"
"label": "Planned Operating Cost", },
"options": "Company:company:default_currency", {
"read_only": 1 "fieldname": "planned_operating_cost",
}, "fieldtype": "Currency",
{ "label": "Planned Operating Cost",
"fieldname": "actual_operating_cost", "options": "Company:company:default_currency",
"fieldtype": "Currency", "read_only": 1
"label": "Actual Operating Cost", },
"no_copy": 1, {
"options": "Company:company:default_currency", "fieldname": "actual_operating_cost",
"read_only": 1 "fieldtype": "Currency",
}, "label": "Actual Operating Cost",
{ "no_copy": 1,
"fieldname": "additional_operating_cost", "options": "Company:company:default_currency",
"fieldtype": "Currency", "read_only": 1
"label": "Additional Operating Cost", },
"no_copy": 1, {
"options": "Company:company:default_currency" "fieldname": "additional_operating_cost",
}, "fieldtype": "Currency",
{ "label": "Additional Operating Cost",
"fieldname": "column_break_24", "no_copy": 1,
"fieldtype": "Column Break" "options": "Company:company:default_currency"
}, },
{ {
"fieldname": "total_operating_cost", "fieldname": "column_break_24",
"fieldtype": "Currency", "fieldtype": "Column Break"
"label": "Total Operating Cost", },
"no_copy": 1, {
"options": "Company:company:default_currency", "fieldname": "total_operating_cost",
"read_only": 1 "fieldtype": "Currency",
}, "label": "Total Operating Cost",
{ "no_copy": 1,
"collapsible": 1, "options": "Company:company:default_currency",
"fieldname": "more_info", "read_only": 1
"fieldtype": "Section Break", },
"label": "More Information", {
"options": "fa fa-file-text" "collapsible": 1,
}, "fieldname": "more_info",
{ "fieldtype": "Section Break",
"fieldname": "description", "label": "More Information",
"fieldtype": "Small Text", "options": "fa fa-file-text"
"label": "Item Description", },
"read_only": 1 {
}, "fieldname": "description",
{ "fieldtype": "Small Text",
"fieldname": "stock_uom", "label": "Item Description",
"fieldtype": "Link", "read_only": 1
"label": "Stock UOM", },
"oldfieldname": "stock_uom", {
"oldfieldtype": "Data", "fieldname": "stock_uom",
"options": "UOM", "fieldtype": "Link",
"read_only": 1 "label": "Stock UOM",
}, "oldfieldname": "stock_uom",
{ "oldfieldtype": "Data",
"fieldname": "column_break2", "options": "UOM",
"fieldtype": "Column Break", "read_only": 1
"width": "50%" },
}, {
{ "fieldname": "column_break2",
"description": "Manufacture against Material Request", "fieldtype": "Column Break",
"fieldname": "material_request", "width": "50%"
"fieldtype": "Link", },
"label": "Material Request", {
"options": "Material Request" "description": "Manufacture against Material Request",
}, "fieldname": "material_request",
{ "fieldtype": "Link",
"fieldname": "material_request_item", "label": "Material Request",
"fieldtype": "Data", "options": "Material Request"
"hidden": 1, },
"label": "Material Request Item", {
"read_only": 1 "fieldname": "material_request_item",
}, "fieldtype": "Data",
{ "hidden": 1,
"fieldname": "sales_order_item", "label": "Material Request Item",
"fieldtype": "Data", "read_only": 1
"hidden": 1, },
"label": "Sales Order Item", {
"read_only": 1 "fieldname": "sales_order_item",
}, "fieldtype": "Data",
{ "hidden": 1,
"fieldname": "production_plan", "label": "Sales Order Item",
"fieldtype": "Link", "read_only": 1
"label": "Production Plan", },
"no_copy": 1, {
"options": "Production Plan", "fieldname": "production_plan",
"print_hide": 1, "fieldtype": "Link",
"read_only": 1 "label": "Production Plan",
}, "no_copy": 1,
{ "options": "Production Plan",
"fieldname": "production_plan_item", "print_hide": 1,
"fieldtype": "Data", "read_only": 1
"label": "Production Plan Item", },
"no_copy": 1, {
"print_hide": 1, "fieldname": "production_plan_item",
"read_only": 1 "fieldtype": "Data",
}, "label": "Production Plan Item",
{ "no_copy": 1,
"fieldname": "product_bundle_item", "print_hide": 1,
"fieldtype": "Link", "read_only": 1
"label": "Product Bundle Item", },
"no_copy": 1, {
"options": "Item", "fieldname": "product_bundle_item",
"print_hide": 1, "fieldtype": "Link",
"read_only": 1 "label": "Product Bundle Item",
}, "no_copy": 1,
{ "options": "Item",
"fieldname": "amended_from", "print_hide": 1,
"fieldtype": "Link", "read_only": 1
"ignore_user_permissions": 1, },
"label": "Amended From", {
"no_copy": 1, "fieldname": "amended_from",
"oldfieldname": "amended_from", "fieldtype": "Link",
"oldfieldtype": "Data", "ignore_user_permissions": 1,
"options": "Work Order", "label": "Amended From",
"read_only": 1 "no_copy": 1,
} "oldfieldname": "amended_from",
], "oldfieldtype": "Data",
"icon": "fa fa-cogs", "options": "Work Order",
"idx": 1, "read_only": 1
"image_field": "image", },
"is_submittable": 1, {
"modified": "2019-05-27 09:36:16.707719", "fieldname": "settings_section",
"modified_by": "Administrator", "fieldtype": "Section Break",
"module": "Manufacturing", "label": "Settings"
"name": "Work Order", },
"owner": "Administrator", {
"permissions": [ "fieldname": "column_break_18",
{ "fieldtype": "Column Break"
"amend": 1, },
"cancel": 1, {
"create": 1, "default": "1",
"delete": 1, "fieldname": "update_consumed_material_cost_in_project",
"email": 1, "fieldtype": "Check",
"export": 1, "label": "Update Consumed Material Cost In Project"
"import": 1, }
"print": 1, ],
"read": 1, "icon": "fa fa-cogs",
"report": 1, "idx": 1,
"role": "Manufacturing User", "image_field": "image",
"set_user_permissions": 1, "is_submittable": 1,
"share": 1, "modified": "2019-07-31 00:13:38.218277",
"submit": 1, "modified_by": "Administrator",
"write": 1 "module": "Manufacturing",
}, "name": "Work Order",
{ "owner": "Administrator",
"read": 1, "permissions": [
"report": 1, {
"role": "Stock User" "amend": 1,
} "cancel": 1,
], "create": 1,
"sort_order": "ASC", "delete": 1,
"title_field": "production_item", "email": 1,
"track_changes": 1, "export": 1,
"track_seen": 1 "import": 1,
} "print": 1,
"read": 1,
"report": 1,
"role": "Manufacturing User",
"set_user_permissions": 1,
"share": 1,
"submit": 1,
"write": 1
},
{
"read": 1,
"report": 1,
"role": "Stock User"
}
],
"sort_field": "modified",
"sort_order": "ASC",
"title_field": "production_item",
"track_changes": 1,
"track_seen": 1
}

View File

@ -0,0 +1,213 @@
frappe.pages['bom-comparison-tool'].on_page_load = function(wrapper) {
var page = frappe.ui.make_app_page({
parent: wrapper,
title: __('BOM Comparison Tool'),
single_column: true
});
new erpnext.BOMComparisonTool(page);
}
erpnext.BOMComparisonTool = class BOMComparisonTool {
constructor(page) {
this.page = page;
this.make_form();
}
make_form() {
this.form = new frappe.ui.FieldGroup({
fields: [
{
label: __('BOM 1'),
fieldname: 'name1',
fieldtype: 'Link',
options: 'BOM',
change: () => this.fetch_and_render()
},
{
fieldtype: 'Column Break'
},
{
label: __('BOM 2'),
fieldname: 'name2',
fieldtype: 'Link',
options: 'BOM',
change: () => this.fetch_and_render()
},
{
fieldtype: 'Section Break'
},
{
fieldtype: 'HTML',
fieldname: 'preview'
}
],
body: this.page.body
});
this.form.make();
}
fetch_and_render() {
let { name1, name2 } = this.form.get_values();
if (!(name1 && name2)) {
this.form.get_field('preview').html('');
return;
}
// set working state
this.form.get_field('preview').html(`
<div class="text-muted margin-top">
${__("Fetching...")}
</div>
`);
frappe.call('erpnext.manufacturing.doctype.bom.bom.get_bom_diff', {
bom1: name1,
bom2: name2
}).then(r => {
let diff = r.message;
frappe.model.with_doctype('BOM', () => {
this.render('BOM', name1, name2, diff);
});
});
}
render(doctype, name1, name2, diff) {
let change_html = (title, doctype, changed) => {
let values_changed = this.get_changed_values(doctype, changed)
.map(change => {
let [fieldname, value1, value2] = change;
return `
<tr>
<td>${frappe.meta.get_label(doctype, fieldname)}</td>
<td>${value1}</td>
<td>${value2}</td>
</tr>
`;
})
.join('');
return `
<h4 class="margin-top">${title}</h4>
<div>
<table class="table table-bordered">
<tr>
<th width="33%">${__('Field')}</th>
<th width="33%">${name1}</th>
<th width="33%">${name2}</th>
</tr>
${values_changed}
</table>
</div>
`;
}
let value_changes = change_html(__('Values Changed'), doctype, diff.changed);
let row_changes_by_fieldname = group_items(diff.row_changed, change => change[0]);
let table_changes = Object.keys(row_changes_by_fieldname).map(fieldname => {
let changes = row_changes_by_fieldname[fieldname];
let df = frappe.meta.get_docfield(doctype, fieldname);
let html = changes.map(change => {
let [fieldname,, item_code, changes] = change;
let df = frappe.meta.get_docfield(doctype, fieldname);
let child_doctype = df.options;
let values_changed = this.get_changed_values(child_doctype, changes);
return values_changed.map((change, i) => {
let [fieldname, value1, value2] = change;
let th = i === 0
? `<th rowspan="${values_changed.length}">${item_code}</th>`
: '';
return `
<tr>
${th}
<td>${frappe.meta.get_label(child_doctype, fieldname)}</td>
<td>${value1}</td>
<td>${value2}</td>
</tr>
`;
}).join('');
}).join('');
return `
<h4 class="margin-top">${__('Changes in {0}', [df.label])}</h4>
<table class="table table-bordered">
<tr>
<th width="25%">${__('Item Code')}</th>
<th width="25%">${__('Field')}</th>
<th width="25%">${name1}</th>
<th width="25%">${name2}</th>
</tr>
${html}
</table>
`;
}).join('');
let get_added_removed_html = (title, grouped_items) => {
return Object.keys(grouped_items).map(fieldname => {
let rows = grouped_items[fieldname];
let df = frappe.meta.get_docfield(doctype, fieldname);
let fields = frappe.meta.get_docfields(df.options)
.filter(df => df.in_list_view);
let html = rows.map(row => {
let [, doc] = row;
let cells = fields
.map(df => `<td>${doc[df.fieldname]}</td>`)
.join('');
return `<tr>${cells}</tr>`;
}).join('');
let header = fields.map(df => `<th>${df.label}</th>`).join('');
return `
<h4 class="margin-top">${$.format(title, [df.label])}</h4>
<table class="table table-bordered">
<tr>${header}</tr>
${html}
</table>
`;
}).join('');
};
let added_by_fieldname = group_items(diff.added, change => change[0]);
let removed_by_fieldname = group_items(diff.removed, change => change[0]);
let added_html = get_added_removed_html(__('Rows Added in {0}'), added_by_fieldname);
let removed_html = get_added_removed_html(__('Rows Removed in {0}'), removed_by_fieldname);
let html = `
${value_changes}
${table_changes}
${added_html}
${removed_html}
`;
this.form.get_field('preview').html(html);
}
get_changed_values(doctype, changed) {
return changed.filter(change => {
let [fieldname, value1, value2] = change;
if (!value1) value1 = '';
if (!value2) value2 = '';
if (value1 === value2) return false;
let df = frappe.meta.get_docfield(doctype, fieldname);
if (!df) return false;
if (df.hidden) return false;
return true;
});
}
};
function group_items(array, fn) {
return array.reduce((acc, item) => {
let key = fn(item);
acc[key] = acc[key] || [];
acc[key].push(item);
return acc;
}, {});
}

View File

@ -0,0 +1,30 @@
{
"content": null,
"creation": "2019-07-29 13:24:38.201981",
"docstatus": 0,
"doctype": "Page",
"idx": 0,
"modified": "2019-07-29 13:24:38.201981",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "bom-comparison-tool",
"owner": "Administrator",
"page_name": "BOM Comparison Tool",
"restrict_to_domain": "Manufacturing",
"roles": [
{
"role": "System Manager"
},
{
"role": "Manufacturing User"
},
{
"role": "Manufacturing Manager"
}
],
"script": null,
"standard": "Yes",
"style": null,
"system_page": 0,
"title": "BOM Comparison Tool"
}

View File

@ -60,7 +60,15 @@ $.extend(erpnext, {
var me = this; var me = this;
$btn.on("click", function() { $btn.on("click", function() {
me.show_serial_batch_selector(grid_row.frm, grid_row.doc); let callback = '';
let on_close = '';
if (grid_row.doc.serial_no) {
grid_row.doc.has_serial_no = true;
}
me.show_serial_batch_selector(grid_row.frm, grid_row.doc,
callback, on_close, true);
}); });
}, },
}); });

View File

@ -255,27 +255,44 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
}); });
return; return;
} else { } else {
var fields = [ const fields = [{
{fieldtype:'Table', fieldname: 'items', label: 'Items',
description: __('Select BOM and Qty for Production'), fieldtype: 'Table',
fields: [ fieldname: 'items',
{fieldtype:'Read Only', fieldname:'item_code', description: __('Select BOM and Qty for Production'),
label: __('Item Code'), in_list_view:1}, fields: [{
{fieldtype:'Link', fieldname:'bom', options: 'BOM', reqd: 1, fieldtype: 'Read Only',
label: __('Select BOM'), in_list_view:1, get_query: function(doc) { fieldname: 'item_code',
return {filters: {item: doc.item_code}}; label: __('Item Code'),
}}, in_list_view: 1
{fieldtype:'Float', fieldname:'pending_qty', reqd: 1, }, {
label: __('Qty'), in_list_view:1}, fieldtype: 'Link',
{fieldtype:'Data', fieldname:'sales_order_item', reqd: 1, fieldname: 'bom',
label: __('Sales Order Item'), hidden:1} options: 'BOM',
], reqd: 1,
data: r.message, label: __('Select BOM'),
get_data: function() { in_list_view: 1,
return r.message get_query: function (doc) {
return { filters: { item: doc.item_code } };
} }
}, {
fieldtype: 'Float',
fieldname: 'pending_qty',
reqd: 1,
label: __('Qty'),
in_list_view: 1
}, {
fieldtype: 'Data',
fieldname: 'sales_order_item',
reqd: 1,
label: __('Sales Order Item'),
hidden: 1
}],
data: r.message,
get_data: () => {
return r.message
} }
] }]
var d = new frappe.ui.Dialog({ var d = new frappe.ui.Dialog({
title: __('Select Items to Manufacture'), title: __('Select Items to Manufacture'),
fields: fields, fields: fields,

View File

@ -251,13 +251,12 @@ def _get_cart_quotation(party=None):
if quotation: if quotation:
qdoc = frappe.get_doc("Quotation", quotation[0].name) qdoc = frappe.get_doc("Quotation", quotation[0].name)
else: else:
[company, price_list] = frappe.db.get_value("Shopping Cart Settings", None, ["company", "price_list"]) company = frappe.db.get_value("Shopping Cart Settings", None, ["company"])
qdoc = frappe.get_doc({ qdoc = frappe.get_doc({
"doctype": "Quotation", "doctype": "Quotation",
"naming_series": get_shopping_cart_settings().quotation_series or "QTN-CART-", "naming_series": get_shopping_cart_settings().quotation_series or "QTN-CART-",
"quotation_to": party.doctype, "quotation_to": party.doctype,
"company": company, "company": company,
"selling_price_list": price_list,
"order_type": "Shopping Cart", "order_type": "Shopping Cart",
"status": "Draft", "status": "Draft",
"docstatus": 0, "docstatus": 0,

View File

@ -145,6 +145,10 @@ class StockEntry(StockController):
self.precision("transfer_qty", item)) self.precision("transfer_qty", item))
def update_cost_in_project(self): def update_cost_in_project(self):
if (self.work_order and not frappe.db.get_value("Work Order",
self.work_order, "update_consumed_material_cost_in_project")):
return
if self.project: if self.project:
amount = frappe.db.sql(""" select ifnull(sum(sed.amount), 0) amount = frappe.db.sql(""" select ifnull(sum(sed.amount), 0)
from from

3
package-lock.json generated
View File

@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}