Merge branch 'develop' of https://github.com/frappe/erpnext into payment-terms

This commit is contained in:
tunde 2017-08-29 15:26:50 +01:00
commit a19ea6e2f3
126 changed files with 3043 additions and 766 deletions

View File

@ -4,7 +4,7 @@ import inspect
import frappe import frappe
from erpnext.hooks import regional_overrides from erpnext.hooks import regional_overrides
__version__ = '8.8.6' __version__ = '8.9.2'
def get_default_company(user=None): def get_default_company(user=None):
'''Get default company for user''' '''Get default company for user'''

View File

@ -4,7 +4,7 @@
""" """
Import chart of accounts from OpenERP sources Import chart of accounts from OpenERP sources
""" """
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import os, json import os, json
import ast import ast
@ -229,7 +229,7 @@ def make_charts():
filename = src["id"][5:] + "_" + chart_id filename = src["id"][5:] + "_" + chart_id
print "building " + filename print("building " + filename)
chart = {} chart = {}
chart["name"] = src["name"] chart["name"] = src["name"]
chart["country_code"] = src["id"][5:] chart["country_code"] = src["id"][5:]

View File

@ -0,0 +1,722 @@
{
"country_code": "tw",
"name": "Taiwan - Chart of Accounts",
"tree": {
"1-\u8cc7\u7522": {
"11~12-\u6d41\u52d5\u8cc7\u7522": {
"111-\u73fe\u91d1\u53ca\u7d04\u7576\u73fe\u91d1": {
"1111-\u5eab\u5b58\u73fe\u91d1": {
"account_type": "Cash"
},
"1112-\u96f6\u7528\u91d1/\u9031\u8f49\u91d1": {
"account_type": "Cash"
},
"1113-\u9280\u884c\u5b58\u6b3e": {
"account_type": "Bank",
"\u4e2d\u570b\u4fe1\u8a17": {
"account_type": "Bank"
},
"\u53f0\u5317\u5bcc\u90a6": {
"account_type": "Bank"
}
},
"1116-\u5728\u9014\u73fe\u91d1": {
"account_type": "Cash"
},
"1117-\u7d04\u7576\u73fe\u91d1": {
"account_type": "Cash"
},
"1118-\u5176\u4ed6\u73fe\u91d1\u53ca\u7d04\u7576\u73fe\u91d1": {
"account_type": "Cash"
},
"account_type": "Cash"
},
"112-\u77ed\u671f\u6295\u8cc7": {
"1121-\u77ed\u671f\u6295\u8cc7 \u2014\u80a1\u7968": {}
},
"113-\u61c9\u6536\u7968\u64da": {
"1131-\u61c9\u6536\u7968\u64da": {
"account_type": "Receivable"
},
"1132-\u61c9\u6536\u7968\u64da\u8cbc\u73fe ": {
"account_type": "Receivable"
},
"1138-\u5176\u4ed6\u61c9\u6536\u7968\u64da ": {
"account_type": "Receivable"
},
"1139-\u5099\u62b5\u5446\u5e33 \uff0d\u61c9\u6536\u7968\u64da ": {
"account_type": "Receivable"
},
"account_type": "Receivable"
},
"114-\u61c9\u6536\u5e33\u6b3e": {
"1141-\u61c9\u6536\u5e33\u6b3e ": {
"account_type": "Receivable"
},
"1142-\u61c9\u6536\u5206\u671f\u5e33\u6b3e ": {
"account_type": "Receivable"
},
"1149-\u5099\u62b5\u5446\u5e33 \uff0d\u61c9\u6536\u5e33\u6b3e ": {
"account_type": "Receivable"
},
"account_type": "Receivable"
},
"118-\u5176\u4ed6\u61c9\u6536\u6b3e": {
"1184-\u61c9\u6536\u6536\u76ca": {
"account_type": "Receivable"
},
"1185-\u61c9\u6536\u9000\u7a05\u6b3e": {
"account_type": "Receivable"
},
"1189-\u5099\u62b5\u5446\u5e33 \u2014 \u5176\u4ed6\u61c9\u6536\u6b3e ": {
"account_type": "Receivable"
},
"account_type": "Receivable"
},
"121~122-\u5b58\u8ca8": {
"1219-\u5099\u62b5\u5b58\u8ca8\u8dcc\u50f9\u640d\u5931": {},
"1229-\u5099\u62b5\u5b58\u8ca8\u8dcc\u50f9\u640d\u5931": {},
"account_type": "Stock",
"is_group": 1
},
"125-\u9810\u4ed8\u8cbb\u7528": {
"1251-\u9810\u4ed8\u85aa\u8cc7": {},
"1252-\u9810\u4ed8\u79df\u91d1": {},
"1253-\u9810\u4ed8\u4fdd\u96aa\u8cbb": {},
"1254-\u7528\u54c1\u76e4\u5b58": {},
"1255-\u9810\u4ed8\u6240\u5f97\u7a05": {},
"1258-\u5176\u4ed6\u9810\u4ed8\u8cbb\u7528": {}
},
"126-\u9810\u4ed8\u6b3e\u9805": {
"1261-\u9810\u4ed8\u8ca8\u6b3e": {},
"1268-\u5176\u4ed6\u9810\u4ed8\u6b3e\u9805": {}
},
"128~129-\u5176\u4ed6\u6d41\u52d5\u8cc7\u7522": {
"1281-\u9032\u9805\u7a05\u984d": {},
"1282-\u7559\u62b5\u7a05\u984d": {},
"1283-\u66ab\u4ed8\u6b3e": {},
"1284-\u4ee3\u4ed8\u6b3e": {},
"1285-\u54e1\u5de5\u501f\u652f": {}
}
},
"13-\u57fa\u91d1\u53ca\u9577\u671f\u6295\u8cc7": {
"131-\u57fa\u91d1": {
"1311-\u511f\u50b5\u57fa\u91d1": {},
"1313-\u610f\u5916\u640d\u5931\u6e96\u5099\u57fa\u91d1": {},
"1314-\u9000\u4f11\u57fa\u91d1": {},
"1318-\u5176\u4ed6\u57fa\u91d1": {}
},
"132-\u9577\u671f\u6295\u8cc7": {
"1321-\u9577\u671f\u80a1\u6b0a\u6295\u8cc7": {},
"1322-\u9577\u671f\u50b5\u5238\u6295\u8cc7": {},
"1323-\u9577\u671f\u4e0d\u52d5\u7522\u6295\u8cc7": {},
"1328-\u5176\u4ed6\u9577\u671f\u6295\u8cc7": {}
}
},
"14~15-\u56fa\u5b9a\u8cc7\u7522": {
"141-\u571f\u5730": {
"1411-\u571f\u5730": {
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"142-\u571f\u5730\u6539\u826f\u7269": {
"1421-\u571f\u5730\u6539\u826f\u7269": {
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"143-\u623f\u5c4b\u53ca\u5efa\u7269": {
"1431-\u623f\u5c4b\u53ca\u5efa\u7269": {
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"144~146-\u6a5f(\u5668)\u5177\u53ca\u8a2d\u5099": {
"1441-\u6a5f(\u5668)\u5177": {
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"151-\u79df\u8cc3\u8cc7\u7522": {
"1511-\u79df\u8cc3\u8cc7\u7522": {
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"152-\u79df\u8cc3\u6b0a\u76ca\u6539\u826f": {
"1521-\u79df\u8cc3\u6b0a\u76ca\u6539\u826f": {
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"156-\u672a\u5b8c\u5de5\u7a0b\u53ca\u9810\u4ed8\u8cfc\u7f6e\u8a2d\u5099\u6b3e": {
"1561-\u672a\u5b8c\u5de5\u7a0b": {
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"158-\u96dc\u9805\u56fa\u5b9a\u8cc7\u7522": {
"1581-\u96dc\u9805\u56fa\u5b9a\u8cc7\u7522": {
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"account_type": "Fixed Asset"
},
"16-\u905e\u8017\u8cc7\u7522": {
"161-\u905e\u8017\u8cc7\u7522": {
"is_group": 1
}
},
"17-\u7121\u5f62\u8cc7\u7522": {
"171-\u5546\u6a19\u6b0a": {
"1711-\u5546\u6a19\u6b0a": {}
},
"172-\u5c08\u5229\u6b0a": {
"1721-\u5c08\u5229\u6b0a": {}
},
"176-\u5546\u8b7d": {
"1761-\u5546\u8b7d": {}
},
"177-\u958b\u8fa6\u8cbb": {
"1771-\u958b\u8fa6\u8cbb": {}
},
"178-\u5176\u4ed6\u7121\u5f62\u8cc7\u7522": {
"1781-\u905e\u5ef6\u9000\u4f11\u91d1\u6210\u672c": {}
}
},
"18-\u5176\u4ed6\u8cc7\u7522": {
"181-\u905e\u5ef6\u8cc7\u7522": {
"1811-\u50b5\u5238\u767c\u884c\u6210\u672c": {},
"1812-\u9577\u671f\u9810\u4ed8\u79df\u91d1": {},
"1813-\u9577\u671f\u9810\u4ed8\u4fdd\u96aa\u8cbb": {},
"1814-\u905e\u5ef6\u6240\u5f97\u7a05\u8cc7\u7522": {},
"1815-\u9810\u4ed8\u9000\u4f11\u91d1": {},
"1818-\u5176\u4ed6\u905e\u5ef6\u8cc7\u7522": {}
},
"182-\u9592\u7f6e\u8cc7\u7522": {
"1821-\u9592\u7f6e\u8cc7\u7522": {}
},
"184-\u9577\u671f\u61c9\u6536\u7968\u64da\u53ca\u6b3e\u9805\u8207\u50ac\u6536\u5e33\u6b3e": {
"1841-\u9577\u671f\u61c9\u6536\u7968\u64da": {
"account_type": "Receivable"
},
"1842-\u9577\u671f\u61c9\u6536\u5e33\u6b3e": {
"account_type": "Receivable"
},
"1843-\u50ac\u6536\u5e33\u6b3e": {
"account_type": "Receivable"
},
"1848-\u5176\u4ed6\u9577\u671f\u61c9\u6536\u6b3e\u9805": {
"account_type": "Receivable"
},
"1849-\u5099\u62b5\u5446\u5e33\u2014\u9577\u671f\u61c9\u6536\u7968\u64da\u53ca\u6b3e\u9805\u8207\u50ac\u6536\u5e33\u6b3e": {
"account_type": "Receivable"
},
"account_type": "Receivable"
},
"185-\u51fa\u79df\u8cc7\u7522": {
"1851-\u51fa\u79df\u8cc7\u7522": {},
"1858-\u51fa\u79df\u8cc7\u7522 \u2014\u91cd\u4f30\u589e\u503c": {},
"1859-\u7d2f\u7a4d\u6298\u820a \u2014\u51fa\u79df\u8cc7\u7522": {
"account_type": "Accumulated Depreciation"
}
},
"186-\u5b58\u51fa\u4fdd\u8b49\u91d1": {
"1861-\u5b58\u51fa\u4fdd\u8b49\u91d1": {}
},
"188-\u96dc\u9805\u8cc7\u7522": {
"1881-\u53d7\u9650\u5236\u5b58\u6b3e": {},
"1888-\u96dc\u9805\u8cc7\u7522 \u2014\u5176\u4ed6": {}
}
},
"Temporary Accounts": {
"Temporary Opening": {
"account_type": "Temporary"
},
"account_type": "Temporary"
},
"root_type": "Asset"
},
"2-\u8ca0\u50b5": {
"21~22-\u6d41\u52d5\u8ca0\u50b5": {
"211-\u77ed\u671f\u501f\u6b3e": {
"2111-\u9280\u884c\u900f\u652f": {},
"2112-\u9280\u884c\u501f\u6b3e": {}
},
"212-\u61c9\u4ed8\u77ed\u671f\u7968\u5238": {
"2121-\u61c9\u4ed8\u5546\u696d\u672c\u7968": {
"account_type": "Payable"
},
"2122-\u9280\u884c\u627f\u514c\u532f\u7968": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"213-\u61c9\u4ed8\u7968\u64da": {
"2131-\u61c9\u4ed8\u7968\u64da": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"214-\u61c9\u4ed8\u5e33\u6b3e": {
"2141-\u61c9\u4ed8\u5e33\u6b3e": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"216-\u61c9\u4ed8\u6240\u5f97\u7a05": {
"2161-\u61c9\u4ed8\u6240\u5f97\u7a05": {
"account_type": "Tax",
"tax_rate": 5.0
},
"account_type": "Tax",
"tax_rate": 5.0
},
"217-\u61c9\u4ed8\u8cbb\u7528": {
"2171-\u61c9\u4ed8\u85aa\u5de5": {},
"2172-\u61c9\u4ed8\u79df\u91d1": {},
"2173-\u61c9\u4ed8\u5229\u606f": {},
"2174-\u61c9\u4ed8\u71df\u696d\u7a05": {},
"2175-\u61c9\u4ed8\u7a05\u6350 \u2014\u5176\u4ed6": {
"account_type": "Tax",
"tax_rate": 5.0
},
"2178-\u5176\u4ed6\u61c9\u4ed8\u8cbb\u7528": {}
},
"218~219-\u5176\u4ed6\u61c9\u4ed8\u6b3e": {
"2184-\u61c9\u4ed8\u571f\u5730\u623f\u5c4b\u6b3e": {},
"2185-\u61c9\u4ed8\u8a2d\u5099\u6b3e": {},
"2192-\u61c9\u4ed8\u80a1\u5229": {}
},
"226-\u9810\u6536\u6b3e\u9805": {
"2261-\u9810\u6536\u8ca8\u6b3e": {},
"2262-\u9810\u6536\u6536\u5165": {},
"2268-\u5176\u4ed6\u9810\u6536\u6b3e": {}
},
"227-\u4e00\u5e74\u6216\u4e00\u71df\u696d\u9031\u671f\u5167\u5230\u671f\u9577\u671f\u8ca0\u50b5": {
"is_group": 1
},
"228~229-\u5176\u4ed6\u6d41\u52d5\u8ca0\u50b5": {
"2281-\u92b7\u9805\u7a05\u984d": {},
"2283-\u66ab\u6536\u6b3e ": {},
"2284-\u4ee3\u6536\u6b3e": {},
"2285-\u4f30\u8a08\u552e\u5f8c\u670d\u52d9/\u4fdd\u56fa\u8ca0\u50b5": {},
"2291-\u905e\u5ef6\u6240\u5f97\u7a05\u8ca0\u50b5": {},
"2292-\u905e\u5ef6\u514c\u63db\u5229\u76ca": {}
}
},
"23-\u9577\u671f\u8ca0\u50b5": {
"231-\u61c9\u4ed8\u516c\u53f8\u50b5": {
"2311-\u61c9\u4ed8\u516c\u53f8\u50b5": {},
"2319-\u61c9\u4ed8\u516c\u53f8\u50b5\u6ea2(\u6298)\u50f9": {}
},
"232-\u9577\u671f\u501f\u6b3e": {
"2321-\u9577\u671f\u9280\u884c\u501f\u6b3e": {},
"2324-\u9577\u671f\u501f\u6b3e \u2014\u696d\u4e3b": {},
"2325-\u9577\u671f\u501f\u6b3e \u2014\u54e1\u5de5": {},
"2327-\u9577\u671f\u501f\u6b3e \u2014\u95dc\u4fc2\u4eba": {},
"2328-\u9577\u671f\u501f\u6b3e \u2014\u5176\u4ed6": {}
},
"233-\u9577\u671f\u61c9\u4ed8\u7968\u64da\u53ca\u6b3e\u9805": {
"2331-\u9577\u671f\u61c9\u4ed8\u7968\u64da": {
"account_type": "Payable"
},
"2332-\u9577\u671f\u61c9\u4ed8\u5e33\u6b3e": {
"account_type": "Payable"
},
"2333-\u9577\u671f\u61c9\u4ed8\u79df\u8cc3\u8ca0\u50b5": {
"account_type": "Payable"
},
"account_type": "Payable"
},
"234-\u4f30\u8a08\u61c9\u4ed8\u571f\u5730\u589e\u503c\u7a05": {
"2341-\u4f30\u8a08\u61c9\u4ed8\u571f\u5730\u589e\u503c\u7a05": {}
},
"235-\u61c9\u8a08\u9000\u4f11\u91d1\u8ca0\u50b5": {
"2351-\u61c9\u8a08\u9000\u4f11\u91d1\u8ca0\u50b5": {}
},
"238-\u5176\u4ed6\u9577\u671f\u8ca0\u50b5": {
"2388-\u5176\u4ed6\u9577\u671f\u8ca0\u50b5\u2014\u5176\u4ed6": {}
}
},
"28-\u5176\u4ed6\u8ca0\u50b5": {
"281-\u905e\u5ef6\u8ca0\u50b5": {
"2811-\u905e\u5ef6\u6536\u5165": {},
"2814-\u905e\u5ef6\u6240\u5f97\u7a05\u8ca0\u50b5": {},
"2818-\u5176\u4ed6\u905e\u5ef6\u8ca0\u50b5": {}
},
"286-\u5b58\u5165\u4fdd\u8b49\u91d1": {
"2861-\u5b58\u5165\u4fdd\u8b49\u91d1": {}
},
"288-\u96dc\u9805\u8ca0\u50b5": {
"2888-\u96dc\u9805\u8ca0\u50b5 \u2014\u5176\u4ed6": {}
}
},
"Stock Received But Not Billed": {
"account_type": "Stock Received But Not Billed"
},
"root_type": "Liability"
},
"3-\u696d\u4e3b\u6b0a\u76ca": {
"31-\u8cc7\u672c": {
"311-\u8cc7\u672c\uff08\u80a1\u672c\uff09 ": {
"3111-\u666e\u901a\u80a1\u80a1\u672c": {},
"3112-\u7279\u5225\u80a1\u80a1\u672c": {},
"3113-\u9810\u6536\u80a1\u672c": {},
"3114-\u5f85\u5206\u914d\u80a1\u7968\u80a1\u5229": {},
"3115-\u8cc7\u672c": {}
}
},
"32-\u8cc7\u672c\u516c\u7a4d": {
"321-\u80a1\u7968\u6ea2\u50f9": {
"3211-\u666e\u901a\u80a1\u80a1\u7968\u6ea2\u50f9": {},
"3212-\u7279\u5225\u80a1\u80a1\u7968\u6ea2\u50f9": {}
},
"323-\u8cc7\u7522\u91cd\u4f30\u589e\u503c\u6e96\u5099": {
"3231-\u8cc7\u7522\u91cd\u4f30\u589e\u503c\u6e96\u5099": {}
},
"324-\u8655\u5206\u8cc7\u7522\u6ea2\u50f9\u516c\u7a4d": {
"3241-\u8655\u5206\u8cc7\u7522\u6ea2\u50f9\u516c\u7a4d": {}
},
"325-\u5408\u4f75\u516c\u7a4d": {
"3251-\u5408\u4f75\u516c\u7a4d": {}
},
"326-\u53d7\u8d08\u516c\u7a4d": {
"3261-\u53d7\u8d08\u516c\u7a4d": {}
},
"328-\u5176\u4ed6\u8cc7\u672c\u516c\u7a4d": {
"3281-\u6b0a\u76ca\u6cd5\u9577\u671f\u80a1\u6b0a\u6295\u8cc7\u8cc7\u672c\u516c\u7a4d": {},
"3282-\u8cc7\u672c\u516c\u7a4d\u2014 \u5eab\u85cf\u80a1\u7968\u4ea4\u6613": {}
}
},
"33-\u4fdd\u7559\u76c8\u9918(\u7d2f\u7a4d\u8667\u640d)": {
"331-\u6cd5\u5b9a\u76c8\u9918\u516c\u7a4d": {
"3311-\u6cd5\u5b9a\u76c8\u9918\u516c\u7a4d": {}
},
"332-\u7279\u5225\u76c8\u9918\u516c\u7a4d": {
"3321-\u610f\u5916\u640d\u5931\u6e96\u5099": {},
"3322-\u6539\u826f\u64f4\u5145\u6e96\u5099": {},
"3323-\u511f\u50b5\u6e96\u5099": {},
"3328-\u5176\u4ed6\u7279\u5225\u76c8\u9918\u516c\u7a4d": {}
},
"335-\u672a\u5206\u914d\u76c8\u9918(\u7d2f\u7a4d\u8667\u640d) ": {
"is_group": 1
}
},
"34-\u6b0a\u76ca\u8abf\u6574": {
"341-\u9577\u671f\u80a1\u6b0a\u6295\u8cc7\u672a\u5be6\u73fe\u8dcc\u50f9\u640d\u5931": {
"3411-\u9577\u671f\u80a1\u6b0a\u6295\u8cc7\u672a\u5be6\u73fe\u8dcc\u50f9\u640d\u5931": {}
},
"342-\u7d2f\u7a4d\u63db\u7b97\u8abf\u6574\u6578": {
"3421-\u7d2f\u7a4d\u63db\u7b97\u8abf\u6574\u6578": {}
},
"343-\u672a\u8a8d\u5217\u70ba\u9000\u4f11\u91d1\u6210\u672c\u4e4b\u6de8\u640d\u5931": {
"3431-\u672a\u8a8d\u5217\u70ba\u9000\u4f11\u91d1\u6210\u672c\u4e4b\u6de8\u640d\u5931": {}
}
},
"35-\u5eab\u85cf\u80a1": {
"351-\u5eab\u85cf\u80a1": {
"3511-\u5eab\u85cf\u80a1": {}
}
},
"36-\u5c11\u6578\u80a1\u6b0a": {
"361-\u5c11\u6578\u80a1\u6b0a": {
"3611-\u5c11\u6578\u80a1\u6b0a": {}
}
},
"root_type": "Equity"
},
"4-\u71df\u696d\u6536\u5165": {
"41-\u92b7\u8ca8\u6536\u5165": {
"411-\u92b7\u8ca8\u6536\u5165": {
"4111-\u92b7\u8ca8\u6536\u5165": {},
"4112-\u5206\u671f\u4ed8\u6b3e\u92b7\u8ca8\u6536\u5165": {}
},
"417-\u92b7\u8ca8\u9000\u56de": {
"4171-\u92b7\u8ca8\u9000\u56de": {}
},
"419-\u92b7\u8ca8\u6298\u8b93": {
"4191-\u92b7\u8ca8\u6298\u8b93": {}
}
},
"46-\u52de\u52d9\u6536\u5165": {
"461-\u52de\u52d9\u6536\u5165": {
"4611-\u52de\u52d9\u6536\u5165": {}
}
},
"47-\u696d\u52d9\u6536\u5165": {
"471-\u696d\u52d9\u6536\u5165": {
"4711-\u696d\u52d9\u6536\u5165": {}
}
},
"48-\u5176\u4ed6\u71df\u696d\u6536\u5165": {
"488-\u5176\u4ed6\u71df\u696d\u6536\u5165\u2014\u5176\u4ed6": {
"4888-\u5176\u4ed6\u71df\u696d\u6536\u5165\u2014\u5176\u4ed6": {}
}
},
"root_type": "Income"
},
"5-\u71df\u696d\u6210\u672c": {
"51-\u92b7\u8ca8\u6210\u672c": {
"511-\u92b7\u8ca8\u6210\u672c": {
"5111-\u92b7\u8ca8\u6210\u672c": {
"account_type": "Cost of Goods Sold"
},
"5112-\u5206\u671f\u4ed8\u6b3e\u92b7\u8ca8\u6210\u672c": {
"account_type": "Cost of Goods Sold"
},
"account_type": "Cost of Goods Sold"
},
"512-\u9032\u8ca8": {
"5121-\u9032\u8ca8": {},
"5122-\u9032\u8ca8\u8cbb\u7528": {},
"5123-\u9032\u8ca8\u9000\u51fa": {},
"5124-\u9032\u8ca8\u6298\u8b93": {}
},
"513-\u9032\u6599": {
"5131-\u9032\u6599": {},
"5132-\u9032\u6599\u8cbb\u7528": {},
"5133-\u9032\u6599\u9000\u51fa": {},
"5134-\u9032\u6599\u6298\u8b93": {}
},
"514-\u76f4\u63a5\u4eba\u5de5": {
"5141-\u76f4\u63a5\u4eba\u5de5": {}
},
"515~518-\u88fd\u9020\u8cbb\u7528": {
"5151-\u9593\u63a5\u4eba\u5de5": {},
"5152-\u79df\u91d1\u652f\u51fa": {},
"5153-\u6587\u5177\u7528\u54c1": {},
"5154-\u65c5\u8cbb": {},
"5155-\u904b\u8cbb": {},
"5156-\u90f5\u96fb\u8cbb": {},
"5157-\u4fee\u7e55\u8cbb": {},
"5158-\u5305\u88dd\u8cbb": {},
"5161-\u6c34\u96fb\u74e6\u65af\u8cbb": {},
"5162-\u4fdd\u96aa\u8cbb": {},
"5163-\u52a0\u5de5\u8cbb": {},
"5166-\u7a05\u6350": {
"account_type": "Tax",
"tax_rate": 5.0
},
"5168-\u6298\u820a ": {
"account_type": "Depreciation"
},
"5169-\u5404\u9805\u8017\u7aed\u53ca\u6524\u63d0": {},
"5172-\u4f19\u98df\u8cbb": {},
"5173-\u8077\u5de5\u798f\u5229": {},
"5176-\u8a13\u7df4\u8cbb": {},
"5177-\u9593\u63a5\u6750\u6599": {},
"5188-\u5176\u4ed6\u88fd\u9020\u8cbb\u7528": {}
},
"Expenses Included In Valuation": {
"account_type": "Expenses Included In Valuation"
},
"account_type": "Cost of Goods Sold"
},
"56-\u52de\u52d9\u6210\u672c\u88fd": {
"561-\u52de\u52d9\u6210\u672c": {
"5611-\u52de\u52d9\u6210\u672c": {}
}
},
"57-\u696d\u52d9\u6210\u672c": {
"571-\u696d\u52d9\u6210\u672c": {
"5711-\u696d\u52d9\u6210\u672c": {}
}
},
"58-\u5176\u4ed6\u71df\u696d\u6210\u672c": {
"588-\u5176\u4ed6\u71df\u696d\u6210\u672c\u2014\u5176\u4ed6 ": {
"5888-\u5176\u4ed6\u71df\u696d\u6210\u672c\u2014\u5176\u4ed6": {}
}
},
"Stock Adjustment": {
"account_type": "Stock Adjustment"
},
"root_type": "Expense"
},
"6-\u71df\u696d\u8cbb\u7528": {
"61-\u63a8\u92b7\u8cbb\u7528": {
"615~618-\u63a8\u92b7\u8cbb\u7528": {
"6151-\u85aa\u8cc7\u652f\u51fa": {},
"6152-\u79df\u91d1\u652f\u51fa": {},
"6153-\u6587\u5177\u7528\u54c1": {},
"6154-\u65c5\u8cbb": {},
"6155-\u904b\u8cbb": {},
"6156-\u90f5\u96fb\u8cbb": {},
"6157-\u4fee\u7e55\u8cbb": {},
"6159-\u5ee3\u544a\u8cbb": {},
"6161-\u6c34\u96fb\u74e6\u65af\u8cbb": {},
"6162-\u4fdd\u96aa\u8cbb": {},
"6164-\u4ea4\u969b\u8cbb": {},
"6165-\u6350\u8d08": {},
"6166-\u7a05\u6350": {
"account_type": "Tax",
"tax_rate": 5.0
},
"6167-\u5446\u5e33\u640d\u5931": {},
"6168-\u6298\u820a ": {
"account_type": "Depreciation"
},
"6169-\u5404\u9805\u8017\u7aed\u53ca\u6524\u63d0": {},
"6172-\u4f19\u98df\u8cbb": {},
"6173-\u8077\u5de5\u798f\u5229": {},
"6175-\u4f63\u91d1\u652f\u51fa": {},
"6176-\u8a13\u7df4\u8cbb": {},
"6188-\u5176\u4ed6\u63a8\u92b7\u8cbb\u7528": {}
}
},
"62-\u7ba1\u7406\u53ca\u7e3d\u52d9\u8cbb\u7528": {
"625~628-\u7ba1\u7406\u53ca\u7e3d\u52d9\u8cbb\u7528": {
"6251-\u85aa\u8cc7\u652f\u51fa": {},
"6252-\u79df\u91d1\u652f\u51fa": {},
"6253-\u6587\u5177\u7528\u54c1": {},
"6254-\u65c5\u8cbb": {},
"6255-\u904b\u8cbb": {},
"6256-\u90f5\u96fb\u8cbb": {},
"6257-\u4fee\u7e55\u8cbb": {},
"6259-\u5ee3\u544a\u8cbb": {},
"6261-\u6c34\u96fb\u74e6\u65af\u8cbb": {},
"6262-\u4fdd\u96aa\u8cbb": {},
"6264-\u4ea4\u969b\u8cbb": {},
"6265-\u6350\u8d08": {},
"6266-\u7a05\u6350": {
"account_type": "Tax",
"tax_rate": 5.0
},
"6267-\u5446\u5e33\u640d\u5931": {},
"6268-\u6298\u820a": {
"account_type": "Depreciation"
},
"6269-\u5404\u9805\u8017\u7aed\u53ca\u6524\u63d0": {},
"6271-\u5916\u92b7\u640d\u5931": {},
"6272-\u4f19\u98df\u8cbb": {},
"6273-\u8077\u5de5\u798f\u5229": {},
"6274-\u7814\u7a76\u767c\u5c55\u8cbb\u7528": {},
"6275-\u4f63\u91d1\u652f\u51fa": {},
"6276-\u8a13\u7df4\u8cbb": {},
"6278-\u52de\u52d9\u8cbb": {},
"6288-\u5176\u4ed6\u7ba1\u7406\u53ca\u7e3d\u52d9\u8cbb\u7528": {}
}
},
"63-\u7814\u7a76\u767c\u5c55\u8cbb\u7528": {
"635~638-\u7814\u7a76\u767c\u5c55\u8cbb\u7528": {
"6351-\u85aa\u8cc7\u652f\u51fa": {},
"6352-\u79df\u91d1\u652f\u51fa": {},
"6353-\u6587\u5177\u7528\u54c1": {},
"6354-\u65c5\u8cbb": {},
"6355-\u904b\u8cbb": {},
"6356-\u90f5\u96fb\u8cbb": {},
"6357-\u4fee\u7e55\u8cbb": {},
"6361-\u6c34\u96fb\u74e6\u65af\u8cbb": {},
"6362-\u4fdd\u96aa\u8cbb": {},
"6364-\u4ea4\u969b\u8cbb": {},
"6366-\u7a05\u6350": {
"account_type": "Tax",
"tax_rate": 5.0
},
"6368-\u6298\u820a": {
"account_type": "Depreciation"
},
"6369-\u5404\u9805\u8017\u7aed\u53ca\u6524\u63d0": {},
"6372-\u4f19\u98df\u8cbb": {},
"6373-\u8077\u5de5\u798f\u5229": {},
"6376-\u8a13\u7df4\u8cbb": {},
"6378-\u5176\u4ed6\u7814\u7a76\u767c\u5c55\u8cbb\u7528": {}
}
},
"root_type": "Expense"
},
"7-\u71df\u696d\u5916\u6536\u5165\u53ca\u8cbb\u7528": {
"71~74-\u71df\u696d\u5916\u6536\u5165": {
"711-\u5229\u606f\u6536\u5165": {
"7111-\u5229\u606f\u6536\u5165": {}
},
"712-\u6295\u8cc7\u6536\u76ca": {
"7121-\u6b0a\u76ca\u6cd5\u8a8d\u5217\u4e4b\u6295\u8cc7\u6536\u76ca": {},
"7122-\u80a1\u5229\u6536\u5165": {},
"7123-\u77ed\u671f\u6295\u8cc7\u5e02\u50f9\u56de\u5347\u5229\u76ca": {}
},
"713-\u514c\u63db\u5229\u76ca": {
"7131-\u514c\u63db\u5229\u76ca": {}
},
"714-\u8655\u5206\u6295\u8cc7\u6536\u76ca": {
"7141-\u8655\u5206\u6295\u8cc7\u6536\u76ca": {}
},
"715-\u8655\u5206\u8cc7\u7522\u6ea2\u50f9\u6536\u5165": {
"7151-\u8655\u5206\u8cc7\u7522\u6ea2\u50f9\u6536\u5165": {}
},
"748-\u5176\u4ed6\u71df\u696d\u5916\u6536\u5165": {
"7481-\u6350\u8d08\u6536\u5165": {},
"7482-\u79df\u91d1\u6536\u5165": {},
"7483-\u4f63\u91d1\u6536\u5165": {},
"7484-\u51fa\u552e\u4e0b\u8173\u53ca\u5ee2\u6599\u6536\u5165": {},
"7485-\u5b58\u8ca8\u76e4\u76c8": {},
"7486-\u5b58\u8ca8\u8dcc\u50f9\u56de\u5347\u5229\u76ca": {},
"7487-\u58de\u5e33\u8f49\u56de\u5229\u76ca": {},
"7488-\u5176\u4ed6\u71df\u696d\u5916\u6536\u5165\u2014\u5176\u4ed6": {}
}
},
"75~78-\u71df\u696d\u5916\u8cbb\u7528": {
"751-\u5229\u606f\u8cbb\u7528": {
"7511-\u5229\u606f\u8cbb\u7528": {}
},
"752-\u6295\u8cc7\u640d\u5931": {
"7521-\u6b0a\u76ca\u6cd5\u8a8d\u5217\u4e4b\u6295\u8cc7\u640d\u5931": {},
"7523-\u77ed\u671f\u6295\u8cc7\u672a\u5be6\u73fe\u8dcc\u50f9\u640d\u5931": {}
},
"753-\u514c\u63db\u640d\u5931": {
"7531-\u514c\u63db\u640d\u5931": {}
},
"754-\u8655\u5206\u6295\u8cc7\u640d\u5931": {
"7541-\u8655\u5206\u6295\u8cc7\u640d\u5931": {}
},
"755-\u8655\u5206\u8cc7\u7522\u640d\u5931": {
"7551-\u8655\u5206\u8cc7\u7522\u640d\u5931 ": {}
},
"788-\u5176\u4ed6\u71df\u696d\u5916\u8cbb\u7528": {
"7881-\u505c\u5de5\u640d\u5931": {},
"7882-\u707d\u5bb3\u640d\u5931": {},
"7885-\u5b58\u8ca8\u76e4\u640d": {},
"7886-\u5b58\u8ca8\u8dcc\u50f9\u53ca\u5446\u6eef\u640d\u5931": {},
"7888-\u5176\u4ed6\u71df\u696d\u5916\u8cbb\u7528\u2014\u5176\u4ed6": {}
}
},
"root_type": "Income"
},
"8-\u6240\u5f97\u7a05\u8cbb\u7528(\u5229\u76ca)": {
"81-\u6240\u5f97\u7a05\u8cbb\u7528(\u5229\u76ca)": {
"811-\u6240\u5f97\u7a05\u8cbb\u7528(\u5229\u76ca) ": {
"8111-\u6240\u5f97\u7a05\u8cbb\u7528(\u5229\u76ca) ": {}
}
},
"root_type": "Expense"
},
"9-\u975e\u7d93\u5e38\u71df\u696d\u640d\u76ca": {
"91-\u505c\u696d\u90e8\u9580\u640d\u76ca": {
"911-\u505c\u696d\u90e8\u9580\u640d\u76ca\u2014\u505c\u696d\u524d\u71df\u696d\u640d\u76ca": {
"9111-\u505c\u696d\u90e8\u9580\u640d\u76ca\u2014\u505c\u696d\u524d\u71df\u696d\u640d\u76ca": {}
},
"912-\u505c\u696d\u90e8\u9580\u640d\u76ca\u2014\u8655\u5206\u640d\u76ca": {
"9121-\u505c\u696d\u90e8\u9580\u640d\u76ca\u2014\u8655\u5206\u640d\u76ca": {}
}
},
"92-\u975e\u5e38\u640d\u76ca": {
"921-\u975e\u5e38\u640d\u76ca": {
"9211-\u975e\u5e38\u640d\u76ca": {}
}
},
"93-\u6703\u8a08\u539f\u5247\u8b8a\u52d5\u7d2f\u7a4d\u5f71\u97ff\u6578": {
"931-\u6703\u8a08\u539f\u5247\u8b8a\u52d5\u7d2f\u7a4d\u5f71\u97ff\u6578": {
"9311-\u6703\u8a08\u539f\u5247\u8b8a\u52d5\u7d2f\u7a4d\u5f71\u97ff\u6578": {}
}
},
"94-\u5c11\u6578\u80a1\u6b0a\u6de8\u5229": {
"941-\u5c11\u6578\u80a1\u6b0a\u6de8\u5229": {
"9411-\u5c11\u6578\u80a1\u6b0a\u6de8\u5229": {}
}
},
"root_type": "Expense"
}
}
}

View File

@ -0,0 +1,22 @@
QUnit.module('Account');
QUnit.test("test Bank Reconciliation", function(assert) {
assert.expect(0);
let done = assert.async();
frappe.run_serially([
() => frappe.set_route('Form', 'Bank Reconciliation'),
() => cur_frm.set_value('bank_account','Cash - FT'),
() => frappe.click_button('Get Payment Entries'),
() => {
for(var i=0;i<=cur_frm.doc.payment_entries.length-1;i++){
cur_frm.doc.payment_entries[i].clearance_date = frappe.datetime.add_days(frappe.datetime.now_date(), 2);
}
},
() => {cur_frm.refresh_fields('payment_entries');},
() => frappe.click_button('Update Clearance Date'),
() => frappe.timeout(0.5),
() => frappe.click_button('Close'),
() => done()
]);
});

View File

@ -0,0 +1,39 @@
QUnit.module('Journal Entry');
QUnit.test("test journal entry", function(assert) {
assert.expect(2);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Journal Entry', [
{posting_date:frappe.datetime.add_days(frappe.datetime.nowdate(), 0)},
{accounts: [
[
{'account':'Debtors - '+frappe.get_abbr(frappe.defaults.get_default('Company'))},
{'party_type':'Customer'},
{'party':'Test Customer 1'},
{'credit_in_account_currency':1000},
{'is_advance':'Yes'},
],
[
{'account':'HDFC - '+frappe.get_abbr(frappe.defaults.get_default('Company'))},
{'debit_in_account_currency':1000},
]
]},
{cheque_no:1234},
{cheque_date: frappe.datetime.add_days(frappe.datetime.nowdate(), -1)},
{user_remark: 'Test'},
]);
},
() => cur_frm.save(),
() => {
// get_item_details
assert.ok(cur_frm.doc.total_debit==1000, "total debit correct");
assert.ok(cur_frm.doc.total_credit==1000, "total credit correct");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),
() => done()
]);
});

View File

@ -579,7 +579,7 @@ frappe.ui.form.on('Payment Entry', {
} }
var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding; var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding;
} else { } else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) {
if(paid_amount > total_negative_outstanding) { if(paid_amount > total_negative_outstanding) {
if(total_negative_outstanding == 0) { if(total_negative_outstanding == 0) {
frappe.msgprint(__("Cannot {0} {1} {2} without any negative outstanding invoice", frappe.msgprint(__("Cannot {0} {1} {2} without any negative outstanding invoice",

View File

@ -0,0 +1,29 @@
QUnit.module('Accounts');
QUnit.test("test payment entry", function(assert) {
assert.expect(1);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Payment Entry', [
{payment_type:'Receive'},
{mode_of_payment:'Cash'},
{party_type:'Customer'},
{party:'Test Customer 3'},
{paid_amount:675},
{reference_no:123},
{reference_date: frappe.datetime.add_days(frappe.datetime.nowdate(), 0)},
]);
},
() => cur_frm.save(),
() => {
// get_item_details
assert.ok(cur_frm.doc.total_allocated_amount==675, "Allocated AmountCorrect");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),
() => done()
]);
});

View File

@ -0,0 +1,52 @@
QUnit.module('Sales Invoice');
QUnit.test("test sales Invoice with payment request", function(assert) {
assert.expect(4);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Sales Invoice', [
{customer: 'Test Customer 1'},
{items: [
[
{'qty': 5},
{'item_code': 'Test Product 1'},
]
]},
{update_stock:1},
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'},
{taxes_and_charges: 'TEST In State GST'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'}
]);
},
() => cur_frm.save(),
() => {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
// grand_total Calculated
assert.ok(cur_frm.doc.grand_total==590, "Grad Total correct");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(2),
() => frappe.tests.click_button('Close'),
() => frappe.tests.click_button('Make'),
() => frappe.tests.click_link('Payment Request'),
() => frappe.timeout(0.2),
() => { cur_frm.set_value('print_format','GST Tax Invoice');},
() => { cur_frm.set_value('email_to','test@gmail.com');},
() => cur_frm.save(),
() => {
// get payment details
assert.ok(cur_frm.doc.grand_total==590, "grand total Correct");
},
() => done()
]);
});

View File

@ -54,13 +54,15 @@ class ShippingRule(Document):
d.idx = i + 1 d.idx = i + 1
def validate_overlapping_shipping_rule_conditions(self): def validate_overlapping_shipping_rule_conditions(self):
def overlap_exists_between((x1, x2), (y1, y2)): def overlap_exists_between(num_range1, num_range2):
""" """
(x1, x2) and (y1, y2) are two ranges num_range1 and num_range2 are two ranges
if condition x = 100 to 300 ranges are represented as a tuple e.g. range 100 to 300 is represented as (100, 300)
then condition y can only be like 50 to 99 or 301 to 400 if condition num_range1 = 100 to 300
then condition num_range2 can only be like 50 to 99 or 301 to 400
hence, non-overlapping condition = (x1 <= x2 < y1 <= y2) or (y1 <= y2 < x1 <= x2) hence, non-overlapping condition = (x1 <= x2 < y1 <= y2) or (y1 <= y2 < x1 <= x2)
""" """
(x1, x2), (y1, y2) = num_range1, num_range2
separate = (x1 <= x2 <= y1 <= y2) or (y1 <= y2 <= x1 <= x2) separate = (x1 <= x2 <= y1 <= y2) or (y1 <= y2 <= x1 <= x2)
return (not separate) return (not separate)

View File

@ -10,15 +10,15 @@
<thead> <thead>
<tr> <tr>
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %} {% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
<th style="width: 15%">{%= __("Date") %}</th> <th style="width: 14%">{%= __("Date") %}</th>
<th style="width: 15%">{%= __("Ref") %}</th> <th style="width: 16%">{%= __("Ref") %}</th>
<th style="width: 40%">{%= __("Party") %}</th> <th style="width: 30%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
<th style="width: 15%">{%= __("Invoiced Amount") %}</th> <th style="width: 10%">{%= __("Invoiced Amount") %}</th>
<th style="width: 15%">{%= __("Paid Amount") %}</th> <th style="width: 10%">{%= __("Paid Amount") %}</th>
<th style="width: 15%">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th> <th style="width: 10%">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
<th style="width: 15%">{%= __("Outstanding Amount") %}</th> <th style="width: 10%">{%= __("Outstanding Amount") %}</th>
{% } else { %} {% } else { %}
<th style="width: 40%">{%= __("Party") %}</th> <th style="width: 40%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
<th style="width: 15%">{%= __("Total Invoiced Amount") %}</th> <th style="width: 15%">{%= __("Total Invoiced Amount") %}</th>
<th style="width: 15%">{%= __("Total Paid Amount") %}</th> <th style="width: 15%">{%= __("Total Paid Amount") %}</th>
<th style="width: 15%">{%= report.report_name === "Accounts Receivable Summary" ? __('Credit Note Amount') : __('Debit Note Amount') %}</th> <th style="width: 15%">{%= report.report_name === "Accounts Receivable Summary" ? __('Credit Note Amount') : __('Debit Note Amount') %}</th>
@ -34,8 +34,12 @@
<td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td> <td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td>
<td>{%= data[i][__("Voucher Type")] %} <td>{%= data[i][__("Voucher Type")] %}
<br>{%= data[i][__("Voucher No")] %}</td> <br>{%= data[i][__("Voucher No")] %}</td>
<td>{%= data[i][__("Customer Name")] || data[i][__("Customer")] || data[i][__("Supplier Name")] || data[i][__("Supplier")] %} <td>
<br>{%= __("Remarks") %}: {%= data[i][__("Remarks")] %}</td> {% if(!(filters.customer || filters.supplier)) { %}
{%= data[i][__("Customer Name")] || data[i][__("Customer")] || data[i][__("Supplier Name")] || data[i][__("Supplier")] %}<br>{%= __("Remarks") %}:
{% } %}
{%= data[i][__("Remarks")] %}
</td>
<td style="text-align: right"> <td style="text-align: right">
{%= format_currency(data[i]["Invoiced Amount"], data[i]["currency"]) %}</td> {%= format_currency(data[i]["Invoiced Amount"], data[i]["currency"]) %}</td>
<td style="text-align: right"> <td style="text-align: right">
@ -59,8 +63,13 @@
{% } else { %} {% } else { %}
{% if(data[i][__("Customer")] || data[i][__("Supplier")]|| "&nbsp;") { %} {% if(data[i][__("Customer")] || data[i][__("Supplier")]|| "&nbsp;") { %}
{% if((data[i][__("Customer")] || data[i][__("Supplier")]) != __("'Total'")) { %} {% if((data[i][__("Customer")] || data[i][__("Supplier")]) != __("'Total'")) { %}
<td>{%= data[i][__("Customer")] || data[i][__("Supplier")] %} <td>
<br>{%= __("Remarks") %}: {%= data[i][__("Remarks")] %}</td> {% if(!(filters.customer || filters.supplier)) { %}
{%= data[i][__("Customer")] || data[i][__("Supplier")] %}
<br>{%= __("Remarks") %}:
{% } %}
{%= data[i][__("Remarks")] %}
</td>
{% } else { %} {% } else { %}
<td><b>{%= __("Total") %}</b></td> <td><b>{%= __("Total") %}</b></td>
{% } %} {% } %}

View File

@ -7,7 +7,7 @@ frappe.query_reports["Item-wise Purchase Register"] = {
"fieldname":"from_date", "fieldname":"from_date",
"label": __("From Date"), "label": __("From Date"),
"fieldtype": "Date", "fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_start_date"), "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
"width": "80" "width": "80"
}, },
{ {

View File

@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
from frappe import _ from frappe import _
from frappe.utils import flt from frappe.utils import flt
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import get_tax_accounts from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import get_tax_accounts
@ -14,10 +14,12 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
if not filters: filters = {} if not filters: filters = {}
columns = get_columns(additional_table_columns) columns = get_columns(additional_table_columns)
company_currency = erpnext.get_company_currency(filters.company)
item_list = get_items(filters, additional_query_columns) item_list = get_items(filters, additional_query_columns)
aii_account_map = get_aii_accounts() aii_account_map = get_aii_accounts()
if item_list: if item_list:
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges") doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges")
columns.append({ columns.append({
@ -26,7 +28,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
"fieldtype": "Data", "fieldtype": "Data",
"width": 80 "width": 80
}) })
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
po_pr_map = get_purchase_receipts_against_purchase_order(item_list) po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
data = [] data = []
@ -125,6 +127,7 @@ def get_purchase_receipts_against_purchase_order(item_list):
po_pr_map = frappe._dict() po_pr_map = frappe._dict()
po_item_rows = list(set([d.po_detail for d in item_list])) po_item_rows = list(set([d.po_detail for d in item_list]))
if po_item_rows:
purchase_receipts = frappe.db.sql(""" purchase_receipts = frappe.db.sql("""
select parent, purchase_order_item select parent, purchase_order_item
from `tabPurchase Receipt Item` from `tabPurchase Receipt Item`

View File

@ -7,7 +7,7 @@ frappe.query_reports["Item-wise Sales Register"] = frappe.query_reports["Sales R
"fieldname":"from_date", "fieldname":"from_date",
"label": __("From Date"), "label": __("From Date"),
"fieldtype": "Date", "fieldtype": "Date",
"default": frappe.defaults.get_default("year_start_date"), "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
"width": "80" "width": "80"
}, },
{ {

View File

@ -2,9 +2,10 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
from frappe import _ from frappe import _
from frappe.utils import flt from frappe.utils import flt
from frappe.model.meta import get_field_precision
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
def execute(filters=None): def execute(filters=None):
@ -14,16 +15,17 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
if not filters: filters = {} if not filters: filters = {}
columns = get_columns(additional_table_columns) columns = get_columns(additional_table_columns)
company_currency = erpnext.get_company_currency(filters.company)
item_list = get_items(filters, additional_query_columns) item_list = get_items(filters, additional_query_columns)
if item_list: if item_list:
itemised_tax, tax_columns = get_tax_accounts(item_list, columns) itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
columns.append({ columns.append({
"fieldname": "currency", "fieldname": "currency",
"label": _("Currency"), "label": _("Currency"),
"fieldtype": "Data", "fieldtype": "Data",
"width": 80 "width": 80
}) })
company_currency = frappe.db.get_value("Company", filters.get("company"), "default_currency")
mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list])) mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list]))
so_dn_map = get_delivery_notes_against_sales_order(item_list) so_dn_map = get_delivery_notes_against_sales_order(item_list)
@ -127,6 +129,7 @@ def get_delivery_notes_against_sales_order(item_list):
so_dn_map = frappe._dict() so_dn_map = frappe._dict()
so_item_rows = list(set([d.so_detail for d in item_list])) so_item_rows = list(set([d.so_detail for d in item_list]))
if so_item_rows:
delivery_notes = frappe.db.sql(""" delivery_notes = frappe.db.sql("""
select parent, so_detail select parent, so_detail
from `tabDelivery Note Item` from `tabDelivery Note Item`
@ -139,16 +142,25 @@ def get_delivery_notes_against_sales_order(item_list):
return so_dn_map return so_dn_map
def get_tax_accounts(item_list, columns, doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"): def get_tax_accounts(item_list, columns, company_currency,
doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
import json import json
item_row_map = {} item_row_map = {}
tax_columns = [] tax_columns = []
invoice_item_row = {} invoice_item_row = {}
itemised_tax = {} itemised_tax = {}
tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field("tax_amount"),
currency=company_currency) or 2
for d in item_list: for d in item_list:
invoice_item_row.setdefault(d.parent, []).append(d) invoice_item_row.setdefault(d.parent, []).append(d)
item_row_map.setdefault(d.parent, {}).setdefault(d.item_code, []).append(d) item_row_map.setdefault(d.parent, {}).setdefault(d.item_code, []).append(d)
conditions = ""
if doctype == "Purchase Invoice":
conditions = " and category in ('Total', 'Valuation and Total')"
tax_details = frappe.db.sql(""" tax_details = frappe.db.sql("""
select select
parent, description, item_wise_tax_detail, parent, description, item_wise_tax_detail,
@ -158,8 +170,9 @@ def get_tax_accounts(item_list, columns, doctype="Sales Invoice", tax_doctype="S
parenttype = %s and docstatus = 1 parenttype = %s and docstatus = 1
and (description is not null and description != '') and (description is not null and description != '')
and parent in (%s) and parent in (%s)
%s
order by description order by description
""" % (tax_doctype, '%s', ', '.join(['%s']*len(invoice_item_row))), """ % (tax_doctype, '%s', ', '.join(['%s']*len(invoice_item_row)), conditions),
tuple([doctype] + invoice_item_row.keys())) tuple([doctype] + invoice_item_row.keys()))
for parent, description, item_wise_tax_detail, charge_type, tax_amount in tax_details: for parent, description, item_wise_tax_detail, charge_type, tax_amount in tax_details:
@ -191,7 +204,7 @@ def get_tax_accounts(item_list, columns, doctype="Sales Invoice", tax_doctype="S
if item_tax_amount: if item_tax_amount:
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({ itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
"tax_rate": tax_rate, "tax_rate": tax_rate,
"tax_amount": item_tax_amount "tax_amount": flt(item_tax_amount, tax_amount_precision)
}) })
except ValueError: except ValueError:
@ -200,7 +213,8 @@ def get_tax_accounts(item_list, columns, doctype="Sales Invoice", tax_doctype="S
for d in invoice_item_row.get(parent, []): for d in invoice_item_row.get(parent, []):
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({ itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
"tax_rate": "NA", "tax_rate": "NA",
"tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total) "tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total,
tax_amount_precision)
}) })
tax_columns.sort() tax_columns.sort()

View File

@ -7,7 +7,7 @@ frappe.query_reports["Purchase Register"] = {
"fieldname":"from_date", "fieldname":"from_date",
"label": __("From Date"), "label": __("From Date"),
"fieldtype": "Date", "fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_start_date"), "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
"width": "80" "width": "80"
}, },
{ {

View File

@ -7,7 +7,7 @@ frappe.query_reports["Sales Register"] = {
"fieldname":"from_date", "fieldname":"from_date",
"label": __("From Date"), "label": __("From Date"),
"fieldtype": "Date", "fieldtype": "Date",
"default": frappe.defaults.get_default("year_start_date"), "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
"width": "80" "width": "80"
}, },
{ {

View File

@ -70,8 +70,8 @@ def get_data():
"items": [ "items": [
{ {
"type": "doctype", "type": "doctype",
"name": "BOM Replace Tool", "name": "BOM Update Tool",
"description": _("Replace Item / BOM in all BOMs"), "description": _("Replace BOM and update latest price in all BOMs"),
}, },
] ]
}, },

View File

@ -370,28 +370,27 @@ def warehouse_query(doctype, txt, searchfield, start, page_len, filters):
bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"), bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"),
bin_conditions, ignore_permissions=True)) bin_conditions, ignore_permissions=True))
response = frappe.db.sql("""select `tabWarehouse`.name, query = """select `tabWarehouse`.name,
CONCAT_WS(" : ", "Actual Qty", ifnull( ({sub_query}), 0) ) as actual_qty CONCAT_WS(" : ", "Actual Qty", ifnull( ({sub_query}), 0) ) as actual_qty
from `tabWarehouse` from `tabWarehouse`
where where
`tabWarehouse`.`{key}` like %(txt)s `tabWarehouse`.`{key}` like '{txt}'
{fcond} {mcond} {fcond} {mcond}
order by order by
`tabWarehouse`.name desc `tabWarehouse`.name desc
limit limit
%(start)s, %(page_len)s {start}, {page_len}
""".format( """.format(
sub_query=sub_query, sub_query=sub_query,
key=frappe.db.escape(searchfield), key=frappe.db.escape(searchfield),
fcond=get_filters_cond(doctype, filter_dict.get("Warehouse"), conditions), fcond=get_filters_cond(doctype, filter_dict.get("Warehouse"), conditions),
mcond=get_match_cond(doctype) mcond=get_match_cond(doctype),
), start=start,
{ page_len=page_len,
"txt": "%%%s%%" % frappe.db.escape(txt), txt=frappe.db.escape('%{0}%'.format(txt))
"start": start, )
"page_len": page_len
}) return frappe.db.sql(query)
return response
def get_doctype_wise_filters(filters): def get_doctype_wise_filters(filters):

View File

@ -270,7 +270,7 @@ class calculate_taxes_and_totals(object):
if tax.item_wise_tax_detail.get(key): if tax.item_wise_tax_detail.get(key):
item_wise_tax_amount += tax.item_wise_tax_detail[key][1] item_wise_tax_amount += tax.item_wise_tax_detail[key][1]
tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount, tax.precision("base_tax_amount"))] tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount)]
def round_off_totals(self, tax): def round_off_totals(self, tax):
tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount")) tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount"))
@ -521,12 +521,20 @@ def get_itemised_tax_breakup_html(doc):
frappe.flags.company = doc.company frappe.flags.company = doc.company
# get headers # get headers
tax_accounts = list(set([d.description for d in doc.taxes])) tax_accounts = []
for tax in doc.taxes:
if getattr(tax, "category", None) and tax.category=="Valuation":
continue
if tax.description not in tax_accounts:
tax_accounts.append(tax.description)
headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts) headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts)
# get tax breakup data # get tax breakup data
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(doc) itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(doc)
get_rounded_tax_amount(itemised_tax, doc.precision("tax_amount", "taxes"))
frappe.flags.company = None frappe.flags.company = None
return frappe.render_template( return frappe.render_template(
@ -554,6 +562,9 @@ def get_itemised_tax_breakup_data(doc):
def get_itemised_tax(taxes): def get_itemised_tax(taxes):
itemised_tax = {} itemised_tax = {}
for tax in taxes: for tax in taxes:
if getattr(tax, "category", None) and tax.category=="Valuation":
continue
tax_amount_precision = tax.precision("tax_amount") tax_amount_precision = tax.precision("tax_amount")
tax_rate_precision = tax.precision("rate") tax_rate_precision = tax.precision("rate")
@ -562,16 +573,16 @@ def get_itemised_tax(taxes):
for item_code, tax_data in item_tax_map.items(): for item_code, tax_data in item_tax_map.items():
itemised_tax.setdefault(item_code, frappe._dict()) itemised_tax.setdefault(item_code, frappe._dict())
if isinstance(tax_data, list) and tax_data[0]: if isinstance(tax_data, list):
precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision
itemised_tax[item_code][tax.description] = frappe._dict(dict( itemised_tax[item_code][tax.description] = frappe._dict(dict(
tax_rate=flt(tax_data[0], precision), tax_rate=flt(tax_data[0]),
tax_amount=flt(tax_data[1], tax_amount_precision) tax_amount=flt(tax_data[1])
)) ))
else: else:
itemised_tax[item_code][tax.description] = frappe._dict(dict( itemised_tax[item_code][tax.description] = frappe._dict(dict(
tax_rate=flt(tax_data, tax_rate_precision), tax_rate=flt(tax_data),
tax_amount=0.0 tax_amount=0.0
)) ))
@ -585,3 +596,9 @@ def get_itemised_taxable_amount(items):
itemised_taxable_amount[item_code] += item.net_amount itemised_taxable_amount[item_code] += item.net_amount
return itemised_taxable_amount return itemised_taxable_amount
def get_rounded_tax_amount(itemised_tax, precision):
# Rounding based on tax_amount precision
for taxes in itemised_tax.values():
for tax_account in taxes:
taxes[tax_account]["tax_amount"] = flt(taxes[tax_account]["tax_amount"], precision)

View File

@ -76,36 +76,6 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "salutation",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Salutation",
"length": 0,
"no_copy": 0,
"options": "Salutation",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -141,21 +111,21 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "gender", "fieldname": "company_name",
"fieldtype": "Link", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Gender", "label": "Organization Name",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Gender", "oldfieldname": "company_name",
"oldfieldtype": "Data",
"permlevel": 0, "permlevel": 0,
"precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
@ -260,6 +230,37 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "gender",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Gender",
"length": 0,
"no_copy": 0,
"options": "Gender",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -295,36 +296,6 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Organization Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "company_name",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -435,6 +406,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Follow Up",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -514,11 +486,12 @@
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 1,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "contact_by", "description": "",
"fieldtype": "Link", "fieldname": "contact_date",
"fieldtype": "Datetime",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -526,12 +499,11 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Next Contact By", "label": "Next Contact Date",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 1,
"oldfieldname": "contact_by", "oldfieldname": "contact_date",
"oldfieldtype": "Link", "oldfieldtype": "Date",
"options": "User",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
@ -550,9 +522,8 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Add to calendar on this date", "fieldname": "contact_by",
"fieldname": "contact_date", "fieldtype": "Link",
"fieldtype": "Datetime",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -560,11 +531,12 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Next Contact Date", "label": "Next Contact By",
"length": 0, "length": 0,
"no_copy": 1, "no_copy": 0,
"oldfieldname": "contact_date", "oldfieldname": "contact_by",
"oldfieldtype": "Date", "oldfieldtype": "Link",
"options": "User",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
@ -726,6 +698,37 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "salutation",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Salutation",
"length": 0,
"no_copy": 0,
"options": "Salutation",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -1144,7 +1147,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-06-22 14:29:12.700000", "modified": "2017-08-21 02:28:21.581948",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Lead", "name": "Lead",

View File

@ -419,6 +419,164 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible_depends_on": "contact_by",
"columns": 0,
"fieldname": "next_contact",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Follow Up",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "contact_by",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Next Contact By",
"length": 0,
"no_copy": 0,
"oldfieldname": "contact_by",
"oldfieldtype": "Link",
"options": "User",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "75px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "contact_date",
"fieldtype": "Datetime",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Next Contact Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "contact_date",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "to_discuss",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "To Discuss",
"length": 0,
"no_copy": 1,
"oldfieldname": "to_discuss",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -435,7 +593,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "", "label": "Items",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
@ -986,164 +1144,6 @@
"unique": 0, "unique": 0,
"width": "50px" "width": "50px"
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible_depends_on": "contact_by",
"columns": 0,
"fieldname": "next_contact",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Next Contact",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Your sales person who will contact the customer in future",
"fieldname": "contact_by",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Next Contact By",
"length": 0,
"no_copy": 0,
"oldfieldname": "contact_by",
"oldfieldtype": "Link",
"options": "User",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "75px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Your sales person will get a reminder on this date to contact the customer",
"fieldname": "contact_date",
"fieldtype": "Datetime",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Next Contact Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "contact_date",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "to_discuss",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "To Discuss",
"length": 0,
"no_copy": 1,
"oldfieldname": "to_discuss",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -1189,7 +1189,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-08-07 21:25:10.836517", "modified": "2017-08-21 02:07:46.486433",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Opportunity", "name": "Opportunity",

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import random, json import random, json
import frappe, erpnext import frappe, erpnext
@ -42,7 +42,7 @@ def setup(domain):
frappe.clear_cache() frappe.clear_cache()
def complete_setup(domain='Manufacturing'): def complete_setup(domain='Manufacturing'):
print "Complete Setup..." print("Complete Setup...")
from frappe.desk.page.setup_wizard.setup_wizard import setup_complete from frappe.desk.page.setup_wizard.setup_wizard import setup_complete
if not frappe.get_all('Company', limit=1): if not frappe.get_all('Company', limit=1):

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe, random import frappe, random
from frappe.desk import query_report from frappe.desk import query_report
@ -36,7 +36,7 @@ def make_purchase_receipt():
try: try:
pr.submit() pr.submit()
except NegativeStockError: except NegativeStockError:
print 'Negative stock for {0}'.format(po) print('Negative stock for {0}'.format(po))
pass pass
frappe.db.commit() frappe.db.commit()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -1,44 +0,0 @@
# BOM Replace Tool
Replace BOM is the utility to replace BOM of sub-assembly item, which is already updated in the BOM of Finished Good item.
To use the Production Planning Tool, go to:
> Manufacturing > Tools > BOM Replace Tool
Let's consider a scenario to understand this better.
If company manufactures computers, Bill of Material of its finished item will constitute of:
1. Monitor
1. Key Board
1. Mouse
1. CPU
Out of all the items above, CPU is asembled separately. Hence separate BOM will be created for the CPU. Following are the items from the BOM of CPU.
1. 250 GB Hard Disk
1. Mother Board
1. Processor
1. SMTP
1. DVD player
If we have more items to be added , or existing items to be edited in the BOM of CPU, then we should create new BOM for it.
1. _350 GB Hard Disk_
1. Mother Board
1. Processor
1. SMTP
1. DVD player
To update new BOM updated in the BOM of finished item, where CPU is selected as raw-material, you can use BOM Replace tool.
<img class="screenshot" alt="BOM replace Tool" src="/docs/assets/img/manufacturing/bom-replace-tool.png">
In this tool, you should select Current BOM, and New BOM. On clicking Replace button, current BOM of CPU will be replaced with New BOM in the BOM of finished Item (Computer).
**Will BOM Replace Tool work for replacing finsihed item in BOM?**
No. You should Cancel and Amend current BOM, or create a new BOM for finished item.
{next}

View File

@ -0,0 +1,54 @@
# BOM Update Tool
From BOM Update Tool, you can replace a sub-assembly BOM and update costs of all BOMs.
### Replace BOM
Using this utility, you can replace an existing BOM of sub-assembly item, with a new one. The system will update the new BOM in all the parent BOMs where it was used.
To use the BOM Update Tool, go to:
> Manufacturing > Tools > BOM Update Tool
Let's consider a scenario to understand this better.
Suppose a company manufactures computers, Bill of Material of of the computer will look like this:
1. Monitor
1. Key Board
1. Mouse
1. CPU
Out of all the items above, CPU is asembled separately. Hence separate BOM will be created for the CPU. Following are the items from the BOM of CPU.
1. 250 GB Hard Disk
1. Mother Board
1. Processor
1. SMTP
1. DVD player
If we have more items to be added , or existing items to be edited in the BOM of CPU, then we should create new BOM for it.
1. _350 GB Hard Disk_
1. Mother Board
1. Processor
1. SMTP
1. DVD player
To update new BOM in all the parent BOMs, where CPU is selected as raw-material, you can use Replace utility.
<img class="screenshot" alt="BOM Update Tool" src="{{docs_base_url}}/assets/img/manufacturing/bom-update-tool.png">
In this tool, you should select Current BOM, and New BOM. On clicking Replace button, current BOM of CPU will be replaced with New BOM in the BOM of finished Item (Computer).
**Will BOM Replace Tool work for replacing finsihed item in BOM?**
No. You should Cancel and Amend current BOM, or create a new BOM for finished item.
### Update BOM Cost
Using the button **Update latest price in all BOMs**, you can update cost of all Bill of Materials, based on latest purchase price / price list rate / valuation rate of raw materials.
On clicking of this buttom, system will create a background process to update all the BOM's cost. It is processed via background jobs because this process can take a few minutes (depending on the number of BOMs) to update all the BOMs.
This functionality can also be executed automatically on daily basis. For that, you need to enable "Update BOM Cost Automatically" from Manufacturing Settings.
{next}

View File

@ -1,2 +1,2 @@
production-planning-tool production-planning-tool
bom-replace-tool bom-update-tool

View File

@ -196,7 +196,8 @@ scheduler_events = {
"erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.send_summary", "erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.send_summary",
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status", "erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status",
"erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards", "erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards",
"erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history" "erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history",
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms",
] ]
} }

