Merge pull request #3584 from neilLasrado/develop

Minor fixes
This commit is contained in:
Nabin Hait 2015-07-13 12:49:46 +05:30
commit 1a0713e4b9
57 changed files with 170 additions and 154 deletions

View File

@ -369,15 +369,15 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
}
cur_frm.cscript.income_account = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "income_account");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "income_account");
}
cur_frm.cscript.expense_account = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "expense_account");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "expense_account");
}
cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "cost_center");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
}
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {

View File

@ -322,9 +322,9 @@
"read_only": 0
},
{
"fieldname": "sales_bom_help",
"fieldname": "product_bundle_help",
"fieldtype": "HTML",
"label": "Sales BOM Help",
"label": "Product Bundle Help",
"permlevel": 0,
"print_hide": 1,
"read_only": 0
@ -1252,7 +1252,7 @@
],
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"is_submittable": 1,
"modified": "2015-07-09 17:33:28.583808",
"modified_by": "Administrator",
"module": "Accounts",

View File

@ -74,9 +74,17 @@ def set_contact_details(out, party, party_type):
{party_type.lower(): party.name, "is_primary_contact":1}, "name")
if not out.contact_person:
return
out.update(get_contact_details(out.contact_person))
out.update({
"contact_person": None,
"contact_display": None,
"contact_email": None,
"contact_mobile": None,
"contact_phone": None,
"contact_designation": None,
"contact_department": None
})
else:
out.update(get_contact_details(out.contact_person))
def set_other_values(out, party, party_type):
# copy

View File

@ -86,23 +86,23 @@ class GrossProfitGenerator(object):
self.filters = frappe._dict(filters)
self.load_invoice_items()
self.load_stock_ledger_entries()
self.load_sales_bom()
self.load_product_bundle()
self.load_non_stock_items()
self.process()
def process(self):
self.grouped = {}
for row in self.si_list:
if self.skip_row(row, self.sales_boms):
if self.skip_row(row, self.product_bundles):
continue
row.base_amount = flt(row.base_net_amount)
sales_boms = self.sales_boms.get(row.parenttype, {}).get(row.parent, frappe._dict())
product_bundles = self.product_bundles.get(row.parenttype, {}).get(row.parent, frappe._dict())
# get buying amount
if row.item_code in sales_boms:
row.buying_amount = self.get_buying_amount_from_sales_bom(row, sales_boms[row.item_code])
if row.item_code in product_bundles:
row.buying_amount = self.get_buying_amount_from_product_bundle(row, product_bundles[row.item_code])
else:
row.buying_amount = self.get_buying_amount(row, row.item_code)
@ -152,13 +152,13 @@ class GrossProfitGenerator(object):
self.grouped_data.append(new_row)
def skip_row(self, row, sales_boms):
def skip_row(self, row, product_bundles):
if self.filters.get("group_by") != "Invoice" and not row.get(scrub(self.filters.get("group_by"))):
return True
def get_buying_amount_from_sales_bom(self, row, sales_bom):
def get_buying_amount_from_product_bundle(self, row, product_bundle):
buying_amount = 0.0
for bom_item in sales_bom:
for bom_item in product_bundle:
if bom_item.get("parent_detail_docname")==row.item_row:
buying_amount += self.get_buying_amount(row, bom_item.item_code)
@ -246,13 +246,13 @@ class GrossProfitGenerator(object):
self.sle[(r.item_code, r.warehouse)].append(r)
def load_sales_bom(self):
self.sales_boms = {}
def load_product_bundle(self):
self.product_bundles = {}
for d in frappe.db.sql("""select parenttype, parent, parent_item,
item_code, warehouse, -1*qty as total_qty, parent_detail_docname
from `tabPacked Item` where docstatus=1""", as_dict=True):
self.sales_boms.setdefault(d.parenttype, frappe._dict()).setdefault(d.parent,
self.product_bundles.setdefault(d.parenttype, frappe._dict()).setdefault(d.parent,
frappe._dict()).setdefault(d.parent_item, []).append(d)
def load_non_stock_items(self):

View File

@ -70,10 +70,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
erpnext.utils.get_address_display(this.frm);
},
contact_person: function() {
erpnext.utils.get_contact_details(this.frm);
},
buying_price_list: function() {
this.apply_price_list();
},

View File

@ -249,7 +249,7 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
cur_frm.cscript.schedule_date = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "schedule_date");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "schedule_date");
}
frappe.provide("erpnext.buying");

