Merge branch 'v4.x.x'
This commit is contained in:
commit
397a2bf1d0
@ -1,2 +1,2 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
__version__ = '4.25.2'
|
__version__ = '4.25.3'
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import frappe
|
|||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
from erpnext.accounts.utils import get_balance_on
|
from erpnext.accounts.utils import get_balance_on
|
||||||
|
from erpnext.accounts.report.financial_statements import sort_root_accounts
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_companies():
|
def get_companies():
|
||||||
@ -21,12 +22,15 @@ def get_children():
|
|||||||
# root
|
# root
|
||||||
if args['parent'] in ("Accounts", "Cost Centers"):
|
if args['parent'] in ("Accounts", "Cost Centers"):
|
||||||
acc = frappe.db.sql(""" select
|
acc = frappe.db.sql(""" select
|
||||||
name as value, if(group_or_ledger='Group', 1, 0) as expandable
|
name as value, if(group_or_ledger='Group', 1, 0) as expandable, root_type, report_type
|
||||||
from `tab%s`
|
from `tab%s`
|
||||||
where ifnull(parent_%s,'') = ''
|
where ifnull(parent_%s,'') = ''
|
||||||
and `company` = %s and docstatus<2
|
and `company` = %s and docstatus<2
|
||||||
order by name""" % (ctype, ctype.lower().replace(' ','_'), '%s'),
|
order by name""" % (ctype, ctype.lower().replace(' ','_'), '%s'),
|
||||||
company, as_dict=1)
|
company, as_dict=1)
|
||||||
|
|
||||||
|
if args["parent"]=="Accounts":
|
||||||
|
sort_root_accounts(acc)
|
||||||
else:
|
else:
|
||||||
# other
|
# other
|
||||||
acc = frappe.db.sql("""select
|
acc = frappe.db.sql("""select
|
||||||
|
|||||||
@ -186,7 +186,10 @@ def filter_accounts(accounts, depth=10):
|
|||||||
filtered_accounts = []
|
filtered_accounts = []
|
||||||
def add_to_list(parent, level):
|
def add_to_list(parent, level):
|
||||||
if level < depth:
|
if level < depth:
|
||||||
for child in (parent_children_map.get(parent) or []):
|
children = parent_children_map.get(parent) or []
|
||||||
|
if parent == None:
|
||||||
|
sort_root_accounts(children)
|
||||||
|
for child in children:
|
||||||
child.indent = level
|
child.indent = level
|
||||||
filtered_accounts.append(child)
|
filtered_accounts.append(child)
|
||||||
add_to_list(child.name, level + 1)
|
add_to_list(child.name, level + 1)
|
||||||
@ -202,6 +205,22 @@ def filter_accounts(accounts, depth=10):
|
|||||||
add_to_list(None, 0)
|
add_to_list(None, 0)
|
||||||
|
|
||||||
return filtered_accounts, accounts_by_name
|
return filtered_accounts, accounts_by_name
|
||||||
|
|
||||||
|
def sort_root_accounts(roots):
|
||||||
|
"""Sort root types as Asset, Liability, Equity, Income, Expense"""
|
||||||
|
|
||||||
|
def compare_roots(a, b):
|
||||||
|
if a.report_type != b.report_type and a.report_type == "Balance Sheet":
|
||||||
|
return -1
|
||||||
|
if a.root_type != b.root_type and a.root_type == "Asset":
|
||||||
|
return -1
|
||||||
|
if a.root_type == "Liability" and b.root_type == "Equity":
|
||||||
|
return -1
|
||||||
|
if a.root_type == "Income" and b.root_type == "Expense":
|
||||||
|
return -1
|
||||||
|
return 1
|
||||||
|
|
||||||
|
roots.sort(compare_roots)
|
||||||
|
|
||||||
def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closing_entries=False):
|
def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closing_entries=False):
|
||||||
"""Returns a dict like { "account": [gl entries], ... }"""
|
"""Returns a dict like { "account": [gl entries], ... }"""
|
||||||
|
|||||||
@ -123,7 +123,8 @@ def accumulate_values_into_parents(accounts, accounts_by_name):
|
|||||||
def prepare_data(accounts, filters, total_row):
|
def prepare_data(accounts, filters, total_row):
|
||||||
show_zero_values = cint(filters.show_zero_values)
|
show_zero_values = cint(filters.show_zero_values)
|
||||||
data = []
|
data = []
|
||||||
for i, d in enumerate(accounts):
|
accounts_with_zero_value = []
|
||||||
|
for d in accounts:
|
||||||
has_value = False
|
has_value = False
|
||||||
row = {
|
row = {
|
||||||
"account_name": d.account_name,
|
"account_name": d.account_name,
|
||||||
@ -140,9 +141,14 @@ def prepare_data(accounts, filters, total_row):
|
|||||||
row[key] = d.get(key, 0.0)
|
row[key] = d.get(key, 0.0)
|
||||||
if row[key]:
|
if row[key]:
|
||||||
has_value = True
|
has_value = True
|
||||||
|
|
||||||
if has_value or show_zero_values:
|
if show_zero_values:
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
else:
|
||||||
|
if not has_value:
|
||||||
|
accounts_with_zero_value.append(d.name)
|
||||||
|
elif d.parent_account not in accounts_with_zero_value:
|
||||||
|
data.append(row)
|
||||||
|
|
||||||
data.extend([{},total_row])
|
data.extend([{},total_row])
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt, cstr
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
|
||||||
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
||||||
@ -64,7 +64,7 @@ class PurchaseCommon(BuyingController):
|
|||||||
= d.rate = item_last_purchase_rate
|
= d.rate = item_last_purchase_rate
|
||||||
|
|
||||||
def validate_for_items(self, obj):
|
def validate_for_items(self, obj):
|
||||||
check_list, chk_dupl_itm=[],[]
|
items = []
|
||||||
for d in obj.get(obj.fname):
|
for d in obj.get(obj.fname):
|
||||||
# validation for valid qty
|
# validation for valid qty
|
||||||
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
|
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
|
||||||
@ -96,30 +96,10 @@ class PurchaseCommon(BuyingController):
|
|||||||
if item[0][1] != 'Yes' and item[0][2] != 'Yes':
|
if item[0][1] != 'Yes' and item[0][2] != 'Yes':
|
||||||
frappe.throw(_("{0} must be a Purchased or Sub-Contracted Item in row {1}").format(d.item_code, d.idx))
|
frappe.throw(_("{0} must be a Purchased or Sub-Contracted Item in row {1}").format(d.item_code, d.idx))
|
||||||
|
|
||||||
# list criteria that should not repeat if item is stock item
|
items.append(cstr(d.item_code))
|
||||||
e = [getattr(d, "schedule_date", None), d.item_code, d.description, d.warehouse, d.uom,
|
if items and len(items) != len(set(items)):
|
||||||
d.meta.get_field('prevdoc_docname') and d.prevdoc_docname or d.meta.get_field('sales_order_no') and d.sales_order_no or '',
|
frappe.msgprint(_("Warning: Same item has been entered multiple times."))
|
||||||
d.meta.get_field('prevdoc_detail_docname') and d.prevdoc_detail_docname or '',
|
|
||||||
d.meta.get_field('batch_no') and d.batch_no or '']
|
|
||||||
|
|
||||||
# if is not stock item
|
|
||||||
f = [getattr(d, "schedule_date", None), d.item_code, d.description]
|
|
||||||
|
|
||||||
ch = frappe.db.sql("""select is_stock_item from `tabItem` where name = %s""", d.item_code)
|
|
||||||
|
|
||||||
if ch and ch[0][0] == 'Yes':
|
|
||||||
# check for same items
|
|
||||||
if e in check_list:
|
|
||||||
frappe.throw(_("Item {0} has been entered multiple times with same description or date or warehouse").format(d.item_code))
|
|
||||||
else:
|
|
||||||
check_list.append(e)
|
|
||||||
|
|
||||||
elif ch and ch[0][0] == 'No':
|
|
||||||
# check for same items
|
|
||||||
if f in chk_dupl_itm:
|
|
||||||
frappe.throw(_("Item {0} has been entered multiple times with same description or date").format(d.item_code))
|
|
||||||
else:
|
|
||||||
chk_dupl_itm.append(f)
|
|
||||||
|
|
||||||
def check_for_stopped_status(self, doctype, docname):
|
def check_for_stopped_status(self, doctype, docname):
|
||||||
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
||||||
|
|||||||
@ -5,7 +5,7 @@ app_publisher = "Web Notes Technologies Pvt. Ltd. and Contributors"
|
|||||||
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
|
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
|
||||||
app_icon = "icon-th"
|
app_icon = "icon-th"
|
||||||
app_color = "#e74c3c"
|
app_color = "#e74c3c"
|
||||||
app_version = "4.25.2"
|
app_version = "4.25.3"
|
||||||
|
|
||||||
error_report_email = "support@erpnext.com"
|
error_report_email = "support@erpnext.com"
|
||||||
|
|
||||||
|
|||||||
@ -254,8 +254,10 @@ class ProductionPlanningTool(Document):
|
|||||||
ifnull(sum(ifnull(fb.qty, 0)/ifnull(bom.quantity, 1)), 0) as qty,
|
ifnull(sum(ifnull(fb.qty, 0)/ifnull(bom.quantity, 1)), 0) as qty,
|
||||||
fb.description, fb.stock_uom, it.min_order_qty
|
fb.description, fb.stock_uom, it.min_order_qty
|
||||||
from `tabBOM Explosion Item` fb, `tabBOM` bom, `tabItem` it
|
from `tabBOM Explosion Item` fb, `tabBOM` bom, `tabItem` it
|
||||||
where bom.name = fb.parent and it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
|
where bom.name = fb.parent and it.name = fb.item_code
|
||||||
|
and ifnull(it.is_pro_applicable, 'No') = 'No'
|
||||||
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
|
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
|
||||||
|
and ifnull(it.is_stock_item, 'No') = 'Yes'
|
||||||
and fb.docstatus<2 and bom.name=%s
|
and fb.docstatus<2 and bom.name=%s
|
||||||
group by item_code, stock_uom""", bom, as_dict=1):
|
group by item_code, stock_uom""", bom, as_dict=1):
|
||||||
bom_wise_item_details.setdefault(d.item_code, d)
|
bom_wise_item_details.setdefault(d.item_code, d)
|
||||||
@ -268,6 +270,7 @@ class ProductionPlanningTool(Document):
|
|||||||
from `tabBOM Item` bom_item, `tabBOM` bom, tabItem item
|
from `tabBOM Item` bom_item, `tabBOM` bom, tabItem item
|
||||||
where bom.name = bom_item.parent and bom.name = %s and bom_item.docstatus < 2
|
where bom.name = bom_item.parent and bom.name = %s and bom_item.docstatus < 2
|
||||||
and bom_item.item_code = item.name
|
and bom_item.item_code = item.name
|
||||||
|
and ifnull(item.is_stock_item, 'No') = 'Yes'
|
||||||
group by item_code""", bom, as_dict=1):
|
group by item_code""", bom, as_dict=1):
|
||||||
bom_wise_item_details.setdefault(d.item_code, d)
|
bom_wise_item_details.setdefault(d.item_code, d)
|
||||||
|
|
||||||
|
|||||||
@ -9,19 +9,20 @@ from frappe.utils import flt, cint
|
|||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
|
|
||||||
|
float_precision = cint(frappe.db.get_default("float_precision")) or 3
|
||||||
|
|
||||||
columns = get_columns(filters)
|
columns = get_columns(filters)
|
||||||
item_map = get_item_details(filters)
|
item_map = get_item_details(filters)
|
||||||
iwb_map = get_item_warehouse_batch_map(filters)
|
iwb_map = get_item_warehouse_batch_map(filters, float_precision)
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
for item in sorted(iwb_map):
|
for item in sorted(iwb_map):
|
||||||
for wh in sorted(iwb_map[item]):
|
for wh in sorted(iwb_map[item]):
|
||||||
for batch in sorted(iwb_map[item][wh]):
|
for batch in sorted(iwb_map[item][wh]):
|
||||||
qty_dict = iwb_map[item][wh][batch]
|
qty_dict = iwb_map[item][wh][batch]
|
||||||
data.append([item, item_map[item]["item_name"],
|
data.append([item, item_map[item]["item_name"], item_map[item]["description"], wh, batch,
|
||||||
item_map[item]["description"], wh, batch,
|
flt(qty_dict.opening_qty, float_precision), flt(qty_dict.in_qty, float_precision),
|
||||||
qty_dict.opening_qty, qty_dict.in_qty,
|
flt(qty_dict.out_qty, float_precision), flt(qty_dict.bal_qty, float_precision)
|
||||||
qty_dict.out_qty, qty_dict.bal_qty
|
|
||||||
])
|
])
|
||||||
|
|
||||||
return columns, data
|
return columns, data
|
||||||
@ -56,8 +57,7 @@ def get_stock_ledger_entries(filters):
|
|||||||
where docstatus < 2 %s order by item_code, warehouse""" %
|
where docstatus < 2 %s order by item_code, warehouse""" %
|
||||||
conditions, as_dict=1)
|
conditions, as_dict=1)
|
||||||
|
|
||||||
def get_item_warehouse_batch_map(filters):
|
def get_item_warehouse_batch_map(filters, float_precision):
|
||||||
float_precision = cint(frappe.db.get_default("float_precision")) or 3
|
|
||||||
sle = get_stock_ledger_entries(filters)
|
sle = get_stock_ledger_entries(filters)
|
||||||
iwb_map = {}
|
iwb_map = {}
|
||||||
|
|
||||||
|
|||||||
2
setup.py
2
setup.py
@ -1,7 +1,7 @@
|
|||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
import os
|
import os
|
||||||
|
|
||||||
version = "4.25.2"
|
version = "4.25.3"
|
||||||
|
|
||||||
with open("requirements.txt", "r") as f:
|
with open("requirements.txt", "r") as f:
|
||||||
install_requires = f.readlines()
|
install_requires = f.readlines()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user