Merge branch 'develop' of https://github.com/frappe/erpnext into dimensions

This commit is contained in:
deepeshgarg007 2019-05-30 22:11:27 +05:30
commit 2580075583
97 changed files with 446910 additions and 417715 deletions

View File

@ -1,20 +0,0 @@
include MANIFEST.in
include requirements.txt
include *.json
include *.md
include *.py
include *.txt
include .travis.yml
recursive-include erpnext *.txt
recursive-include erpnext *.css
recursive-include erpnext *.csv
recursive-include erpnext *.html
recursive-include erpnext *.ico
recursive-include erpnext *.js
recursive-include erpnext *.json
recursive-include erpnext *.md
recursive-include erpnext *.png
recursive-include erpnext *.py
recursive-include erpnext *.svg
recursive-include erpnext/public *
recursive-exclude * *.pyc

View File

@ -59,18 +59,38 @@ frappe.ui.form.on("Request for Quotation",{
var dialog = new frappe.ui.Dialog({
title: __("Get Suppliers"),
fields: [
{ "fieldtype": "Select", "label": __("Get Suppliers By"),
{
"fieldtype": "Select", "label": __("Get Suppliers By"),
"fieldname": "search_type",
"options": "Tag\nSupplier Group", "reqd": 1 },
{ "fieldtype": "Link", "label": __("Supplier Group"),
"options": ["Tag","Supplier Group"],
"reqd": 1,
onchange() {
if(dialog.get_value('search_type') == 'Tag'){
frappe.call({
method: 'erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_supplier_tag',
}).then(r => {
dialog.set_df_property("tag", "options", r.message)
});
}
}
},
{
"fieldtype": "Link", "label": __("Supplier Group"),
"fieldname": "supplier_group",
"options": "Supplier Group", "reqd": 0,
"depends_on": "eval:doc.search_type == 'Supplier Group'"},
{ "fieldtype": "Data", "label": __("Tag"),
"fieldname": "tag", "reqd": 0,
"depends_on": "eval:doc.search_type == 'Tag'" },
{ "fieldtype": "Button", "label": __("Add All Suppliers"),
"fieldname": "add_suppliers", "cssClass": "btn-primary"},
"options": "Supplier Group",
"reqd": 0,
"depends_on": "eval:doc.search_type == 'Supplier Group'"
},
{
"fieldtype": "Select", "label": __("Tag"),
"fieldname": "tag",
"reqd": 0,
"depends_on": "eval:doc.search_type == 'Tag'",
},
{
"fieldtype": "Button", "label": __("Add All Suppliers"),
"fieldname": "add_suppliers"
},
]
});

View File

@ -341,3 +341,16 @@ def get_item_from_material_requests_based_on_supplier(source_name, target_doc =
}, target_doc)
return target_doc
@frappe.whitelist()
def get_supplier_tag():
data = frappe.db.sql("select _user_tags from `tabSupplier`")
tags = []
for tag in data:
tags += filter(bool, tag[0].split(","))
tags = list(set(tags))
return tags

View File

@ -279,14 +279,14 @@ def copy_attributes_to_variant(item, variant):
variant.set(field.fieldname, item.get(field.fieldname))
variant.variant_of = item.name
if 'description' in allow_fields:
variant.has_variants = 0
if 'description' not in allow_fields:
if not variant.description:
variant.description = ""
if item.variant_based_on=='Item Attribute':
if variant.attributes:
attributes_description = ""
attributes_description = item.description + " "
for d in variant.attributes:
attributes_description += "<div>" + d.attribute + ": " + cstr(d.attribute_value) + "</div>"

View File

@ -316,19 +316,27 @@ class StatusUpdater(Document):
.format(frappe.db.escape(frappe.session.user))
def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
ref_fieldname = ref_dt.lower().replace(" ", "_")
zero_amount_refdoc = []
all_zero_amount_refdoc = frappe.db.sql_list("""select name from `tab%s`
where docstatus=1 and base_net_total = 0""" % ref_dt)
ref_fieldname = frappe.scrub(ref_dt)
for item in self.get("items"):
if item.get(ref_fieldname) \
and item.get(ref_fieldname) in all_zero_amount_refdoc \
and item.get(ref_fieldname) not in zero_amount_refdoc:
zero_amount_refdoc.append(item.get(ref_fieldname))
ref_docs = [item.get(ref_fieldname) for item in (self.get('items') or []) if item.get(ref_fieldname)]
if not ref_docs:
return
if zero_amount_refdoc:
self.update_billing_status(zero_amount_refdoc, ref_dt, ref_fieldname)
zero_amount_refdocs = frappe.db.sql_list("""
SELECT
name
from
`tab{ref_dt}`
where
docstatus = 1
and base_net_total = 0
and name in %(ref_docs)s
""".format(ref_dt=ref_dt), {
'ref_docs': ref_docs
})
if zero_amount_refdocs:
self.update_billing_status(zero_amount_refdocs, ref_dt, ref_fieldname)
def update_billing_status(self, zero_amount_refdoc, ref_dt, ref_fieldname):
for ref_dn in zero_amount_refdoc:

View File

@ -135,8 +135,8 @@ class NamingSeries(Document):
def validate_series_name(self, n):
import re
if not re.match("^[\w\- /.#]*$", n, re.UNICODE):
throw(_('Special Characters except "-", "#", "." and "/" not allowed in naming series'))
if not re.match("^[\w\- /.#{}]*$", n, re.UNICODE):
throw(_('Special Characters except "-", "#", ".", "/", "{" and "}" not allowed in naming series'))
def get_options(self, arg=None):
if frappe.get_meta(arg or self.select_doc_for_series).get_field("naming_series"):

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestWarehouseType(unittest.TestCase):
pass

View File

@ -0,0 +1,8 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Warehouse Type', {
// refresh: function(frm) {
// }
});