View File

@ -60,7 +60,7 @@ def get_data():
"items": [
{
"type": "doctype",
"name": "Salary Manager",
"name": "Process Payroll",
"label": _("Process Payroll"),
"description":_("Generate Salary Slips"),
"hide_count": True

View File

@ -144,7 +144,7 @@ def get_data():
},
{
"type": "doctype",
"name": "Sales BOM",
"name": "Product Bundle",
"description": _("Bundle items at time of sale."),
},
{

View File

@ -83,6 +83,11 @@ def get_data():
"name": "Stock UOM Replace Utility",
"description": _("Change UOM for an Item."),
},
{
"type": "doctype",
"name": "Manage Variants",
"description": _("Manage Item Variants."),
},
]
},
{

View File

@ -171,6 +171,9 @@ class SellingController(StockController):
frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx))
if self.doctype == "Sales Order":
if (frappe.db.get_value("Item", d.item_code, "is_stock_item") == 'Yes' or
self.has_product_bundle(d.item_code)) and not d.warehouse:
frappe.throw(_("Reserved Warehouse required for stock Item {0} in row {1}").format(d.item_code, d.idx))
reserved_warehouse = d.warehouse
if flt(d.qty) > flt(d.delivered_qty):
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
@ -188,7 +191,7 @@ class SellingController(StockController):
else:
reserved_qty_for_main_item = -flt(d.qty)
if self.has_sales_bom(d.item_code):
if self.has_product_bundle(d.item_code):
for p in self.get("packed_items"):
if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
# the packing details table's qty is already multiplied with parent's qty
@ -218,8 +221,8 @@ class SellingController(StockController):
}))
return il
def has_sales_bom(self, item_code):
return frappe.db.sql("""select name from `tabSales BOM`
def has_product_bundle(self, item_code):
return frappe.db.sql("""select name from `tabProduct Bundle`
where new_item_code=%s and docstatus != 2""", item_code)
def get_already_delivered_qty(self, dn, so, so_detail):

View File

@ -59,6 +59,6 @@ cur_frm.cscript.make_jv = function(doc, dt, dn) {
}
frappe.ui.form.on("Salary Manager", "refresh", function(frm) {
frappe.ui.form.on("Process Payroll", "refresh", function(frm) {
frm.disable_save();
});

View File

@ -154,10 +154,10 @@
"icon": "icon-cog",
"idx": 1,
"issingle": 1,
"modified": "2015-06-05 11:33:00.152362",
"modified": "2015-07-07 07:16:02.380839",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Manager",
"name": "Process Payroll",
"owner": "Administrator",
"permissions": [
{

View File

@ -8,7 +8,7 @@ from frappe import _
from frappe.model.document import Document
class SalaryManager(Document):
class ProcessPayroll(Document):
def get_emp_list(self):
"""

View File

@ -1 +0,0 @@
Tool to issue monthly Salary Slips to all Employees.

View File

@ -1,21 +0,0 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Frappe Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
from frappe import ValidationError
class SalarySlipExistsError(ValidationError): pass

View File

@ -49,7 +49,7 @@ class SalarySlip(TransactionBase):
if not self.month:
self.month = "%02d" % getdate(nowdate()).month
m = frappe.get_doc('Salary Manager').get_month_details(self.fiscal_year, self.month)
m = frappe.get_doc('Process Payroll').get_month_details(self.fiscal_year, self.month)
holidays = self.get_holidays_for_employee(m)
if not cint(frappe.db.get_value("HR Settings", "HR Settings",

View File

@ -31,7 +31,7 @@
"fieldname": "d_depends_on_lwp",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Depends on LWP",
"label": "Depends on Leave Without Pay",
"permlevel": 0,
"print_hide": 1
},
@ -46,7 +46,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2015-03-03 12:41:04.505378",
"modified": "2015-07-07 07:13:11.919941",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Slip Deduction",

View File

@ -31,7 +31,7 @@
"fieldname": "e_depends_on_lwp",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Depends on LWP",
"label": "Depends on Leave Without Pay",
"permlevel": 0,
"print_hide": 1
},
@ -46,7 +46,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2015-03-03 12:42:49.087748",
"modified": "2015-07-07 07:13:24.833881",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Slip Earning",

View File

@ -317,7 +317,7 @@ class ProductionOrder(Document):
def validate_delivery_date(self):
if self.planned_start_date and self.expected_delivery_date \
and getdate(self.expected_delivery_date) < getdate(self.planned_start_date):
frappe.throw(_("Expected Delivery Date must be greater than Planned Start Date."))
frappe.msgprint(_("Expected Delivery Date is lesser than Planned Start Date."))
def delete_time_logs(self):
for time_log in frappe.get_all("Time Log", ["name"], {"production_order": self.name}):

View File

@ -42,6 +42,15 @@
"reqd": 1,
"width": "100px"
},
{
"default": "",
"fieldname": "planned_start_date",
"fieldtype": "Datetime",
"label": "Planned Start Date",
"permlevel": 0,
"precision": "",
"reqd": 1
},
{
"fieldname": "sales_order",
"fieldtype": "Link",
@ -104,7 +113,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2015-02-19 01:07:00.936590",
"modified": "2015-07-08 07:12:11.211808",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan Item",

View File

@ -1,6 +1,8 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.require("assets/erpnext/js/utils.js");
cur_frm.cscript.onload = function(doc, cdt, cdn) {
cur_frm.set_value("company", frappe.defaults.get_user_default("company"))
cur_frm.set_value("use_multi_level_bom", 1)
@ -72,3 +74,7 @@ cur_frm.fields_dict.customer.get_query = function(doc,cdt,cdn) {
cur_frm.fields_dict.sales_orders.grid.get_field("customer").get_query =
cur_frm.fields_dict.customer.get_query;
cur_frm.cscript.planned_start_date = function(doc, cdt, cdn) {
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "planned_start_date");
}

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt, cint, nowdate, now, add_days, comma_and
from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and
from frappe import msgprint, _
@ -211,8 +211,6 @@ class ProductionPlanningTool(Document):
for key in items:
pro = frappe.new_doc("Production Order")
pro.update(items[key])
pro.planned_start_date = now()
pro.set_production_order_operations()
frappe.flags.mute_messages = True

View File

@ -172,4 +172,6 @@ erpnext.patches.v5_0.item_variants
erpnext.patches.v5_0.update_item_desc_in_invoice
erpnext.patches.v5_1.fix_against_account
erpnext.patches.v5_1.fix_credit_days_based_on
erpnext.patches.v5_1.track_operations
erpnext.patches.v5_1.track_operations
erpnext.patches.v5_1.sales_bom_rename
execute:frappe.rename_doc("DocType", "Salary Manager", "Process Payroll", force=True)

View File

@ -0,0 +1,12 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
tables = frappe.db.sql_list("show tables")
for old_dt, new_dt in [["Sales BOM Item", "Product Bundle Item"],
["Sales BOM", "Product Bundle"]]:
if "tab"+new_dt not in tables:
frappe.rename_doc("DocType", old_dt, new_dt, force=True)

View File

@ -70,16 +70,5 @@ erpnext.stock.StockController = frappe.ui.form.Controller.extend({
frappe.set_route("query-report", "General Ledger");
}, "icon-table");
}
},
copy_account_in_all_row: function(doc, dt, dn, fieldname) {
var d = locals[dt][dn];
if(d[fieldname]){
var cl = doc["items"] || [];
for(var i = 0; i < cl.length; i++) {
if(!cl[i][fieldname]) cl[i][fieldname] = d[fieldname];
}
}
refresh_field("items");
}
});