View File

@ -0,0 +1,58 @@
QUnit.module('hr');
QUnit.test("Test: Expense Claim [HR]", function (assert) {
assert.expect(3);
let done = assert.async();
let employee_name;
frappe.run_serially([
// Creating Appraisal
() => frappe.set_route('List','Appraisal','List'),
() => frappe.timeout(0.3),
() => frappe.click_button('Make a new Appraisal'),
() => {
cur_frm.set_value('kra_template','Test Appraisal 1'),
cur_frm.set_value('start_date','2017-08-21'),
cur_frm.set_value('end_date','2017-09-21');
},
() => frappe.timeout(1),
() => frappe.model.set_value('Appraisal Goal','New Appraisal Goal 1','score',4),
() => frappe.model.set_value('Appraisal Goal','New Appraisal Goal 1','score_earned',2),
() => frappe.model.set_value('Appraisal Goal','New Appraisal Goal 2','score',4),
() => frappe.model.set_value('Appraisal Goal','New Appraisal Goal 2','score_earned',2),
() => frappe.timeout(1),
() => frappe.db.get_value('Employee', {'employee_name': 'Test Employee 1'}, 'name'),
(r) => {
employee_name = r.message.name;
},
() => frappe.timeout(1),
() => cur_frm.set_value('employee',employee_name),
() => cur_frm.set_value('employee_name','Test Employee 1'),
() => cur_frm.set_value('company','Test Company'),
() => frappe.click_button('Calculate Total Score'),
() => frappe.timeout(1),
() => cur_frm.save(),
() => frappe.timeout(1),
() => cur_frm.save(),
// Submitting the Appraisal
() => frappe.click_button('Submit'),
() => frappe.click_button('Yes'),
() => frappe.timeout(3),
// Checking if the appraisal is correctly set for the employee
() => {
assert.equal('Submitted',cur_frm.get_field('status').value,
'Appraisal is submitted');
assert.equal('Test Employee 1',cur_frm.get_field('employee_name').value,
'Appraisal is created for correct employee');
assert.equal(4,cur_frm.get_field('total_score').value,
'Total score is correctly calculated');
},
() => done()
]);
});