View File

@ -0,0 +1,108 @@
{
"autoname": "Prompt",
"creation": "2019-05-21 15:27:06.514511",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"description"
],
"fields": [
{
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description"
}
],
"modified": "2019-05-27 18:35:33.354571",
"modified_by": "Administrator",
"module": "Stock",
"name": "Warehouse Type",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Item Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Stock Manager",
"share": 1,
"write": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"share": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Stock User",
"share": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase User",
"share": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Manufacturing User",
"share": 1
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class WarehouseType(Document):
pass

View File

@ -0,0 +1,58 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
// For license information, please see license.txt
frappe.query_reports["Product Bundle Balance"] = {
"filters": [
{
"fieldname":"date",
"label": __("Date"),
"fieldtype": "Date",
"width": "80",
"reqd": 1,
"default": frappe.datetime.get_today(),
},
{
"fieldname": "item_code",
"label": __("Item"),
"fieldtype": "Link",
"width": "80",
"options": "Item",
"get_query": function() {
return {
query: "erpnext.controllers.queries.item_query",
filters: {"is_stock_item": 0}
};
}
},
{
"fieldname": "item_group",
"label": __("Item Group"),
"fieldtype": "Link",
"width": "80",
"options": "Item Group"
},
{
"fieldname":"brand",
"label": __("Brand"),
"fieldtype": "Link",
"options": "Brand"
},
{
"fieldname": "warehouse",
"label": __("Warehouse"),
"fieldtype": "Link",
"width": "80",
"options": "Warehouse"
},
],
"initial_depth": 0,
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (!data.parent_item) {
value = $(`<span>${value}</span>`);
var $value = $(value).css("font-weight", "bold");
value = $value.wrap("<p></p>").parent().html();
}
return value;
}
};

View File

@ -0,0 +1,23 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2019-03-06 01:40:35.418304",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2019-03-06 01:40:35.418304",
"modified_by": "Administrator",
"module": "Stock",
"name": "Product Bundle Balance",
"owner": "Administrator",
"ref_doctype": "Stock Ledger Entry",
"report_name": "Product Bundle Balance",
"report_type": "Script Report",
"roles": [
{
"role": "Stock User"
}
]
}

View File