View File

@ -282,6 +282,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
get_company_currency: function() {
return erpnext.get_currency(this.frm.doc.company);
},
contact_person: function() {
erpnext.utils.get_contact_details(this.frm);
},
currency: function() {
var me = this;

View File

@ -46,7 +46,7 @@ erpnext.feature_setup.feature_dict = {
'Purchase Invoice': {'items':['brand']},
'Quotation': {'items':['brand']},
'Sales Invoice': {'items':['brand']},
'Sales BOM': {'fields':['new_item_brand']},
'Product Bundle': {'fields':['new_item_brand']},
'Sales Order': {'items':['brand']},
'Serial No': {'fields':['brand']}
},
@ -95,7 +95,7 @@ erpnext.feature_setup.feature_dict = {
'Purchase Voucher': {'items':['item_group']},
'Quotation': {'items':['item_group']},
'Sales Invoice': {'items':['item_group']},
'Sales BOM': {'fields':['serial_no']},
'Product Bundle': {'fields':['serial_no']},
'Sales Order': {'items':['item_group']},
'Serial No': {'fields':['item_group']},
'Sales Partner': {'targets':['item_group']},
@ -129,7 +129,7 @@ erpnext.feature_setup.feature_dict = {
'base_total', 'base_net_total', 'base_discount_amount', 'base_total_taxes_and_charges'],
'items': ['base_price_list_rate','base_amount','base_rate', 'base_net_rate', 'base_net_amount']
},
'Sales BOM': {'fields':['currency']},
'Product Bundle': {'fields':['currency']},
'Sales Order': {
'fields': ['conversion_rate','currency','base_grand_total','base_in_words','base_rounded_total',
'base_total', 'base_net_total', 'base_discount_amount', 'base_total_taxes_and_charges'],

View File

@ -131,6 +131,17 @@ $.extend(erpnext.utils, {
}
);
}
},
copy_value_in_all_row: function(doc, dt, dn, table_fieldname, fieldname) {
var d = locals[dt][dn];
if(d[fieldname]){
var cl = doc[table_fieldname] || [];
for(var i = 0; i < cl.length; i++) {
if(!cl[i][fieldname]) cl[i][fieldname] = d[fieldname];
}
}
refresh_field(table_fieldname);
}
});