View File

@ -0,0 +1,30 @@
QUnit.module('hr');
QUnit.test("Test: Appraisal Template [HR]", function (assert) {
assert.expect(1);
let done = assert.async();
frappe.run_serially([
// Job Opening creation
() => {
frappe.tests.make('Appraisal Template', [
{ kra_title: 'Test Appraisal 1'},
{ description: 'This is just a test'},
{ goals: [
[
{ kra: 'Design'},
{ per_weightage: 50}
],
[
{ kra: 'Code creation'},
{ per_weightage: 50}
]
]},
]);
},
() => frappe.timeout(5),
() => {
assert.equal('Test Appraisal 1',cur_frm.doc.kra_title, 'Appraisal name correctly set');
},
() => done()
]);
});

View File

@ -0,0 +1,79 @@
QUnit.test("Test Loan [HR]", function(assert) {
assert.expect(8);
let done = assert.async();
let employee_name;
// To create a loan and check principal,interest and balance amount
let loan_creation = (ename,lname) => {
return frappe.run_serially([
() => frappe.db.get_value('Employee', {'employee_name': ename}, 'name'),
(r) => {
employee_name = r.message.name;
},
() => frappe.db.get_value('Employee Loan Application', {'loan_type': lname}, 'name'),
(r) => {
// Creating loan for an employee
return frappe.tests.make('Employee Loan', [
{ company: 'Test Company'},
{ posting_date: '2017-08-26'},
{ employee: employee_name},
{ employee_loan_application: r.message.name},
{ disbursement_date: '2018-08-26'},
{ mode_of_payment: 'Cash'},
{ employee_loan_account: 'Temporary Opening - TC'},
{ interest_income_account: 'Service - TC'}
]);
},
() => frappe.timeout(3),
() => frappe.click_button('Submit'),
() => frappe.timeout(1),
() => frappe.click_button('Yes'),
() => frappe.timeout(3),
// Checking if all the amounts are correctly calculated
() => {
assert.ok(cur_frm.get_field('employee_name').value=='Test Employee 1'&&
(cur_frm.get_field('status').value=='Sanctioned'),
'Loan Sanctioned for correct employee');
assert.equal(7270,
cur_frm.get_doc('repayment_schedule').repayment_schedule[0].principal_amount,
'Principal amount for first instalment is correctly calculated');
assert.equal(2333,
cur_frm.get_doc('repayment_schedule').repayment_schedule[0].interest_amount,
'Interest amount for first instalment is correctly calculated');
assert.equal(192730,
cur_frm.get_doc('repayment_schedule').repayment_schedule[0].balance_loan_amount,
'Balance amount after first instalment is correctly calculated');
assert.equal(9479,
cur_frm.get_doc('repayment_schedule').repayment_schedule[23].principal_amount,
'Principal amount for last instalment is correctly calculated');
assert.equal(111,
cur_frm.get_doc('repayment_schedule').repayment_schedule[23].interest_amount,
'Interest amount for last instalment is correctly calculated');
assert.equal(0,
cur_frm.get_doc('repayment_schedule').repayment_schedule[23].balance_loan_amount,
'Balance amount after last instalment is correctly calculated');
},
() => frappe.set_route('List','Employee Loan','List'),
() => frappe.timeout(2),
// Checking the submission of Loan
() => {
assert.ok(cur_list.data[0].docstatus==1,'Loan sanctioned and submitted successfully');
},
]);
};
frappe.run_serially([
// Creating loan
() => loan_creation('Test Employee 1','Test Loan'),
() => done()
]);
});

