Merge branch 'develop' into gross-profit-product-bundle
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js
index ba17a94..856b97d 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.js
+++ b/erpnext/accounts/report/gross_profit/gross_profit.js
@@ -36,5 +36,20 @@
"options": "Invoice\nItem Code\nItem Group\nBrand\nWarehouse\nCustomer\nCustomer Group\nTerritory\nSales Person\nProject",
"default": "Invoice"
},
- ]
+ ],
+ "tree": true,
+ "name_field": "parent",
+ "parent_field": "parent_invoice",
+ "initial_depth": 3,
+ "formatter": function(value, row, column, data, default_formatter) {
+ value = default_formatter(value, row, column, data);
+
+ if (data && data.indent == 0.0) {
+ value = $(`<span>${value}</span>`);
+ var $value = $(value).css("font-weight", "bold");
+ value = $value.wrap("<p></p>").parent().html();
+ }
+
+ return value;
+ },
}
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index c949d9b..8ea5e07 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -41,6 +41,34 @@
columns = get_columns(group_wise_columns, filters)
+ if filters.group_by == 'Invoice':
+ get_data_when_grouped_by_invoice(columns, gross_profit_data, filters, group_wise_columns, data)
+
+ else:
+ get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_columns, data)
+
+ return columns, data
+
+def get_data_when_grouped_by_invoice(columns, gross_profit_data, filters, group_wise_columns, data):
+ column_names = get_column_names()
+
+ # to display item as Item Code: Item Name
+ columns[0] = 'Sales Invoice:Link/Item:300'
+ # removing Item Code and Item Name columns
+ del columns[4:6]
+
+ for src in gross_profit_data.si_list:
+ row = frappe._dict()
+ row.indent = src.indent
+ row.parent_invoice = src.parent_invoice
+ row.currency = filters.currency
+
+ for col in group_wise_columns.get(scrub(filters.group_by)):
+ row[column_names[col]] = src.get(col)
+
+ data.append(row)
+
+def get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_columns, data):
for idx, src in enumerate(gross_profit_data.grouped_data):
row = []
for col in group_wise_columns.get(scrub(filters.group_by)):
@@ -51,8 +79,6 @@
row[0] = frappe.bold("Total")
data.append(row)
- return columns, data
-
def get_columns(group_wise_columns, filters):
columns = []
column_map = frappe._dict({
@@ -93,12 +119,38 @@
return columns
+def get_column_names():
+ return frappe._dict({
+ 'parent': 'sales_invoice',
+ 'customer': 'customer',
+ 'customer_group': 'customer_group',
+ 'posting_date': 'posting_date',
+ 'item_code': 'item_code',
+ 'item_name': 'item_name',
+ 'item_group': 'item_group',
+ 'brand': 'brand',
+ 'description': 'description',
+ 'warehouse': 'warehouse',
+ 'qty': 'qty',
+ 'base_rate': 'avg._selling_rate',
+ 'buying_rate': 'valuation_rate',
+ 'base_amount': 'selling_amount',
+ 'buying_amount': 'buying_amount',
+ 'gross_profit': 'gross_profit',
+ 'gross_profit_percent': 'gross_profit_%',
+ 'project': 'project'
+ })
+
class GrossProfitGenerator(object):
def __init__(self, filters=None):
self.data = []
self.average_buying_rate = {}
self.filters = frappe._dict(filters)
self.load_invoice_items()
+
+ if filters.group_by == 'Invoice':
+ self.group_items_by_invoice()
+
self.load_stock_ledger_entries()
self.load_product_bundle()
self.load_non_stock_items()
@@ -112,7 +164,12 @@
self.currency_precision = cint(frappe.db.get_default("currency_precision")) or 3
self.float_precision = cint(frappe.db.get_default("float_precision")) or 2
- for row in self.si_list:
+ grouped_by_invoice = True if self.filters.get("group_by") == "Invoice" else False
+
+ if grouped_by_invoice:
+ buying_amount = 0
+
+ for row in reversed(self.si_list):
if self.skip_row(row, self.product_bundles):
continue
@@ -134,12 +191,20 @@
row.buying_amount = flt(self.get_buying_amount(row, row.item_code),
self.currency_precision)
+ if grouped_by_invoice:
+ if row.indent == 1.0:
+ buying_amount += row.buying_amount
+ elif row.indent == 0.0:
+ row.buying_amount = buying_amount
+ buying_amount = 0
+
# get buying rate
- if row.qty:
- row.buying_rate = flt(row.buying_amount / row.qty, self.float_precision)
- row.base_rate = flt(row.base_amount / row.qty, self.float_precision)
+ if flt(row.qty):
+ row.buying_rate = flt(row.buying_amount / flt(row.qty), self.float_precision)
+ row.base_rate = flt(row.base_amount / flt(row.qty), self.float_precision)
else:
- row.buying_rate, row.base_rate = 0.0, 0.0
+ if self.is_not_invoice_row(row):
+ row.buying_rate, row.base_rate = 0.0, 0.0
# calculate gross profit
row.gross_profit = flt(row.base_amount - row.buying_amount, self.currency_precision)
@@ -171,7 +236,7 @@
if i==0:
new_row = row
else:
- new_row.qty += row.qty
+ new_row.qty += flt(row.qty)
new_row.buying_amount += flt(row.buying_amount, self.currency_precision)
new_row.base_amount += flt(row.base_amount, self.currency_precision)
new_row = self.set_average_rate(new_row)
@@ -183,16 +248,19 @@
and row.item_code in self.returned_invoices[row.parent]:
returned_item_rows = self.returned_invoices[row.parent][row.item_code]
for returned_item_row in returned_item_rows:
- row.qty += returned_item_row.qty
+ row.qty += flt(returned_item_row.qty)
row.base_amount += flt(returned_item_row.base_amount, self.currency_precision)
- row.buying_amount = flt(row.qty * row.buying_rate, self.currency_precision)
- if row.qty or row.base_amount:
+ row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision)
+ if (flt(row.qty) or row.base_amount) and self.is_not_invoice_row(row):
row = self.set_average_rate(row)
self.grouped_data.append(row)
self.add_to_totals(row)
self.set_average_gross_profit(self.totals)
self.grouped_data.append(self.totals)
+ def is_not_invoice_row(self, row):
+ return (self.filters.get("group_by") == "Invoice" and row.indent != 0.0) or self.filters.get("group_by") != "Invoice"
+
def set_average_rate(self, new_row):
self.set_average_gross_profit(new_row)
new_row.buying_rate = flt(new_row.buying_amount / new_row.qty, self.float_precision) if new_row.qty else 0
@@ -354,6 +422,109 @@
.format(conditions=conditions, sales_person_cols=sales_person_cols,
sales_team_table=sales_team_table, match_cond = get_match_cond('Sales Invoice')), self.filters, as_dict=1)
+ def group_items_by_invoice(self):
+ """
+ Turns list of Sales Invoice Items to a tree of Sales Invoices with their Items as children.
+ """
+
+ parents = []
+
+ for row in self.si_list:
+ if row.parent not in parents:
+ parents.append(row.parent)
+
+ parents_index = 0
+ for index, row in enumerate(self.si_list):
+ if parents_index < len(parents) and row.parent == parents[parents_index]:
+ invoice = self.get_invoice_row(row)
+ self.si_list.insert(index, invoice)
+ parents_index += 1
+
+ else:
+ # skipping the bundle items rows
+ if not row.indent:
+ row.indent = 1.0
+ row.parent_invoice = row.parent
+ row.parent = row.item_code
+
+ if frappe.db.exists('Product Bundle', row.item_code):
+ self.add_bundle_items(row, index)
+
+ def get_invoice_row(self, row):
+ return frappe._dict({
+ 'parent_invoice': "",
+ 'indent': 0.0,
+ 'parent': row.parent,
+ 'posting_date': row.posting_date,
+ 'posting_time': row.posting_time,
+ 'project': row.project,
+ 'update_stock': row.update_stock,
+ 'customer': row.customer,
+ 'customer_group': row.customer_group,
+ 'item_code': None,
+ 'item_name': None,
+ 'description': None,
+ 'warehouse': None,
+ 'item_group': None,
+ 'brand': None,
+ 'dn_detail': None,
+ 'delivery_note': None,
+ 'qty': None,
+ 'item_row': None,
+ 'is_return': row.is_return,
+ 'cost_center': row.cost_center,
+ 'base_net_amount': frappe.db.get_value('Sales Invoice', row.parent, 'base_net_total')
+ })
+
+ def add_bundle_items(self, product_bundle, index):
+ bundle_items = self.get_bundle_items(product_bundle)
+
+ for i, item in enumerate(bundle_items):
+ bundle_item = self.get_bundle_item_row(product_bundle, item)
+ self.si_list.insert((index+i+1), bundle_item)
+
+ def get_bundle_items(self, product_bundle):
+ return frappe.get_all(
+ 'Product Bundle Item',
+ filters = {
+ 'parent': product_bundle.item_code
+ },
+ fields = ['item_code', 'qty']
+ )
+
+ def get_bundle_item_row(self, product_bundle, item):
+ item_name, description, item_group, brand = self.get_bundle_item_details(item.item_code)
+
+ return frappe._dict({
+ 'parent_invoice': product_bundle.item_code,
+ 'indent': product_bundle.indent + 1,
+ 'parent': item.item_code,
+ 'posting_date': product_bundle.posting_date,
+ 'posting_time': product_bundle.posting_time,
+ 'project': product_bundle.project,
+ 'customer': product_bundle.customer,
+ 'customer_group': product_bundle.customer_group,
+ 'item_code': item.item_code,
+ 'item_name': item_name,
+ 'description': description,
+ 'warehouse': product_bundle.warehouse,
+ 'item_group': item_group,
+ 'brand': brand,
+ 'dn_detail': product_bundle.dn_detail,
+ 'delivery_note': product_bundle.delivery_note,
+ 'qty': (flt(product_bundle.qty) * flt(item.qty)),
+ 'item_row': None,
+ 'is_return': product_bundle.is_return,
+ 'cost_center': product_bundle.cost_center
+ })
+
+ def get_bundle_item_details(self, item_code):
+ return frappe.db.get_value(
+ 'Item',
+ item_code,
+ ['item_name', 'description', 'item_group', 'brand']
+ )
+
def load_stock_ledger_entries(self):
res = frappe.db.sql("""select item_code, voucher_type, voucher_no,
voucher_detail_no, stock_value, warehouse, actual_qty as qty
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 521432d..d6f0f0e 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -28,6 +28,9 @@
}
});
+ frm.set_df_property('packed_items', 'cannot_add_rows', true);
+ frm.set_df_property('packed_items', 'cannot_delete_rows', true);
+
},
company: function(frm) {
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index a55a0b7..e37d31a 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -61,6 +61,8 @@
"set_warehouse",
"items_section",
"items",
+ "bundle_items_section",
+ "packed_items",
"sb_last_purchase",
"total_qty",
"base_total",
@@ -144,9 +146,7 @@
{
"fieldname": "supplier_section",
"fieldtype": "Section Break",
- "options": "fa fa-user",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-user"
},
{
"allow_on_submit": 1,
@@ -156,9 +156,7 @@
"hidden": 1,
"label": "Title",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "naming_series",
@@ -170,9 +168,7 @@
"options": "PUR-ORD-.YYYY.-",
"print_hide": 1,
"reqd": 1,
- "set_only_once": 1,
- "show_days": 1,
- "show_seconds": 1
+ "set_only_once": 1
},
{
"bold": 1,
@@ -186,18 +182,14 @@
"options": "Supplier",
"print_hide": 1,
"reqd": 1,
- "search_index": 1,
- "show_days": 1,
- "show_seconds": 1
+ "search_index": 1
},
{
"depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))",
"description": "Fetch items based on Default Supplier.",
"fieldname": "get_items_from_open_material_requests",
"fieldtype": "Button",
- "label": "Get Items from Open Material Requests",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Get Items from Open Material Requests"
},
{
"bold": 1,
@@ -206,9 +198,7 @@
"fieldtype": "Data",
"in_global_search": 1,
"label": "Supplier Name",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "company",
@@ -220,17 +210,13 @@
"options": "Company",
"print_hide": 1,
"remember_last_selected_value": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"print_width": "50%",
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -242,35 +228,27 @@
"oldfieldname": "transaction_date",
"oldfieldtype": "Date",
"reqd": 1,
- "search_index": 1,
- "show_days": 1,
- "show_seconds": 1
+ "search_index": 1
},
{
"allow_on_submit": 1,
"fieldname": "schedule_date",
"fieldtype": "Date",
- "label": "Required By",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Required By"
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.docstatus===1",
"fieldname": "order_confirmation_no",
"fieldtype": "Data",
- "label": "Order Confirmation No",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Order Confirmation No"
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.order_confirmation_no",
"fieldname": "order_confirmation_date",
"fieldtype": "Date",
- "label": "Order Confirmation Date",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Order Confirmation Date"
},
{
"fieldname": "amended_from",
@@ -282,25 +260,19 @@
"oldfieldtype": "Data",
"options": "Purchase Order",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "drop_ship",
"fieldtype": "Section Break",
- "label": "Drop Ship",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Drop Ship"
},
{
"fieldname": "customer",
"fieldtype": "Link",
"label": "Customer",
"options": "Customer",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"bold": 1,
@@ -308,41 +280,31 @@
"fieldtype": "Data",
"label": "Customer Name",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_19",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "customer_contact_person",
"fieldtype": "Link",
"label": "Customer Contact",
- "options": "Contact",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Contact"
},
{
"fieldname": "customer_contact_display",
"fieldtype": "Small Text",
"hidden": 1,
"label": "Customer Contact",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "customer_contact_mobile",
"fieldtype": "Small Text",
"hidden": 1,
"label": "Customer Mobile No",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "customer_contact_email",
@@ -350,35 +312,27 @@
"hidden": 1,
"label": "Customer Contact Email",
"options": "Email",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
"fieldname": "section_addresses",
"fieldtype": "Section Break",
- "label": "Address and Contact",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Address and Contact"
},
{
"fieldname": "supplier_address",
"fieldtype": "Link",
"label": "Supplier Address",
"options": "Address",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "contact_person",
"fieldtype": "Link",
"label": "Supplier Contact",
"options": "Contact",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "address_display",
@@ -405,42 +359,32 @@
"label": "Contact Email",
"options": "Email",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "col_break_address",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "shipping_address",
"fieldtype": "Link",
"label": "Company Shipping Address",
"options": "Address",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "shipping_address_display",
"fieldtype": "Small Text",
"label": "Shipping Address Details",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"collapsible": 1,
"fieldname": "currency_and_price_list",
"fieldtype": "Section Break",
"label": "Currency and Price List",
- "options": "fa fa-tag",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-tag"
},
{
"fieldname": "currency",
@@ -450,9 +394,7 @@
"oldfieldtype": "Select",
"options": "Currency",
"print_hide": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "conversion_rate",
@@ -462,24 +404,18 @@
"oldfieldtype": "Currency",
"precision": "9",
"print_hide": 1,
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "cb_price_list",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "buying_price_list",
"fieldtype": "Link",
"label": "Price List",
"options": "Price List",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "price_list_currency",
@@ -487,18 +423,14 @@
"label": "Price List Currency",
"options": "Currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "plc_conversion_rate",
"fieldtype": "Float",
"label": "Price List Exchange Rate",
"precision": "9",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"default": "0",
@@ -507,9 +439,7 @@
"label": "Ignore Pricing Rule",
"no_copy": 1,
"permlevel": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "sec_warehouse",
@@ -522,15 +452,11 @@
"fieldtype": "Link",
"label": "Set Target Warehouse",
"options": "Warehouse",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "col_break_warehouse",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"default": "No",
@@ -539,35 +465,27 @@
"in_standard_filter": 1,
"label": "Supply Raw Materials",
"options": "No\nYes",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"depends_on": "eval:doc.is_subcontracted==\"Yes\"",
"fieldname": "supplier_warehouse",
"fieldtype": "Link",
"label": "Supplier Warehouse",
- "options": "Warehouse",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Warehouse"
},
{
"fieldname": "items_section",
"fieldtype": "Section Break",
"hide_border": 1,
"oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-shopping-cart"
},
{
"fieldname": "scan_barcode",
"fieldtype": "Data",
"label": "Scan Barcode",
- "options": "Barcode",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Barcode"
},
{
"allow_bulk_edit": 1,
@@ -577,34 +495,26 @@
"oldfieldname": "po_details",
"oldfieldtype": "Table",
"options": "Purchase Order Item",
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"collapsible": 1,
"fieldname": "section_break_48",
"fieldtype": "Section Break",
- "label": "Pricing Rules",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Pricing Rules"
},
{
"fieldname": "pricing_rules",
"fieldtype": "Table",
"label": "Purchase Order Pricing Rule",
"options": "Pricing Rule Detail",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"collapsible_depends_on": "supplied_items",
"fieldname": "raw_material_details",
"fieldtype": "Section Break",
- "label": "Raw Materials Supplied",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Raw Materials Supplied"
},
{
"fieldname": "supplied_items",
@@ -615,23 +525,17 @@
"oldfieldtype": "Table",
"options": "Purchase Order Item Supplied",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "sb_last_purchase",
- "fieldtype": "Section Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Section Break"
},
{
"fieldname": "total_qty",
"fieldtype": "Float",
"label": "Total Quantity",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "base_total",
@@ -639,9 +543,7 @@
"label": "Total (Company Currency)",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "base_net_total",
@@ -652,24 +554,18 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_26",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "total",
"fieldtype": "Currency",
"label": "Total",
"options": "currency",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "net_total",
@@ -679,26 +575,20 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "total_net_weight",
"fieldtype": "Float",
"label": "Total Net Weight",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "taxes_section",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-money"
},
{
"fieldname": "taxes_and_charges",
@@ -707,24 +597,18 @@
"oldfieldname": "purchase_other_charges",
"oldfieldtype": "Link",
"options": "Purchase Taxes and Charges Template",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break_50",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "shipping_rule",
"fieldtype": "Link",
"label": "Shipping Rule",
"options": "Shipping Rule",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "section_break_52",
@@ -737,17 +621,13 @@
"label": "Purchase Taxes and Charges",
"oldfieldname": "purchase_tax_details",
"oldfieldtype": "Table",
- "options": "Purchase Taxes and Charges",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Purchase Taxes and Charges"
},
{
"collapsible": 1,
"fieldname": "sec_tax_breakup",
"fieldtype": "Section Break",
- "label": "Tax Breakup",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Tax Breakup"
},
{
"fieldname": "other_charges_calculation",
@@ -756,18 +636,14 @@
"no_copy": 1,
"oldfieldtype": "HTML",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "totals",
"fieldtype": "Section Break",
"label": "Taxes and Charges",
"oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-money"
},
{
"depends_on": "base_taxes_and_charges_added",
@@ -778,9 +654,7 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "base_taxes_and_charges_deducted",
@@ -791,9 +665,7 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "base_total_taxes_and_charges",
@@ -805,15 +677,11 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_39",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"depends_on": "taxes_and_charges_added",
@@ -824,9 +692,7 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "taxes_and_charges_deducted",
@@ -837,9 +703,7 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "total_taxes_and_charges",
@@ -848,18 +712,14 @@
"label": "Total Taxes and Charges",
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "apply_discount_on",
"fieldname": "discount_section",
"fieldtype": "Section Break",
- "label": "Additional Discount",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Additional Discount"
},
{
"default": "Grand Total",
@@ -867,9 +727,7 @@
"fieldtype": "Select",
"label": "Apply Additional Discount On",
"options": "\nGrand Total\nNet Total",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "base_discount_amount",
@@ -877,32 +735,24 @@
"label": "Additional Discount Amount (Company Currency)",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_45",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "additional_discount_percentage",
"fieldtype": "Float",
"label": "Additional Discount Percentage",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "discount_amount",
"fieldtype": "Currency",
"label": "Additional Discount Amount",
"options": "currency",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "totals_section",
@@ -918,9 +768,7 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -930,9 +778,7 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"description": "In Words will be visible once you save the Purchase Order.",
@@ -943,9 +789,7 @@
"oldfieldname": "in_words",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "base_rounded_total",
@@ -955,16 +799,12 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break4",
"fieldtype": "Column Break",
- "oldfieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "oldfieldtype": "Column Break"
},
{
"fieldname": "grand_total",
@@ -974,9 +814,7 @@
"oldfieldname": "grand_total_import",
"oldfieldtype": "Currency",
"options": "currency",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "eval:!doc.disable_rounded_total",
@@ -986,26 +824,20 @@
"no_copy": 1,
"options": "currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "rounded_total",
"fieldtype": "Currency",
"label": "Rounded Total",
"options": "currency",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"default": "0",
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
- "label": "Disable Rounded Total",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Disable Rounded Total"
},
{
"fieldname": "in_words",
@@ -1015,9 +847,7 @@
"oldfieldname": "in_words_import",
"oldfieldtype": "Data",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "advance_paid",
@@ -1026,25 +856,19 @@
"no_copy": 1,
"options": "party_account_currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"collapsible": 1,
"fieldname": "payment_schedule_section",
"fieldtype": "Section Break",
- "label": "Payment Terms",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Payment Terms"
},
{
"fieldname": "payment_terms_template",
"fieldtype": "Link",
"label": "Payment Terms Template",
- "options": "Payment Terms Template",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Payment Terms Template"
},
{
"fieldname": "payment_schedule",
@@ -1052,9 +876,7 @@
"label": "Payment Schedule",
"no_copy": 1,
"options": "Payment Schedule",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
@@ -1063,9 +885,7 @@
"fieldtype": "Section Break",
"label": "Terms and Conditions",
"oldfieldtype": "Section Break",
- "options": "fa fa-legal",
- "show_days": 1,
- "show_seconds": 1
+ "options": "fa fa-legal"
},
{
"fieldname": "tc_name",
@@ -1074,27 +894,21 @@
"oldfieldname": "tc_name",
"oldfieldtype": "Link",
"options": "Terms and Conditions",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "terms",
"fieldtype": "Text Editor",
"label": "Terms and Conditions",
"oldfieldname": "terms",
- "oldfieldtype": "Text Editor",
- "show_days": 1,
- "show_seconds": 1
+ "oldfieldtype": "Text Editor"
},
{
"collapsible": 1,
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Information",
- "oldfieldtype": "Section Break",
- "show_days": 1,
- "show_seconds": 1
+ "oldfieldtype": "Section Break"
},
{
"default": "Draft",
@@ -1109,9 +923,7 @@
"print_hide": 1,
"read_only": 1,
"reqd": 1,
- "search_index": 1,
- "show_days": 1,
- "show_seconds": 1
+ "search_index": 1
},
{
"fieldname": "ref_sq",
@@ -1122,9 +934,7 @@
"oldfieldtype": "Data",
"options": "Supplier Quotation",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "party_account_currency",
@@ -1134,24 +944,18 @@
"no_copy": 1,
"options": "Currency",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "inter_company_order_reference",
"fieldtype": "Link",
"label": "Inter Company Order Reference",
"options": "Sales Order",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "column_break_74",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"depends_on": "eval:!doc.__islocal",
@@ -1161,9 +965,7 @@
"label": "% Received",
"no_copy": 1,
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"depends_on": "eval:!doc.__islocal",
@@ -1173,9 +975,7 @@
"label": "% Billed",
"no_copy": 1,
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"collapsible": 1,
@@ -1185,8 +985,6 @@
"oldfieldtype": "Column Break",
"print_hide": 1,
"print_width": "50%",
- "show_days": 1,
- "show_seconds": 1,
"width": "50%"
},
{
@@ -1197,9 +995,7 @@
"oldfieldname": "letter_head",
"oldfieldtype": "Select",
"options": "Letter Head",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -1211,15 +1007,11 @@
"oldfieldtype": "Link",
"options": "Print Heading",
"print_hide": 1,
- "report_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "report_hide": 1
},
{
"fieldname": "column_break_86",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"allow_on_submit": 1,
@@ -1227,25 +1019,19 @@
"fieldname": "group_same_items",
"fieldtype": "Check",
"label": "Group same items",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "language",
"fieldtype": "Data",
"label": "Print Language",
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"collapsible": 1,
"fieldname": "subscription_section",
"fieldtype": "Section Break",
- "label": "Subscription Section",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Subscription Section"
},
{
"allow_on_submit": 1,
@@ -1253,9 +1039,7 @@
"fieldtype": "Date",
"label": "From Date",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -1263,15 +1047,11 @@
"fieldtype": "Date",
"label": "To Date",
"no_copy": 1,
- "print_hide": 1,
- "show_days": 1,
- "show_seconds": 1
+ "print_hide": 1
},
{
"fieldname": "column_break_97",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "auto_repeat",
@@ -1280,35 +1060,27 @@
"no_copy": 1,
"options": "Auto Repeat",
"print_hide": 1,
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval: doc.auto_repeat",
"fieldname": "update_auto_repeat_reference",
"fieldtype": "Button",
- "label": "Update Auto Repeat Reference",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Update Auto Repeat Reference"
},
{
"fieldname": "tax_category",
"fieldtype": "Link",
"label": "Tax Category",
- "options": "Tax Category",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Tax Category"
},
{
"depends_on": "supplied_items",
"fieldname": "set_reserve_warehouse",
"fieldtype": "Link",
"label": "Set Reserve Warehouse",
- "options": "Warehouse",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Warehouse"
},
{
"collapsible": 1,
@@ -1318,9 +1090,7 @@
},
{
"fieldname": "column_break_75",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Column Break"
},
{
"fieldname": "billing_address",
@@ -1361,25 +1131,35 @@
"default": "0",
"fieldname": "apply_tds",
"fieldtype": "Check",
- "label": "Apply Tax Withholding Amount",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Apply Tax Withholding Amount"
},
{
"depends_on": "eval: doc.apply_tds",
"fieldname": "tax_withholding_category",
"fieldtype": "Link",
"label": "Tax Withholding Category",
- "options": "Tax Withholding Category",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Tax Withholding Category"
+ },
+ {
+ "fieldname": "packed_items",
+ "fieldtype": "Table",
+ "label": "Bundle Items",
+ "options": "Packed Item"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "packed_items",
+ "fieldname": "bundle_items_section",
+ "fieldtype": "Section Break",
+ "label": "Bundle Items",
+ "options": "fa fa-suitcase"
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-17 20:16:12.737743",
+ "modified": "2021-08-27 02:18:07.342249",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index ca3bd90..e7d422d 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -67,6 +67,9 @@
self.set_received_qty_for_drop_ship_items()
validate_inter_company_party(self.doctype, self.supplier, self.company, self.inter_company_order_reference)
+ from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
+ make_packing_list(self)
+
def validate_with_previous_doc(self):
super(PurchaseOrder, self).validate_with_previous_doc({
"Supplier Quotation": {
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index 132dd17..01526fc 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -488,7 +488,6 @@
"no_copy": 1,
"options": "Sales Order",
"print_hide": 1,
- "read_only": 1,
"search_index": 1
},
{
@@ -836,7 +835,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-06-28 19:22:22.715365",
+ "modified": "2021-08-27 01:35:37.755413",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 1223449..0e1a915 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -18,6 +18,8 @@
}
});
+ frm.set_df_property('packed_items', 'cannot_add_rows', true);
+ frm.set_df_property('packed_items', 'cannot_delete_rows', true);
},
refresh: function(frm) {
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index 3eba62b..6bfb2c2 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -43,6 +43,8 @@
"ignore_pricing_rule",
"items_section",
"items",
+ "bundle_items_section",
+ "packed_items",
"pricing_rule_details",
"pricing_rules",
"sec_break23",
@@ -926,6 +928,20 @@
"label": "Lost Reasons",
"options": "Quotation Lost Reason Detail",
"read_only": 1
+ },
+ {
+ "fieldname": "packed_items",
+ "fieldtype": "Table",
+ "label": "Bundle Items",
+ "options": "Packed Item"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "packed_items",
+ "fieldname": "bundle_items_section",
+ "fieldtype": "Section Break",
+ "label": "Bundle Items",
+ "options": "fa fa-suitcase"
}
],
"icon": "fa fa-shopping-cart",
@@ -933,7 +949,7 @@
"is_submittable": 1,
"links": [],
"max_attachments": 1,
- "modified": "2020-10-30 13:58:59.212060",
+ "modified": "2021-08-27 02:23:33.460607",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index e4f8a47..6cd03dd 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -31,6 +31,9 @@
if self.items:
self.with_items = 1
+ from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
+ make_packing_list(self)
+
def validate_valid_till(self):
if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date):
frappe.throw(_("Valid till date cannot be before transaction date"))
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 38ea5c8..6c4a403 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -55,6 +55,8 @@
"items_section",
"scan_barcode",
"items",
+ "packing_list",
+ "packed_items",
"pricing_rule_details",
"pricing_rules",
"section_break_31",
@@ -101,8 +103,6 @@
"in_words",
"advance_paid",
"disable_rounded_total",
- "packing_list",
- "packed_items",
"payment_schedule_section",
"payment_terms_template",
"payment_schedule",
@@ -1511,7 +1511,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-17 20:15:26.531553",
+ "modified": "2021-08-27 02:45:54.968867",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index 717fd9b..531cf65 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -23,6 +23,7 @@
"maintain_same_rate_action",
"editable_price_list_rate",
"validate_selling_price",
+ "editable_bundle_item_rates",
"sales_transactions_settings_section",
"so_required",
"dn_required",
@@ -191,6 +192,12 @@
"fieldname": "sales_transactions_settings_section",
"fieldtype": "Section Break",
"label": "Transaction Settings"
+ },
+ {
+ "default": "0",
+ "fieldname": "editable_bundle_item_rates",
+ "fieldtype": "Check",
+ "label": "Calculate Product Bundle Price based on Child Items' Rates"
}
],
"icon": "fa fa-cog",
@@ -198,7 +205,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-08-06 22:25:50.119458",
+ "modified": "2021-08-24 22:08:34.470897",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py
index b219e7e..b54559a 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.py
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.py
@@ -15,6 +15,7 @@
class SellingSettings(Document):
def on_update(self):
self.toggle_hide_tax_id()
+ self.toggle_editable_rate_for_bundle_items()
def validate(self):
for key in ["cust_master_name", "campaign_naming_by", "customer_group", "territory",
@@ -33,6 +34,11 @@
make_property_setter(doctype, "tax_id", "hidden", self.hide_tax_id, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "tax_id", "print_hide", self.hide_tax_id, "Check", validate_fields_for_doctype=False)
+ def toggle_editable_rate_for_bundle_items(self):
+ editable_bundle_item_rates = cint(self.editable_bundle_item_rates)
+
+ make_property_setter("Packed Item", "rate", "read_only", not(editable_bundle_item_rates), "Check", validate_fields_for_doctype=False)
+
def set_default_customer_group_and_territory(self):
if not self.customer_group:
self.customer_group = get_root_of('Customer Group')
diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json
index bb396e8..6f0f527 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.json
+++ b/erpnext/stock/doctype/packed_item/packed_item.json
@@ -16,6 +16,7 @@
"conversion_factor",
"column_break_9",
"qty",
+ "rate",
"uom",
"section_break_9",
"serial_no",
@@ -215,13 +216,22 @@
"fieldname": "conversion_factor",
"fieldtype": "Float",
"label": "Conversion Factor"
+ },
+ {
+ "fetch_from": "item_code.valuation_rate",
+ "fetch_if_empty": 1,
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Rate",
+ "print_hide": 1
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-05-26 07:08:05.111385",
+ "modified": "2021-08-27 01:20:55.308822",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index 4ab71bd..4f1a675 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -86,6 +86,9 @@
cleanup_packing_list(doc, parent_items)
+ if frappe.db.get_single_value("Selling Settings", "editable_bundle_item_rates"):
+ update_product_bundle_price(doc, parent_items)
+
def cleanup_packing_list(doc, parent_items):
"""Remove all those child items which are no longer present in main item table"""
delete_list = []
@@ -103,6 +106,40 @@
if d not in delete_list:
doc.append("packed_items", d)
+def update_product_bundle_price(doc, parent_items):
+ """Updates the prices of Product Bundles based on the rates of the Items in the bundle."""
+
+ if not doc.get('items'):
+ return
+
+ parent_items_index = 0
+ bundle_price = 0
+
+ for bundle_item in doc.get("packed_items"):
+ if parent_items[parent_items_index][0] == bundle_item.parent_item:
+ bundle_item_rate = bundle_item.rate if bundle_item.rate else 0
+ bundle_price += bundle_item.qty * bundle_item_rate
+ else:
+ update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price)
+
+ bundle_price = 0
+ parent_items_index += 1
+
+ # for the last product bundle
+ if doc.get("packed_items"):
+ update_parent_item_price(doc, parent_items[parent_items_index][0], bundle_price)
+
+def update_parent_item_price(doc, parent_item_code, bundle_price):
+ parent_item_doc = doc.get('items', {'item_code': parent_item_code})[0]
+
+ current_parent_item_price = parent_item_doc.amount
+ if current_parent_item_price != bundle_price:
+ parent_item_doc.amount = bundle_price
+ update_parent_item_rate(parent_item_doc, bundle_price)
+
+def update_parent_item_rate(parent_item_doc, bundle_price):
+ parent_item_doc.rate = bundle_price/parent_item_doc.qty
+
@frappe.whitelist()
def get_items_from_product_bundle(args):
args = json.loads(args)