View File

@ -7,10 +7,10 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.fields_dict.new_item_code.get_query = function() {
return{
query: "erpnext.selling.doctype.sales_bom.sales_bom.get_new_item_code"
query: "erpnext.selling.doctype.product_bundle.product_bundle.get_new_item_code"
}
}
cur_frm.fields_dict.new_item_code.query_description = __('Please select Item where "Is Stock Item" is "No" and "Is Sales Item" is "Yes" and there is no other Sales BOM');
cur_frm.fields_dict.new_item_code.query_description = __('Please select Item where "Is Stock Item" is "No" and "Is Sales Item" is "Yes" and there is no other Product Bundle');
cur_frm.cscript.item_code = function(doc, dt, dn) {
var d = locals[dt][dn];

View File

@ -1,7 +1,7 @@
{
"allow_import": 1,
"creation": "2013-06-20 11:53:21",
"description": "Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**. \n\nThe package **Item** will have \"Is Stock Item\" as \"No\" and \"Is Sales Item\" as \"Yes\".\n\nFor Example: If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Sales BOM Item.\n\nNote: BOM = Bill of Materials",
"description": "Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**. \n\nThe package **Item** will have \"Is Stock Item\" as \"No\" and \"Is Sales Item\" as \"Yes\".\n\nFor Example: If you are selling Laptops and Backpacks separately and have a special price if the customer buys both, then the Laptop + Backpack will be a new Product Bundle Item.\n\nNote: BOM = Bill of Materials",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
@ -38,7 +38,7 @@
"label": "Items",
"oldfieldname": "sales_bom_items",
"oldfieldtype": "Table",
"options": "Sales BOM Item",
"options": "Product Bundle Item",
"permlevel": 0,
"reqd": 1
}
@ -46,10 +46,10 @@
"icon": "icon-sitemap",
"idx": 1,
"is_submittable": 0,
"modified": "2015-02-20 05:05:03.719573",
"modified": "2015-07-06 06:11:10.534423",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales BOM",
"name": "Product Bundle",
"owner": "Administrator",
"permissions": [
{

View File

@ -8,9 +8,7 @@ from frappe import _
from frappe.model.document import Document
class SalesBOM(Document):
class ProductBundle(Document):
def autoname(self):
self.name = self.new_item_code
@ -39,7 +37,7 @@ def get_new_item_code(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select name, item_name, description from tabItem
where is_stock_item="No" and is_sales_item="Yes"
and name not in (select name from `tabSales BOM`) and %s like %s
and name not in (select name from `tabProduct Bundle`) and %s like %s
%s limit %s, %s""" % (searchfield, "%s",
get_match_cond(doctype),"%s", "%s"),
("%%%s%%" % txt, start, page_len))

View File

@ -1,7 +1,8 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
test_records = frappe.get_test_records('Sales BOM')
test_records = frappe.get_test_records('Product Bundle')

View File

@ -1,16 +1,16 @@
[
{
"doctype": "Sales BOM",
"new_item_code": "_Test Sales BOM Item",
"doctype": "Product Bundle",
"new_item_code": "_Test Product Bundle Item",
"items": [
{
"doctype": "Sales BOM Item",
"doctype": "Product Bundle Item",
"item_code": "_Test Item",
"parentfield": "items",
"qty": 5.0
},
{
"doctype": "Sales BOM Item",
"doctype": "Product Bundle Item",
"item_code": "_Test Item Home Desktop 100",
"parentfield": "items",
"qty": 2.0

View File

@ -1,5 +1,5 @@
{
"creation": "2013-05-23 16:55:51.000000",
"creation": "2013-05-23 16:55:51",
"docstatus": 0,
"doctype": "DocType",
"fields": [
@ -60,9 +60,10 @@
],
"idx": 1,
"istable": 1,
"modified": "2013-12-20 19:21:38.000000",
"modified": "2015-07-06 06:05:18.854360",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales BOM Item",
"owner": "Administrator"
"name": "Product Bundle Item",
"owner": "Administrator",
"permissions": []
}

View File

@ -1,10 +1,10 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class SalesBOMItem(Document):
pass
class ProductBundleItem(Document):
pass

View File

@ -6,7 +6,7 @@ import frappe, json
from frappe.utils import flt
import unittest
test_dependencies = ["Sales BOM"]
test_dependencies = ["Product Bundle"]
class TestQuotation(unittest.TestCase):
def test_make_sales_order(self):

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -125,7 +125,7 @@ class TestSalesOrder(unittest.TestCase):
existing_reserved_qty_item1 = get_reserved_qty("_Test Item")
existing_reserved_qty_item2 = get_reserved_qty("_Test Item Home Desktop 100")
so = make_sales_order(item_code="_Test Sales BOM Item")
so = make_sales_order(item_code="_Test Product Bundle Item")
self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1 + 50)
self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),
@ -164,12 +164,12 @@ class TestSalesOrder(unittest.TestCase):
def test_reserved_qty_for_over_delivery_with_packing_list(self):
# set over-delivery tolerance
frappe.db.set_value('Item', "_Test Sales BOM Item", 'tolerance', 50)
frappe.db.set_value('Item', "_Test Product Bundle Item", 'tolerance', 50)
existing_reserved_qty_item1 = get_reserved_qty("_Test Item")
existing_reserved_qty_item2 = get_reserved_qty("_Test Item Home Desktop 100")
so = make_sales_order(item_code="_Test Sales BOM Item")
so = make_sales_order(item_code="_Test Product Bundle Item")
self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1 + 50)
self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"),

View File

@ -5,12 +5,12 @@
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
"modified": "2014-06-03 07:18:16.914298",
"modified": "2015-07-06 06:11:10.534423",
"modified_by": "Administrator",
"module": "Selling",
"name": "Available Stock for Packing Items",
"owner": "Administrator",
"ref_doctype": "Sales BOM",
"ref_doctype": "Product Bundle",
"report_name": "Available Stock for Packing Items",
"report_type": "Script Report"
}

View File

@ -39,9 +39,9 @@ def get_columns():
return columns
def get_sales_bom_items():
def get_product_bundle_items():
sbom_item_map = {}
for sbom in frappe.db.sql("""select parent, item_code, qty from `tabSales BOM Item`
for sbom in frappe.db.sql("""select parent, item_code, qty from `tabProduct Bundle Item`
where docstatus < 2""", as_dict=1):
sbom_item_map.setdefault(sbom.parent, {}).setdefault(sbom.item_code, sbom.qty)
@ -67,7 +67,7 @@ def get_item_warehouse_quantity():
def get_item_warehouse_quantity_map():
sbom_map = {}
iwq_map = get_item_warehouse_quantity()
sbom_item_map = get_sales_bom_items()
sbom_item_map = get_product_bundle_items()
for sbom, sbom_items in sbom_item_map.items():
for item, child_qty in sbom_items.items():

View File

@ -112,10 +112,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
erpnext.utils.get_address_display(this.frm, "shipping_address_name", "shipping_address");
},
contact_person: function() {
erpnext.utils.get_contact_details(this.frm);
},
sales_partner: function() {
this.apply_pricing_rule();
},
@ -295,27 +291,27 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
set_dynamic_labels: function() {
this._super();
this.set_sales_bom_help(this.frm.doc);
this.set_product_bundle_help(this.frm.doc);
},
set_sales_bom_help: function(doc) {
set_product_bundle_help: function(doc) {
if(!cur_frm.fields_dict.packing_list) return;
if ((doc.packed_items || []).length) {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true);
if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
help_msg = "<div class='alert alert-warning'>" +
__("For 'Sales BOM' items, Warehouse, Serial No and Batch No will be considered from the 'Packing List' table. If Warehouse and Batch No are same for all packing items for any 'Sales BOM' item, those values can be entered in the main Item table, values will be copied to 'Packing List' table.")+
__("For 'Product Bundle' items, Warehouse, Serial No and Batch No will be considered from the 'Packing List' table. If Warehouse and Batch No are same for all packing items for any 'Product Bundle' item, those values can be entered in the main Item table, values will be copied to 'Packing List' table.")+
"</div>";
frappe.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = help_msg;
frappe.meta.get_docfield(doc.doctype, 'product_bundle_help', doc.name).options = help_msg;
}
} else {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(false);
if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
frappe.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = '';
frappe.meta.get_docfield(doc.doctype, 'product_bundle_help', doc.name).options = '';
}
}
refresh_field('sales_bom_help');
refresh_field('product_bundle_help');
}
});