View File

@ -0,0 +1,68 @@
QUnit.module('hr');
QUnit.test("Test: Employee Loan Application [HR]", function (assert) {
assert.expect(8);
let done = assert.async();
let employee_name;
frappe.run_serially([
// Creation of Loan Application
() => frappe.db.get_value('Employee', {'employee_name': 'Test Employee 1'}, 'name'),
(r) => {
employee_name = r.message.name;
},
() => {
frappe.tests.make('Employee Loan Application', [
{ company: 'Test Company'},
{ employee: employee_name},
{ employee_name: 'Test Employee 1'},
{ status: 'Approved'},
{ loan_type: 'Test Loan '},
{ loan_amount: 200000},
{ description: 'This is just a test'},
{ repayment_method: 'Repay Over Number of Periods'},
{ repayment_periods: 24},
{ rate_of_interest: 14}
]);
},
() => frappe.timeout(6),
() => frappe.click_button('Submit'),
() => frappe.timeout(1),
() => frappe.click_button('Yes'),
() => frappe.timeout(2),
() => {
// To check if all the amounts are correctly calculated
assert.ok(cur_frm.get_field('employee_name').value == 'Test Employee 1',
'Application created successfully');
assert.ok(cur_frm.get_field('status').value=='Approved',
'Status of application is correctly set');
assert.ok(cur_frm.get_field('loan_type').value=='Test Loan',
'Application is created for correct Loan Type');
assert.ok(cur_frm.get_field('status').value=='Approved',
'Status of application is correctly set');
assert.ok(cur_frm.get_field('repayment_amount').value==9603,
'Repayment amount is correctly calculated');
assert.ok(cur_frm.get_field('total_payable_interest').value==30459,
'Interest amount is correctly calculated');
assert.ok(cur_frm.get_field('total_payable_amount').value==230459,
'Total payable amount is correctly calculated');
},
() => frappe.set_route('List','Employee Loan Application','List'),
() => frappe.timeout(2),
// Checking the submission of Loan Application
() => {
assert.ok(cur_list.data[0].docstatus==1,'Loan Application submitted successfully');
},
() => frappe.timeout(1),
() => done()
]);
});