@ -0,0 +1,187 @@
# 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
from frappe import _
from frappe.utils import flt
from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
from six import iteritems
def execute(filters=None):
if not filters:
filters = frappe._dict()
columns = get_columns()
item_details, pb_details, parent_items, child_items = get_items(filters)
stock_balance = get_stock_balance(filters, child_items)
data = []
for parent_item in parent_items:
parent_item_detail = item_details[parent_item]
required_items = pb_details[parent_item]
warehouse_company_map = {}
for child_item in required_items:
child_item_balance = stock_balance.get(child_item.item_code, frappe._dict())
for warehouse, sle in iteritems(child_item_balance):
if flt(sle.qty_after_transaction) > 0:
warehouse_company_map[warehouse] = sle.company
for warehouse, company in iteritems(warehouse_company_map):
parent_row = {
"indent": 0,
"item_code": parent_item,
"item_name": parent_item_detail.item_name,
"item_group": parent_item_detail.item_group,
"brand": parent_item_detail.brand,
"description": parent_item_detail.description,
"warehouse": warehouse,
"uom": parent_item_detail.stock_uom,
"company": company,
}
child_rows = []
for child_item_detail in required_items:
child_item_balance = stock_balance.get(child_item_detail.item_code, frappe._dict()).get(warehouse, frappe._dict())
child_row = {
"indent": 1,
"parent_item": parent_item,
"item_code": child_item_detail.item_code,
"item_name": child_item_detail.item_name,
"item_group": child_item_detail.item_group,
"brand": child_item_detail.brand,
"description": child_item_detail.description,
"warehouse": warehouse,
"uom": child_item_detail.uom,
"actual_qty": flt(child_item_balance.qty_after_transaction),
"minimum_qty": flt(child_item_detail.qty),
"company": company,
}
child_row["bundle_qty"] = child_row["actual_qty"] // child_row["minimum_qty"]
child_rows.append(child_row)
min_bundle_qty = min(map(lambda d: d["bundle_qty"], child_rows))
parent_row["bundle_qty"] = min_bundle_qty
data.append(parent_row)
data += child_rows
return columns, data
def get_columns():
columns = [
{"fieldname": "item_code", "label": _("Item"), "fieldtype": "Link", "options": "Item", "width": 300},
{"fieldname": "warehouse", "label": _("Warehouse"), "fieldtype": "Link", "options": "Warehouse", "width": 100},
{"fieldname": "uom", "label": _("UOM"), "fieldtype": "Link", "options": "UOM", "width": 70},
{"fieldname": "bundle_qty", "label": _("Bundle Qty"), "fieldtype": "Float", "width": 100},
{"fieldname": "actual_qty", "label": _("Actual Qty"), "fieldtype": "Float", "width": 100},
{"fieldname": "minimum_qty", "label": _("Minimum Qty"), "fieldtype": "Float", "width": 100},
{"fieldname": "item_group", "label": _("Item Group"), "fieldtype": "Link", "options": "Item Group", "width": 100},
{"fieldname": "brand", "label": _("Brand"), "fieldtype": "Link", "options": "Brand", "width": 100},
{"fieldname": "description", "label": _("Description"), "width": 140},
{"fieldname": "company", "label": _("Company"), "fieldtype": "Link", "options": "Company", "width": 100}
]
return columns
def get_items(filters):
pb_details = frappe._dict()
item_details = frappe._dict()
conditions = get_parent_item_conditions(filters)
parent_item_details = frappe.db.sql("""
select item.name as item_code, item.item_name, pb.description, item.item_group, item.brand, item.stock_uom
from `tabItem` item
inner join `tabProduct Bundle` pb on pb.new_item_code = item.name
where ifnull(item.disabled, 0) = 0 {0}
""".format(conditions), filters, as_dict=1) # nosec
parent_items = []
for d in parent_item_details:
parent_items.append(d.item_code)
item_details[d.item_code] = d
if parent_items:
child_item_details = frappe.db.sql("""
select
pb.new_item_code as parent_item, pbi.item_code, item.item_name, pbi.description, item.item_group, item.brand,
item.stock_uom, pbi.uom, pbi.qty
from `tabProduct Bundle Item` pbi
inner join `tabProduct Bundle` pb on pb.name = pbi.parent
inner join `tabItem` item on item.name = pbi.item_code
where pb.new_item_code in ({0})
""".format(", ".join(["%s"] * len(parent_items))), parent_items, as_dict=1) # nosec
else:
child_item_details = []
child_items = set()
for d in child_item_details:
if d.item_code != d.parent_item:
pb_details.setdefault(d.parent_item, []).append(d)
child_items.add(d.item_code)
item_details[d.item_code] = d
child_items = list(child_items)
return item_details, pb_details, parent_items, child_items
def get_stock_balance(filters, items):
sle = get_stock_ledger_entries(filters, items)
stock_balance = frappe._dict()
for d in sle:
stock_balance.setdefault(d.item_code, frappe._dict())[d.warehouse] = d
return stock_balance
def get_stock_ledger_entries(filters, items):
if not items:
return []
item_conditions_sql = ' and sle.item_code in ({})' \
.format(', '.join([frappe.db.escape(i) for i in items]))
conditions = get_sle_conditions(filters)
return frappe.db.sql("""
select
sle.item_code, sle.warehouse, sle.qty_after_transaction, sle.company
from
`tabStock Ledger Entry` sle force index (posting_sort_index)
left join `tabStock Ledger Entry` sle2 on
sle.item_code = sle2.item_code and sle.warehouse = sle2.warehouse
and (sle.posting_date, sle.posting_time, sle.name) < (sle2.posting_date, sle2.posting_time, sle2.name)
where sle2.name is null and sle.docstatus < 2 %s %s""" % (item_conditions_sql, conditions), as_dict=1) # nosec
def get_parent_item_conditions(filters):
conditions = []
if filters.get("item_code"):
conditions.append("item.item_code = %(item_code)s")
else:
if filters.get("brand"):
conditions.append("item.brand=%(brand)s")
if filters.get("item_group"):
conditions.append(get_item_group_condition(filters.get("item_group")))
conditions = " and ".join(conditions)
return "and {0}".format(conditions) if conditions else ""
def get_sle_conditions(filters):
conditions = ""
if not filters.get("date"):
frappe.throw(_("'Date' is required"))
conditions += " and sle.posting_date <= %s" % frappe.db.escape(filters.get("date"))
if filters.get("warehouse"):
warehouse_details = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1)
if warehouse_details:
conditions += " and exists (select name from `tabWarehouse` wh \
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)" % (warehouse_details.lft, warehouse_details.rgt) # nosec
return conditions