View File

@ -26,7 +26,7 @@
"permlevel": 0
},
{
"description": "To track brand name in the following documents Delivery Note, Opportunity, Material Request, Item, Purchase Order, Purchase Voucher, Purchaser Receipt, Quotation, Sales Invoice, Sales BOM, Sales Order, Serial No",
"description": "To track brand name in the following documents Delivery Note, Opportunity, Material Request, Item, Purchase Order, Purchase Voucher, Purchaser Receipt, Quotation, Sales Invoice, Product Bundle, Sales Order, Serial No",
"fieldname": "fs_brands",
"fieldtype": "Check",
"in_list_view": 1,
@ -205,7 +205,7 @@
"icon": "icon-glass",
"idx": 1,
"issingle": 1,
"modified": "2015-02-05 05:11:38.842809",
"modified": "2015-07-06 06:11:10.534423",
"modified_by": "Administrator",
"module": "Setup",
"name": "Features Setup",

View File

@ -331,9 +331,9 @@
"read_only": 1
},
{
"fieldname": "sales_bom_help",
"fieldname": "product_bundle_help",
"fieldtype": "HTML",
"label": "Sales BOM Help",
"label": "Product Bundle Help",
"permlevel": 0,
"print_hide": 1,
"read_only": 0
@ -1070,7 +1070,7 @@
"idx": 1,
"in_create": 0,
"is_submittable": 1,
"modified": "2015-06-15 15:37:54.699371",
"modified": "2015-07-07 02:37:08.064584",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",

View File

@ -112,7 +112,7 @@ class TestDeliveryNote(unittest.TestCase):
stock_in_hand_account = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"})
prev_bal = get_balance_on(stock_in_hand_account)
dn = create_delivery_note(item_code="_Test Sales BOM Item")
dn = create_delivery_note(item_code="_Test Product Bundle Item")
stock_value_diff_rm1 = abs(frappe.db.get_value("Stock Ledger Entry",
{"voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": "_Test Item"},
@ -208,4 +208,4 @@ def create_delivery_note(**args):
dn.submit()
return dn
test_dependencies = ["Sales BOM"]
test_dependencies = ["Product Bundle"]

View File

@ -181,6 +181,7 @@
"fieldname": "has_variants",
"fieldtype": "Check",
"label": "Has Variants",
"no_copy": 1,
"options": "",
"permlevel": 0,
"precision": "",

View File

@ -109,7 +109,7 @@
"stock_uom": "_Test UOM 1"
},
{
"description": "_Test Sales BOM Item 5",
"description": "_Test Product Bundle Item 5",
"doctype": "Item",
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
@ -124,9 +124,9 @@
"is_service_item": "No",
"is_stock_item": "No",
"is_sub_contracted_item": "No",
"item_code": "_Test Sales BOM Item",
"item_code": "_Test Product Bundle Item",
"item_group": "_Test Item Group Desktops",
"item_name": "_Test Sales BOM Item",
"item_name": "_Test Product Bundle Item",
"stock_uom": "_Test UOM"
},
{

View File

@ -13,9 +13,9 @@ from frappe.model.document import Document
class PackedItem(Document):
pass
def get_sales_bom_items(item_code):
def get_product_bundle_items(item_code):
return frappe.db.sql("""select t1.item_code, t1.qty, t1.uom
from `tabSales BOM Item` t1, `tabSales BOM` t2
from `tabProduct Bundle Item` t1, `tabProduct Bundle` t2
where t2.new_item_code=%s and t1.parent = t2.name""", item_code, as_dict=1)
def get_packing_item_details(item):
@ -58,14 +58,14 @@ def update_packing_list_item(obj, packing_item_code, qty, warehouse, line):
def make_packing_list(obj, item_table_fieldname):
"""make packing list for sales bom item"""
"""make packing list for Product Bundle item"""
if obj.get("_action") and obj._action == "update_after_submit": return
parent_items = []
for d in obj.get(item_table_fieldname):
if frappe.db.get_value("Sales BOM", {"new_item_code": d.item_code}):
for i in get_sales_bom_items(d.item_code):
if frappe.db.get_value("Product Bundle", {"new_item_code": d.item_code}):
for i in get_product_bundle_items(d.item_code):
update_packing_list_item(obj, i['item_code'], flt(i['qty'])*flt(d.qty), d.warehouse, d)
if [d.item_code, d.name] not in parent_items:

View File

@ -1 +1 @@
Child Item grouped in parent Sales BOM.
Child Item grouped in parent Product Bundle.

View File

@ -519,11 +519,11 @@ cur_frm.cscript.validate_items = function(doc) {
}
cur_frm.cscript.expense_account = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "expense_account");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "expense_account");
}
cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "cost_center");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
}
cur_frm.fields_dict.customer.get_query = function(doc, cdt, cdn) {

View File

@ -346,7 +346,7 @@ class TestStockEntry(unittest.TestCase):
self._test_sales_invoice_return("_Test Item", 5, 2)
def test_sales_invoice_return_of_packing_item(self):
self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20)
self._test_sales_invoice_return("_Test Product Bundle Item", 25, 20)
def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty):
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
@ -381,7 +381,7 @@ class TestStockEntry(unittest.TestCase):
self._test_delivery_note_return("_Test Item", 5, 2)
def test_delivery_note_return_of_packing_item(self):
self._test_delivery_note_return("_Test Sales BOM Item", 25, 20)
self._test_delivery_note_return("_Test Product Bundle Item", 25, 20)
def _test_sales_return_jv(self, se):
jv = make_return_jv(se.name)
@ -399,7 +399,7 @@ class TestStockEntry(unittest.TestCase):
self._test_sales_return_jv(se)
def test_make_return_jv_for_sales_invoice_packing_item(self):
se = self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20)
se = self._test_sales_invoice_return("_Test Product Bundle Item", 25, 20)
self._test_sales_return_jv(se)
def test_make_return_jv_for_delivery_note_non_packing_item(self):
@ -410,10 +410,10 @@ class TestStockEntry(unittest.TestCase):
self._test_sales_return_jv(se)
def test_make_return_jv_for_delivery_note_packing_item(self):
se = self._test_delivery_note_return("_Test Sales BOM Item", 25, 20)
se = self._test_delivery_note_return("_Test Product Bundle Item", 25, 20)
self._test_sales_return_jv(se)
se = self._test_delivery_note_return_against_sales_order("_Test Sales BOM Item", 25, 20)
se = self._test_delivery_note_return_against_sales_order("_Test Product Bundle Item", 25, 20)
self._test_sales_return_jv(se)
def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty):

View File

@ -67,7 +67,8 @@
"label": "Items",
"options": "Stock Reconciliation Item",
"permlevel": 0,
"precision": ""
"precision": "",
"reqd": 1
},
{
"fieldname": "get_items",
@ -148,7 +149,7 @@
"idx": 1,
"is_submittable": 1,
"max_attachments": 1,
"modified": "2015-02-20 04:39:46.585018",
"modified": "2015-07-06 03:13:52.054017",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Reconciliation",

View File

@ -7,12 +7,12 @@ import frappe, json
def execute(filters=None):
data = []
parents = {
"Sales BOM Item": "Sales BOM",
"Product Bundle Item": "Product Bundle",
"BOM Explosion Item": "BOM",
"BOM Item": "BOM"
}
for doctype in ("Sales BOM Item",
for doctype in ("Product Bundle Item",
"BOM Explosion Item" if filters.search_sub_assemblies else "BOM Item"):
all_boms = {}
for d in frappe.get_all(doctype, fields=["parent", "item_code"]):

View File

@ -66,5 +66,4 @@ def get_contact_details(contact):
"contact_designation": contact.get("designation"),
"contact_department": contact.get("department")
}
return out