View File

@ -0,0 +1,59 @@
QUnit.module('hr');
QUnit.test("Test: Expense Claim [HR]", function (assert) {
assert.expect(3);
let done = assert.async();
let employee_name;
let d;
frappe.run_serially([
// Creating Expense Claim
() => frappe.set_route('List','Expense Claim','List'),
() => frappe.timeout(0.3),
() => frappe.click_button('Make a new Expense Claim'),
() => {
cur_frm.set_value('exp_approver','Administrator'),
cur_frm.set_value('is_paid',1),
cur_frm.set_value('expenses',[]),
d = frappe.model.add_child(cur_frm.doc,'Expense Claim Detail','expenses'),
d.expense_date = '2017-08-01',
d.expense_type = 'Test Expense Type 1',
d.description = 'This is just to test Expense Claim',
d.claim_amount = 2000,
d.sanctioned_amount=2000,
refresh_field('expenses');
},
() => frappe.timeout(2),
() => frappe.db.get_value('Employee', {'employee_name': 'Test Employee 1'}, 'name'),
(r) => {
employee_name = r.message.name;
},
() => frappe.timeout(1),
() => cur_frm.set_value('employee',employee_name),
() => cur_frm.set_value('employee_name','Test Employee 1'),
() => cur_frm.set_value('company','Test Company'),
() => cur_frm.set_value('payable_account','Creditors - TC'),
() => cur_frm.set_value('cost_center','Main - TC'),
() => cur_frm.set_value('mode_of_payment','Cash'),
() => cur_frm.save(),
() => frappe.timeout(1),
() => cur_frm.set_value('approval_status','Approved'),
() => frappe.timeout(1),
() => cur_frm.save(),
// Submitting the Expense Claim
() => frappe.click_button('Submit'),
() => frappe.click_button('Yes'),
() => frappe.timeout(3),
// Checking if the amount is correctly reimbursed for the employee
() => {
assert.equal(employee_name,cur_frm.get_field('employee').value,
'Expense Claim is created for correct employee');
assert.equal(1,cur_frm.get_field('is_paid').value,
'Expense is paid as required');
assert.equal(2000,cur_frm.get_field('total_amount_reimbursed').value,
'Amount is reimbursed correctly');
},
() => done()
]);
});

View File

@ -0,0 +1,30 @@
QUnit.module('hr');
QUnit.test("Test: Expense Claim Type [HR]", function (assert) {
assert.expect(1);
let done = assert.async();
frappe.run_serially([
// Creating a Expense Claim Type
() => {
frappe.tests.make('Expense Claim Type', [
{ expense_type: 'Test Expense Type 1'},
{ description:'This is just a test'},
{ accounts: [
[
{ company: 'Test Company'},
{ default_account: 'Round Off - TC'}
]
]},
]);
},
() => frappe.timeout(5),
// Checking if the created type is present in the list
() => {
assert.equal('Test Expense Type 1', cur_frm.doc.expense_type,
'Expense Claim Type created successfully');
},
() => done()
]);
});

View File

@ -1,7 +1,7 @@
QUnit.module('hr'); QUnit.module('hr');
QUnit.test("Test: Leave application [HR]", function (assert) { QUnit.test("Test: Leave application [HR]", function (assert) {
assert.expect(5); assert.expect(4);
let done = assert.async(); let done = assert.async();
let today_date = frappe.datetime.nowdate(); let today_date = frappe.datetime.nowdate();
let leave_date = frappe.datetime.add_days(today_date, 1); // leave for tomorrow let leave_date = frappe.datetime.add_days(today_date, 1); // leave for tomorrow
@ -22,8 +22,6 @@ QUnit.test("Test: Leave application [HR]", function (assert) {
}, },
() => frappe.timeout(1), () => frappe.timeout(1),
// check calculated total leave days // check calculated total leave days
() => assert.equal("0.5", cur_frm.doc.total_leave_days,
"leave application for half day"),
() => assert.ok(!cur_frm.doc.docstatus, () => assert.ok(!cur_frm.doc.docstatus,
"leave application not submitted with status as open"), "leave application not submitted with status as open"),
() => cur_frm.set_value("status", "Approved"), // approve the application [as administrator] () => cur_frm.set_value("status", "Approved"), // approve the application [as administrator]

View File

@ -0,0 +1,31 @@
QUnit.module('hr');
QUnit.test("Test: Loan Type [HR]", function (assert) {
assert.expect(3);
let done = assert.async();
frappe.run_serially([
// Loan Type creation
() => {
frappe.tests.make('Loan Type', [
{ loan_name: 'Test Loan'},
{ maximum_loan_amount: 400000},
{ rate_of_interest: 14},
{ description:
'This is just a test.'}
]);
},
() => frappe.timeout(3),
() => frappe.set_route('List','Loan Type','List'),
() => frappe.timeout(2),
// Checking if the fields are correctly set
() => {
assert.ok(cur_list.data.length==1, 'Loan Type created successfully');
assert.ok(cur_list.data[0].name=='Test Loan', 'Loan title Correctly set');
assert.ok(cur_list.data[0].disabled==0, 'Loan enabled');
},
() => done()
]);
});

View File

@ -0,0 +1,55 @@
QUnit.module('hr');
QUnit.test("Test: Training Event [HR]", function (assert) {
assert.expect(4);
let done = assert.async();
let employee_name;
frappe.run_serially([
// Creation of Training Event
() => frappe.db.get_value('Employee', {'employee_name': 'Test Employee 1'}, 'name'),
(r) => {
employee_name = r.message.name;
},
() => {
frappe.tests.make('Training Event', [
{ event_name: 'Test Training Event 1'},
{ location: 'Mumbai'},
{ start_time: '2017-09-01 11:00:0'},
{ end_time: '2017-09-01 17:00:0'},
{ introduction: 'This is just a test'},
{ employees: [
[
{employee: employee_name},
{employee_name: 'Test Employee 1'}
]
]},
]);
},
() => frappe.timeout(7),
() => frappe.click_button('Submit'),
() => frappe.timeout(1),
() => frappe.click_button('Yes'),
() => frappe.timeout(8),
() => {
// To check if the fields are correctly set
assert.ok(cur_frm.get_field('event_name').value == 'Test Training Event 1',
'Event created successfully');
assert.ok(cur_frm.get_field('event_status').value=='Scheduled',
'Status of event is correctly set');
assert.ok(cur_frm.doc.employees[0].employee_name=='Test Employee 1',
'Attendee Employee is correctly set');
},
() => frappe.set_route('List','Training Event','List'),
() => frappe.timeout(2),
// Checking the submission of Training Event
() => {
assert.ok(cur_list.data[0].docstatus==1,'Training Event Submitted successfully');
},
() => frappe.timeout(2),
() => done()
]);
});

View File

@ -0,0 +1,52 @@
QUnit.module('hr');
QUnit.test("Test: Training Feedback [HR]", function (assert) {
assert.expect(3);
let done = assert.async();
let employee_name;
frappe.run_serially([
// Creating Training Feedback
() => frappe.set_route('List','Training Feedback','List'),
() => frappe.timeout(0.3),
() => frappe.click_button('Make a new Training Feedback'),
() => frappe.timeout(1),
() => frappe.db.get_value('Employee', {'employee_name': 'Test Employee 1'}, 'name'),
(r) => {
employee_name = r.message.name;
},
() => cur_frm.set_value('employee',employee_name),
() => cur_frm.set_value('employee_name','Test Employee 1'),
() => cur_frm.set_value('training_event','Test Training Event 1'),
() => cur_frm.set_value('event_name','Test Training Event 1'),
() => cur_frm.set_value('feedback','Great Experience. This is just a test.'),
() => frappe.timeout(1),
() => cur_frm.save(),
() => frappe.timeout(1),
() => cur_frm.save(),
// Submitting the feedback
() => frappe.click_button('Submit'),
() => frappe.click_button('Yes'),
() => frappe.timeout(3),
// Checking if the feedback is given by correct employee
() => {
assert.equal('Test Employee 1',cur_frm.get_field('employee_name').value,
'Feedback is given by correct employee');
assert.equal('Test Training Event 1',cur_frm.get_field('training_event').value,
'Feedback is given for correct event');
},
() => frappe.set_route('List','Training Feedback','List'),
() => frappe.timeout(2),
// Checking the submission of Training Result
() => {
assert.ok(cur_list.data[0].docstatus==1,'Training Feedback Submitted successfully');
},
() => done()
]);
});

View File

@ -0,0 +1,53 @@
QUnit.module('hr');
QUnit.test("Test: Training Result [HR]", function (assert) {
assert.expect(5);
let done = assert.async();
frappe.run_serially([
// Creating Training Result
() => frappe.set_route('List','Training Result','List'),
() => frappe.timeout(0.3),
() => frappe.click_button('Make a new Training Result'),
() => {
cur_frm.set_value('training_event','Test Training Event 1');
},
() => frappe.timeout(1),
() => frappe.model.set_value('Training Result Employee','New Training Result Employee 1','hours',4),
() => frappe.model.set_value('Training Result Employee','New Training Result Employee 1','grade','A'),
() => frappe.model.set_value('Training Result Employee','New Training Result Employee 1','comments','Nice Seminar'),
() => frappe.timeout(1),
() => cur_frm.save(),
() => frappe.timeout(1),
() => cur_frm.save(),
// Submitting the Training Result
() => frappe.click_button('Submit'),
() => frappe.click_button('Yes'),
() => frappe.timeout(4),
// Checking if the fields are correctly set
() => {
assert.equal('Test Training Event 1',cur_frm.get_field('training_event').value,
'Training Result is created');
assert.equal('Test Employee 1',cur_frm.doc.employees[0].employee_name,
'Training Result is created for correct employee');
assert.equal(4,cur_frm.doc.employees[0].hours,
'Hours field is correctly calculated');
assert.equal('A',cur_frm.doc.employees[0].grade,
'Grade field is correctly set');
},
() => frappe.set_route('List','Training Result','List'),
() => frappe.timeout(2),
// Checking the submission of Training Result
() => {
assert.ok(cur_list.data[0].docstatus==1,'Training Result Submitted successfully');
},
() => done()
]);
});

View File

@ -5,7 +5,7 @@ frappe.provide("erpnext.bom");
frappe.ui.form.on("BOM", { frappe.ui.form.on("BOM", {
setup: function(frm) { setup: function(frm) {
frm.add_fetch('buying_price_list', 'currency', 'currency') frm.add_fetch('buying_price_list', 'currency', 'currency');
frm.set_query("bom_no", "items", function() { frm.set_query("bom_no", "items", function() {
return { return {
@ -13,7 +13,7 @@ frappe.ui.form.on("BOM", {
'currency': frm.doc.currency, 'currency': frm.doc.currency,
'company': frm.doc.company 'company': frm.doc.company
} }
} };
}); });
frm.set_query("source_warehouse", "items", function() { frm.set_query("source_warehouse", "items", function() {
@ -21,7 +21,7 @@ frappe.ui.form.on("BOM", {
filters: { filters: {
'company': frm.doc.company, 'company': frm.doc.company,
} }
} };
}); });
}, },
@ -57,10 +57,14 @@ frappe.ui.form.on("BOM", {
doc: frm.doc, doc: frm.doc,
method: "update_cost", method: "update_cost",
freeze: true, freeze: true,
args: {
update_parent: true,
from_child_bom:false
},
callback: function(r) { callback: function(r) {
if(!r.exc) frm.refresh_fields(); if(!r.exc) frm.refresh_fields();
} }
}) });
} }
}); });

View File

@ -232,7 +232,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
@ -262,7 +262,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
@ -291,6 +291,37 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Set rate of sub-assembly item based on BOM",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -1640,7 +1671,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-08-11 14:09:30.492628", "modified": "2017-08-23 14:09:30.492628",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "BOM", "name": "BOM",

View File

@ -92,7 +92,7 @@ class BOM(WebsiteGenerator):
def validate_rm_item(self, item): def validate_rm_item(self, item):
if (item[0]['name'] in [it.item_code for it in self.items]) and item[0]['name'] == self.item: if (item[0]['name'] in [it.item_code for it in self.items]) and item[0]['name'] == self.item:
frappe.throw(_("Raw material cannot be same as main Item")) frappe.throw(_("BOM #{0}: Raw material cannot be same as main Item").format(self.name))
def set_bom_material_details(self): def set_bom_material_details(self):
for item in self.get("items"): for item in self.get("items"):
@ -155,15 +155,17 @@ class BOM(WebsiteGenerator):
rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list, rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list,
"item_code": arg["item_code"]}, "price_list_rate") or 0 "item_code": arg["item_code"]}, "price_list_rate") or 0
if not rate and arg['bom_no']: if arg['bom_no'] and (not rate or self.set_rate_of_sub_assembly_item_based_on_bom):
rate = self.get_bom_unitcost(arg['bom_no']) rate = self.get_bom_unitcost(arg['bom_no'])
return rate return rate
def update_cost(self): def update_cost(self, update_parent=True, from_child_bom=False):
if self.docstatus == 2: if self.docstatus == 2:
return return
existing_bom_cost = self.total_cost
for d in self.get("items"): for d in self.get("items"):
rate = self.get_bom_material_detail({'item_code': d.item_code, 'bom_no': d.bom_no, rate = self.get_bom_material_detail({'item_code': d.item_code, 'bom_no': d.bom_no,
'stock_qty': d.stock_qty})["rate"] 'stock_qty': d.stock_qty})["rate"]
@ -176,6 +178,15 @@ class BOM(WebsiteGenerator):
self.save() self.save()
self.update_exploded_items() self.update_exploded_items()
# update parent BOMs
if self.total_cost != existing_bom_cost and update_parent:
parent_boms = frappe.db.sql_list("""select distinct parent from `tabBOM Item`
where bom_no = %s and docstatus=1""", self.name)
for bom in parent_boms:
frappe.get_doc("BOM", bom).update_cost(from_child_bom=True)
if not from_child_bom:
frappe.msgprint(_("Cost Updated")) frappe.msgprint(_("Cost Updated"))
def get_bom_unitcost(self, bom_no): def get_bom_unitcost(self, bom_no):
@ -567,3 +578,26 @@ def get_children():
and bom_item.item_code = item.name and bom_item.item_code = item.name
order by bom_item.idx order by bom_item.idx
""", frappe.form_dict.parent, as_dict=True) """, frappe.form_dict.parent, as_dict=True)
def get_boms_in_bottom_up_order(bom_no=None):
def _get_parent(bom_no):
return frappe.db.sql_list("""select distinct parent from `tabBOM Item`
where bom_no = %s and docstatus=1""", bom_no)
count = 0
bom_list = []
if bom_no:
bom_list.append(bom_no)
else:
# get all leaf BOMs
bom_list = frappe.db.sql_list("""select name from `tabBOM` bom where docstatus=1
and not exists(select bom_no from `tabBOM Item`
where parent=bom.name and ifnull(bom_no, '')!='')""")
while(count < len(bom_list)):
for child_bom in _get_parent(bom_list[count]):
if child_bom not in bom_list:
bom_list.append(child_bom)
count += 1
return bom_list

View File

@ -6,6 +6,8 @@ from __future__ import unicode_literals
import unittest import unittest
import frappe import frappe
from frappe.utils import cstr from frappe.utils import cstr
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost
test_records = frappe.get_test_records('BOM') test_records = frappe.get_test_records('BOM')
@ -47,5 +49,31 @@ class TestBOM(unittest.TestCase):
self.assertTrue(_get_default_bom_in_item(), bom.name) self.assertTrue(_get_default_bom_in_item(), bom.name)
def test_update_bom_cost_in_all_boms(self):
# get current rate for '_Test Item 2'
rm_rate = frappe.db.sql("""select rate from `tabBOM Item`
where parent='BOM-_Test Item Home Desktop Manufactured-001'
and item_code='_Test Item 2' and docstatus=1""")
rm_rate = rm_rate[0][0] if rm_rate else 0
# update valuation rate of item '_Test Item 2'
warehouse_list = frappe.db.sql_list("""select warehouse from `tabBin`
where item_code='_Test Item 2' and actual_qty > 0""")
if not warehouse_list:
warehouse_list.append("_Test Warehouse - _TC")
for warehouse in warehouse_list:
create_stock_reconciliation(item_code="_Test Item 2", warehouse=warehouse,
qty=200, rate=rm_rate + 10)
# update cost of all BOMs based on latest valuation rate
update_cost()
# check if new valuation rate updated in all BOMs
for d in frappe.db.sql("""select rate from `tabBOM Item`
where item_code='_Test Item 2' and docstatus=1""", as_dict=1):
self.assertEqual(d.rate, rm_rate + 10)
def get_default_bom(item_code="_Test FG Item 2"): def get_default_bom(item_code="_Test FG Item 2"):
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1}) return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})

View File

@ -1 +0,0 @@
Tool to replace one Item with another in all Bill of Material (BOM) trees.

View File

@ -1,22 +0,0 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
cur_frm.cscript.refresh = function(doc) {
cur_frm.disable_save();
}
cur_frm.set_query("current_bom", function(doc) {
return{
query: "erpnext.controllers.queries.bom",
filters: {name: "!" + doc.new_bom}
}
});
cur_frm.set_query("new_bom", function(doc) {
return{
query: "erpnext.controllers.queries.bom",
filters: {name: "!" + doc.current_bom}
}
});

View File

@ -1,119 +0,0 @@
{
"allow_copy": 1,
"allow_import": 0,
"allow_rename": 0,
"creation": "2012-12-06 12:10:10",
"custom": 0,
"description": "Replace a particular BOM in all other BOMs where it is used. It will replace the old BOM link, update cost and regenerate \"BOM Explosion Item\" table as per new BOM",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "The BOM which will be replaced",
"fieldname": "current_bom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Current BOM",
"no_copy": 0,
"options": "BOM",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "The new BOM after replacement",
"fieldname": "new_bom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "New BOM",
"no_copy": 0,
"options": "BOM",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "replace",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Replace",
"no_copy": 0,
"options": "replace_bom",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 1,
"hide_toolbar": 1,
"icon": "fa fa-magic",
"idx": 1,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"modified": "2015-08-12 08:52:46.035343",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Replace Tool",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Manufacturing Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"read_only": 1,
"read_only_onload": 0
}

View File

@ -0,0 +1,34 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('BOM Update Tool', {
setup: function(frm) {
frm.set_query("current_bom", function() {
return {
query: "erpnext.controllers.queries.bom",
filters: {name: "!" + frm.doc.new_bom}
};
});
frm.set_query("new_bom", function() {
return {
query: "erpnext.controllers.queries.bom",
filters: {name: "!" + frm.doc.current_bom}
};
});
},
refresh: function(frm) {
frm.disable_save();
},
update_latest_price_in_all_boms: function() {
frappe.call({
method: "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.enqueue_update_cost",
freeze: true,
callback: function() {
frappe.msgprint(__("Latest price updated in all BOMs"));
}
});
}
});

View File

@ -0,0 +1,244 @@
{
"allow_copy": 1,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2012-12-06 12:10:10",
"custom": 0,
"description": "Replace a particular BOM in all other BOMs where it is used. It will replace the old BOM link, update cost and regenerate \"BOM Explosion Item\" table as per new BOM.\nIt also updates latest price in all the BOMs.",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
"editable_grid": 0,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "replace_bom_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Replace BOM",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "The BOM which will be replaced",
"fieldname": "current_bom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Current BOM",
"length": 0,
"no_copy": 0,
"options": "BOM",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "The new BOM after replacement",
"fieldname": "new_bom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "New BOM",
"length": 0,
"no_copy": 0,
"options": "BOM",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "replace",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Replace",
"length": 0,
"no_copy": 0,
"options": "replace_bom",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "update_cost_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Update Cost",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "update_latest_price_in_all_boms",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Update latest price in all BOMs",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 1,
"hide_toolbar": 1,
"icon": "icon-magic",
"idx": 1,
"image_view": 0,
"in_create": 1,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-31 18:08:05.919276",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Update Tool",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Manufacturing Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 1,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 0,
"track_seen": 0
}

View File

@ -1,14 +1,15 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # -*- coding: utf-8 -*-
# License: GNU General Public License v3. See license.txt # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import cstr, flt from frappe.utils import cstr, flt
from frappe import _ from frappe import _
from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order
from frappe.model.document import Document from frappe.model.document import Document
class BOMReplaceTool(Document): class BOMUpdateTool(Document):
def replace_bom(self): def replace_bom(self):
self.validate_bom() self.validate_bom()
self.update_new_bom() self.update_new_bom()
@ -40,3 +41,17 @@ class BOMReplaceTool(Document):
return [d[0] for d in frappe.db.sql("""select distinct parent return [d[0] for d in frappe.db.sql("""select distinct parent
from `tabBOM Item` where ifnull(bom_no, '') = %s and docstatus < 2""", from `tabBOM Item` where ifnull(bom_no, '') = %s and docstatus < 2""",
self.new_bom)] self.new_bom)]
@frappe.whitelist()
def enqueue_update_cost():
frappe.enqueue("erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_cost")
frappe.msgprint(_("Queued for updating latest price in all Bill of Materials. It may take a few minutes."))
def update_latest_price_in_all_boms():
if frappe.db.get_single_value("Manufacturing Settings", "update_bom_costs_automatically"):
update_cost()
def update_cost():
bom_list = get_boms_in_bottom_up_order()
for bom in bom_list:
frappe.get_doc("BOM", bom).update_cost(update_parent=False, from_child_bom=True)

View File

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: BOM Update Tool", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially('BOM Update Tool', [
// insert a new BOM Update Tool
() => frappe.tests.make([
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@ -0,0 +1,30 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import unittest
import frappe
test_records = frappe.get_test_records('BOM')
class TestBOMUpdateTool(unittest.TestCase):
def test_replace_bom(self):
current_bom = "BOM-_Test Item Home Desktop Manufactured-001"
bom_doc = frappe.copy_doc(test_records[0])
bom_doc.items[1].item_code = "_Test Item"
bom_doc.insert()
update_tool = frappe.get_doc("BOM Update Tool")
update_tool.current_bom = current_bom
update_tool.new_bom = bom_doc.name
update_tool.replace_bom()
self.assertFalse(frappe.db.sql("select name from `tabBOM Item` where bom_no=%s", current_bom))
self.assertTrue(frappe.db.sql("select name from `tabBOM Item` where bom_no=%s", bom_doc.name))
# reverse, as it affects other testcases
update_tool.current_bom = bom_doc.name
update_tool.new_bom = current_bom
update_tool.replace_bom()

View File

@ -1,23 +1,32 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
"beta": 0,
"creation": "2014-11-27 14:12:07.542534", "creation": "2014-11-27 14:12:07.542534",
"custom": 0, "custom": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Document", "document_type": "Document",
"editable_grid": 0,
"engine": "InnoDB",
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "capacity_planning", "fieldname": "capacity_planning",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Capacity Planning", "label": "Capacity Planning",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -26,6 +35,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -33,16 +43,21 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"description": "Disables creation of time logs against Production Orders. Operations shall not be tracked against Production Order", "description": "Disables creation of time logs against Production Orders. Operations shall not be tracked against Production Order",
"fieldname": "disable_capacity_planning", "fieldname": "disable_capacity_planning",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Disable Capacity Planning and Time Tracking", "label": "Disable Capacity Planning and Time Tracking",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -51,6 +66,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -58,16 +74,21 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"description": "Plan time logs outside Workstation Working Hours.", "description": "Plan time logs outside Workstation Working Hours.",
"fieldname": "allow_overtime", "fieldname": "allow_overtime",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Overtime", "label": "Allow Overtime",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -76,6 +97,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -83,16 +105,21 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"default": "", "default": "",
"fieldname": "allow_production_on_holidays", "fieldname": "allow_production_on_holidays",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Allow Production on Holidays", "label": "Allow Production on Holidays",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -102,6 +129,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -109,15 +137,20 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "column_break_3", "fieldname": "column_break_3",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -125,6 +158,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -132,17 +166,22 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"default": "30", "default": "30",
"description": "Try planning operations for X days in advance.", "description": "Try planning operations for X days in advance.",
"fieldname": "capacity_planning_for_days", "fieldname": "capacity_planning_for_days",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Capacity Planning For (Days)", "label": "Capacity Planning For (Days)",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -151,6 +190,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -158,16 +198,21 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"description": "Default 10 mins", "description": "Default 10 mins",
"fieldname": "mins_between_operations", "fieldname": "mins_between_operations",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Time Between Operations (in mins)", "label": "Time Between Operations (in mins)",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -176,6 +221,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -183,15 +229,20 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "section_break_6", "fieldname": "section_break_6",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -199,6 +250,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -206,15 +258,20 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "over_production_allowance_percentage", "fieldname": "over_production_allowance_percentage",
"fieldtype": "Percent", "fieldtype": "Percent",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Over Production Allowance Percentage", "label": "Over Production Allowance Percentage",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -223,6 +280,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -230,16 +288,21 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"default": "BOM", "default": "BOM",
"fieldname": "backflush_raw_materials_based_on", "fieldname": "backflush_raw_materials_based_on",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Backflush Raw Materials Based On", "label": "Backflush Raw Materials Based On",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -249,6 +312,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -256,15 +320,22 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "column_break_11", "columns": 0,
"fieldtype": "Column Break", "description": "Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",
"fieldname": "update_bom_costs_automatically",
"fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Update BOM Cost Automatically",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -272,6 +343,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -279,15 +351,49 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "column_break_11",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_wip_warehouse", "fieldname": "default_wip_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Work In Progress Warehouse", "label": "Default Work In Progress Warehouse",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -297,6 +403,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -304,15 +411,20 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "default_fg_warehouse", "fieldname": "default_fg_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Finished Goods Warehouse", "label": "Default Finished Goods Warehouse",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -322,6 +434,7 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -329,18 +442,19 @@
"unique": 0 "unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 0,
"icon": "fa fa-wrench", "icon": "icon-wrench",
"idx": 0, "idx": 0,
"image_view": 0,
"in_create": 0, "in_create": 0,
"in_dialog": 0,
"is_submittable": 0, "is_submittable": 0,
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2015-12-10 00:03:20.895790", "modified": "2017-07-31 19:25:04.242693",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Manufacturing Settings", "name": "Manufacturing Settings",
@ -368,8 +482,12 @@
"write": 1 "write": 1
} }
], ],
"quick_entry": 0,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC" "sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
} }

View File

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Manufacturing Settings", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially('Manufacturing Settings', [
// insert a new Manufacturing Settings
() => frappe.tests.make([
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@ -523,7 +523,8 @@ def set_production_order_ops(name):
@frappe.whitelist() @frappe.whitelist()
def make_stock_entry(production_order_id, purpose, qty=None): def make_stock_entry(production_order_id, purpose, qty=None):
production_order = frappe.get_doc("Production Order", production_order_id) production_order = frappe.get_doc("Production Order", production_order_id)
if not frappe.db.get_value("Warehouse", production_order.wip_warehouse, "is_group"): if not frappe.db.get_value("Warehouse", production_order.wip_warehouse, "is_group") \
and not production_order.skip_transfer:
wip_warehouse = production_order.wip_warehouse wip_warehouse = production_order.wip_warehouse
else: else:
wip_warehouse = None wip_warehouse = None

View File

@ -229,6 +229,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:!parent.skip_transfer",
"fieldname": "transferred_qty", "fieldname": "transferred_qty",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@ -353,7 +354,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-07-10 17:37:20.212361", "modified": "2017-08-18 18:11:10.311736",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Production Order Item", "name": "Production Order Item",

View File

@ -433,4 +433,6 @@ erpnext.patches.v8_6.update_timesheet_company_from_PO
erpnext.patches.v8_6.set_write_permission_for_quotation_for_sales_manager erpnext.patches.v8_6.set_write_permission_for_quotation_for_sales_manager
erpnext.patches.v8_5.remove_project_type_property_setter erpnext.patches.v8_5.remove_project_type_property_setter
erpnext.patches.v8_7.add_more_gst_fields erpnext.patches.v8_7.add_more_gst_fields
erpnext.patches.v8_7.fix_purchase_receipt_status
erpnext.patches.v8_6.rename_bom_update_tool
erpnext.patches.v8_8.update_gl_due_date_for_pi_and_si erpnext.patches.v8_8.update_gl_due_date_for_pi_and_si

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
def execute(): def execute():
@ -10,5 +10,5 @@ def execute():
frappe.db.get_value("Global Defaults", "Global Defaults", "country")}) frappe.db.get_value("Global Defaults", "Global Defaults", "country")})
d.insert() d.insert()
except: except:
print frappe.get_traceback() print(frappe.get_traceback())

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
from frappe.permissions import reset_perms from frappe.permissions import reset_perms
def execute(): def execute():
@ -16,5 +16,5 @@ def execute():
try: try:
reset_perms(doctype) reset_perms(doctype)
except: except:
print "Error resetting perms for", doctype print("Error resetting perms for", doctype)
raise raise

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.custom.doctype.property_setter.property_setter import make_property_setter
@ -91,7 +91,7 @@ def get_default_series(doctype, new_series):
(new_series, new_series)) (new_series, new_series))
if not (default_series and default_series[0][0]): if not (default_series and default_series[0][0]):
print "[Skipping] Cannot guess which naming series to use for", doctype print("[Skipping] Cannot guess which naming series to use for", doctype)
return return
return default_series[0][0] return default_series[0][0]

View File

@ -1,11 +1,11 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
def execute(): def execute():
print "WARNING!!!! Email Settings not migrated. Please setup your email again." print("WARNING!!!! Email Settings not migrated. Please setup your email again.")
# this will happen if you are migrating very old accounts # this will happen if you are migrating very old accounts
# comment out this line below and remember to create new Email Accounts # comment out this line below and remember to create new Email Accounts

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
def execute(): def execute():
@ -31,4 +31,4 @@ def execute():
frappe.db.sql("""UPDATE tabAccount SET root_type=%s WHERE lft>%s and rgt<%s""", frappe.db.sql("""UPDATE tabAccount SET root_type=%s WHERE lft>%s and rgt<%s""",
(root.root_type, root.lft, root.rgt)) (root.root_type, root.lft, root.rgt))
else: else:
print b"Root type not found for {0}".format(root.name.encode("utf-8")) print(b"Root type not found for {0}".format(root.name.encode("utf-8")))

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
from frappe.utils import flt from frappe.utils import flt
@ -37,7 +37,7 @@ def execute():
if stock_bal and account_bal and abs(flt(stock_bal[0][0]) - flt(account_bal[0][0])) > 0.1: if stock_bal and account_bal and abs(flt(stock_bal[0][0]) - flt(account_bal[0][0])) > 0.1:
try: try:
print voucher_type, voucher_no, stock_bal[0][0], account_bal[0][0] print(voucher_type, voucher_no, stock_bal[0][0], account_bal[0][0])
frappe.db.sql("""delete from `tabGL Entry` frappe.db.sql("""delete from `tabGL Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no)) where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
@ -45,10 +45,10 @@ def execute():
voucher = frappe.get_doc(voucher_type, voucher_no) voucher = frappe.get_doc(voucher_type, voucher_no)
voucher.make_gl_entries(repost_future_gle=False) voucher.make_gl_entries(repost_future_gle=False)
frappe.db.commit() frappe.db.commit()
except Exception, e: except Exception as e:
print frappe.get_traceback() print(frappe.get_traceback())
rejected.append([voucher_type, voucher_no]) rejected.append([voucher_type, voucher_no])
frappe.db.rollback() frappe.db.rollback()
print "Failed to repost: " print("Failed to repost: ")
print rejected print(rejected)

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
def execute(): def execute():
@ -109,7 +109,7 @@ def delete_individual_party_account():
and exists(select gle.name from `tabGL Entry` gle where gle.account = tabAccount.name)""") and exists(select gle.name from `tabGL Entry` gle where gle.account = tabAccount.name)""")
if accounts_not_deleted: if accounts_not_deleted:
print "Accounts not deleted: " + "\n".join(accounts_not_deleted) print("Accounts not deleted: " + "\n".join(accounts_not_deleted))
def remove_customer_supplier_account_report(): def remove_customer_supplier_account_report():

View File

@ -1,7 +1,7 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
from erpnext.stock.stock_ledger import NegativeStockError from erpnext.stock.stock_ledger import NegativeStockError
@ -28,7 +28,7 @@ def execute():
frappe.local.stockledger_exceptions = None frappe.local.stockledger_exceptions = None
frappe.db.rollback() frappe.db.rollback()
print "Failed to repost: ", failed_list print("Failed to repost: ", failed_list)

View File

@ -1,13 +1,13 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
def execute(): def execute():
country = frappe.db.get_single_value("Global Defaults", "country") country = frappe.db.get_single_value("Global Defaults", "country")
if not country: if not country:
print "Country not specified in Global Defaults" print("Country not specified in Global Defaults")
return return
for company in frappe.db.sql_list("""select name from `tabCompany` for company in frappe.db.sql_list("""select name from `tabCompany`

View File

@ -1,7 +1,7 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
def execute(): def execute():
@ -21,6 +21,6 @@ def execute():
je.make_gl_entries() je.make_gl_entries()
if je_list: if je_list:
print je_list print(je_list)

View File

@ -6,7 +6,7 @@ import frappe
def execute(): def execute():
for dt in ["Payment Tool", "Bank Reconciliation", "Payment Reconciliation", "Leave Control Panel", for dt in ["Payment Tool", "Bank Reconciliation", "Payment Reconciliation", "Leave Control Panel",
"Salary Manager", "Upload Attenadance", "Production Planning Tool", "BOM Replace Tool", "Customize Form", "Salary Manager", "Upload Attenadance", "Production Planning Tool", "BOM Update Tool", "Customize Form",
"Employee Attendance Tool", "Rename Tool", "BOM Replace Tool", "Process Payroll", "Naming Series"]: "Employee Attendance Tool", "Rename Tool", "BOM Update Tool", "Process Payroll", "Naming Series"]:
frappe.db.sql("delete from `tabSingles` where doctype=%s", dt) frappe.db.sql("delete from `tabSingles` where doctype=%s", dt)

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
import os import os
from frappe.utils import get_files_path from frappe.utils import get_files_path
@ -45,7 +45,7 @@ def fix_files_for_item(files_path, unlinked_files):
try: try:
file_data.save() file_data.save()
except IOError: except IOError:
print "File {0} does not exist".format(new_file_url) print("File {0} does not exist".format(new_file_url))
# marking fix to prevent further errors # marking fix to prevent further errors
fixed_files.append(file_url) fixed_files.append(file_url)

View File

@ -1,7 +1,7 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
from frappe.email import sendmail_to_system_managers from frappe.email import sendmail_to_system_managers
from frappe.utils import get_link_to_form from frappe.utils import get_link_to_form
@ -36,6 +36,6 @@ Administrator""" % "\n".join([(d[0] + ": " + ", ".join(d[1])) for d in wrong_rec
except: except:
pass pass
print "="*50 print("="*50)
print content print(content)
print "="*50 print("="*50)

View File

@ -1,7 +1,7 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
import MySQLdb import MySQLdb
@ -32,7 +32,7 @@ def execute():
migrate_item_variants() migrate_item_variants()
except MySQLdb.ProgrammingError: except MySQLdb.ProgrammingError:
print "`tabItem Variant` not found" print("`tabItem Variant` not found")
def rename_and_reload_doctypes(): def rename_and_reload_doctypes():
if "tabVariant Attribute" in frappe.db.get_tables(): if "tabVariant Attribute" in frappe.db.get_tables():

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
""" """
@ -38,19 +38,19 @@ def check():
si_list = get_affected_sales_invoice() si_list = get_affected_sales_invoice()
if so_list or dn_list or si_list: if so_list or dn_list or si_list:
print "Entries with Target Warehouse:" print("Entries with Target Warehouse:")
if so_list: if so_list:
print "Sales Order" print("Sales Order")
print so_list print(so_list)
if dn_list: if dn_list:
print "Delivery Notes" print("Delivery Notes")
print [d.name for d in dn_list] print([d.name for d in dn_list])
if si_list: if si_list:
print "Sales Invoice" print("Sales Invoice")
print [d.name for d in si_list] print([d.name for d in si_list])
def repost(): def repost():
@ -61,34 +61,34 @@ def repost():
frappe.db.commit() frappe.db.commit()
if dn_failed_list: if dn_failed_list:
print "-"*40 print("-"*40)
print "Delivery Note Failed to Repost" print("Delivery Note Failed to Repost")
print dn_failed_list print(dn_failed_list)
if si_failed_list: if si_failed_list:
print "-"*40 print("-"*40)
print "Sales Invoice Failed to Repost" print("Sales Invoice Failed to Repost")
print si_failed_list print(si_failed_list)
print print()
print """ print("""
If above Delivery Notes / Sales Invoice failed due to negative stock, follow these steps: If above Delivery Notes / Sales Invoice failed due to negative stock, follow these steps:
- Ensure that stock is available for those items in the mentioned warehouse on the date mentioned in the error - Ensure that stock is available for those items in the mentioned warehouse on the date mentioned in the error
- Run this patch again - Run this patch again
""" """)
def repost_dn(dn_failed_list): def repost_dn(dn_failed_list):
dn_list = get_affected_delivery_notes() dn_list = get_affected_delivery_notes()
if dn_list: if dn_list:
print "-"*40 print("-"*40)
print "Reposting Delivery Notes" print("Reposting Delivery Notes")
for dn in dn_list: for dn in dn_list:
if dn.docstatus == 0: if dn.docstatus == 0:
continue continue
print dn.name print(dn.name)
try: try:
dn_doc = frappe.get_doc("Delivery Note", dn.name) dn_doc = frappe.get_doc("Delivery Note", dn.name)
@ -107,7 +107,7 @@ def repost_dn(dn_failed_list):
except Exception: except Exception:
dn_failed_list.append(dn.name) dn_failed_list.append(dn.name)
frappe.local.stockledger_exceptions = None frappe.local.stockledger_exceptions = None
print frappe.get_traceback() print(frappe.get_traceback())
frappe.db.rollback() frappe.db.rollback()
frappe.db.sql("update `tabDelivery Note Item` set target_warehouse='' where docstatus=0") frappe.db.sql("update `tabDelivery Note Item` set target_warehouse='' where docstatus=0")
@ -116,14 +116,14 @@ def repost_si(si_failed_list):
si_list = get_affected_sales_invoice() si_list = get_affected_sales_invoice()
if si_list: if si_list:
print "-"*40 print("-"*40)
print "Reposting Sales Invoice" print("Reposting Sales Invoice")
for si in si_list: for si in si_list:
if si.docstatus == 0: if si.docstatus == 0:
continue continue
print si.name print(si.name)
try: try:
si_doc = frappe.get_doc("Sales Invoice", si.name) si_doc = frappe.get_doc("Sales Invoice", si.name)
@ -141,7 +141,7 @@ def repost_si(si_failed_list):
except Exception: except Exception:
si_failed_list.append(si.name) si_failed_list.append(si.name)
frappe.local.stockledger_exceptions = None frappe.local.stockledger_exceptions = None
print frappe.get_traceback() print(frappe.get_traceback())
frappe.db.rollback() frappe.db.rollback()
frappe.db.sql("update `tabSales Invoice Item` set target_warehouse='' where docstatus=0") frappe.db.sql("update `tabSales Invoice Item` set target_warehouse='' where docstatus=0")
@ -152,8 +152,8 @@ def repost_so():
frappe.db.sql("update `tabSales Order Item` set target_warehouse=''") frappe.db.sql("update `tabSales Order Item` set target_warehouse=''")
if so_list: if so_list:
print "-"*40 print("-"*40)
print "Sales Order reposted" print("Sales Order reposted")
def get_affected_delivery_notes(): def get_affected_delivery_notes():

View File

@ -1,7 +1,7 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
from frappe.utils import cstr from frappe.utils import cstr
@ -33,7 +33,7 @@ def execute():
(pi.name, company.expenses_included_in_valuation)) (pi.name, company.expenses_included_in_valuation))
if gle_for_expenses_included_in_valuation: if gle_for_expenses_included_in_valuation:
print pi.name print(pi.name)
frappe.db.sql("""delete from `tabGL Entry` frappe.db.sql("""delete from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s""", pi.name) where voucher_type='Purchase Invoice' and voucher_no=%s""", pi.name)

View File

@ -1,7 +1,7 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
def execute(): def execute():
@ -44,7 +44,7 @@ def execute():
where name=%s""", d.name) where name=%s""", d.name)
for d in journal_entries: for d in journal_entries:
print d print(d)
# delete existing gle # delete existing gle
frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d) frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d)

View File

@ -1,3 +1,4 @@
from __future__ import print_function
import frappe import frappe
def execute(): def execute():
@ -11,4 +12,4 @@ def execute():
if item_doc.thumbnail: if item_doc.thumbnail:
item_doc.db_set("thumbnail", item_doc.thumbnail, update_modified=False) item_doc.db_set("thumbnail", item_doc.thumbnail, update_modified=False)
except Exception: except Exception:
print "Unable to make thumbnail for {0}".format(item.website_image.encode("utf-8")) print("Unable to make thumbnail for {0}".format(item.website_image.encode("utf-8")))

View File

@ -1,7 +1,7 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
def execute(): def execute():
@ -13,7 +13,7 @@ def execute():
and against_voucher=je.reference_name)""") and against_voucher=je.reference_name)""")
for d in je_list: for d in je_list:
print d print(d)
# delete existing gle # delete existing gle
frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d) frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d)

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
from frappe.utils import encode from frappe.utils import encode
@ -25,7 +25,7 @@ def execute():
try: try:
file.validate_file() file.validate_file()
except IOError: except IOError:
print encode(item.website_image), "does not exist" print(encode(item.website_image), "does not exist")
file.delete() file.delete()
item.db_set("website_image", None, update_modified=False) item.db_set("website_image", None, update_modified=False)

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe, erpnext import frappe, erpnext
def execute(): def execute():
@ -35,11 +35,11 @@ def execute():
voucher.make_gl_entries() voucher.make_gl_entries()
frappe.db.commit() frappe.db.commit()
except Exception as e: except Exception as e:
print frappe.get_traceback() print(frappe.get_traceback())
rejected.append([voucher_type, voucher_no]) rejected.append([voucher_type, voucher_no])
frappe.db.rollback() frappe.db.rollback()
print rejected print(rejected)
def set_warehouse_for_stock_account(warehouse_account): def set_warehouse_for_stock_account(warehouse_account):
for account in warehouse_account: for account in warehouse_account:

View File

@ -81,7 +81,7 @@ def execute():
try: try:
frappe.db.sql("""INSERT INTO `tabSalary Component` ({0}) SELECT {1} FROM `tab{2}`""" frappe.db.sql("""INSERT INTO `tabSalary Component` ({0}) SELECT {1} FROM `tab{2}`"""
.format(target_cols, source_cols, doctype)) .format(target_cols, source_cols, doctype))
except Exception, e: except Exception as e:
if e.args[0]==1062: if e.args[0]==1062:
pass pass

View File

@ -0,0 +1,7 @@
import frappe
def execute():
frappe.delete_doc_if_exists("DocType", "BOM Replace Tool")
frappe.reload_doctype("BOM")
frappe.db.sql("update tabBOM set conversion_rate=1 where conversion_rate is null or conversion_rate=0")
frappe.db.sql("update tabBOM set set_rate_of_sub_assembly_item_based_on_bom=1")

View File

@ -0,0 +1,12 @@
import frappe
def execute():
# there is no more status called "Submitted", there was an old issue that used
# to set it as Submitted, fixed in this commit
frappe.db.sql("""
update
`tabPurchase Receipt`
set
status = 'To Bill'
where
status = 'Submitted'""")

View File

@ -508,8 +508,8 @@ frappe.help.help_links['Form/Production Planning Tool'] = [
{ label: 'Production Planning Tool', url: 'https://frappe.github.io/erpnext/user/manual/en/manufacturing/tools/production-planning-tool' }, { label: 'Production Planning Tool', url: 'https://frappe.github.io/erpnext/user/manual/en/manufacturing/tools/production-planning-tool' },
] ]
frappe.help.help_links['Form/BOM Replace Tool'] = [ frappe.help.help_links['Form/BOM Update Tool'] = [
{ label: 'BOM Replace Tool', url: 'https://frappe.github.io/erpnext/user/manual/en/manufacturing/tools/bom-replace-tool' }, { label: 'BOM Update Tool', url: 'https://frappe.github.io/erpnext/user/manual/en/manufacturing/tools/bom-update-tool' },
] ]
//Customize //Customize

View File

@ -13,7 +13,8 @@ def execute(filters=None):
dict(fieldtype='Data', label='Invoice Type', width=120), dict(fieldtype='Data', label='Invoice Type', width=120),
dict(fieldtype='Data', label='Export Type', width=120), dict(fieldtype='Data', label='Export Type', width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', width=130), dict(fieldtype='Data', label='E-Commerce GSTIN', width=130),
dict(fieldtype='Data', label='HSN Code', width=120) dict(fieldtype='Data', label='HSN Code', width=120),
dict(fieldtype='Data', label='Supplier Invoice No', width=120)
], additional_query_columns=[ ], additional_query_columns=[
'supplier_gstin', 'supplier_gstin',
'company_gstin', 'company_gstin',
@ -21,5 +22,6 @@ def execute(filters=None):
'invoice_type', 'invoice_type',
'export_type', 'export_type',
'ecommerce_gstin', 'ecommerce_gstin',
'gst_hsn_code' 'gst_hsn_code',
'bill_no'
]) ])

View File

@ -17,7 +17,7 @@ class TestCourseSchedule(unittest.TestCase):
cs1 = make_course_schedule_test_record(simulate= True) cs1 = make_course_schedule_test_record(simulate= True)
cs2 = make_course_schedule_test_record(schedule_date=cs1.schedule_date, from_time= cs1.from_time, cs2 = make_course_schedule_test_record(schedule_date=cs1.schedule_date, from_time= cs1.from_time,
to_time= cs1.to_time, instructor="_T-Instructor-00002", room="RM0002", do_not_save= 1) to_time= cs1.to_time, instructor="_Test Instructor 2", room="RM0002", do_not_save= 1)
self.assertRaises(OverlapError, cs2.save) self.assertRaises(OverlapError, cs2.save)
def test_instructor_conflict(self): def test_instructor_conflict(self):
@ -31,14 +31,14 @@ class TestCourseSchedule(unittest.TestCase):
cs1 = make_course_schedule_test_record(simulate= True) cs1 = make_course_schedule_test_record(simulate= True)
cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time, cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
student_group="Course-TC101-2014-2015 (_Test Academic Term)", instructor="_T-Instructor-00002", do_not_save= 1) student_group="Course-TC101-2014-2015 (_Test Academic Term)", instructor="_Test Instructor 2", do_not_save= 1)
self.assertRaises(OverlapError, cs2.save) self.assertRaises(OverlapError, cs2.save)
def test_no_conflict(self): def test_no_conflict(self):
cs1 = make_course_schedule_test_record(simulate= True) cs1 = make_course_schedule_test_record(simulate= True)
make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time, make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
student_group="Course-TC102-2014-2015 (_Test Academic Term)", instructor="_T-Instructor-00002", room="RM0002") student_group="Course-TC102-2014-2015 (_Test Academic Term)", instructor="_Test Instructor 2", room="RM0002")
def make_course_schedule_test_record(**args): def make_course_schedule_test_record(**args):
args = frappe._dict(args) args = frappe._dict(args)
@ -46,7 +46,7 @@ def make_course_schedule_test_record(**args):
course_schedule = frappe.new_doc("Course Schedule") course_schedule = frappe.new_doc("Course Schedule")
course_schedule.student_group = args.student_group or "Course-TC101-2014-2015 (_Test Academic Term)" course_schedule.student_group = args.student_group or "Course-TC101-2014-2015 (_Test Academic Term)"
course_schedule.course = args.course or "TC101" course_schedule.course = args.course or "TC101"
course_schedule.instructor = args.instructor or "_T-Instructor-00001" course_schedule.instructor = args.instructor or "_Test Instructor"
course_schedule.room = args.room or "RM0001" course_schedule.room = args.room or "RM0001"
course_schedule.schedule_date = args.schedule_date or today() course_schedule.schedule_date = args.schedule_date or today()

View File

@ -208,7 +208,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2017-06-30 08:21:49.055531", "modified": "2017-08-25 01:03:14.602994",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Instructor", "name": "Instructor",

View File

@ -4,7 +4,21 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.model.naming import make_autoname
class Instructor(Document): class Instructor(Document):
pass def autoname(self):
naming_method = frappe.db.get_value("School Settings", None, "instructor_created_by")
if not naming_method:
frappe.throw(_("Please setup Instructor Naming System in School > School Settings"))
else:
if naming_method == 'Naming Series':
self.name = make_autoname(self.naming_series + '.####')
elif naming_method == 'Employee Number':
if not self.employee:
frappe.throw("Please select Employee")
self.name = self.employee
elif naming_method == 'Full Name':
self.name = self.instructor_name

View File

@ -194,6 +194,67 @@
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Full Name",
"fieldname": "instructor_created_by",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Instructor Records to be created by",
"length": 0,
"no_copy": 0,
"options": "Full Name\nNaming Series\nEmployee Number",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "has_web_view": 0,
@ -206,7 +267,7 @@
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-06-30 08:21:50.339169", "modified": "2017-08-25 02:36:48.744456",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "School Settings", "name": "School Settings",

View File

@ -26,3 +26,10 @@ class SchoolSettings(Document):
def get_defaults(self): def get_defaults(self):
return frappe.defaults.get_defaults() return frappe.defaults.get_defaults()
def validate(self):
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
if self.get('instructor_created_by')=='Naming Series':
make_property_setter('Instructor', "naming_series", "hidden", 0, "Check")
else:
make_property_setter('Instructor', "naming_series", "hidden", 1, "Check")

View File

@ -3,6 +3,11 @@
frappe.ui.form.on('Student', { frappe.ui.form.on('Student', {
setup: function(frm) { setup: function(frm) {
frm.add_fetch("guardian", "guardian_name", "guardian_name");
frm.add_fetch("student", "title", "full_name");
frm.add_fetch("student", "gender", "gender");
frm.add_fetch("student", "date_of_birth", "date_of_birth");
frm.set_query("student", "siblings", function(doc, cdt, cdn) { frm.set_query("student", "siblings", function(doc, cdt, cdn) {
return { return {
"filters": { "filters": {
@ -12,17 +17,3 @@ frappe.ui.form.on('Student', {
}) })
} }
}); });
frappe.ui.form.on("Student Guardian", {
guardian: function(frm) {
frm.add_fetch("guardian", "guardian_name", "guardian_name");
}
});
frappe.ui.form.on('Student Sibling', {
student: function(frm) {
frm.add_fetch("student", "title", "full_name");
frm.add_fetch("student", "gender", "gender");
frm.add_fetch("student", "date_of_birth", "date_of_birth");
}
});

View File

@ -39,15 +39,12 @@ frappe.ui.form.on("Student Applicant", {
method: "erpnext.schools.api.enroll_student", method: "erpnext.schools.api.enroll_student",
frm: frm frm: frm
}) })
} },
});
setup: function(frm) {
frappe.ui.form.on('Student Sibling', { frm.add_fetch("guardian", "guardian_name", "guardian_name");
student: function(frm) {
frm.add_fetch("student", "title", "full_name"); frm.add_fetch("student", "title", "full_name");
frm.add_fetch("student", "gender", "gender"); frm.add_fetch("student", "gender", "gender");
frm.add_fetch("student", "date_of_birth", "date_of_birth"); frm.add_fetch("student", "date_of_birth", "date_of_birth");
} }
}); });

View File

@ -881,7 +881,7 @@
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Guardians", "label": "Guardians",
"length": 0, "length": 0,
"no_copy": 1, "no_copy": 0,
"options": "Student Guardian", "options": "Student Guardian",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
@ -1058,7 +1058,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2017-06-30 08:21:50.917086", "modified": "2017-08-23 06:12:36.996978",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Schools", "module": "Schools",
"name": "Student Applicant", "name": "Student Applicant",

View File

@ -2,7 +2,7 @@
# Copyright (c) 2015, Frappe Technologies and contributors # Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
@ -13,7 +13,7 @@ class StudentApplicant(Document):
if self.student_admission: if self.student_admission:
naming_series = frappe.db.get_value('Student Admission', self.student_admission, naming_series = frappe.db.get_value('Student Admission', self.student_admission,
'naming_series_for_student_applicant') 'naming_series_for_student_applicant')
print naming_series print(naming_series)
if naming_series: if naming_series:
self.naming_series = naming_series self.naming_series = naming_series

View File

@ -0,0 +1,41 @@
QUnit.module('Quotation');
QUnit.test("test quotation submit cancel amend", function(assert) {
assert.expect(2);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Quotation', [
{customer: 'Test Customer 1'},
{items: [
[
{'delivery_date': frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)},
{'qty': 5},
{'item_code': 'Test Product 1'}
]
]},
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'}
]);
},
() => cur_frm.save(),
() => {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct");
// get uom details
assert.ok(cur_frm.doc.grand_total== 500, "Grand total correct ");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.tests.click_button('Cancel'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.5),
() => frappe.tests.click_button('Amend'),
() => cur_frm.save(),
() => done()
]);
});

View File

@ -47,7 +47,7 @@ class TestCompany(unittest.TestCase):
def test_coa_based_on_country_template(self): def test_coa_based_on_country_template(self):
countries = ["India", "Brazil", "United Arab Emirates", "Canada", "Germany", "France", countries = ["India", "Brazil", "United Arab Emirates", "Canada", "Germany", "France",
"Guatemala", "Indonesia", "Mexico", "Nicaragua", "Netherlands", "Singapore", "Guatemala", "Indonesia", "Mexico", "Nicaragua", "Netherlands", "Singapore",
"Brazil", "Argentina", "Hungary"] "Brazil", "Argentina", "Hungary", "Taiwan"]
for country in countries: for country in countries:
templates = get_charts_for_country(country) templates = get_charts_for_country(country)

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import print_function, unicode_literals
import unittest import unittest
import frappe import frappe
from frappe.utils.nestedset import NestedSetRecursionError, NestedSetMultipleRootsError, \ from frappe.utils.nestedset import NestedSetRecursionError, NestedSetMultipleRootsError, \
@ -112,7 +112,7 @@ class TestItem(unittest.TestCase):
def print_tree(self): def print_tree(self):
import json import json
print json.dumps(frappe.db.sql("select name, lft, rgt from `tabItem Group` order by lft"), indent=1) print(json.dumps(frappe.db.sql("select name, lft, rgt from `tabItem Group` order by lft"), indent=1))
def test_move_leaf_into_another_group(self): def test_move_leaf_into_another_group(self):
# before move # before move

View File

@ -1,47 +1,55 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// License: GNU General Public License v3. See license.txt // For license information, please see license.txt
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { frappe.ui.form.on("Naming Series", {
cur_frm.disable_save(); onload: function(frm) {
cur_frm.toolbar.print_icon.addClass("hide"); frm.disable_save();
return cur_frm.call({ frm.events.get_doc_and_prefix(frm);
doc: cur_frm.doc, },
method: 'get_transactions',
get_doc_and_prefix: function(frm) {
frappe.call({
method: "get_transactions",
doc: frm.doc,
callback: function(r) { callback: function(r) {
cur_frm.cscript.update_selects(r); frm.set_df_property("select_doc_for_series", "options", r.message.transactions);
cur_frm.cscript.select_doc_for_series(doc, cdt, cdn); frm.set_df_property("prefix", "options", r.message.prefixes);
} }
}); });
} },
cur_frm.cscript.update_selects = function(r) { select_doc_for_series: function(frm) {
set_field_options('select_doc_for_series', r.message.transactions); frm.set_value("user_must_always_select", 0);
set_field_options('prefix', r.message.prefixes); frappe.call({
} method: "get_options",
doc: frm.doc,
cur_frm.cscript.select_doc_for_series = function(doc, cdt, cdn) { callback: function(r) {
cur_frm.set_value('user_must_always_select', 0); frm.set_value("set_options", r.message);
cur_frm.toggle_display(['help_html','set_options', 'user_must_always_select', 'update'],
doc.select_doc_for_series);
var callback = function(r, rt){
locals[cdt][cdn].set_options = r.message;
refresh_field('set_options');
if(r.message && r.message.split('\n')[0]=='') if(r.message && r.message.split('\n')[0]=='')
cur_frm.set_value('user_must_always_select', 1); frm.set_value('user_must_always_select', 1);
frm.refresh();
} }
});
},
if(doc.select_doc_for_series) prefix: function(frm) {
return $c_obj(doc,'get_options','',callback); frappe.call({
method: "get_current",
doc: frm.doc,
callback: function(r) {
frm.refresh_field("current_value");
} }
});
},
cur_frm.cscript.update = function() { update: function(frm) {
return cur_frm.call_server('update_series', '', cur_frm.cscript.update_selects); frappe.call({
method: "update_series",
doc: frm.doc,
callback: function(r) {
frm.events.get_doc_and_prefix(frm);
} }
cur_frm.cscript.prefix = function(doc, dt, dn) {
return cur_frm.call_server('get_current', '', function(r) {
refresh_field('current_value');
}); });
} }
});

View File

@ -1,29 +1,40 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
"beta": 0,
"creation": "2013-01-25 11:35:08", "creation": "2013-01-25 11:35:08",
"custom": 0, "custom": 0,
"description": "Set prefix for numbering series on your transactions", "description": "Set prefix for numbering series on your transactions",
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"editable_grid": 0,
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"description": "Set prefix for numbering series on your transactions", "description": "Set prefix for numbering series on your transactions",
"fieldname": "setup_series", "fieldname": "setup_series",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Setup Series", "label": "Setup Series",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -31,20 +42,28 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "select_doc_for_series", "fieldname": "select_doc_for_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Select Transaction", "label": "Select Transaction",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -52,21 +71,30 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"depends_on": "select_doc_for_series",
"fieldname": "help_html", "fieldname": "help_html",
"fieldtype": "HTML", "fieldtype": "HTML",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Help HTML", "label": "Help HTML",
"length": 0,
"no_copy": 0, "no_copy": 0,
"options": "<div class=\"well\">\nEdit list of Series in the box below. Rules:\n<ul>\n<li>Each Series Prefix on a new line.</li>\n<li>Allowed special characters are \"/\" and \"-\"</li>\n<li>Optionally, set the number of digits in the series using dot (.) followed by hashes (#). For example, \".####\" means that the series will have four digits. Default is five digits.</li>\n</ul>\nExamples:<br>\nINV-<br>\nINV-10-<br>\nINVK-<br>\nINV-.####<br>\n</div>", "options": "<div class=\"well\">\nEdit list of Series in the box below. Rules:\n<ul>\n<li>Each Series Prefix on a new line.</li>\n<li>Allowed special characters are \"/\" and \"-\"</li>\n<li>Optionally, set the number of digits in the series using dot (.) followed by hashes (#). For example, \".####\" means that the series will have four digits. Default is five digits.</li>\n</ul>\nExamples:<br>\nINV-<br>\nINV-10-<br>\nINVK-<br>\nINV-.####<br>\n</div>",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -74,20 +102,29 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"depends_on": "select_doc_for_series",
"fieldname": "set_options", "fieldname": "set_options",
"fieldtype": "Text", "fieldtype": "Text",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Series List for this Transaction", "label": "Series List for this Transaction",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -95,21 +132,30 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"depends_on": "select_doc_for_series",
"description": "Check this if you want to force the user to select a series before saving. There will be no default if you check this.", "description": "Check this if you want to force the user to select a series before saving. There will be no default if you check this.",
"fieldname": "user_must_always_select", "fieldname": "user_must_always_select",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "User must always select", "label": "User must always select",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -117,20 +163,30 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"depends_on": "select_doc_for_series",
"fieldname": "update", "fieldname": "update",
"fieldtype": "Button", "fieldtype": "Button",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Update", "label": "Update",
"length": 0,
"no_copy": 0, "no_copy": 0,
"options": "",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -138,21 +194,29 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"description": "Change the starting / current sequence number of an existing series.", "description": "Change the starting / current sequence number of an existing series.",
"fieldname": "update_series", "fieldname": "update_series",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Update Series", "label": "Update Series",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -160,20 +224,28 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "prefix", "fieldname": "prefix",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Prefix", "label": "Prefix",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -181,21 +253,29 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"description": "This is the number of the last created transaction with this prefix", "description": "This is the number of the last created transaction with this prefix",
"fieldname": "current_value", "fieldname": "current_value",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Current Value", "label": "Current Value",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -203,21 +283,29 @@
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "update_series_start", "fieldname": "update_series_start",
"fieldtype": "Button", "fieldtype": "Button",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0,
"label": "Update Series Number", "label": "Update Series Number",
"length": 0,
"no_copy": 0, "no_copy": 0,
"options": "update_series_start", "options": "update_series_start",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
@ -225,16 +313,18 @@
"unique": 0 "unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 1, "hide_toolbar": 1,
"icon": "fa fa-sort-by-order", "icon": "fa fa-sort-by-order",
"idx": 1, "idx": 1,
"image_view": 0,
"in_create": 0, "in_create": 0,
"in_dialog": 0,
"is_submittable": 0, "is_submittable": 0,
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"modified": "2015-02-05 05:11:41.473793", "max_attachments": 0,
"modified": "2017-08-17 03:41:37.685910",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Setup", "module": "Setup",
"name": "Naming Series", "name": "Naming Series",
@ -261,6 +351,10 @@
"write": 1 "write": 1
} }
], ],
"quick_entry": 0,
"read_only": 1, "read_only": 1,
"read_only_onload": 0 "read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 0,
"track_seen": 0
} }

View File

@ -21,7 +21,6 @@ class NamingSeries(Document):
where fieldname='naming_series'"""))) where fieldname='naming_series'""")))
doctypes = list(set(get_doctypes_with_read()) | set(doctypes)) doctypes = list(set(get_doctypes_with_read()) | set(doctypes))
prefixes = "" prefixes = ""
for d in doctypes: for d in doctypes:
options = "" options = ""
@ -34,9 +33,8 @@ class NamingSeries(Document):
if options: if options:
prefixes = prefixes + "\n" + options prefixes = prefixes + "\n" + options
prefixes.replace("\n\n", "\n") prefixes.replace("\n\n", "\n")
prefixes = "\n".join(sorted(prefixes.split())) prefixes = "\n".join(sorted(prefixes.split("\n")))
return { return {
"transactions": "\n".join([''] + sorted(doctypes)), "transactions": "\n".join([''] + sorted(doctypes)),
@ -112,9 +110,7 @@ class NamingSeries(Document):
where dt.name = df.dt and df.fieldname='naming_series' and dt.name != %s""", where dt.name = df.dt and df.fieldname='naming_series' and dt.name != %s""",
self.select_doc_for_series) self.select_doc_for_series)
)) ))
sr = [[frappe.get_meta(p).get_field("naming_series").options, p] sr = [[frappe.get_meta(p).get_field("naming_series").options, p] for p in parent]
for p in parent]
dt = frappe.get_doc("DocType", self.select_doc_for_series) dt = frappe.get_doc("DocType", self.select_doc_for_series)
options = self.scrub_options_list(self.set_options.split("\n")) options = self.scrub_options_list(self.set_options.split("\n"))
for series in options: for series in options:

View File

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Naming Series", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Naming Series
() => frappe.tests.make('Naming Series', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

Some files were not shown because too many files have changed in this diff Show More