View File

@ -49,7 +49,24 @@ frappe.query_reports["Stock Balance"] = {
"label": __("Warehouse"),
"fieldtype": "Link",
"width": "80",
"options": "Warehouse"
"options": "Warehouse",
get_query: () => {
var warehouse_type = frappe.query_report.get_filter_value('warehouse_type');
if(warehouse_type){
return {
filters: {
'warehouse_type': warehouse_type
}
}
}
}
},
{
"fieldname": "warehouse_type",
"label": __("Warehouse Type"),
"fieldtype": "Link",
"width": "80",
"options": "Warehouse Type"
},
{
"fieldname":"include_uom",

View File

@ -113,6 +113,10 @@ def get_conditions(filters):
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"%(warehouse_details.lft,
warehouse_details.rgt)
if filters.get("warehouse_type") and not filters.get("warehouse"):
conditions += " and exists (select name from `tabWarehouse` wh \
where wh.warehouse_type = '%s' and sle.warehouse = wh.name)"%(filters.get("warehouse_type"))
return conditions
def get_stock_ledger_entries(filters, items):

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
DocType: Account,Accounts,དངུལ་རྩིས།
DocType: Pricing Rule,Buying,ཉོ་བ།
1 DocType: Account Accounts དངུལ་རྩིས།
DocType: Account Accounts དངུལ་རྩིས།
DocType: Pricing Rule Buying ཉོ་བ།

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
DocType: Patient,Married,既婚
1 DocType: Patient Married 既婚
DocType: Patient Married 既婚

View File

View File

File diff suppressed because it is too large Load Diff

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff